#include <stdio.h>
#include <string>
#include <unistd.h>

#include "../hubolib.h"
#include "CStringDump.h"

using namespace HuboLib;
using namespace BCM2835;

using namespace std;

/*
Compile and link:
	g++ Transceiver.cpp CStringDump.cpp -L../ -lhubo -lpthread -lrt -o Transceiver.out
Run:
	sudo ./Transceiver.out <r|w> <filename>
Purpose:
	The demo shows how the GPIO interface can be used to read in and bit bang out a stream of bits
	from and to two 433MHz transmission modules.
*/


void ReceiveToFile		(unsigned short pin, string sFilename, unsigned long long breakTime);
void TransmitFromFile	(unsigned short pin, string sFilename, int repeatCount);


int main(int argc, char *argv[])
{
	if (argc!=3 || !(argv[1][0]=='r'||argv[1][0]=='w'))
	{
		printf (
				"Usage:\n"
				"receive <r|w> <filename>\n"
				"r: read radio signals into filename\n"
				"w: write content of filename to transmitter\n"
				);
		return -1;
	}

	unsigned char command = argv[1][0];
	string sFilename = argv[2];

	if (!BCM2835::IsGPIOInitialized ())
	{
		printf ("GPIO not properly initialized. Are you running the program as sudoer?\n");
		return -1;
	}

	// The two pins we will use for bit banging.
	unsigned short transmit_pin  = 17; // BCM GPIO=17 = GPIO0 = Raspi pinheader 11
	unsigned short receive_pin   = 22; // BCM GPIO=22 = GPIO3 = Raspi pinheader 15

	switch (command)
	{
	case 'r':
		ReceiveToFile(receive_pin, sFilename, 1000000);
		break;
	case 'w':
		TransmitFromFile(transmit_pin, sFilename, 1);
		break;
	}

	return 0;
}

void ReceiveToFile(unsigned short pin, string sFilename, unsigned long long breakTime)
{
	FunctionSelectPin(pin, Input);
	SetPullUpDown(pin, PUD_OFF);
	// SetPullUpDown(pin, PUD_UP);

	unsigned long long now, last_time, delay;
	now = last_time = GetTime_MicroSeconds();
	unsigned short last_value, value;
	last_value = value = 0;

	CStringDump log(sFilename);
	log.Reset();
	
	while (1)
	{
		value = ReadPin(pin);
		if (value != last_value)
		{
			now = GetTime_MicroSeconds();
			delay = now - last_time;

			if (delay >= breakTime)
			{
				if (log.GetCount() > 0)
				{
					log.Dump();
					printf ("Writing done...\n");
					sleep(1);
					log.Reset();
				}
			}
			else
			{
				char buffer[128];
				sprintf (buffer, "%ld %d\n", (long) delay, value);
				log.Add(buffer);
				// printf ("%s", buffer); // Uncomment for testing purposes.
			}

			last_value = value;
			last_time = now;
		}
	}
}

void TransmitFromFile (unsigned short pin, string sFilename, int repeatCount)
{
	std::list<unsigned long long>	m_DelayList;
	std::list<int>					m_ValueList;

	// Read file into the above lists.
	FILE* pFile = fopen (sFilename.c_str(), "r");
	if (!pFile)
	{
		printf ("Error opening file!\n");
		return;
	}
	char buffer[128];
	while (fgets(buffer, 128, pFile))
	{
		unsigned long long delay;
		int value;
		if (sscanf(buffer, "%llu %d", &delay, &value) != 2)
			printf ("Error in format reading\n");
		else
		{
			m_DelayList.push_back(delay);
			m_ValueList.push_back(value);
		}
	}
	fclose(pFile);

	// Check content.
	if (m_DelayList.empty() || m_ValueList.empty())
	{
		printf ("Files seem to be empty.\n");
		return;
	}

	// Define output pin.
	FunctionSelectPin(pin, Output);

	// Replay data from the two lists.
	for (int i=0; i<repeatCount; i++)
	{
		std::list<unsigned long long>::iterator iterator_delay = m_DelayList.begin();
		std::list<int>::iterator iterator_value = m_ValueList.begin();

		while (iterator_delay != m_DelayList.end() && iterator_value != m_ValueList.end())
		{
			Delay_MicroSeconds((unsigned long)*iterator_delay);
			WritePin (pin, (unsigned char) *iterator_value);
			// printf ("%llu %d\n", *iterator_delay, *iterator_value);
			iterator_delay++;
			iterator_value++;
		}
	}
}
