Infrared4Arduino
IrWidgetAggregating.cpp
Go to the documentation of this file.
1 // Copyright (c) 2012 Michael Dreher <michael(at)5dot1.de>
2 // this code may be distributed under the terms of the General Public License V2 (GPL V2)
3 
4 // This is a slight reorganization of the original code, by Bengt Martensson.
5 
6 #if defined (DOXYGEN) || !defined(ARDUINO) || defined ARDUINO_ARCH_AVR
7 
8 #include "IrWidgetAggregating.h"
9 
10 static const frequency_t min_frequency = 20000U;
11 
12 IrWidgetAggregating::IrWidgetAggregating(size_t captureLength,
13  bool pullup,
14  int16_t markExcess,
15  milliseconds_t beginningTimeout,
16  milliseconds_t endingTimeout)
17 : IrWidget(captureLength, pullup, markExcess, beginningTimeout, endingTimeout) {
18 }
19 
20 IrWidgetAggregating *IrWidgetAggregating::instance = NULL;
21 
23  bool pullup,
24  int16_t markExcess,
25  milliseconds_t beginningTimeout,
26  milliseconds_t endingTimeout) {
27  if (instance != NULL)
28  return NULL;
29  instance = new IrWidgetAggregating(captureLength, pullup, markExcess,
31  return instance;
32 }
33 
35  delete instance;
36  instance = NULL;
37 }
38 
39 // Wait for a signal on pin ICP1 and store the captured time values in the array 'captureData'
41 #ifdef ARDUINO
42  uint32_t timeForBeginTimeout = millis() + beginningTimeout;
43  uint8_t tccr0b = TCCR0B;
44  //TCCR0B &= ~(_BV(CS02) | _BV(CS01) | _BV(CS00)); // stop timer0 (disables timer IRQs)
45 
46  uint16_t period = (F_CPU / min_frequency) >> CAPTURE_PRESCALER_BITS; // the time of one period in CPU clocks
47  //uint16_t aggThreshold = (period * 10UL) / 8UL; // 65 us = (1/20kHz * 130%) might be a good starting point
48  uint16_t aggThreshold = period * 2U;
49  uint8_t icesn_val = _BV(CAT2(ICES, CAP_TIM));
50  uint8_t tccrnb = CAT3(TCCR, CAP_TIM, B);
51  if (invertingSensor)
52  tccrnb &= ~icesn_val; // trigger on falling edge
53  else
54  tccrnb |= icesn_val; // trigger on rising edge
55 
56  CAT3(TCCR, CAP_TIM, B) = tccrnb;
57  OCR1A = CAT2(TCNT, CAP_TIM) - 1;
58  CAT2(TIFR, CAP_TIM) = _BV(CAT2(ICF, CAP_TIM))
59  | _BV(CAT3(OCF, CAP_TIM, CAP_TIM_OC)) | _BV(CAT2(TOV, CAP_TIM)); // clear all timer flags
60  uint8_t tifr; // cache the result of reading TIFR1 (masked with ICF1 and OCF1A)
61  uint8_t calShiftM1 = 1;
62  uint8_t calCount = 1 << (calShiftM1 + 1);
63  uint8_t aggCount = 0;
64  ovlBitsDataType ovlCnt = 0;
65  uint16_t val;
66  uint16_t prevVal = 0;
67  uint16_t *pCapDat = captureData; // pointer to current item in captureData[]
68  uint32_t aggVal = 0;
69  uint32_t diffVal;
70 
71  // disabling IRQs for a long time will disconnect the USB connection of the ATmega32U4, therefore we
72  // defer the sbi() instruction until we got the starting edge and only stop the Timer0 in the meanwhile
73  uint8_t sreg = SREG;
74  debugPinClear();
75 
77  // wait for first edge
78  while (!(tifr = (CAT2(TIFR, CAP_TIM) & (_BV(CAT2(ICF, CAP_TIM)))))) {
79  if (millis() >= timeForBeginTimeout) {
80  timeouted = true;
81  goto endCapture;
82  }
83  }
84  TCCR0B &= ~(_BV(CS02) | _BV(CS01) | _BV(CS00)); // stop timer0 (disables timer IRQs)
86  val = CAT2(ICR, CAP_TIM);
87  CAT3(OCR, CAP_TIM, CAP_TIM_OC) = val; // timeout based on previous trigger time
88 
89  noInterrupts(); // disable IRQs after the first edge
90 
91  // clear input capture and output compare flag bit
92  CAT2(TIFR, CAP_TIM) = _BV(CAT2(ICF, CAP_TIM)) | _BV(CAT3(OCF, CAP_TIM, CAP_TIM_OC));
93  prevVal = val;
94 
96  // wait for all following edges
97  for (; pCapDat <= &captureData[bufferSize - sampleSize];) // 2 values are stored in each loop, TODO: change to 3 when adding the aggCount
98  {
100  // wait for edge or overflow (output compare match)
101  while (!(tifr =
102  (CAT2(TIFR, CAP_TIM) & (_BV(CAT2(ICF, CAP_TIM)) | _BV(CAT3(OCF, CAP_TIM, CAP_TIM_OC)))))) {
103  }
104  debugPinToggle();
105  val = CAT2(ICR, CAP_TIM);
106  CAT3(OCR, CAP_TIM, CAP_TIM_OC) = val; // timeout based on previous trigger time
107 
108  if (tifr & _BV(CAT3(OCF, CAP_TIM, CAP_TIM_OC))) // check for overflow bit
109  {
110  if (ovlCnt >= endingTimeout) // TODO: handle this check together with the check for the pulse length (if packTimeValNormal can handle the value)
111  {
112  if (aggVal > 0) {
113  // TODO check is to value is small enough to be stored
114  *pCapDat = packTimeVal/*Normal*/(aggVal); // store the pulse length
115  pCapDat++;
116  *pCapDat = packTimeVal/*Normal*/((uint32_t) endingTimeout << 16);
117  pCapDat++;
118  }
119  break; // maximum value reached, treat this as timeout and abort capture
120  }
121  ovlCnt++;
122  // clear input capture and output compare flag bit
123  CAT2(TIFR, CAP_TIM) = _BV(CAT2(ICF, CAP_TIM)) | _BV(CAT3(OCF, CAP_TIM, CAP_TIM_OC));
124  continue;
125  }
126 
127  // clear input capture and output compare flag bit
128  CAT2(TIFR, CAP_TIM) = _BV(CAT2(ICF, CAP_TIM)) | _BV(CAT3(OCF, CAP_TIM, CAP_TIM_OC));
129 
130  diffVal = ((val - prevVal) & 0xffff) | ((uint32_t) ovlCnt << 16);
131  ovlCnt = 0;
132  prevVal = val;
133 
134  if (diffVal < aggThreshold) {
135  aggVal += diffVal;
136 
137  // calculate the carrier frequency only within the first burst (often a preamble)
138  if (calCount) {
139  aggCount++; // only used to calculate the period
140  // do a calibration on every aggCount which is a power of two because then dividing by calShiftM1
141  // (shiftcount - 1) can simply be performed by shifting right
142  if (aggCount == calCount) {
143  aggThreshold = aggVal >> calShiftM1;
144  calShiftM1++;
145  calCount = calCount << 1; // this will automatically terminate calibrating when calCount is 128 because then (128 << 1) & 0xff = 0
146  }
147  }
148  } else {
149  *pCapDat = packTimeVal/*Normal*/(aggVal); // store the pulse length
150  pCapDat++;
151  // TODO check if value is small enough to be stored
152  *pCapDat = packTimeVal/*Normal*/(diffVal); // store the pause length
153  pCapDat++;
154 
155  aggVal = 0;
156  calCount = 0; // avoid further period calculation and calibration
157  }
158  }
159 
160 endCapture:
161  debugPinClear();
162 
163  TCCR0B = tccr0b; // re-enable Timer0
164  SREG = sreg; // enable IRQs
165 
166  captureCount = pCapDat - captureData;
167  if (aggThreshold == period * 2U) {
168  frequency = 0U;
169  } else {
170  uint32_t mediumPeriod = timerValueToNanoSeconds(aggThreshold / 2U);
171  frequency = (frequency_t) (1000000000L / mediumPeriod);
172  }
173 #endif // ARDUINO
174 }
175 
176 #endif // ARDUINO_ARCH_AVR
static IrWidgetAggregating * newIrWidgetAggregating(size_t captureLength=defaultCaptureLength, bool pullup=false, int16_t markExcess=defaultMarkExcess, milliseconds_t beginningTimeout=defaultBeginningTimeout, milliseconds_t endingTimeout=defaultEndingTimeout)
bool timeouted
True if last receive ended with a timeout.
Definition: IrReader.h:47
void debugPinToggle(void)
Definition: IrWidget.h:188
uint32_t frequency_t
Type for modulation frequency in Hz.
Definition: InfraredTypes.h:32
static const uint8_t sampleSize
Definition: IrWidget.h:201
uint8_t ovlBitsDataType
Definition: IrWidget.h:128
size_t bufferSize
Definition: IrReader.h:41
uint16_t milliseconds_t
Type for durations in milli seconds.
Definition: InfraredTypes.h:25
#define CAP_TIM
Definition: IrWidget.h:172
#define CAT3(prefix, num, postfix)
Definition: IrWidget.h:184
#define CAP_TIM_OC
Definition: IrWidget.h:173
Base class for classes based upon ICP pins capture.
Definition: IrWidget.h:45
This class implements the IrWidget.
static const frequency_t min_frequency
uint16_t * captureData
Definition: IrWidget.h:199
static const bool invertingSensor
Set true means if sensor signal is inverted (low = signal on) (false has not been tested,...
Definition: IrWidget.h:64
static uint32_t timerValueToNanoSeconds(uint32_t x)
Definition: IrWidget.h:207
uint16_t captureCount
Definition: IrWidget.h:200
#define CAPTURE_PRESCALER_BITS
Definition: IrWidget.h:118
frequency_t frequency
Definition: IrWidget.h:50
milliseconds_t beginningTimeout
Definition: IrReader.h:38
void debugPinClear(void)
Definition: IrWidget.h:194
ovlBitsDataType endingTimeout
Definition: IrWidget.h:133
#define CAT2(prefix, num)
Definition: IrWidget.h:182
int16_t markExcess
Microseconds subtracted from pulses and added to gaps.
Definition: IrReader.h:44