Subversion Repositories FlightCtrl

Rev

Rev 1869 | Rev 1962 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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