Esempio n. 1
0
// Calculate & set any offsets to account for execution times.
//
// Args:
//   hz: The frequency to calibrate at >= 1000Hz. Default is 38000Hz.
//
// Status:  ALPHA / Untested.
//
// NOTE:
//   This will generate an 65535us mark() IR LED signal.
//   This only needs to be called once, if at all.
void IRsend::calibrate(uint16_t hz) {
  if (hz < 1000)  // Were we given kHz? Supports the old call usage.
    hz *= 1000;
  periodOffset = 0;  // Turn off any existing offset while we calibrate.
  enableIROut(hz);
  IRtimer usecTimer = IRtimer();  // Start a timer *just* before we do the call.
  uint16_t pulses = mark(UINT16_MAX);  // Generate a PWM of 65,535 us. (Max.)
  uint32_t timeTaken = usecTimer.elapsed();  // Record the time it took.
  // While it shouldn't be neccesary, assume at least 1 pulse, to avoid a
  // divide by 0 situation.
  pulses = std::max(pulses, (uint16_t) 1U);
  uint32_t calcPeriod = calcUSecPeriod(hz);  // e.g. @38kHz it should be 26us.
  // Assuming 38kHz for the example calculations:
  // In a 65535us pulse, we should have 2520.5769 pulses @ 26us periods.
  // e.g. 65535.0us / 26us = 2520.5769
  // This should have caused approx 2520 loops through the main loop in mark().
  // The average over that many interations should give us a reasonable
  // approximation at what offset we need to use to account for instruction
  // execution times.
  //
  // Calculate the actual period from the actual time & the actual pulses
  // generated.
  double_t actualPeriod = (double_t) timeTaken / (double_t) pulses;
  // Store the difference between the actual time per period vs. calculated.
  periodOffset = (int8_t) ((double_t) calcPeriod - actualPeriod);
}
Esempio n. 2
0
// Set the output frequency modulation and duty cycle.
//
// Args:
//   freq: The freq we want to modulate at. Assumes < 1000 means kHz else Hz.
//   duty: Percentage duty cycle of the LED. e.g. 25 = 25% = 1/4 on, 3/4 off.
//
// Note:
//   Integer timing functions & math mean we can't do fractions of
//   microseconds timing. Thus minor changes to the freq & duty values may have
//   limited effect. You've been warned.
void IRsend::enableIROut(uint32_t freq, uint8_t duty) {
  // Can't have more than 100% duty cycle.
  duty = std::min(duty, (uint8_t) 100);
  if (freq < 1000)  // Were we given kHz? Supports the old call usage.
    freq *= 1000;
  uint32_t period = calcUSecPeriod(freq);
  // Nr. of uSeconds the LED will be on per pulse.
  onTimePeriod = (period * duty) / 100;
  // Nr. of uSeconds the LED will be off per pulse.
  offTimePeriod = period - onTimePeriod;
}
Esempio n. 3
0
// Send a Pronto Code formatted message.
//
// Args:
//   data: An array of uint16_t containing the pronto codes.
//   len: Nr. of entries in the data[] array.
//   repeat: Nr. of times to repeat the message.
//
// Status: ALPHA / Not tested in the real world.
//
// Note:
//   Pronto codes are typically represented in hexadecimal.
//   You will need to convert the code to an array of integers, and calculate
//   it's length.
//   e.g.
//      A Sony 20 bit DVD remote command.
//      "0000 0067 0000 0015 0060 0018 0018 0018 0030 0018 0030 0018 0030 0018
//       0018 0018 0030 0018 0018 0018 0018 0018 0030 0018 0018 0018 0030 0018
//       0030 0018 0030 0018 0018 0018 0018 0018 0030 0018 0018 0018 0018 0018
//       0030 0018 0018 03f6"
//
//   converts to:
//
//       uint16_t prontoCode[46] = {
//           0x0000, 0x0067, 0x0000, 0x0015,
//           0x0060, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018, 0x0030, 0x0018,
//           0x0030, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018,
//           0x0018, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018,
//           0x0030, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
//           0x0030, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018,
//           0x0018, 0x03f6};
//       // Send the Pronto(Sony) code. Repeat twice as Sony's require that.
//       sendPronto(prontoCode, 46, SONY_MIN_REPEAT);
//
// Ref:
//   http://www.etcwiki.org/wiki/Pronto_Infrared_Format
//   http://www.remotecentral.com/features/irdisp2.htm
void IRsend::sendPronto(uint16_t data[], uint16_t len, uint16_t repeat) {
  // Check we have enough data to work out what to send.
  if (len < PRONTO_MIN_LENGTH) return;

  // We only know how to deal with 'raw' pronto codes types. Reject all others.
  if (data[PRONTO_TYPE_OFFSET] != 0) return;

  // Pronto frequency is in Hz.
  uint16_t hz = (uint16_t) (1000000U / (data[PRONTO_FREQ_OFFSET] *
                                        PRONTO_FREQ_FACTOR));
  enableIROut(hz);

  // Grab the length of the two sequences.
  uint16_t seq_1_len = data[PRONTO_SEQ_1_LEN_OFFSET] * 2;
  uint16_t seq_2_len = data[PRONTO_SEQ_2_LEN_OFFSET] * 2;
  // Calculate where each sequence starts in the buffer.
  uint16_t seq_1_start = PRONTO_DATA_OFFSET;
  uint16_t seq_2_start = PRONTO_DATA_OFFSET + seq_1_len;

  uint32_t periodic_time = calcUSecPeriod(hz, false);

  // Normal (1st sequence) case.
  // Is there a first (normal) sequence to send?
  if (seq_1_len > 0) {
    // Check we have enough data to send the complete first sequence.
    if (seq_1_len + seq_1_start > len) return;
    // Send the contents of the 1st sequence.
    for (uint16_t i = seq_1_start; i < seq_1_start + seq_1_len; i += 2) {
      mark(data[i] * periodic_time);
      space(data[i + 1] * periodic_time);
    }
  } else {
    // There was no first sequence to send, it is implied that we have to send
    // the 2nd/repeat sequence an additional time. i.e. At least once.
    repeat++;
  }

  // Repeat (2nd sequence) case.
  // Is there a second (repeat) sequence to be sent?
  if (seq_2_len > 0) {
    // Check we have enough data to send the complete second sequence.
    if (seq_2_len + seq_2_start > len) return;

    // Send the contents of the 2nd sequence.
    for (uint16_t r = 0; r < repeat; r++)
      for (uint16_t i = seq_2_start; i < seq_2_start + seq_2_len; i += 2) {
        mark(data[i] * periodic_time);
        space(data[i + 1] * periodic_time);
      }
  }
}
Esempio n. 4
0
// Set the output frequency modulation and duty cycle.
//
// Args:
//   freq: The freq we want to modulate at. Assumes < 1000 means kHz else Hz.
//   duty: Percentage duty cycle of the LED. e.g. 25 = 25% = 1/4 on, 3/4 off.
//         This is ignored if modulation is disabled at object instantiation.
//
// Note:
//   Integer timing functions & math mean we can't do fractions of
//   microseconds timing. Thus minor changes to the freq & duty values may have
//   limited effect. You've been warned.
void IRsend::enableIROut(uint32_t freq, uint8_t duty) {
  // Set the duty cycle to use if we want freq. modulation.
  if (modulation) {
    _dutycycle = std::min(duty, (uint8_t) DUTY_MAX);
  } else {
    _dutycycle = DUTY_MAX;
  }
  if (freq < 1000)  // Were we given kHz? Supports the old call usage.
    freq *= 1000;
  uint32_t period = calcUSecPeriod(freq);
  // Nr. of uSeconds the LED will be on per pulse.
  onTimePeriod = (period * _dutycycle) / DUTY_MAX;
  // Nr. of uSeconds the LED will be off per pulse.
  offTimePeriod = period - onTimePeriod;
}