Rev Author Line No. Line
1271 kaklik 1 /*---------------------------------------------------------------*/
2 /* GPS data logger R0.02 (C)ChaN, 2008 */
3 /*---------------------------------------------------------------*/
4  
5 #include <avr/io.h>
6 #include <avr/pgmspace.h>
7 #include <avr/interrupt.h>
8 #include <string.h>
9 #include "tff.h"
10 #include "diskio.h"
11  
12  
13 #define SYSCLK 10000000UL
14  
15 #define BEEP_ON() TCCR0B=0b011
16 #define BEEP_OFF() TCCR0B=0b000
17 #define GPS_ON() PORTB|=0x02
18 #define GPS_OFF() PORTB&=0xFD
19 #define DELAY(dly) for(Timer=dly;Timer;)
20  
21 #define VTH_LOW (WORD)(8000UL*100/3838)
22 #define VTH_HIGH (WORD)(11500UL*100/3838)
23 #define POWER_check 0b01000000 | 1
24 #define ANALOG_IN1 0b01000000 | 2
25  
26  
27 FATFS fatfs; /* File system object for each logical drive */
28 FIL file1; /* File object */
29 BYTE Buff[82]; /* File/Console buffer */
30  
31 uint16_t battery; // battery voltage
32 uint16_t intensity; // radiation intensity
33  
34 volatile BYTE Timer; /* 100Hz decrement timer */
35 volatile BYTE Stat; /* Status */
36  
37  
38 typedef struct _fifo {
39 uint8_t idx_w;
40 uint8_t idx_r;
41 uint8_t count;
42 uint8_t buff[150];
43 } FIFO;
44 volatile FIFO rxfifo;
45  
46  
47  
48 /*---------------------------------------------------------*/
49 /* ADC interrupt */
50 /*---------------------------------------------------------*/
51  
52 ISR(ADC_vect)
53 {
54 WORD n;
55 static BYTE l, h;
56  
57 n = ADC;
58  
59 if(ADMUX == POWER_check)
60 {
61 if (n < VTH_LOW) {
62 if (l >= 15) {
63 Stat |= 0x01;
64 }
65 else {l++;}
66 }
67 else {l = 0;}
68  
69 if (n > VTH_HIGH) {
70 if (h >= 15) {
71 Stat &= 0xFE;
72 }
73 else {h++;}
74 }
75 else {h = 0;}
76  
77 battery = n;
78 ADMUX = ANALOG_IN1;
79 }
80  
81 if(ADMUX == ANALOG_IN1)
82 {
83 intensity = n;
84 ADMUX = POWER_check;
85 }
86  
87 //!!!!
88 //Stat &= 0xFE;
89  
90 ADCSRA = _BV(ADEN)|_BV(ADSC)|_BV(ADIF)|_BV(ADIE)|0b111;
91 }
92  
93  
94 /*---------------------------------------------------------*/
95 /* 100Hz timer interrupt generated by OC1A */
96 /*---------------------------------------------------------*/
97  
98  
99 ISR(TIMER1_COMPA_vect)
100 {
101 BYTE n;
102 static WORD ivt_sync;
103  
104  
105 n = Timer;
106 if (n) Timer = n - 1;
107  
108 if (++ivt_sync >= 180 * 100) {
109 ivt_sync = 0;
110 Stat |= 4;
111 }
112  
113 disk_timerproc(); /* Drive timer procedure of low level disk I/O module */
114  
115 }
116  
117  
118  
119 /*---------------------------------------------------------*/
120 /* User Provided Timer Function for FatFs module */
121 /*---------------------------------------------------------*/
122 /* This is a real time clock service to be called from */
123 /* FatFs module. Any valid time must be returned even if */
124 /* the system does not support a real time clock. */
125  
126  
127 DWORD get_fattime ()
128 {
129 return ((2007UL - 1980) << 25) /* Fixed to 2007.5.1, 00:00:00 */
130 | ((5UL) << 21)
131 | ((1UL) << 16)
132 | (0 << 11)
133 | (0 << 5)
134 | (0 >> 1);
135 }
136  
137  
138 /*--------------------------------------------------------------------------*/
139 /* UART control */
140  
141  
142 static
143 void uart_init (void)
144 {
145 cli();
146 UCSR0B = 0;
147 rxfifo.idx_r = 0;
148 rxfifo.idx_w = 0;
149 rxfifo.count = 0;
150 UBRR0L = SYSCLK/16/9600; // Enable USRAT0 in N81,4800bps
151 UCSR0B = _BV(RXCIE0)|_BV(RXEN0)|_BV(TXEN0);
152 Stat &= 0xFD; // Clear overflow flag
153 sei();
154 }
155  
156  
157 static
158 void uart_stop (void)
159 {
160 UCSR0B = 0;
161 }
162  
163  
164 /* Get a received character */
165 static
166 uint8_t uart_get ()
167 {
168 uint8_t d, i;
169  
170  
171 i = rxfifo.idx_r;
172 if (rxfifo.count == 0) return 0;
173 d = rxfifo.buff[i++];
174 cli();
175 rxfifo.count--;
176 sei();
177 if(i >= sizeof(rxfifo.buff))
178 i = 0;
179 rxfifo.idx_r = i;
180  
181 return d;
182 }
183  
184 ISR(USART_RX_vect)
185 {
186 uint8_t d, n, i;
187
188  
189  
190 n = rxfifo.count;
191 if(n < sizeof(rxfifo.buff)) {
192 rxfifo.count = ++n;
193 i = rxfifo.idx_w;
194 rxfifo.buff[i++] = d;
195 if(i >= sizeof(rxfifo.buff))
196 i = 0;
197 rxfifo.idx_w = i;
198 } else {
199 Stat |= 2;
200 }
201 }
202
203  
204  
205  
206 /* Get a line received from GPS module */
207 /*----------------------------------------------------*/
208
209  
210 BYTE get_line (void) // 0: Power fail occured, >0: Number of bytes received.
211 {
212 BYTE c, i = 0;
213
214  
215  
216 if (Stat & 1) return 0; // When power fail is detected, return with zero.
217 c = uart_get();
218 if (Stat & 2) { // When buffer overflow has occured, restert to receive line.
219 uart_init();
220 i = 0; c = 0;
221 }
222 if (!c || (i == 0 && c != '$')) continue;
223 Buff[i++] = c;
224 if (c == '\n') break;
225 if (i >= sizeof(Buff)) i = 0;
226 }
227 return i;
228 }
229
230  
231  
232  
233 /* Controls */
234
235  
236 void beep (BYTE len, BYTE cnt)
237 {
238 while (cnt--) {
239 BEEP_ON();
240 DELAY(len);
241 BEEP_OFF();
242 DELAY(len);
243 }
244 }
245
246  
247  
248  
249  
250 static
251 BYTE gp_comp (BYTE *str1, const prog_uint8_t *str2)
252 {
253 BYTE c;
254
255  
256 c = pgm_read_byte(str2++);
257 } while (c && c == *str1++);
258 return c;
259 }
260
261  
262 static
263 BYTE* gp_col ( /* Returns pointer to the item (returns a NULL when not found) */
264 const BYTE* buf, /* Pointer to the sentence */
265 BYTE col /* Column number (0 is the 1st item) */
266 ) {
267 BYTE c;
268
269  
270  
271 do {
272 c = *buf++;
273 if (c <= ' ') return NULL;
274 } while (c != ',');
275 col--;
276 }
277 return (BYTE*)buf;
278 }
279
280  
281  
282  
283 void ioinit (void)
284 {
285 PORTB = 0b00001101; // Port B
286 DDRB = 0b00101110;
287 PORTC = 0b00111111; // Port C
288 DDRC = 0b00000000;
289 PORTD = 0b10101110; // Port D
290 DDRD = 0b01010010;
291
292  
293 SPSR = 0b00000001;
294
295  
296 TCCR1B = 0b00001010;
297 TIMSK1 = _BV(OCIE1A); // Enable TC1.oca interrupt
298
299  
300 TCCR0A = 0b01000010;
301
302  
303 ADCSRA = _BV(ADEN)|_BV(ADSC)|_BV(ADIF)|_BV(ADIE)|0b111;
304
305  
306 }
307
308  
309  
310  
311 /* Main */
312
313  
314  
315 {
316 BYTE b, err, *p = NULL;
317 WORD s;
318
319  
320  
321 f_mount(0, &fatfs); /* Enable file I/O layer */
322
323  
324 uart_stop();
325 GPS_OFF();
326 Timer = 100;
327 do {
328 if (Stat & 1) Timer = 100;
329 } while (Timer);
330
331  
332 Timer = 255;
333 do {
334 if ((Stat & 1) || (disk_status(0) & STA_NODISK)) Timer = 255;
335 } while (Timer);
336
337  
338 uart_init();
339 do { // Wait for valid RMC sentence.
340 b = get_line();
341 if (!b) break;
342 if (gp_comp(Buff, PSTR("$GPRMC"))) continue;
343 p = gp_col(Buff,2);
344 } while (!p || *p != 'A');
345 if (!b) continue;
346 p = gp_col(Buff,9); // Open log file with the name of current date (YYMMDD.log in UTC).
347
348  
349
350  
351 memcpy(&Buff[2], p+2, 2);
352 memcpy(&Buff[4], p+0, 2);
353 strcpy_P(&Buff[6], PSTR(".log"));
354 if (f_open(&file1, Buff, FA_OPEN_ALWAYS | FA_WRITE) || f_lseek(&file1, file1.fsize)) { err = 4; break; }
355
356  
357 err = 0;
358 while ((b = get_line()) > 0) {
359 if ( !gp_comp(Buff, PSTR("$GPGGA")) // Which sentence is logged?
360 || !gp_comp(Buff, PSTR("$GPRMC"))
361 // || !gp_comp(Buff, PSTR("$GPGSA"))
362 // || !gp_comp(Buff, PSTR("$GPGLL"))
363 // || !gp_comp(Buff, PSTR("$GPGSV"))
364 // || !gp_comp(Buff, PSTR("$GPZDA"))
365 // || !gp_comp(Buff, PSTR("$GPVTG"))
366 )
367 {
368 if (f_write(&file1, Buff, b, &s) || b != s) { err = 5; break; };
369 }
370 if ((Stat & 4) == 0) continue;
371 if (f_sync(&file1)) { err = 6; break; };// Synchronize the file in interval of 300 sec.
372 cli(); Stat &= 0xFB; sei(); // Clear sync request
373 }
374 if (err) break;
375
376  
377 uart_stop();
378 GPS_OFF();
379 if (f_close(&file1)) { err = 7; break; };
380
381  
382 beep(50, 1);
383 }
384
385  
386 uart_stop();
387 GPS_OFF();
388 beep(25, err);
389 for (;;);
390 }
391
392  
393