/*
* Author: AnalysIR via http://www.AnalysIR.com/
*
* Date: 4th October 2015 V1.0
*
* License: Creative Commons, Attribution-NonCommercial-ShareAlike 4.0 International
*      http://creativecommons.org/licenses/by-nc-sa/4.0/
*
* For Commercial use or alternative License: Please contact the Author, via the website above
*
* Attribution: Please credit the Author on all media and provide a link to http://www.AnalysIR.com/
*
* Feedback: We would love to hear about how you use this software & suggestions for improvement.
*
*/

unsigned int carrierFreq = 0; //default wi;l be 38kHz

unsigned long sigTime = 0; //used in mark & space functions to keep track of time
unsigned long sigStart = 0; //used to calculate correct length of existing signal, to handle some repeats


//RAW NEC signal -32 bit with 1 repeat - make sure buffer starts with a Mark
unsigned int NEC_RAW[] = {9000, 4500, 560, 560, 560, 560, 560, 1690, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 1690, 560, 1690, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 560, 560, 560, 560, 1690, 560, 560, 560, 560, 560, 560, 560, 1690, 560, 560, 560, 1690, 560, 1690, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 560, 560, 1690, 560, 39980, 9000, 2232, 560}; //AnalysIR Batch Export (IRremote) - RAW

#define NEC_HEX_VALUE 0x20DF22DDL
#define NEC_BIT_COUNT 32
#define LED 13
#define txPinIR 4



//RAW Mitsubishi 88 bit signal  - make sure buffer starts with a Mark
unsigned int Mitsubishi88AC_RAW[] = {3172, 1586, 394, 394, 394, 1182, 394, 394, 394, 394, 394, 1182, 394, 394, 394, 1182, 394, 394, 394, 394, 394, 1182, 394, 1182, 394, 1182, 394, 394, 394, 1182, 394, 394, 394, 1182, 394, 1182, 394, 1182, 394, 394, 394, 394, 394, 394, 394, 394, 394, 1182, 394, 1182, 394, 394, 394, 1182, 394, 1182, 394, 394, 394, 394, 394, 1182, 394, 394, 394, 394, 394, 1182, 394, 394, 394, 394, 394, 1182, 394, 1182, 394, 394, 394, 1182, 394, 1182, 394, 1182, 394, 1182, 394, 1182, 394, 1182, 394, 1182, 394, 1182, 394, 1182, 394, 1182, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 1182, 394, 1182, 394, 1182, 394, 1182, 394, 1182, 394, 1182, 394, 394, 394, 1182, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 1182, 394, 394, 394, 394, 394, 1182, 394, 1182, 394, 1182, 394, 1182, 394, 1182, 394, 394, 394, 1182, 394, 1182, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 1182, 394, 394, 394}; //AnalysIR Batch Export (IRremote) - RAW

unsigned char Mitsubishi88AC_Hex[] = {0x4A, 0x75, 0xC3, 0x64, 0x9B, 0xFF, 0x00, 0xFD, 0x02, 0x7D, 0x82};

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(txPinIR, OUTPUT); //Sybchronous clock output, force clock to be output with sysnchronous comms
  digitalWrite(txPinIR, LOW);
  digitalWrite(LED, LOW);
}

void loop() { //just send example signals ever 5 seconds at a range of carrier frequencies

  //First send the NEC RAW signal defined above
  sendRawBuf(NEC_RAW, sizeof(NEC_RAW) / sizeof(NEC_RAW[0]), 30);
  delay(5000); //wait 5 seconds between each signal (change to suit)

  //Next send the Mitsubishi AC RAW signal defined above
  sendRawBuf(Mitsubishi88AC_RAW, sizeof(Mitsubishi88AC_RAW) / sizeof(Mitsubishi88AC_RAW[0]), 33);
  delay(5000); //wait 5 seconds between each signal (change to suit)

  //Next send the NEC_HEX_VALUE signal defined above
  sendHexNEC(NEC_HEX_VALUE, NEC_BIT_COUNT, 1, 38);
  delay(5000); //wait 5 seconds between each signal (change to suit)

  //Next send the Mitsubishi88AC_Hex signal defined above
  sendHexMITSUBISHI88AC(Mitsubishi88AC_Hex, sizeof(Mitsubishi88AC_Hex) / sizeof(Mitsubishi88AC_Hex[0]), 36);
  delay(5000); //wait 5 seconds between each signal (change to suit)

  //Next send the Mitsubishi88AC_Hex signal defined above
  sendHexNEC(NEC_HEX_VALUE, NEC_BIT_COUNT, 1, 40);
  delay(5000); //wait 5 seconds between each signal (change to suit)

  //Next send the Mitsubishi88AC_Hex signal defined above
  sendHexMITSUBISHI88AC(Mitsubishi88AC_Hex, sizeof(Mitsubishi88AC_Hex) / sizeof(Mitsubishi88AC_Hex[0]), 56);
  delay(5000); //wait 5 seconds between each signal (change to suit)

  //Next send the Mitsubishi88AC_Hex signal defined above
  sendHexMITSUBISHI88AC(Mitsubishi88AC_Hex, sizeof(Mitsubishi88AC_Hex) / sizeof(Mitsubishi88AC_Hex[0]), 455); //45 is used for 455kHz
  delay(5000); //wait 5 seconds between each signal (change to suit)

}

void sendRawBuf(unsigned int *sigArray, unsigned int sizeArray, unsigned int kHz) {
  digitalWrite(LED, HIGH); //blink LED for every signal - not needed
  initUPWM(kHz); //we only need to re-initialise if it has changed from last signal sent
  sigTime = micros(); //keeps rolling track of signal time to avoid impact of loop & code execution delays
  for (int i = 0; i < sizeArray; i++) {
    mark(sigArray[i++]); //also move pointer to next position
    if (i < sizeArray) { //check we have a space remaining before sending it
      space(sigArray[i]); //pointer will be moved by for loop
    }
  }
  digitalWrite(LED, LOW); //blink LED for every signal - not needed
}

void sendHexNEC(unsigned long sigCode, byte numBits, unsigned char repeats, unsigned int kHz) {
  /*  A basic 32 bit NEC signal is made up of:
   *  1 x 9000 uSec Header Mark, followed by
   *  1 x 4500 uSec Header Space, followed by
   *  32 x bits uSec ( 1- bit 560 uSec Mark followed by 1690 uSec space; 0 - bit 560 uSec Mark follwed by 560 uSec Space)
   *  1 x 560 uSec Trailer Mark
   *  There can also be a generic repeat signal, which is usually not neccessary & can be replaced by sending multiple signals
   */
#define NEC_HEADER_MARK 9000
#define NEC_HEADER_SPACE 4500
#define NEC_ONE_MARK 560
#define NEC_ZERO_MARK 560
#define NEC_ONE_SPACE 1690
#define NEC_ZERO_SPACE 560
#define NEC_TRAILER_MARK 560

  digitalWrite(LED, HIGH); //blink LED for every signal - not needed;

  unsigned long bitMask = (unsigned long) 1 << (numBits - 1); //allows for signal from 1 bit up to 32 bits
  //
  if (carrierFreq != kHz)  initUPWM(kHz); //we only need to re-initialise if it has changed from last signal sent

  sigTime = micros(); //keeps rolling track of signal time to avoid impact of loop & code execution delays
  sigStart = sigTime; //remember for calculating first repeat gap (space), must end 108ms after signal starts
  // First send header Mark & Space
  mark(NEC_HEADER_MARK);
  space(NEC_HEADER_SPACE);

  while (bitMask) {
    if (bitMask & sigCode) { //its a One bit
      mark(NEC_ONE_MARK);
      space(NEC_ONE_SPACE);
    }
    else { // its a Zero bit
      mark(NEC_ZERO_MARK);
      space(NEC_ZERO_SPACE);
    }
    bitMask = (unsigned long) bitMask >> 1; // shift the mask bit along until it reaches zero & we exit the while loop
  }
  // Last send NEC Trailer MArk
  mark(NEC_TRAILER_MARK);

  //now send the requested number of NEC repeat signals. Repeats can be useful for certain functions like Vol+, Vol- etc
  /*  A repeat signal consists of
   *   A space which ends 108ms after the start of the last signal in this sequence
  *  1 x 9000 uSec Repeat Header Mark, followed by
  *  1 x 2250 uSec Repeat Header Space, followed by
  *  32 x bits uSec ( 1- bit 560 uSec Mark followed by 1690 uSec space; 0 - bit 560 uSec Mark followed by 560 uSec Space)
  *  1 x 560 uSec repeat Trailer Mark
  */
  //First calculate length of space for first repeat
  //by getting length of signal to date and subtracting from 108ms

  if (repeats == 0) return; //finished - no repeats
  else if (repeats > 0) { //first repeat must start 108ms after first signal
    space(108000 - (sigTime - sigStart)); //first repeat Header should start 108ms after first signal
    mark(NEC_HEADER_MARK);
    space(NEC_HEADER_SPACE / 2); //half the length for repeats
    mark(NEC_TRAILER_MARK);
  }

  while (--repeats > 0) { //now send any remaining repeats
    space(108000 - NEC_HEADER_MARK - NEC_HEADER_SPACE / 2 - NEC_TRAILER_MARK); //subsequent repeat Header must start 108ms after previous repeat signal
    mark(NEC_HEADER_MARK);
    space(NEC_HEADER_SPACE / 2); //half the length for repeats
    mark(NEC_TRAILER_MARK);
  }
  //interrupts();
  digitalWrite(LED, LOW); //blink LED for every signal - not needed
}

void sendHexMITSUBISHI88AC(unsigned char *sigArray, unsigned int sizeArray, unsigned int kHz) { //Mitsubish 88 bit Ir protocol format
  /*  A basic 88 bit NEC-'like' signal is made up of:
   *  1 x 3172 uSec Header Mark, followed by
   *  1 x 1586 uSec Header Space, followed by
   *  32 x bits uSec ( 1- bit 394 uSec Mark followed by 1182 uSec space; 0 - bit 394 uSec Mark followed by 394 uSec Space)
   *  1 x 9000 uSec Trailer Mark
   *  There can also be a generic repeat signal, which is usually not neccessary & can be replaced by sending multiple signals
   */
#define MITSUBISHI88AC_HEADER_MARK 3172
#define MITSUBISHI88AC_HEADER_SPACE 1586
#define MITSUBISHI88AC_ONE_MARK 394
#define MITSUBISHI88AC_ZERO_MARK 394
#define MITSUBISHI88AC_ONE_SPACE 1182
#define MITSUBISHI88AC_ZERO_SPACE 394
#define MITSUBISHI88AC_TRAILER_MARK 394

  digitalWrite(LED, HIGH); //blink LED for every signal - not needed
  //
  if (carrierFreq != kHz)  initUPWM(kHz); //we only need to re-initialise if it has changed from last signal sent
  sigTime = micros(); //keeps rolling track of signal time to avoid impact of loop & code execution delays

  // First send header Mark & Space
  mark(MITSUBISHI88AC_HEADER_MARK);
  space(MITSUBISHI88AC_HEADER_SPACE);

  for (unsigned int i = 0; i < sizeArray; i++) { //iterate thru each byte in sigArray
    register unsigned char bitMask =  0x80; //starting value of bitmask fo each Hex byte
    while (bitMask) { //do 8 times for each bit of the 8 bit byte
      if (bitMask & sigArray[i]) { //its a One bit
        mark(MITSUBISHI88AC_ONE_MARK);
        space(MITSUBISHI88AC_ONE_SPACE);
      }
      else { // its a Zero bit
        mark(MITSUBISHI88AC_ZERO_MARK);
        space(MITSUBISHI88AC_ZERO_SPACE);
      }
      bitMask = (unsigned char) bitMask >> 1; // shift the mask bit along until it reaches zero & we exit the while loop
    }
  }
  // Last send NEC Trailer MArk
  mark(MITSUBISHI88AC_TRAILER_MARK);

  digitalWrite(LED, LOW); //blink LED for every signal - not needed
}

void initUPWM(unsigned int carrier) { // Assumes standard 8-bit Arduino, running at 16Mhz
  //supported values are 30, 33, 36, 38, 40, 56 kHz, any other value defaults to 38kHz
  //duty cycle is limited to 50, 40, 30, 20, 10 % - other values will be set to 40%

  if (carrierFreq == carrier) return; //already set up so no need to repeat
  pinMode(4, OUTPUT);

  digitalWrite(4, LOW);
  switch (carrier) { // set the baud rate to 10 time the carrier frequency
    case 30  : // 30kHz
      Serial.begin(30000 / 4);
      break;

    case 33  : // 33kHz
      Serial.begin(33000 / 4);
      break;

    case 36  : // 36kHz
      Serial.begin(36000 / 4);
      break;

    case 40  : // 40kHz
      Serial.begin(40000 / 4);
      break;

    case 56  : // 56kHz
      Serial.begin(56000 / 4);
      break;

    case 455  : // 455kHz  ( we actually get 444kHz, which is close enough)
      Serial.begin(455000 / 4);
      break;

    case 38  : //default is 38kHz
    default :
      Serial.begin(38000 / 4);
      break;
  }
  UCSR0B = 0x08; //enable TX pin D1, , rx pin is normal IO D0
  carrierFreq = carrier; //save for later to avoid repetition of init
}

void mark(unsigned int mLen) { //uses sigTime as end parameter
  //digitalWrite(txPinLowIR, HIGH);
  UCSR0C = 0x40; //enable Synchronous UART clock on pin 4
  unsigned long startTime = micros();

  sigTime += mLen; //mark ends at new sigTime

  unsigned long dur = sigTime - startTime; //allows for rolling time adjustment due to code execution delays

  if (dur == 0) return;

  while ((micros() - startTime) < dur) {} //just wait here until time is up

  UCSR0C = 0x00; //turn off the Synchronous UART clock on pin 4
}

void space(unsigned int sLen) { //uses sigTime as end parameter
  sigTime += sLen; //space ends at new sigTime
  unsigned long startTime = micros();
  unsigned long dur = sigTime - startTime; //allows for rolling time adjustment due to code execution delays
  if (dur == 0) return;
  while ((micros() - startTime) < dur) ; //just wait here until time is up
}