#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
//#include <math.h>
#define TEMPS 4
#define LOG 0
#define AVG_SECS 3
#define MAX_SEC 255
/*
const char *Locations[9] = {
	"/sys/class/hwmon/hwmon2/pwm1_enable",
	"/sys/class/hwmon/hwmon1/pwm1_enable",
	"/sys/class/hwmon/hwmon2/pwm3_enable",
	"/sys/class/hwmon/hwmon0/temp1_input",
	"/sys/class/hwmon/hwmon1/temp1_input",
	"/sys/class/hwmon/hwmon0/temp1_input",
	"/sys/class/hwmon/hwmon2/pwm1",
	"/sys/class/hwmon/hwmon1/pwm1",
	"/sys/class/hwmon/hwmon2/pwm3"
};
*/
const char *Enable[TEMPS] = {
	"/sys/class/hwmon/hwmon3/pwm1_enable",
	"/sys/class/hwmon/hwmon2/pwm1_enable",
	"/sys/class/hwmon/hwmon3/pwm2_enable",
	"/sys/class/hwmon/hwmon3/pwm3_enable"
};

///sys/class/hwmon/hwmon6/temp1_input
const char *Temp[TEMPS] = {
	"/sys/class/hwmon/hwmon0/temp1_input",
	"/sys/class/hwmon/hwmon2/temp1_input",
	"/sys/class/hwmon/hwmon6/temp1_input",
	"/sys/class/hwmon/hwmon0/temp1_input"
};

const char *Pwm[TEMPS] = {
	"/sys/class/hwmon/hwmon3/pwm1",
	"/sys/class/hwmon/hwmon2/pwm1",
	"/sys/class/hwmon/hwmon3/pwm2",
	"/sys/class/hwmon/hwmon3/pwm3"
};



struct fan_params {
	uint8_t pwm;
	uint8_t temp;
	uint8_t maxtemp;
	uint8_t mintemp;
	uint8_t medtemp;
	uint8_t maxpwm;
	uint8_t minpwm;
	uint8_t medpwm;
	uint8_t highpwm;
};

uint8_t avg(uint8_t *readings){
	uint8_t i;
	uint16_t sum = 0;
	for(i=0; i<AVG_SECS; i++){
		sum += readings[i];
	}
	return (uint8_t)(sum/i);
}


int main(int argc, char **argv){
	FILE *fp;

#if LOG==1
	FILE *log;
#endif
	uint8_t num1; //curpwm, curtemp;
	uint8_t num2;
	// cpu gpu mem intake
	struct fan_params Params[TEMPS] = {{0, 0, 50, 20, 40, 255, 105, 150, 200}, {0, 0, 70, 40, 55, 255, 40, 100, 185}, {0, 0, 44, 30, 37, 255, 0, 20, 100}, {0, 0, 50, 20, 40, 255, 120, 180, 230}}; //{0, 0, 50, 20, 40, 255, 100, 133, 200}};
	char linestring[7];
	uint8_t temp_five[TEMPS][AVG_SECS]; //= {{255, 255, 255}, {255, 255, 255}, {255, 255, 255}}; , {[0 ... AVG_SECS] = 255}};  = {{255, 255, 255, 255, 255}, {255, 255, 255, 255, 255}, {255, 255, 255, 255, 255}};
	//uint8_t avg_temp = 0;
	uint8_t sec = 0;

	//memset((void *)temp_five[num1], 255, AVG_SEC);
	//Enable pwm control
	for(num1=0; num1<TEMPS; num1++){
		memset((void *)temp_five[num1], 255, AVG_SECS);
		if ( (fp = fopen(Enable[num1], "w")) ){
			fprintf(fp, "%u\n", 1 );
		}
		fclose(fp);
	}

	//open logdir
	//if ( (log = fopen("/gputemps.txt", "a")) == NULL){
	//	//fprintf(fp, "%u\n", 1 );
	//	fprintf( stderr, "Error opening log file\n");
	//}

	//Main loop
	while(1){


		//Read Temperatures
		for(num1=0; num1<TEMPS; num1++){
			Params[num1].temp = 100;
			if( ( fp = fopen(Temp[num1], "r" ) ) == NULL ) {
				fprintf( stderr, "Error opening %s\n", Temp[num1] );
			}else{
				if( fgets(linestring, sizeof(linestring), fp) == NULL){
					fprintf( stderr, "Error reading %s\n", Temp[num1] );
				}else{
					//Params[num1].temp = atoi(linestring)/1000;
					temp_five[num1][sec] = atoi(linestring)/1000;
					Params[num1].temp = avg(temp_five[num1]);
				}
			}
			fclose(fp);
			//Params[num1].temp = curtemp;
		}

		for(num1=0; num1<3; num1++){
			//if(num1==2){
			//	curpwm = Params[1].pwm>Params[0].pwm ? Params[1].pwm : Params[0].pwm;
			if(Params[num1].temp < Params[num1].mintemp){
				Params[num1].pwm = Params[num1].minpwm*Params[num1].temp/Params[num1].mintemp;
			}else if(Params[num1].temp < Params[num1].medtemp){
				Params[num1].pwm = Params[num1].medpwm*Params[num1].temp/Params[num1].medtemp;
			}else if(Params[num1].temp < Params[num1].maxtemp){
				Params[num1].pwm = Params[num1].highpwm*Params[num1].temp/Params[num1].maxtemp;
			}else{
				Params[num1].pwm = Params[num1].maxpwm;
			}
			//Params[num1].pwm = curpwm;
		}
		num2 = Params[1].pwm>Params[0].pwm ? Params[1].pwm : Params[0].pwm;
//		while(num1<TEMPS){
			if(num2 > Params[num1].minpwm)
				Params[num1].pwm = num2;
			else
				Params[num1].pwm = Params[num1].minpwm;
//			num1++;
//		}

		//if(num2 > Params[num1].minpwm)
		//	Params[num1].pwm = num2;
		//else
		//	Params[num1].pwm = Params[num1].minpwm;
		//Params[num1].pwm = Params[1].pwm>Params[0].pwm ? Params[1].pwm : Params[0].pwm;

		for(num1=0; num1<TEMPS; num1++){
			if ( (fp = fopen(Pwm[num1], "w")) ){
				fprintf(fp, "%u\n", Params[num1].pwm );
//fprintf(fp, "%u\n", Params[num1].maxpwm );
			}
			fclose(fp);
		}
#if LOG==1
// /sys/class/hwmon/hwmon2/temp5_input



		if( ( fp = fopen("/sys/class/hwmon/hwmon2/temp5_input", "r" ) ) == NULL ){
			fprintf( stderr, "Error opening vrm input file\n");
		}else{
			if( fgets(linestring, sizeof(linestring), fp) == NULL){
				fprintf( stderr, "Error reading vrm input file\n");
			}else{
				if ( (log = fopen("/vrmtemps.txt", "a")) == NULL){
					fprintf( stderr, "Error opening vrm log file\n");
				}else{
					num2 = atoi(linestring)/1000;
					fprintf(log, "%u\n", num2);
				}
				fclose(log);
			}
		}
		fclose(fp);
		//if ( (log = fopen("/gputemps.txt", "a")) == NULL){
		//	fprintf( stderr, "Error opening log file\n");
		//}
		//fprintf(log, "%u %u\n", Params[1].temp, Params[1].pwm );
		//fclose(log);
#endif

		//	Params[num1].pwm = curpwm;
		if(sec==AVG_SECS-1)
			sec=0;
		else
			sec++;

		sleep(1);
	}
	//fclose(log);
	return 0;
}
