Rev Author Line No. Line
1213 mija 1 /* mija 2008
2 demo for LCD NOKIA5110 and MCP9800 and GPS modul
3  
4 CPU ATMEGA644P
5 fcpu = 1MHz
6  
7 !! define PIN,PORT,DDR for IOpin !!
8 */
9  
10  
11 //************************************************************************
12 // defines
13  
1220 mija 14 #define MY_LAT 48*60+57.7647
15 #define MY_LON 14*60+28.0836
16  
1213 mija 17 #define KEY_TIME_DEAD 5 //cca 50ms 8*5
18 //#define KEY_TIME_START_REPEAT 100 //cca 1s
19 //#define KEY_TIME_REPEAT 20 //cca 240ms
20 #define KEY_TIME_FIRST 50
21  
22 #define TEMP_TIME_REPEAT 100
23  
24 #define OFF_TIME 200
1220 mija 25 #define TIME_KEY_LONG 200
1213 mija 26  
27 #define REFRESH_TIME 100
28  
29 #define STATUS_REFRESH_TIME 100
30  
31 #define CLOCK1S 100
32 #define CLOCK2S 200
33 #define CLOCK5S 255;
34 #define CLOCK50MS 5
35  
36 #define DEBUG
37  
38 //************************************************************************
39 //including
40  
41 #include <avr/io.h>
42 #include <stdlib.h>
43 #include <avr/pgmspace.h>
44 #include <avr/interrupt.h>
45 #include <avr/sleep.h>
46 #include <util/delay.h>
47 #include <stdio.h>
48 #include <math.h>
49 //#include "ascii_table.h"
50 #include "lcd.h" //define PINs LCD
51 #include "GPS.h" //define PINs GPS,TL,LED,REF,I2C
52 #include "nmea_scan.h"
53  
54 //************************************************************************
55 // pomocne
1217 mija 56  
1213 mija 57 #define WIDTH_CHAR_SIGNALL 8
58 prog_uint8_t CHAR_SIGNALL[WIDTH_CHAR_SIGNALL]={127,12,30,51,51,30,12,127};
59  
60 #define WIDTH_CHAR_SIGNALL_D 8
61 prog_uint8_t CHAR_SIGNALL_D[WIDTH_CHAR_SIGNALL_D]={127,12,30,63,63,30,12,127};
62  
63 #define WIDTH_CHAR_SIGNALL_2D 7
64 prog_uint8_t CHAR_SIGNALL_2D[WIDTH_CHAR_SIGNALL_2D]={1,2,4,127,4,2,1};
65  
66 #define WIDTH_CHAR_SIGNALL_3D 7
67 prog_uint8_t CHAR_SIGNALL_3D[WIDTH_CHAR_SIGNALL_3D]={124,68,71,69,125,17,31};
68  
69 #define WIDTH_CHAR_LIGHT 5
70 prog_uint8_t CHAR_LIGHT[WIDTH_CHAR_LIGHT]={127,65,95,95,127};
71  
72  
1217 mija 73 #define BOOT() (((void(*)(void))(char *)0x7C00)())
74 #define RESET() (((void(*)(void))(char *)0x0000)())
1213 mija 75 //***********************************************************************
76 // global variables
1217 mija 77  
1213 mija 78 extern uint8_t video_buf[504];
79 extern uint8_t *offset_text;
80  
81 uint8_t id_mod;
82 char scan_buf[MAX_NMEA_LOAD];
83 POINT_T now,max,min;
84 DATA_GPS gps;
85 DATA_GPS *pgps;
86  
87 enum {ID_TIME,ID_LOCATION,ID_COURSE,ID_ALL_POSITION,ID_ALL_SERVICE,ID_SERVICE,ID_TEMP,ID_SATELITES,ID_NORTH,ID_NAV};
88  
1217 mija 89 static FILE mystdout = FDEV_SETUP_STREAM(lcd_put, NULL,_FDEV_SETUP_WRITE); // in lcd.h
90 static FILE mystdout2 = FDEV_SETUP_STREAM(lcd_put2, NULL,_FDEV_SETUP_WRITE); // in lcd.h
1213 mija 91  
1217 mija 92 //************************************************************************
93 // prototypes
1213 mija 94  
1217 mija 95 //(*bootloader)(void) = 0x7C00;
96 void delay_ms(uint16_t time);
97 void null_variables(void);
98  
1213 mija 99 //************************************************************************
100 // general cpu init
101  
102 void general_cpu_init(void)
103 {
104 //*** IO_PIN ***
105 TL1_INIT;
106 TL1_PULLUP;
107 TL2_INIT;
108 TL2_PULLUP;
109 TL3_INIT;
110 TL3_PULLUP;
111  
1217 mija 112 USB_INIT;
113 //USB_PULLUP;
1213 mija 114  
115 GPS_INIT;
116 GPS_OFF;
117  
118 REF_INIT;
119 REF_OFF;
120  
121 nSCLK_INIT;
122 nSDIN_INIT;
123 nDC_INIT;
124 nCS_INIT;
125 nRESET_INIT;
126  
127 SCL_INIT;
128 SDA_FLOAT;
129  
130 LED_INIT;
131 LED_OFF;
132  
133 //*** EXTERNAL PIN INTERRUPTS
1217 mija 134 //EICRA = _BV(ISC21); //pin INT2 - TL2
135 //EIMSK = _BV(INT2); //pin INT2 - TL2
136  
1213 mija 137  
1217 mija 138 //*** PIN CHANGE INTERRUPTS PCINT29
139 PCICR = _BV(PCIE1);
140 PCMSK1 = _BV(PCINT10) | _BV(PCINT11) |_BV(PCINT12); //pin change TL1,TL2,TL3
141  
142 PCICR |= _BV(PCIE3);
143 PCMSK3 = _BV(PCINT29); // pin USB
144  
145 //*** TIMER1 *** tik for TL fosc/64 /1024(TCNT1) cca 8ms
1213 mija 146 TCNT1 = 0;
147 OCR1A = 1024;
148 TCCR1A = _BV(WGM11) | _BV(WGM10);
1217 mija 149 TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11) | _BV(CS10) ; // TIMER1 fast PWM
1213 mija 150 TIMSK1 = _BV(TOIE1);
151  
152 //*** TIMER2 *** RTC
153 ASSR = _BV(AS2);
154 TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20);
155 TIMSK2 = _BV(TOIE2);
156  
157 //*** SLEEP ***
158 SMCR = _BV(SM1) | _BV(SM0) | _BV(SE);
159  
160 //*** WDT ***
161 //WDTCSR = _BV(WDCE) | _BV(WDE);
162 //WDTCSR = _BV(WDIE) | _BV(WDP3) | _BV(WDP0);
163  
164 //*** USART0 *** RX PD0, TX PD1, GPS
1217 mija 165 UBRR0 = 95;
1213 mija 166 //UCSR0A =
167 UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0);
168  
169 //*** USART1 *** RX PD2, TX PD3 PC
1217 mija 170 #ifndef DEBUG
171 UBRR1 = 95;
172 #else
173 UBRR1 = 3;
174 #endif
1213 mija 175 //UCSR0A =
176 UCSR1B = _BV(RXCIE1) | _BV(RXEN0) | _BV(TXEN1);
177  
178 //*** ADC ***
179 ADMUX = _BV(REFS1) | _BV(MUX0);
1217 mija 180 ADCSRA = _BV(ADPS1) | _BV(ADPS2);
1213 mija 181  
182 }
183  
184 //************************************************************************
185 // interrupts + RTC / clock 8s ... TIMER2 /
186  
187 volatile uint8_t RTC_flag;
188 volatile uint8_t sRTC,mRTC,hRTC,dRTC,mdRTC,yRTC;
189  
190 uint8_t modulo(uint8_t h,uint8_t m) //pomocna fce pro modulo x
191 {
192 if (h<m) return (h);
193 return(h-m);
194 }
195  
196 void set_date(void) //citac datumu
197 {
198 dRTC++;
199 switch (mdRTC)
200 {
201 case 1:
202 case 3:
203 case 5:
204 case 7:
205 case 8:
206 case 10:
207 case 12: if(dRTC>=32) {dRTC=1;mdRTC++;if(mdRTC==13) {mdRTC =1;yRTC=modulo(yRTC++,100);}} break;
208 case 4:
209 case 6:
210 case 9:
211 case 11: if(dRTC>=31) {dRTC=1;mdRTC++;} break;
212 case 2: if (dRTC >= 30) {dRTC=1;mdRTC++;break;}
213 if (dRTC ==29) {if (!(yRTC & 0x03)) break;dRTC=1;mdRTC++;}
214 }
215 }
216  
217  
218 volatile uint8_t timer1_ovf;
219  
220 ISR(TIMER1_OVF_vect)
221 {
222 timer1_ovf ++;
223 }
224  
225  
226 ISR(TIMER2_OVF_vect)
227 {
228 sRTC += 8;
229 if (sRTC >= 60)
230 {
231 sRTC=modulo(sRTC,60); //1min
232 if (++mRTC>=60)
233 {
234 mRTC=0; //1hod
235 if (++hRTC>=24)
236 {
237 hRTC=0;
238 set_date(); //1den
239 }
240 }
241 }
242 }
243  
244 char rx_buf[MAX_RX_BUF];
245 volatile uint8_t rx_shift;
246  
247 ISR(USART0_RX_vect)
248 {
249 if (++rx_shift >= MAX_RX_BUF) rx_shift =0;
250 rx_buf[rx_shift]=UDR0;
251 UDR1 = UDR0;
252 }
253  
1217 mija 254 uint8_t first_char_usart1 = 0;
255  
1213 mija 256 ISR(USART1_RX_vect)
257 {
1217 mija 258 #ifndef DEBUG
1213 mija 259 UDR0 = UDR1;
1217 mija 260 #else
261 if (TL1_INPUT && TL3_INPUT) BOOT();
262 //bootloader();
263 #endif
1213 mija 264 }
265  
1217 mija 266 ISR(PCINT1_vect)
267 {
268 if ((!TL3_INPUT) && (!TL1_INPUT)) RESET();
269 }
270  
271 ISR(PCINT3_vect)
272 {
273 if (!TL2_INPUT && USB_INPUT)
274 {
275 cli();
276 buffer_clr();
277 gotoxy(2,3);
1220 mija 278 fprintf(&mystdout2,"update");
279 gotoxy(2,5);
280 fprintf(&mystdout2,"firmware");
1217 mija 281 lcd_refresh();
282 delay_ms(1000);
283 BOOT();
284 }
285  
286 }
287  
1213 mija 288 EMPTY_INTERRUPT(INT0_vect)
289 EMPTY_INTERRUPT(INT2_vect)
290 EMPTY_INTERRUPT(WDT_vect)
291  
292 //************************************************************************
293 // delay_ms functions /define fcpu /
294  
295 void delay_ms(uint16_t time)
296 {
297 while(time--) _delay_ms(1);
298 }
299 //************************************************************************
300 // static navigation
301  
302 void gps_put(char c)
303 {
304 while ( !( UCSR0A & _BV(UDRE0)) );
305 UDR0 = c;
306 }
307  
308 //************************************************************************
309 // key + timer1_ovf
310  
311  
312 volatile uint8_t key_press;
313 volatile uint8_t key_flag;
314 volatile uint8_t timer_key;
315 volatile uint8_t timer_temp;
316 volatile uint8_t timer_off;
317 volatile uint8_t timer_refresh;
318 volatile uint8_t timer_status;
1220 mija 319 volatile uint8_t timer_key_long;
1213 mija 320  
321 void timer1_tik(void)
322 {
323 uint8_t key_temp;
324  
1217 mija 325 while (timer1_ovf)
1213 mija 326 {
1217 mija 327 timer1_ovf--;
1213 mija 328 if (timer_status) timer_status--;
329 if (timer_refresh) timer_refresh--;
330 if (timer_off) timer_off--;
1220 mija 331 if (timer_key_long) timer_key_long--;
1213 mija 332 if (timer_temp) timer_temp--;
333 if (timer_key) timer_key--;
334 else
335 {
1217 mija 336 key_temp = 0;
337 if (!TL1_INPUT) key_temp = _BV(KEY1);
338 if (!TL2_INPUT) key_temp |= _BV(KEY2);
339 if (!TL3_INPUT) key_temp |= _BV(KEY3);
1220 mija 340 //if (key_temp != key_press)
1213 mija 341 {
1220 mija 342 if (key_temp != key_press)
343 {
344 timer_off= OFF_TIME;
345 timer_key_long=TIME_KEY_LONG;
346 }
1213 mija 347 timer_key = KEY_TIME_DEAD;
348 key_press = key_temp;
349 if (!key_flag) key_flag = key_press;
1220 mija 350  
1213 mija 351 }
352 }
353 }
354 }
355  
356 uint8_t key_read(void)
357 {
358 uint8_t key_send;
359  
360 key_send = key_flag;
361 key_flag = 0;
362 return key_send;
363 }
364  
365 //************************************************************************
366 // SW I2C /define SDA, SCL; tested for fosc 1Mhz/
367  
368 void I2C_start(void)
369 {
370 SDA_OUT;
371 SDA_L;
372 SCL_L;
373 }
374  
375 void I2C_stop(void)
376 {
377 SCL_H;
378 SDA_OUT;
379 SDA_H;
380 SDA_FLOAT;
381 }
382  
383 void I2C_write(uint8_t data)
384 {
385 uint8_t a;
386  
387 SDA_OUT;
388 for(a=0;a<8;a++)
389 {
390 SCL_L;
391 if (data & 0x80) SDA_H;
392 else SDA_L;
393 SCL_H;
394 data <<= 1;
395 }
396 SCL_L;
397 SDA_FLOAT;
398 SCL_H;
399 SCL_L;
400 }
401  
402 uint8_t I2C_read(uint8_t ack)
403 {
404 uint8_t a;
405 uint8_t data;
406  
407 SDA_IN;
408 data=0;
409 for(a=0;a<8;a++)
410 {
411 SCL_H;
412 if (SDA_INPUT) data |=1;
413 SCL_L;
414 if (a != 7)data <<= 1;
415 }
416  
417 if (ack) {SDA_OUT;SDA_L;}
418 else SDA_FLOAT;
419 SCL_H;
420 SCL_L;
421 SDA_FLOAT;
422 return data;
423 }
424  
425 //************************************************************************
426 // temperature sensor MCP9800 of MICROCHIP
427  
428 void start_MCP9800(void)
429 {
430 I2C_start();
431 I2C_write(0x90);
432 I2C_write(0x1); // configuration pointer MCP9800
433 //I2C_write(0xE1); // 12bit + only 1 convert and then sleep
434 I2C_write(0x81); // 9bit + only 1 convert and then sleep
435 I2C_stop();
436 I2C_start();
437 I2C_write(0x90);
438 I2C_write(0x0); // temperature pointer
439 I2C_stop();
440 }
441  
442 uint16_t read_temp(void)
443 {
444 uint16_t temp;
445  
446 I2C_start();
447 I2C_write(0x91);
448 temp = I2C_read(1) << 8;
449 temp |= I2C_read(0);
450 I2C_stop();
451 return temp;
452 }
453  
454 //************************************************************************
455 // templota
456  
457 void print_temp(int16_t teplota)
458 {
459 printf("%d.%01dC",((teplota>>8) & 0x807F) | (teplota & 0x8000),5*((teplota>>7)& 0x1));
460 }
461  
462 void print_time(TIME_T time)
463 {
464 uint8_t temp;
465  
466 temp = time.hour/10;
467 if (temp == 0) lcd_put(' ',0);
468 else lcd_put(temp + 0x30,0);
469 lcd_put(time.hour%10 + 0x30,0);
470 //put_lcd(':');
471 *(offset_text++) = 0x36;
472 offset_text++;
473 lcd_put(time.min/10 + 0x30,0);
474 lcd_put(time.min%10 + 0x30,0);
475 //put_lcd(':');
476 //put_lcd(sRTC/10 + 0x30);
477 //put_lcd(sRTC%10 + 0x30);
478 }
479  
480 void print_date(DATE_T date)
481 {
482 uint8_t temp;
483  
484 temp = date.day/10;
485 if (temp == 0) lcd_put(' ',0);
486 else lcd_put(temp + 0x30,0);
487 lcd_put(date.day%10 + 0x30,0);
488 //put_lcd('/');
489 *(offset_text++) = 0x60;
490 offset_text++;
491 temp = date.mon/10;
492 if (temp != 0) lcd_put(temp + 0x30,0);
493 lcd_put(date.mon%10 + 0x30,0);
494 if (temp == 0)
495 {
496 *(offset_text++) = 0x60;
497 offset_text++;
498 }
499 //put_lcd('/');
500 //put_lcd(yRTC/10 + 0x30);
501 //put_lcd(yRTC%10 + 0x30);
502 }
503  
504 TIME_T actual_time(void)
505 {
506 TIME_T time;
507  
508 time.sec=sRTC;
509 time.min=mRTC;
510 time.hour=hRTC;
511 return time;
512 }
513  
514 DATE_T actual_date(void)
515 {
516 DATE_T date;
517  
518 date.day=dRTC;
519 date.mon=mdRTC;
520 date.year=yRTC;
521 return date;
522 }
523  
524 //*********************************************************************
1220 mija 525 // key
526  
527 uint8_t test_key(void)
528 {
529 static uint8_t key_next = 0;
530  
531 if (key_press)
532 {
533 if (key_next)
534 {
535 key_read();
536 return 0;
537 }
538  
539 if(!timer_key_long)
540 {
541 key_next = 1;
542 timer_key = KEY_TIME_FIRST;
543 switch(key_read())
544 {
545 case _BV(KEY1): return KEY1_LONG;
546 case _BV(KEY2): return KEY2_LONG;
547 case _BV(KEY3): return KEY3_LONG;
548 }
549 }
550 return 0;
551 }
552 key_next=0;
553 switch(key_read())
554 {
555 case _BV(KEY1): return KEY1_SHORT;
556 case _BV(KEY2): return KEY2_SHORT;
557 case _BV(KEY3): return KEY3_SHORT;
558 }
559 return 0;
560 }
561  
562 //*********************************************************************
1213 mija 563 //status
564  
565 void status(void)
566 {
567 uint8_t a,b;
568 uint8_t *ptr;
569  
570 start_MCP9800();
571 REF_ON;
572 ADC_ON;
573 ADCSRA |= _BV(ADSC);
574 while (!(ADCSRA & _BV(ADIF)));
575  
576 gotoxy(1,1);
577 printf("%0.1fV %2d",1024.0*25/ADC/10,read_temp()>>8);
578 offset_text = video_buf + LCD_WIDTH - WIDTH_CHAR_LIGHT - 2*CHAR_WIDTH - WIDTH_CHAR_SIGNALL_3D - WIDTH_CHAR_SIGNALL - 2;
579 if (gps.fix_position)
580 {
1217 mija 581  
582 ptr= CHAR_SIGNALL_3D;b=WIDTH_CHAR_SIGNALL_3D;//offset_text++;
583 if (gps.mode2 == '3')
584 for (a=0;a<b;a++) *(offset_text++) =pgm_read_byte(ptr++);
585  
586 offset_text = video_buf + LCD_WIDTH - WIDTH_CHAR_LIGHT - 2*CHAR_WIDTH - WIDTH_CHAR_SIGNALL_3D - 2;
1213 mija 587 switch (gps.fix_position)
588 {
589 case 1: ptr= CHAR_SIGNALL;b=WIDTH_CHAR_SIGNALL;break;
590 case 2: ptr= CHAR_SIGNALL_D;b=WIDTH_CHAR_SIGNALL_D;break;
591 case 0:
592 default:ptr= CHAR_SIGNALL;b=0;
593 }
594 for (a=0;a<b;a++) *(offset_text++) =pgm_read_byte(ptr++);
595  
1217 mija 596  
1213 mija 597 }
598 offset_text = video_buf + LCD_WIDTH - WIDTH_CHAR_LIGHT-2*CHAR_WIDTH;
599 printf("%d",gps.satelites_used);
600 if (LED_INPUT)
601 {
602 ptr= CHAR_LIGHT;b=WIDTH_CHAR_LIGHT;
603 offset_text = video_buf + LCD_WIDTH - WIDTH_CHAR_LIGHT;
604 for (a=0;a<b;a++) *(offset_text++) =pgm_read_byte(ptr++);
605 }
606  
607 }
608  
609 //************************************************************************
610 // mod
611  
612 void displ_time(void)
613 {
614 GPS_ON;
1220 mija 615  
616 switch(test_key())
617 {
618 case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
619 case KEY2_LONG: id_mod=ID_OFF;return;
620 case KEY3_LONG: return;
621 case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
622 case KEY2_SHORT:
623 case KEY3_SHORT:break;
624 }
625  
1213 mija 626 if (!timer_refresh)
627 {
628 timer_refresh = CLOCK1S;
629 buffer_clr();
630 status();
1217 mija 631 //gotoxy(1,2);
632 // printf("time & date");
1213 mija 633 gotoxy(1,3);
634 fprintf(&mystdout2," %2d:%02d:%02d",gps.hour+2,gps.minute,gps.second);
635 gotoxy(1,5);
636 fprintf(&mystdout2," %2d.%02d.20%02d",gps.day,gps.month,gps.year);
637 lcd_refresh();
638 }
639 }
640  
641 void displ_location(void)
642 {
1217 mija 643 uint8_t a,b;
644 uint8_t *ptr;
645  
1220 mija 646 switch(test_key())
647 {
648 case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
649 case KEY2_LONG: id_mod=ID_OFF;return;
650 case KEY3_LONG: return;
651 case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
652 case KEY2_SHORT:
653 case KEY3_SHORT:break;
654 }
655  
1213 mija 656 if (!timer_refresh)
657 {
658 timer_refresh = CLOCK1S;
659 buffer_clr();
660 status();
1217 mija 661  
662 gotoxy(8,2);
663 offset_text -=2;
664 ptr= CHAR_SIGNALL_3D;b=WIDTH_CHAR_SIGNALL_3D;//offset_text++;
665 for (a=0;a<b;a++) *(offset_text++) =pgm_read_byte(ptr++);
666  
667 //gotoxy(9,2);
668 printf("%4.0fm",gps.altitude);
669  
1213 mija 670 gotoxy(1,3);
671 //gps.latitude = 14.5;
672 fprintf(&mystdout2,"%c %3d%.4f'",gps.ns_indicator,(uint8_t)gps.latitude,(gps.latitude - 1.0*(uint8_t)gps.latitude)*60);
673 gotoxy(1,5);
674 //gps.longitude = 48.25;
675 fprintf(&mystdout2,"%c %3d%.4f'",gps.we_indicator,(uint8_t)gps.longitude,(gps.longitude - 1.0*(uint8_t)gps.longitude)*60);
676 lcd_refresh();
677 }
678 }
679  
680 void displ_speed(void)
681 {
1220 mija 682 switch(test_key())
683 {
684 case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
685 case KEY2_LONG: id_mod=ID_OFF;return;
686 case KEY3_LONG: return;
687 case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
688 case KEY2_SHORT:
689 case KEY3_SHORT:break;
690 }
691  
1213 mija 692 if (!timer_refresh)
693 {
694 timer_refresh = CLOCK1S;
695 buffer_clr();
696 status();
697 gotoxy(1,2);
698 printf("speed");
699 gotoxy(1,4);
700 fprintf(&mystdout2," %3.1f km/h",gps.speed);
701 lcd_refresh();
702 }
703 }
704  
705 void displ_course(void)
706 {
1220 mija 707 switch(test_key())
708 {
709 case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
710 case KEY2_LONG: id_mod=ID_OFF;return;
711 case KEY3_LONG: return;
712 case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
713 case KEY2_SHORT:
714 case KEY3_SHORT:break;
715 }
716  
1213 mija 717 if (!timer_refresh)
718 {
719 timer_refresh = CLOCK1S;
720 buffer_clr();
721 status();
722 //gotoxy(1,2);
723 //printf("course");
724 gotoxy(1,3);
725 fprintf(&mystdout2," %3.1f km/h",gps.speed);
726 gotoxy(6,5);
727 fprintf(&mystdout2,"%3.0f",gps.course);
728 lcd_refresh();
729 }
730 }
731  
732 void displ_satelites(void)
733 {
734 #define WIDTH_REC 60
735  
736 uint8_t a,x,y,b;
737 static uint8_t d = 0;
738 static uint8_t c = 0;
739 double elevace,azimut;
740  
1220 mija 741 switch(test_key())
742 {
743 case KEY1_LONG:if (LED_INPUT) LED_OFF;else LED_ON;break;
744 case KEY2_LONG: c=0;id_mod=ID_OFF;return;
745 case KEY3_LONG: c=0;return;
746 case KEY1_SHORT:c=0;timer_refresh = 0;++id_mod;return;
747 case KEY2_SHORT:c=0;d++;timer_refresh = 0;break;
748 case KEY3_SHORT: break;
749 }
750  
1213 mija 751 if (!timer_refresh)
752 {
753 timer_refresh = CLOCK1S;
754 if (c--) return;
1220 mija 755 c=5;
1213 mija 756 buffer_clr();
757 //status();
758 #ifdef DEBUG
759 if(gps.gsv_satelites_view > 12)
760 {
761 printf("error view satelites");
762 lcd_refresh();
1220 mija 763 c=5;
1213 mija 764 return;
765 }
766 #endif
1220 mija 767 if (d >= gps.gsv_satelites_view) d = 0;
1213 mija 768 gotoxy(12,1);
769 printf("%d",gps.gsv_satelites_view);
770 gotoxy(12,2);
771 printf("%d",gps.satelit_detail[d].id);
772 gotoxy(12,3);
773 printf("%d",gps.satelit_detail[d].azimut);
774 gotoxy(12,4);
775 printf("%d",gps.satelit_detail[d].elevation);
776 gotoxy(12,5);
777 printf("%d",gps.satelit_detail[d].SNR);
778 gotoxy(12,6);
779  
780 for (a=0;a<gps.gsv_satelites_view;a++)
781 {
782 azimut = (double)gps.satelit_detail[a].azimut;
783 elevace = (double)gps.satelit_detail[a].elevation;
784  
785 x=(uint8_t)((WIDTH_REC-4)/2.0/90.0*(90.0-elevace)*sin(M_PI/180*azimut) + WIDTH_REC/2.0);
786 y=(uint8_t)((LCD_HEIGHT-4)/2.0/90.0*(90.0-elevace)*cos(M_PI/180*azimut) + LCD_HEIGHT/2.0);
787 if (gps.satelit_detail[a].SNR)
788 {
789 lcd_plot(x-1,y);lcd_plot(x+1,y);lcd_plot(x,y-1);lcd_plot(x,y+1);
790 for (b=0;b<gps.satelites_used;b++)
791 if (gps.satelit_detail[a].id == gps.satelite_id[b])
792 lcd_plot(x,y);
793 }
794 else lcd_plot(x,y);
795  
796 if (d == a)
797 {
798 lcd_line(x-2,y-2,x-2,y+2);
799 lcd_line(x+2,y+2,x+2,y-2);
800 lcd_line(x+2,y+2,x-2,y+2);
801 lcd_line(x-2,y-2,x+2,y-2);
802 }
803 }
804  
805 lcd_line(0,0,WIDTH_REC,0);
806 lcd_line(0,LCD_HEIGHT-1,WIDTH_REC,LCD_HEIGHT-1);
807 lcd_line(0,0,0,LCD_HEIGHT-1);
808 lcd_line(WIDTH_REC,0,WIDTH_REC,LCD_HEIGHT-1);
809  
810 lcd_refresh();
811 }
812 }
813  
814 void displ_all_position()
815 {
1220 mija 816  
817 switch(test_key())
818 {
819 case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
820 case KEY2_LONG: id_mod=ID_OFF;return;
821 case KEY3_LONG: return;
822 case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
823 case KEY2_SHORT:
824 case KEY3_SHORT:break;
825 }
826  
1213 mija 827 if (!timer_refresh)
828 {
829 timer_refresh = CLOCK1S;
830 buffer_clr();
831 status();
832  
833 gotoxy(1,2);
834 printf("%c %3d%.4f'",gps.ns_indicator,(uint8_t)gps.latitude,(gps.latitude - 1.0*(uint8_t)gps.latitude)*60);
835 gotoxy(1,3);
836 printf("%c %3d%.4f'",gps.we_indicator,(uint8_t)gps.longitude,(gps.longitude - 1.0*(uint8_t)gps.longitude)*60);
837 gotoxy(1,4);
838 printf("alt%4.0fm V%2.1f",gps.altitude,gps.VDOP);
839 gotoxy(1,5);
1217 mija 840 printf("geo%4.1fm H%2.1f",gps.geoid,gps.HDOP);
1213 mija 841 gotoxy(1,6);
842 printf("%3.0fkm/h %3.0f",gps.speed,gps.course);
843 lcd_refresh();
844 }
845 }
846  
847 void displ_nav(void)
848 {
1217 mija 849  
1213 mija 850 double lon,lat,temp;
851 double course;
852 uint8_t x,y,xl,yl,xp,yp;
1217 mija 853 uint8_t a,b;
854 uint8_t *ptr;
1213 mija 855  
1220 mija 856 switch(test_key())
857 {
858 case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
859 case KEY2_LONG: id_mod=ID_OFF;return;
860 case KEY3_LONG: return;
861 case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
862 case KEY2_SHORT:
863 case KEY3_SHORT:break;
864 }
865  
1213 mija 866 if (!timer_refresh)
867 {
868 timer_refresh = CLOCK1S;
869 buffer_clr();
870 status();
871  
1220 mija 872 const float gc_lat= MY_LAT,gc_lon=MY_LON; // DOMA
1213 mija 873  
874 lon=(gc_lon-gps.longitude*60)*1214;
875 lat=(gc_lat-gps.latitude*60)*1854;
876 temp = sqrt((lon*lon) + (lat*lat));
877  
878 gotoxy(9,3);
1217 mija 879 offset_text -=2;
880 ptr= CHAR_SIGNALL_3D;b=WIDTH_CHAR_SIGNALL_3D;
881 for (a=0;a<b;a++) *(offset_text++) =pgm_read_byte(ptr++);
882 //offset_text++;
883  
884 //gotoxy(10,3);
885 printf("%4.0fm",gps.altitude);
886  
887 gotoxy(7,2);
888 printf("go home");
889  
890 gotoxy(9,4);
1213 mija 891 if (temp < 10000)
892 {
893 if (temp<1000) fprintf(&mystdout2,"%.1f ",temp);
894 else
895 {
896 fprintf(&mystdout2,"%.3f ",temp/1000);
1217 mija 897 gotoxy(12,6);
1213 mija 898 printf("k");
899 }
1217 mija 900 gotoxy(13,6);
1213 mija 901 printf("m");
902 }
903 else
904 {
905 temp=temp/1000;
906 if (temp < 1000)
907 {
908 if (temp < 100)
909 {
910 fprintf(&mystdout2,"%.2f ",temp);
911 }
912 else
913 {
914 fprintf(&mystdout2,"%.1f ",temp);
915 }
916 }
917 else fprintf(&mystdout2,"%5.0f ",temp);
1217 mija 918 gotoxy(12,6);
1213 mija 919 printf("km");
920 }
921  
922 if (lat==0) lat=0.001;
923 lon=M_PI/2.0-(atan2(lat,lon));
924 if (lon<0) lon+=2*M_PI;
925 if (lon>(2*M_PI)) lon-=2*M_PI;
926 //printf(lcd_putc,"BE%2.0g*",lon);
927 lat=M_PI/180*gps.course;
928 lon=lon-lat;
929 if (lon<0) lon+=2*M_PI;
930 if (lon>2*M_PI) lon-=2*M_PI;
931 //printf(lcd_putc,"HE%2.0g*AZ%2.0g* ",lon,lat);
932  
933 #define WIDTH_REC_NAV 43
934 #define LCD_HEIGHT_NAV 35
935  
936 course = lon;
937 x=(uint8_t)(WIDTH_REC_NAV/2.0*sin(course) +WIDTH_REC_NAV/2);
938 y=(uint8_t)((LCD_HEIGHT_NAV)/2.0*cos(course) +(LCD_HEIGHT_NAV)/2);
939  
940 xl=(uint8_t)(WIDTH_REC_NAV/2.0*sin((course-2.62))+WIDTH_REC_NAV/2 );
941 yl=(uint8_t)((LCD_HEIGHT_NAV)/2.0*cos((course-2.62))+(LCD_HEIGHT_NAV)/2 );
942  
943 xp=(uint8_t)(WIDTH_REC_NAV/2.0*sin((course+2.62))+WIDTH_REC_NAV/2 );
944 yp=(uint8_t)((LCD_HEIGHT_NAV)/2.0*cos((course+2.62)) +(LCD_HEIGHT_NAV)/2);
945  
946 //xs=(uint8_t)((WIDTH_REC_NORTH-26)/2.0*sin(M_PI/180*(course+180.0))+WIDTH_REC_NORTH/2 );
947 //ys=(uint8_t)(((LCD_HEIGHT_NORTH-20))/2.0*cos(M_PI/180*(course+180.0)) +(LCD_HEIGHT_NORTH)/2);
948  
949 lcd_line( x,y,xl,yl);
950 lcd_line( x,y,xp,yp);
951 //lcd_line( xp,yp,xl,yl);
952 lcd_line(xl,yl,WIDTH_REC_NAV/2,(LCD_HEIGHT_NAV)/2);
953 lcd_line(xp,yp,WIDTH_REC_NAV/2,(LCD_HEIGHT_NAV)/2);
954  
955 //lcd_line(xl,yl,xs,ys);
956 //lcd_line(xp,yp,xs,ys);
957 lcd_refresh();
958 }
959 }
960  
961 void displ_service(char *buf)
962 {
963 uint8_t a;
1220 mija 964  
965 switch(test_key())
966 {
967 case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
968 case KEY2_LONG: id_mod=ID_OFF;return;
969 case KEY3_LONG: return;
970 case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
971 case KEY2_SHORT:
972 case KEY3_SHORT:break;
973 }
974  
1213 mija 975 if (!timer_refresh)
976 {
977 timer_refresh = CLOCK1S;
978 buffer_clr();
979 for (a = 0; a<80; a++) putchar(*(buf++));
980 lcd_refresh();
981 }
982 }
983  
984 void displ_north(void)
985 {
1217 mija 986 uint8_t a,b;
987 uint8_t *ptr;
1213 mija 988 uint8_t x,y;
989 uint8_t xp,yp;
990 uint8_t xl,yl;
991 //uint8_t xs,ys;
992 double course;
993  
1220 mija 994 switch(test_key())
995 {
996 case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
997 case KEY2_LONG: id_mod=ID_OFF;return;
998 case KEY3_LONG: return;
999 case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
1000 case KEY2_SHORT:
1001 case KEY3_SHORT:break;
1002 }
1003  
1213 mija 1004 if (!timer_refresh)
1005 {
1006 timer_refresh = CLOCK1S;
1007 buffer_clr();
1008 status();
1217 mija 1009  
1213 mija 1010 gotoxy(9,3);
1217 mija 1011 offset_text -=2;
1012 ptr= CHAR_SIGNALL_3D;b=WIDTH_CHAR_SIGNALL_3D;//offset_text++;
1013 for (a=0;a<b;a++) *(offset_text++) =pgm_read_byte(ptr++);
1014  
1015 //gotoxy(10,3);
1016 printf("%4.0fm",gps.altitude);
1017  
1018 gotoxy(9,2);
1019 printf("north");
1020  
1021 gotoxy(9,4);
1213 mija 1022 fprintf(&mystdout2,"%3.1f",gps.speed);
1217 mija 1023 gotoxy(10,6);
1213 mija 1024 printf("km/h");
1025  
1026 #define WIDTH_REC_NORTH 43
1027 #define LCD_HEIGHT_NORTH 35
1028  
1029 course = 360-gps.course;
1030 x=(uint8_t)(WIDTH_REC_NORTH/2.0*sin(M_PI/180*course) +WIDTH_REC_NORTH/2);
1031 y=(uint8_t)((LCD_HEIGHT_NORTH)/2.0*cos(M_PI/180*course) +(LCD_HEIGHT_NORTH)/2);
1032  
1033 xl=(uint8_t)(WIDTH_REC_NORTH/2.0*sin(M_PI/180*(course-150.0))+WIDTH_REC_NORTH/2 );
1034 yl=(uint8_t)((LCD_HEIGHT_NORTH)/2.0*cos(M_PI/180*(course-150.0))+(LCD_HEIGHT_NORTH)/2 );
1035  
1036 xp=(uint8_t)(WIDTH_REC_NORTH/2.0*sin(M_PI/180*(course+150.0))+WIDTH_REC_NORTH/2 );
1037 yp=(uint8_t)((LCD_HEIGHT_NORTH)/2.0*cos(M_PI/180*(course+150.0)) +(LCD_HEIGHT_NORTH)/2);
1038  
1039 //xs=(uint8_t)((WIDTH_REC_NORTH-26)/2.0*sin(M_PI/180*(course+180.0))+WIDTH_REC_NORTH/2 );
1040 //ys=(uint8_t)(((LCD_HEIGHT_NORTH-20))/2.0*cos(M_PI/180*(course+180.0)) +(LCD_HEIGHT_NORTH)/2);
1041  
1042 lcd_line( x,y,xl,yl);
1043 lcd_line( x,y,xp,yp);
1044 //lcd_line( xp,yp,xl,yl);
1045 lcd_line(xl,yl,WIDTH_REC_NORTH/2,(LCD_HEIGHT_NORTH)/2);
1046 lcd_line(xp,yp,WIDTH_REC_NORTH/2,(LCD_HEIGHT_NORTH)/2);
1047  
1048 //lcd_line(xl,yl,xs,ys);
1049 //lcd_line(xp,yp,xs,ys);
1050 lcd_refresh();
1051 }
1052 }
1053  
1054 void displ_all_service(void)
1055 {
1056 uint8_t a;
1057  
1220 mija 1058 switch(test_key())
1059 {
1060 case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
1061 case KEY2_LONG: id_mod=ID_OFF;return;
1062 case KEY3_LONG: return;
1063 case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
1064 case KEY2_SHORT:
1065 case KEY3_SHORT:break;
1066 }
1067  
1213 mija 1068 if (!timer_refresh)
1069 {
1070 timer_refresh = CLOCK1S;
1071 buffer_clr();
1072 status();
1073  
1074 gotoxy(1,2);
1075 printf("d=%d %ds",gps.diff_id,gps.age_diff_corr);
1076 gotoxy(1,3);
1077 printf("%c st=%cD ",gps.mode1,gps.mode2);
1078 switch (gps.fix_position)
1079 {
1080 case 0: printf("nofix");break;
1081 case 1: printf("SPSfix");break;
1082 case 2: printf(" Dfix");break;
1083 default: printf("nopref");
1084 }
1085 gotoxy(1,4);
1086 printf("GSV %d %d %d",gps.gsv_num_msg,gps.gsv_msg,gps.gsv_satelites_view);
1087 gotoxy(1,5);
1088 for(a=0;a<6;a++)
1089 {
1090 printf("%2d",gps.satelite_id[a]);
1091 offset_text+=2;
1092 }
1093 gotoxy(1,6);
1094 for(a=6;a<12;a++)
1095 {
1096 printf("%2d",gps.satelite_id[a]);
1097 if (a != 11) offset_text+=2;
1098 }
1099 lcd_refresh();
1100 }
1101 }
1102  
1220 mija 1103 void temp(void)
1213 mija 1104 {
1220 mija 1105 timer_temp = TEMP_TIME_REPEAT;
1213 mija 1106 now.temperature=read_temp();
1107 now.time=actual_time();
1108 now.date=actual_date();
1109  
1110 buffer_clr();
1111 gotoxy(1,1);
1112 stdout = &mystdout2;
1113 print_temp(now.temperature);
1114 stdout = &mystdout;
1115 gotoxy(11,1);
1116 offset_text-= 2;
1117 print_time(now.time);
1118 gotoxy(11,2);
1119 offset_text-= 2;
1120 print_date(now.date);
1121 gotoxy(1,4);
1122 if (now.temperature > max.temperature) max=now;
1123 print_temp(max.temperature);
1124 gotoxy(11,4);
1125 offset_text-= 2;
1126 print_date(max.date);
1127 gotoxy(6,3);
1128 printf("max");
1129 gotoxy(11,3);
1130 offset_text-= 2;
1131 print_time(max.time);
1132 gotoxy(1,6);
1133 if (now.temperature < min.temperature) min=now;
1134 print_temp(min.temperature);
1135 gotoxy(11,6);
1136 offset_text-= 2;
1137 print_date(min.date);
1138 gotoxy(6,5);
1139 printf("min");
1140 gotoxy(11,5);
1141 offset_text-= 2;
1142 print_time(min.time);
1143 lcd_refresh();
1144 start_MCP9800();
1220 mija 1145 }
1146  
1147 void displ_temp()
1148 {
1149 //GPS_OFF;
1150 //ADC_OFF;
1151 //REF_OFF;
1152  
1153 switch(test_key())
1154 {
1155 case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
1156 case KEY2_LONG: id_mod=ID_OFF;return;
1157 case KEY3_LONG: return;
1158 case KEY1_SHORT:timer_refresh = 0;id_mod++;return;
1159 case KEY2_SHORT:timer_temp = 0; max.temperature=0x8000;min.temperature=0x7FFF;
1160 if (GPS_INPUT && (gps.status == 'A'))
1161 {
1162 sRTC=gps.second;
1163 mRTC=gps.minute;
1164 hRTC=gps.hour+2;
1165  
1166 dRTC=gps.day;
1167 mdRTC=gps.month;
1168 yRTC=gps.year;
1169 }break;
1170 case KEY3_SHORT: break;
1171 }
1172  
1173 if(!timer_temp)
1174 {
1175 temp();
1213 mija 1176 }
1177 }
1178  
1220 mija 1179  
1213 mija 1180 void displ_start(void)
1181 {
1182 buffer_clr();
1183 gotoxy(6,3);
1184 fprintf(&mystdout2,"GPS");
1185 lcd_refresh();
1186 delay_ms(1000);
1187 id_mod = ID_TEMP;
1188 }
1189  
1190 void all_off(void)
1191 {
1220 mija 1192 uint8_t temp_wiev;
1193  
1213 mija 1194 buffer_clr();
1195 gotoxy(6,3);
1196 fprintf(&mystdout2,"OFF");
1197 lcd_refresh();
1198 GPS_OFF;
1199 REF_OFF;
1220 mija 1200 ADC_OFF;
1217 mija 1201 delay_ms(1000);
1202 LED_OFF;
1213 mija 1203 N5110_send_command(POWER_DOWN);
1204  
1220 mija 1205 temp_wiev = 0;
1213 mija 1206 while (TL2_INPUT)
1217 mija 1207 {
1208 sleep_cpu();
1220 mija 1209 if (!TL1_INPUT)
1210 {
1211 if (!temp_wiev) N5110_send_command(ACTIVE_CHIP);
1212 temp_wiev = 1;
1213 timer1_ovf = 0;
1214 while ((!TL1_INPUT) && (timer1_ovf<200));
1215 if (timer1_ovf==200)
1216 {
1217 max.temperature=0x8000;
1218 min.temperature=0x7FFF;
1219 }
1220 }
1221 if (!TL3_INPUT) {N5110_send_command(POWER_DOWN);temp_wiev = 0;}
1222 if (temp_wiev) temp();
1213 mija 1223  
1217 mija 1224 }
1225 null_variables();
1213 mija 1226 LCD_N5110_INIT();
1217 mija 1227 displ_start();
1213 mija 1228 }
1229  
1230 //************************************************************************
1231 // spol key
1232  
1233 uint8_t key(uint8_t mod)
1234 {
1235 if(key_press)
1236 {
1237 if (!timer_off)
1238 {
1239 if (key_read() == _BV(KEY2))
1240 {
1241 timer_refresh = 0;
1242 timer_key = CLOCK2S;
1243 key_read();
1244 return ID_OFF;
1245 }
1246 }
1247 }
1248 else
1249 {
1250 if (key_flag == _BV(KEY1))
1251 {
1252 timer_key = KEY_TIME_FIRST;
1253 key_read();
1254 timer_refresh = 0;
1255 ++mod;
1256 }
1257 if (key_flag == _BV(KEY2))
1258 {
1259 if (LED_INPUT) LED_OFF;
1260 else LED_ON;
1261 timer_key = KEY_TIME_FIRST;
1262 key_read();
1263 }
1264 if (key_flag == _BV(KEY3))
1265 {
1266 max.temperature=0x8000;
1267 min.temperature=0x7FFF;
1268 if (GPS_INPUT && (gps.status == 'A'))
1269 {
1270 sRTC=gps.second;
1271 mRTC=gps.minute;
1272 hRTC=gps.hour+2;
1273  
1274 dRTC=gps.day;
1275 mdRTC=gps.month;
1276 yRTC=gps.year;
1277 }
1278  
1279 timer_key = KEY_TIME_FIRST;
1280 key_read();
1281 }
1282 }
1283 return mod;
1284 }
1285  
1217 mija 1286 void null_variables(void)
1287 {
1288 key_press = 0;
1289 key_flag = 0;
1290  
1291 timer_key = 0;
1292 timer_temp = 0;
1293 timer_off = OFF_TIME;
1294 timer_refresh = 0;
1295 timer_status = 0;
1296 timer1_ovf =0;
1297  
1298 //max.temperature=0x8000;
1299 //min.temperature=0x7FFF;
1300  
1301 //sRTC=0;
1302 //mRTC=15;
1303 //hRTC=17;
1304  
1305 //dRTC=25;
1306 //mdRTC=7;
1307 //yRTC=8;
1308  
1309 id_mod = ID_START;
1310 }
1311  
1213 mija 1312 //************************************************************************
1313 // main
1314  
1315 int main(void)
1217 mija 1316 {
1213 mija 1317  
1318 pgps = &gps;
1319  
1217 mija 1320 null_variables();
1321  
1213 mija 1322 general_cpu_init();
1323 //GPS_ON;
1324 LCD_N5110_INIT();
1325  
1326 //set_static_navigation(0);
1327  
1328 stdout = &mystdout;
1329 sei();
1330  
1331 for (;;)
1332 {
1333 switch(id_mod)
1334 {
1217 mija 1335 case ID_TIME: displ_time(); break;
1336 case ID_LOCATION: displ_location();break;
1213 mija 1337 //case ID_SPEED: displ_speed(); break;
1217 mija 1338 case ID_SATELITES: displ_satelites();break;
1339 case ID_COURSE: id_mod++;break;displ_course(); break;
1340 case ID_ALL_POSITION: displ_all_position(); break;
1341 case ID_ALL_SERVICE: id_mod++;break;displ_all_service();break;
1342 case ID_SERVICE: id_mod++;break;displ_service(scan_buf);break;
1343 case ID_TEMP: displ_temp(); break;
1344 case ID_OFF: all_off(); break;
1345 case ID_START: displ_start(); break;
1213 mija 1346 case ID_NAV: displ_nav();break;
1217 mija 1347 case ID_NORTH: displ_north();break;
1213 mija 1348 default : id_mod = 0;
1349 }
1350  
1351  
1352 switch (load_nmea(rx_shift,rx_buf,scan_buf))
1353 {
1354 case RETURN_GGA: nmea_gga(scan_buf,pgps);break;
1355 case RETURN_GSA: nmea_gsa(scan_buf,pgps);break;
1356 case RETURN_GSV: nmea_gsv(scan_buf,pgps);break;
1357 case RETURN_RMC: nmea_rmc(scan_buf,pgps);break;
1358 case RETURN_VTG: nmea_vtg(scan_buf,pgps);break;
1359 }
1217 mija 1360  
1361 timer1_tik();
1362  
1220 mija 1363 //id_mod = key(id_mod);
1217 mija 1364  
1213 mija 1365 }
1366 return 0;
1367 }
1368