;VHFBCN05 Andy Talbot G4JNT Jan 2006 ;Frequency and other constants stored in VHFBCNEE.INC ;Sequence format (data type) vs interval stored in VHFBCNGT.INC ; Edit these to alter operating parameters ;Uses 9852 DDS to generate JT44 Messages ;from 10 MHz master oscillator, generates 4482Hz ;Fc = 2.5 MHz /4 prescale , timer counts 256 to overflow int at 2441Hz ; Int routine counts 907 for 2.69Hz timing interval. ;Read data string from GPS, send data messages according to 60s interval ;Ver 2 adds in CW and RTTY message code and PPS monitor ;2005/01/15 JT44, RTTY and CW coded ;Ver 3 adds test mode on B7 ; GPS receiver data from Oncore (incl. Jupiter-T), not NMEA ;2005/03/06 GPS Status bit mask changed (ignore poor geometry) ;Ver 4 adds NMEAPol assembler flag for inverted inputs (1 = RS232, 0 = logic) ;Ver5 Converted from JT44 to JT65, 1s BPSK mode added ; New Include files VHFBCNE2 & VHFBCNG2 (so Ver 4/JT44 remains untouched) LIST P=16F628 INCLUDE "P16F628.INC" #define MR PORTA, 0 #define SCLK PORTA, 1 #define IOUD PORTA, 2 #define SDIO PORTA, 3 #define IORST PORTA, 4 #define PPS PORTB, 0 ;Allows use as INT #define SERIN PORTB, 1 #define SEROUT PORTB, 2 #define LCKEN PORTB, 3 #define DEBUGTXD PORTB, 6 ;RS2232 polarity output for debugging #define TESTLINK PORTB, 7 #define LEDGrn PORTB, 4 #define LEDRed PORTB, 5 #define FigFlag Flags, 0 #define TestModeFlag Flags, 1 #define GPSOk Flags, 2 errorlevel 1, -207 ;Suppress msgs. and warnings about labels after col 1. include "VHFBCNE2.INC" ;Constants ,EEPRom data & config word org 0 boot nop movlw b'00000000' ;No interupts until passed thro here once movwf INTCON ; goto startup ;jump to main code ;------------------------------------ ints ;/4 prescale & /256 for ovflow int = 2441Hz bcf INTCON , T0IF ; movwf Wreg ;Save W swapf STATUS , W ; nb. movwf does not affect any STATUS bits movwf SaveSts ;Stave STATUS, without affecting it incf IntCountLo btfsc STATUS, Z incf IntCountHi movlw HIGH(d'907') ;4882/907 = 2.691337Hz symbol rate subwf IntCountHi, W btfss STATUS, Z goto OutInterrupt movlw LOW(d'907') subwf IntCountLo, W btfss STATUS, Z goto OutInterrupt ;............ Here at 2.69Hz clrf IntCountLo clrf IntCountHi btfsc SymbCount, 0 ;Flash Red LED at half symbol rate bsf LEDRed btfss SymbCount, W bcf LEDRed movf SymbCount ;Test for First symbol, in which case btfsc STATUS, Z ; don't do any DDS update goto NotFirstPass bsf IOUD ;Update DDS with LAST frequency, so we need nop ; to have an extra interrupt to allow this nop ; BUT not first time into interrupt bcf IOUD NotFirstPass movlw d'126' subwf SymbCount, W ;So do the testing for a full message here, btfss STATUS, Z goto NotLastSymbol bcf INTCON, T0IE ;Inhibit interrupt after final symbol goto OutInterrupt ; and don't do anything else ;............... NotLastSymbol movf SymbCount ;Test for first symbol btfsc STATUS, Z call SyncToStack ;Load sync pattern into stack first time here rlf Stack0 ;Stack holds sync / message tone pattern rlf Stack1 rlf Stack2 rlf Stack3 rlf Stack4 rlf Stack5 rlf Stack6 rlf Stack7 rlf Stack8 rlf Stack9 rlf StackA rlf StackB rlf StackC rlf StackD rlf StackE rlf StackF btfss STATUS, C ;1 = sync, 0 = character goto JTSymb movlw d'0' ;0 passed to routine sends sync tone call GenToneData goto SendTone ;................... JTSymb ;Get next symbol value in message (0-63) movf CharCount, W addlw JTDATAOFFSET call GetEE ;Get value 0 to 63 addlw 2 ;2* interval Offset from sync (was 3 in JT44) call GenToneData ;Pass symbol value to routine, ; generates frequency data in D0-D3 incf CharCount ;.......... SendTone ;Get here with frequency data in D0-5 movlw 2 movwf DDSAddr call DataTo9852 ;Send Freq data, updated at NEXT symbol int. incf SymbCount ;Increment here, but tested at start allows ; the DDS update at last+1 interval, ie. =136 OutInterrupt swapf SaveSts , W ;Restore STATUS movwf STATUS swapf Wreg ;Restore W swapf Wreg , W ;Can't use movf as it affects Z bit retfie ;===================================== startup clrf PORTA ;Special setup to disable comparator on 'F628 movlw 7 movwf CMCON bsf STATUS,RP0 ;ram page 1 movlw b'00000001' ;Internal input, Prescalar /4 pull-ups movwf OPTION_REG movlw b'00000000' ; movwf PORTA ; movlw b'10000011' ;B0 PPS, B1 SerIn, B2 SerOut B3 Lock Nenable movwf PORTB ;B6 Debug output, B7 test mode input bcf STATUS,RP0 ;ram page 0 clrf PORTB clrf PORTA clrf TMR0 clrf IntCountHi clrf IntCountLo bsf LCKEN ;High gives open loop operation until GPSOk clrf CharCount clrf SymbCount ;Position at start of message clrf SerCounter clrf Flags bsf LEDRed ;Allow a few seconds for GPS to set call LongDelay ; itself up, ready to accept commands bcf LEDRed bsf LEDGrn call LongDelay bsf LEDRed bcf LEDGrn call LongDelay bcf LEDRed bsf LEDGrn call LongDelay bcf LEDGrn call InitGPS call SetUpDDS ;Includes a settling delay call InitGPS ;Send it again to make sure movlw b'10000000' ;Enable global int, ready for T0IE movwf INTCON ;Started after DDS is set up ;========================== SitAndWait ;Sit in this loop unless doing somehitng btfsc GPSOk ;Double test to avoid glitches on LCKEn bcf LCKEN btfss GPSOk bsf LCKEN btfsc TESTLINK goto NotTestMode btfsc TestModeFlag goto SitAndWait ;If already in testmode, do nothing more bsf LEDGrn ;Green led, on continuously, test mode bcf LEDRed bsf TestModeFlag goto CarrierOnly ;........................... NotTestMode bcf LEDRed bcf TestModeFlag call GetGPSData btfss ICount, 7 ;Signals that next PPS is to be used goto SitAndWait call WaitPPS ;Synchronise to NEXT seconds marker movlw HIGH($) movwf PCLATH movlw b'00001111' andwf ICount, W ;Extract ICount value bcf LEDGrn ;Needed for correct LEDRed operation addwf PCL INCLUDE "VHFBCNG2.INC" ;Contains GOTO instructions @@@@@@@@@@@ ;........................... for each interval SendJT65 btfss GPSOk goto SendCW1 ;Basic CW Message in place of JT65 ; if GPS is not locked up call LongDelay clrf IntCountLo clrf IntCountHi clrf CharCount clrf SymbCount ;Re-Initialise registers movlw 1 ;Turn on RF call OnOff bsf INTCON, T0IE ;Starts sending as interrupt is enabled ; T0IE reset in int routine when frame complete JT65Loop btfsc INTCON, T0IE ;Sit in here waiting for completion goto JT65Loop goto CarrierOnly ;Complete the last few seconds with tone ;.......................... SendRTTY movlw d'250' movwf Counter RTTYLeadInLoop ;Start 0.5s into interval call Delay1ms call Delay1ms decfsz Counter goto RTTYLeadInLoop movlw 1 call OnOff call SendRTTYMsg goto CarrierOnly ;Exit sending plain tone ;.......................... SendBPSK bsf LEDRed movlw d'28' movwf CharCount BpskLoop call WaitPPS movlw 0 btfsc CharCount, 0 ;Toggle the phase 0/180 each second movlw 1 call SendPhase movlw b'00110000' ;Toggle Red and green leds for BPSK data xorwf PORTB decfsz CharCount goto BpskLoop bcf LEDRed bsf LEDGrn goto CarrierOnly ;.......................... SendCW1 movlw CWMSG1OFFSET movwf CWMsgCnt goto StartCW SendCW2 movlw CWMSG2OFFSET movwf CWMsgCnt goto StartCW SendCW3 movlw CWMSG2OFFSET movwf CWMsgCnt goto StartCW SendCW4 movlw CWMSG1OFFSET movwf CWMsgCnt goto StartCW StartCW bcf LEDGrn ;To guarantee correct REDLed operation movlw 2 movwf DDSAddr call DataTo9852 movlw d'17' ;Set CW carrier frequency call GetEE movwf D0 movlw d'16' call GetEE movwf D1 movlw d'15' call GetEE movwf D2 movlw d'14' call GetEE movwf D3 movlw d'13' call GetEE movwf D4 movlw d'12' call GetEE movwf D5 call DataTo9852 bsf IOUD nop nop bcf IOUD call SendCWMsg movlw 1 call OnOff ;Exit sending plain carrier goto CarrierOnly ;.................. CarrierOnly movlw 2 movwf DDSAddr call DataTo9852 movlw d'17' ;Set carrier frequency call GetEE movwf D0 movlw d'16' call GetEE movwf D1 movlw d'15' call GetEE movwf D2 movlw d'14' call GetEE movwf D3 movlw d'13' call GetEE movwf D4 movlw d'12' call GetEE movwf D5 call DataTo9852 bsf IOUD nop nop bcf IOUD movlw 1 call OnOff ;Exit sending plain carrier goto SitAndWait ; ......................... TestMode ;Here if B7 link made, W contains masked goto SitAndWait ;--------------------------------------- WaitPPS ;Look for rising edge on PPS input btfsc PPS ;A low first goto WaitPPS WaitPPSHigh ;Followed by a high btfss PPS goto WaitPPSHigh return ;--------------------------------------- GenToneData ;Enter with tone offset, 0, or 3 to 66 movwf A0 ;save Offset movlw 5 ;Get sync carrier frequency call GetEE movwf D0 movlw 4 call GetEE movwf D1 movlw 3 call GetEE movwf D2 movlw 2 call GetEE movwf D3 movlw 1 call GetEE movwf D4 movlw 0 call GetEE movwf D5 movf A0 , w ;Test for sync iorlw 0 btfsc STATUS, Z goto ToneMultDone ; and do nothing else if it is ;A0 alreadycontains tone multiple movlw 6 ;B0-5 contains data for a single interval call GetEE movwf B5 movlw 7 call GetEE movwf B4 movlw 8 call GetEE movwf B3 movlw 9 call GetEE movwf B2 movlw d'10' call GetEE movwf B1 movlw d'11' call GetEE movwf B0 call Multiply24x8 ;Tone offset stored in Acc0-3 ;Will need bigger multiplication routine ; for Lower clock freqeuncy, or higher ; tone spacing movf Acc0, W addwf D0 btfss STATUS, C goto TonAdd1 incf D1 btfss STATUS, Z goto TonAdd1 incf D2 btfss STATUS, Z goto TonAdd1 incf D3 btfss STATUS, Z goto TonAdd1 incf D4 btfsc STATUS, Z incf D5 TonAdd1 movf Acc1, W addwf D1 btfss STATUS, C goto TonAdd2 incf D2 btfss STATUS, Z goto TonAdd2 incf D3 btfss STATUS, Z goto TonAdd2 incf D4 btfsc STATUS, Z incf D5 TonAdd2 movf Acc2, W addwf D2 btfss STATUS, C goto TonAdd3 incf D3 btfss STATUS, Z goto TonAdd3 incf D4 btfsc STATUS, Z incf D5 TonAdd3 movf Acc3, W addwf D3 btfss STATUS, C goto TonAdd4 incf D4 btfsc STATUS, Z incf D5 TonAdd4 ToneMultDone return ;------------------------------ Multiply24x8 ;24 bit * 8 bit multiplication, more efficient method Clrf Acc0 ;Input A0/1/2 and B0/1/2, output Acc0/2/3/4/5/6 clrf Acc1 ;A destroyed, B kept clrf Acc2 clrf Acc3 movlw d'8' ;A and B 24 bit movwf Counter MultLoop bcf STATUS, C rrf A0 ;Working bit into carry btfss STATUS, C ; into Acc depending on working bit of A goto NoMult movf B0, W ;get shifted B0 value addwf Acc1 ; and add into Accumulator if 1 in btfss STATUS, C ; appropriate bit in Avalue goto MulAdd1 incf Acc2 btfss STATUS, Z goto MulAdd1 ;Need more complex addition routine as final Carry movlw 1 ; must be preserved for the shift addwf Acc3 MulAdd1 movf B1, W addwf Acc2 btfss STATUS, C goto MulAdd2 movlw 1 addwf Acc3 MulAdd2 movf B2, W addwf Acc3 NoMult ;Need to rotate in carry from final addition rrf Acc3 ;C already zero if we've jumped in here rrf Acc2 rrf Acc1 rrf Acc0 decfsz Counter goto MultLoop return ;Acc3/2/1/0 = A * B B kept, A destroyed ;------------------------------------------------------------------ SyncToStack movlw 0x98 movwf StackF movlw 0xFD movwf StackE movlw 0x45 movwf StackD movlw 0x91 movwf StackC movlw 0xCF movwf StackB movlw 0x6F movwf StackA movlw 0x1A movwf Stack9 movlw 0xB3 movwf Stack8 movlw 0x54 movwf Stack7 movlw 0x81 movwf Stack6 movlw 0x80 movwf Stack5 movlw 0xD2 movwf Stack4 movlw 0xD5 movwf Stack3 movlw 0x32 movwf Stack2 movlw 0x43 movwf Stack1 movlw 0xFC movwf Stack0 return ;--------------------------------------- GetEE ;different from ;F84 EE registers all in bank 1 now bsf STATUS,RP0 ;ram page 1 movwf EEADR bsf EECON1 , RD movf EEDATA , W bcf STATUS , RP0 ;ram page 0 return ;------------------------- ;----------------------- SetUpDDS bsf MR movlw d'10' movwf DelCount2 call LongDelay bcf MR call LongDelay ;Allow things to settle movlw 7 ;Control register movwf DDSAddr movlw 0x10 movwf D3 movlw 0x50 ;PLL X16, and high range movwf D2 movlw 0x00 ;LSB of this is external update movwf D1 movlw 0x60 movwf D0 call DataTo9852 return ;-------------------------- OnOff ;Keys DDS Output on / off, immediately iorlw 0 ;W = 0 output off, W = 1, Output level = max btfsc STATUS, Z goto TurnOff movlw 0x0F movwf D1 movlw 0xFF movwf D0 goto SendOnOff TurnOff clrf D1 clrf D0 SendOnOff movlw 8 movwf DDSAddr call DataTo9852 bsf IOUD nop nop bcf IOUD return ;-------------------------- SendPhase movwf Temp ;Save phase value movlw 0 movf Temp ;Test for 0/1 btfss STATUS, Z movlw high(PHASE180) movwf D1 movlw 0 movf Temp ;Do it this way for equal delay btfss STATUS, Z movlw low(PHASE180) movwf D0 clrf DDSAddr ;Phase is address 0 call DataTo9852 bsf IOUD nop nop bcf IOUD return ;-------------------------- Send9852Byte movwf Temp movlw 8 movwf Counter DDSSendLoop rlf Temp btfsc STATUS, C bsf SDIO btfss STATUS, C bcf SDIO nop bsf SCLK nop bcf SCLK decfsz Counter goto DDSSendLoop return ;------------------------- ;------------------------- LongDelay ;Approx 1 second delay movlw d'250' movwf DelCount2 LongDelLoop call Delay1ms call Delay1ms call Delay1ms call Delay1ms decfsz DelCount2 goto LongDelLoop return ;------------------------- Delay1ms ;5N+5 = 1250 clocks, * 2 = 2500 clocks = 1ms movlw d'249' movwf DelCount Del1msLoop nop nop decfsz DelCount goto Del1msLoop movlw d'249' movwf DelCount Del1ms2Loop nop nop decfsz DelCount goto Del1ms2Loop nop nop nop nop return ;------------------------- GetGPSData ;Monitors SERIN line for @@Ea incf SerCounter bsf LEDGrn ;Flash Green LED Until header is received btfss GPSOk bcf LEDGrn ;Flash in antiphase if GPS is not locked up call PushStack call GetByte movwf Stack0 ;String starts @@Eamdyyhms ;Stack position - A9876543210 movf StackA , W sublw "@" btfss STATUS , Z goto GetGPSData movf Stack9 , W sublw "@" btfss STATUS , Z goto GetGPSData movf Stack8 , W sublw "E" btfss STATUS , Z goto GetGPSData movf Stack7 , W sublw "a" btfss STATUS , Z goto GetGPSData ;Having reached here means correct data message ; has started and HMS data is stored in stack call DoTime ;Extract time from stack and update counters bcf LEDGrn ;Green off means time data has been decoded btfss GPSOk bsf LEDGrn ;Flash in antiphase if GPS is not locked up GetGPSStatus ;Now read in rest of stack data until [cr][lf] incf SerCounter ; at the end. BUT, these may occur as part of call PushStack ; binary data, so only test after 74 chars call GetByte ; have been received (should be 76, but...) movwf Stack0 movlw d'74' subwf SerCounter, W btfss STATUS, C ;W = SerCounter - W, if +Ve (C=1) count is ready goto GetGPSStatus ; to test for [cr][lf] movf Stack0, W sublw 0x0A ;Stack ends with ...msdsC[cr][lf] btfss STATUS , Z ; 65432 1 0 goto GetGPSStatus ;At some future point, could validate movf Stack1, W ; with a checksum calculation. sublw 0x0D btfss STATUS , Z goto GetGPSStatus ;Reached here means terminating [cr][lf] is in movf Stack3, W ; the right place, so extract status info movwf RxStatus call DoStatus clrf SerCounter ;Ready for next time return ;-------------------------------------- GetByte if NMEAPol == 1 ; 1 = RS232 levels (0/-ve = Idle btfss SERIN ; 0 = Logic levels (1 = Idle) else btfsc SERIN endif goto GetByte ;Loop waiting for start bit call HalfBitDelay ;Centre of start bit if NMEAPol == 1 btfss SERIN else btfsc SERIN ;Check it's still low endif goto GetByte movlw 8 movwf Counter clrf Temp ;probably not needed, but good practice InitByteLoop call HalfBitDelay call HalfBitDelay ; nop bcf STATUS , C ;start in known state if NMEAPol == 1 btfss SERIN else btfsc SERIN endif bsf STATUS , C ;Data into Carry rrf Temp ;and then into Temp, LSB first decfsz Counter goto InitByteLoop ;loop is 8 + 2 * HalfBitDelay long call HalfBitDelay ;#### Don't really need to wait for stop bit! #### ; Now have approx 50us of stop bit left movf Temp , W ;to use this data return ;Exit with received byte in W and Temp ;----------------------------------------- SendByte movwf Temp if NMEAPol == 1 bsf SEROUT else bcf SEROUT ;start bit endif call HalfBitDelay ; call HalfBitDelay movlw 8 movwf Counter SendDatLoop rrf Temp ;bit into C if NMEAPol == 1 btfsc STATUS , C bcf SEROUT btfss STATUS , C bsf SEROUT ;could have 2us jitter depending on 1/0 else btfsc STATUS , C bsf SEROUT btfss STATUS , C bcf SEROUT ;could have 2us jitter depending on 1/0 endif call HalfBitDelay call HalfBitDelay decfsz Counter goto SendDatLoop ;loop 8 + BitDelay long if NMEAPol == 1 bcf SEROUT else bsf SEROUT endif call HalfBitDelay call HalfBitDelay ;Two stop bits call HalfBitDelay call HalfBitDelay return ;----------------------------------------- DebugByte ;Send a byte on DEBUGTXD - RS232 polarity movwf Temp bsf DEBUGTXD ;start bit call HalfBitDelay ; call HalfBitDelay movlw 8 movwf Counter SendDbgLoop rrf Temp ;bit into C btfsc STATUS , C bcf DEBUGTXD btfss STATUS , C bsf DEBUGTXD ; call HalfBitDelay call HalfBitDelay decfsz Counter goto SendDbgLoop ;loop 8 + BitDelay long bcf DEBUGTXD call HalfBitDelay call HalfBitDelay ;Two stop bits return ;----------------------------------------- HalfBitDelay ;9600 baud needs 104us, so delay 126 clocks here movlw d'24' ; for a total of 126 * 2 + 8 = 260 clocks = 104us movwf DelCount BaudDelLoop nop nop decfsz DelCount goto BaudDelLoop nop return ;------------------------------- PushStack movf StackE , W movwf StackF movf StackD , W movwf StackE movf StackC , W movwf StackD movf StackB , W movwf StackC movf StackA , W movwf StackB movf Stack9 , W movwf StackA movf Stack8 , W movwf Stack9 movf Stack7 , W movwf Stack8 movf Stack6 , W movwf Stack7 movf Stack5 , W movwf Stack6 movf Stack4 , W movwf Stack5 movf Stack3 , W movwf Stack4 movf Stack2 , W movwf Stack3 movf Stack1 , W movwf Stack2 movf Stack0 , W movwf Stack1 return ;------------------------------- DoTime ;Extract MMSS from ser data, generate interval value movf Stack1, W ; in ICount and a flag when ready for next update movwf Minutes MinModLoop ;Repeatedly subtract RPTTime until result is -ve movlw RPTTime ; subwf Minutes, W ;W = Minutes - RPTime, if -ve(C=0), MOD is done btfss STATUS, C goto ModDone1 movwf Minutes ; otherwise save back and continue goto MinModLoop ;.................. ModDone1 bcf STATUS, C rlf Minutes, W andlw b'01111111' ;Mask out MSB just for safety movwf ICount ;30 second interval, so minute = 2 intervals movf Stack0, W movwf Seconds movlw d'29' subwf Seconds, W btfss STATUS, Z goto Not29 bsf ICount, 0 goto NormICount ;............ Not29 movlw d'59' subwf Seconds, W btfss STATUS, Z goto DoneTime ;Not 29 and not 59 bcf ICount, 0 ;Here at 59 seconds incf ICount ;As we work on the NEXT interval, the value of incf ICount ; ICount needs to be adjusted +2 for Minute +1 NormICount ;Currently, ICount goes from 1 to 2.N movlw RPTTime ; Need to normalise so 2.N count = 0 movwf Temp bcf STATUS, C rlf Temp, W subwf ICount, W btfsc STATUS, Z clrf ICount bsf ICount, 7 ;Bit 7 set indicates NEXT PPS is to be acted on DoneTime return ;-------------------------------------- DoStatus movf RxStatus, W call DebugByte ;Wrap it round for debugging bcf GPSOk movlw b'00001011' ;Mask the GPS status data to give just the andwf RxStatus, W ; bits that show no proper fix then, only btfsc STATUS, Z ; if these are all zero, set GPSOk Flag bsf GPSOk ; WAS b'01001011', now ignores poor geometry flag return ;----------------------------------------- MultTen ;Multiply W x 10 movwf Temp bcf STATUS, C rlf Temp rlf Temp ; *4 addwf Temp ; *5 bcf STATUS, C rlf Temp, W ; *10 return ;---------------------- SendCWMsg ;Enter with EE address programmed into CWMsgCnt movf CWMsgCnt, W call GetEE ;Test for terminator at start = no CW message addlw 0 btfsc STATUS, Z return movlw 0 ;Lead in gap makes initial CW clearer call OnOff call CWDelay call CWDelay call CWDelay call CWDelay CWLoop movf CWMsgCnt, W call GetEE addlw 0 btfsc STATUS, Z goto DoneCWMsg call SendCWChar incf CWMsgCnt goto CWLoop DoneCWMsg call CWDelay call CWDelay call CWDelay call CWDelay return ;-------------------------- SendCWChar ;Sends a single CW character addlw 0xE0 ;Subtract 32 (add 256 - 32) to point to table call CWTable movwf CWChar ;Doesn't affect STATUS so... movf CWChar ; check for invalid returned code here btfsc STATUS , Z goto NoChar movlw 0x07 andwf CWChar , W ;Extract element count into W movwf CWCharCnt movlw 6 subwf CWCharCnt , W ;W = Elcount - 6. If +ve/0 then C=1, > 5 els btfss STATUS , C goto Send5 rrf CWCharCnt ;Puts LSB into C as 110 = . 111 = - call SendEle ;First . or - for 6 element characters movlw 5 movwf CWCharCnt ;Force count to 5 for rest of the elements Send5 rlf CWChar ;Element to be sent into C. call SendEle ; count already in Counter decfsz CWCharCnt goto Send5 NoChar ;Inter word gap, and invalid codes. bcf LEDRed call CWDelay call CWDelay return ;------------------- SendEle ;Data in STATUS , C; 0 = dit 1 = dah rrf Stack0 ;Save C bit temporarily on stack movlw 1 call OnOff bsf LEDRed rlf Stack0 ;Recovery C bit again, to get dot/dash btfss STATUS , C ;test for dot or dash goto SendDot call CWDelay call CWDelay SendDot call CWDelay movlw 0 call OnOff bcf LEDRed call CWDelay ;Inter element gap return ;------------------- CWDelay movlw CWSPEED movwf DelCount2 CWDelLoop call Delay1ms decfsz DelCount2 goto CWDelLoop return ;--------------------------- ;--------------------------- SendRTTYMsg movlw " " call SendRTTYChar movlw " " call SendRTTYChar movlw "R" call SendRTTYChar movlw "Y" call SendRTTYChar movlw "R" call SendRTTYChar movlw "Y" call SendRTTYChar movlw "R" call SendRTTYChar movlw "Y" call SendRTTYChar movlw "R" call SendRTTYChar movlw "Y" call SendRTTYChar movlw "R" call SendRTTYChar movlw "Y" call SendRTTYChar movlw 0x0D call SendRTTYChar movlw 0x0A call SendRTTYChar movlw RTTYMSGOFFSET movwf RttyMsgCnt call GetEE ;Test for terminator at start = no RTTY message addlw 0 ;Sets status flag btfsc STATUS, Z ;Test for null termination character return RttyLoop movf RttyMsgCnt, W call GetEE addlw 0 btfsc STATUS, Z goto DoneRTTYMsg call SendRTTYChar incf RttyMsgCnt goto RttyLoop DoneRTTYMsg ;Insert [cr][lf] to save storing it movlw 0x0D call SendRTTYChar movlw 0x0A call SendRTTYChar movlw 0x0D call SendRTTYChar movlw 0x0A call SendRTTYChar return ;--------------------------- SendRTTYChar ;Sends ASCII data in W as RTTY on serial I/F call BaudoTable ;Convert to RTTY character addlw 0 btfsc STATUS, C ;Test for non printing character return ;And ignore if so movwf RttyChar movlw 0x04 ;Baudot space character subwf RttyChar, W ;Remove all this block if unshift on space btfss STATUS, Z ; is not wanted goto NotSpace movlw 0x1F ;Force Letter shift char every space call RttySend bcf FigFlag goto SendIt ;Now send the space character itself ;........ NotSpace btfsc RttyChar, 7 goto DoFigs ;Test for fig shift btfss FigFlag ;Test if already in fig shift goto SendIt ;Stay unchanged in letter shift bcf FigFlag ;Clear flag if shifted. movlw 0x1F ;Letter shift character call RttySend goto SendIt ;........ DoFigs btfsc FigFlag goto SendIt ;Stay in figure shift if already there bsf FigFlag ;Set flag if not movlw 0x1B ;Fig shift character call RttySend ;.... SendIt movf RttyChar, W call RttySend return ;--------------------------- RttySend movwf RttyBitPatt rlf RttyBitPatt ;Align first bit ready to shift out rlf RttyBitPatt rlf RttyBitPatt movlw 0 call RttyTone ;Start bit bcf LEDRed movlw BAUDCONST call RTTYBaudDel movlw 5 ;Its only a 5 bit code movwf RTTYCharCnt RttySendLoop rlf RttyBitPatt ;bit into C btfsc STATUS , C movlw 1 ; btfss STATUS , C movlw 0 call RttyTone movlw BAUDCONST call RTTYBaudDel ;Baud period = 9 + Delay decfsz RTTYCharCnt goto RttySendLoop movlw 1 call RttyTone ;1.5 StopBits bsf LEDRed movlw BAUDCONST*3/2 call RTTYBaudDel return ;--------------------------- RTTYBaudDel ; Delay N * 500us (+ a few us) movwf DelCount RttyDelLoop1 ; movlw d'249' ;1 movwf DelCount2 ;1 nop ;1 RttyDelLoop2 ;Inner loop alone = 5.N-1 = 1244 nop nop decfsz DelCount2 goto RttyDelLoop2 decfsz DelCount ;1 goto RttyDelLoop1 ;2 return ;--------------------------- RttyTone iorlw 0 ;Test for 0/1 movlw d'18' ;Space TOne = 0 btfsc STATUS, Z movlw d'24' ;Mark Tone = 1 movwf TonePtr movlw 2 movwf DDSAddr call DataTo9852 movlw 0 addwf TonePtr, W call GetEE movwf D5 movlw 1 addwf TonePtr, W call GetEE movwf D4 movlw 2 addwf TonePtr, W call GetEE movwf D3 movlw 3 addwf TonePtr, W call GetEE movwf D2 movlw 4 addwf TonePtr, W call GetEE movwf D1 movlw 5 addwf TonePtr, W call GetEE movwf D0 call DataTo9852 bsf IOUD nop nop bcf IOUD return ;----------------------------------------- InitGPS ;Initialise (Oncore type) GPS to SERIN mode, RMC on movlw "@" call SendByte movlw "@" call SendByte movlw "E" call SendByte movlw "a" call SendByte movlw 0x01 ;Send Position/Status data message every second call SendByte movlw 0x25 ;Checksum "E" XOR "a" XOR 0x01 call SendByte movlw 0x0D ;Terminated with cr/lf call SendByte movlw 0x0A call SendByte return ;_________________________________________ org 0x700 ;Put all routines with tables into last page ;------------------------- ;--------------------------------------- GetRegLen ;gets number of bytes needed for value in DDSAddr movlw HIGH($) movwf PCLATH movf DDSAddr, W addwf PCL dt 2,2,6,6,6,4,3,4,2,2,1,2 ;Number of bytes in each register ;------------------------- ;----------------- DataTo9852 ;Send contents of Dn...D0 to 9852 movf DDSAddr, W call Send9852Byte ;Send the address data call GetRegLen ;Returns with number of bytes to be sent movwf Temp bcf STATUS, C rlf Temp, W sublw d'12' ;W = 12 - 2 * (No of bytes to be sent) addwf PCL ;Jump into byte sending at the right place movf D5, W call Send9852Byte movf D4, W call Send9852Byte movf D3, W call Send9852Byte movf D2, W call Send9852Byte movf D1, W call Send9852Byte movf D0, W call Send9852Byte bcf SDIO ;Rest in low state for min. current consumption return ;------------------------- CWTable ;CW Characters in compressed form. movwf Temp movlw HIGH($) movwf PCLATH movf Temp , W addwf PCL retlw b'00000000' ; [sp] 00 retlw b'00000000' ; ! 00 retlw b'10010110' ; " 96 retlw b'00010101' ; # 15 retlw b'00000000' ; $ 00 retlw b'00000000' ; % 00 retlw b'00000000' ; & 00 retlw b'11110110' ; ' F6 retlw b'10110101' ; ( B5 retlw b'01101111' ; ) 6F retlw b'01000101' ; * 45 retlw b'00000000' ; + 00 retlw b'10011111' ; , 9F Coding for CW characters of up to retlw b'00001111' ; - 0F 6 elements. Stored as : retlw b'10101110' ; . AE Bits 7 to 3 make first five CW elements retlw b'10010101' ; / 95 Reading Left to Right retlw b'11111101' ; 0 FD Coded as 0 = dit 1 = dah retlw b'01111101' ; 1 7D Bts 2-0 are number of elements except for retlw b'00111101' ; 2 3D 110 > 1st element is a dit retlw b'00011101' ; 3 1D 111 > 1st element is a dah retlw b'00001101' ; 4 0D retlw b'00000101' ; 5 05 retlw b'10000101' ; 6 85 retlw b'11000101' ; 7 C5 retlw b'11100101' ; 8 E5 retlw b'11110101' ; 9 F5 retlw b'00000000' ; : 00 retlw b'00000000' ; ; 00 retlw b'00000000' ; < 00 retlw b'10001101' ; = 8D retlw b'00000000' ; > 00 retlw b'01100110' ; ? 66 retlw b'11010110' ; @ D6 retlw b'01000010' ; A 42 retlw b'10000100' ; B 84 retlw b'10100100' ; C A4 retlw b'10000011' ; D 83 retlw b'00000001' ; E 01 retlw b'00100100' ; F 24 retlw b'11000011' ; G C3 retlw b'00000100' ; H 04 retlw b'00000010' ; I 02 retlw b'01110100' ; J 74 retlw b'10100011' ; K A3 retlw b'01000100' ; L 44 retlw b'11000010' ; M C2 retlw b'10000010' ; N 82 retlw b'11100011' ; O E3 retlw b'01100100' ; P 64 retlw b'11010100' ; Q D4 retlw b'01000011' ; R 43 retlw b'00000011' ; S 03 retlw b'10000001' ; T 81 retlw b'00100011' ; U 23 retlw b'00010100' ; V 14 retlw b'01100011' ; W 63 retlw b'10010100' ; X 94 retlw b'10110100' ; Y B4 retlw b'11000100' ; Z C4 ;------------------------------- BaudoTable ;No lower case allowed to save space movwf Temp bcf Temp, 7 ;Clear msb just in case movlw HIGH($) movwf PCLATH movlw 0x0A subwf Temp , W ;W = Char - 0x0A, points at start of table addwf PCL ;All characters transmitted left to right. ie B4 >> B0 retlw 0x08 ; [LF] Ascii 0x0A retlw 0x00 ; All unprintable characters return 00 retlw 0x00 ; retlw 0x02 ; [CR] 0x0D retlw 0x00 ; retlw 0x00 ; dt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;Other unused control characters retlw 0x04 ; [SP] Ascii d'32' retlw 0x96 ; ! retlw 0x00 ; " retlw 0x85 ; # retlw 0x92 ; $ retlw 0x00 ; % retlw 0x8B ; & retlw 0x00 ; ' retlw 0x9E ; ( retlw 0x89 ; ) retlw 0x00 ; * retlw 0x00 ; + retlw 0x86 ; , retlw 0x98 ; - retlw 0x87 ; . retlw 0x97 ; / retlw 0x8D ; 0 Ascii d'48' retlw 0x9D ; 1 retlw 0x99 ; 2 retlw 0x90 ; 3 retlw 0x8A ; 4 retlw 0x81 ; 5 retlw 0x95 ; 6 retlw 0x9C ; 7 retlw 0x8C ; 8 retlw 0x83 ; 9 retlw 0x8E ; : retlw 0x8F ; ; retlw 0x00 ; < retlw 0x00 ; = retlw 0x00 ; > retlw 0x93 ; ? retlw 0x00 ; @ Ascii d'64' retlw 0x18 ; A retlw 0x13 ; B retlw 0x0E ; C retlw 0x12 ; D retlw 0x10 ; E retlw 0x16 ; F retlw 0x0B ; G retlw 0x05 ; H retlw 0x0C ; I retlw 0x1A ; J retlw 0x1E ; K retlw 0x09 ; L retlw 0x07 ; M retlw 0x06 ; N retlw 0x03 ; O retlw 0x0D ; P Ascii d'80' 0x50 retlw 0x1D ; Q retlw 0x0A ; R retlw 0x14 ; S retlw 0x01 ; T retlw 0x1C ; U retlw 0x0F ; V retlw 0x19 ; W retlw 0x17 ; X retlw 0x15 ; Y retlw 0x11 ; Z Gets right to end of segment ;---------------------------- cblock 0x20 Temp DelCount DelCount2 IntCountLo IntCountHi Counter IntCounter ; CharCount ;Counts 0 to 63 Symbols in message SymbCount ;Counts 0 to 126, symbols in sequence DDSAddr Flags Wreg SaveSts Seconds Minutes ICount CommaCount CWChar CWMsgCnt CWCharCnt RttyMsgCnt RttyChar RttyBitPatt RTTYCharCnt TonePtr SerCounter ;Count of characters on GPS serial data RxStatus ;GPS Receiver status D0 ;D data sent to DDS registers D1 D2 D3 D4 D5 A0 ;Ax and Bx inputs to maths routines A1 A2 A3 A4 A5 B0 B1 B2 B3 B4 B5 ;Accx output from maths routines Acc0 Acc1 Acc2 Acc3 Stack0 ;Holds shifted Tone / Sync PRN Stack1 Stack2 Stack3 Stack4 Stack5 Stack6 Stack7 Stack8 Stack9 StackA StackB StackC StackD StackE StackF endc ;========================================== end