Subversion Repositories FlightCtrl

Rev

Rev 1821 | Rev 1869 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1612 dongfang 1
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2
// + Copyright (c) 04.2007 Holger Buss
3
// + Nur für den privaten Gebrauch
4
// + www.MikroKopter.com
5
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6
// + Es gilt für das gesamte Projekt (Hardware, Software, Binärfiles, Sourcecode und Dokumentation),
7
// + dass eine Nutzung (auch auszugsweise) nur für den privaten (nicht-kommerziellen) Gebrauch zulässig ist.
8
// + Sollten direkte oder indirekte kommerzielle Absichten verfolgt werden, ist mit uns (info@mikrokopter.de) Kontakt
9
// + bzgl. der Nutzungsbedingungen aufzunehmen.
10
// + Eine kommerzielle Nutzung ist z.B.Verkauf von MikroKoptern, Bestückung und Verkauf von Platinen oder Bausätzen,
11
// + Verkauf von Luftbildaufnahmen, usw.
12
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
13
// + Werden Teile des Quellcodes (mit oder ohne Modifikation) weiterverwendet oder veröffentlicht,
14
// + unterliegen sie auch diesen Nutzungsbedingungen und diese Nutzungsbedingungen incl. Copyright müssen dann beiliegen
15
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16
// + Sollte die Software (auch auszugesweise) oder sonstige Informationen des MikroKopter-Projekts
17
// + auf anderen Webseiten oder sonstigen Medien veröffentlicht werden, muss unsere Webseite "http://www.mikrokopter.de"
18
// + eindeutig als Ursprung verlinkt werden
19
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
20
// + Keine Gewähr auf Fehlerfreiheit, Vollständigkeit oder Funktion
21
// + Benutzung auf eigene Gefahr
22
// + Wir übernehmen keinerlei Haftung für direkte oder indirekte Personen- oder Sachschäden
23
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
24
// + Die Portierung der Software (oder Teile davon) auf andere Systeme (ausser der Hardware von www.mikrokopter.de) ist nur
25
// + mit unserer Zustimmung zulässig
26
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
27
// + Die Funktion printf_P() unterliegt ihrer eigenen Lizenz und ist hiervon nicht betroffen
28
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
29
// + Redistributions of source code (with or without modifications) must retain the above copyright notice,
30
// + this list of conditions and the following disclaimer.
31
// +   * Neither the name of the copyright holders nor the names of contributors may be used to endorse or promote products derived
32
// +     from this software without specific prior written permission.
33
// +   * The use of this project (hardware, software, binary files, sources and documentation) is only permittet
34
// +     for non-commercial use (directly or indirectly)
1868 - 35
// +     Commercial use (for example: selling of MikroKopters, selling of PCBs, assembly, ...) is only permitted
1612 dongfang 36
// +     with our written permission
37
// +   * If sources or documentations are redistributet on other webpages, out webpage (http://www.MikroKopter.de) must be
38
// +     clearly linked as origin
39
// +   * porting to systems other than hardware from www.mikrokopter.de is not allowed
40
// +  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
41
// +  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
// +  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43
// +  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
44
// +  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
45
// +  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
46
// +  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
47
// +  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN// +  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48
// +  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49
// +  POSSIBILITY OF SUCH DAMAGE.
50
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
51
#include <stdlib.h>
52
#include <avr/io.h>
53
#include <avr/interrupt.h>
54
 
55
#include "rc.h"
1775 - 56
#include "uart0.h"
1612 dongfang 57
#include "controlMixer.h"
58
#include "configuration.h"
1775 - 59
#include "commands.h"
1612 dongfang 60
 
61
// The channel array is 1-based. The 0th entry is not used.
62
volatile int16_t PPM_in[MAX_CHANNELS];
63
volatile int16_t PPM_diff[MAX_CHANNELS];
64
volatile uint8_t NewPpmData = 1;
65
volatile int16_t RC_Quality = 0;
66
int16_t RC_PRTY[4];
1821 - 67
uint8_t lastRCCommand = COMMAND_NONE;
1775 - 68
uint8_t commandTimer = 0;
1612 dongfang 69
 
1775 - 70
// Useless. Just trim on the R/C instead.
71
// int16_t stickOffsetPitch = 0, stickOffsetRoll = 0;
1612 dongfang 72
 
73
/***************************************************************
74
 *  16bit timer 1 is used to decode the PPM-Signal            
75
 ***************************************************************/
1821 - 76
void RC_Init(void) {
77
        uint8_t sreg = SREG;
1612 dongfang 78
 
1821 - 79
        // disable all interrupts before reconfiguration
80
        cli();
1612 dongfang 81
 
1821 - 82
        // PPM-signal is connected to the Input Capture Pin (PD6) of timer 1
83
        DDRD &= ~(1 << DDD6);
84
        PORTD |= (1 << PORTD6);
1612 dongfang 85
 
1821 - 86
        // Channel 5,6,7 is decoded to servo signals at pin PD5 (J3), PD4(J4), PD3(J5)
87
        // set as output
88
        DDRD |= (1 << DDD5) | (1 << DDD4) | (1 << DDD3);
89
        // low level
90
        PORTD &= ~((1 << PORTD5) | (1 << PORTD4) | (1 << PORTD3));
1612 dongfang 91
 
1821 - 92
        // PD3 can't be used if 2nd UART is activated
93
        // because TXD1 is at that port
94
        if (CPUType != ATMEGA644P) {
95
                DDRD |= (1 << PORTD3);
96
                PORTD &= ~(1 << PORTD3);
97
        }
1612 dongfang 98
 
1821 - 99
        // Timer/Counter1 Control Register A, B, C
1612 dongfang 100
 
1821 - 101
        // Normal Mode (bits: WGM13=0, WGM12=0, WGM11=0, WGM10=0)
102
        // Compare output pin A & B is disabled (bits: COM1A1=0, COM1A0=0, COM1B1=0, COM1B0=0)
103
        // Set clock source to SYSCLK/64 (bit: CS12=0, CS11=1, CS10=1)
104
        // Enable input capture noise cancler (bit: ICNC1=1)
105
        // Trigger on positive edge of the input capture pin (bit: ICES1=1),
106
        // Therefore the counter incremets at a clock of 20 MHz/64 = 312.5 kHz or 3.2µs
107
        // The longest period is 0xFFFF / 312.5 kHz = 0.209712 s.
108
        TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0) | (1 << COM1B1) | (1 << COM1B0)
109
                        | (1 << WGM11) | (1 << WGM10));
110
        TCCR1B &= ~((1 << WGM13) | (1 << WGM12) | (1 << CS12));
111
        TCCR1B |= (1 << CS11) | (1 << CS10) | (1 << ICES1) | (1 << ICNC1);
112
        TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B));
1612 dongfang 113
 
1821 - 114
        // Timer/Counter1 Interrupt Mask Register
1612 dongfang 115
 
1821 - 116
        // Enable Input Capture Interrupt (bit: ICIE1=1)
117
        // Disable Output Compare A & B Match Interrupts (bit: OCIE1B=0, OICIE1A=0)
118
        // Enable Overflow Interrupt (bit: TOIE1=0)
119
        TIMSK1 &= ~((1 << OCIE1B) | (1 << OCIE1A) | (1 << TOIE1));
120
        TIMSK1 |= (1 << ICIE1);
1612 dongfang 121
 
1821 - 122
        RC_Quality = 0;
1612 dongfang 123
 
1821 - 124
        SREG = sreg;
1612 dongfang 125
}
126
 
127
/********************************************************************/
128
/*         Every time a positive edge is detected at PD6            */
129
/********************************************************************/
130
/*                               t-Frame
1821 - 131
 <----------------------------------------------------------------------->
1868 - 132
    ____   ______   _____   ________                ______    sync gap      ____
133
   |    | |      | |     | |        |              |      |                |
134
   |    | |      | |     | |        |              |      |                |
135
___|    |_|      |_|     |_|        |_.............|      |________________|
136
   <-----><-------><------><-------->              <------>                <---
1821 - 137
 t0       t1      t2       t4                     tn                     t0
1612 dongfang 138
 
1821 - 139
 The PPM-Frame length is 22.5 ms.
140
 Channel high pulse width range is 0.7 ms to 1.7 ms completed by an 0.3 ms low pulse.
141
 The mininimum time delay of two events coding a channel is ( 0.7 + 0.3) ms = 1 ms.
142
 The maximum time delay of two events coding a chanel is ( 1.7 + 0.3) ms = 2 ms.
143
 The minimum duration of all channels at minimum value is  8 * 1 ms = 8 ms.
144
 The maximum duration of all channels at maximum value is  8 * 2 ms = 16 ms.
145
 The remaining time of (22.5 - 8 ms) ms = 14.5 ms  to (22.5 - 16 ms) ms = 6.5 ms is
146
 the syncronization gap.
147
 */
148
ISR(TIMER1_CAPT_vect)
149
{ // typical rate of 1 ms to 2 ms
150
        int16_t signal = 0, tmp;
151
        static int16_t index;
152
        static uint16_t oldICR1 = 0;
153
 
154
        // 16bit Input Capture Register ICR1 contains the timer value TCNT1
155
        // at the time the edge was detected
156
 
157
        // calculate the time delay to the previous event time which is stored in oldICR1
158
        // calculatiing the difference of the two uint16_t and converting the result to an int16_t
159
        // implicit handles a timer overflow 65535 -> 0 the right way.
160
        signal = (uint16_t) ICR1 - oldICR1;
161
        oldICR1 = ICR1;
162
 
163
        //sync gap? (3.52 ms < signal < 25.6 ms)
164
        if ((signal > 1100) && (signal < 8000)) {
165
                // if a sync gap happens and there where at least 4 channels decoded before
166
                // then the NewPpmData flag is reset indicating valid data in the PPM_in[] array.
167
                if (index >= 4) {
168
                        NewPpmData = 0; // Null means NewData for the first 4 channels
169
                }
170
                // synchronize channel index
171
                index = 1;
172
        } else { // within the PPM frame
173
                if (index < MAX_CHANNELS - 1) { // PPM24 supports 12 channels
174
                        // check for valid signal length (0.8 ms < signal < 2.1984 ms)
175
                        // signal range is from 1.0ms/3.2us = 312 to 2.0ms/3.2us = 625
176
                        if ((signal > 250) && (signal < 687)) {
177
                                // shift signal to zero symmetric range  -154 to 159
178
                                signal -= 470; // offset of 1.4912 ms ??? (469 * 3.2µs = 1.5008 ms)
179
                                // check for stable signal
180
                                if (abs(signal - PPM_in[index]) < 6) {
181
                                        if (RC_Quality < 200)
182
                                                RC_Quality += 10;
183
                                        else
184
                                                RC_Quality = 200;
185
                                }
186
                                // If signal is the same as before +/- 1, just keep it there.
187
                                if (signal >= PPM_in[index] - 1 && signal <= PPM_in[index] + 1) {
188
                                        // In addition, if the signal is very close to 0, just set it to 0.
189
                                        if (signal >= -1 && signal <= 1) {
190
                                                tmp = 0;
191
                                        } else {
192
                                                tmp = PPM_in[index];
193
                                        }
194
                                } else
195
                                        tmp = signal;
196
                                // calculate signal difference on good signal level
197
                                if (RC_Quality >= 195)
198
                                        PPM_diff[index] = ((tmp - PPM_in[index]) / 3) * 3; // cut off lower 3 bit for nois reduction
199
                                else
200
                                        PPM_diff[index] = 0;
201
                                PPM_in[index] = tmp; // update channel value
202
                        }
203
                        index++; // next channel
204
                        // demux sum signal for channels 5 to 7 to J3, J4, J5
205
                        // TODO: General configurability of this R/C channel forwarding. Or remove it completely - the
206
                        // channels are usually available at the receiver anyway.
207
                        // if(index == 5) J3HIGH; else J3LOW;
208
                        // if(index == 6) J4HIGH; else J4LOW;
209
                        // if(CPUType != ATMEGA644P) // not used as TXD1
210
                        //  {
211
                        //    if(index == 7) J5HIGH; else J5LOW;
212
                        //  }
213
                }
1796 - 214
        }
1612 dongfang 215
}
216
 
217
#define RCChannel(dimension) PPM_in[staticParams.ChannelAssignment[dimension]]
218
#define RCDiff(dimension) PPM_diff[staticParams.ChannelAssignment[dimension]]
1775 - 219
#define COMMAND_THRESHOLD 85
220
#define COMMAND_CHANNEL_VERTICAL CH_THROTTLE
221
#define COMMAND_CHANNEL_HORIZONTAL CH_YAW
1612 dongfang 222
 
1775 - 223
// Internal.
224
uint8_t RC_getStickCommand(void) {
1821 - 225
        if (RCChannel(COMMAND_CHANNEL_VERTICAL) > COMMAND_THRESHOLD) {
226
                // vertical is up
227
                if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) > COMMAND_THRESHOLD)
228
                        return COMMAND_GYROCAL;
229
                if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) < -COMMAND_THRESHOLD)
230
                        return COMMAND_ACCCAL;
231
                return COMMAND_NONE;
232
        } else if (RCChannel(COMMAND_CHANNEL_VERTICAL) < -COMMAND_THRESHOLD) {
233
                // vertical is down
234
                if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) > COMMAND_THRESHOLD)
235
                        return COMMAND_STOP;
236
                if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) < -COMMAND_THRESHOLD)
237
                        return COMMAND_START;
238
                return COMMAND_NONE;
239
        }
240
        // vertical is around center
241
        return COMMAND_NONE;
1775 - 242
}
243
 
1612 dongfang 244
/*
245
 * This must be called (as the only thing) for each control loop cycle (488 Hz).
246
 */
247
void RC_update() {
1821 - 248
        int16_t tmp1, tmp2;
249
        if (RC_Quality) {
250
                RC_Quality--;
251
                if (NewPpmData-- == 0) {
252
                        RC_PRTY[CONTROL_PITCH] = RCChannel(CH_PITCH) * staticParams.StickP
253
                                        + RCDiff(CH_PITCH) * staticParams.StickD;
1868 - 254
 
255
                    DebugOut.Analog[21] = RCChannel(CH_THROTTLE);
256
 
1821 - 257
                        RC_PRTY[CONTROL_ROLL] = RCChannel(CH_ROLL) * staticParams.StickP
258
                                        + RCDiff(CH_ROLL) * staticParams.StickD;
259
                        RC_PRTY[CONTROL_THROTTLE] = RCChannel(CH_THROTTLE) + RCDiff(CH_THROTTLE)
260
                                        * dynamicParams.UserParams[3] + 120;
261
                        if (RC_PRTY[CONTROL_THROTTLE] < 0)
262
                                RC_PRTY[CONTROL_THROTTLE] = 0; // Throttle is non negative.
263
                        tmp1 = -RCChannel(CH_YAW) - RCDiff(CH_YAW);
264
                        // exponential stick sensitivity in yawing rate
265
                        tmp2 = (int32_t) staticParams.StickYawP * ((int32_t) tmp1 * abs(tmp1))
266
                                        / 512L; // expo  y = ax + bx^2
267
                        tmp2 += (staticParams.StickYawP * tmp1) / 4;
268
                        RC_PRTY[CONTROL_YAW] = tmp2;
269
                }
270
                uint8_t command = RC_getStickCommand();
271
                if (lastRCCommand == command) {
272
                        // Keep timer from overrunning.
273
                        if (commandTimer < COMMAND_TIMER)
274
                                commandTimer++;
275
                } else {
276
                        // There was a change.
277
                        lastRCCommand = command;
278
                        commandTimer = 0;
279
                }
280
        } else { // Bad signal
281
                RC_PRTY[CONTROL_PITCH] = RC_PRTY[CONTROL_ROLL] = RC_PRTY[CONTROL_THROTTLE]
282
                                = RC_PRTY[CONTROL_YAW] = 0;
283
        }
1612 dongfang 284
}
285
 
286
/*
287
 * Get Pitch, Roll, Throttle, Yaw values
288
 */
289
int16_t* RC_getPRTY(void) {
1821 - 290
        return RC_PRTY;
1612 dongfang 291
}
292
 
293
/*
294
 * Get other channel value
295
 */
1821 - 296
int16_t RC_getVariable(uint8_t varNum) {
297
        if (varNum < 4)
298
                // 0th variable is 5th channel (1-based) etc.
299
                return RCChannel(varNum + 4) + POT_OFFSET;
300
        /*
301
         * Let's just say:
302
         * The RC variable 4 is hardwired to channel 5
303
         * The RC variable 5 is hardwired to channel 6
304
         * The RC variable 6 is hardwired to channel 7
305
         * The RC variable 7 is hardwired to channel 8
306
         * Alternatively, one could bind them to channel (4 + varNum) - or whatever...
307
         */
308
        return PPM_in[varNum + 1] + POT_OFFSET;
1612 dongfang 309
}
310
 
311
uint8_t RC_getSignalQuality(void) {
1821 - 312
        if (RC_Quality >= 160)
313
                return SIGNAL_GOOD;
314
        if (RC_Quality >= 140)
315
                return SIGNAL_OK;
316
        if (RC_Quality >= 120)
317
                return SIGNAL_BAD;
318
        return SIGNAL_LOST;
1612 dongfang 319
}
320
 
321
/*
322
 * To should fired only when the right stick is in the center position.
323
 * This will cause the value of pitch and roll stick to be adjusted
324
 * to zero (not just to near zero, as per the assumption in rc.c
325
 * about the rc signal. I had values about 50..70 with a Futaba
326
 * R617 receiver.) This calibration is not strictly necessary, but
327
 * for control logic that depends on the exact (non)center position
328
 * of a stick, it may be useful.
329
 */
330
void RC_calibrate(void) {
1821 - 331
        // Do nothing.
1775 - 332
}
333
 
334
/*
1821 - 335
 if (staticParams.GlobalConfig & CFG_HEADING_HOLD) {
336
 // In HH, it s OK to trim the R/C. The effect should not be conteracted here.
337
 stickOffsetPitch = stickOffsetRoll = 0;
338
 } else {
339
 stickOffsetPitch = RCChannel(CH_PITCH) * staticParams.StickP;
340
 stickOffsetRoll = RCChannel(CH_ROLL)   * staticParams.StickP;
341
 }
342
 }
343
 */
1612 dongfang 344
 
345
uint8_t RC_getCommand(void) {
1821 - 346
        if (commandTimer == COMMAND_TIMER) {
347
                // Stick has been held long enough; command committed.
348
                return lastRCCommand;
349
        }
350
        // Not yet sure what the command is.
351
        return COMMAND_NONE;
1612 dongfang 352
}
353
 
354
/*
355
 * Command arguments on R/C:
356
 * 2--3--4
357
 * |     |  +
358
 * 1  0  5  ^ 0
359
 * |     |  |  
360
 * 8--7--6
361
 *    
362
 * + <--
363
 *    0
364
 *
365
 * Not in any of these positions: 0
366
 */
1635 - 367
 
1612 dongfang 368
#define ARGUMENT_THRESHOLD 70
1635 - 369
#define ARGUMENT_CHANNEL_VERTICAL CH_PITCH
370
#define ARGUMENT_CHANNEL_HORIZONTAL CH_ROLL
371
 
1612 dongfang 372
uint8_t RC_getArgument(void) {
1821 - 373
        if (RCChannel(ARGUMENT_CHANNEL_VERTICAL) > ARGUMENT_THRESHOLD) {
374
                // vertical is up
375
                if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
376
                        return 2;
377
                if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
378
                        return 4;
379
                return 3;
380
        } else if (RCChannel(ARGUMENT_CHANNEL_VERTICAL) < -ARGUMENT_THRESHOLD) {
381
                // vertical is down
382
                if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
383
                        return 8;
384
                if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
385
                        return 6;
386
                return 7;
387
        } else {
388
                // vertical is around center
389
                if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
390
                        return 1;
391
                if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
392
                        return 5;
393
                return 0;
394
        }
1612 dongfang 395
}
396
 
397
uint8_t RC_getLooping(uint8_t looping) {
1821 - 398
        //  static uint8_t looping = 0;
1612 dongfang 399
 
1821 - 400
        if (RCChannel(CH_ROLL) > staticParams.LoopThreshold && staticParams.BitConfig
401
                        & CFG_LOOP_LEFT) {
402
                looping |= (LOOPING_ROLL_AXIS | LOOPING_LEFT);
403
        } else if ((looping & LOOPING_LEFT) && RCChannel(CH_ROLL)
404
                        < staticParams.LoopThreshold - staticParams.LoopHysteresis) {
405
                looping &= (~(LOOPING_ROLL_AXIS | LOOPING_LEFT));
406
        }
1612 dongfang 407
 
1821 - 408
        if (RCChannel(CH_ROLL) < -staticParams.LoopThreshold
409
                        && staticParams.BitConfig & CFG_LOOP_RIGHT) {
410
                looping |= (LOOPING_ROLL_AXIS | LOOPING_RIGHT);
411
        } else if ((looping & LOOPING_RIGHT) && RCChannel(CH_ROLL)
412
                        > -staticParams.LoopThreshold - staticParams.LoopHysteresis) {
413
                looping &= (~(LOOPING_ROLL_AXIS | LOOPING_RIGHT));
414
        }
415
 
416
        if (RCChannel(CH_PITCH) > staticParams.LoopThreshold
417
                        && staticParams.BitConfig & CFG_LOOP_UP) {
418
                looping |= (LOOPING_PITCH_AXIS | LOOPING_UP);
419
        } else if ((looping & LOOPING_UP) && RCChannel(CH_PITCH)
420
                        < staticParams.LoopThreshold - staticParams.LoopHysteresis) {
421
                looping &= (~(LOOPING_PITCH_AXIS | LOOPING_UP));
422
        }
423
 
424
        if (RCChannel(CH_PITCH) < -staticParams.LoopThreshold
425
                        && staticParams.BitConfig & CFG_LOOP_DOWN) {
426
                looping |= (LOOPING_PITCH_AXIS | LOOPING_DOWN);
427
        } else if ((looping & LOOPING_DOWN) && RCChannel(CH_PITCH)
428
                        > -staticParams.LoopThreshold - staticParams.LoopHysteresis) {
429
                looping &= (~(LOOPING_PITCH_AXIS | LOOPING_DOWN));
430
        }
431
 
432
        return looping;
1612 dongfang 433
}
434
 
1775 - 435
uint8_t RC_testCompassCalState(void) {
1821 - 436
        static uint8_t stick = 1;
437
        // if pitch is centered or top set stick to zero
438
        if (RCChannel(CH_PITCH) > -20)
439
                stick = 0;
440
        // if pitch is down trigger to next cal state
441
        if ((RCChannel(CH_PITCH) < -70) && !stick) {
442
                stick = 1;
443
                return 1;
444
        }
445
        return 0;
1775 - 446
}
1612 dongfang 447
/*
448
 * Abstract controls are not used at the moment.
449
 t_control rc_control = {
450
 RC_getPitch,
451
 RC_getRoll,
452
 RC_getYaw,
453
 RC_getThrottle,
454
 RC_getSignalQuality,
455
 RC_calibrate
456
 };
1821 - 457
 */