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