Subversion Repositories FlightCtrl

Rev

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

Rev 1969 Rev 1975
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 now 0-based.
61
// The channel array is now 0-based.
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 uint8_t RC_Quality = 0;
65
volatile uint8_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
/***************************************************************
70
/***************************************************************
71
 *  16bit timer 1 is used to decode the PPM-Signal            
71
 *  16bit timer 1 is used to decode the PPM-Signal            
72
 ***************************************************************/
72
 ***************************************************************/
73
void RC_Init(void) {
73
void RC_Init(void) {
74
  uint8_t sreg = SREG;
74
  uint8_t sreg = SREG;
75
 
75
 
76
  // disable all interrupts before reconfiguration
76
  // disable all interrupts before reconfiguration
77
  cli();
77
  cli();
78
 
78
 
79
  // PPM-signal is connected to the Input Capture Pin (PD6) of timer 1
79
  // PPM-signal is connected to the Input Capture Pin (PD6) of timer 1
80
  DDRD &= ~(1<<6);
80
  DDRD &= ~(1<<6);
81
  PORTD |= (1<<PORTD6);
81
  PORTD |= (1<<PORTD6);
82
 
82
 
83
  // Channel 5,6,7 is decoded to servo signals at pin PD5 (J3), PD4(J4), PD3(J5)
83
  // Channel 5,6,7 is decoded to servo signals at pin PD5 (J3), PD4(J4), PD3(J5)
84
  // set as output
84
  // set as output
85
  DDRD |= (1<<DDD5) | (1<<DDD4) | (1<<DDD3);
85
  DDRD |= (1<<DDD5) | (1<<DDD4) | (1<<DDD3);
86
  // low level
86
  // low level
87
  PORTD &= ~((1<<PORTD5) | (1<<PORTD4) | (1<<PORTD3));
87
  PORTD &= ~((1<<PORTD5) | (1<<PORTD4) | (1<<PORTD3));
88
 
88
 
89
  // PD3 can't be used if 2nd UART is activated
89
  // PD3 can't be used if 2nd UART is activated
90
  // because TXD1 is at that port
90
  // because TXD1 is at that port
91
  if (CPUType != ATMEGA644P) {
91
  if (CPUType != ATMEGA644P) {
92
    DDRD |= (1<<PORTD3);
92
    DDRD |= (1<<PORTD3);
93
    PORTD &= ~(1<<PORTD3);
93
    PORTD &= ~(1<<PORTD3);
94
  }
94
  }
95
 
95
 
96
  // Timer/Counter1 Control Register A, B, C
96
  // Timer/Counter1 Control Register A, B, C
97
 
97
 
98
  // Normal Mode (bits: WGM13=0, WGM12=0, WGM11=0, WGM10=0)
98
  // Normal Mode (bits: WGM13=0, WGM12=0, WGM11=0, WGM10=0)
99
  // Compare output pin A & B is disabled (bits: COM1A1=0, COM1A0=0, COM1B1=0, COM1B0=0)
99
  // Compare output pin A & B is disabled (bits: COM1A1=0, COM1A0=0, COM1B1=0, COM1B0=0)
100
  // Set clock source to SYSCLK/64 (bit: CS12=0, CS11=1, CS10=1)
100
  // Set clock source to SYSCLK/64 (bit: CS12=0, CS11=1, CS10=1)
101
  // Enable input capture noise cancler (bit: ICNC1=1)
101
  // Enable input capture noise cancler (bit: ICNC1=1)
102
  // Trigger on positive edge of the input capture pin (bit: ICES1=1),
102
  // Trigger on positive edge of the input capture pin (bit: ICES1=1),
103
  // Therefore the counter incremets at a clock of 20 MHz/64 = 312.5 kHz or 3.2�s
103
  // Therefore the counter incremets at a clock of 20 MHz/64 = 312.5 kHz or 3.2�s
104
  // The longest period is 0xFFFF / 312.5 kHz = 0.209712 s.
104
  // The longest period is 0xFFFF / 312.5 kHz = 0.209712 s.
105
  TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0) | (1 << COM1B1) | (1 << COM1B0) | (1 << WGM11) | (1 << WGM10));
105
  TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0) | (1 << COM1B1) | (1 << COM1B0) | (1 << WGM11) | (1 << WGM10));
106
  TCCR1B &= ~((1 << WGM13) | (1 << WGM12) | (1 << CS12));
106
  TCCR1B &= ~((1 << WGM13) | (1 << WGM12) | (1 << CS12));
107
  TCCR1B |= (1 << CS11) | (1 << CS10) | (1 << ICES1) | (1 << ICNC1);
107
  TCCR1B |= (1 << CS11) | (1 << CS10) | (1 << ICES1) | (1 << ICNC1);
108
  TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B));
108
  TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B));
109
 
109
 
110
  // Timer/Counter1 Interrupt Mask Register
110
  // Timer/Counter1 Interrupt Mask Register
111
  // Enable Input Capture Interrupt (bit: ICIE1=1)
111
  // Enable Input Capture Interrupt (bit: ICIE1=1)
112
  // Disable Output Compare A & B Match Interrupts (bit: OCIE1B=0, OICIE1A=0)
112
  // Disable Output Compare A & B Match Interrupts (bit: OCIE1B=0, OICIE1A=0)
113
  // Enable Overflow Interrupt (bit: TOIE1=0)
113
  // Enable Overflow Interrupt (bit: TOIE1=0)
114
  TIMSK1 &= ~((1<<OCIE1B) | (1<<OCIE1A) | (1<<TOIE1));
114
  TIMSK1 &= ~((1<<OCIE1B) | (1<<OCIE1A) | (1<<TOIE1));
115
  TIMSK1 |= (1<<ICIE1);
115
  TIMSK1 |= (1<<ICIE1);
116
 
116
 
117
  RC_Quality = 0;
117
  RC_Quality = 0;
118
 
118
 
119
  SREG = sreg;
119
  SREG = sreg;
120
}
120
}
121
 
121
 
122
/********************************************************************/
122
/********************************************************************/
123
/*         Every time a positive edge is detected at PD6            */
123
/*         Every time a positive edge is detected at PD6            */
124
/********************************************************************/
124
/********************************************************************/
125
/*                               t-Frame
125
/*                               t-Frame
126
    <----------------------------------------------------------------------->
126
    <----------------------------------------------------------------------->
127
     ____   ______   _____   ________                ______    sync gap      ____
127
     ____   ______   _____   ________                ______    sync gap      ____
128
    |    | |      | |     | |        |              |      |                |
128
    |    | |      | |     | |        |              |      |                |
129
    |    | |      | |     | |        |              |      |                |
129
    |    | |      | |     | |        |              |      |                |
130
 ___|    |_|      |_|     |_|        |_.............|      |________________|
130
 ___|    |_|      |_|     |_|        |_.............|      |________________|
131
    <-----><-------><------><-----------            <------>                <---
131
    <-----><-------><------><-----------            <------>                <---
132
 t0       t1      t2       t4                     tn                     t0
132
 t0       t1      t2       t4                     tn                     t0
133
 
133
 
134
 The PPM-Frame length is 22.5 ms.
134
 The PPM-Frame length is 22.5 ms.
135
 Channel high pulse width range is 0.7 ms to 1.7 ms completed by an 0.3 ms low pulse.
135
 Channel high pulse width range is 0.7 ms to 1.7 ms completed by an 0.3 ms low pulse.
136
 The mininimum time delay of two events coding a channel is ( 0.7 + 0.3) ms = 1 ms.
136
 The mininimum time delay of two events coding a channel is ( 0.7 + 0.3) ms = 1 ms.
137
 The maximum time delay of two events coding a channel is ( 1.7 + 0.3) ms = 2 ms.
137
 The maximum time delay of two events coding a channel is ( 1.7 + 0.3) ms = 2 ms.
138
 The minimum duration of all channels at minimum value is  8 * 1 ms = 8 ms.
138
 The minimum duration of all channels at minimum value is  8 * 1 ms = 8 ms.
139
 The maximum duration of all channels at maximum value is  8 * 2 ms = 16 ms.
139
 The maximum duration of all channels at maximum value is  8 * 2 ms = 16 ms.
140
 The remaining time of (22.5 - 8 ms) ms = 14.5 ms  to (22.5 - 16 ms) ms = 6.5 ms is
140
 The remaining time of (22.5 - 8 ms) ms = 14.5 ms  to (22.5 - 16 ms) ms = 6.5 ms is
141
 the syncronization gap.
141
 the syncronization gap.
142
 */
142
 */
143
ISR(TIMER1_CAPT_vect)
143
ISR(TIMER1_CAPT_vect)
144
{ // typical rate of 1 ms to 2 ms
144
{ // typical rate of 1 ms to 2 ms
145
  int16_t signal = 0, tmp;
145
  int16_t signal = 0, tmp;
146
  static int16_t index;
146
  static int16_t index;
147
  static uint16_t oldICR1 = 0;
147
  static uint16_t oldICR1 = 0;
148
 
148
 
149
  // 16bit Input Capture Register ICR1 contains the timer value TCNT1
149
  // 16bit Input Capture Register ICR1 contains the timer value TCNT1
150
  // at the time the edge was detected
150
  // at the time the edge was detected
151
 
151
 
152
  // calculate the time delay to the previous event time which is stored in oldICR1
152
  // calculate the time delay to the previous event time which is stored in oldICR1
153
  // calculatiing the difference of the two uint16_t and converting the result to an int16_t
153
  // calculatiing the difference of the two uint16_t and converting the result to an int16_t
154
  // implicit handles a timer overflow 65535 -> 0 the right way.
154
  // implicit handles a timer overflow 65535 -> 0 the right way.
155
  signal = (uint16_t) ICR1 - oldICR1;
155
  signal = (uint16_t) ICR1 - oldICR1;
156
  oldICR1 = ICR1;
156
  oldICR1 = ICR1;
157
 
157
 
158
  //sync gap? (3.52 ms < signal < 25.6 ms)
158
  //sync gap? (3.52 ms < signal < 25.6 ms)
159
  if ((signal > 1100) && (signal < 8000)) {
159
  if ((signal > 1100) && (signal < 8000)) {
160
    // if a sync gap happens and there where at least 4 channels decoded before
160
    // if a sync gap happens and there where at least 4 channels decoded before
161
    // then the NewPpmData flag is reset indicating valid data in the PPM_in[] array.
161
    // then the NewPpmData flag is reset indicating valid data in the PPM_in[] array.
162
    if (index >= 3) {
162
    if (index >= 3) {
163
      NewPpmData = 0; // Null means NewData for the first 4 channels
163
      NewPpmData = 0; // Null means NewData for the first 4 channels
164
    }
164
    }
165
    // synchronize channel index
165
    // synchronize channel index
166
    index = 0;
166
    index = 0;
167
  } else { // within the PPM frame
167
  } else { // within the PPM frame
168
    if (index < MAX_CHANNELS) { // PPM24 supports 12 channels
168
    if (index < MAX_CHANNELS) { // PPM24 supports 12 channels
169
      // check for valid signal length (0.8 ms < signal < 2.1984 ms)
169
      // check for valid signal length (0.8 ms < signal < 2.1984 ms)
170
      // signal range is from 1.0ms/3.2us = 312 to 2.0ms/3.2us = 625
170
      // signal range is from 1.0ms/3.2us = 312 to 2.0ms/3.2us = 625
171
      if ((signal > 250) && (signal < 687)) {
171
      if ((signal > 250) && (signal < 687)) {
172
        // shift signal to zero symmetric range  -154 to 159
172
        // shift signal to zero symmetric range  -154 to 159
173
        signal -= 470; // offset of 1.4912 ms ??? (469 * 3.2�s = 1.5008 ms)
173
        signal -= 470; // offset of 1.4912 ms ??? (469 * 3.2�s = 1.5008 ms)
174
        // check for stable signal
174
        // check for stable signal
175
        if (abs(signal - PPM_in[index]) < 6) {
175
        if (abs(signal - PPM_in[index]) < 6) {
176
          if (RC_Quality < 200)
176
          if (RC_Quality < 200)
177
            RC_Quality += 10;
177
            RC_Quality += 10;
178
          else
178
          else
179
            RC_Quality = 200;
179
            RC_Quality = 200;
180
        }
180
        }
181
        // If signal is the same as before +/- 1, just keep it there.
181
        // If signal is the same as before +/- 1, just keep it there.
182
        if (signal >= PPM_in[index] - 1 && signal <= PPM_in[index] + 1) {
182
        if (signal >= PPM_in[index] - 1 && signal <= PPM_in[index] + 1) {
183
          // In addition, if the signal is very close to 0, just set it to 0.
183
          // In addition, if the signal is very close to 0, just set it to 0.
184
          if (signal >= -1 && signal <= 1) {
184
          if (signal >= -1 && signal <= 1) {
185
            tmp = 0;
185
            tmp = 0;
186
          } else {
186
          } else {
187
            tmp = PPM_in[index];
187
            tmp = PPM_in[index];
188
          }
188
          }
189
        } else
189
        } else
190
          tmp = signal;
190
          tmp = signal;
191
        // calculate signal difference on good signal level
191
        // calculate signal difference on good signal level
192
        if (RC_Quality >= 195)
192
        if (RC_Quality >= 195)
193
          PPM_diff[index] = ((tmp - PPM_in[index]) / 3) * 3; // cut off lower 3 bit for nois reduction
193
          PPM_diff[index] = ((tmp - PPM_in[index]) / 3) * 3; // cut off lower 3 bit for nois reduction
194
        else
194
        else
195
          PPM_diff[index] = 0;
195
          PPM_diff[index] = 0;
196
        PPM_in[index] = tmp; // update channel value
196
        PPM_in[index] = tmp; // update channel value
197
      }
197
      }
198
      index++; // next channel
198
      index++; // next channel
199
      // demux sum signal for channels 5 to 7 to J3, J4, J5
199
      // demux sum signal for channels 5 to 7 to J3, J4, J5
200
      // TODO: General configurability of this R/C channel forwarding. Or remove it completely - the
200
      // TODO: General configurability of this R/C channel forwarding. Or remove it completely - the
201
      // channels are usually available at the receiver anyway.
201
      // channels are usually available at the receiver anyway.
202
      // if(index == 5) J3HIGH; else J3LOW;
202
      // if(index == 5) J3HIGH; else J3LOW;
203
      // if(index == 6) J4HIGH; else J4LOW;
203
      // if(index == 6) J4HIGH; else J4LOW;
204
      // if(CPUType != ATMEGA644P) // not used as TXD1
204
      // if(CPUType != ATMEGA644P) // not used as TXD1
205
      //  {
205
      //  {
206
      //    if(index == 7) J5HIGH; else J5LOW;
206
      //    if(index == 7) J5HIGH; else J5LOW;
207
      //  }
207
      //  }
208
    }
208
    }
209
  }
209
  }
210
}
210
}
211
 
211
 
212
#define RCChannel(dimension) PPM_in[channelMap.channels[dimension]]
212
#define RCChannel(dimension) PPM_in[channelMap.channels[dimension]]
213
#define RCDiff(dimension) PPM_diff[channelMap.channels[dimension]]
213
#define RCDiff(dimension) PPM_diff[channelMap.channels[dimension]]
214
#define COMMAND_THRESHOLD 85
214
#define COMMAND_THRESHOLD 85
215
#define COMMAND_CHANNEL_VERTICAL CH_THROTTLE
215
#define COMMAND_CHANNEL_VERTICAL CH_THROTTLE
216
#define COMMAND_CHANNEL_HORIZONTAL CH_YAW
216
#define COMMAND_CHANNEL_HORIZONTAL CH_YAW
217
 
217
 
218
// Internal.
218
// Internal.
219
uint8_t RC_getStickCommand(void) {
219
uint8_t RC_getStickCommand(void) {
220
  if (RCChannel(COMMAND_CHANNEL_VERTICAL) > COMMAND_THRESHOLD) {
220
  if (RCChannel(COMMAND_CHANNEL_VERTICAL) > COMMAND_THRESHOLD) {
221
    // vertical is up
221
    // vertical is up
222
    if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) > COMMAND_THRESHOLD)
222
    if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) > COMMAND_THRESHOLD)
223
      return COMMAND_GYROCAL;
223
      return COMMAND_GYROCAL;
224
    if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) < -COMMAND_THRESHOLD)
224
    if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) < -COMMAND_THRESHOLD)
225
      return COMMAND_ACCCAL;
225
      return COMMAND_ACCCAL;
226
    return COMMAND_NONE;
226
    return COMMAND_NONE;
227
  } else if (RCChannel(COMMAND_CHANNEL_VERTICAL) < -COMMAND_THRESHOLD) {
227
  } else if (RCChannel(COMMAND_CHANNEL_VERTICAL) < -COMMAND_THRESHOLD) {
228
    // vertical is down
228
    // vertical is down
229
    if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) > COMMAND_THRESHOLD)
229
    if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) > COMMAND_THRESHOLD)
230
      return COMMAND_STOP;
230
      return COMMAND_STOP;
231
    if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) < -COMMAND_THRESHOLD)
231
    if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) < -COMMAND_THRESHOLD)
232
      return COMMAND_START;
232
      return COMMAND_START;
233
    return COMMAND_NONE;
233
    return COMMAND_NONE;
234
  }
234
  }
235
  // vertical is around center
235
  // vertical is around center
236
  return COMMAND_NONE;
236
  return COMMAND_NONE;
237
}
237
}
238
 
238
 
239
/*
239
/*
240
 * This must be called (as the only thing) for each control loop cycle (488 Hz).
240
 * This must be called (as the only thing) for each control loop cycle (488 Hz).
241
 */
241
 */
242
void RC_update() {
242
void RC_update() {
243
  int16_t tmp1, tmp2;
243
  int16_t tmp1, tmp2;
244
  if (RC_Quality) {
244
  if (RC_Quality) {
245
    RC_Quality--;
245
    RC_Quality--;
246
    if (NewPpmData-- == 0) {
246
    if (NewPpmData-- == 0) {
247
      RC_PRTY[CONTROL_PITCH] = RCChannel(CH_PITCH) * staticParams.stickP
247
      RC_PRTY[CONTROL_PITCH] = RCChannel(CH_PITCH) * staticParams.stickP
248
          + RCDiff(CH_PITCH) * staticParams.stickD;
248
          + RCDiff(CH_PITCH) * staticParams.stickD;
249
      RC_PRTY[CONTROL_ROLL] = RCChannel(CH_ROLL) * staticParams.stickP
249
      RC_PRTY[CONTROL_ROLL] = RCChannel(CH_ROLL) * staticParams.stickP
250
          + RCDiff(CH_ROLL) * staticParams.stickD;
250
          + RCDiff(CH_ROLL) * staticParams.stickD;
251
      RC_PRTY[CONTROL_THROTTLE] = RCChannel(CH_THROTTLE) + RCDiff(CH_THROTTLE)
251
      RC_PRTY[CONTROL_THROTTLE] = RCChannel(CH_THROTTLE) + RCDiff(CH_THROTTLE)
252
          * staticParams.stickThrottleD + 120;
252
          * staticParams.stickThrottleD + 120;
253
      if (RC_PRTY[CONTROL_THROTTLE] < 0)
253
      if (RC_PRTY[CONTROL_THROTTLE] < 0)
254
        RC_PRTY[CONTROL_THROTTLE] = 0; // Throttle is non negative.
254
        RC_PRTY[CONTROL_THROTTLE] = 0; // Throttle is non negative.
255
      tmp1 = -RCChannel(CH_YAW) - RCDiff(CH_YAW);
255
      tmp1 = -RCChannel(CH_YAW) - RCDiff(CH_YAW);
256
      // exponential stick sensitivity in yawing rate
256
      // exponential stick sensitivity in yawing rate
257
      tmp2 = (int32_t) staticParams.stickYawP * ((int32_t) tmp1 * abs(tmp1))
257
      tmp2 = (int32_t) staticParams.stickYawP * ((int32_t) tmp1 * abs(tmp1))
258
          / 512L; // expo  y = ax + bx^2
258
          / 512L; // expo  y = ax + bx^2
259
      tmp2 += (staticParams.stickYawP * tmp1) >> 2;
259
      tmp2 += (staticParams.stickYawP * tmp1) >> 2;
260
      RC_PRTY[CONTROL_YAW] = tmp2;
260
      RC_PRTY[CONTROL_YAW] = tmp2;
261
    }
261
    }
262
    uint8_t command = RC_getStickCommand();
262
    uint8_t command = RC_getStickCommand();
263
 
263
 
264
    if (lastRCCommand == command) {
264
    if (lastRCCommand == command) {
265
      // Keep timer from overrunning.
265
      // Keep timer from overrunning.
266
      if (commandTimer < COMMAND_TIMER)
266
      if (commandTimer < COMMAND_TIMER)
267
        commandTimer++;
267
        commandTimer++;
268
    } else {
268
    } else {
269
      // There was a change.
269
      // There was a change.
270
      lastRCCommand = command;
270
      lastRCCommand = command;
271
      commandTimer = 0;
271
      commandTimer = 0;
272
    }
272
    }
273
  } else { // Bad signal
273
  } else { // Bad signal
274
    RC_PRTY[CONTROL_PITCH] = RC_PRTY[CONTROL_ROLL] = RC_PRTY[CONTROL_THROTTLE]
274
    RC_PRTY[CONTROL_PITCH] = RC_PRTY[CONTROL_ROLL] = RC_PRTY[CONTROL_THROTTLE]
275
        = RC_PRTY[CONTROL_YAW] = 0;
275
        = RC_PRTY[CONTROL_YAW] = 0;
276
  }
276
  }
277
 
-
 
278
  debugOut.analog[3] = channelMap.channels[0];
-
 
279
  debugOut.analog[4] = channelMap.channels[1];
-
 
280
  debugOut.analog[5] = channelMap.channels[2];
-
 
281
}
277
}
282
 
278
 
283
/*
279
/*
284
 * Get Pitch, Roll, Throttle, Yaw values
280
 * Get Pitch, Roll, Throttle, Yaw values
285
 */
281
 */
286
int16_t* RC_getPRTY(void) {
282
int16_t* RC_getPRTY(void) {
287
  return RC_PRTY;
283
  return RC_PRTY;
288
}
284
}
289
 
285
 
290
/*
286
/*
291
 * Get other channel value
287
 * Get other channel value
292
 */
288
 */
293
int16_t RC_getVariable(uint8_t varNum) {
289
int16_t RC_getVariable(uint8_t varNum) {
294
  if (varNum < 4)
290
  if (varNum < 4)
295
    // 0th variable is 5th channel (1-based) etc.
291
    // 0th variable is 5th channel (1-based) etc.
296
    return RCChannel(varNum + 4) + POT_OFFSET;
292
    return RCChannel(varNum + 4) + POT_OFFSET;
297
  /*
293
  /*
298
   * Let's just say:
294
   * Let's just say:
299
   * The RC variable 4 is hardwired to channel 5
295
   * The RC variable 4 is hardwired to channel 5
300
   * The RC variable 5 is hardwired to channel 6
296
   * The RC variable 5 is hardwired to channel 6
301
   * The RC variable 6 is hardwired to channel 7
297
   * The RC variable 6 is hardwired to channel 7
302
   * The RC variable 7 is hardwired to channel 8
298
   * The RC variable 7 is hardwired to channel 8
303
   * Alternatively, one could bind them to channel (4 + varNum) - or whatever...
299
   * Alternatively, one could bind them to channel (4 + varNum) - or whatever...
304
   */
300
   */
305
  return PPM_in[varNum + 1] + POT_OFFSET;
301
  return PPM_in[varNum + 1] + POT_OFFSET;
306
}
302
}
307
 
303
 
308
uint8_t RC_getSignalQuality(void) {
304
uint8_t RC_getSignalQuality(void) {
309
  if (RC_Quality >= 160)
305
  if (RC_Quality >= 160)
310
    return SIGNAL_GOOD;
306
    return SIGNAL_GOOD;
311
  if (RC_Quality >= 140)
307
  if (RC_Quality >= 140)
312
    return SIGNAL_OK;
308
    return SIGNAL_OK;
313
  if (RC_Quality >= 120)
309
  if (RC_Quality >= 120)
314
    return SIGNAL_BAD;
310
    return SIGNAL_BAD;
315
  return SIGNAL_LOST;
311
  return SIGNAL_LOST;
316
}
312
}
317
 
313
 
318
/*
314
/*
319
 * To should fired only when the right stick is in the center position.
315
 * 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
316
 * 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
317
 * 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
318
 * about the rc signal. I had values about 50..70 with a Futaba
323
 * R617 receiver.) This calibration is not strictly necessary, but
319
 * R617 receiver.) This calibration is not strictly necessary, but
324
 * for control logic that depends on the exact (non)center position
320
 * for control logic that depends on the exact (non)center position
325
 * of a stick, it may be useful.
321
 * of a stick, it may be useful.
326
 */
322
 */
327
void RC_calibrate(void) {
323
void RC_calibrate(void) {
328
  // Do nothing.
324
  // Do nothing.
329
}
325
}
330
 
326
 
331
/*
327
/*
332
 if (staticParams.GlobalConfig & CFG_HEADING_HOLD) {
328
 if (staticParams.GlobalConfig & CFG_HEADING_HOLD) {
333
 // In HH, it s OK to trim the R/C. The effect should not be conteracted here.
329
 // In HH, it s OK to trim the R/C. The effect should not be conteracted here.
334
 stickOffsetPitch = stickOffsetRoll = 0;
330
 stickOffsetPitch = stickOffsetRoll = 0;
335
 } else {
331
 } else {
336
 stickOffsetPitch = RCChannel(CH_PITCH) * staticParams.StickP;
332
 stickOffsetPitch = RCChannel(CH_PITCH) * staticParams.StickP;
337
 stickOffsetRoll = RCChannel(CH_ROLL)   * staticParams.StickP;
333
 stickOffsetRoll = RCChannel(CH_ROLL)   * staticParams.StickP;
338
 }
334
 }
339
 }
335
 }
340
 */
336
 */
341
 
337
 
342
uint8_t RC_getCommand(void) {
338
uint8_t RC_getCommand(void) {
343
  if (commandTimer == COMMAND_TIMER) {
339
  if (commandTimer == COMMAND_TIMER) {
344
    // Stick has been held long enough; command committed.
340
    // Stick has been held long enough; command committed.
345
    return lastRCCommand;
341
    return lastRCCommand;
346
  }
342
  }
347
  // Not yet sure what the command is.
343
  // Not yet sure what the command is.
348
  return COMMAND_NONE;
344
  return COMMAND_NONE;
349
}
345
}
350
 
346
 
351
/*
347
/*
352
 * Command arguments on R/C:
348
 * Command arguments on R/C:
353
 * 2--3--4
349
 * 2--3--4
354
 * |     |  +
350
 * |     |  +
355
 * 1  0  5  ^ 0
351
 * 1  0  5  ^ 0
356
 * |     |  |  
352
 * |     |  |  
357
 * 8--7--6
353
 * 8--7--6
358
 *    
354
 *    
359
 * + <--
355
 * + <--
360
 *    0
356
 *    0
361
 *
357
 *
362
 * Not in any of these positions: 0
358
 * Not in any of these positions: 0
363
 */
359
 */
364
 
360
 
365
#define ARGUMENT_THRESHOLD 70
361
#define ARGUMENT_THRESHOLD 70
366
#define ARGUMENT_CHANNEL_VERTICAL CH_PITCH
362
#define ARGUMENT_CHANNEL_VERTICAL CH_PITCH
367
#define ARGUMENT_CHANNEL_HORIZONTAL CH_ROLL
363
#define ARGUMENT_CHANNEL_HORIZONTAL CH_ROLL
368
 
364
 
369
uint8_t RC_getArgument(void) {
365
uint8_t RC_getArgument(void) {
370
  if (RCChannel(ARGUMENT_CHANNEL_VERTICAL) > ARGUMENT_THRESHOLD) {
366
  if (RCChannel(ARGUMENT_CHANNEL_VERTICAL) > ARGUMENT_THRESHOLD) {
371
    // vertical is up
367
    // vertical is up
372
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
368
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
373
      return 2;
369
      return 2;
374
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
370
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
375
      return 4;
371
      return 4;
376
    return 3;
372
    return 3;
377
  } else if (RCChannel(ARGUMENT_CHANNEL_VERTICAL) < -ARGUMENT_THRESHOLD) {
373
  } else if (RCChannel(ARGUMENT_CHANNEL_VERTICAL) < -ARGUMENT_THRESHOLD) {
378
    // vertical is down
374
    // vertical is down
379
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
375
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
380
      return 8;
376
      return 8;
381
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
377
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
382
      return 6;
378
      return 6;
383
    return 7;
379
    return 7;
384
  } else {
380
  } else {
385
    // vertical is around center
381
    // vertical is around center
386
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
382
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
387
      return 1;
383
      return 1;
388
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
384
    if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
389
      return 5;
385
      return 5;
390
    return 0;
386
    return 0;
391
  }
387
  }
392
}
388
}
393
 
389
 
394
/*
390
/*
395
uint8_t RC_getLooping(uint8_t looping) {
391
uint8_t RC_getLooping(uint8_t looping) {
396
  //  static uint8_t looping = 0;
392
  //  static uint8_t looping = 0;
397
 
393
 
398
  if (RCChannel(CH_ROLL) > staticParams.LoopThreshold && staticParams.BitConfig
394
  if (RCChannel(CH_ROLL) > staticParams.LoopThreshold && staticParams.BitConfig
399
      & CFG_LOOP_LEFT) {
395
      & CFG_LOOP_LEFT) {
400
    looping |= (LOOPING_ROLL_AXIS | LOOPING_LEFT);
396
    looping |= (LOOPING_ROLL_AXIS | LOOPING_LEFT);
401
  } else if ((looping & LOOPING_LEFT) && RCChannel(CH_ROLL)
397
  } else if ((looping & LOOPING_LEFT) && RCChannel(CH_ROLL)
402
      < staticParams.LoopThreshold - staticParams.LoopHysteresis) {
398
      < staticParams.LoopThreshold - staticParams.LoopHysteresis) {
403
    looping &= (~(LOOPING_ROLL_AXIS | LOOPING_LEFT));
399
    looping &= (~(LOOPING_ROLL_AXIS | LOOPING_LEFT));
404
  }
400
  }
405
 
401
 
406
  if (RCChannel(CH_ROLL) < -staticParams.LoopThreshold
402
  if (RCChannel(CH_ROLL) < -staticParams.LoopThreshold
407
      && staticParams.BitConfig & CFG_LOOP_RIGHT) {
403
      && staticParams.BitConfig & CFG_LOOP_RIGHT) {
408
    looping |= (LOOPING_ROLL_AXIS | LOOPING_RIGHT);
404
    looping |= (LOOPING_ROLL_AXIS | LOOPING_RIGHT);
409
  } else if ((looping & LOOPING_RIGHT) && RCChannel(CH_ROLL)
405
  } else if ((looping & LOOPING_RIGHT) && RCChannel(CH_ROLL)
410
      > -staticParams.LoopThreshold - staticParams.LoopHysteresis) {
406
      > -staticParams.LoopThreshold - staticParams.LoopHysteresis) {
411
    looping &= (~(LOOPING_ROLL_AXIS | LOOPING_RIGHT));
407
    looping &= (~(LOOPING_ROLL_AXIS | LOOPING_RIGHT));
412
  }
408
  }
413
 
409
 
414
  if (RCChannel(CH_PITCH) > staticParams.LoopThreshold
410
  if (RCChannel(CH_PITCH) > staticParams.LoopThreshold
415
      && staticParams.BitConfig & CFG_LOOP_UP) {
411
      && staticParams.BitConfig & CFG_LOOP_UP) {
416
    looping |= (LOOPING_PITCH_AXIS | LOOPING_UP);
412
    looping |= (LOOPING_PITCH_AXIS | LOOPING_UP);
417
  } else if ((looping & LOOPING_UP) && RCChannel(CH_PITCH)
413
  } else if ((looping & LOOPING_UP) && RCChannel(CH_PITCH)
418
      < staticParams.LoopThreshold - staticParams.LoopHysteresis) {
414
      < staticParams.LoopThreshold - staticParams.LoopHysteresis) {
419
    looping &= (~(LOOPING_PITCH_AXIS | LOOPING_UP));
415
    looping &= (~(LOOPING_PITCH_AXIS | LOOPING_UP));
420
  }
416
  }
421
 
417
 
422
  if (RCChannel(CH_PITCH) < -staticParams.LoopThreshold
418
  if (RCChannel(CH_PITCH) < -staticParams.LoopThreshold
423
      && staticParams.BitConfig & CFG_LOOP_DOWN) {
419
      && staticParams.BitConfig & CFG_LOOP_DOWN) {
424
    looping |= (LOOPING_PITCH_AXIS | LOOPING_DOWN);
420
    looping |= (LOOPING_PITCH_AXIS | LOOPING_DOWN);
425
  } else if ((looping & LOOPING_DOWN) && RCChannel(CH_PITCH)
421
  } else if ((looping & LOOPING_DOWN) && RCChannel(CH_PITCH)
426
      > -staticParams.LoopThreshold - staticParams.LoopHysteresis) {
422
      > -staticParams.LoopThreshold - staticParams.LoopHysteresis) {
427
    looping &= (~(LOOPING_PITCH_AXIS | LOOPING_DOWN));
423
    looping &= (~(LOOPING_PITCH_AXIS | LOOPING_DOWN));
428
  }
424
  }
429
 
425
 
430
  return looping;
426
  return looping;
431
}
427
}
432
*/
428
*/
433
 
429
 
434
uint8_t RC_testCompassCalState(void) {
430
uint8_t RC_testCompassCalState(void) {
435
  static uint8_t stick = 1;
431
  static uint8_t stick = 1;
436
  // if pitch is centered or top set stick to zero
432
  // if pitch is centered or top set stick to zero
437
  if (RCChannel(CH_PITCH) > -20)
433
  if (RCChannel(CH_PITCH) > -20)
438
    stick = 0;
434
    stick = 0;
439
  // if pitch is down trigger to next cal state
435
  // if pitch is down trigger to next cal state
440
  if ((RCChannel(CH_PITCH) < -70) && !stick) {
436
  if ((RCChannel(CH_PITCH) < -70) && !stick) {
441
    stick = 1;
437
    stick = 1;
442
    return 1;
438
    return 1;
443
  }
439
  }
444
  return 0;
440
  return 0;
445
}
441
}
446
/*
442
/*
447
 * Abstract controls are not used at the moment.
443
 * Abstract controls are not used at the moment.
448
 t_control rc_control = {
444
 t_control rc_control = {
449
 RC_getPitch,
445
 RC_getPitch,
450
 RC_getRoll,
446
 RC_getRoll,
451
 RC_getYaw,
447
 RC_getYaw,
452
 RC_getThrottle,
448
 RC_getThrottle,
453
 RC_getSignalQuality,
449
 RC_getSignalQuality,
454
 RC_calibrate
450
 RC_calibrate
455
 };
451
 };
456
 */
452
 */
457
 
453