Subversion Repositories FlightCtrl

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1775 - 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 und 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 Medien veröffentlicht werden, muss unsere Webseite "http://www.mikrokopter.de"
18
// + eindeutig als Ursprung verlinkt und genannt 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)
35
// +     Commercial use (for excample: selling of MikroKopters, selling of PCBs, assembly, ...) is only permitted
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
48
// +  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49
// +  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
50
// +  POSSIBILITY OF SUCH DAMAGE.
51
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
52
 
53
#include <avr/io.h>
54
#include <avr/interrupt.h>
55
#include <avr/wdt.h>
56
#include <avr/pgmspace.h>
57
#include <stdarg.h>
58
#include <string.h>
59
 
60
#include "eeprom.h"
61
#include "menu.h"
62
#include "timer0.h"
63
#include "uart0.h"
64
#include "attitude.h"
65
#include "rc.h"
66
#include "externalControl.h"
67
#include "output.h"
68
 
69
#if defined (USE_MK3MAG)
70
#include "ubx.h"
71
#endif
72
#ifdef USE_MK3MAG
73
#include "mk3mag.h"
74
#endif
75
 
76
#define FC_ADDRESS 1
77
#define NC_ADDRESS 2
78
#define MK3MAG_ADDRESS 3
79
 
80
#define FALSE   0
81
#define TRUE    1
82
//int8_t test __attribute__ ((section (".noinit")));
83
uint8_t request_VerInfo                 = FALSE;
84
uint8_t request_ExternalControl         = FALSE;
85
uint8_t request_Display                 = FALSE;
86
uint8_t request_Display1                = FALSE;
87
uint8_t request_DebugData               = FALSE;
88
uint8_t request_Data3D                  = FALSE;
89
uint8_t request_DebugLabel              = 255;
90
uint8_t request_PPMChannels             = FALSE;
91
uint8_t request_MotorTest               = FALSE;
92
uint8_t request_variables               = FALSE;
93
 
94
uint8_t DisplayLine = 0;
95
 
96
volatile uint8_t txd_buffer[TXD_BUFFER_LEN];
97
volatile uint8_t rxd_buffer_locked = FALSE;
98
volatile uint8_t rxd_buffer[RXD_BUFFER_LEN];
99
volatile uint8_t txd_complete = TRUE;
100
volatile uint8_t ReceivedBytes = 0;
101
volatile uint8_t *pRxData = 0;
102
volatile uint8_t RxDataLen = 0;
103
 
104
uint8_t motorTestActive  = 0;
105
uint8_t motorTest[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
106
uint8_t ConfirmFrame;
107
 
108
typedef struct {
109
  int16_t Heading;
110
} __attribute__((packed)) Heading_t;
111
 
112
DebugOut_t              DebugOut;
113
Data3D_t                Data3D;
114
UART_VersionInfo_t      UART_VersionInfo;
115
 
116
uint16_t DebugData_Timer;
117
uint16_t Data3D_Timer;
118
uint16_t DebugData_Interval = 500; // in 1ms
119
uint16_t Data3D_Interval = 0; // in 1ms
120
 
121
#ifdef USE_MK3MAG
122
int16_t Compass_Timer;
123
#endif
124
 
125
// keep lables in flash to save 512 bytes of sram space
126
const prog_uint8_t ANALOG_LABEL[32][16] = {
127
    //1234567890123456
128
    "AnglePitch      ", //0
129
    "AngleRoll       ",
130
    "AngleYaw        ",
131
    "GyroPitch(PID)  ",
132
    "GyroRoll(PID)   ",
133
    "GyroYaw         ", //5
134
    "GyroPitch(AC)   ",
135
    "GyroRoll(AC)    ",
136
    "GyroYaw(AC)     ",
137
    "AccPitch (angle)",
138
    "AccRoll (angle) ", //10
139
    "UBat            ",
140
    "RC Pitch        ",
141
    "RC Roll         ",
142
    "Corr 0/00 pitch ",
143
    "Corr 0/00 roll  ", //15
144
    "Corr pitch      ",
145
    "Corr roll       ",
146
    "Acc pitch filter",
147
    "Acc roll filter ",
148
    "ADPitchGyroOffs ", //20
149
    "ADRollGyroOffs  ",
150
    "M1              ",
151
    "M2              ",
152
    "M3              ",
153
    "M4              ", //25
154
    "Pitch acc noise ",
155
    "Roll acc noise  ",
156
    "DriftCompPitch  ",
157
    "DriftCompRoll   ",
158
    "Pitch Noise     ", //30
159
    "Roll Noise      "
160
  };
161
 
162
/****************************************************************/
163
/*              Initialization of the USART0                    */
164
/****************************************************************/
165
void usart0_Init (void) {
166
  uint8_t sreg = SREG;
167
  uint16_t ubrr = (uint16_t) ((uint32_t) SYSCLK/(8 * USART0_BAUD) - 1);
168
 
169
  // disable all interrupts before configuration
170
  cli();
171
 
172
  // disable RX-Interrupt
173
  UCSR0B &= ~(1 << RXCIE0);
174
  // disable TX-Interrupt
175
  UCSR0B &= ~(1 << TXCIE0);
176
 
177
  // set direction of RXD0 and TXD0 pins
178
  // set RXD0 (PD0) as an input pin
179
  PORTD |= (1 << PORTD0);
180
  DDRD &= ~(1 << DDD0);
181
  // set TXD0 (PD1) as an output pin
182
  PORTD |= (1 << PORTD1);
183
  DDRD |=  (1 << DDD1);
184
 
185
  // USART0 Baud Rate Register
186
  // set clock divider
187
  UBRR0H = (uint8_t)(ubrr >> 8);
188
  UBRR0L = (uint8_t)ubrr;
189
 
190
  // USART0 Control and Status Register A, B, C
191
 
192
  // enable double speed operation in
193
  UCSR0A |= (1 << U2X0);
194
  // enable receiver and transmitter in
195
  UCSR0B = (1 << TXEN0) | (1 << RXEN0);
196
  // set asynchronous mode
197
  UCSR0C &= ~(1 << UMSEL01);
198
  UCSR0C &= ~(1 << UMSEL00);
199
  // no parity
200
  UCSR0C &= ~(1 << UPM01);
201
  UCSR0C &= ~(1 << UPM00);
202
  // 1 stop bit
203
  UCSR0C &= ~(1 << USBS0);
204
  // 8-bit
205
  UCSR0B &= ~(1 << UCSZ02);
206
  UCSR0C |=  (1 << UCSZ01);
207
  UCSR0C |=  (1 << UCSZ00);
208
 
209
  // flush receive buffer
210
  while ( UCSR0A & (1<<RXC0) ) UDR0;
211
 
212
  // enable interrupts at the end
213
  // enable RX-Interrupt
214
  UCSR0B |= (1 << RXCIE0);
215
  // enable TX-Interrupt
216
  UCSR0B |= (1 << TXCIE0);
217
 
218
  // initialize the debug timer
219
  DebugData_Timer = SetDelay(DebugData_Interval);
220
 
221
  // unlock rxd_buffer
222
  rxd_buffer_locked = FALSE;
223
  pRxData = 0;
224
  RxDataLen = 0;
225
 
226
  // no bytes to send
227
  txd_complete = TRUE;
228
 
229
#ifdef USE_MK3MAG
230
  Compass_Timer = SetDelay(220);
231
#endif
232
 
233
  UART_VersionInfo.SWMajor = VERSION_MAJOR;
234
  UART_VersionInfo.SWMinor = VERSION_MINOR;
235
  UART_VersionInfo.SWPatch = VERSION_PATCH;
236
  UART_VersionInfo.ProtoMajor = VERSION_SERIAL_MAJOR;
237
  UART_VersionInfo.ProtoMinor = VERSION_SERIAL_MINOR;
238
 
239
  // restore global interrupt flags
240
  SREG = sreg;
241
}
242
 
243
/****************************************************************/
244
/* USART0 transmitter ISR                                       */
245
/****************************************************************/
246
ISR(USART0_TX_vect) {
247
  static uint16_t ptr_txd_buffer = 0;
248
  uint8_t tmp_tx;
249
  if(!txd_complete) { // transmission not completed
250
    ptr_txd_buffer++;                    // die [0] wurde schon gesendet
251
    tmp_tx = txd_buffer[ptr_txd_buffer];
252
    // if terminating character or end of txd buffer was reached
253
    if((tmp_tx == '\r') || (ptr_txd_buffer == TXD_BUFFER_LEN)) {
254
      ptr_txd_buffer = 0; // reset txd pointer
255
      txd_complete = 1; // stop transmission
256
    }
257
    UDR0 = tmp_tx; // send current byte will trigger this ISR again
258
  }
259
  // transmission completed
260
  else ptr_txd_buffer = 0;
261
}
262
 
263
/****************************************************************/
264
/* USART0 receiver               ISR                            */
265
/****************************************************************/
266
ISR(USART0_RX_vect) {
267
  static uint16_t crc;
268
  static uint8_t ptr_rxd_buffer = 0;
269
  uint8_t crc1, crc2;
270
  uint8_t c;
271
 
272
  DebugOut.Digital[0] ^= DEBUG_SERIAL;
273
  DebugOut.Digital[1] ^= DEBUG_SERIAL;
274
 
275
  c = UDR0;  // catch the received byte
276
 
277
#if (defined (USE_MK3MAG))
278
  // If the cpu is not an Atmega644P the ublox module should be conneced to rxd of the 1st uart.
279
  if(CPUType != ATMEGA644P) ubx_parser(c);
280
#endif
281
 
282
  if(rxd_buffer_locked) return; // if rxd buffer is locked immediately return
283
 
284
  // the rxd buffer is unlocked
285
  if((ptr_rxd_buffer == 0) && (c == '#')) { // if rxd buffer is empty and syncronisation character is received
286
    rxd_buffer[ptr_rxd_buffer++] = c; // copy 1st byte to buffer
287
    crc = c; // init crc
288
  }
289
#if 0
290
  else if (ptr_rxd_buffer == 1) { // handle address
291
    rxd_buffer[ptr_rxd_buffer++] = c; // copy byte to rxd buffer
292
    crc += c; // update crc
293
  }
294
#endif
295
  else if (ptr_rxd_buffer < RXD_BUFFER_LEN) { // collect incomming bytes
296
    if(c != '\r') { // no termination character
297
      rxd_buffer[ptr_rxd_buffer++] = c; // copy byte to rxd buffer
298
      crc += c; // update crc
299
    } else { // termination character was received
300
      // the last 2 bytes are no subject for checksum calculation
301
      // they are the checksum itself
302
      crc -= rxd_buffer[ptr_rxd_buffer-2];
303
      crc -= rxd_buffer[ptr_rxd_buffer-1];
304
      // calculate checksum from transmitted data
305
      crc %= 4096;
306
      crc1 = '=' + crc / 64;
307
      crc2 = '=' + crc % 64;
308
      // compare checksum to transmitted checksum bytes
309
      if((crc1 == rxd_buffer[ptr_rxd_buffer-2]) && (crc2 == rxd_buffer[ptr_rxd_buffer-1])) {
310
        // checksum valid
311
        rxd_buffer[ptr_rxd_buffer] = '\r'; // set termination character
312
        ReceivedBytes = ptr_rxd_buffer + 1;// store number of received bytes
313
        rxd_buffer_locked = TRUE;          // lock the rxd buffer
314
        // if 2nd byte is an 'R' enable watchdog that will result in an reset
315
        if(rxd_buffer[2] == 'R') {wdt_enable(WDTO_250MS);} // Reset-Commando
316
      } else {  // checksum invalid
317
        rxd_buffer_locked = FALSE; // unlock rxd buffer
318
      }
319
      ptr_rxd_buffer = 0; // reset rxd buffer pointer
320
    }
321
  } else { // rxd buffer overrun
322
    ptr_rxd_buffer = 0; // reset rxd buffer
323
    rxd_buffer_locked = FALSE; // unlock rxd buffer
324
  }
325
}
326
 
327
// --------------------------------------------------------------------------
328
void AddCRC(uint16_t datalen) {
329
  uint16_t tmpCRC = 0, i;
330
  for(i = 0; i < datalen; i++) {
331
    tmpCRC += txd_buffer[i];
332
  }
333
  tmpCRC %= 4096;
334
  txd_buffer[i++] = '=' + tmpCRC / 64;
335
  txd_buffer[i++] = '=' + tmpCRC % 64;
336
  txd_buffer[i++] = '\r';
337
  txd_complete = FALSE;
338
  UDR0 = txd_buffer[0]; // initiates the transmittion (continued in the TXD ISR)
339
}
340
 
341
// --------------------------------------------------------------------------
342
// application example:
343
// SendOutData('A', FC_ADDRESS, 2, (uint8_t *)&request_DebugLabel, sizeof(request_DebugLabel), label, 16);
344
/*
345
void SendOutData(uint8_t cmd, uint8_t addr, uint8_t numofbuffers, ...) { // uint8_t *pdata, uint8_t len, ...
346
  va_list ap;
347
  uint16_t txd_bufferIndex = 0;
348
  uint8_t *currentBuffer;
349
  uint8_t currentBufferIndex;
350
  uint16_t lengthOfCurrentBuffer;
351
  uint8_t shift = 0;
352
 
353
  txd_buffer[txd_bufferIndex++] = '#';                  // Start character
354
  txd_buffer[txd_bufferIndex++] = 'a' + addr;           // Address (a=0; b=1,...)
355
  txd_buffer[txd_bufferIndex++] = cmd;                  // Command
356
 
357
  va_start(ap, numofbuffers);
358
 
359
  while(numofbuffers) {
360
    currentBuffer = va_arg(ap, uint8_t*);
361
    lengthOfCurrentBuffer = va_arg(ap, int);
362
    currentBufferIndex = 0;
363
    // Encode data: 3 bytes of data are encoded into 4 bytes,
364
    // where the 2 most significant bits are both 0.
365
    while(currentBufferIndex != lengthOfCurrentBuffer) {
366
      if (!shift) txd_buffer[txd_bufferIndex] = 0;
367
      txd_buffer[txd_bufferIndex]  |= currentBuffer[currentBufferIndex] >> (shift + 2);
368
      txd_buffer[++txd_bufferIndex] = (currentBuffer[currentBufferIndex] << (4 - shift)) & 0b00111111;
369
      shift += 2;
370
      if (shift == 6) { shift=0; txd_bufferIndex++; }
371
      currentBufferIndex++;
372
    }
373
  }
374
  // If the number of data bytes was not divisible by 3, stuff
375
  //  with 0 pseudodata  until length is again divisible by 3.
376
  if (shift == 2) {
377
    // We need to stuff with zero bytes at the end.
378
    txd_buffer[txd_bufferIndex]  &= 0b00110000;
379
    txd_buffer[++txd_bufferIndex] = 0;
380
    shift = 4;
381
  }
382
  if (shift == 4) {
383
    // We need to stuff with zero bytes at the end.
384
    txd_buffer[txd_bufferIndex++] &= 0b00111100;
385
    txd_buffer[txd_bufferIndex]    = 0;
386
  }
387
  va_end(ap);
388
  AddCRC(pt); // add checksum after data block and initates the transmission
389
}
390
*/
391
 
392
void SendOutData(uint8_t cmd, uint8_t addr, uint8_t numofbuffers, ...) { // uint8_t *pdata, uint8_t len, ...
393
  va_list ap;
394
  uint16_t pt = 0;
395
  uint8_t a,b,c;
396
  uint8_t ptr = 0;
397
 
398
  uint8_t *pdata = 0;
399
  int len = 0;
400
 
401
  txd_buffer[pt++] = '#';                       // Start character
402
  txd_buffer[pt++] = 'a' + addr;        // Address (a=0; b=1,...)
403
  txd_buffer[pt++] = cmd;                       // Command
404
 
405
  va_start(ap, numofbuffers);
406
 
407
  if(numofbuffers) {
408
    pdata = va_arg(ap, uint8_t*);
409
    len = va_arg(ap, int);
410
    ptr = 0;
411
    numofbuffers--;
412
  }
413
 
414
  while(len){
415
    if(len) {
416
      a = pdata[ptr++];
417
      len--;
418
      if((!len) && numofbuffers) {
419
        pdata = va_arg(ap, uint8_t*);
420
        len = va_arg(ap, int);
421
        ptr = 0;
422
        numofbuffers--;
423
      }
424
    }
425
    else a = 0;
426
    if(len) {
427
      b = pdata[ptr++];
428
      len--;
429
      if((!len) && numofbuffers) {
430
        pdata = va_arg(ap, uint8_t*);
431
        len = va_arg(ap, int);
432
        ptr = 0;
433
        numofbuffers--;
434
      }
435
    } else b = 0;
436
    if(len) {
437
      c = pdata[ptr++];
438
      len--;
439
      if((!len) && numofbuffers) {
440
        pdata = va_arg(ap, uint8_t*);
441
        len = va_arg(ap, int);
442
        ptr = 0;
443
        numofbuffers--;
444
      }
445
    }
446
    else c = 0;
447
    txd_buffer[pt++] = '=' + (a >> 2);
448
    txd_buffer[pt++] = '=' + (((a & 0x03) << 4) | ((b & 0xf0) >> 4));
449
    txd_buffer[pt++] = '=' + (((b & 0x0f) << 2) | ((c & 0xc0) >> 6));
450
    txd_buffer[pt++] = '=' + ( c & 0x3f);
451
  }
452
  va_end(ap);
453
  AddCRC(pt); // add checksum after data block and initates the transmission
454
}
455
 
456
// --------------------------------------------------------------------------
457
void Decode64(void) {
458
  uint8_t a,b,c,d;
459
  uint8_t x,y,z;
460
  uint8_t ptrIn = 3;
461
  uint8_t ptrOut = 3;
462
  uint8_t len = ReceivedBytes - 6;
463
 
464
  while(len) {
465
    a = rxd_buffer[ptrIn++] - '=';
466
    b = rxd_buffer[ptrIn++] - '=';
467
    c = rxd_buffer[ptrIn++] - '=';
468
    d = rxd_buffer[ptrIn++] - '=';
469
    //if(ptrIn > ReceivedBytes - 3) break;
470
 
471
    x = (a << 2) | (b >> 4);
472
    y = ((b & 0x0f) << 4) | (c >> 2);
473
    z = ((c & 0x03) << 6) | d;
474
 
475
    if(len--) rxd_buffer[ptrOut++] = x; else break;
476
    if(len--) rxd_buffer[ptrOut++] = y; else break;
477
    if(len--) rxd_buffer[ptrOut++] = z; else break;
478
  }
479
  pRxData = &rxd_buffer[3];
480
  RxDataLen = ptrOut - 3;
481
}
482
 
483
// --------------------------------------------------------------------------
484
void usart0_ProcessRxData(void) {
485
  // We control the motorTestActive var from here: Count it down.
486
  if (motorTestActive) motorTestActive--;
487
  // if data in the rxd buffer are not locked immediately return
488
  if(!rxd_buffer_locked) return;
489
  uint8_t tempchar1, tempchar2;
490
  Decode64(); // decode data block in rxd_buffer
491
 
492
  switch(rxd_buffer[1] - 'a') {
493
 
494
  case FC_ADDRESS:
495
    switch(rxd_buffer[2]) {
496
#ifdef USE_MK3MAG
497
    case 'K':// compass value
498
      compassHeading = ((Heading_t *)pRxData)->Heading;
499
      compassOffCourse = ((540 + compassHeading - compassCourse) % 360) - 180;
500
      break;
501
#endif
502
    case 't': // motor test
503
      if(RxDataLen > 20) {
504
        memcpy(&motorTest[0], (uint8_t*)pRxData, sizeof(motorTest));
505
      } else {
506
        memcpy(&motorTest[0], (uint8_t*)pRxData, 4);
507
      }
508
      motorTestActive = 255;
509
      externalControlActive = 255;
510
      break;
511
 
512
    case 'n':// "Get Mixer Table
513
      while(!txd_complete); // wait for previous frame to be sent
514
      SendOutData('N', FC_ADDRESS, 1, (uint8_t *) &Mixer, sizeof(Mixer));
515
      break;
516
 
517
    case 'm':// "Set Mixer Table
518
      if(pRxData[0] == EEMIXER_REVISION) {
519
        memcpy(&Mixer, (uint8_t*)pRxData, sizeof(Mixer));
520
        MixerTable_WriteToEEProm();
521
        while(!txd_complete); // wait for previous frame to be sent
522
        tempchar1 = 1;
523
      } else {
524
        tempchar1 = 0;
525
      }
526
      SendOutData('M', FC_ADDRESS,  1, &tempchar1, 1);
527
      break;
528
 
529
    case 'p': // get PPM channels
530
      request_PPMChannels = TRUE;
531
      break;
532
 
533
    case 'q':// request settings
534
      if(pRxData[0] == 0xFF) {
535
        pRxData[0] = GetParamByte(PID_ACTIVE_SET);
536
      }
537
      // limit settings range
538
      if(pRxData[0] < 1) pRxData[0] = 1; // limit to 1
539
      else if(pRxData[0] > 5) pRxData[0] = 5; // limit to 5
540
      // load requested parameter set
541
      ParamSet_ReadFromEEProm(pRxData[0]);
542
      tempchar1 = pRxData[0];
543
      tempchar2 = EEPARAM_REVISION;
544
      while(!txd_complete); // wait for previous frame to be sent
545
      SendOutData('Q', FC_ADDRESS,3, &tempchar1, sizeof(tempchar1), &tempchar2, sizeof(tempchar2), (uint8_t *) &staticParams, sizeof(staticParams));
546
      break;
547
 
548
    case 's': // save settings
549
      if(!(MKFlags & MKFLAG_MOTOR_RUN)) // save settings only if motors ar off
550
        {
551
          if((1 <= pRxData[0]) && (pRxData[0] <= 5) && (pRxData[1] == EEPARAM_REVISION)) // check for setting to be in range and version of settings
552
            {
553
              memcpy(&staticParams, (uint8_t*)&pRxData[2], sizeof(staticParams));
554
              ParamSet_WriteToEEProm(pRxData[0]);
555
              /*
556
                TODO: Remove this encapsulation breach
557
                turnOver180Pitch = (int32_t) staticParams.AngleTurnOverPitch * 2500L;
558
                turnOver180Roll = (int32_t) staticParams.AngleTurnOverRoll * 2500L;
559
              */
560
              tempchar1 = getActiveParamSet();
561
              beepNumber(tempchar1);
562
            }
563
          else
564
            {
565
              tempchar1 = 0;    //indicate bad data
566
            }
567
          while(!txd_complete); // wait for previous frame to be sent
568
          SendOutData('S', FC_ADDRESS,1, &tempchar1, sizeof(tempchar1));
569
        }
570
      break;
571
 
572
    default:
573
      //unsupported command received
574
      break;
575
    } // case FC_ADDRESS:
576
 
577
  default: // any Slave Address
578
    switch(rxd_buffer[2]) {
579
      case 'a':// request for labels of the analog debug outputs
580
        request_DebugLabel = pRxData[0];
581
        if(request_DebugLabel > 31) request_DebugLabel = 31;
582
        externalControlActive = 255;
583
        break;
584
 
585
      case 'b': // submit extern control
586
        memcpy(&externalControl, (uint8_t*)pRxData, sizeof(externalControl));
587
        ConfirmFrame = externalControl.frame;
588
        externalControlActive = 255;
589
        break;
590
 
591
      case 'h':// request for display columns
592
        externalControlActive = 255;
593
        RemoteKeys |= pRxData[0];
594
        if(RemoteKeys) DisplayLine = 0;
595
        request_Display = TRUE;
596
        break;
597
 
598
      case 'l':// request for display columns
599
        externalControlActive = 255;
600
        MenuItem = pRxData[0];
601
        request_Display1 = TRUE;
602
        break;
603
 
604
      case 'v': // request for version and board release
605
        request_VerInfo = TRUE;
606
        break;
607
 
608
    case 'x':
609
      request_variables = TRUE;
610
      break;
611
 
612
      case 'g':// get external control data
613
        request_ExternalControl = TRUE;
614
        break;
615
 
616
      case 'd': // request for the debug data
617
        DebugData_Interval = (uint16_t) pRxData[0] * 10;
618
        if(DebugData_Interval > 0) request_DebugData = TRUE;
619
        break;
620
 
621
      case 'c': // request for the 3D data
622
        Data3D_Interval = (uint16_t) pRxData[0] * 10;
623
        if(Data3D_Interval > 0) request_Data3D = TRUE;
624
        break;
625
 
626
      default:
627
        //unsupported command received
628
        break;
629
      }
630
    break; // default:
631
  }
632
  // unlock the rxd buffer after processing
633
  pRxData = 0;
634
  RxDataLen = 0;
635
  rxd_buffer_locked = FALSE;
636
}
637
 
638
/************************************************************************/
639
/* Routine für die Serielle Ausgabe                                     */
640
/************************************************************************/
641
int16_t uart_putchar (int8_t c) {
642
  if (c == '\n')
643
    uart_putchar('\r');
644
  // wait until previous character was send
645
  loop_until_bit_is_set(UCSR0A, UDRE0);
646
  // send character
647
  UDR0 = c;
648
  return (0);
649
}
650
 
651
//---------------------------------------------------------------------------------------------
652
void usart0_TransmitTxData(void) {
653
  if(!txd_complete) return;
654
 
655
  if(request_VerInfo && txd_complete) {
656
    SendOutData('V', FC_ADDRESS, 1, (uint8_t *) &UART_VersionInfo, sizeof(UART_VersionInfo));
657
    request_VerInfo = FALSE;
658
  }
659
 
660
  if(request_Display && txd_complete) {
661
    LCD_PrintMenu();
662
    SendOutData('H', FC_ADDRESS, 2, &DisplayLine, sizeof(DisplayLine), &DisplayBuff[DisplayLine * 20], 20);
663
    DisplayLine++;
664
    if(DisplayLine >= 4) DisplayLine = 0;
665
    request_Display = FALSE;
666
  }
667
 
668
  if(request_Display1 && txd_complete) {
669
    LCD_PrintMenu();
670
    SendOutData('L', FC_ADDRESS, 3, &MenuItem, sizeof(MenuItem), &MaxMenuItem, sizeof(MaxMenuItem), DisplayBuff, sizeof(DisplayBuff));
671
    request_Display1 = FALSE;
672
  }
673
 
674
  if(request_DebugLabel != 0xFF) { // Texte für die Analogdaten
675
    uint8_t label[16]; // local sram buffer
676
    memcpy_P(label, ANALOG_LABEL[request_DebugLabel], 16); // read lable from flash to sram buffer
677
    SendOutData('A', FC_ADDRESS, 2, (uint8_t *) &request_DebugLabel, sizeof(request_DebugLabel), label, 16);
678
    request_DebugLabel = 0xFF;
679
  }
680
 
681
  if(ConfirmFrame && txd_complete) {   // Datensatz ohne CRC bestätigen
682
    SendOutData('B', FC_ADDRESS, 1, (uint8_t*)&ConfirmFrame, sizeof(ConfirmFrame));
683
    ConfirmFrame = 0;
684
  }
685
 
686
  if(((DebugData_Interval && CheckDelay(DebugData_Timer)) || request_DebugData) && txd_complete) {
687
    SendOutData('D', FC_ADDRESS, 1,(uint8_t *) &DebugOut, sizeof(DebugOut));
688
    DebugData_Timer = SetDelay(DebugData_Interval);
689
    request_DebugData = FALSE;
690
  }
691
 
692
  if( ((Data3D_Interval && CheckDelay(Data3D_Timer)) || request_Data3D) && txd_complete) {
693
    SendOutData('C', FC_ADDRESS, 1,(uint8_t *) &Data3D, sizeof(Data3D));
694
    Data3D.AngleNick = (int16_t)((10 * angle[PITCH]) / GYRO_DEG_FACTOR_PITCHROLL); // convert to multiple of 0.1°
695
    Data3D.AngleRoll = (int16_t)((10 * angle[ROLL]) / GYRO_DEG_FACTOR_PITCHROLL); // convert to multiple of 0.1°
696
    Data3D.Heading   = (int16_t)((10 * yawGyroHeading)   / GYRO_DEG_FACTOR_YAW); // convert to multiple of 0.1°
697
    Data3D_Timer = SetDelay(Data3D_Interval);
698
    request_Data3D = FALSE;
699
  }
700
 
701
  if(request_ExternalControl && txd_complete) {
702
    SendOutData('G', FC_ADDRESS, 1,(uint8_t *) &externalControl, sizeof(externalControl));
703
    request_ExternalControl = FALSE;
704
  }
705
 
706
#ifdef USE_MK3MAG
707
  if((CheckDelay(Compass_Timer)) && txd_complete) {
708
    ToMk3Mag.Attitude[0] = (int16_t)((10 * angle[PITCH]) / GYRO_DEG_FACTOR_PITCHROLL);  // approx. 0.1 deg
709
    ToMk3Mag.Attitude[1] = (int16_t)((10 * angle[ROLL]) / GYRO_DEG_FACTOR_PITCHROLL);  // approx. 0.1 deg
710
    ToMk3Mag.UserParam[0] = dynamicParams.UserParams[0];
711
    ToMk3Mag.UserParam[1] = dynamicParams.UserParams[1];
712
    ToMk3Mag.CalState = compassCalState;
713
    SendOutData('w', MK3MAG_ADDRESS, 1,(uint8_t *) &ToMk3Mag,sizeof(ToMk3Mag));
714
    // the last state is 5 and should be send only once to avoid multiple flash writing
715
    if(compassCalState > 4)  compassCalState = 0;
716
    Compass_Timer = SetDelay(99);
717
  }
718
#endif
719
 
720
  if(request_MotorTest && txd_complete) {
721
    SendOutData('T', FC_ADDRESS, 0);
722
    request_MotorTest = FALSE;
723
  }
724
 
725
  if(request_PPMChannels && txd_complete) {
726
    SendOutData('P', FC_ADDRESS, 1, (uint8_t *)&PPM_in, sizeof(PPM_in));
727
    request_PPMChannels = FALSE;
728
  }
729
 
730
  if (request_variables && txd_complete) {
731
    SendOutData('X', FC_ADDRESS, 1, (uint8_t *)&variables, sizeof(variables));
732
    request_variables = FALSE;
733
  }
734
}