/*---------------------------------------------------------------*//* GPS data logger R0.02 (C)ChaN, 2008 *//*---------------------------------------------------------------*/#include <avr/io.h>#include <avr/pgmspace.h>#include <avr/interrupt.h>#include <string.h>#include "tff.h"#include "diskio.h"#define SYSCLK 10000000UL#define BEEP_ON() TCCR0B=0b011#define BEEP_OFF() TCCR0B=0b000#define GPS_ON() PORTB|=0x02#define GPS_OFF() PORTB&=0xFD#define DELAY(dly) for(Timer=dly;Timer;)#define VTH_LOW (WORD)(8000UL*100/3838)#define VTH_HIGH (WORD)(11500UL*100/3838)#define POWER_check 0b01000000 | 1#define ANALOG_IN1 0b01000000 | 2FATFS fatfs; /* File system object for each logical drive */FIL file1; /* File object */BYTE Buff[82]; /* File/Console buffer */uint16_t battery; // battery voltageuint16_t intensity; // radiation intensityvolatile BYTE Timer; /* 100Hz decrement timer */volatile BYTE Stat; /* Status */typedef struct _fifo {uint8_t idx_w;uint8_t idx_r;uint8_t count;uint8_t buff[150];} FIFO;volatile FIFO rxfifo;/*---------------------------------------------------------*//* ADC interrupt *//*---------------------------------------------------------*/ISR(ADC_vect){WORD n;static BYTE l, h;n = ADC;if(ADMUX == POWER_check){if (n < VTH_LOW) {if (l >= 15) {Stat |= 0x01;}else {l++;}}else {l = 0;}if (n > VTH_HIGH) {if (h >= 15) {Stat &= 0xFE;}else {h++;}}else {h = 0;}battery = n;ADMUX = ANALOG_IN1;}if(ADMUX == ANALOG_IN1){intensity = n;ADMUX = POWER_check;}//!!!!//Stat &= 0xFE;ADCSRA = _BV(ADEN)|_BV(ADSC)|_BV(ADIF)|_BV(ADIE)|0b111;}/*---------------------------------------------------------*//* 100Hz timer interrupt generated by OC1A *//*---------------------------------------------------------*/ISR(TIMER1_COMPA_vect){BYTE n;static WORD ivt_sync;n = Timer;if (n) Timer = n - 1;if (++ivt_sync >= 180 * 100) {ivt_sync = 0;Stat |= 4;}disk_timerproc(); /* Drive timer procedure of low level disk I/O module */}/*---------------------------------------------------------*//* User Provided Timer Function for FatFs module *//*---------------------------------------------------------*//* This is a real time clock service to be called from *//* FatFs module. Any valid time must be returned even if *//* the system does not support a real time clock. */DWORD get_fattime (){return ((2007UL - 1980) << 25) /* Fixed to 2007.5.1, 00:00:00 */| ((5UL) << 21)| ((1UL) << 16)| (0 << 11)| (0 << 5)| (0 >> 1);}/*--------------------------------------------------------------------------*//* UART control */staticvoid uart_init (void){cli();UCSR0B = 0;rxfifo.idx_r = 0;rxfifo.idx_w = 0;rxfifo.count = 0;UBRR0L = SYSCLK/16/9600; // Enable USRAT0 in N81,4800bpsUCSR0B = _BV(RXCIE0)|_BV(RXEN0)|_BV(TXEN0);Stat &= 0xFD; // Clear overflow flagsei();}staticvoid uart_stop (void){UCSR0B = 0;}/* Get a received character */staticuint8_t uart_get (){uint8_t d, i;i = rxfifo.idx_r;if (rxfifo.count == 0) return 0;d = rxfifo.buff[i++];cli();rxfifo.count--;sei();if(i >= sizeof(rxfifo.buff))i = 0;rxfifo.idx_r = i;return d;}/* USART0 RXC interrupt */ISR(USART_RX_vect){uint8_t d, n, i;d = UDR0;n = rxfifo.count;if(n < sizeof(rxfifo.buff)) {rxfifo.count = ++n;i = rxfifo.idx_w;rxfifo.buff[i++] = d;if(i >= sizeof(rxfifo.buff))i = 0;rxfifo.idx_w = i;} else {Stat |= 2;}}/*----------------------------------------------------*//* Get a line received from GPS module *//*----------------------------------------------------*/staticBYTE get_line (void) // 0: Power fail occured, >0: Number of bytes received.{BYTE c, i = 0;for (;;) {if (Stat & 1) return 0; // When power fail is detected, return with zero.c = uart_get();if (Stat & 2) { // When buffer overflow has occured, restert to receive line.uart_init();i = 0; c = 0;}if (!c || (i == 0 && c != '$')) continue;Buff[i++] = c;if (c == '\n') break;if (i >= sizeof(Buff)) i = 0;}return i;}/*--------------------------------------------------------------------------*//* Controls */staticvoid beep (BYTE len, BYTE cnt){while (cnt--) {BEEP_ON();DELAY(len);BEEP_OFF();DELAY(len);}}/* Compare sentence header string */staticBYTE gp_comp (BYTE *str1, const prog_uint8_t *str2){BYTE c;do {c = pgm_read_byte(str2++);} while (c && c == *str1++);return c;}/* Get a column item */staticBYTE* gp_col ( /* Returns pointer to the item (returns a NULL when not found) */const BYTE* buf, /* Pointer to the sentence */BYTE col /* Column number (0 is the 1st item) */) {BYTE c;while (col) {do {c = *buf++;if (c <= ' ') return NULL;} while (c != ',');col--;}return (BYTE*)buf;}staticvoid ioinit (void){PORTB = 0b00001101; // Port BDDRB = 0b00101110;PORTC = 0b00111111; // Port CDDRC = 0b00000000;PORTD = 0b10101110; // Port DDDRD = 0b01010010;SPCR = 0b01010000; /* Initialize SPI port (Mode 0) */SPSR = 0b00000001;OCR1A = SYSCLK/8/100-1; // Timer1: 100Hz interval (OC1A)TCCR1B = 0b00001010;TIMSK1 = _BV(OCIE1A); // Enable TC1.oca interruptOCR0A = SYSCLK/64/4000/2-1; // Timer0: 4kHz sound (OC0A)TCCR0A = 0b01000010;ADMUX = POWER_check; // Select ADC inputADCSRA = _BV(ADEN)|_BV(ADSC)|_BV(ADIF)|_BV(ADIE)|0b111;sei();}/*-----------------------------------------------------------------------*//* Main */int main (){BYTE b, err, *p = NULL;WORD s;ioinit();f_mount(0, &fatfs); /* Enable file I/O layer */for (;;) {uart_stop();GPS_OFF();Timer = 100;do {if (Stat & 1) Timer = 100;} while (Timer);GPS_ON();Timer = 255;do {if ((Stat & 1) || (disk_status(0) & STA_NODISK)) Timer = 255;} while (Timer);beep(5, 1); // Single beep. Start to get current time.uart_init();do { // Wait for valid RMC sentence.b = get_line();if (!b) break;if (gp_comp(Buff, PSTR("$GPRMC"))) continue;p = gp_col(Buff,2);} while (!p || *p != 'A');if (!b) continue;p = gp_col(Buff,9); // Open log file with the name of current date (YYMMDD.log in UTC).if (!p) {err = 3; break;}memcpy(&Buff[0], p+4, 2);memcpy(&Buff[2], p+2, 2);memcpy(&Buff[4], p+0, 2);strcpy_P(&Buff[6], PSTR(".log"));if (f_open(&file1, Buff, FA_OPEN_ALWAYS | FA_WRITE) || f_lseek(&file1, file1.fsize)) { err = 4; break; }beep(5, 2); // Two beeps. Start logging.err = 0;while ((b = get_line()) > 0) {if ( !gp_comp(Buff, PSTR("$GPGGA")) // Which sentence is logged?|| !gp_comp(Buff, PSTR("$GPRMC"))// || !gp_comp(Buff, PSTR("$GPGSA"))// || !gp_comp(Buff, PSTR("$GPGLL"))// || !gp_comp(Buff, PSTR("$GPGSV"))// || !gp_comp(Buff, PSTR("$GPZDA"))// || !gp_comp(Buff, PSTR("$GPVTG"))){if (f_write(&file1, Buff, b, &s) || b != s) { err = 5; break; };}if ((Stat & 4) == 0) continue;if (f_sync(&file1)) { err = 6; break; };// Synchronize the file in interval of 300 sec.cli(); Stat &= 0xFB; sei(); // Clear sync request}if (err) break;// Turn-off GPS power and close the log file by power supply is discharged.uart_stop();GPS_OFF();if (f_close(&file1)) { err = 7; break; };// When a long beep is sounded, the shutdoun process has been succeeded.beep(50, 1);}// Unrecoverble error. Enter shutdown state.uart_stop();GPS_OFF();beep(25, err);for (;;);}