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