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