main.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /*---------------------------------------------------------------*
  2. * Automotive GPS logger (C)ChaN, 2014 *
  3. * Modified k4be, 2022 *
  4. *---------------------------------------------------------------*/
  5. #include <avr/io.h>
  6. #include <avr/interrupt.h>
  7. #include <avr/sleep.h>
  8. #include <util/delay.h>
  9. #include <avr/pgmspace.h>
  10. #include <string.h>
  11. #include "main.h"
  12. #include "ff.h"
  13. #include "diskio.h"
  14. #include "uart0.h"
  15. #include "uart1.h"
  16. #include "xprintf.h"
  17. #include "stime.h"
  18. #include "ds18b20.h"
  19. #include "I2C.h"
  20. #include "expander.h"
  21. #include "HD44780-I2C.h"
  22. /*FUSES = {0xFF, 0x11, 0xFE};*/ /* ATmega644PA fuses: Low, High, Extended.
  23. This is the fuse settings for this project. The fuse bits will be included
  24. in the output hex file with program code. However some old flash programmers
  25. cannot load the fuse bits from hex file. If it is the case, remove this line
  26. and use these values to program the fuse bits. */
  27. volatile struct system_s System;
  28. FATFS Fatfs; /* File system object for each logical drive */
  29. FIL File1; /* File object */
  30. char Line[100]; /* Line buffer */
  31. time_t utc; /* current time */
  32. /*---------------------------------------------------------*/
  33. /* 100Hz timer interrupt generated by OC1A */
  34. /*---------------------------------------------------------*/
  35. ISR(TIMER1_COMPA_vect)
  36. {
  37. static WORD ivt_sync;
  38. static BYTE led;
  39. unsigned int *volatile ctimer;
  40. unsigned char i;
  41. for(i=0; i<sizeof(System.timers)/sizeof(unsigned int); i++){ // decrement every variable from timers struct unless it's already zero
  42. ctimer = ((unsigned int *)&System.timers) + i;
  43. if(*ctimer)
  44. (*ctimer)--;
  45. }
  46. /* Sync interval */
  47. if (IVT_SYNC && ++ivt_sync >= IVT_SYNC * 100) {
  48. ivt_sync = 0;
  49. FLAGS |= F_SYNC;
  50. }
  51. /* Green LED drive */
  52. if (FLAGS & F_POW) {
  53. if ((FLAGS & F_GPSOK) || (++led & 0x20)) {
  54. LEDG_ON();
  55. } else {
  56. LEDG_OFF();
  57. }
  58. } else {
  59. LEDG_OFF();
  60. }
  61. /* MMC/SD timer procedure */
  62. disk_timerproc();
  63. }
  64. /* Power supply monitor */
  65. ISR(ADC_vect)
  66. {
  67. WORD ad;
  68. static BYTE lvt;
  69. ad = ADC * 100;
  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. }
  84. /*---------------------------------------------------------*/
  85. /* User Provided Timer Function for FatFs module */
  86. /*---------------------------------------------------------*/
  87. DWORD get_fattime (void)
  88. {
  89. return 0;
  90. }
  91. /*----------------------------------------------------*/
  92. /* Get a line received from GPS module */
  93. /*----------------------------------------------------*/
  94. UINT get_line ( /* 0:Brownout, >0: Number of bytes received. */
  95. char *buff,
  96. UINT sz_buf
  97. )
  98. {
  99. char c;
  100. UINT i = 0;
  101. set_timer(recv_timeout, 1000);
  102. for (;;) {
  103. if (FLAGS & F_LVD)
  104. return 0; /* A brownout is detected */
  105. if (timer_expired(recv_timeout))
  106. return 0; /* timeout; continue the main loop */
  107. if (!uart0_test())
  108. continue;
  109. c = (char)uart0_get();
  110. xputc(c);
  111. if (i == 0 && c != '$')
  112. continue; /* Find start of line */
  113. buff[i++] = c;
  114. if (c == '\n')
  115. break; /* EOL */
  116. if (i >= sz_buf)
  117. i = 0; /* Buffer overflow (abort this line) */
  118. }
  119. return i;
  120. }
  121. /*--------------------------------------------------------------------------*/
  122. /* Controls */
  123. void beep (UINT len, BYTE cnt)
  124. {
  125. while (cnt--) {
  126. BEEP_ON();
  127. set_timer(beep, len);
  128. while(!timer_expired(beep)) {};
  129. BEEP_OFF();
  130. set_timer(beep, len);
  131. while(!timer_expired(beep)) {};
  132. }
  133. }
  134. /* Compare sentence header string */
  135. BYTE gp_comp (const char *str1, __flash const char *str2)
  136. {
  137. char c;
  138. do {
  139. c = pgm_read_byte(str2++);
  140. } while (c && c == *str1++);
  141. return c;
  142. }
  143. /* Get a column item */
  144. static
  145. BYTE* gp_col ( /* Returns pointer to the item (returns a NULL when not found) */
  146. const char* buf, /* Pointer to the sentence */
  147. BYTE col /* Column number (0 is the 1st item) */
  148. ) {
  149. BYTE c;
  150. while (col) {
  151. do {
  152. c = *buf++;
  153. if (c <= ' ') return NULL;
  154. } while (c != ',');
  155. col--;
  156. }
  157. return (BYTE*)buf;
  158. }
  159. static
  160. BYTE gp_val2 (
  161. const BYTE *db
  162. )
  163. {
  164. BYTE n, m;
  165. n = db[0] - '0';
  166. if (n >= 10)
  167. return 0;
  168. m = db[1] - '0';
  169. if (m >= 10)
  170. return 0;
  171. return n * 10 + m;
  172. }
  173. static
  174. time_t gp_rmctime ( /* Get GPS status from RMC sentence */
  175. const char *str
  176. )
  177. {
  178. const BYTE *p;
  179. struct tm tmc;
  180. time_t utc;
  181. if (gp_comp(str, PSTR("$GPRMC")))
  182. return 0; /* Not the RMC */
  183. p = gp_col(str, 2); /* Get status */
  184. if (!p || *p != 'A') {
  185. FLAGS &= ~F_GPSOK;
  186. return 0;
  187. }
  188. p = gp_col(str, 1); /* Get h:m:s */
  189. if (!p)
  190. return 0;
  191. tmc.tm_hour = gp_val2(p);
  192. tmc.tm_min = gp_val2(p+2);
  193. tmc.tm_sec = gp_val2(p+4);
  194. p = gp_col(str, 9); /* Get y:m:d */
  195. if (!p)
  196. return 0;
  197. tmc.tm_mday = gp_val2(p);
  198. tmc.tm_mon = gp_val2(p+2) - 1;
  199. tmc.tm_year = gp_val2(p+4) + 100;
  200. utc = mktime(&tmc); /* Check time validity */
  201. if (utc == -1)
  202. return 0;
  203. FLAGS |= F_GPSOK;
  204. return utc;
  205. }
  206. static
  207. void ioinit (void)
  208. {
  209. BUZZER_DDR |= BUZZER;
  210. GPS_DIS_DDR |= GPS_DIS;
  211. LEDR_DDR |= LEDR;
  212. OCR1A = F_CPU/8/100-1; /* Timer1: 100Hz interval (OC1A) */
  213. TCCR1B = _BV(WGM12) | _BV(CS11);
  214. TIMSK1 = _BV(OCIE1A); /* Enable TC1.oca interrupt */
  215. ACSR = _BV(ACD); /* Disable analog comp */
  216. /* ADC */
  217. ADMUX = 0;
  218. ADCSRA = _BV(ADEN)|_BV(ADATE)|_BV(ADIE)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0);
  219. /* uart1 (debug) */
  220. uart1_init();
  221. I2C_init();
  222. expander_init(0, 0x00, 0x00); /* all as outputs */
  223. LCD_Initialize();
  224. LCD_Clear();
  225. sei();
  226. ADCSRA |= _BV(ADSC);
  227. }
  228. /*-----------------------------------------------------------------------*/
  229. /* Main */
  230. /*-----------------------------------------------------------------------*/
  231. int main (void)
  232. {
  233. UINT bw, len;
  234. struct tm *ct;
  235. time_t tmp_utc;
  236. FRESULT res;
  237. unsigned char prev_status;
  238. ioinit();
  239. xdev_out(uart1_put);
  240. for (;;) {
  241. utc = 0;
  242. prev_status = System.status;
  243. System.status = STATUS_NO_POWER;
  244. beep(250, prev_status); /* Error beep */
  245. /* Wait for supply voltage stabled */
  246. while (FLAGS & F_LVD) {};
  247. _delay_ms(500);
  248. if (FLAGS & F_LVD)
  249. continue;
  250. /* report error here ( prev_status) */
  251. if (disk_status(0) & STA_NODISK) {
  252. System.status = STATUS_NO_DISK;
  253. continue;
  254. }
  255. res = f_mount(&Fatfs, "", 1);
  256. if (res != FR_OK) {
  257. xprintf(PSTR("FS error %u\r\n"), res);
  258. System.status = STATUS_DISK_ERROR;
  259. continue;
  260. }
  261. System.status = STATUS_NO_GPS;
  262. xputs(PSTR("FS Ok\r\n"));
  263. beep(50, 1); /* 1 beep */
  264. /* Initialize GPS receiver */
  265. GPS_ON(); /* GPS power on */
  266. FLAGS |= F_POW;
  267. _delay_ms(300); /* Delay */
  268. uart0_init(); /* Enable UART */
  269. // xfprintf(uart0_put, PSTR("$PSRF106,21*0F\r\n")); /* Send initialization command (depends on the receiver) */
  270. for (;;) { /* main loop */
  271. gettemp();
  272. if (!(FLAGS & F_GPSOK))
  273. xputs_P(PSTR("Waiting for GPS\r\n"));
  274. len = get_line(Line, sizeof Line); /* Receive a line from GPS receiver */
  275. if (!len){
  276. if (FLAGS & F_LVD)
  277. break; /* brownout */
  278. continue;
  279. }
  280. tmp_utc = gp_rmctime(Line);
  281. if (tmp_utc)
  282. utc = tmp_utc + LOCALDIFF * 3600L; /* Local time */
  283. if (utc && !(FLAGS & F_FILEOPEN)) {
  284. ct = gmtime(&utc);
  285. xsprintf(Line, PSTR("%02u%02u%02u.LOG"), ct->tm_year % 100, ct->tm_mon + 1, ct->tm_mday);
  286. xprintf(PSTR("Open %s\r\n"), Line);
  287. if (f_open(&File1, Line, FA_WRITE | FA_OPEN_ALWAYS) /* Open log file */
  288. || f_lseek(&File1, f_size(&File1)) /* Append mode */
  289. || f_write(&File1, "\r\n", 2, &bw)) /* Put a blank line as start marker */
  290. {
  291. System.status = STATUS_FILE_OPEN_ERROR;
  292. break; /* Failed to start logging */
  293. }
  294. FLAGS |= F_FILEOPEN;
  295. System.status = STATUS_OK;
  296. beep(50, 2);
  297. continue; /* Two beeps. Start logging. */
  298. }
  299. if (FLAGS & F_FILEOPEN) {
  300. f_write(&File1, Line, len, &bw);
  301. if (bw != len) {
  302. System.status = STATUS_FILE_WRITE_ERROR;
  303. break;
  304. }
  305. if (FLAGS & F_SYNC) {
  306. if (f_sync(&File1)) {
  307. System.status = STATUS_FILE_SYNC_ERROR;
  308. break;
  309. }
  310. FLAGS &= ~F_SYNC;
  311. }
  312. }
  313. }
  314. /* Stop GPS receiver */
  315. uart0_deinit();
  316. GPS_OFF();
  317. FLAGS &= ~F_POW;
  318. /* Close file */
  319. if (FLAGS & F_FILEOPEN) {
  320. if (f_close(&File1))
  321. System.status = STATUS_FILE_CLOSE_ERROR;
  322. xputs_P(PSTR("File closed\r\n"));
  323. }
  324. FLAGS &= ~F_FILEOPEN;
  325. disk_ioctl(0, CTRL_POWER, 0);
  326. if (System.status != STATUS_FILE_CLOSE_ERROR)
  327. beep(500, 1); /* Long beep on file close succeeded */
  328. }
  329. }