// Sample Chofu heat pump remote control code, use with TSOP1738 circuit where idle state = 1 and output is inverted
// results first to RAM because printing on the run causes missed INTs
// 16.5.2011 mstr

#include <owntimer.h>
int bit1, i, j, ti, freq;
char n;
volatile byte portstate = 0;
int ones = 0;
int pri = 0;
byte result = 0;
byte res[1500];		// save samples to RAM, 1500 bytes can hold 12000 samples which corresponds to 15 samples/ms for 800 ms, for example
byte start = 0;
unsigned long cntrtest0 = 0;
unsigned long cntrtest = 0;				// counts the number of INTs 
unsigned long times0;					// ms timer value at start
unsigned long times1;					// ms timer value at end
unsigned long cntr8 = 0;
unsigned long idle = 0;					// idle loop counter just to detect how much time is left over

void readport() {					// INT routine
  portstate = PINB | B01000000;
}

void setup() {
  Serial.begin (115200); 
  pinMode ( 9 , INPUT);					// connect signal from TSOP1738 to portB pin 9
  while (Serial.available() <= 0) {			// wait trigger from PC
  }
  n = Serial.read();					// get multiplier for the sampling frequency n * 3 kHz
  ti = n - '0';
  freq = ti*3000; 
  Serial.print ("I: taajuus ");
  Serial.println (freq, DEC);
  owntimer::set(freq, readport);			// initialize ATMega328
  owntimer::start();					// start INT timer
}

void loop() {
  if ((portstate & B01000000) != 0) {			// check if INT occurred
    bit1 = portstate & B00000010;			// copy the state of input pin
    cntrtest++;						// counts the number of INTs
    portstate = 0;
    if ((start == 1) || ( bit1 == B00000000)) {		// recording starts with the first sample in state '0', afer that every bit recorded
      cntr8++;		  				// this indicates when 8 bits recorded and one byte can be saved
      portstate = 0;
      result <<= 1;
      if (start == 0) {
	times0 = millis();				// record start time
	cntrtest0 = cntrtest;				// record idle count start
	start = 1;					// indicates that recording on
      }
      if (bit1 == B00000010) {				// input bit '1'
	result = result | 0x01;
	ones++;						// count consecutive ones in order to end recording when all ones
      }							// Chofu sends two identical groups, stop after the first
      else {						// input bit '0'
 	if (ones <= 160) {				// value 160 learned in tests, other brands may need other values
	result = result & 0xFE;
	  ones = 0;					// a received '0' resets the consecutive-ones-counter
	}
      }
      if ((cntr8%8 == 0) && (ones <= 160)) {		// save result byte, stop saving when all ones
	j = j + 1;
	res[j] = result;
      }
    }
  }
  else {						// idle loop, INT has not occurred
    if (start == 1) {					
      idle++;						// counts the number of times in idle loop
    }
  }
  if ((ones >= 161) && (pri == 0)) {			// stop recording
	owntimer::stop();
	pri = 1;
	times1 = millis();
	Serial.print ("I: alkuaika ");
	Serial.print (times0, DEC);
	Serial.print (" loppuaika ");
	Serial.print (times1, DEC);
	Serial.print (" aikavali ");
	Serial.println (times1-times0, DEC);

	Serial.print ("I: bytes and idle count ");
	Serial.print (j, DEC);
	Serial.print ("  ");
	Serial.println (idle, DEC);

	Serial.print ("I: int lkm alussa: ");
	Serial.print (cntrtest0, DEC);
	Serial.print (" int lkm lopussa: ");
	Serial.print (cntrtest, DEC);
	Serial.print (" int lkm erotus: ");
	Serial.println (cntrtest-cntrtest0, DEC);

	Serial.print ("I: ");
	Serial.println (res[1], HEX);
	
	for (i = 1; i < j; i++) {
	  Serial.println (res[i], HEX);
	}
  }
}
