import time
import hackrf
import random
import datetime
import RXTools as rx
import signal
import os
import threading
import sys
import numpy as np
from collections import OrderedDict
import serial
import random

# Where we will save power data
#powerLogDir = '/media/drive1/Jam/Data'
powerLogDir = 'Data'

# Define the hack RFs
devices = [ {'ID':'0000000000000000a06063c824237e5f','cal':0},
            {'ID':'0000000000000000675c62dc326331cf','cal':0},
            {'ID':'0000000000000000675c62dc300764cf','cal':7} ] # Why is this HackRF down?
numDevices = len(devices)

# Jam pattern enumerations
dFastPulse3xL1     = 0
dFastPulse1xL1     = 1
dFastPulseRamp1xL1 = 2
dConstCW3xGPSL1    = 3
dConstCW3xL1       = 4
dSlowPulse1xL1     = 5
dCWRampL1L2L5      = 6
dConstCWL1L2L5     = 7
dSlowPulseL1L2L5   = 8
dCycleTestL1       = 9
dFastPulseRamp3xL1 = 10
dTripleCarrRamp   = 11
dTripleCarrRampWide   = 12
dTripleCarrPulsedRampWide   = 13
dCycleTestL1_0dBm   = 14
dSlowFastPulseL1    = 15
dSlowPulse3xL1   = 16
d2MHzGaussianRamp3xL1 = 17
d2MHzGaussianRampL1L2L5 = 18
dSlowPulse1xL1LowPower     = 21
dSlowChirpRamp = 22
dSlowChirpFreqRamp = 23
dSlowChirpFreqRampL1L2L5 = 24
dSlowChirpRampL1L2L5 = 25
dCycleTestNarrowL1_0dBm   = 26
dCycleTestNarrowL1_Neg15dBm   = 27
dSlowPulse1xL1wRamp     = 28
dCWRampL1      =29 
dSlowPulseCWwPseudoIridiumL1 = 30
dSlowPulseCWwPseudoIridiumL1V2 = 31
dSlowPulse1xL5     = 32
dBulgarianSlowPulseE6 = 33
dBulgarianSlowPulseL2 = 34
dCarrRampWideWithTwoL1CW = 35
dCarrRampWide1587WithTwoL1CW = 36
dDHSL1 = 37
dCarrRamp1585_5dBm = 38
dCarrRamp1567_5dBm = 39
dCarrRamp1575_5dBm = 40
d2MHzGaussianRamp3xL1Atten = 41
d2MHzGaussianRampL1L2L5Atten = 42
dSlowPulse3xL1LowerPow   = 43
dGlobalStar = 44
dHeavyChirpMulti = 45
dPrimaryL1SecondaryL2L5 = 46
dOverlappingL1CW = 47

# Used to control the Ctrl-C program termination
ThreadingActive = False
# Handle for each HackRF
hackRFHandle = [{}] * numDevices
deviceJamType = [None] * numDevices

def signal_handler(signal,frame):
  global ThreadingActive
  print('Ctrl+C Detected - shutting down ...')
  ThreadingActive = False

  for num in range(3):
    threadHandle[num].join()

  sys.exit(0)


def init_hackrf1_atten():
  """Turn off buzzer"""
  ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=1)
  time.sleep(1)
  ret = ser.write(b'*BUZZER OFF\n')
  time.sleep(1)

def set_hackrf1_atten(atten_dB):
  """Set attenuator loss to 'atten_dB'. Attenuator is only in
  series with hackrf 0000000000000000a06063c824237e5f"""
  ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=1)
  time.sleep(1)
  tmp = 'ATT ' + "{atten:.1f}".format(atten=atten_dB) + '\n'
  ret = ser.write(tmp.encode())
  print(datetime.datetime.now().isoformat()," attenuator:",ret,tmp,end='')


#freqList = [1577.42, 1573.42, 1593,     1588,   1563.0,  1581,     1605]
#freqList = [1176.45, 1297.14, 1202.025, 1185,   1177.45, 1191.795, 1180.45,1199,1186.45,1190.795]
#freqList = [1227.6,  1242.9,  1228.6,   1248.6, 1229.6,  1235.1247, 1240]


# We keep track of which frequency was output as a diagnostic to 
# help with post-processing
lastFreq = [0] * numDevices
lastPower = [0] * numDevices

def logPower(index, freq, power, jamType, first=False):
  global lastFreq
  global lastPower

  # Now capture the time to a file
  gpsEpoch = datetime.datetime(1980,1,6)

  # Get the time adjusted for the current leap seconds
  leapSecs = 18
  now = datetime.datetime.utcnow() + datetime.timedelta(seconds=leapSecs)
    
  # Get the GPS time
  gpsTime  = now - gpsEpoch
  week    = int((gpsTime.total_seconds())/(86400*7))
  gpsSecs = gpsTime.total_seconds() - week*86400*7

  if powerLogDir:
    with open(powerLogDir + '/Source' + str(index) + '-' + str(now.year) + '-' + str(now.month).zfill(2) + '-' + str(now.day).zfill(2) + '.txt','a') as fid:
      #print(index, first, lastFreq[index], freq,power,jamType)
      # Indicate we are switching off the last frequency
      if(first == False):
          if( (lastFreq[index] > 1000) and (lastFreq[index] < 2000) ):
              fid.write("%d %.1f %.3f %.2f %d\n" % (week,gpsSecs,lastFreq[index],lastPower[index],jamType))

          if( (freq < 1000) or (freq > 2000) ):
              # Indicate an off condition - helps with pen up when plotting
              fid.write("%d %.1f Nan Nan %d\n" % (week,gpsSecs,jamType))

      # Indicate we are enabling a new freq
      if( (freq > 1000) and (freq < 2000) ):
          fid.write("%d %.1f %.3f %.2f %d\n" % (week,gpsSecs,freq,power,jamType))

  lastFreq[index]  = freq
  lastPower[index] = power

def initAllHackRF(jamType):
    for num in range(numDevices):
        if(deviceJamType[num] != jamType):
            setupHackRF(num,jamType,-30)

def initHackRF(jamType, num):
    if(deviceJamType[num] != jamType):
        setupHackRF(num,jamType,-30)

def setupHackRF(index,jamType,power):
    global hackRFHandle
    global deviceJamType

    freq = 5000
    #freq = 250
    # Connect to the HackRF One
    if hackRFHandle[index] != {}:
         print("Shutting down hackRF %d"%index)
         hackRFHandle[index].stop()
         hackRFHandle[index].wait()
         hackRFHandle[index] = {}

    print("Connecting to hackRF %d"%index)
    hackRFHandle[index] = hackrf.device_connect(devices[index]['ID'],jamType)
    hackRFHandle[index].start()
    hackRFHandle[index].turn_signal_on(freq, power)
    hackRFHandle[index].set_freq(freq)
    deviceJamType[index] = jamType

def setSynth(index,freq,power,jamType):
    global hackRFHandle

#    if(configSynth):
#        setupHackRF(index,'CW',power)

    # Set the frequency
    if(lastFreq[index] != freq):
        print('Call HackRF(Freq) = ',freq)
        hackRFHandle[index].set_freq(freq)
    
    # Handle the HackRF power calibration
    localPower = power + devices[index]['cal']
    if(localPower > 7):
      localPower = 7
    elif(localPower < -30):
      localPower = -30
 
    thisPower = localPower - devices[index]['cal']
    logPower(index, freq, thisPower,jamType)

    #print('Power[%d]:%.1f' % (index,power))
    # Set the power
    #if(lastPower[index] != thisPower):
    #    print('Setting power',index,localPower)
    #    hackRFHandle[index].set_power(localPower)
    print('Call HackRF(power) = ',localPower)
    hackRFHandle[index].set_power(localPower)

def constCW(index,freq,power,jamType):
    setSynth(index,freq,power,jamType)
    count = 0
    while(ThreadingActive):
        time.sleep(1)
        count += 1
        # Unless we call logPower, we won't output any data
        # to the scenario log. The analytics checks for a 
        # constant scenario number for each hour. Unless we
        # periodically write something, the scripts won't
        # detect the system was jammed.
        if(count == 600):
            logPower(index, freq, power, jamType)
            count = 0

def rampCW(index,freq,jamType):
    power = -30
    direction = 1
    setSynth(index,freq,power,jamType)

    while(ThreadingActive):
        # Delay for 10s before we ramp the power
        for i in range(10):
            if(ThreadingActive):
                time.sleep(1)

        if(direction == 1):
            if(power < 7):            
                power += 1
            else:
                direction = -1
                power -=1
        elif(direction == -1):          
            if(power > -30):            
                power -= 1
            else:
                direction = 1
                power +=1

        # Adjust the power
        print('Adjust [%d] = %d' % (index,power))
        setSynth(index,freq,power,jamType)


def rampFastPulse(index,freq,jamType):
    power = -30
    direction = 1
    setSynth(index,freq[0],power,jamType)

    while(ThreadingActive):
        for thisFreq in freq:
            delay = 1.5
            print("FastRamp:",index,thisFreq,power,jamType)
            setSynth(index,thisFreq,power,jamType)
        
            now = datetime.datetime.now() + datetime.timedelta(seconds=delay)
            while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                time.sleep(0.1)

            # Off
            if(ThreadingActive):
                setSynth(index,5000,power,jamType)
                time.sleep(0.5)

        if(direction == 1):
            if(power < 7):            
                power += 1
            else:
                direction = -1
                power -=1
        elif(direction == -1):          
            if(power > -30):            
                power -= 1
            else:
                direction = 1
                power +=1

        # Adjust the power
        print('Adjust [%d] = %d' % (index,power))
        print("FastRamp-power:",index,thisFreq,power,jamType)
        setSynth(index,thisFreq,power,jamType)


def cycleTestL1(index,power,jamType):
    setSynth(index,5000,power,jamType)

    while(ThreadingActive):
        #for thisFreq in range(1530,1650):
        for thisFreq in range(1575,1630):

            # On for a minute
            setSynth(index,thisFreq,power,jamType)
            now = datetime.datetime.now() + datetime.timedelta(seconds=60)
            while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                time.sleep(0.1)

            # Off for a minute
            setSynth(index,5000,power,jamType)
            now = datetime.datetime.now() + datetime.timedelta(seconds=60)
            while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                time.sleep(0.1)

def cycleTestNarrowL1(index,power,jamType):
    setSynth(index,5000,power,jamType)

    while(ThreadingActive):
        thisFreq = 1573.4
        while(thisFreq <= 1577.4):

            # On for a minute
            setSynth(index,thisFreq,power,jamType)
            now = datetime.datetime.now() + datetime.timedelta(seconds=60)
            while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                time.sleep(0.1)

            # Off for a minute
            setSynth(index,5000,power,jamType)
            now = datetime.datetime.now() + datetime.timedelta(seconds=60)
            while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                time.sleep(0.1)

            thisFreq += 0.02


#    while(ThreadingActive and ((now + dwell - datetime.datetime.now()).total_seconds() > 0)):
#      print(index,(now + dwell - datetime.datetime.now()).total_seconds())
#      time.sleep(1)



def rampTest(index,power,start,stop,step,jamType):
    setSynth(index,5000,power,jamType)

    while(ThreadingActive):
        thisFreq = start
        while(thisFreq <= stop):

            # On for a minute
            setSynth(index,thisFreq,power,jamType)
            now = datetime.datetime.now() + datetime.timedelta(seconds=60)
            while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                time.sleep(0.1)

            # Off for a minute
            setSynth(index,5000,power,jamType)
            now = datetime.datetime.now() + datetime.timedelta(seconds=60)
            while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                time.sleep(0.1)

            thisFreq += step



def slowFastPulseCW(index,slowFreqs,fastFreqs,jamType):
    power = 0
    setSynth(index,slowFreqs[0],power,jamType)
    
    print('Start Slow/Fast PulseCW loop')
    while(ThreadingActive):
        for thisFreq in slowFreqs:
            delay = random.uniform(55,65)
            print('Jam',thisFreq,power,delay)
            setSynth(index,thisFreq,power,jamType)
        
            now = datetime.datetime.now() + datetime.timedelta(seconds=delay)
            while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                time.sleep(0.1)

            # Off
            if(ThreadingActive):
                print('Jam - Disable synth')
                setSynth(index,5000,power,jamType)
                time.sleep(5)

        # Now the fast pulses
        for loops in range(20):
            for thisFreq in fastFreqs:
                if(ThreadingActive):
                    setSynth(index,thisFreq,power,jamType)
                    time.sleep(1.5)
                    setSynth(index,5000,power,jamType)
                    time.sleep(0.5)




def slowPulsewithFastCW(index,freq,power,jamType,fastDelay):
    setSynth(index,freq[0],power,jamType)
    
    print('Start SlowPulseCW with fast CW loop')
    while(ThreadingActive):
        for thisFreq in freq:
            if(ThreadingActive == False):
                break

            # The slow pulse
            if(index == 0):
                delay = random.uniform(55,65)
                print('Jam',thisFreq,power,delay)
                setSynth(index,thisFreq,power,jamType)
        
                now = datetime.datetime.now() + datetime.timedelta(seconds=delay)
                while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                    time.sleep(0.1)

                # Off
                if(ThreadingActive):
                    print('Jam - Disable synth')
                    setSynth(index,5000,power,jamType)
                    time.sleep(45)
            else: 
                # The Fase pulse
                setSynth(index,thisFreq,power,jamType)
                time.sleep(fastDelay)




def slowPulseCW(index,freq,power,jamType):
    setSynth(index,freq[0],power,jamType)
    
    print('Start SlowPulseCW loop')
    while(ThreadingActive):
        for thisFreq in freq:
            delay = random.uniform(55,65)
            print('Jam',thisFreq,power,delay)
            setSynth(index,thisFreq,power,jamType)
        
            now = datetime.datetime.now() + datetime.timedelta(seconds=delay)
            while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                time.sleep(0.1)

            # Off
            if(ThreadingActive):
                print('Jam - Disable synth')
                setSynth(index,5000,power,jamType)
                time.sleep(5)


def slowPulseCWwRamp(index,freq,jamType):
    power = -30
    direction = 1
    setSynth(index,freq,power,jamType)
    
    print('Start SlowPulseCW loop')
    while(ThreadingActive):
        delay = random.uniform(55,65)
        print('Jam',freq,power,delay)
        setSynth(index,freq,power,jamType)
        
        now = datetime.datetime.now() + datetime.timedelta(seconds=delay)
        while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
            time.sleep(0.1)

        # Off
        if(ThreadingActive):
            print('Jam - Disable synth')
            setSynth(index,5000,power,jamType)
            time.sleep(5)

        if(direction == 1):
            if(power < 7):            
                power += 1
            else:
                direction = -1
                power -=1
        elif(direction == -1):          
            if(power > -30):            
                power -= 1
            else:
                direction = 1
                power +=1


def fastPulseCW(index,freq,power,jamType,off,delay):
    setSynth(index,freq[0],power,jamType)

    print(index,ThreadingActive)
    while(ThreadingActive):
        for thisFreq in freq:
            setSynth(index,thisFreq,power,jamType)
        
            if(delay > 0.1):
                now = datetime.datetime.now() + datetime.timedelta(seconds=delay)
                while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                    time.sleep(0.1)
            else:
                time.sleep(delay)

            # Off
            if(ThreadingActive and off > 0.0):
                setSynth(index,5000,power,jamType)
                time.sleep(off)

def rampTripleCarr(index,freq,pulsed,jamType):
    power = -30
    direction = 1
    setSynth(index,freq,power,jamType)

    while(ThreadingActive):
        if(direction == 1):
            if(power < 7):
                power += 1
            else:
                direction = -1
                power -=1
        elif(direction == -1):
            if(power > -30):
                power -= 1
            else:
                direction = 1
                power +=1

        if(pulsed == False):
            now = datetime.datetime.now() + datetime.timedelta(seconds=60)
            while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                time.sleep(0.1)
            # Adjust the power
            print('Adjust [%d] = %d' % (index,power))
            print("FastRamp-power:",index,freq,power,jamType)
            setSynth(index,freq,power,jamType)
        else:
            # Simulate a slow pulse, e.g. a radar

            # 10 loops at this power ~120s
            for loop in range(10):
              if(ThreadingActive):
                # 3 seconds on
                setSynth(index,freq,power,jamType)
                now = datetime.datetime.now() + datetime.timedelta(seconds=3)
                while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                    time.sleep(0.1)

                # 9 seconds off
                if(ThreadingActive):
                    setSynth(index,250,power,jamType)
                    now = datetime.datetime.now() + datetime.timedelta(seconds=9)
                    while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                        time.sleep(0.1)


def globalStar(index, jamType):

    while(ThreadingActive):
      for modulation in range(2):
          if(modulation == 0):
              # Bottom of the band is 1610, as we are outputting
              # a 2MHz signal, center it at 1611MHz
              globalStarFreq = 1611
              initHackRF('GAUSSIAN_RFI_2MHz', 0)
              #setSynth(index,globalStarFreq,-30,jamType)
          else:
              # Bottom of the band is 1610, as we are outputting
              # a 5MHz signal, center it at 1612.5MHz
              globalStarFreq = 1612.5
              initHackRF('GAUSSIAN_RFI_5MHz', 0)
              #setSynth(index,globalStarFreq,-30,jamType)
          
          # 2MHz steps
          for offset in range(0,12,2):
              for step in range(-30,8):
                  setSynth(index,globalStarFreq + offset,step,jamType)
                  now = datetime.datetime.now() + datetime.timedelta(seconds=3)
                  while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                      time.sleep(0.1)
                  
              # A little recovery time
              setSynth(index,5000,-30,jamType)
              now = datetime.datetime.now() + datetime.timedelta(seconds=15)
              while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                  time.sleep(0.1)
                  
              # Now some 5s pulses - this is the length of transmission
              # Deere observed from an irrigation system
              for thisPower in [-16,-5,7]:
                  for pulses in range(10):
                      setSynth(index,globalStarFreq + offset,thisPower,jamType)
                      now = datetime.datetime.now() + datetime.timedelta(seconds=5)
                      while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                          time.sleep(0.1)
                      setSynth(index,5000,thisPower,jamType)
                      now = datetime.datetime.now() + datetime.timedelta(seconds=3)
                      while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                          time.sleep(0.1)
    
                      if(ThreadingActive == False):
                          return
                  
              # A little recovery time
              setSynth(index,5000,-30,jamType)
              now = datetime.datetime.now() + datetime.timedelta(seconds=15)
              while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                  time.sleep(0.1)

def heavyMulti(index, jamType):
    while(ThreadingActive):
        for thisCNo in range(-30,7):
            for i in range(15):
                if(index == 0):
                    freqList = [1575.42, 1601.5 , 1227.6,   1561.098, 1176.45, 1207.14, 1191.795]
                elif(index == 1):
                    freqList = [1176.45, 1207.14, 1191.795, 1575.42, 1601.5 , 1561.098, 1227.6  ]
                else:
                    freqList = [1268.52, 1278.75]

                for thisFreq in freqList:
                    setSynth(index,thisFreq,thisCNo,jamType)
                    time.sleep(0.1)

                    if(ThreadingActive == False):
                        return

        setSynth(index,5000,-30,jamType)
        # Recovery time
        now = datetime.datetime.now() + datetime.timedelta(seconds=5)
        while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
            time.sleep(0.1)


def rampChirp(index,freq,jamType):
    power = -30
    direction = 1
    setSynth(index,freq,power,jamType)
    print('Start Chirp')

    while(ThreadingActive):
        # Delay for 10s before we ramp the power
        for i in range(10):
            if(ThreadingActive):
                time.sleep(1)

        if(direction == 1):
            if(power < 7):
                power += 1
            else:
                direction = -1
                power -=1
        elif(direction == -1):
            if(power > -30):
                power -= 1
            else:
                direction = 1
                power +=1

        # Adjust the power
        print('Adjust [%d] = %d' % (index,power))
        setSynth(index,freq,power,jamType)

def rampGaussian(index,freq,jamType):
    power = -30
    direction = 1
    setSynth(index,freq,power,jamType)

    while(ThreadingActive):
        # Delay for 10s before we ramp the power
        for i in range(10):
            if(ThreadingActive):
                time.sleep(1)

        if(direction == 1):
            if(power < 7):
                power += 1
            else:
                direction = -1
                power -=1
        elif(direction == -1):
            if(power > -30):
                power -= 1
            else:
                direction = 1
                power +=1

        # Adjust the power
        print('Adjust [%d] = %d' % (index,power))
        setSynth(index,freq,power,jamType)

def rampGaussianWithAtten(index,freq,jamType):
    atten_index = 0
    if index == atten_index:
        # attenuator is only hooked up to index 0
        lowest_power = -50
    else:
        lowest_power = -30
    power = lowest_power
    direction = 1
    setSynth(index,freq,power,jamType)

    while(ThreadingActive):
        # Delay for 5s before we ramp the power
        for i in range(5):
            if(ThreadingActive):
                time.sleep(1)

        if(direction == 1):
            if(power < 7):
                power += 1
            else:
                direction = -1
                power -=1
        elif(direction == -1):
            if(power > lowest_power):
                power -= 1
            else:
                direction = 1
                power +=1

        # Adjust the power
        if index == atten_index:
            if power >= -30:
                atten_dB = 0
                synth_power = power
            else:
                atten_dB = -30 - power
                synth_power = -30
            print('Adjust [%d] = atten=%d synth=%d' % (index,atten_dB,synth_power))
            set_hackrf1_atten(atten_dB)
            setSynth(index,freq,synth_power,jamType)
        else:
            print('Adjust [%d] = %d' % (index,power))
            setSynth(index,freq,power,jamType)

def jammerOffQuick():
    for num in range(numDevices):
        setupHackRF(num,'CW',-30)

    # Turn off the jammer
    for index in range(numDevices):
        setSynth(index,5000,-30,-1)
    # Turn off attenuation
    set_hackrf1_atten(0)

def jammerOff(num,delay=300):
    # Turn off the jammer
    jammerOffQuick()

    # Starting the test on the hour makes the analysis easier.
    # Wait here for the next hour roll (adjusting for the 18s 
    # leapsecond). We want some recovery time. If we are too close
    # to the hour roll, recover for a full hour + the current
    # time to the roll.
    now = datetime.datetime.now()
    delta = datetime.timedelta(hours=1)
    next_hour = (now + delta).replace(microsecond=0, second=18, minute=0)
    wait_seconds = (next_hour - now).seconds

    if(wait_seconds < delay):
        print('Bumping to the next hour')
        next_hour += delta

    # Could likely just sleep as the clock should be accurate ... just in case
    while((next_hour - datetime.datetime.now()).total_seconds() > 0):
        time.sleep(1)



def killThreads(numThreads):
  global ThreadingActive
  ThreadingActive = False
  # Thread's killed
  for num in range(numThreads):
    threadHandle[num].join()
    #print('Turning off',num)
    #hackRFHandle[num].turn_signal_off()
    #print('Stopping',num)
    #hackRFHandle[num].stop()
    #print('Waiting',num)
    #hackRFHandle[num].wait()
    #print('Done',num)



def testCase8():
    global ThreadingActive
    global threadHandle
    # Ramped power CW jamming on each band for an hour
    print('Slow pulse all bands only')
    initAllHackRF('CW')
    ThreadingActive = True
    for num in range(numDevices):
        # There are a different number of frequencies for each band, so the phasing of the
        # jamming on each band will change over time
        if(num == 0):
            freqList = [1577.42, 1573.42, 1593, 1588, 1563.0, 1581, 1605]
        elif(num == 1):
            freqList = [1176.45, 1297.14, 1202.025, 1185, 1177.45, 1191.795, 1180.45,1199,1186.45,1190.795]
        else:
            freqList = [1227.6,  1242.9, 1228.6, 1248.6, 1229.6, 1235.1247, 1240]
        t = threading.Thread(target=slowPulseCW, args=(num,freqList,0,dSlowPulseL1L2L5))
        threadHandle.append(t)
        t.start()
    time.sleep(JamTest)
    killThreads(3)
    threadHandle = []

    jammerOff(3)



def testCase30():
    global ThreadingActive
    global threadHandle
    # Ramped power CW jamming on each band for an hour
    print('Slow pulse all bands only')
    initAllHackRF('CW')
    ThreadingActive = True
    for num in range(numDevices):
        # There are a different number of frequencies for each band, so the phasing of the
        # jamming on each band will change over time
        if(num == 0):
            freqList = [1576.42, 1601, 1574.75, 1598.1,  1560.098, 1573.42, 1575.42]
        elif(num == 1):
            freqList = np.arange(1624, 1626, 0.04167).tolist()
            random.seed(12345)  
            random.shuffle(freqList)
        else:
            freqList = np.arange(1624, 1626, 0.04167).tolist()
            random.seed(31415)  
            random.shuffle(freqList)

        t = threading.Thread(target=slowPulsewithFastCW, args=(num,freqList,0,dSlowPulseCWwPseudoIridiumL1,0.05))
        threadHandle.append(t)
        t.start()
    time.sleep(JamTest)
    killThreads(3)
    threadHandle = []

    jammerOff(3)



def testCase31():
    global ThreadingActive
    global threadHandle
    # Ramped power CW jamming on each band for an hour
    print('Slow pulse all bands only')
    initAllHackRF('CW')
    ThreadingActive = True
    for num in range(numDevices):
        # There are a different number of frequencies for each band, so the phasing of the
        # jamming on each band will change over time
        if(num == 0):
            freqList = [1576.42, 1601, 1574.75, 1598.1,  1560.098, 1573.42, 1575.42]
        elif(num == 1):
            # freqList1 does the most damage to GPS due to 50MHz alias
            freqList1 = np.arange(1624, 1626, 0.04167).tolist()
            # Add the same number of elements across the rest of the band
            freqList2 = np.arange(1616, 1626.5, (1626.5-1616) / len(freqList1)).tolist()
            freqList = freqList1 + freqList2
            random.seed(12345)  
            random.shuffle(freqList)
        else:
            # freqList1 does the most damage to GPS due to 50MHz alias
            freqList1 = np.arange(1624, 1626, 0.04167).tolist()
            # Add the same number of elements across the rest of the band
            freqList2 = np.arange(1616, 1626.5, (1626.5-1616) / len(freqList1)).tolist()
            freqList = freqList1 + freqList2
            random.seed(31415)  
            random.shuffle(freqList)

        t = threading.Thread(target=slowPulsewithFastCW, args=(num,freqList,0,dSlowPulseCWwPseudoIridiumL1V2,0.02))
        threadHandle.append(t)
        t.start()
    time.sleep(JamTest)
    killThreads(3)
    threadHandle = []
    jammerOff(3)


def testCase33():
    global ThreadingActive
    global threadHandle
    # Ramped power CW jamming on each band for an hour
    print('Bulgarian jamming in E6')
    initAllHackRF('CW')
    ThreadingActive = True
    for num in range(numDevices):
        # freqList1 does the most damage to GPS due to 50MHz alias
        if(num == 0):
            freqList = np.arange(1294, 1295, 0.001).tolist()
        elif(num == 1):
            freqList = np.arange(1279, 1280, 0.001).tolist()
        elif(num == 2):
            freqList = np.arange(1275, 1276, 0.001).tolist()
        random.seed(234 * num)  
        random.shuffle(freqList)
        t = threading.Thread(target=fastPulseCW, args=(num,freqList,0,dBulgarianSlowPulseE6,0.0,0.02))
        threadHandle.append(t)
        t.start()
    time.sleep(JamTest)
    killThreads(3)
    threadHandle = []
    jammerOff(3)


def testCase34():
    global ThreadingActive
    global threadHandle
    # Ramped power CW jamming on each band for an hour
    print('Bulgarian jamming in L2')
    initAllHackRF('CW')
    ThreadingActive = True
    for num in range(numDevices):
        if(num == 0):
            freqList = np.arange(1248, 1249, 0.001).tolist()
        elif(num == 1):
            freqList = np.arange(1238, 1239, 0.001).tolist()
        elif(num == 2):
            freqList = np.arange(1229, 1230, 0.001).tolist()
        random.seed(234 * num)  
        random.shuffle(freqList)
        t = threading.Thread(target=fastPulseCW, args=(num,freqList,0,dBulgarianSlowPulseL2,0.0,0.02))
        threadHandle.append(t)
        t.start()
    time.sleep(JamTest)
    killThreads(3)
    threadHandle = []
    jammerOff(3)




def testCase14():
    global ThreadingActive
    global threadHandle
    # Cycle through L1 @ 0 dBm
    print('L1 cycle testing')
    initAllHackRF('CW')
    ThreadingActive = True
    t = threading.Thread(target=cycleTestL1, args=(0,0,dCycleTestL1_0dBm))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    #time.sleep(8*3600)
    killThreads(1)
    threadHandle = []

    jammerOff(3)


def testCase26():
    global ThreadingActive
    global threadHandle
    # Cycle through L1 @ 0 dBm
    print('L1 cycle testing')
    initAllHackRF('CW')
    ThreadingActive = True
    t = threading.Thread(target=cycleTestNarrowL1, args=(0,0,dCycleTestNarrowL1_0dBm))
    threadHandle.append(t)
    t.start()
    # Test takes 6.66 hours - give a little time for setup etc
    time.sleep(6*3600 + 3000)
    killThreads(1)
    threadHandle = []

    jammerOff(3)



def testCase27():
    global ThreadingActive
    global threadHandle
    # Cycle through L1 @ -15 dBm
    print('L1 cycle testing')
    initAllHackRF('CW')
    ThreadingActive = True
    t = threading.Thread(target=cycleTestNarrowL1, args=(0,-15,dCycleTestNarrowL1_Neg15dBm))
    threadHandle.append(t)
    t.start()
    # Test takes 6.66 hours - give a little time for setup etc
    time.sleep(6*3600 + 3000)
    killThreads(1)
    threadHandle = []

    jammerOff(3)


def testCase38():
    global ThreadingActive
    global threadHandle
    # Cycle through L1 @ 0 dBm
    print('L1 cycle testing 1585 @ 5dBm')
    initAllHackRF('CW')
    ThreadingActive = True
    t = threading.Thread(target=rampTest, args=(0,5,1584,1586,0.04,dCarrRamp1585_5dBm))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)


def testCase39():
    global ThreadingActive
    global threadHandle
    # Cycle through L1 @ 0 dBm
    print('L1 cycle testing 1567 @ 5dBm')
    initAllHackRF('CW')
    ThreadingActive = True
    t = threading.Thread(target=rampTest, args=(0,5,1566,1568,0.04,dCarrRamp1567_5dBm))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)

def testCase40():
    global ThreadingActive
    global threadHandle
    # Cycle through L1 @ 0 dBm
    print('L1 cycle testing 1575.42 @ 5dBm')
    initAllHackRF('CW')
    ThreadingActive = True
    t = threading.Thread(target=rampTest, args=(0,5,1574.42,1576.42,0.04,dCarrRamp1575_5dBm))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)


def testCase6():
    global ThreadingActive
    global threadHandle
    # Ramped power CW jamming on each band for an hour
    print('Ramp CW starting')
    initAllHackRF('CW')
    freq = [1575,1227,1191]
    ThreadingActive = True
    for num in range(numDevices):
        t = threading.Thread(target=rampCW, args=(num,freq[num],dCWRampL1L2L5))
        threadHandle.append(t)
        t.start()
    time.sleep(JamTest)
    killThreads(3)
    threadHandle = []

    jammerOff(3)


def testCase29():
    global ThreadingActive
    global threadHandle
    # Ramped power CW jamming on each band for an hour
    print('Ramp CW starting')
    initAllHackRF('CW')
    ThreadingActive = True
    t = threading.Thread(target=rampCW, args=(0,1575.42,dCWRampL1))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)




def testCase15():
    global ThreadingActive
    global threadHandle
    # Ramped power CW jamming on each band for an hour
    print('Slow+Fast pulse L1 only')
    initAllHackRF('CW')
    ThreadingActive = True
    # Earlier testing had two different frequeny lists, let's match that testing
    SlowFreqList = [1577.42, 1573.42,1563.0,1605]
    FastFreqList = [1577.42, 1573.42,1593,1588,1563.0,1581,1605]
    t = threading.Thread(target=slowFastPulseCW, args=(0,SlowFreqList,FastFreqList,dSlowFastPulseL1))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)


def testCase5():
    global ThreadingActive
    global threadHandle
    # Pulse ~60s on / 5s off sequentially on a range of frequencies
    print('Slow pulse L1 only')
    initAllHackRF('CW')
    ThreadingActive = True
    freqList = [1577.42, 1573.42, 1593, 1575.42, 1588, 1574.42, 1563.0, 1576.42, 1581, 1590, 1575.92, 1605]
    t = threading.Thread(target=slowPulseCW, args=(0,freqList,0,dSlowPulse1xL1))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)


def testCase32():
    global ThreadingActive
    global threadHandle
    # Pulse ~60s on / 5s off sequentially on a range of frequencies
    print('Slow pulse L5 only')
    initAllHackRF('CW')
    ThreadingActive = True
    freqList = [1176.45, 1207.14, 1191.795]
    t = threading.Thread(target=slowPulseCW, args=(0,freqList,0,dSlowPulse1xL5))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)




def testCase21():
    global ThreadingActive
    global threadHandle
    # Pulse ~60s on / 5s off sequentially on a range of frequencies
    print('Slow pulse L1 only')
    initAllHackRF('CW')
    ThreadingActive = True
    freqList = [1577.42, 1573.42, 1593, 1575.42, 1588, 1574.42, 1563.0, 1576.42, 1581, 1590, 1575.92, 1605]
    t = threading.Thread(target=slowPulseCW, args=(0,freqList,-25,dSlowPulse1xL1LowPower))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)


def testCase28():
    global ThreadingActive
    global threadHandle
    # Pulse ~60s on / 5s off sequentially on a range of frequencies
    print('Slow pulse ramp L1 only')
    initAllHackRF('CW')
    ThreadingActive = True
    t = threading.Thread(target=slowPulseCWwRamp, args=(0,1575.42,dSlowPulse1xL1wRamp))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)


def testCase9():
    global ThreadingActive
    global threadHandle
    # Cycle through L1 @ -15dBm
    print('L1 cycle testing')
    initAllHackRF('CW')
    ThreadingActive = True
    t = threading.Thread(target=cycleTestL1, args=(0,-15,dCycleTestL1))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)

   
def testCase2():   
    global ThreadingActive
    global threadHandle
    # Fast pulse jamming with ramp
    print('Fast pulse L1 only power ramp')
    initAllHackRF('CW')
    ThreadingActive = True
    freqList = [1577.42, 1573.42, 1593, 1588, 1563.0, 1581, 1605]
    t = threading.Thread(target=rampFastPulse, args=(0,freqList,dFastPulseRamp1xL1))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)


def testCase10():
    global ThreadingActive
    global threadHandle
    # Fast pulse jamming with ramp
    print('Fast pulse x2 only power ramp')
    initAllHackRF('CW')
    ThreadingActive = True
    for num in range(3):
        if(num == 0):
            freqList = [1577.42, 1573.42, 1593, 1588, 1563.0, 1581, 1605]
        elif(num == 1):
            freqList = [1176.45, 1297.14, 1202.025, 1185, 1177.45, 1191.795, 1180.45,1199,1186.45,1190.795]
        else:
            freqList = [1227.6,  1242.9, 1228.6, 1248.6, 1229.6, 1235.1247, 1240]
        t = threading.Thread(target=rampFastPulse, args=(num,freqList,dFastPulseRamp3xL1))
        threadHandle.append(t)
        t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)


def testCase0():
    global ThreadingActive
    global threadHandle
    # Fast pulse jamming 3 x in L1
    print('Fast pulse 3xL1 only')
    initAllHackRF('CW')
    ThreadingActive = True
    for num in range(3):
        if(num == 0):
            freqList = [1577.42, 1573.42, 1575.42, 1574.42]
        elif(num == 1):
            freqList = [1605.4,1598.1,1603,1600,1601]
        elif(num == 2):
            freqList = [1585,1590,1561]
        t = threading.Thread(target=fastPulseCW, args=(num,freqList,0,dFastPulse3xL1,0.5,1.5))
        threadHandle.append(t)
        t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)


def testCase1():
    global ThreadingActive
    global threadHandle
    # Fast pulse jamming
    print('Fast pulse L1 only')
    initAllHackRF('CW')
    ThreadingActive = True
    freqList = [1577.42, 1573.42, 1593, 1588, 1563.0, 1581, 1605]
    t = threading.Thread(target=fastPulseCW, args=(0,freqList,0,dFastPulse1xL1,0.5,1.5))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)


def testCase3():
    global ThreadingActive
    global threadHandle
    # Multi-tone at L1
    print('Triple CW starting - GPS only')
    initAllHackRF('CW')
    freq = [1575.42,1576.42,1574.42]
    ThreadingActive = True
    for num in range(numDevices):
        t = threading.Thread(target=constCW, args=(num,freq[num],0,dConstCW3xGPSL1))
        threadHandle.append(t)
        t.start()
    time.sleep(JamTest)
    killThreads(3)
    threadHandle = []

    jammerOff(3)


def testCase4():
    global ThreadingActive
    global threadHandle
    # Multi-tone at L1 GPS / GLN
    print('Triple CW starting - GPS + GLN')
    initAllHackRF('CW')
    freq = [1575.42,1599.5,1602.5]
    ThreadingActive = True
    for num in range(numDevices):
        t = threading.Thread(target=constCW, args=(num,freq[num],0,dConstCW3xL1))
        threadHandle.append(t)
        t.start()
    time.sleep(JamTest)
    killThreads(3)
    threadHandle = []

    jammerOff(3)


def testCase7():
    global ThreadingActive
    global threadHandle
    print('Const CW starting')
    initAllHackRF('CW')
    freq = [1575,1227,1191]
    ThreadingActive = True
    for num in range(numDevices):
        t = threading.Thread(target=constCW, args=(num,freq[num],0,dConstCWL1L2L5))
        threadHandle.append(t)
        t.start()
    time.sleep(6*3600 + 3000)
    killThreads(3)
    threadHandle = []

    jammerOff(3)


def testCase16():
    global ThreadingActive
    global threadHandle
    # Slow pulse jam - 3x HackRFs on L1
    print('Slow pulse all bands only')
    initAllHackRF('CW')
    ThreadingActive = True
    for num in range(numDevices):
        # The lists are the same length. However, each thread has an independent
        # random on time. So they will align on average, but there will be 
        # jitter 
        if(num == 0):
            freqList = [1576.42, 1601, 1574.75, 1598.1,  1560.098, 1573.42, 1575.42]
        elif(num == 1):
            freqList =   [1575.42, 1603, 1575.42, 1601.75, 1561.098, 1575.42, 1601.75]
        else:
            freqList =   [1577.42, 1604, 1576.42, 1605.4,  1562.098, 1577.42, 1561.098]
        t = threading.Thread(target=slowPulseCW, args=(num,freqList,0,dSlowPulse3xL1))
        threadHandle.append(t)
        t.start()
    time.sleep(JamTest)
    killThreads(3)
    threadHandle = []

    jammerOff(3)

def testCase43():
    global ThreadingActive
    global threadHandle
    # Slow pulse jam - 3x HackRFs on L1
    print('Slow pulse all bands only - lower power')
    initAllHackRF('CW')
    ThreadingActive = True
    for num in range(numDevices):
        # The lists are the same length. However, each thread has an independent
        # random on time. So they will align on average, but there will be
        # jitter
        if(num == 0):
            freqList = [1576.42, 1601, 1574.75, 1598.1,  1560.098, 1573.42, 1575.42]
        elif(num == 1):
            freqList =   [1575.42, 1603, 1575.42, 1601.75, 1561.098, 1575.42, 1601.75]
        else:
            freqList =   [1577.42, 1604, 1576.42, 1605.4,  1562.098, 1577.42, 1561.098]
        t = threading.Thread(target=slowPulseCW, args=(num,freqList,-12,dSlowPulse3xL1LowerPow))
        threadHandle.append(t)
        t.start()
    time.sleep(JamTest)
    killThreads(3)
    threadHandle = []

    jammerOff(3)


def testCase44():
    global ThreadingActive
    global threadHandle
    print('GlobalStar')
    initAllHackRF('GAUSSIAN_RFI_2MHz')

    ThreadingActive = True
    t = threading.Thread(target=globalStar, args=(0, dGlobalStar))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)


def testCase45():
    global ThreadingActive
    global threadHandle
    print('Heavy Jamming')
    initHackRF('THREECARR',0)
    initHackRF('CHIRP',1)
    initHackRF('CW',2)

    ThreadingActive = True
    for num in range(numDevices):
        t = threading.Thread(target=heavyMulti, args=(num, dHeavyChirpMulti))
        threadHandle.append(t)
        t.start()
    time.sleep(JamTest)
    killThreads(3)
    threadHandle = []

    jammerOff(3)


def primaryL1SecondaryL2L5(jamType):
    
    #powerLevel_0 = -10
    #powerLevel_1 = -15
    
    powerLevel_0 = -4
    powerLevel_1 = 0

    
    #setSynth(0,1574.0,powerLevel_0,jamType)
    #setSynth(1,1191.795,powerLevel_1,jamType)
    #time.sleep(300)

    while(ThreadingActive):
        setSynth(0,1574.0,powerLevel_0,jamType)

        for j in range(60):
            setSynth(1,1176.45,powerLevel_1,jamType)
            time.sleep(1)
            setSynth(1,1246,powerLevel_1,jamType)
            time.sleep(1)
            setSynth(1,1191.795,powerLevel_1,jamType)
            time.sleep(1)
            setSynth(1,1207.14,powerLevel_1,jamType)
            time.sleep(1)
            setSynth(1,1227.6,powerLevel_1,jamType)
            time.sleep(1)

            if(ThreadingActive == False):
                break
        
        # Recovery
        setSynth(0,5000,-30,jamType)
        setSynth(1,5000,-30,jamType)
        time.sleep(5)


def testCase46():
    global ThreadingActive
    global threadHandle
    print('Primary L1 / Secondary L2&L5')
    initHackRF('CW',0)
    initHackRF('THREECARR2',1)
    initHackRF('CW',2) # Unused

    ThreadingActive = True
    t = threading.Thread(target=primaryL1SecondaryL2L5, args=(dPrimaryL1SecondaryL2L5,))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)



def overlappingL1CW(jamType):
    # Only one thread for both synths!

    print('Starting thread')
    while(ThreadingActive):
        # Each run is around 2.5 hours
        for refPower in range(0,36,3):
            powerLevel_0 = refPower - 28
            powerLevel_1 = powerLevel_0 -2
            
            setSynth(0,1575.42, powerLevel_0,jamType)
            # Test to review power levels
            #step = 0
            #setSynth(1,1575.42 - (2*1.023) + step, powerLevel_1,jamType)
            #time.sleep(60)

            print('Set synth 1')
            for i in range(60):
                step = i * 4 * 1.023 / 60
                setSynth(1,1575.42 - (2*1.023) + step, powerLevel_1,jamType)
                # 15s delay
                now = datetime.datetime.now() + datetime.timedelta(seconds=15)
                while(ThreadingActive and ((now - datetime.datetime.now()).total_seconds() > 0)):
                    time.sleep(0.1)

                if(ThreadingActive == False):
                    break
            if(ThreadingActive == False):
                break

def testCase47():
    global ThreadingActive
    global threadHandle
    print('Overlapping L1 CW')
    initAllHackRF('CW')

    ThreadingActive = True
    t = threading.Thread(target=overlappingL1CW, args=(dOverlappingL1CW,))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest + 2*3600)
    killThreads(1)
    threadHandle = []

    jammerOff(3)

def testCase11():
    global ThreadingActive
    global threadHandle
    print('Triple Carr ramp test')
    initAllHackRF('THREECARR')
    ThreadingActive = True
    t = threading.Thread(target=rampTripleCarr, args=(0,1575.42,False,dTripleCarrRamp))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)

def testCase12():
    global ThreadingActive
    global threadHandle
    # Cycle through L1
    print('Triple Carr ramp test wide')
    initAllHackRF('THREECARR2')
    ThreadingActive = True
    t = threading.Thread(target=rampTripleCarr, args=(0,1575.42,False,dTripleCarrRampWide))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)


def testCase35():
    global ThreadingActive
    global threadHandle
    print('Carr ramp test wide with 2xCW at L1')

    setupHackRF(0,'THREECARR2',-30)
    setupHackRF(1,'CW',-30)
    setupHackRF(2,'CW',-30)

    freq = [1575.42, 1575.42 + 1.023]
    ThreadingActive = True
    for num in range(numDevices):
        if(num == 0): # Multi-carrier over GLONASS
            t = threading.Thread(target=rampTripleCarr, args=(num,1601.8,False,dCarrRampWideWithTwoL1CW))
        else:
            t = threading.Thread(target=constCW, args=(num,freq[num-1],-20,dCarrRampWideWithTwoL1CW))
        threadHandle.append(t)
        t.start()
    time.sleep(JamTest)
    killThreads(3)
    threadHandle = []

    jammerOff(3)

def testCase36():
    global ThreadingActive
    global threadHandle
    print('Carr ramp test wide @1591 with 2xCW at L1')

    setupHackRF(0,'THREECARR2',-30)
    setupHackRF(1,'CW',-30)
    setupHackRF(2,'CW',-30)

    freq = [1575.42, 1575.42 + 1.023]
    ThreadingActive = True
    for num in range(numDevices):
        if(num == 0): # Multi-carrier between GPS &  GLONASS
            t = threading.Thread(target=rampTripleCarr, args=(num,1587.9,False,dCarrRampWide1587WithTwoL1CW))
        else:
            t = threading.Thread(target=constCW, args=(num,freq[num-1],-20,dCarrRampWide1587WithTwoL1CW))
        threadHandle.append(t)
        t.start()
    time.sleep(JamTest)
    killThreads(3)
    threadHandle = []

    jammerOff(3)


def testCase37():
    global ThreadingActive
    global threadHandle
    print('DHS Test')

    setupHackRF(0,'GAUSSIAN_RFI_2MHz',-30)
    setupHackRF(1,'GAUSSIAN_RFI_5MHz',-30)

    freq = [1575.42, (1598.1 + 1605.4)/2]

    ThreadingActive = True
    for num in range(2):
        t = threading.Thread(target=rampGaussian, args=(num,freq[num],dDHSL1))
        threadHandle.append(t)
        t.start()
    time.sleep(JamTest)
    killThreads(2)
    threadHandle = []

    jammerOff(3)

def testCase13():
    global ThreadingActive
    global threadHandle
    print('Triple Carr ramp test wide with pulse')
    initAllHackRF('THREECARR2')
    ThreadingActive = True
    t = threading.Thread(target=rampTripleCarr, args=(0,1575.42,True,dTripleCarrPulsedRampWide))
    threadHandle.append(t)
    t.start()
    time.sleep(JamTest)
    killThreads(1)
    threadHandle = []

    jammerOff(3)

# Note cases 24 and 25 install slightly different chirp modulation
def testCase24():
  global ThreadingActive
  global threadHandle
  print("Slow chirp freq ramp test L1/L2/L5")
  initAllHackRF('CHIRP_SLOW')
  freq = [1575,1227,1191]
  ThreadingActive = True
  for num in range(numDevices):
    t = threading.Thread(target=rampChirp, args=(num,freq[num],dSlowChirpFreqRampL1L2L5))
    threadHandle.append(t)
    t.start()
  time.sleep(JamTest)
  killThreads(3)
  threadHandle = []

  jammerOff(3)


def testCase25():
  global ThreadingActive
  global threadHandle
  print("Slow chirp ramp L1/L2/L5")
  initAllHackRF('CHIRP')
  freq = [1575,1227,1191]
  ThreadingActive = True
  for num in range(numDevices):
    t = threading.Thread(target=rampChirp, args=(num,freq[num],dSlowChirpRampL1L2L5))
    threadHandle.append(t)
    t.start()
  time.sleep(JamTest)
  killThreads(3)
  threadHandle = []

  jammerOff(3)



def testCase22():
  global ThreadingActive
  global threadHandle
  print("Slow chirp ramp")
  initAllHackRF('CHIRP')
  freq = [1575.42,1561.098,1602]
  ThreadingActive = True
  for num in range(numDevices):
    t = threading.Thread(target=rampChirp, args=(num,freq[num],dSlowChirpRamp))
    threadHandle.append(t)
    t.start()
  time.sleep(JamTest)
  killThreads(3)
  threadHandle = []

  jammerOff(3)


def testCase17():
  global ThreadingActive
  global threadHandle
  print("d2MHzGaussianRamp3xL1")
  initAllHackRF('GAUSSIAN_RFI_2MHz')
  freq = [1575.42,1561.098,1602]
  ThreadingActive = True
  for num in range(numDevices):
    t = threading.Thread(target=rampGaussian, args=(num,freq[num],d2MHzGaussianRamp3xL1))
    threadHandle.append(t)
    t.start()
  time.sleep(JamTest)
  killThreads(3)
  threadHandle = []

  jammerOff(3)

def testCase41():
  global ThreadingActive
  global threadHandle
  print("d2MHzGaussianRamp3xL1 attenuated")
  initAllHackRF('GAUSSIAN_RFI_2MHz')
  freq = [1575.42,1561.098,1602]
  ThreadingActive = True
  for num in range(numDevices):
    t = threading.Thread(target=rampGaussianWithAtten, args=(num,freq[num],d2MHzGaussianRamp3xL1Atten))
    threadHandle.append(t)
    t.start()
  time.sleep(JamTest)
  killThreads(3)
  threadHandle = []

  jammerOff(3)

def testCase18():
  global ThreadingActive
  global threadHandle
  print("d2MHzGaussianRampL1L2L5")
  initAllHackRF('GAUSSIAN_RFI_2MHz')
  freq = [1575,1227,1191]
  ThreadingActive = True
  for num in range(numDevices):
    t = threading.Thread(target=rampGaussian, args=(num,freq[num],d2MHzGaussianRampL1L2L5))
    threadHandle.append(t)
    t.start()
  time.sleep(JamTest)
  killThreads(3)
  threadHandle = []

  jammerOff(3)

def testCase42():
  global ThreadingActive
  global threadHandle
  print("d2MHzGaussianRampL1L2L5 attenuated")
  initAllHackRF('GAUSSIAN_RFI_2MHz')
  freq = [1575,1227,1191]
  ThreadingActive = True
  for num in range(numDevices):
    t = threading.Thread(target=rampGaussianWithAtten, args=(num,freq[num],d2MHzGaussianRampL1L2L5Atten))
    threadHandle.append(t)
    t.start()
  time.sleep(JamTest)
  killThreads(3)
  threadHandle = []

  jammerOff(3)

all_tests = OrderedDict([
  # Some basic tests to start
  (5,testCase5),
  (16,testCase16),
  (29,testCase29),
  (15,testCase15),
  (28,testCase28),
  (0,testCase0),
  # More challenging - mostly wide band tests
  (45,testCase45),
  (35,testCase35),
  (11,testCase11),
  (12,testCase12),
  (13,testCase13),
  (41,testCase41),
  (18,testCase18),
  (42,testCase42),
  (22,testCase22),
  (24,testCase24),
  (17,testCase17),
  (25,testCase25),
  (34,testCase34),
  (33,testCase33),
  (36,testCase36),
  (37,testCase37),
  (46,testCase46),
  (47,testCase47),
  # remaining
  (43,testCase43),
  (38,testCase38),
  (39,testCase39),
  (21,testCase21),
  (32,testCase32),
  (14,testCase14),
  (30,testCase30),
  (8,testCase8),
  (6,testCase6),
  (2,testCase2),
  (7,testCase7),
  (31,testCase31),
  (3,testCase3),
  (9,testCase9),
  (10,testCase10),
  (4,testCase4),
  (1,testCase1),
  (27,testCase27),
  (26,testCase26),
  (44,testCase44),
  (40,testCase40)
  ] )

def main_loop(mode, test_ids, start_now=True):
    global threadHandle
    global ThreadingActive
    global JamTest

    threadHandle = []

    # Config the synth
    initAllHackRF('CW')
    init_hackrf1_atten()

    # Setup a mutex - we'll use this to protect stdout printing.
    mutex = threading.Lock()
    
    #JamTest = 6 * 3600
    #JamTest = 3 * 3600 - 400
    JamTest = 3 * 3600 - 400
    #JamTest = 120

    if(False):
        setSynth(0,5000,-30,-1)
        setSynth(1,5000,-30,-1)
        setSynth(2,5000,-30,-1)
        hackRFHandle[0].turn_signal_off()
        hackRFHandle[1].turn_signal_off()
        hackRFHandle[2].turn_signal_off()
        time.sleep(20)

    # If we want to wait for the hour roll to start
    if start_now:
        jammerOffQuick()
        time.sleep(60)
    else:
        jammerOff(3,delay=30)

    print('Starting Jam Loop');
    if mode == "All":
      print("Running all tests in original order")
      tests_to_run = list(all_tests.values())
    elif mode == "AllShuffle":
      tests_to_run = list(all_tests.values())
      random.shuffle(tests_to_run)
      print("Running all tests in shuffled order",tests_to_run)
    elif mode == "Only":
      print("Running only given tests")
      tests_to_run = []
      for num in test_ids:
        tests_to_run.append(all_tests[num])
    elif mode == "First":
      print("Running given tests first")
      tests_to_run = []
      for num in test_ids:
        tests_to_run.append(all_tests[num])
      for num,test_func in all_tests.items():
        if num not in test_ids:
          tests_to_run.append(all_tests[num])

    print("To run:",tests_to_run)
    while(True):
      for test_func in tests_to_run:
        func_name = str(test_func).split()[1]
        print(func_name)
        if os.path.isfile('Data/status.txt'):
          with open('Data/status.txt','w') as f_out:
            print(func_name,file=f_out)
        test_func()


if __name__ == '__main__':
    # Setup a Ctrl-C handler
    signal.signal(signal.SIGINT, signal_handler)
    main_loop("All",[],start_now=False)
