1
0

main.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. /*---------------------------------------------------------------*/
  2. /* Automotive GPS logger (C)ChaN, 2014 */
  3. /*---------------------------------------------------------------*/
  4. #include <avr/io.h>
  5. #include <avr/interrupt.h>
  6. #include <avr/sleep.h>
  7. #include <string.h>
  8. #include "ff.h"
  9. #include "diskio.h"
  10. #include "uart.h"
  11. #include "suart.h"
  12. #include "xitoa.h"
  13. #include "stime.h"
  14. FUSES = {0xE6, 0xD9, 0xFD}; /* ATmega328P fuses: Low, High, Extended.
  15. This is the fuse settings for this project. The fuse bits will be included
  16. in the output hex file with program code. However some old flash programmers
  17. cannot load the fuse bits from hex file. If it is the case, remove this line
  18. and use these values to program the fuse bits. */
  19. #define LOCALDIFF +9 /* Time difference from UTC [hours] */
  20. #define IVT_SYNC 180 /* f_sync() interval (0:no periodic sync) [sec] */
  21. #define VI_LVL 9.0 /* Blackout threshold [volt] */
  22. #define VI_LVH 10.0 /* Recharge threshold [volt] */
  23. #define VI_MULT (10.0 / 130 / 3.0 * 1024)
  24. #define BEEP_ON() TCCR0A = 0b01000010
  25. #define BEEP_OFF() TCCR0A = 0b10000010
  26. #define LEDG_ON() PORTB &= ~_BV(0)
  27. #define LEDG_OFF() PORTB |= _BV(0)
  28. #define GPS_ON() PORTC |= _BV(1)
  29. #define GPS_OFF() PORTC &= ~_BV(1)
  30. #define DELAY_MS(d) {for (Timer = (BYTE)(d / 10); Timer; ) ; }
  31. FATFS Fatfs; /* File system object for each logical drive */
  32. FIL File1; /* File object */
  33. char Line[100]; /* Line buffer */
  34. volatile BYTE Timer; /* 100Hz decrement timer */
  35. #define FLAGS GPIOR0 /* Status flags and bit definitions */
  36. #define F_POW 0x80 /* Power */
  37. #define F_GPSOK 0x08 /* GPS data valid */
  38. #define F_SYNC 0x04 /* Sync request */
  39. #define F_LVD 0x01 /* Low battery detect */
  40. /*---------------------------------------------------------*/
  41. /* 100Hz timer interrupt generated by OC1A */
  42. /*---------------------------------------------------------*/
  43. ISR(TIMER1_COMPA_vect)
  44. {
  45. BYTE n;
  46. WORD ad;
  47. static WORD ivt_sync;
  48. static BYTE led, lvt;
  49. n = Timer;
  50. if (n) Timer = --n;;
  51. /* Sync interval */
  52. if (IVT_SYNC && ++ivt_sync >= IVT_SYNC * 100) {
  53. ivt_sync = 0;
  54. FLAGS |= F_SYNC;
  55. }
  56. /* Green LED drive */
  57. if (FLAGS & F_POW) {
  58. if ((FLAGS & F_GPSOK) || (++led & 0x20)) {
  59. LEDG_ON();
  60. } else {
  61. LEDG_OFF();
  62. }
  63. } else {
  64. LEDG_OFF();
  65. }
  66. /* Power supply monitor */
  67. ad = ADC * 100;
  68. ADMUX = 7;
  69. ADCSRA = _BV(ADEN)|_BV(ADSC)|0b110;
  70. if (FLAGS & F_LVD) {
  71. if (ad > (WORD)(VI_LVH * VI_MULT) * 100) {
  72. FLAGS &= ~F_LVD;
  73. lvt = 0;
  74. }
  75. } else {
  76. if (ad < (WORD)(VI_LVL * VI_MULT) * 100) {
  77. if (++lvt >= 10)
  78. FLAGS |= F_LVD;
  79. } else {
  80. lvt = 0;
  81. }
  82. }
  83. /* MMC/SD timer procedure */
  84. disk_timerproc();
  85. }
  86. /*---------------------------------------------------------*/
  87. /* User Provided Timer Function for FatFs module */
  88. /*---------------------------------------------------------*/
  89. DWORD get_fattime (void)
  90. {
  91. return 0;
  92. }
  93. /*----------------------------------------------------*/
  94. /* Get a line received from GPS module */
  95. /*----------------------------------------------------*/
  96. UINT get_line ( /* 0:Brownout, >0: Number of bytes received. */
  97. char *buff,
  98. UINT sz_buf
  99. )
  100. {
  101. char c;
  102. UINT i = 0;
  103. for (;;) {
  104. if (FLAGS & F_LVD) return 0; /* A brownout is detected */
  105. if (!uart_test()) continue;
  106. c = (char)uart_get();
  107. xputc(c);
  108. if (i == 0 && c != '$') continue; /* Find start of line */
  109. buff[i++] = c;
  110. if (c == '\n') break; /* EOL */
  111. if (i >= sz_buf) i = 0; /* Buffer overflow (abort this line) */
  112. }
  113. return i;
  114. }
  115. /*--------------------------------------------------------------------------*/
  116. /* Controls */
  117. void beep (UINT len, BYTE cnt)
  118. {
  119. while (cnt--) {
  120. BEEP_ON();
  121. DELAY_MS(len);
  122. BEEP_OFF();
  123. DELAY_MS(len);
  124. }
  125. }
  126. /* Compare sentence header string */
  127. BYTE gp_comp (const char *str1, const prog_char *str2)
  128. {
  129. char c;
  130. do {
  131. c = pgm_read_byte(str2++);
  132. } while (c && c == *str1++);
  133. return c;
  134. }
  135. /* Get a column item */
  136. static
  137. BYTE* gp_col ( /* Returns pointer to the item (returns a NULL when not found) */
  138. const char* buf, /* Pointer to the sentence */
  139. BYTE col /* Column number (0 is the 1st item) */
  140. ) {
  141. BYTE c;
  142. while (col) {
  143. do {
  144. c = *buf++;
  145. if (c <= ' ') return NULL;
  146. } while (c != ',');
  147. col--;
  148. }
  149. return (BYTE*)buf;
  150. }
  151. static
  152. BYTE gp_val2 (
  153. const BYTE *db
  154. )
  155. {
  156. BYTE n, m;
  157. n = db[0] - '0';
  158. if (n >= 10) return 0;
  159. m = db[1] - '0';
  160. if (m >= 10) return 0;
  161. return n * 10 + m;
  162. }
  163. static
  164. time_t gp_rmctime ( /* Get GPS status from RMC sentence */
  165. const char *str
  166. )
  167. {
  168. const BYTE *p;
  169. struct tm tmc;
  170. time_t utc;
  171. if (gp_comp(str, PSTR("$GPRMC"))) return 0; /* Not the RMC */
  172. p = gp_col(str, 2); /* Get status */
  173. if (!p || *p != 'A') {
  174. FLAGS &= ~F_GPSOK;
  175. return 0;
  176. }
  177. p = gp_col(str, 1); /* Get h:m:s */
  178. if (!p) return 0;
  179. tmc.tm_hour = gp_val2(p);
  180. tmc.tm_min = gp_val2(p+2);
  181. tmc.tm_sec = gp_val2(p+4);
  182. p = gp_col(str, 9); /* Get y:m:d */
  183. if (!p) return 0;
  184. tmc.tm_mday = gp_val2(p);
  185. tmc.tm_mon = gp_val2(p+2) - 1;
  186. tmc.tm_year = gp_val2(p+4) + 100;
  187. utc = mktime(&tmc); /* Check time validity */
  188. if (utc == -1) return 0;
  189. FLAGS |= F_GPSOK;
  190. return utc;
  191. }
  192. static
  193. void ioinit (void)
  194. {
  195. PORTB = 0b00000011; /* --zzzzHH */
  196. DDRB = 0b00000011;
  197. PORTC = 0b00111101; /* --uuuuLH */
  198. DDRC = 0b00000011;
  199. PORTD = 0b10111110; /* uLuuuuHz */
  200. DDRD = 0b01000010;
  201. OCR1A = F_CPU/8/100-1; /* Timer1: 100Hz interval (OC1A) */
  202. TCCR1B = 0b00001010;
  203. TIMSK1 = _BV(OCIE1A); /* Enable TC1.oca interrupt */
  204. OCR0A = F_CPU/64/4000/2-1; /* Timer0: 4kHz sound (OC0A) */
  205. TCCR0A = 0b10000010;
  206. TCCR0B = 0b00000011;
  207. ACSR = _BV(ACD); /* Disable analog comp */
  208. sei();
  209. }
  210. /*-----------------------------------------------------------------------*/
  211. /* Main */
  212. /*-----------------------------------------------------------------------*/
  213. int main (void)
  214. {
  215. UINT bw, len, err;
  216. struct tm *ct;
  217. time_t utc;
  218. FRESULT res;
  219. ioinit();
  220. #ifdef LEDR_UART
  221. xdev_out(xmit);
  222. #endif
  223. err = 0;
  224. for (;;) {
  225. beep(250, err); /* Error beep */
  226. err = 0;
  227. /* Wait for supply voltage stabled */
  228. while (FLAGS & F_LVD) ;
  229. DELAY_MS(500);
  230. if (FLAGS & F_LVD) continue;
  231. if (disk_status(0) & STA_NODISK) continue;
  232. res = f_mount(&Fatfs, "", 1);
  233. if (res != FR_OK) {
  234. xprintf(PSTR("FS error %u\r\n"), res);
  235. err = 2; continue;
  236. }
  237. xputs(PSTR("FS Ok\r\n"));
  238. beep(50, 1); /* 1 beep */
  239. /* Initialize GPS receiver */
  240. GPS_ON(); /* GPS power on */
  241. FLAGS |= F_POW;
  242. DELAY_MS(300); /* Delay */
  243. uart_init(); /* Enable UART */
  244. xfprintf(uart_put, PSTR("$PSRF106,21*0F\r\n")); /* Send initialization command (depends on the receiver) */
  245. utc = 0;
  246. for (;;) {
  247. len = get_line(Line, sizeof Line); /* Receive a line from GPS receiver */
  248. if (!len) break; /* Brownout? */
  249. if (!utc) {
  250. utc = gp_rmctime(Line); /* Get time in UTC from a valid RMC sentence */
  251. if (utc) {
  252. utc += LOCALDIFF * 3600L; /* Local time */
  253. ct = gmtime(&utc);
  254. xsprintf(Line, PSTR("%02u%02u%02u.LOG"), ct->tm_year % 100, ct->tm_mon + 1, ct->tm_mday);
  255. xprintf(PSTR("Open %s\r\n"), Line);
  256. if (f_open(&File1, Line, FA_WRITE | FA_OPEN_ALWAYS) /* Open log file */
  257. || f_lseek(&File1, f_size(&File1)) /* Append mode */
  258. || f_write(&File1, "\r\n", 2, &bw)) /* Put a blank line as start marker */
  259. {
  260. utc = 0; err = 2; break; /* Failed to start logging */
  261. }
  262. beep(50, 2); /* Two beeps. Start logging. */
  263. }
  264. } else {
  265. gp_rmctime(Line);
  266. f_write(&File1, Line, len, &bw);
  267. if (bw != len) {
  268. err = 3; break;
  269. }
  270. if (FLAGS & F_SYNC) {
  271. if (f_sync(&File1)) {
  272. err = 2; break;
  273. }
  274. FLAGS &= ~F_SYNC;
  275. }
  276. }
  277. }
  278. /* Stop GPS receiver */
  279. uart_deinit();
  280. GPS_OFF();
  281. FLAGS &= ~F_POW;
  282. /* Close file */
  283. if (utc && f_close(&File1)) err = 2;
  284. disk_ioctl(0, CTRL_POWER_OFF, 0);
  285. if (!err) beep(500, 1); /* Long beep on file close succeeded */
  286. }
  287. }