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