#---------------------------------------
# Raspberry Pi Pico
# WSPR TX locked by GPS, by J.J.Leijssen
# most simple version for Raspberry Pi Pico, a Chinese DDS with AD9851 and a ATGM336H GPS Module
# WARNING!!! harmonics of the DDS will interfere with the GPS module, keep physical distance between modules
# 7/8 dec. 2021 extra test added foor locking GPS module
#---------------------------------------
from machine import UART, Pin
import utime, sys, time
import genwsprcode as g

#---------------------------------------
# init hardware
#---------------------------------------
uart1 = UART(1, baudrate=9600, tx=Pin(8), rx=Pin(9)) # board 11, 12
# uart0 = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))
led   = Pin(25, Pin.OUT)
W_CLK = Pin(10, Pin.OUT)
DATA  = Pin(11, Pin.OUT)
FQ_UD = Pin(12, Pin.OUT)
RESET = Pin(13, Pin.OUT)
TX_PIN = Pin(15, Pin.OUT) # use to disable TX
#---------------------------------------
# init software variables
#---------------------------------------
callsign = "pa1w"
grid = "jo21"
power = "23"
idle = 2 # idle time in min (must be an even value) between wspr messages

frequency = ["14097005","10140105","14097155","10140255","14097015","10140115","14097165","10140265"]
freqIdle = "30000000" # to prevent drifting, set DDS to out-of-band frequency
ppt = 0
freq_shift = 12000/8192
bit_time = 0.683
tx_delay = 0.100
offset = -2200 # global x-tal correction 40 = 5 Hz

WORD1='00000001'#W0 multiplier6x, power up
WORD0='00000101'#W0 power down, multiplier6x

#---------------------------------------
# coded message "PA1W JO21 23", the 162 symbols are created with an external program
#---------------------------------------
# Now using genwsprcode.py

#---------------------------------------
# reset hardware
#---------------------------------------
def reset():
    RESET.high()
    RESET.low()
    W_CLK.high()
    W_CLK.low()
    FQ_UD.high()
    FQ_UD.low()
    led.toggle()
    TX_PIN.low()
    return()

#---------------------------------------
# controll the DDS
#---------------------------------------
def AD9851(tunef,WORD,symbx):
    freq = int(tunef)
    if freq > 70000000:
        print('AD9851: frequency must be lower than 70 MHz',file=sys.stderr) 
        sys.exit(-1)
    fsk=symbx*freq_shift #frequency shift key
    freq_word_int=int((freq+fsk)*(2**32)/(6*30e6+offset)) ##6xrefclock turned on in WORD0 
    FREQWORD='{0:032b}'.format(freq_word_int)
    SERIALWORD=WORD+FREQWORD
    for i in range(39,-1,-1):
        W_CLK.low()
        if int(SERIALWORD[i]):
            DATA.high()
        W_CLK.high()
        DATA.low()
        W_CLK.low()
    FQ_UD.high()
    FQ_UD.low()
    return()

#---------------------------------------
# initiate the transmit sequence
#---------------------------------------
def wsprTx():
    global ppt
    TX_PIN.high()
    for x in symbols: #modulate the symbols
        AD9851(frequency[ppt],WORD1,int(x))
        utime.sleep(bit_time)
    TX_PIN.low()
    AD9851(freqIdle,WORD1,0) # not power down, keep temperature
    #reset()
    ppt += 1
    ppt &= 0x7
    return()
    
#---------------------------------------
# Main program
#---------------------------------------
reset()
AD9851(freqIdle,WORD1,0) # heating up DDS
# generate the code
symbols=g.Genwsprcode(callsign,grid,power)
symbols=symbols.rstrip(',')
symbols=symbols.split(',')
print(symbols)

print("Start wspr secuence, wait for GPS next TX window.....")
wait = idle//2
while True:
    rxData = bytes()
    while uart1.any() > 0:
        rxData += uart1.readline()
        led.toggle()
        try:
            str1 = rxData.decode('ascii')
        except UnicodeError: # prevent stopping if GPS not in lock
            rxData = bytes()
            print("Er1 ",end='')
            time.sleep(2)
            continue
        # print(str1)
        if str1.startswith("$GNZDA"): # pick time        
            try:
                strxx = int(str1[9:11])
            except ValueError: # prevent stopping if GPS not in lock
                rxData = bytes()
                print(".",end='')
                continue
                    
            minute = int(str1[9:11])
            second = int(str1[11:13])
            if (minute % 2 == 0)  and (second == 0): # if 137kHz on air => and (minute % 10 != 4):
                if wait == 0:
                    print("Tx busy, GMT time is %s:%s:%s" % (str1[7:9],str1[9:11],str1[11:13]))
                    wsprTx()
                    wait = idle//2
                    print("Done, next Tx => ",int(str1[9:11])+2*idle)
                else:
                    wait -= 1
        rxData = bytes()
   
# $GNZDA,214356.000,10,03,2021,00,00*4C <= filters UTC clock string, occurs once per second
