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