// GndStation.cpp : Decode tiemstamped telemetry data as produced from our module.
//

#include "stdafx.h"

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include "math.h"

using namespace std;

void loadSettings(int& low, int& high, int modes[], string unitnames[], unsigned short int& numchans); // set up channel parameters
void writeHeaderRow(ofstream& fout, bool digislot[], int modes[]); // write first line of output file
void hexToDec(string data, short int chandat[]); // convert ASCII hex data to integer

int main(int argc, char* argv[])
{
	string infilename;
	string outfilename;
	string timestamp;
	ifstream fin;
	ofstream fout;
	
	string buffer;
	
	int modes[8];
	int high=0, low=0;

	//.string channames[8]={"C0","C1","C2","C3","C4","C5","C6","C7"};
	string unitnames[8];
	//string::size_type chanloc[8];
	string data;
	
	short int chandat[8]={0}; // integer between 0-255
	float chandatproc[8]={0}; // voltage between 0-5V
	bool digitaldata[8]={false};	
	bool digichannel[8]={false};
	bool digislot[8]={false};
	int digichannum=0;
	int digiwidth[8]={0};
	int digistartpos[8]={0};
	bool start=true;
	int bitmasks[8]={0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
	int digitaldatapos=0;
	int currentdigidata=0;
	unsigned short int subtractor=0;
	unsigned short int numchans=0;


	loadSettings(low, high, modes, unitnames, numchans);

	do
	{	
		fin.clear();
		cout << "Enter the filename containing the decoded data:  ";
		cin >> infilename;
		fin.open(infilename.c_str());
		if (!fin)
			cout << "Input file " << infilename << " does not exist.  Please check the filename and try again." <<endl;
	}while(!fin);

	cout << "Enter the filename for the output file:  ";
	cin >> outfilename;
	fout.open(outfilename.c_str());
	cout << endl;
	
	for (unsigned short int k=0; k<8; k++)
	{
		
		if (modes[k]>1) digichannel[k]=true; // flag all channels that are part of the digital data
			
		start=true;

		for (unsigned short int l=0; l<8; l++)
		{	
			
			if (modes[l]==digichannum+2) // set up digital parameters
			{
				digislot[k]=true; // there could be up to eight digital data groups; flag each one being used
				if (start) digistartpos[k]=l; // determine where each digital channel starts
				digiwidth[k]++; // determine width of each digital channel
				start=false;
			}
		}
		digichannum++;
	}

	writeHeaderRow(fout, digislot, modes);

	while(fin)
	{
		getline(fin, buffer);
		cout << "Raw packet:  " << buffer << endl;

		string::size_type timestamploc=buffer.find('[',0); // timestamp is bracketed on TNC2's
		string::size_type timestampend=buffer.find(']',0);

		if (timestamploc!=string::npos)
		{
			timestamp=buffer.substr(timestamploc+1, timestampend-timestamploc-1);
			cout << "Time:  " << timestamp << endl;
			fout << timestamp;
		}

		string::size_type startloc=buffer.find_last_of(':',string::npos); // find where the packet payload begins (after last colon)
		
		if (startloc!=string::npos)
			data=buffer.substr(startloc+1,numchans*2); 
		
		else continue;

		hexToDec(data, chandat); // Convert character hex data to integer

		for (unsigned short int i=0; i<8; i++)
		{
			chandatproc[i]=(chandat[i]-low)*(5.0/(high-low)); // Convert integer to voltage
				
			if (modes[i]==1)
			{
				cout << "Channel " << i << ": " << chandatproc[i] << unitnames [i] << endl;	 // Append unit name and write to screen and file
				fout << "," << chandatproc[i];
			}
			
			if (modes[i]>1) digitaldata[i]=(chandatproc[i]>=2);//Process digital data: TTL definition of high (>2V)
			
		}
		
		for (unsigned short int m=0; m<8; m++) // calculate value of digital data based on the width of the digital field
		{
			currentdigidata=0;
			subtractor=1;
			
			if (digislot[m])
			{
				for (unsigned short int p=digistartpos[m]; p<digistartpos[m]+digiwidth[m]; p++)
				{
					currentdigidata+=digitaldata[p]*pow(2,(digiwidth[m]-subtractor)); // determine the power of two represented by the current field & add to the digital value if it's a 1
					subtractor++;
				}
			cout << "Digital group " << m << ": " << currentdigidata << endl; // after calculating the value, write it
			fout << "," << currentdigidata;
			}
		}
	fout << endl;		
	}
	fin.close();
	fout.close();
	return 0;
}

void loadSettings(int& low, int& high, int modes[], string unitnames[], unsigned short int& numchans)
{
	unsigned short int lsi=0; // loop counter
	unsigned short int lsj=0; // loop counter
	string mode; // temporary storage location for the mode designator
	string unit; // temporary storage location for the unit designator
	ifstream cfgin; // input file stream

	cfgin.open("decode.ini"); // look for file decode.ini
	if (!cfgin)
	{
		cout << "Configuration file not found.  Please see GndStation.txt for help." << endl;
		exit(1); // terminate if not found
	}
	
	cfgin>>low; // first line of file is the integer value corresponding to 0V, ideally 0 (00 from module)
	cfgin.ignore(255,'\n');
	cfgin>>high; // second line of file is the hex value corresponding to 5V, ideally 255 (FF from module)
	cfgin.ignore(255,'\n');

	while (cfgin)
	{
		cfgin >> mode; // Mode "A" is analog, mode "I" is ignore, mode "Dx" is digital channel x
		if (mode[0]=='I')
			modes[lsi++]=0; // In the modes array, 0=ignore, 1=analog, >1 digital
		if (mode[0]=='A')
		{
			modes[lsi++]=1;
			numchans++;
		}
		if (mode[0]=='D')
		{
			modes[lsi++]=(mode[1]-'0')+2; // 2=digital ch 0, 3=digital ch 1, etc.
			numchans++;
		}
		
		if (mode[0]=='A' || mode[0]=='D') cfgin >> unitnames[lsj++]; // capture unit name for analog or digital channel

		cfgin.ignore(255,'\n');
	}
}

void writeHeaderRow(ofstream& fout, bool digislot[], int modes[]) // setup CSV header row
{
	int whri=0; // loop counter
	fout << "Timestamp"; 
	for (whri=0; whri<8; whri++) if (modes[whri]==1) fout << ",Analog Ch. " << whri;
	whri=0;
	for (whri=0; whri<8; whri++) if (digislot[whri]) fout << ",Digital Ch. " << whri;
	fout << endl;
}
		

void hexToDec(string data, short int chandat[8]) // convert two character hex to integer
{ 
	unsigned short int htdj=0; // loop counter
	string currentbyte;

	for(unsigned short int htdi=0; htdi<data.length(); htdi+=2)
	{
		currentbyte=data.substr(htdi,2);
		
		if (currentbyte[0]>64) //if the first byte is 'A' through 'F'...
			chandat[htdj]=16*(10+(currentbyte[0]-65)); // subtract 'A', add 10, and multiply by 16
		else
			chandat[htdj]=16*(currentbyte[0]-48); // if the first byte is '0' through '9', subtract '0' and multiply by 16

		if (currentbyte[1]>64) // use the same logic for the second byte
			chandat[htdj]+=(10+(currentbyte[1]-65));
		else
			chandat[htdj]+=(currentbyte[1]-48);

		htdj++;
	}
}