diff --git a/control_lcd_45mhz_if_v4.ino b/control_lcd_45mhz_if_v4.ino new file mode 100644 index 0000000..f4eb989 --- /dev/null +++ b/control_lcd_45mhz_if_v4.ino @@ -0,0 +1,899 @@ +/** + * This source file is under General Public License version 3. + * + * Most source code are meant to be understood by the compilers and the computers. + * Code that has to be hackable needs to be well understood and properly documented. + * Donald Knuth coined the term Literate Programming to indicate code that is written be + * easily read and understood. + * + * The Raduino is a small board that includes the Arduin Nano, a 16x2 LCD display and + * an Si5351a frequency synthesizer. This board is manufactured by Paradigm Ecomm Pvt Ltd + * + * To learn more about Arduino you may visit www.arduino.cc. + * + * The Arduino works by firt executing the code in a function called setup() and then it + * repeatedly keeps calling loop() forever. All the initialization code is kept in setup() + * and code to continuously sense the tuning knob, the function button, transmit/receive, + * etc is all in the loop() function. If you wish to study the code top down, then scroll + * to the bottom of this file and read your way up. + * + * Below are the libraries to be included for building the Raduino + * The EEPROM library is used to store settings like the frequency memory, caliberation data, + * callsign etc . + */ + +#include + +/** + * The main chip which generates upto three oscillators of various frequencies in the + * Raduino is the Si5351a. To learn more about Si5351a you can download the datasheet + * from www.silabs.com although, strictly speaking it is not a requirment to understand this code. + * Instead, you can look up the Si5351 library written by xxx, yyy. You can download and + * install it from www.url.com to complile this file. + * The Wire.h library is used to talk to the Si5351 and we also declare an instance of + * Si5351 object to control the clocks. + */ +#include +#include +Si5351 si5351; +/** + * The Radiono board is the size of a standard 16x2 LCD panel. It has three connectors: + * + * First, is an 8 pin connector that provides +5v, GND and six analog input pins that can also be + * configured to be used as digital input or output pins. These are referred to as A0,A1,A2, + * A3,A6 and A7 pins. The A4 and A5 pins are missing from this connector as they are used to + * talk to the Si5351 over I2C protocol. + * + * Second is a 16 pin LCD connector. This connector is meant specifically for the standard 16x2 + * LCD display in 4 bit mode. The 4 bit mode requires 4 data lines and two control lines to work: + * Lines used are : RESET, ENABLE, D4, D5, D6, D7 + * We include the library and declare the configuration of the LCD panel too + */ + +#include +LiquidCrystal lcd(8,9,10,11,12,13); + +/** + * The Arduino, unlike C/C++ on a regular computer with gigabytes of RAM, has very little memory. + * We have to be very careful with variables that are declared inside the functions as they are + * created in a memory region called the stack. The stack has just a few bytes of space on the Arduino + * if you declare large strings inside functions, they can easily exceed the capacity of the stack + * and mess up your programs. + * We circumvent this by declaring a few global buffers as kitchen counters where we can + * slice and dice our strings. These strings are mostly used to control the display or handle + * the input and output from the USB port. We must keep a count of the bytes used while reading + * the serial port as we can easily run out of buffer space. This is done in the serial_in_count variable. + */ +char serial_in[32], c[30], b[30], printBuff[32]; +int count = 0; +unsigned char serial_in_count = 0; + +/** + * We need to carefully pick assignment of pin for various purposes. + * There are two sets of completely programmable pins on the Raduino. + * First, on the top of the board, in line with the LCD connector is an 8-pin connector + * that is largely meant for analog inputs and front-panel control. It has a regulated 5v output, + * ground and six pins. Each of these six pins can be individually programmed + * either as an analog input, a digital input or a digital output. + * The pins are assigned as follows: + * A0, A1, A2, A3, +5v, GND, A6, A7 + * (while holding the board up so that back of the board faces you) + * + * Though, this can be assigned anyway, for this application of the Arduino, we will make the following + * assignment + * A2 will connect to the PTT line, which is the usually a part of the mic connector + * A3 is connected to a push button that can momentarily ground this line. This will be used for RIT/Bandswitching, etc. + * A6 is to implement a keyer, it is reserved and not yet implemented + * A7 is connected to a center pin of good quality 100K or 10K linear potentiometer with the two other ends connected to + * ground and +5v lines available on the connector. This implments the tuning mechanism + */ +#define S_METER (A0) +#define PTT (A1) +#define FBUTTON (A3) +#define ANALOG_KEYER (A7) +#define ANALOG_TUNING (A6) + +/** + * The second set of 16 pins on the bottom connector are have the three clock outputs and the digital lines to control the rig. + * This assignment is as follows : + * Pin 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + * GND +5V CLK0 GND GND CLK1 GND GND CLK2 GND D2 D3 D4 D5 D6 D7 + * These too are flexible with what you may do with them, for the Raduino, we use them to : + * - TX_RX line : Switches between Transmit and Receive after sensing the PTT or the morse keyer + * - CW_KEY line : turns on the carrier for CW + */ + +#define TX_RX (7) +#define CW_TONE (6) +#define TX_LPF_SEL (5) +#define CW_KEY (4) + +/** + * The raduino has a number of timing parameters, all specified in milliseconds + * CW_TIMEOUT : how many milliseconds between consecutive keyup and keydowns before switching back to receive? + * The next set of three parameters determine what is a tap, a double tap and a hold time for the funciton button + * TAP_DOWN_MILLIS : upper limit of how long a tap can be to be considered as a button_tap + * TAP_UP_MILLIS : upper limit of how long a gap can be between two taps of a button_double_tap + * TAP_HOLD_MILIS : many milliseconds of the buttonb being down before considering it to be a button_hold + */ + +#define TAP_UP_MILLIS (500) +#define TAP_DOWN_MILLIS (600) +#define TAP_HOLD_MILLIS (2000) +#define CW_TIMEOUT (2000l) // in milliseconds, this is the parameter that determines how long the tx will hold between cw key downs + +/** + * The Raduino supports two VFOs : A and B and receiver incremental tuning (RIT). + * we define a variables to hold the frequency of the two VFOs, RITs + * the rit offset as well as status of the RIT + */ +#define VFO_A 0 +#define VFO_B 1 +char ritOn = 0; +char vfoActive = VFO_A; +unsigned long vfoA=7100000L, vfoB=14200000L, ritA, ritB, sideTone=800, lsbCarrier, usbCarrier; + +#define MASTER_CAL 0 +#define LSB_CAL 4 +#define USB_CAL 8 +#define SIDE_TONE 12 + +/** + * Raduino needs to keep track of current state of the transceiver. These are a few variables that do it + */ +char inTx = 0; +char keyDown = 0; +char isUSB = 0; +unsigned long cwTimeout = 0; +unsigned char txFilter = 0; + +/** Tuning Mechanism of the Raduino + * We use a linear pot that has two ends connected to +5 and the ground. the middle wiper + * is connected to ANALOG_TUNNING pin. Depending upon the position of the wiper, the + * reading can be anywhere from 0 to 1024. + * The tuning control works in steps of 50Hz each for every increment between 50 and 950. + * Hence the turning the pot fully from one end to the other will cover 50 x 900 = 45 KHz. + * At the two ends, that is, the tuning starts slowly stepping up or down in 10 KHz steps + * To stop the scanning the pot is moved back from the edge. + * To rapidly change from one band to another, you press the function button and then + * move the tuning pot. Now, instead of 50 Hz, the tuning is in steps of 50 KHz allowing you + * rapidly use it like a 'bandset' control. + * To implement this, we fix a 'base frequency' to which we add the offset that the pot + * points to. We also store the previous position to know if we need to wake up and change + * the frequency. + */ + +unsigned long baseTune = 7100000L; +int old_knob = 0; + +#define FIRST_IF (45000000l) +#define SECOND_OSC (57000000l) +#define INIT_USB_FREQ (11996500l) +#define INIT_LSB_FREQ (11998500l) +#define LOWEST_FREQ (3000000l) +#define HIGHEST_FREQ (30000000l) + +long frequency, stepSize=100000; + +/** + * The raduino can be booted into multiple modes: + * MODE_NORMAL : works the radio normally + * MODE_CALIBRATION : used to calibrate Raduino. + * To enter this mode, hold the function button down and power up. Tune to exactly 10 MHz on clock0 and release the function button + */ + #define MODE_NORMAL (0) + #define MODE_CALIBRATE (1) + char mode = MODE_NORMAL; + +char meter[17]; +byte s_meter[] = { + B0,B0,B0,B0,B0,B00000,B0,B10101, + B0,B0,B0,B0,B10000,B10000,B0,B10101, + B0,B0,B0,B0,B11000,B11000,B0,B10101, + B0,B0,B0,B0,B11100,B11100,B0,B10101, + B0,B0,B0,B0,B11110,B11110,B0,B10101, + B0,B0,B0,B0,B11111,B11111,B0,B10101 +}; + +void setupSmeter(){ + lcd.createChar(1, s_meter); + lcd.createChar(2, s_meter + 8); + lcd.createChar(3, s_meter + 16); + lcd.createChar(4, s_meter + 24); + lcd.createChar(5, s_meter + 32); + lcd.createChar(6, s_meter + 40); +} + +/* display routines */ +void printLine1(char *c){ + if (strcmp(c, printBuff)){ + lcd.setCursor(0, 0); + lcd.print(c); + strcpy(printBuff, c); + count++; + } +} + +void printLine2(char *c){ + if (strlen(c) > 16) + c[16] = 0; + lcd.setCursor(0, 1); + lcd.print(c); +} + +void displayFrequency(unsigned long f){ + int mhz, khz, hz; + + mhz = f / 1000000l; + khz = (f % 1000000l)/1000; + hz = f % 1000l; + sprintf(b, "[%02d.%03d.%03d]", mhz, khz, hz); + printLine1(b); +} + +void updateMeter(){ + int16_t best, i, s; + + best = 0; + //take 100 readings, take the peaks + for (i = 0; i < 100; i++){ + s = analogRead(S_METER); + if (s > best) + best = s; + } + //now, use the s to get the signal + s = best *2; + sprintf(meter, "%3d", s); + for (i = 3; i < 14; i++){ + if (s >= 5) + meter[i] = 6; + else if (s > 0) + meter[i] = 1 + s; + else + meter[i] = 1; + s = s - 5; + } + meter[i] = 0; + printLine2(meter); +} + +/** + * Defines for menus + */ +byte menuOn = 0; + +int ritToggle(int btn){ + if (!btn){ + if (ritOn == 1) + printLine2("RIT:On, Off? "); + else + printLine2("RIT:Off, On? "); + } + else { + if (ritOn == 0){ + ritOn = 1; + printLine2("RIT is On. "); + } + else { + ritOn = 0; + printLine2("RIT Is Off. "); + } + } +} + +int vfoToggle(int btn){ + + if (!btn){ + if (vfoActive == VFO_A) + printLine2("Select VFO B? "); + else + printLine2("Select VFO A? "); + } + else { + if (vfoActive == VFO_A){ + vfoActive = VFO_A; + printLine1("Selected VFO A "); + frequency = vfoA; + } + else { + vfoActive = VFO_B; + printLine1("Selected VFO B "); + frequency = vfoB; + } + setFrequency(frequency); + updateDisplay(); + resetBasefrequency(); + } +} + +/** + * Load the new correction and resets the clock 0 to 10 MHz + */ + +void recalibrate(int32_t correction){ + + si5351.set_correction(correction); + + si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA); + si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLB); + + si5351.output_enable(SI5351_CLK0, 1); + si5351.output_enable(SI5351_CLK1, 0); + si5351.output_enable(SI5351_CLK2, 0); + + si5351.set_freq(1000000000ULL, SI5351_CLK0); +} + +void calibrateMaster(int btn){ + int knob = 0; + int32_t correction; + + if (!btn){ + printLine2("Set Calibration?"); + return; + } + printLine1("Set to 10.000.000"); + printLine2("PTT to confirm. "); + delay(2000); + + recalibrate(0); + + //disable all clock 1 and clock 2 + while(digitalRead(PTT) == HIGH && !btnDown()){ + knob = analogRead(ANALOG_TUNING); + correction = (knob - 500) * 500ULL; + recalibrate(correction); + //abort if this button is down + if (btnDown()){ + //re-enable the clock1 and clock 2 + break; + } + sprintf(c, "%3d ", knob); + printLine2(c); + } + + //save the setting + if (digitalRead(PTT) == LOW){ + printLine2("Calibration set!"); + EEPROM.put(MASTER_CAL, correction); + delay(2000); + } + else { + EEPROM.get(MASTER_CAL, correction); + } + + si5351.set_correction(correction); + si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA); + si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLB); + + si5351.output_enable(SI5351_CLK0, 1); + si5351.output_enable(SI5351_CLK1, 1); + si5351.output_enable(SI5351_CLK2, 1); + + resetBasefrequency(); + setFrequency(frequency); + updateDisplay(); + menuOn = 0; +} + +void setBFO(int btn, byte isLSB){ + int knob = 0; + int32_t lsb_Freq; + + if (!btn){ + if (isLSB) + printLine2("Set LSB Carrier "); + else + printLine2("Set USB Carrier "); + return; + } + if (isLSB) + printLine1("Tune to best LSB"); + else + printLine1("Tune to best USB"); + printLine2("PTT to confirm. "); + delay(2000); + + //disable all clock 1 and clock 2 + while(digitalRead(PTT) == HIGH && !btnDown()){ + knob = analogRead(ANALOG_TUNING); + if (isLSB){ + lsbCarrier = 12000000l - knob * 10; + si5351.set_freq(lsbCarrier * 100ULL, SI5351_CLK0); + } + else { + usbCarrier = 12000000l - knob * 10; + si5351.set_freq(usbCarrier * 100ULL, SI5351_CLK0); + } + //abort if this button is down + if (btnDown()){ + break; + } + sprintf(c, "%3d ", knob); + printLine2(c); + } + //save the setting + if (digitalRead(PTT) == LOW){ + printLine2("Carrier set! "); + if (isLSB) + EEPROM.put(LSB_CAL, lsbCarrier); + else + EEPROM.put(USB_CAL, usbCarrier); + delay(2000); + } + else { + EEPROM.get(LSB_CAL, lsbCarrier); + EEPROM.get(USB_CAL, usbCarrier); + } + + resetBasefrequency(); + setFrequency(frequency); + updateDisplay(); + menuOn = 0; +} + +void resetBasefrequency(){ + int knob = analogRead(ANALOG_TUNING); + baseTune = frequency - (50l * knob); +} + +int exitMenu(int btn){ + + if (!btn){ + printLine2("Exit Menu? "); + } + else{ + menuOn = 0; + resetBasefrequency(); + } +} + +void doMenu(){ + int select, btnState; + menuOn = 1; + + while(menuOn){ + select = analogRead(ANALOG_TUNING); + //downscale the selection + select = (select-50)/50; + btnState = btnDown(); + delay(200); + switch(select){ + case 0: + ritToggle(btnState); + break; + case 1: + vfoToggle(btnState); + break; + case 2: + calibrateMaster(btnState); + break; + case 3: + setBFO(btnState, 1); + break; + case 4: + setBFO(btnState, 0); + break; + + default: + exitMenu(btnState); + break; + } + } +} + +void updateDisplay(){ + sprintf(b, "%8ld", frequency); + sprintf(c, "%s:%.2s.%.3s.%1s", vfoActive == VFO_A ? "A" : "B" , b, b+2, b+5); + if (isUSB) + strcat(c, " USB"); + else + strcat(c, " LSB"); + + if (inTx) + strcat(c, " TX"); + else if (ritOn) + strcat(c, " +R"); + else + strcat(c, " "); + + + printLine1(c); +/* sprintf(c, "%s %s %d", isLSB ? "LSB" : "USB", inTx ? " TX" : " RX", digitalRead(FBUTTON)); + printLine2(c); */ +} + +void setSidebandAndTXFilters(unsigned long freq){ + + if (freq > 10000000L){ + isUSB = 1; + si5351.set_freq(usbCarrier * 100ULL, SI5351_CLK0); + digitalWrite(TX_LPF_SEL, 1); + } + else{ + isUSB = 0; + digitalWrite(TX_LPF_SEL, 0); + si5351.set_freq(lsbCarrier * 100ULL, SI5351_CLK0); + } +} + +void setFrequency(unsigned long f){ + uint64_t osc_f; + + setSidebandAndTXFilters(f); + + if (isUSB) + si5351.set_freq((SECOND_OSC - usbCarrier + f) * 100ULL, SI5351_CLK2); + else + si5351.set_freq((SECOND_OSC - lsbCarrier + f) * 100ULL, SI5351_CLK2); + + frequency = f; +} + +void checkTX(){ + + //we don't check for ptt when transmitting cw + if (cwTimeout > 0) + return; + + if (digitalRead(PTT) == 0 && inTx == 0){ + inTx = 1; + digitalWrite(TX_RX, 1); + updateDisplay(); + } + + if (digitalRead(PTT) == 1 && inTx == 1){ + inTx = 0; + digitalWrite(TX_RX, 0); + updateDisplay(); + } +} + +/* +byte prevWasDot = 0; + +void keyer(){ + int key = analogRead(ANALOG_KEYER); + + if (key < 50) //straight key + keyDown(); + else if (key < 300) // both + if (prevWasDot){ + keyDown(dotPeriod * 3); + prevWasDot = 0; + } + else { + keyDown(dotPeriod); + prevWasDot = 1; + } + else if (key < 600){ //dash + keyDown(dotPeriod * 3); + prevWasDot = 0; + } + else if (key > 900){ //dot + keyUp(); + } +} +*/ + + +void checkCW2(){ + + if (keyDown == 0 && analogRead(ANALOG_KEYER) < 50){ + //switch to transmit mode if we are not already in it + if (inTx == 0){ + digitalWrite(TX_RX, 1); +// selectTransmitFilter(); + //give the relays a few ms to settle the T/R relays + delay(50); + } + inTx = 1; + keyDown = 1; + tone(CW_TONE, (int)sideTone); + updateDisplay(); + } + + //reset the timer as long as the key is down + if (keyDown == 1){ + cwTimeout = CW_TIMEOUT + millis(); + } + + //if we have a keyup + if (keyDown == 1 && analogRead(ANALOG_KEYER) > 150){ + keyDown = 0; + noTone(CW_TONE); + cwTimeout = millis() + CW_TIMEOUT; + } + + //if we are in cw-mode and have a keyuup for a longish time + if (cwTimeout > 0 && inTx == 1 && cwTimeout < millis()){ + //move the radio back to receive + digitalWrite(TX_RX, 0); + inTx = 0; + cwTimeout = 0; + updateDisplay(); + } +} + +void checkCW3(){ + + if (keyDown == 0 && analogRead(ANALOG_KEYER) < 50){ + //switch to transmit mode if we are not already in it + if (inTx == 0){ + + if (isUSB) + si5351.set_freq((frequency + sideTone) * 100ULL, SI5351_CLK2); + else + si5351.set_freq((frequency - sideTone) * 100ULL, SI5351_CLK2); + //switch off the second oscillator and the bfo + si5351.output_enable(SI5351_CLK0, 0); + si5351.output_enable(SI5351_CLK1, 0); + si5351.output_enable(SI5351_CLK2, 1); + + digitalWrite(TX_RX, 1); +// selectTransmitFilter(); + //give the relays a few ms to settle the T/R relays + delay(50); + } + inTx = 1; + keyDown = 1; + tone(CW_TONE, (int)sideTone); + digitalWrite(CW_KEY, 1); + + updateDisplay(); + } + + //reset the timer as long as the key is down + if (keyDown == 1){ + cwTimeout = CW_TIMEOUT + millis(); + } + + //if we have a keyup + if (keyDown == 1 && analogRead(ANALOG_KEYER) > 150){ + keyDown = 0; + noTone(CW_TONE); + digitalWrite(CW_KEY, 0); + cwTimeout = millis() + CW_TIMEOUT; + } + + //if we are in cw-mode and have a keyuup for a longish time + if (cwTimeout > 0 && inTx == 1 && cwTimeout < millis()){ + //move the radio back to receive + digitalWrite(TX_RX, 0); + inTx = 0; + cwTimeout = 0; + updateDisplay(); + + //switch off the second oscillator and the bfo + si5351.output_enable(SI5351_CLK0, 1); + si5351.output_enable(SI5351_CLK1, 1); + si5351.output_enable(SI5351_CLK2, 1); + setFrequency(frequency); + } +} + + +void checkCW(){ + + if (keyDown == 0 && analogRead(ANALOG_KEYER) < 50){ + //switch to transmit mode if we are not already in it + if (inTx == 0){ + digitalWrite(TX_RX, 1); + delay(50); + inTx = 1; + keyDown = 1; + } + if (isUSB) + si5351.set_freq((frequency + sideTone) * 100ULL, SI5351_CLK2); + else + si5351.set_freq((frequency - sideTone) * 100ULL, SI5351_CLK2); + //switch off the second oscillator and the bfo + si5351.output_enable(SI5351_CLK0, 0); + si5351.output_enable(SI5351_CLK1, 0); + si5351.output_enable(SI5351_CLK2, 1); + + digitalWrite(CW_KEY, 1); + tone(CW_TONE, sideTone); + updateDisplay(); + } + + //reset the timer as long as the key is down + if (keyDown == 1){ + cwTimeout = CW_TIMEOUT + millis(); + } + + //if we have a keyup + if (keyDown == 1 && analogRead(ANALOG_KEYER) > 150){ + keyDown = 0; + noTone(CW_TONE); + digitalWrite(CW_KEY, 0); + cwTimeout = millis() + CW_TIMEOUT; + } + + //if we are in cw-mode and have a keyuup for a longish time + if (cwTimeout > 0 && inTx == 1 && cwTimeout < millis()){ + //move the radio back to receive + digitalWrite(TX_RX, 0); + inTx = 0; + cwTimeout = 0; + //switch off the second oscillator and the bfo + si5351.output_enable(SI5351_CLK0, 1); + si5351.output_enable(SI5351_CLK1, 1); + si5351.output_enable(SI5351_CLK2, 1); + setFrequency(frequency); + updateDisplay(); + } +} + +int btnDown(){ + if (digitalRead(FBUTTON) == HIGH) + return 0; + else + return 1; +} + +void checkButton(){ + int i, t1, t2, knob, new_knob, duration; + + //only if the button is pressed + if (!btnDown()) + return; + + //wait for 50 ms before declaring the button to be really down + delay(50); + if (!btnDown()) + return; + + t1 = millis(); + knob = analogRead(ANALOG_TUNING); + duration = 0; + + /* keep measuring how long the duration of btn down has been to a max of 3 seconds */ + while (btnDown() && duration < 3000){ + /* if the tuning knob is moved while the btn is down, + then track the bandset until the button is up and return + */ + new_knob = analogRead(ANALOG_TUNING); + if (abs(new_knob - knob) > 10){ + int count = 0; + /* track the tuning and return */ + while (btnDown()){ + frequency = baseTune = ((analogRead(ANALOG_TUNING) * 30000l) + 1000000l); + setFrequency(frequency); + updateDisplay(); + count++; + delay(200); + } + delay(1000); + return; + } /* end of handling the bandset */ + + delay(100); + duration += 100; + } + + if (duration < 1000) { + printLine2("Menu."); + doMenu(); + } +} + +void doTuning(){ + unsigned long newFreq; + + int knob = analogRead(ANALOG_TUNING); + unsigned long old_freq = frequency; + + if (knob < 10 && frequency > LOWEST_FREQ) { + baseTune = baseTune - 1000l; + frequency = baseTune; + updateDisplay(); + setFrequency(frequency); + delay(50); + } + else if (knob > 1010 && frequency < HIGHEST_FREQ) { + baseTune = baseTune + 1000l; + frequency = baseTune + 50000l; + setFrequency(frequency); + updateDisplay(); + delay(50); + } + // in the middle, it is business as usual + else if (knob != old_knob){ + frequency = baseTune + (50l * knob); + old_knob = knob; + setFrequency(frequency); + updateDisplay(); + } +} + + +void setup() +{ + int32_t cal; + + lcd.begin(16, 2); + setupSmeter(); + printBuff[0] = 0; + printLine1("HFuino v0.01 "); + printLine2(" "); + + EEPROM.get(MASTER_CAL, cal); + EEPROM.get(LSB_CAL, lsbCarrier); + EEPROM.get(USB_CAL, usbCarrier); + //set the lsb and usb to defaults + if (lsbCarrier == 0) + lsbCarrier = INIT_LSB_FREQ; + if (usbCarrier == 0) + usbCarrier = INIT_USB_FREQ; + + // Start serial and initialize the Si5351 + Serial.begin(9600); + analogReference(DEFAULT); + Serial.println("*HFuino v0.01\n"); + Serial.println("*Searching Si5351\n"); + + //configure the function button to use the external pull-up + pinMode(FBUTTON, INPUT); + digitalWrite(FBUTTON, HIGH); + + pinMode(PTT, INPUT); + digitalWrite(PTT, HIGH); + + digitalWrite(ANALOG_KEYER, HIGH); + + pinMode(CW_TONE, OUTPUT); + digitalWrite(CW_TONE, 0); + pinMode(TX_RX,OUTPUT); + digitalWrite(TX_RX, 0); + pinMode(TX_LPF_SEL, OUTPUT); + digitalWrite(TX_LPF_SEL, 0); + pinMode(CW_KEY, OUTPUT); + digitalWrite(CW_KEY, 0); + EEPROM.get(0,cal); + + si5351.init(SI5351_CRYSTAL_LOAD_8PF,25000000l,0); + + si5351.set_correction(cal); + si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA); + si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLB); + + si5351.output_enable(SI5351_CLK0, 1); + si5351.output_enable(SI5351_CLK1, 1); + si5351.output_enable(SI5351_CLK2, 1); + // printLine1("check freq "); + // si5351.set_freq(1000000000l, SI5351_CLK2); + + // delay(20000); + + si5351.set_freq(lsbCarrier * 100ULL, SI5351_CLK0); + si5351.set_freq(SECOND_OSC * 100ULL, SI5351_CLK1); + si5351.set_freq(5900000000l, SI5351_CLK2); + printLine2(b); + delay(2000); + + // Set CLK0 to output 7 MHz with a fixed PLL frequency + + si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); + si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_8MA); + si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_8MA); + + + Serial.println("*Si5350 ON"); + delay(10); +} + +void loop(){ + + //generateCW(10000); + //the order of testing first for cw and then for ptt is important. + checkCW3(); + checkTX(); + checkButton(); + //tune only when not tranmsitting + if (!inTx) + doTuning(); + updateMeter(); + delay(50); +} +