| 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; | 
      
        | 1271 | kaklik | 185 | } | 
      
        | 1234 | kaklik | 186 |  | 
      
        |  |  | 187 | ISR(USART_RX_vect) | 
      
        |  |  | 188 | { | 
      
        |  |  | 189 | 	uint8_t d, n, i; | 
      
        |  |  | 190 |  | 
      
        |  |  | 191 |  | 
      
        |  |  | 192 |  | 
      
        |  |  | 193 | 	n = rxfifo.count; | 
      
        |  |  | 194 | 	if(n < sizeof(rxfifo.buff)) { | 
      
        |  |  | 195 | 		rxfifo.count = ++n; | 
      
        |  |  | 196 | 		i = rxfifo.idx_w; | 
      
        |  |  | 197 | 		rxfifo.buff[i++] = d; | 
      
        |  |  | 198 | 		if(i >= sizeof(rxfifo.buff)) | 
      
        |  |  | 199 | 			i = 0; | 
      
        |  |  | 200 | 		rxfifo.idx_w = i; | 
      
        |  |  | 201 | 	} else { | 
      
        |  |  | 202 | 		Stat |= 2; | 
      
        |  |  | 203 | 	} | 
      
        |  |  | 204 | } | 
      
        |  |  | 205 |  | 
      
        |  |  | 206 |  | 
      
        |  |  | 207 |  | 
      
        |  |  | 208 |  | 
      
        |  |  | 209 | /*  Get a line received from GPS module               */ | 
      
        |  |  | 210 | /*----------------------------------------------------*/ | 
      
        |  |  | 211 |  | 
      
        |  |  | 212 |  | 
      
        |  |  | 213 | BYTE get_line (void)	// 0: Power fail occured, >0: Number of bytes received. | 
      
        |  |  | 214 | { | 
      
        |  |  | 215 | 	BYTE c, i = 0; | 
      
        |  |  | 216 |  | 
      
        |  |  | 217 |  | 
      
        |  |  | 218 |  | 
      
        |  |  | 219 | 		if (Stat & 1) return 0;	// When power fail is detected, return with zero. | 
      
        |  |  | 220 | 		c = uart_get(); | 
      
        |  |  | 221 | 		if (Stat & 2) {			// When buffer overflow has occured, restert to receive line. | 
      
        |  |  | 222 | 			uart_init(); | 
      
        |  |  | 223 | 			i = 0; c = 0; | 
      
        |  |  | 224 | 		} | 
      
        |  |  | 225 | 		if (!c || (i == 0 && c != '$')) continue; | 
      
        |  |  | 226 | 		Buff[i++] = c; | 
      
        |  |  | 227 | 		if (c == '\n') break; | 
      
        |  |  | 228 | 		if (i >= sizeof(Buff)) i = 0; | 
      
        |  |  | 229 | 	} | 
      
        |  |  | 230 | 	return i; | 
      
        |  |  | 231 | } | 
      
        |  |  | 232 |  | 
      
        |  |  | 233 |  | 
      
        |  |  | 234 |  | 
      
        |  |  | 235 |  | 
      
        |  |  | 236 | /* Controls                                                                 */ | 
      
        |  |  | 237 |  | 
      
        |  |  | 238 |  | 
      
        |  |  | 239 | void beep (BYTE len, BYTE cnt) | 
      
        |  |  | 240 | { | 
      
        |  |  | 241 | 	while (cnt--) { | 
      
        |  |  | 242 | 		BEEP_ON(); | 
      
        |  |  | 243 | 		DELAY(len); | 
      
        |  |  | 244 | 		BEEP_OFF(); | 
      
        |  |  | 245 | 		DELAY(len); | 
      
        |  |  | 246 | 	} | 
      
        |  |  | 247 | } | 
      
        |  |  | 248 |  | 
      
        |  |  | 249 |  | 
      
        |  |  | 250 |  | 
      
        |  |  | 251 |  | 
      
        |  |  | 252 |  | 
      
        |  |  | 253 | static | 
      
        |  |  | 254 | BYTE gp_comp (BYTE *str1, const prog_uint8_t *str2) | 
      
        |  |  | 255 | { | 
      
        |  |  | 256 | 	BYTE c; | 
      
        |  |  | 257 |  | 
      
        |  |  | 258 |  | 
      
        |  |  | 259 | 		c = pgm_read_byte(str2++); | 
      
        |  |  | 260 | 	} while (c && c == *str1++); | 
      
        |  |  | 261 | 	return c; | 
      
        |  |  | 262 | } | 
      
        |  |  | 263 |  | 
      
        |  |  | 264 |  | 
      
        |  |  | 265 | static | 
      
        |  |  | 266 | BYTE* gp_col (			/* Returns pointer to the item (returns a NULL when not found) */ | 
      
        |  |  | 267 | 	const BYTE* buf,	/* Pointer to the sentence */ | 
      
        |  |  | 268 | 	BYTE col			/* Column number (0 is the 1st item) */ | 
      
        |  |  | 269 | ) { | 
      
        |  |  | 270 | 	BYTE c; | 
      
        |  |  | 271 |  | 
      
        |  |  | 272 |  | 
      
        |  |  | 273 |  | 
      
        |  |  | 274 | 		do { | 
      
        |  |  | 275 | 			c = *buf++; | 
      
        |  |  | 276 | 			if (c <= ' ') return NULL; | 
      
        |  |  | 277 | 		} while (c != ','); | 
      
        |  |  | 278 | 		col--; | 
      
        |  |  | 279 | 	} | 
      
        |  |  | 280 | 	return (BYTE*)buf; | 
      
        |  |  | 281 | } | 
      
        |  |  | 282 |  | 
      
        |  |  | 283 |  | 
      
        |  |  | 284 |  | 
      
        |  |  | 285 |  | 
      
        |  |  | 286 | void ioinit (void) | 
      
        |  |  | 287 | { | 
      
        |  |  | 288 | 	PORTB = 0b00001101;	 	// Port B | 
      
        |  |  | 289 | 	DDRB  = 0b00101110; | 
      
        |  |  | 290 | 	PORTC = 0b00111111;		// Port C | 
      
        |  |  | 291 | 	DDRC  = 0b00000000; | 
      
        |  |  | 292 | 	PORTD = 0b10101110;		// Port D | 
      
        |  |  | 293 | 	DDRD  = 0b01010010; | 
      
        |  |  | 294 |  | 
      
        |  |  | 295 |  | 
      
        |  |  | 296 | 	SPSR = 0b00000001; | 
      
        |  |  | 297 |  | 
      
        |  |  | 298 |  | 
      
        |  |  | 299 | 	TCCR1B = 0b00001010; | 
      
        |  |  | 300 | 	TIMSK1 = _BV(OCIE1A);		// Enable TC1.oca interrupt | 
      
        |  |  | 301 |  | 
      
        |  |  | 302 |  | 
      
        |  |  | 303 | 	TCCR0A = 0b01000010; | 
      
        |  |  | 304 |  | 
      
        |  |  | 305 |  | 
      
        |  |  | 306 | 	ADCSRA = _BV(ADEN)|_BV(ADSC)|_BV(ADIF)|_BV(ADIE)|0b111; | 
      
        |  |  | 307 |  | 
      
        |  |  | 308 |  | 
      
        |  |  | 309 | } | 
      
        |  |  | 310 |  | 
      
        |  |  | 311 |  | 
      
        |  |  | 312 |  | 
      
        |  |  | 313 |  | 
      
        |  |  | 314 | /* Main                                                                  */ | 
      
        |  |  | 315 |  | 
      
        |  |  | 316 |  | 
      
        |  |  | 317 |  | 
      
        |  |  | 318 | { | 
      
        |  |  | 319 | 	BYTE b, err, *p = NULL; | 
      
        |  |  | 320 | 	WORD s; | 
      
        |  |  | 321 |  | 
      
        |  |  | 322 |  | 
      
        |  |  | 323 |  | 
      
        |  |  | 324 | 	f_mount(0, &fatfs);					/* Enable file I/O layer */ | 
      
        |  |  | 325 |  | 
      
        |  |  | 326 |  | 
      
        |  |  | 327 | 		uart_stop(); | 
      
        |  |  | 328 | 		GPS_OFF(); | 
      
        |  |  | 329 | 		Timer = 100; | 
      
        |  |  | 330 | 		do { | 
      
        |  |  | 331 | 			if (Stat & 1) Timer = 100; | 
      
        |  |  | 332 | 		} while (Timer); | 
      
        |  |  | 333 |  | 
      
        |  |  | 334 |  | 
      
        |  |  | 335 | 		Timer = 255; | 
      
        |  |  | 336 | 		do { | 
      
        |  |  | 337 | 			if ((Stat & 1) || (disk_status(0) & STA_NODISK))  Timer = 255; | 
      
        |  |  | 338 | 		} while (Timer); | 
      
        |  |  | 339 |  | 
      
        |  |  | 340 |  | 
      
        |  |  | 341 | 		uart_init(); | 
      
        |  |  | 342 | 		do {			// Wait for valid RMC sentence. | 
      
        |  |  | 343 | 			b = get_line(); | 
      
        |  |  | 344 | 			if (!b) break; | 
      
        |  |  | 345 | 			if (gp_comp(Buff, PSTR("$GPRMC"))) continue; | 
      
        |  |  | 346 | 			p = gp_col(Buff,2); | 
      
        |  |  | 347 | 		} while (!p || *p != 'A'); | 
      
        |  |  | 348 | 		if (!b) continue; | 
      
        |  |  | 349 | 		p = gp_col(Buff,9);		// Open log file with the name of current date (YYMMDD.log in UTC). | 
      
        |  |  | 350 | 		 | 
      
        |  |  | 351 |  | 
      
        |  |  | 352 |  | 
      
        |  |  | 353 |  | 
      
        |  |  | 354 | 		memcpy(&Buff[2], p+2, 2); | 
      
        |  |  | 355 | 		memcpy(&Buff[4], p+0, 2); | 
      
        |  |  | 356 | 		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; } | 
      
        |  |  | 358 |  | 
      
        |  |  | 359 |  | 
      
        |  |  | 360 | 		err = 0; | 
      
        |  |  | 361 | 		while ((b = get_line()) > 0) { | 
      
        |  |  | 362 | 			if (   !gp_comp(Buff, PSTR("$GPGGA"))	// Which sentence is logged? | 
      
        |  |  | 363 | 				|| !gp_comp(Buff, PSTR("$GPRMC")) | 
      
        |  |  | 364 | 			//	|| !gp_comp(Buff, PSTR("$GPGSA")) | 
      
        |  |  | 365 | 			//	|| !gp_comp(Buff, PSTR("$GPGLL")) | 
      
        |  |  | 366 | 			//	|| !gp_comp(Buff, PSTR("$GPGSV")) | 
      
        |  |  | 367 | 			//	|| !gp_comp(Buff, PSTR("$GPZDA")) | 
      
        |  |  | 368 | 			//	|| !gp_comp(Buff, PSTR("$GPVTG")) | 
      
        |  |  | 369 | 			)  | 
      
        |  |  | 370 | 			{ | 
      
        |  |  | 371 | 				if (f_write(&file1, Buff, b, &s) || b != s) { err = 5; break; }; | 
      
        |  |  | 372 | /*				itoa(battery,&Value1,10);		// convert binary number to character | 
      
        | 1271 | kaklik | 373 | 				itoa(intensity,&Value2,10); | 
      
        | 1234 | kaklik | 374 | 				strcpy(&Buff[0], Value1); | 
      
        |  |  | 375 | 				strcpy_P(&Buff[4], PSTR(",")); | 
      
        |  |  | 376 | 				strcpy(&Buff[5], Value2); | 
      
        |  |  | 377 | 				strcpy_P(&Buff[9], PSTR("\r\n")); | 
      
        |  |  | 378 | 				if (f_write(&file1, Buff, 11, &s) || 11 != s) { err = 8; break; }; | 
      
        | 1271 | kaklik | 379 | */			} | 
      
        |  |  | 380 | 			if ((Stat & 4) == 0) continue; | 
      
        | 1234 | kaklik | 381 | 			if (f_sync(&file1)) { err = 6; break; };// Synchronize the file in interval of 300 sec. | 
      
        |  |  | 382 | 			cli(); Stat &= 0xFB; sei();				// Clear sync request | 
      
        |  |  | 383 | 		} | 
      
        |  |  | 384 | 		if (err) break; | 
      
        |  |  | 385 |  | 
      
        |  |  | 386 |  | 
      
        |  |  | 387 | 		uart_stop(); | 
      
        |  |  | 388 | 		GPS_OFF(); | 
      
        |  |  | 389 | 		if (f_close(&file1)) { err = 7; break; }; | 
      
        |  |  | 390 |  | 
      
        |  |  | 391 |  | 
      
        |  |  | 392 | 		beep(50, 1); | 
      
        |  |  | 393 | 	} | 
      
        |  |  | 394 |  | 
      
        |  |  | 395 |  | 
      
        |  |  | 396 | 	uart_stop(); | 
      
        |  |  | 397 | 	GPS_OFF(); | 
      
        |  |  | 398 | 	beep(25, err); | 
      
        |  |  | 399 | 	for (;;); | 
      
        |  |  | 400 | } | 
      
        |  |  | 401 |  | 
      
        |  |  | 402 |  | 
      
        |  |  | 403 |  |