Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
730 woggle 1
/*****************************************************************************
2
 *   Copyright (C) 2009 Peter "woggle" Mack, mac@denich.net                  *
3
 *   taken some ideas from the C-OSD code from CaScAdE                       *
4
 *   the MK communication routines are taken from the MK source              *
5
 *    (killagreg version)                                                    *
6
 *                                                                           *
7
 *   This program is free software; you can redistribute it and/or modify    *
8
 *   it under the terms of the GNU General Public License as published by    *
9
 *   the Free Software Foundation; either version 2 of the License.          *
10
 *                                                                           *
11
 *   This program is distributed in the hope that it will be useful,         *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
14
 *   GNU General Public License for more details.                            *
15
 *                                                                           *
16
 *   You should have received a copy of the GNU General Public License       *
17
 *   along with this program; if not, write to the                           *
18
 *   Free Software Foundation, Inc.,                                         *
19
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.               *
20
 *                                                                           *
21
 *****************************************************************************/
22
 
23
#include <avr/io.h>
24
#include <avr/interrupt.h>
25
#include <avr/pgmspace.h>
26
#include <avr/wdt.h>
27
#include <util/delay.h>
28
#include <stdarg.h>
29
 
30
#include "main.h"
31
#include "usart.h"
32
#include "lcd.h"
33
 
34
uint8_t buffer[30];
35
 
36
volatile uint8_t txd_buffer[TXD_BUFFER_LEN];
37
volatile uint8_t txd_complete = TRUE;
38
volatile uint8_t rxd_buffer[RXD_BUFFER_LEN];
39
volatile uint8_t rxd_buffer_locked = FALSE;
40
volatile uint8_t ReceivedBytes = 0;
41
volatile uint8_t *pRxData = 0;
42
volatile uint8_t RxDataLen = 0;
43
 
44
volatile uint16_t stat_crc_error = 0;
45
volatile uint16_t stat_overflow_error = 0;
46
 
47
#ifdef DEBUG_UART
48
//*****************************************************************************
49
// USART1 transmitter ISR
50
ISR (USART1_TXC_vect)
51
{
52
        static uint16_t ptr_txd_buffer = 0;
53
        uint8_t tmp_tx;
54
 
55
        if(!txd_complete) // transmission not completed
56
        {
57
                ptr_txd_buffer++;                    // [0] was already sent
58
                tmp_tx = txd_buffer[ptr_txd_buffer];
59
                // if terminating character or end of txd buffer was reached
60
                if((tmp_tx == '\r') || (ptr_txd_buffer == TXD_BUFFER_LEN))
61
                {
62
                        ptr_txd_buffer = 0;             // reset txd pointer
63
                        txd_complete = TRUE;    // stop transmission
64
                }
65
                UDR1 = tmp_tx; // send current byte will trigger this ISR again
66
        }
67
        // transmission completed
68
        else ptr_txd_buffer = 0;
69
}
70
 
71
//*****************************************************************************
72
// 
73
void USART1_Init (void)
74
{
75
        // set clock divider
76
#undef BAUD
77
#define BAUD USART_BAUD
78
#include <util/setbaud.h>
79
        UBRR1H = UBRRH_VALUE;
80
        UBRR1L = UBRRL_VALUE;
81
 
82
#if USE_2X
83
        UCSR1A |= (1 << U2X1);  // enable double speed operation
84
#else
85
        UCSR1A &= ~(1 << U2X1); // disable double speed operation
86
#endif
87
 
88
        // set 8N1
89
        UCSR1C = (1 << UCSZ11) | (1 << UCSZ10);
90
        UCSR1B &= ~(1 << UCSZ12);
91
 
92
        // flush receive buffer
93
        while ( UCSR1A & (1 << RXC1) ) UDR1;
94
 
95
        //      UCSR1B |= (1 << RXEN1) | (1 << TXEN1);
96
        //      UCSR1B |= (1 << RXCIE1) | (1 << TXCIE1);
97
        UCSR1B |= (1 << RXEN1) | (1 << TXEN1);
98
        UCSR1B |= (1 << TXCIE1);
99
}
100
 
101
void debug ()
102
{
103
        sprintf (txd_buffer, "test\r");
104
        txd_complete = FALSE;
105
        UDR1 = txd_buffer[0];
106
}
107
#endif
108
 
109
#ifdef USART_INT
110
//*****************************************************************************
111
// USART0 transmitter ISR
112
ISR (USART_TXC_vect)
113
{
114
        static uint16_t ptr_txd_buffer = 0;
115
        uint8_t tmp_tx;
116
 
117
        if(!txd_complete) // transmission not completed
118
        {
119
                ptr_txd_buffer++;                    // [0] was already sent
120
                tmp_tx = txd_buffer[ptr_txd_buffer];
121
                // if terminating character or end of txd buffer was reached
122
                if((tmp_tx == '\r') || (ptr_txd_buffer == TXD_BUFFER_LEN))
123
                {
124
                        ptr_txd_buffer = 0;             // reset txd pointer
125
                        txd_complete = TRUE;    // stop transmission
126
                }
127
                UDR = tmp_tx; // send current byte will trigger this ISR again
128
        }
129
        // transmission completed
130
        else ptr_txd_buffer = 0;
131
}
132
#endif
133
 
134
//*****************************************************************************
135
// 
136
ISR (USART_RXC_vect)
137
{
138
        static uint16_t crc;
139
        static uint8_t ptr_rxd_buffer = 0;
140
        uint8_t crc1, crc2;
141
        uint8_t c;
142
 
143
        c = UDR;  // catch the received byte
144
 
145
        if (rxd_buffer_locked)
146
        {
147
                return; // if rxd buffer is locked immediately return
148
        }
149
 
150
        // the rxd buffer is unlocked
151
        if ((ptr_rxd_buffer == 0) && (c == '#')) // if rxd buffer is empty and syncronisation character is received
152
        {
153
                LED6_OFF;
154
                rxd_buffer[ptr_rxd_buffer++] = c; // copy 1st byte to buffer
155
                crc = c; // init crc
156
        }
157
        else if (ptr_rxd_buffer < RXD_BUFFER_LEN) // collect incomming bytes
158
        {
159
                if(c != '\r') // no termination character
160
                {
161
                        rxd_buffer[ptr_rxd_buffer++] = c; // copy byte to rxd buffer
162
                        crc += c; // update crc
163
                }
164
                else // termination character was received
165
                {
166
                        // the last 2 bytes are no subject for checksum calculation
167
                        // they are the checksum itself
168
                        crc -= rxd_buffer[ptr_rxd_buffer-2];
169
                        crc -= rxd_buffer[ptr_rxd_buffer-1];
170
                        // calculate checksum from transmitted data
171
                        crc %= 4096;
172
                        crc1 = '=' + crc / 64;
173
                        crc2 = '=' + crc % 64;
174
                        // compare checksum to transmitted checksum bytes
175
                        if((crc1 == rxd_buffer[ptr_rxd_buffer-2]) && (crc2 == rxd_buffer[ptr_rxd_buffer-1]))
176
                        {   // checksum valid
177
                                rxd_buffer[ptr_rxd_buffer] = '\r'; // set termination character
178
                                ReceivedBytes = ptr_rxd_buffer + 1;// store number of received bytes
179
                                if (mode == rxd_buffer[2])
180
                                {
181
                                        rxd_buffer_locked = TRUE;          // lock the rxd buffer
182
                                        LED6_ON;
183
                                        // if 2nd byte is an 'R' enable watchdog that will result in an reset
184
                                        if(rxd_buffer[2] == 'R') {wdt_enable(WDTO_250MS);} // Reset-Commando
185
                                }
186
                        }
187
                        else
188
                        {       // checksum invalid
189
                                stat_crc_error++;
190
                                rxd_buffer_locked = FALSE; // unlock rxd buffer
191
                                //LED5_TOGGLE;
192
                                //lcd_putc(0, 6, rxd_buffer[2], 0);
193
                        }
194
                        ptr_rxd_buffer = 0; // reset rxd buffer pointer
195
                }
196
        }
197
        else // rxd buffer overrun
198
        {
199
                //LED4_TOGGLE;
200
                stat_overflow_error++;
201
                ptr_rxd_buffer = 0; // reset rxd buffer
202
                rxd_buffer_locked = FALSE; // unlock rxd buffer
203
        }
204
}
205
 
206
//*****************************************************************************
207
// 
208
void USART_Init (void)
209
{
210
        // set clock divider
211
        #undef BAUD
212
        #define BAUD USART_BAUD
213
        #include <util/setbaud.h>
214
        UBRRH = UBRRH_VALUE;
215
        UBRRL = UBRRL_VALUE;
216
 
217
#if USE_2X
218
        UCSRA |= (1 << U2X);    // enable double speed operation
219
#else
220
        UCSRA &= ~(1 << U2X);   // disable double speed operation
221
#endif
222
 
223
        // set 8N1
224
#if defined (__AVR_ATmega8__) || defined (__AVR_ATmega32__)
225
        UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);
226
#else
227
        UCSRC = (1 << UCSZ1) | (1 << UCSZ0);
228
#endif
229
        UCSRB &= ~(1 << UCSZ2);
230
 
231
        // flush receive buffer
232
        while ( UCSRA & (1 << RXC) ) UDR;
233
 
234
        UCSRB |= (1 << RXEN) | (1 << TXEN);
235
#ifdef USART_INT
236
        UCSRB |= (1 << RXCIE) | (1 << TXCIE);
237
#else
238
        UCSRB |= (1 << RXCIE);
239
#endif
240
}
241
 
242
//*****************************************************************************
243
// disable the txd pin of usart
244
void USART_DisableTXD (void)
245
{
246
#ifdef USART_INT
247
        UCSRB &= ~(1 << TXCIE);         // disable TX-Interrupt
248
#endif
249
        UCSRB &= ~(1 << TXEN);          // disable TX in USART
250
        DDRB  &= ~(1 << DDB3);          // set TXD pin as input
251
        PORTB &= ~(1 << PORTB3);        // disable pullup on TXD pin
252
}
253
 
254
//*****************************************************************************
255
// enable the txd pin of usart
256
void USART_EnableTXD (void)
257
{
258
        DDRB  |=  (1 << DDB3);          // set TXD pin as output
259
        PORTB &= ~(1 << PORTB3);        // disable pullup on TXD pin
260
        UCSRB |=  (1 << TXEN);          // enable TX in USART
261
#ifdef USART_INT
262
        UCSRB |=  (1 << TXCIE);         // enable TX-Interrupt
263
#endif
264
}
265
 
266
//*****************************************************************************
267
// short script to directly send a request thorugh usart including en- and disabling it
268
// where <address> is the address of the receipient, <label> is which data set to request
269
// and <ms> represents the milliseconds delay between data
270
void USART_request_mk_data (uint8_t cmd, uint8_t addr, uint8_t ms)
271
{
272
        USART_EnableTXD ();     // re-enable TXD pin
273
 
274
        unsigned char mstenth = ms/10;
275
        SendOutData(cmd, addr, 1, &mstenth, 1);
276
        // wait until command transmitted
277
        while (txd_complete == FALSE);
278
 
279
        USART_DisableTXD ();    // disable TXD pin again
280
}
281
 
282
//*****************************************************************************
283
// 
284
void USART_putc (char c)
285
{
286
#ifdef USART_INT
287
#else
288
        loop_until_bit_is_set(UCSRA, UDRE);
289
        UDR = c;
290
#endif
291
}
292
 
293
//*****************************************************************************
294
// 
295
void USART_puts (char *s)
296
{
297
#ifdef USART_INT
298
#else
299
        while (*s)
300
        {
301
                USART_putc (*s);
302
                s++;
303
        }
304
#endif
305
}
306
 
307
//*****************************************************************************
308
// 
309
void USART_puts_p (const char *s)
310
{
311
#ifdef USART_INT
312
#else
313
        while (pgm_read_byte(s))
314
        {
315
                USART_putc (pgm_read_byte(s));
316
                s++;
317
        }
318
#endif
319
}
320
 
321
//*****************************************************************************
322
// 
323
void SendOutData(uint8_t cmd, uint8_t addr, uint8_t numofbuffers, ...) // uint8_t *pdata, uint8_t len, ...
324
{
325
        va_list ap;
326
        uint16_t pt = 0;
327
        uint8_t a,b,c;
328
        uint8_t ptr = 0;
329
        uint16_t tmpCRC = 0;
330
 
331
        uint8_t *pdata = 0;
332
        int len = 0;
333
 
334
        txd_buffer[pt++] = '#';                                 // Start character
335
        txd_buffer[pt++] = 'a' + addr;  // Address (a=0; b=1,...)
336
        txd_buffer[pt++] = cmd;                                 // Command
337
 
338
        va_start(ap, numofbuffers);
339
        if(numofbuffers)
340
        {
341
                pdata = va_arg (ap, uint8_t*);
342
                len = va_arg (ap, int);
343
                ptr = 0;
344
                numofbuffers--;
345
        }
346
 
347
        while(len)
348
        {
349
                if(len)
350
                {
351
                        a = pdata[ptr++];
352
                        len--;
353
                        if((!len) && numofbuffers)
354
                        {
355
                                pdata = va_arg(ap, uint8_t*);
356
                                len = va_arg(ap, int);
357
                                ptr = 0;
358
                                numofbuffers--;
359
                        }
360
                }
361
                else a = 0;
362
                if(len)
363
                {
364
                        b = pdata[ptr++];
365
                        len--;
366
                        if((!len) && numofbuffers)
367
                        {
368
                                pdata = va_arg(ap, uint8_t*);
369
                                len = va_arg(ap, int);
370
                                ptr = 0;
371
                                numofbuffers--;
372
                        }
373
                }
374
                else b = 0;
375
                if(len)
376
                {
377
                        c = pdata[ptr++];
378
                        len--;
379
                        if((!len) && numofbuffers)
380
                        {
381
                                pdata = va_arg(ap, uint8_t*);
382
                                len = va_arg(ap, int);
383
                                ptr = 0;
384
                                numofbuffers--;
385
                        }
386
                }
387
                else c = 0;
388
                txd_buffer[pt++] = '=' + (a >> 2);
389
                txd_buffer[pt++] = '=' + (((a & 0x03) << 4) | ((b & 0xf0) >> 4));
390
                txd_buffer[pt++] = '=' + (((b & 0x0f) << 2) | ((c & 0xc0) >> 6));
391
                txd_buffer[pt++] = '=' + ( c & 0x3f);
392
        }
393
        va_end(ap);
394
 
395
        for(a = 0; a < pt; a++)
396
        {
397
                tmpCRC += txd_buffer[a];
398
        }
399
        tmpCRC %= 4096;
400
        txd_buffer[pt++] = '=' + tmpCRC / 64;
401
        txd_buffer[pt++] = '=' + tmpCRC % 64;
402
        txd_buffer[pt++] = '\r';
403
 
404
        txd_complete = FALSE;
405
#ifdef USART_INT
406
        UDR = txd_buffer[0]; // initiates the transmittion (continued in the TXD ISR)
407
#else
408
        for(a = 0; a < pt; a++)
409
        {
410
                loop_until_bit_is_set(UCSRA, UDRE);
411
                UDR = txd_buffer[a];
412
        }
413
        txd_complete = TRUE;
414
#endif
415
}
416
 
417
//*****************************************************************************
418
// 
419
void Decode64 (void)
420
{
421
        uint8_t a,b,c,d;
422
        uint8_t ptrIn = 3;
423
        uint8_t ptrOut = 3;
424
        uint8_t len = ReceivedBytes - 6;
425
 
426
        while (len)
427
        {
428
                a = rxd_buffer[ptrIn++] - '=';
429
                b = rxd_buffer[ptrIn++] - '=';
430
                c = rxd_buffer[ptrIn++] - '=';
431
                d = rxd_buffer[ptrIn++] - '=';
432
                //if(ptrIn > ReceivedBytes - 3) break;
433
 
434
                if (len--)
435
                        rxd_buffer[ptrOut++] = (a << 2) | (b >> 4);
436
                else
437
                        break;
438
                if (len--)
439
                        rxd_buffer[ptrOut++] = ((b & 0x0f) << 4) | (c >> 2);
440
                else
441
                        break;
442
                if (len--)
443
                        rxd_buffer[ptrOut++] = ((c & 0x03) << 6) | d;
444
                else
445
                        break;
446
        }
447
        pRxData = &rxd_buffer[3];
448
        RxDataLen = ptrOut - 3;
449
}
450
 
451
 
452
//*****************************************************************************
453
// 
454
void SwitchToNC (void)
455
{
456
        // switch to NC
457
        USART_putc (0x1b);
458
        USART_putc (0x1b);
459
        USART_putc (0x55);
460
        USART_putc (0xaa);
461
        USART_putc (0x00);
462
 
463
        current_hardware = NC;
464
        _delay_ms (50);
465
}
466
 
467
//*****************************************************************************
468
// 
469
void SwitchToFC (void)
470
{
471
        uint8_t cmd;
472
 
473
        if (current_hardware == NC)
474
        {
475
                // switch to FC
476
                cmd = 0x00;     // 0 = FC, 1 = MK3MAG, 2 = MKGPS
477
                SendOutData('u', ADDRESS_NC, 1, &cmd, 1);
478
 
479
                current_hardware = FC;
480
                _delay_ms (50);
481
        }
482
}
483
 
484
//*****************************************************************************
485
// 
486
void SwitchToMAG (void)
487
{
488
        uint8_t cmd;
489
 
490
        if (current_hardware == NC)
491
        {
492
                // switch to MK3MAG
493
                cmd = 0x01;     // 0 = FC, 1 = MK3MAG, 2 = MKGPS
494
                SendOutData('u', ADDRESS_NC, 1, &cmd, 1);
495
 
496
                current_hardware = MK3MAG;
497
                _delay_ms (50);
498
        }
499
}
500
 
501
//*****************************************************************************
502
// 
503
void SwitchToGPS (void)
504
{
505
        uint8_t cmd;
506
        if (current_hardware == NC)
507
        {
508
                // switch to MKGPS
509
                cmd = 0x02;     // 0 = FC, 1 = MK3MAG, 2 = MKGPS
510
                SendOutData('u', ADDRESS_NC, 1, &cmd, 1);
511
 
512
                current_hardware = MKGPS;
513
                _delay_ms (50);
514
        }
515
}