/
IRPipboy.cpp
246 lines (217 loc) · 6.12 KB
/
IRPipboy.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
#include "IRPipboy.h"
void IRPipboy::init (void)
{
pinMode (irTransmit,OUTPUT);
digitalWrite (irTransmit, 0); // Keep output low when not in use
}
int IRPipboy::getChecksum (int val1, int val2, int val3) {
int checksum = val1;
checksum = checksum ^ val2;
checksum = checksum ^ val3;
return checksum;
}
// return non-zero if a shot was detected
int IRPipboy::IRDetected ( void )
{
int shot = 0;
unsigned int val; // IR value
int check;
if (irReady) {
val = decodeBits ( 35, true, false);
if (val == 0x0018) { // Micro Huan Qi
shot = 1; // Huan Qi
} else {
val = decodeBits (18, true, false);
if (val == 0xCCCC) { // Huan Qi
shot = 2;
} else {
val = decodeBits (15, true, false);
if (val != 0) {
check = getChecksum ((val & 0xF000) / 0x1000, (val & 0xF00) / 0x100, (val & 0xF0) / 0x10);
if ((val & 0xF) == check ) {
shot = (val & 0xFFF0) / 0x10;
} else {
Serial.print ( val, HEX );
Serial.print ( " != " );
Serial.println ( check, HEX );
}
}
}
}
resetIR();
}
return shot;
}
/* Leave pin off for time (given in microseconds) */
void space(int time) {
// Sends an IR space for the specified number of microseconds.
// A space is no output, so the PWM output is disabled.
TCCR2A &= ~(_BV(COM2B1)); // Disable pin 3 PWM output
delayMicroseconds(time * 50);
}
void sendRaw(unsigned int uDelay, int index)
{
if (index & 1)
TCCR2A &= ~(_BV(COM2B1)); // Disable pin 3 PWM output
else
TCCR2A |= _BV(COM2B1); // Enable pin 3 PWM output
delayMicroseconds(uDelay);
}
void enableIROut()
{
#define SYSCLOCK 16000000 // main Arduino clock
int khz = 38;
// Enables IR output. The khz value controls the modulation frequency in kilohertz.
// The IR output will be on pin 3 (OC2B).
// This routine is designed for 36-40KHz; if you use it for other values, it's up to you
// to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.)
// TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B
// controlling the duty cycle.
// There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A)
// To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin.
// A few hours staring at the ATmega documentation and this will all make sense.
// See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details.
// Disable the Timer2 Interrupt (which is used for receiving IR)
// TIMSK2 &= ~_BV(TOIE2); //Timer2 Overflow Interrupt
// atmega168
// Not sure about next line
//TIMSK1 &= ~_BV(OCIE1A); // Disable the interrupt that is used to read RF
pinMode(3, OUTPUT);
digitalWrite(3, LOW); // When not sending PWM, we want it low
// COM2A = 00: disconnect OC2A
// COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted
// WGM2 = 101: phase-correct PWM with OCRA as top
// CS2 = 000: no prescaling
TCCR2A = _BV(WGM20);
TCCR2B = _BV(WGM22) | _BV(CS20);
// The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A.
OCR2A = SYSCLOCK / 2 / khz / 1000;
OCR2B = OCR2A / 2; // 50% duty cycle... / 3; = 33% duty cycle
}
/*
Limitation:
You cannot place any Serial.println instructions here.
The program will not run
*/
void IRPipboy::fire (void)
{
unsigned int myDelay;
Timer1->stop();
enableIROut();
for (int i=0; i<4; i++){
for (int j = 0; j < HUANPULSES; j++) {
myDelay = huanQiPulses[j];
sendRaw (myDelay, j);
}
}
Timer1->resume();
}
void IRPipboy::fireData(void)
{
unsigned int myDelay;
Serial.print ("Sh");
Timer1->stop();
enableIROut();
for (int j = 0; j < 32; j++) {
myDelay = firePulses[j];
sendRaw (myDelay, j);
}
Timer1->resume();
}
void IRPipboy::sendFirePulse(void)
{
unsigned int myDelay;
enableIROut();
fireType--;
switch (fireType)
{
default:
break;
case 6:
for (int i=0; i<3; i++)
{
for (int j = 0; j < MICROHUANQI; j++)
{
myDelay = microHuanQi[j];
sendRaw (myDelay, j);
}
}
break;
case 5:
for (int i=0; i<4; i++)
{
for (int j = 0; j < MINITANK; j++)
{
myDelay = miniTankPulses[j];
sendRaw (myDelay, j);
}
}
break;
case 4:
for (int i=0; i<4; i++)
{
for (int j = 0; j < HUANPULSES; j++)
{
myDelay = huanQiPulses[j];
sendRaw (myDelay, j);
}
}
break;
case 3:
for (int j=0; j<FOVPULSES; j++)
{
myDelay = FOVPulses[j];
sendRaw (myDelay, j);
}
space(0); // Just to be sure
break;
case 2:
for (int j=0; j<DANBARPULSES; j++)
{
myDelay = DanbarPulses[j];
sendRaw (myDelay, j);
}
space(0); // Just to be sure
break;
case 1:
for (int i=0; i<2; i++)
{
for (int j=0; j<AIRBENDERPULSES; j++)
{
myDelay = airBenderPulses[j];
sendRaw (myDelay,j);
}
space(0); // Just to be sure
}
break;
case 0:
for (int i=0; i<2; i++) {
if (repairRobot) {
for (int j=0; j<REPAIRPULSES; j++)
{
myDelay = repairPulses[j];
sendRaw (myDelay,j);
}
} else {
for (int j=0; j<BATTLEMACHINEPULSES; j++)
{
myDelay = battleMachinePulses[j];
sendRaw (myDelay,j);
}
}
space(0); // Just to be sure
}
break;
}
}
/*
Limitation:
You cannot place any Serial.println instructions here.
The program will not run
*/
void IRPipboy::fireAll (void)
{
Timer1->stop();
sendFirePulse(); // Update fireTimeout and send pulse
Timer1->resume();
}