/*
 * Authors : Kerem Yollu & Edwin Koch
 * Date : 07.03.2021
 *
 * Description : 
 * TODO : Write description or doxygene 
 *
 */

#include <iostream>
#include <stdint.h>
#include <unistd.h>
#include <bitset>
#include <functional>

// Management
#include "./management/command/commandManager.h"

// Communication
#include "./communication/i2c/i2c.hpp"
#include "./systems/systemcall/systemCall.h"

// drivers
#include "./drivers/bh1750/bh1750.h"
#include "./drivers/pf8574/pf8574lcd.h"
#include "./drivers/pca9685/pca9685.h"
#include "./drivers/mcp4725/mcp4725.hpp"	
#include "./drivers/pca9555/pca9555.h"

// Periferals
#include "./periferals/gpio/gpio.hpp"

// Algorithms
#include "./algorithms/bitgestion/bitgestion.h"



CommandManager commander; 

I2C i2c;
char char_array[TOTAL_CHAR_CAP];


int initPlatform()
{
	lcd_init(&i2c); 
	Gpio gpio;
	gpio.pinUninitiate(17);
	gpio.config(17, Gpio::gpio, Gpio::output, Gpio::openDrain, Gpio::none, Gpio::slow); 
	gpio.readPin(17);
	gpio.writePin(17,1);
	gpio.readPin(17);
	gpio.writePin(17,0);
	gpio.readPin(17);
	return 0; 
}


void pca9555_test()
{
	uint8_t pinState = 0; 
	uint8_t bank = 0; 
	uint8_t pinNo = 0; 
	uint8_t inOut = 0; 

	Pca9555 gpioExpander(&i2c);
	gpioExpander.setAllOut(); 
	gpioExpander.setAllHigh();
	usleep(1000000);
	bank = 1;
	pinNo = 7; 
	gpioExpander.writePin(bank,pinNo,0);
	bank = 0;
	pinNo = 3; 
	inOut = 1; //input
	gpioExpander.setPin(bank,pinNo,inOut);

	while(1)
	{
		usleep(1000);
		pinState = gpioExpander.readPin(0,3);
		std::cout << "Pin State ; "<< unsigned(pinState) << std::endl;
	}
}


void pca9685_test()
{
	Pca9685 pwmGenarator(&i2c);
	pwmGenarator.setOnDutyPercent(0,50);
	for(int i = 3 ; i <= 255; i++)
	{	
		pwmGenarator.setPwmRaw(i);
		strcpy(char_array, "Pwm Freq: ");
		lcd_display_string(1,0,char_array,0); 
		std::string Msg = std::to_string(pwmGenarator.getPwmFreq()); 
		strcpy(char_array, Msg.c_str());
		lcd_display_string(1,10, char_array, 7); 
		strcpy(char_array, "Hz");
		lcd_display_string(1,18, char_array, 7); 
		usleep(200000);
	}
}



void pca9685_motor()
{
	Pca9685 pwmGenarator(&i2c);
	pwmGenarator.setPwmFreq(1500); 
	strcpy(char_array, "Pwm Freq: ");
	lcd_display_string(1,0,char_array,0); 
	std::string Msg = std::to_string(pwmGenarator.getPwmFreq()); 
	strcpy(char_array, Msg.c_str());
	lcd_display_string(1,10, char_array, 7); 
	strcpy(char_array, "Hz");
	lcd_display_string(1,18, char_array, 7); 
	int i = 0; 	
	for(i = 0 ; i <= 100; i++)
	{
		pwmGenarator.setOnDutyPercent(0,i);
		pwmGenarator.setOnDutyPercent(2,i);
		usleep(20000);
	}
	
	for(i = 100 ; i >= 0; i--)
	{
		pwmGenarator.setOnDutyPercent(0,i);
		pwmGenarator.setOnDutyPercent(2,i);
		usleep(20000);
	}
}


void mcp4725_test()
{

	uint8_t i = 0;
	std::cout << "mcp4725 dac test" << std::endl;
	
	
	MCP4725 dac(&i2c);
		  
	dac == 0x0000;
	
	for(i = 20 ; i > 0; i--)
	{
		
		std::cout << static_cast<unsigned int>(i) << std::endl;
		std::cout << "on" << std::endl;
		dac = 0xFFFF;
		usleep(2000000);	
		std::cout << "off" << std::endl;
		dac = 0x0000;
		usleep(2000000);

	}
	/*
	MCP4725 dac(//MCP4725::pwrd_md::normal,
	 	    MCP4725::i2c_addr::addr_0x6,
		    std::bind(&foo,  std::placeholders::_1));


	
	//MCP4725::pwrd_md g = MCP4725::pwrd_md::normal;
	MCP4725 dac(MCP4725::i2c_addr::addr_0x6,
		    std::bind(&I2C::writeBuffer,
			    &i2c,
			    std::placeholders::_1,
			    std::placeholders::_2,
			    std::placeholders::_3));
*/

}

void dac_test_1()
{
	uint16_t value = 0;
	
	MCP4725 dac(&i2c);
		  
	std::cout << "set dac value: ";
	std::cin >> value;

	dac = value;
}

void dummy() 
{
	std::cout << "Dummy" << std::endl;
}

void bh1750_test()
{
	Bh1750 lightSens(&i2c);
	while(1)
	{
//		std::cout << "value "<< lightSens.continious(BH1750_CONTINUOUS_HIGH_RES_MODE_1,1) << " Lux" <<std::endl; 
		std::string Msg = std::to_string(lightSens.continious(BH1750_CONTINUOUS_HIGH_RES_MODE_1,1)); 
		char char_array[TOTAL_CHAR_CAP];
		strcpy(char_array, Msg.c_str());
		lcd_display_string(2,0, char_array,5); 
		usleep(150*1000);
	}
}


int main(int argc, char *argv[])
{
	// Init 
	initPlatform(); 
	std::cout << "Main Begin" << std::endl;
	commander.addNewCommand("dummy", "The test command for testing the test", dummy);
	commander.addNewCommand("bh1750", "The test command for testing the bh1750", bh1750_test);
	commander.addNewCommand("pca9685", "The test command for testing the pca8695", pca9685_test);
	commander.addNewCommand("motor", "The test command for testing the pca8695", pca9685_motor);
	commander.addNewCommand("dac", "The test command for testing the mcp4725", mcp4725_test);
	commander.addNewCommand("set_dac_val", "The test command for setting the mcp4725 manually", dac_test_1);
	commander.addNewCommand("pca9555", "The test command for setting the mcp4725 manually", pca9555_test);
	commander(argv[1]); 	
	std::cout << "Main End" << std::endl;

	return 1; 
}
