//https://www.instructables.com/Signal-Generator-AD9833/

//-----------------------------------------------------------------------------
// Copyright 2018 Peter Balch
// subject to the GNU General Public License
//-----------------------------------------------------------------------------

#include <math.h>

//-----------------------------------------------------------------------------
// Global Constants
//-----------------------------------------------------------------------------

const long BAUDRATE  = 115200;  // Baud rate of UART in bps

//-----------------------------------------------------------------------------
// Global Variables
//-----------------------------------------------------------------------------

const byte numberOfDigits = 6; // number of digits in the frequense
byte freqSGLo[numberOfDigits] = {0, 0, 0, 1, 0, 0}; // 1000Hz 
byte freqSGHi[numberOfDigits] = {0, 0, 0, 0, 2, 0}; // 20kHz  

const int wSine     = 0b0000000000000000;
const int wTriangle = 0b0000000000000010;
const int wSquare   = 0b0000000000101000;

int waveType = wSine;

const int SG_fsyncPin = 7;
const int SG_CLK = 8;
const int SG_DATA = 9;

int SG_iSweep,SG_nSweep;

//-----------------------------------------------------------------------------
//returns 10^y
//-----------------------------------------------------------------------------
unsigned long Power(int y) {
  unsigned long t = 1;
  for (byte i = 0; i < y; i++)
    t = t * 10;
  return t;
}

//-----------------------------------------------------------------------------
//calculate the frequency from the array.
//-----------------------------------------------------------------------------
unsigned long calcFreq(byte* freqSG) {
  unsigned long i = 0;
  for (byte x = 0; x < numberOfDigits; x++)
    i = i + freqSG[x] * Power(x);
  return i;
}

//-----------------------------------------------------------------------------
// SG_WriteRegister
//-----------------------------------------------------------------------------
void SG_WriteRegister(word dat) {
  digitalWrite(SG_CLK, LOW);
  digitalWrite(SG_CLK, HIGH);

  digitalWrite(SG_fsyncPin, LOW);
  for (byte i = 0; i < 16; i++) {
    if (dat & 0x8000)
      digitalWrite(SG_DATA, HIGH);
    else
      digitalWrite(SG_DATA, LOW);
    dat = dat << 1;
    digitalWrite(SG_CLK, HIGH);
    digitalWrite(SG_CLK, LOW);
  }
  digitalWrite(SG_CLK, HIGH);
  digitalWrite(SG_fsyncPin, HIGH);
}

//-----------------------------------------------------------------------------
// SG_Reset
//-----------------------------------------------------------------------------
void SG_Reset() {
  delay(100);
  SG_WriteRegister(0x100);
  delay(100);
}

//-----------------------------------------------------------------------------
// SG_freqReset
//    reset the SG regs then set the frequency and wave type
//-----------------------------------------------------------------------------
void SG_freqReset(long frequency, int wave) {
  long fl = frequency * (0x10000000 / 25000000.0);
  SG_WriteRegister(0x2100);
  SG_WriteRegister((int)(fl & 0x3FFF) | 0x4000);
  SG_WriteRegister((int)((fl & 0xFFFC000) >> 14) | 0x4000);
  SG_WriteRegister(0xC000);
  SG_WriteRegister(wave);
  waveType = wave;
}

//-----------------------------------------------------------------------------
// SG_freqSet
//    set the SG frequency regs 
//-----------------------------------------------------------------------------
void SG_freqSet(long frequency, int wave) {
  long fl = frequency * (0x10000000 / 25000000.0);
  SG_WriteRegister(0x2000 | wave);
  SG_WriteRegister((int)(fl & 0x3FFF) | 0x4000);
  SG_WriteRegister((int)((fl & 0xFFFC000) >> 14) | 0x4000);
}

//-----------------------------------------------------------------------------
// SG_StepSweep
//    increment the FG frequency 
//-----------------------------------------------------------------------------
//void SG_StepSweep(void) {
//  if (SG_iSweep > SG_nSweep) SG_iSweep = 0;
//  long f = exp((log(calcFreq(freqSGHi)) - log(calcFreq(freqSGLo)))*SG_iSweep/SG_nSweep + log(calcFreq(freqSGLo))) +0.5;
//  SG_freqSet(f, waveType);
//  SG_iSweep++;
//}

//-----------------------------------------------------------------------------
// Sweep
//   sweeps siggen freq continuously
//   takes n mS for whole sweep
//   SDC regs are saved and restored
//   stops when receives a serial char
//-----------------------------------------------------------------------------
//void Sweep(int n) {
//  int fmin,fmax;
//  fmin = calcFreq(freqSGLo);
//  fmax = calcFreq(freqSGHi);
//  int i=0; 
//  do {
//    long f = exp((log(fmax) - log(fmin))*i/(n-1) + log(fmin)) +0.5;
//    SG_freqSet(f, waveType);
//    delay(1);
//    i++;
//    if (i >= n) i = 0;
//  } while (!Serial.available());
//  
//  SG_freqSet(calcFreq(freqSGLo), waveType);
//}

//-----------------------------------------------------------------------------
// SerialCommand
//   if a byte is available in teh seril input buffer
//   execute it as a command
//-----------------------------------------------------------------------------
//void SerialCommand(void) {
//  if ( Serial.available() > 0 ) {
//    char c = Serial.read();
//
//    if ((c >= '0') && (c <= '9')) {
//      for (int i=5; i>0; i--) freqSGLo[i] = freqSGLo[i-1];
//      freqSGLo[0] = c - '0';
//    } else {
//      switch (c) {
//        case 'S': waveType = wSine; SG_freqReset(calcFreq(freqSGLo), waveType); break;   // SigGen wave is sine
//        case 'T': waveType = wTriangle; SG_freqReset(calcFreq(freqSGLo), waveType); break;   // SigGen wave is triangle
//        case 'Q': waveType = wSquare; SG_freqReset(calcFreq(freqSGLo), waveType); break;   // SigGen wave is square
//        case 'R': SG_Reset();  break;   // SigGen reset
//        case 'M': for (int i=0; i<=5; i++) freqSGHi[i] = freqSGLo[i]; break;   // move freq to high array
//        case 'G': Sweep(1000);  break; // sweep SigGen
//        case 'H': Sweep(5000);  break; // sweep SigGen
//        case 'I': Sweep(20000);  break; // sweep SigGen
//
//        default: return;
//      }
//    }
//  }
//}

//-----------------------------------------------------------------------------
// InitSigGen
//-----------------------------------------------------------------------------
void InitSigGen(void) {
 // pinMode(SG_POWER, OUTPUT);
 // digitalWrite(SG_POWER, HIGH);

  pinMode(SG_DATA, OUTPUT);
  pinMode(SG_CLK, OUTPUT);
  pinMode(SG_fsyncPin, OUTPUT);
  digitalWrite(SG_fsyncPin, HIGH);
  digitalWrite(SG_CLK, HIGH);
  SG_Reset();
  SG_freqReset(calcFreq(freqSGLo), waveType);
}

int ii = 0;
//-----------------------------------------------------------------------------
// Main routines
// The setup function
//-----------------------------------------------------------------------------
void setup (void) {
  // Open serial port with a baud rate of BAUDRATE b/s
  Serial.begin(BAUDRATE);

  Serial.println("SigGen " __DATE__); // compilation date
  Serial.println("OK");

  pinMode(LED_BUILTIN, OUTPUT);

  InitSigGen();
  SG_freqSet(100000,wSine);
}

//-----------------------------------------------------------------------------
// Main routines
// loop
//-----------------------------------------------------------------------------
void loop (void) {
//  SerialCommand();
  SG_freqSet(100000*ii,wSine);
  ii++;
  delay(1000);
}