/*********************************************************************
				NMM-1
NMEA0183 serial Monitor.

By Jony Silva
Wed 24 Jan 23:11:25 GMT 2018
*********************************************************************/

// Libraries to be included
#include <SPI.h>
#include <Wire.h>
#include <SoftwareSerial.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 8
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 56 // OLED display height, in pixels
// create display object for oled display
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define ON 0  // ON means pin is on GND
#define OFF 1 // OFF means pin is on VCC

// Assign switches and led's to arduino pins
#define UP 2       // Switch 1 will be function UP connected to arduino PD 2
#define OK 3       // Switch 2 will be function OK connected to arduino pin 3
#define DOWN 4     // Switch 3 will be function DOWN connected to arduino pin 4
#define CANCEL 5   // Switch 4 will be function CANCEL connected to arduino pin 5
#define led1 9     // Led 1 connected to arduino pin 9
#define led2 10    // Led 2 connected to arduino pin 10
#define batt 17	   // Battery plus connected to arduino pin 17

// Macros to read the switchs
#define rUP digitalRead(UP)         // Read button UP state
#define rOK digitalRead(OK)         // Read button OK state
#define rDOWN digitalRead(DOWN)     // Read button DOWN state
#define rCANCEL digitalRead(CANCEL) // Read button CANCEL state


// Function declarations
void one();				// Menu one
void two();				// Menu two
void three();			// Menu three
void four();			// Menu four
void read_serial();		// Menu that reads the serial
void write_gps();		// Menu that writes gps out to serial
void write_hdg();		// Menu that writes hdg out to serial
void write_dep();		// Menu that writes dep out to serial
void batt_icon();		// Draws the battery icon acording to value
void write_serial();	// Menu that writes to serial



// Variables creation
int menuState = 1;  // Integer with the number of the menu you are in
int prevMenu = 1;	// Previous menu
int UP_state = OFF;  // Holds state for UP, either ON or OFF
int OK_state = OFF;  // Holds state for OK, either ON or OFF
int DOWN_state = OFF;  // Holds state for DOWN, either ON or OFF
int CANCEL_state = OFF;  // Holds state for CANCEL, either ON or OFF
int batt_val = 0;	// Holds the value of battery voltage
int read_s = 0;		// Serial flag, if 0 not reading, if 1 is reading


// Create SoftwareSerial object and designate pins
  SoftwareSerial mySerial(6, 7); // RX, TX

void setup() {    // BEGIN SETUP ------------------------------------


  pinMode(led1, OUTPUT);    // Led 1 is an output
  pinMode(led2, OUTPUT);    // Led 2 is an output
  pinMode(UP, INPUT);      // Switch 1 is an input
  pinMode(OK, INPUT);      // Switch 2 is an input
  pinMode(DOWN, INPUT);      // Switch 3 is an input
  pinMode(CANCEL, INPUT);      // Switch 4 is an input

  // Define the starting state of the led's
  digitalWrite(led1,HIGH);  // Turn off led 1
  digitalWrite(led2,HIGH);  // Turn off led 2

	// set the data rate for the Serial port
	Serial.begin(4800);

  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x32)
  // init done


  // initialize timer1 ---------------------------------------
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;

  OCR1A = 9000;             // Load value to compare
  TCCR1B |= (1 << WGM12);   // CTC mode
  TCCR1B |= (1 << CS10);    // 64 prescaler
  TCCR1B |= (1 << CS11);    //
  TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt
  interrupts();             // enable all interrupts
  // ----------------------------------------------------------


  // Clear the buffer.
  display.clearDisplay();			// Clean display
  display.display();				// Refresh display

  display.setTextSize(2);			// Set text size on the display
  display.setTextColor(WHITE);		// Set text color on the display
  display.setCursor(36,18);			// Set the display cursor to position
  display.println("NMM-1");			// Print on display
  display.display();				// Refresh display
  delay(3000);
  display.clearDisplay();			// Clean display
  display.display();				// Refresh display

}   // END SETUP --------------------------------------------------------------------



// Timer compare interrupt service routine --------------------------
ISR(TIMER1_COMPA_vect)
{
	if (!rUP)						// If button UP pressed
	{
		if (menuState == 1){}		// Do nothing and leave menuState
									// as it is (1)
		else {
			menuState--;
		}
		while (!rUP);				// Check if button is still pressed, do nothing
	}


	if (!rDOWN)						// If button DOWN pressed
	{
		if (menuState == 4){}		// Do nothing and leave menuState
									// as it is (4)
		else {
			menuState++;
		}
		while (!rDOWN);				// Check if button is still pressed, do nothing
	}


	if (!rOK)						// If button OK pressed
	{
		if (menuState == 1)			// and the menuState is 1
		{
			prevMenu = menuState;	// set prevMenu to 1
			menuState = 10;			// then reset menuState to 10
		}
		else if (menuState == 2)	// If menuState is 2
		{
			prevMenu = menuState;	// set prevMenu to 2
			menuState = 11;			// then reset menuState to 11
		}
		else if (menuState == 3)	// If menuState is 3
		{
			prevMenu = menuState;	// set prevMenu to 3
			menuState = 12;			// then reset menuState to 12
		}
		else if (menuState == 4)	// If menuState is 4
		{
			prevMenu = menuState;	// set prevMenu to 4
			menuState = 13;			// then reset menuState to 13
		}
		while (!rOK);				// Check if button is still pressed, do nothing
	}

	if (!rCANCEL)					// If button CANCEL pressed
	{
		menuState = prevMenu;		// set menuState to same value as prevMenu
		while (!rCANCEL);			// Check if button is still pressed, do nothing
	}

}
// End of Timer compare interrupt ---------------------------------------


// Main loop routine -----------------------------------------
void loop()
{

	batt_val = analogRead(batt);		// Read analog value from battery into batt_val

	if (menuState == 1)					// If menuState is 1
	{
		one();							// call function one()
		mySerial.end();					// close serial connection
		read_s = 0;						// and set read_s to 0
	}
	else if (menuState == 2)			// If menuState is 2
	{
		two();							// call function two()
		mySerial.end();					// close serial connection
		read_s = 0;						// and set read_s to 0
	}
	else if (menuState == 3)			// If menuState is 3
	{
		three();						// call function three()
		mySerial.end();					// close serial connection
		read_s = 0;						// and set read_s to 0
	}
	else if (menuState == 4)			// If menuState is 4
	{
		four();							// call function four()
		mySerial.end();					// close serial connection
		read_s = 0;						// and set read_s to 0
	}
	else if (menuState == 10)			// If menuState is 10
	{
		if (read_s == 0)				// and read_s is 0
		{
			mySerial.begin(4800);					// Start serial with 4800bps
			read_s = 1;								// set read_s to 1
			display.clearDisplay();					// Clean display
			display.setTextSize(1);					// Set text size on the display
			display.setTextColor(WHITE);			// Set text color on the display
			display.setCursor(1,17);				// Set the display cursor to position
			display.println("Sending GPS.....");	// Print on display
			batt_icon();							// call function batt_icon()
			display.display();						// Refresh display
		}
		write_gps();								// call function write_gps()
	}
	else if (menuState == 11)						// If menuState is 11
	{
		if (read_s == 0)							// and read_s is 0
		{
			mySerial.begin(4800);					// Start serial with 4800bps
			read_s = 1;								// set read_s to 1
			display.clearDisplay();					// Clean display
			display.setTextSize(1);					// Set text size on the display
			display.setTextColor(WHITE);			// Set text color on the display
			display.setCursor(1,17);				// Set the display cursor to position
			display.println("Sending Heading.....");	// Print on display
			batt_icon();							// call function batt_icon()
			display.display();						// Refresh display
		}
		write_hdg();								// call function write_hdg()
	}
	else if (menuState == 12)						// If menuState is 12
	{
		if (read_s == 0)							// and read_s is 0
		{
			mySerial.begin(4800);					// Start serial with 4800bps
			read_s = 1;								// set read_s to 1
			display.clearDisplay();					// Clean display
			display.setTextSize(1);					// Set text size on the display
			display.setTextColor(WHITE);			// Set text color on the display
			display.setCursor(1,17);				// Set the display cursor to position
			display.println("Sending Depth.....");	// Print on display
			batt_icon();							// call function batt_icon()
			display.display();						// Refresh display
		}
		write_dep();								// call function write_dep()
	}
	else if (menuState == 13)						// If menuState is 13
	{
		if (read_s == 0)							// and read_s is 0
		{
			mySerial.begin(4800);					// Start serial with 4800bps
			read_s = 1;								// set read_s to 1
			display.clearDisplay();					// Clean display
			display.setTextSize(1);					// Set text size on the display
			display.setTextColor(WHITE);			// Set text color on the display
			display.setCursor(1,17);				// Set the display cursor to position
			display.println("RS-422 to USB");		// Print on display
			display.println("Sending...");			// Print on display
			batt_icon();							// call function batt_icon()
			display.display();						// Refresh display
		}
		read_serial();								// call function read_serial()
	}
	else											// otherwise
	{
		one();										// call function one()
		mySerial.end();								// close serial connection
		read_s = 0;									// set read_s to 0
	}
}
// END of Main loop routine -----------------------------------------



void batt_icon (void)
{


	if (batt_val > 962)								// If analog value is bigger then 962
	{
		// Draw the battery icon - Full battery
		display.drawRect(111, 1, 16, 6, WHITE);		// Draw white reactangle with coordinates
		display.drawRect(112, 2, 14, 4, WHITE);
		display.drawRect(113, 3, 12, 2, WHITE);
		display.drawPixel(110, 3, WHITE);			// Draw white dot with coordinates
		display.drawPixel(110, 4, WHITE);
		display.drawPixel(109, 3, WHITE);
		display.drawPixel(109, 4, WHITE);
		display.drawPixel(108, 3, WHITE);
		display.drawPixel(108, 4, WHITE);
	}

	else if ((batt_val > 901) & (batt_val < 962))	// If analog value is between 901 and 962
	{
		// Draw the battery icon - 2/3 battery
		display.drawRect(111, 1, 16, 6, WHITE);		// Draw white reactangle with coordinates
		display.drawRect(116, 2, 10, 4, WHITE);
		display.drawRect(117, 3, 8, 2, WHITE);
		display.drawPixel(110, 3, WHITE);			// Draw white dot with coordinates
		display.drawPixel(110, 4, WHITE);
		display.drawPixel(109, 3, WHITE);
		display.drawPixel(109, 4, WHITE);
		display.drawPixel(108, 3, WHITE);
		display.drawPixel(108, 4, WHITE);
	}

	else if ((batt_val > 840) & (batt_val < 901))	// If analog value is between 840 and 901
	{
	// Draw the battery icon - 1/3 battery
		display.drawRect(111, 1, 16, 6, WHITE);		// Draw white reactangle with coordinates
		display.drawRect(121, 2, 5, 4, WHITE);
		display.drawRect(122, 3, 3, 2, WHITE);
		display.drawPixel(110, 3, WHITE);			// Draw white dot with coordinates
		display.drawPixel(110, 4, WHITE);
		display.drawPixel(109, 3, WHITE);
		display.drawPixel(109, 4, WHITE);
		display.drawPixel(108, 3, WHITE);
		display.drawPixel(108, 4, WHITE);
	}

	else											// otherwise
	{
		// Draw the battery icon - Empty battery
		display.setCursor(35,1);					// Set the display cursor to position
		display.println("BATT LOW");				// Print on display
		display.drawRect(111, 1, 16, 6, WHITE);		// Draw white reactangle with coordinates
		display.drawPixel(110, 3, WHITE);			// Draw white dot with coordinates
		display.drawPixel(110, 4, WHITE);
		display.drawPixel(109, 3, WHITE);
		display.drawPixel(109, 4, WHITE);
		display.drawPixel(108, 3, WHITE);
		display.drawPixel(108, 4, WHITE);
	}
}

void one (void)
{
	display.clearDisplay();							// Clean display
	display.setTextSize(1);							// Set text size on the display
	display.setTextColor(WHITE);					// Set text color on the display
	display.setCursor(1,18);						// Set the display cursor to position
	display.println("Send GPS          <--");		// Print on display
	display.setCursor(1,28);						// Set the display cursor to position
	display.println("Send Heading");				// Print on display
	display.setCursor(1,38);						// Set the display cursor to position
	display.println("Send Depth");					// Print on display
	display.setCursor(1,48);						// Set the display cursor to position
	display.println("RS422 <==> USB");				// Print on display
	batt_icon();									// call function batt_icon()
	display.display();								// Refresh display
}

void two (void)
{
	display.clearDisplay();							// Clean display
	display.setTextSize(1);							// Set text size on the display
	display.setTextColor(WHITE);					// Set text color on the display
	display.setCursor(1,18);						// Set the display cursor to position
	display.println("Send GPS");					// Print on display
	display.setCursor(1,28);						// Set the display cursor to position
	display.println("Send Heading      <--");		// Print on display
	display.setCursor(1,38);						// Set the display cursor to position
	display.println("Send Depth");					// Print on display
	display.setCursor(1,48);						// Set the display cursor to position
	display.println("RS422 <==> USB");				// Print on display
	batt_icon();									// call function batt_icon()
	display.display();								// Refresh display
}

void three (void)
{
	display.clearDisplay();							// Clean display
	display.setTextSize(1);							// Set text size on the display
	display.setTextColor(WHITE);					// Set text color on the display
	display.setCursor(1,18);						// Set the display cursor to position
	display.println("Send GPS");					// Print on display
	display.setCursor(1,28);						// Set the display cursor to position
	display.println("Send Heading");				// Print on display
	display.setCursor(1,38);						// Set the display cursor to position
	display.println("Send Depth        <--");		// Print on display
	display.setCursor(1,48);						// Set the display cursor to position
	display.println("RS422 <==> USB");				// Print on display
	batt_icon();									// call function batt_icon()
	display.display();								// Refresh display
}

void four (void)
{
	display.clearDisplay();							// Clean display
	display.setTextSize(1);							// Set text size on the display
	display.setTextColor(WHITE);					// Set text color on the display
	display.setCursor(1,18);						// Set the display cursor to position
	display.println("Send GPS");					// Print on display
	display.setCursor(1,28);						// Set the display cursor to position
	display.println("Send Heading");				// Print on display
	display.setCursor(1,38);						// Set the display cursor to position
	display.println("Send Depth");					// Print on display
	display.setCursor(1,48);						// Set the display cursor to position
	display.println("RS422 <==> USB    <--");		// Print on display
	batt_icon();									// call function batt_icon()
	display.display();								// Refresh display
}

void read_serial (void)
{
	if (mySerial.available())						// If incoming NMEA0183 serial
	{
		Serial.write(mySerial.read());				// redirect it to USB
	}

	if (Serial.available())							// If incoming USB serial
	{
		mySerial.write(Serial.read());				// redirect it to NMEA0183 serial
	}
}

void write_gps (void)
{
	// Write NMEA0183 GPS sentence to USB
	mySerial.print("$GPGGA,090000.10,6350.37829338,N,02225.18272240,W,1,05,2.87,160.00,M,-21.3213,M,,*64");
	mySerial.println();								// Send string to NMEA0183 serial
	delay(100);
}

void write_hdg (void)
{
	// Write NMEA0183 Heading sentence to USB
	mySerial.print("$HEHDT,268.4,T*27");
	mySerial.println();								// Send string to NMEA0183 serial
	delay(100);
}

void write_dep (void)
{
	// Write NMEA0183 Depth sentence to USB
	mySerial.print("$SDDBT,0038.0,f,0011.6,M,0006.3,F");
	mySerial.println();								// Send string to NMEA0183 serial
	delay(100);
}
