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