Infrared4Arduino 1.2.3
Loading...
Searching...
No Matches
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
7
8#if HAS_INPUT_CAPTURE
9
10static constexpr frequency_t min_frequency = 20000U;
11
12IrWidgetAggregating::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
20IrWidgetAggregating *IrWidgetAggregating::instance = nullptr;
21
23 bool pullup,
24 int16_t markExcess,
25 milliseconds_t beginningTimeout,
26 milliseconds_t endingTimeout) {
27 if (instance != nullptr)
28 return nullptr;
29 instance = new IrWidgetAggregating(captureLength, pullup, markExcess,
31 return instance;
32}
33
35 delete instance;
36 instance = nullptr;
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);
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;
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 }
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
160endCapture:
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#endif // TCCR0B
uint32_t frequency_t
Type for modulation frequency in Hz.
Definition: InfraredTypes.h:31
uint16_t milliseconds_t
Type for durations in milli seconds.
Definition: InfraredTypes.h:24
#define CAP_TIM
Definition: IrWidget.h:171
#define CAPTURE_PRESCALER_BITS
Definition: IrWidget.h:117
#define CAT3(prefix, num, postfix)
Definition: IrWidget.h:183
#define CAT2(prefix, num)
Definition: IrWidget.h:181
#define CAP_TIM_OC
Definition: IrWidget.h:172
int16_t markExcess
Microseconds subtracted from pulses and added to gaps.
Definition: IrReader.h:44
milliseconds_t beginningTimeout
Definition: IrReader.h:38
size_t bufferSize
Definition: IrReader.h:41
bool timeouted
True if last receive ended with a timeout.
Definition: IrReader.h:47
This class implements the IrWidget.
static void deleteInstance()
static IrWidgetAggregating * newIrWidgetAggregating(size_t captureLength=defaultCaptureLength, bool pullup=false, int16_t markExcess=defaultMarkExcess, milliseconds_t beginningTimeout=defaultBeginningTimeout, milliseconds_t endingTimeout=defaultEndingTimeout)
Base class for classes based upon ICP pins capture.
Definition: IrWidget.h:44
uint16_t * captureData
Definition: IrWidget.h:198
uint16_t captureCount
Definition: IrWidget.h:199
static constexpr uint8_t sampleSize
Definition: IrWidget.h:200
uint8_t ovlBitsDataType
Definition: IrWidget.h:127
frequency_t frequency
Definition: IrWidget.h:49
static const bool invertingSensor
Set true means if sensor signal is inverted (low = signal on) (false has not been tested,...
Definition: IrWidget.h:63
void debugPinToggle(void)
Definition: IrWidget.h:187
static uint32_t timerValueToNanoSeconds(uint32_t x)
Definition: IrWidget.h:206
void debugPinClear(void)
Definition: IrWidget.h:193
ovlBitsDataType endingTimeout
Definition: IrWidget.h:132