// 
// 
// 

#include "GPIOHelper.h"

void GPIOHelper::Init() {
	SensorPulse = 0;
	PrintArray(SensorData);
	Serial.println(SensorData.size());
	for (int i = 0; i < SensorData.size(); i++) {
		SensorData.remove(0);
	}
	pinMode(IR_SENSOR_INPUT, INPUT);
	Serial.println("initialised");
}

void GPIOHelper::Reset() {
	LastSensorState = 0;
	SensorPulse = 0;
	SensorData.clear();
}

void GPIOHelper::Check() {
	int state = digitalRead(IR_SENSOR_INPUT);
	
	if (state != LastSensorState) {
		//Serial.println("new state");
		LastSensorState = state;
		unsigned long c_time = micros();
		unsigned long c_pulse = c_time - SensorPulse;
		//Serial.println(c_time);
		if (c_pulse >= PULSE_MIN && c_pulse <= PULSE_MAX) {
			//valid pulse, process bit..
			ProcessBit(c_pulse);
		}
		else {
			if(SensorData.size()>= DATA_BIT_LENGTH)
				SensorData.clear();
		}
		SensorPulse = c_time;
	}
	return;
}

void GPIOHelper::ProcessBit(unsigned long pulseWidth) {
	if (pulseWidth >= PULSE_ONE) {
		SensorData.add(1);
	}
	else {
		SensorData.add(0);
	}
	//Serial.print("pulse: ");
	//Serial.println(pulseWidth);
	//Serial.println(SensorData.size());
	if (SensorData.size() == DATA_BIT_LENGTH) {
		//Serial.println("processing packet");
		// first two bytes have to be zero
		if (SensorData.get(0) == 0 && SensorData.get(1) == 0) {
			//Serial.print("SensorDataLen: ");
			//Serial.println(SensorData.size());
			int datChkSum = SensorData.get(DATA_BIT_LENGTH-1);
			SensorData.remove(DATA_BIT_LENGTH-1);		//remove "checksum"
			SensorData.remove(0);							//remove two headers
			SensorData.remove(0);

			//Serial.println("publishing");
			PublishData(SensorData, datChkSum);
			while (SensorData.size() != 0) {
				SensorData.pop();
			}
		}
		else {
			SensorData.remove(0);
		}
		//Serial.println("Exiting..");
	}
	return;
}

void GPIOHelper::PublishData(LinkedList<int>& data, int checksum) {
	int id = -1;
	bool validPacket = false;
	unsigned int numOnes = Num_Ones_In_Buffer(data);
	unsigned int calcChkSum = numOnes % 2;
	/*Serial.print("1 count: ");
	Serial.print(numOnes);
	Serial.print(", odd number:");
	Serial.print(checksum);
	Serial.print(", calculated chk:");
	Serial.println(calcChkSum);*/
	if (calcChkSum == checksum)
		validPacket = true;

	if (validPacket) {
		id = ConvertBitArrayToInt(data);
	}

	if (validPacket && id != 0) {
		Serial.print("Id is: ");
		Serial.println(id);
		transponderId = id;
		_evm.queueEvent(ID_RECOGNISED_EVENT, transponderId);
	}
	//Serial.println("exiting publish");
	return;
}
void GPIOHelper::PrintArray(LinkedList<int>& arr) {
	for (int i = 0; i < arr.size(); i++) {
		Serial.println(arr.get(i));
	}
	return;
}
int GPIOHelper::ConvertBitArrayToInt(LinkedList<int>& arr) {
	int multiplier = 1;
	long bin = 0;
	for (int i = arr.size()-1; i>=0; i--)
	{
		bin = bin + (multiplier * arr.get(i));
		multiplier = multiplier* 2;
	}
	return bin;
}

unsigned int GPIOHelper::Num_Ones_In_Buffer(LinkedList<int>& data) {
	unsigned int t = 0;
	for (int i = 0; i < data.size(); i++) {
		if (data.get(i) == 1) {
			t += 1;
		}
	}
	return t;
}
