No changes between revisions
/Designs/Data_loggers/GPSRL03A/main.c
0,0 → 1,402
/*---------------------------------------------------------------*/
/* 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 GPS_BAUDRATE 4800 // Enable USRAT0 in N81,9600bps
 
#define VTH_LOW (WORD)(8000UL*100/3838)
#define VTH_HIGH (WORD)(11500UL*100/3838)
#define POWER_check 0b01000000 | 1
#define ANALOG_IN1 0b01000000 | 2
 
 
FATFS fatfs; /* File system object for each logical drive */
FIL file1; /* File object */
BYTE Buff[82]; /* File/Console buffer */
 
BYTE Value1[4]; // logged values
BYTE Value2[4];
 
uint16_t battery; // battery voltage
uint16_t intensity; // radiation intensity
 
volatile 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 */
 
 
static
void uart_init (void)
{
cli();
UCSR0B = 0;
rxfifo.idx_r = 0;
rxfifo.idx_w = 0;
rxfifo.count = 0;
UBRR0L = SYSCLK/16/GPS_BAUDRATE;
UCSR0B = _BV(RXCIE0)|_BV(RXEN0)|_BV(TXEN0);
Stat &= 0xFD; // Clear overflow flag
sei();
}
 
 
static
void uart_stop (void)
{
UCSR0B = 0;
}
 
 
/* Get a received character */
static
uint8_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 */
+/*----------------------------------------------------*/
+
+static
+BYTE 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, restart 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 */
+
+static
+void beep (BYTE len, BYTE cnt)
+{
+ while (cnt--) {
+ BEEP_ON();
+ DELAY(len);
+ BEEP_OFF();
+ DELAY(len);
+ }
+}
+
+
+
+
+/* Compare sentence header string */
+static
+BYTE 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 */
+static
+BYTE* 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;
+}
+
+
+
+static
+void ioinit (void)
+{
+ PORTB = 0b00001101; // Port B
+ DDRB = 0b00101110;
+ PORTC = 0b00111111; // Port C
+ DDRC = 0b00000000;
+ PORTD = 0b10101110; // Port D
+ DDRD = 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 interrupt
+
+ OCR0A = SYSCLK/64/4000/2-1; // Timer0: 4kHz sound (OC0A)
+ TCCR0A = 0b01000010;
+
+ ADMUX = POWER_check; // Select ADC input
+ ADCSRA = _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; };
+ itoa(battery,&Value1,10); // convert number to character
+ itoa(intensity,&Value2,10);
+ sprintf(Buff,"%d,%d\n",Value1,Value2);
+ if (f_write(&file1, Buff,strlen(Buff), &s) || (strlen(Buff) != s)) { err = 8; 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 (;;);
+}
+
+