main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  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 <avr/wdt.h>
  11. #include <string.h>
  12. #include <stdlib.h>
  13. #include "main.h"
  14. #include "ff.h"
  15. #include "diskio.h"
  16. #include "uart0.h"
  17. #include "uart1.h"
  18. #include "xprintf.h"
  19. #include "stime.h"
  20. #include "ds18b20.h"
  21. #include "I2C.h"
  22. #include "expander.h"
  23. #include "HD44780-I2C.h"
  24. #include "gpx.h"
  25. #include "display.h"
  26. #include "working_modes.h"
  27. #include "timec.h"
  28. #include "nmea.h"
  29. /*FUSES = {0xFF, 0x11, 0xFE};*/ /* ATmega644PA fuses: Low, High, Extended.
  30. This is the fuse settings for this project. The fuse bits will be included
  31. in the output hex file with program code. However some old flash programmers
  32. cannot load the fuse bits from hex file. If it is the case, remove this line
  33. and use these values to program the fuse bits. */
  34. volatile struct system_s System;
  35. FATFS Fatfs; /* File system object for each logical drive */
  36. FIL gps_log; /* File object */
  37. FIL system_log; /* System log file */
  38. char Line[100]; /* Line buffer */
  39. time_t utc; /* current time */
  40. struct location_s location;
  41. void start_bootloader(void) {
  42. typedef void (*do_reboot_t)(void);
  43. const do_reboot_t do_reboot = (do_reboot_t)((FLASHEND - 1023) >> 1);
  44. cli();
  45. uart1_deinit();
  46. /* close_files(0); // FIXME not working
  47. display_state(DISPLAY_STATE_BOOTLOADER);*/
  48. LCD_Clear(); /* Do not call display.c here! */
  49. LCD_GoTo(0,0);
  50. LCD_WriteTextP(PSTR("Aktualizacja"));
  51. LCD_GoTo(8,1);
  52. LCD_WriteTextP(PSTR("softu..."));
  53. TCCR0A = TCCR1A = TCCR2A = 0; // make sure interrupts are off and timers are reset.
  54. do_reboot();
  55. wdt_enable(WDTO_15MS);
  56. while(1);
  57. }
  58. /*---------------------------------------------------------*/
  59. /* 100Hz timer interrupt generated by OC1A */
  60. /*---------------------------------------------------------*/
  61. ISR(TIMER1_COMPA_vect)
  62. {
  63. static WORD ivt_sync;
  64. // static BYTE led;
  65. static unsigned int power_sw;
  66. unsigned int *volatile ctimer;
  67. unsigned char i;
  68. unsigned char k;
  69. static unsigned char oldk;
  70. for(i=0; i<sizeof(System.timers)/sizeof(unsigned int); i++){ // decrement every variable from timers struct unless it's already zero
  71. ctimer = ((unsigned int *)&System.timers) + i;
  72. if(*ctimer)
  73. (*ctimer)--;
  74. }
  75. /* Sync interval */
  76. if (IVT_SYNC && ++ivt_sync >= IVT_SYNC * 100) {
  77. ivt_sync = 0;
  78. FLAGS |= F_SYNC;
  79. }
  80. /* Green LED drive */
  81. /* if (FLAGS & F_POW) {
  82. if ((FLAGS & F_GPSOK) || (++led & 0x20)) {
  83. LEDG_ON();
  84. } else {
  85. LEDG_OFF();
  86. }
  87. } else {
  88. LEDG_OFF();
  89. }*/
  90. /* MMC/SD timer procedure */
  91. disk_timerproc();
  92. /* Switch off */
  93. if (POWER_SW_PRESSED()) {
  94. if (++power_sw == POWER_SW_TIME){
  95. FLAGS |= F_POWEROFF;
  96. power_sw++;
  97. }
  98. System.timers.backlight = ms(BACKLIGHT_TIME);
  99. } else {
  100. power_sw = 0;
  101. }
  102. if (uart1_test() && uart1_get() == '0' && uart1_get() == ' '){
  103. LEDB_ON();
  104. start_bootloader();
  105. }
  106. /* keyboard */
  107. k = ((~PIND) >> 4) & 0x0f;
  108. if (POWER_SW_PRESSED())
  109. k |= K_POWER;
  110. if (k && k != oldk) {
  111. System.keypress = k;
  112. oldk = k;
  113. }
  114. if (!k)
  115. oldk = 0;
  116. }
  117. unsigned char getkey(void) {
  118. unsigned char key = System.keypress;
  119. System.keypress = 0;
  120. return key;
  121. }
  122. /* Power supply monitor */
  123. ISR(ADC_vect)
  124. {
  125. float bat_volt;
  126. static unsigned int adc_buf;
  127. static unsigned char adc_cnt;
  128. static BYTE lvt;
  129. adc_buf += ADC;
  130. if(++adc_cnt < 15)
  131. return;
  132. bat_volt = (float)adc_buf/(float)(adc_cnt)/VI_MULT;
  133. adc_buf = 0;
  134. adc_cnt = 0;
  135. System.bat_volt = bat_volt;
  136. if (FLAGS & F_LVD) {
  137. if (bat_volt > VI_LVH) {
  138. FLAGS &= ~F_LVD;
  139. lvt = 0;
  140. }
  141. } else {
  142. if (bat_volt < VI_LVL) {
  143. if (++lvt >= 3)
  144. FLAGS |= F_LVD;
  145. } else {
  146. lvt = 0;
  147. }
  148. }
  149. }
  150. void sleep(void) {
  151. set_sleep_mode(SLEEP_MODE_IDLE);
  152. sleep_enable();
  153. sleep_cpu();
  154. sleep_disable();
  155. }
  156. /*--------------------------------------------------------------------------*/
  157. /* Controls */
  158. void beep (UINT len, BYTE cnt)
  159. {
  160. while (cnt--) {
  161. BEEP_ON();
  162. set_timer(beep, len);
  163. while(!timer_expired(beep)) {};
  164. BEEP_OFF();
  165. set_timer(beep, len);
  166. while(!timer_expired(beep)) {};
  167. }
  168. }
  169. #define LOG_SIZE 300
  170. struct {
  171. char buf[LOG_SIZE+1];
  172. unsigned int len;
  173. } logbuf;
  174. void log_put(char c){
  175. UINT bw;
  176. uart1_put(c);
  177. logbuf.buf[logbuf.len++] = c;
  178. if (logbuf.len >= LOG_SIZE && (FLAGS & F_FILEOPEN)) {
  179. if(!f_write(&system_log, logbuf.buf, logbuf.len, &bw))
  180. logbuf.len = 0;
  181. }
  182. if (logbuf.len > LOG_SIZE) {
  183. logbuf.len--;
  184. }
  185. }
  186. static
  187. void ioinit (void)
  188. {
  189. wdt_enable(WDTO_4S);
  190. MCUSR = 0;
  191. POWER_ON_DDR |= POWER_ON;
  192. PORTA |= POWER_ON;
  193. BUZZER_DDR |= BUZZER;
  194. GPS_DIS_DDR |= GPS_DIS;
  195. LEDR_DDR |= LEDR;
  196. OCR1A = F_CPU/8/100-1; /* Timer1: 100Hz interval (OC1A) */
  197. TCCR1B = _BV(WGM12) | _BV(CS11);
  198. TIMSK1 = _BV(OCIE1A); /* Enable TC1.oca interrupt */
  199. /* ADC */
  200. // ADMUX = 0;
  201. ADMUX = 1; // FIXME only testing battery voltage
  202. ADCSRA = _BV(ADEN)|_BV(ADATE)|_BV(ADIE)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0);
  203. /* uart1 (debug) */
  204. uart1_init();
  205. I2C_init();
  206. expander_init(0, 0x00, 0x00); /* all as outputs */
  207. LCD_Initialize();
  208. LCD_Clear();
  209. sei();
  210. ADCSRA |= _BV(ADSC);
  211. /* unused pins */
  212. DDRA |= _BV(PA2) | _BV(PA4) | _BV(PA5);
  213. PRR0 |= _BV(PRTIM2) | _BV(PRTIM0);
  214. ACSR = _BV(ACD); /* Disable analog comp */
  215. }
  216. void close_files(unsigned char flush_logs) {
  217. UINT bw;
  218. if (FLAGS & F_FILEOPEN) {
  219. if (f_close(&gps_log))
  220. System.status = STATUS_FILE_CLOSE_ERROR;
  221. if (gpx_close(&gpx_file))
  222. System.status = STATUS_FILE_CLOSE_ERROR;
  223. if (flush_logs && logbuf.len && !f_write(&system_log, logbuf.buf, logbuf.len, &bw)) {
  224. logbuf.len = 0;
  225. }
  226. if (f_close(&system_log))
  227. System.status = STATUS_FILE_CLOSE_ERROR;
  228. xputs_P(PSTR("File closed\r\n"));
  229. display_state(DISPLAY_STATE_FILE_CLOSED);
  230. }
  231. FLAGS &= ~F_FILEOPEN;
  232. disk_ioctl(0, CTRL_POWER, 0);
  233. }
  234. __flash const char __open_msg[] = "Open %s\r\n";
  235. /*-----------------------------------------------------------------------*/
  236. /* Main */
  237. /*-----------------------------------------------------------------------*/
  238. int main (void)
  239. {
  240. UINT bw, len;
  241. static struct tm ct;
  242. time_t tmp_utc, localtime;
  243. FRESULT res;
  244. unsigned char prev_status;
  245. ioinit();
  246. xdev_out(log_put);
  247. xputs_P(PSTR("STARTUP\r\n"));
  248. display_state(DISPLAY_STATE_STARTUP);
  249. for (;;) {
  250. wdt_reset();
  251. if (FLAGS & (F_POWEROFF | F_LVD)) {
  252. xputs_P(PSTR("POWEROFF\r\n"));
  253. display_state(DISPLAY_STATE_POWEROFF);
  254. if (FLAGS & F_LVD) {
  255. display_state(DISPLAY_STATE_POWEROFF_LOWBAT);
  256. _delay_ms(500);
  257. }
  258. POWEROFF();
  259. while (POWER_SW_PRESSED());
  260. _delay_ms(2000); /* wait for switch off */
  261. FLAGS &= ~F_POWEROFF; /* restart if power is not lost */
  262. POWERON();
  263. xputs_P(PSTR("RESTART\r\n"));
  264. }
  265. display_state(DISPLAY_STATE_START_MESSAGE);
  266. xprintf(PSTR("LOOP err=%u\r\n"), (unsigned int)System.status);
  267. utc = 0;
  268. localtime = 0;
  269. prev_status = System.status;
  270. System.status = STATUS_NO_POWER;
  271. beep(250, prev_status); /* Error beep */
  272. /* Wait for supply voltage stabled */
  273. _delay_ms(500);
  274. if (FLAGS & F_LVD)
  275. continue;
  276. /* report error here ( prev_status) */
  277. if (disk_status(0) & STA_NODISK) {
  278. System.status = STATUS_NO_DISK;
  279. continue;
  280. }
  281. res = f_mount(&Fatfs, "", 1);
  282. if (res != FR_OK) {
  283. xprintf(PSTR("FS error %u\r\n"), res);
  284. System.status = STATUS_DISK_ERROR;
  285. continue;
  286. }
  287. res = f_mkdir(DIR_PATH_GPX);
  288. if (res != FR_OK && res != FR_EXIST) {
  289. xprintf(PSTR("FS dir error %u\r\n"), res);
  290. System.status = STATUS_DISK_ERROR;
  291. continue;
  292. }
  293. res = f_mkdir(DIR_PATH_SYSLOG);
  294. if (res != FR_OK && res != FR_EXIST) {
  295. xprintf(PSTR("FS dir error %u\r\n"), res);
  296. System.status = STATUS_DISK_ERROR;
  297. continue;
  298. }
  299. res = f_mkdir(DIR_PATH_NMEA);
  300. if (res != FR_OK && res != FR_EXIST) {
  301. xprintf(PSTR("FS dir error %u\r\n"), res);
  302. System.status = STATUS_DISK_ERROR;
  303. continue;
  304. }
  305. System.status = STATUS_NO_GPS;
  306. xputs(PSTR("FS Ok\r\n"));
  307. display_state(DISPLAY_STATE_CARD_OK);
  308. beep(50, 1); /* 1 beep */
  309. /* Initialize GPS receiver */
  310. GPS_ON(); /* GPS power on */
  311. FLAGS |= F_POW;
  312. _delay_ms(300); /* Delay */
  313. uart0_init(); /* Enable UART */
  314. // xfprintf(uart0_put, PSTR("$PSRF106,21*0F\r\n")); /* Send initialization command (depends on the receiver) */
  315. for (;;) { /* main loop */
  316. wdt_reset();
  317. display_refresh(DISPLAY_STATE_NO_CHANGE);
  318. gettemp();
  319. key_process();
  320. if (System.timers.backlight)
  321. LEDW_ON();
  322. else
  323. LEDW_OFF();
  324. if (!(FLAGS & F_GPSOK))
  325. xputs_P(PSTR("Waiting for GPS\r\n"));
  326. len = get_line(Line, sizeof Line); /* Receive a line from GPS receiver */
  327. if (!len){
  328. if (FLAGS & (F_LVD | F_POWEROFF))
  329. break; /* brownout */
  330. continue;
  331. }
  332. tmp_utc = gps_parse(Line);
  333. if (tmp_utc) {
  334. localtime = tmp_utc + local_time_diff(tmp_utc) * 3600L; /* Local time */
  335. ct = *gmtime(&localtime);
  336. if (timer_expired(system_log)) {
  337. set_timer(system_log, 5000);
  338. xprintf(PSTR("Time: %u.%02u.%04u %u:%02u:%02u\r\n"), ct.tm_mday, ct.tm_mon + 1, ct.tm_year+1900, ct.tm_hour, ct.tm_min, ct.tm_sec);
  339. xprintf(PSTR("Bat volt: %.3f\r\n"), System.bat_volt);
  340. if (System.temperature_ok)
  341. xprintf(PSTR("Temp: %.2f\r\n"), System.temperature);
  342. else
  343. xputs_P(PSTR("Temperature unknown\r\n"));
  344. }
  345. LEDG_ON();
  346. _delay_ms(2);
  347. LEDG_OFF();
  348. }
  349. if (FLAGS & F_FILEOPEN) {
  350. f_write(&gps_log, Line, len, &bw);
  351. if (bw != len) {
  352. System.status = STATUS_FILE_WRITE_ERROR;
  353. break;
  354. }
  355. if (System.location_valid == LOC_VALID_NEW) { /* a new point */
  356. gpx_process_point(&location, &gpx_file);
  357. System.gpx_points_written_nb++;
  358. }
  359. wdt_reset();
  360. if (FLAGS & F_SYNC) {
  361. if (f_sync(&gps_log)) {
  362. System.status = STATUS_FILE_SYNC_ERROR;
  363. break;
  364. }
  365. FLAGS &= ~F_SYNC;
  366. }
  367. }
  368. if (System.location_valid == LOC_VALID_NEW) {
  369. System.location_valid = LOC_VALID;
  370. }
  371. if (localtime && !(FLAGS & F_FILEOPEN)) {
  372. char *time = get_iso_time(utc, 1);
  373. char *ptr = time;
  374. while (*ptr) {
  375. switch (*ptr) {
  376. case ':': *ptr = '-'; break;
  377. case '+': *ptr = 'p'; break;
  378. }
  379. ptr++;
  380. }
  381. xsprintf(Line, PSTR("%s/%s-NMEA.LOG"), DIR_PATH_NMEA, time);
  382. xprintf(__open_msg, Line);
  383. if (f_open(&gps_log, Line, FA_WRITE | FA_OPEN_ALWAYS) /* Open log file */
  384. || f_lseek(&gps_log, f_size(&gps_log)) /* Append mode */
  385. || f_write(&gps_log, "\r\n", 2, &bw)) /* Put a blank line as start marker */
  386. {
  387. System.status = STATUS_FILE_OPEN_ERROR;
  388. break; /* Failed to start logging */
  389. }
  390. wdt_reset();
  391. xsprintf(Line, PSTR("%s/%s.GPX"), DIR_PATH_GPX, time);
  392. xprintf(__open_msg, Line);
  393. if (f_open(&gpx_file, Line, FA_WRITE | FA_OPEN_ALWAYS) /* Open log file */
  394. || f_lseek(&gpx_file, f_size(&gpx_file)) /* Append mode */
  395. || gpx_init(&gpx_file)) /* Put a blank line as start marker */
  396. {
  397. f_close(&gpx_file);
  398. System.status = STATUS_FILE_OPEN_ERROR;
  399. break; /* Failed to start logging */
  400. }
  401. wdt_reset();
  402. xsprintf(Line, PSTR("%s/%s-SYSTEM.LOG"), DIR_PATH_SYSLOG, time);
  403. xprintf(__open_msg, Line);
  404. if (f_open(&system_log, Line, FA_WRITE | FA_OPEN_ALWAYS) /* Open log file */
  405. || f_lseek(&system_log, f_size(&system_log)) /* Append mode */
  406. || f_write(&system_log, "\r\n", 2, &bw)) /* Put a blank line as start marker */
  407. {
  408. f_close(&gpx_file);
  409. f_close(&gps_log);
  410. System.status = STATUS_FILE_OPEN_ERROR;
  411. break; /* Failed to start logging */
  412. }
  413. wdt_reset();
  414. FLAGS |= F_FILEOPEN;
  415. System.status = STATUS_OK;
  416. beep(50, 2); /* Two beeps. Start logging. */
  417. display_state(DISPLAY_STATE_FILE_OPEN);
  418. continue;
  419. }
  420. }
  421. /* Stop GPS receiver */
  422. uart0_deinit();
  423. GPS_OFF();
  424. FLAGS &= ~F_POW;
  425. /* Close file */
  426. close_files(1);
  427. if (System.status != STATUS_FILE_CLOSE_ERROR)
  428. beep(500, 1); /* Long beep on file close succeeded */
  429. }
  430. }