main.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. /*---------------------------------------------------------------*
  2. * Automotive GPS logger (C)ChaN, 2014 *
  3. * Modified k4be, 2022 *
  4. *---------------------------------------------------------------*/
  5. #include "main.h"
  6. /*FUSES = {0xFF, 0x11, 0xFE};*/ /* ATmega644PA fuses: Low, High, Extended.
  7. This is the fuse settings for this project. The fuse bits will be included
  8. in the output hex file with program code. However some old flash programmers
  9. cannot load the fuse bits from hex file. If it is the case, remove this line
  10. and use these values to program the fuse bits. */
  11. volatile struct system_s System;
  12. FATFS Fatfs; /* File system object for each logical drive */
  13. FIL gps_log; /* File object */
  14. FIL system_log; /* System log file */
  15. char Line[100]; /* Line buffer */
  16. time_t utc; /* current time */
  17. struct location_s location;
  18. struct auto_pause_s auto_pause;
  19. volatile unsigned long int uptime_ms; /* milliseconds since MCU startup, for the system log */
  20. static unsigned int io_max_ms; /* longest single SD f_write()/f_sync() duration since the last status line, ms */
  21. /*
  22. * Reset cause: this board is always started via Optiboot, not a fresh MCU
  23. * reset straight into main(). Optiboot reads MCUSR at its own entry, clears
  24. * only WDRF (to avoid looping on its own watchdog-based re-entry), and passes
  25. * the *original* MCUSR value to the application in register r2 before jumping
  26. * to address 0 - see optiboot.c ("save the reset flags in the designated
  27. * register ... by putting code in .init0 ... to save R2 to a global
  28. * variable"). By the time main() runs, the real MCUSR register no longer
  29. * reflects the actual reset cause, so it must be read out of r2 instead, and
  30. * that has to happen in .init0 - the very first code executed - before
  31. * anything else can clobber the register.
  32. */
  33. volatile unsigned char reset_cause __attribute__((section(".noinit")));
  34. void get_mcusr_from_r2(void) __attribute__((naked, used, section(".init0")));
  35. void get_mcusr_from_r2(void) {
  36. __asm__ __volatile__ ("mov %0, r2\n" : "=r" (reset_cause) :);
  37. }
  38. /* Disable the watchdog as early as possible (in case this image is ever
  39. * flashed directly via ISP, bypassing Optiboot, which already turns the
  40. * watchdog off itself before jumping to the application): otherwise a
  41. * watchdog-triggered reset with a short timeout could loop forever before
  42. * main() re-enables it with the timeout it actually wants. */
  43. void wdt_disable_early(void) __attribute__((naked, used, section(".init3")));
  44. void wdt_disable_early(void) {
  45. MCUSR = 0;
  46. wdt_disable();
  47. }
  48. /*
  49. * Stack headroom (AVR121 "StackPaint" pattern): fill all RAM between the end
  50. * of .bss/.noinit and the top of RAM with a known byte as early as possible
  51. * (.init1, before the stack pointer itself is set up in .init2), then later
  52. * count how many bytes of that pattern are still untouched. That count can
  53. * only shrink over the session, as the deepest interrupt/call nesting grows,
  54. * so it is a running record of the worst-case stack headroom seen so far -
  55. * no extra storage needed to remember a "minimum".
  56. */
  57. #define STACK_CANARY 0xc5
  58. extern uint8_t __heap_start;
  59. extern uint8_t __stack;
  60. void stack_paint(void) __attribute__((naked, used, section(".init1")));
  61. void stack_paint(void) {
  62. __asm__ __volatile__ (
  63. " ldi r30,lo8(__heap_start)\n"
  64. " ldi r31,hi8(__heap_start)\n"
  65. " ldi r24,lo8(0xc5)\n" /* STACK_CANARY */
  66. " ldi r25,hi8(__stack)\n"
  67. " rjmp .Lstackpaint_cmp\n"
  68. ".Lstackpaint_loop:\n"
  69. " st Z+,r24\n"
  70. ".Lstackpaint_cmp:\n"
  71. " cpi r30,lo8(__stack)\n"
  72. " cpc r31,r25\n"
  73. " brlo .Lstackpaint_loop\n"
  74. " breq .Lstackpaint_loop\n"
  75. );
  76. }
  77. unsigned int get_stack_free_bytes(void) {
  78. const uint8_t *p = &__heap_start;
  79. unsigned int count = 0;
  80. while (p <= &__stack && *p == STACK_CANARY) {
  81. p++;
  82. count++;
  83. }
  84. return count;
  85. }
  86. void io_mark(unsigned long int start_ms) {
  87. unsigned int dt = (unsigned int)(get_uptime_ms() - start_ms);
  88. if (dt > io_max_ms)
  89. io_max_ms = dt;
  90. }
  91. unsigned int io_get_and_reset_max(void) {
  92. unsigned int v = io_max_ms;
  93. io_max_ms = 0;
  94. return v;
  95. }
  96. void start_bootloader(void) {
  97. typedef void (*do_reboot_t)(void);
  98. const do_reboot_t do_reboot = (do_reboot_t)((FLASHEND - 1023) >> 1);
  99. cli();
  100. uart1_deinit();
  101. /* close_files(0); // FIXME not working
  102. display_event(DISPLAY_EVENT_BOOTLOADER);*/
  103. LCD_Clear(); /* Do not call display.c here! */
  104. LCD_GoTo(0,0);
  105. LCD_WriteTextP(PSTR("Aktualizacja"));
  106. LCD_GoTo(8,1);
  107. LCD_WriteTextP(PSTR("softu..."));
  108. TCCR0A = TCCR1A = TCCR2A = 0; // make sure interrupts are off and timers are reset.
  109. do_reboot();
  110. wdt_enable(WDTO_15MS);
  111. while(1);
  112. }
  113. /*---------------------------------------------------------*/
  114. /* 100Hz timer interrupt generated by OC1A */
  115. /*---------------------------------------------------------*/
  116. ISR(TIMER1_COMPA_vect)
  117. {
  118. static WORD ivt_sync;
  119. // static BYTE led;
  120. static unsigned int power_sw;
  121. unsigned int *volatile ctimer;
  122. unsigned char i;
  123. unsigned char k;
  124. static unsigned char oldk;
  125. uptime_ms += 10; /* this ISR fires at 100Hz */
  126. for(i=0; i<sizeof(System.timers)/sizeof(unsigned int); i++){ // decrement every variable from timers struct unless it's already zero
  127. ctimer = ((unsigned int *)&System.timers) + i;
  128. if(*ctimer)
  129. (*ctimer)--;
  130. }
  131. /* Sync interval */
  132. if (IVT_SYNC && ++ivt_sync >= IVT_SYNC * 100) {
  133. ivt_sync = 0;
  134. FLAGS |= F_SYNC;
  135. }
  136. /* Green LED drive */
  137. /* if (FLAGS & F_POW) {
  138. if ((FLAGS & F_GPSOK) || (++led & 0x20)) {
  139. LEDG_ON();
  140. } else {
  141. LEDG_OFF();
  142. }
  143. } else {
  144. LEDG_OFF();
  145. }*/
  146. /* MMC/SD timer procedure */
  147. disk_timerproc();
  148. /* Switch off */
  149. if (POWER_SW_PRESSED()) {
  150. if (++power_sw == POWER_SW_TIME){
  151. FLAGS |= F_POWEROFF;
  152. power_sw++;
  153. }
  154. System.timers.backlight = ms(BACKLIGHT_TIME);
  155. } else {
  156. power_sw = 0;
  157. }
  158. if (uart1_test() && uart1_get() == '0' && uart1_get() == ' '){
  159. LEDB_ON();
  160. start_bootloader();
  161. }
  162. /* keyboard */
  163. k = ((~PIND) >> 4) & 0x0f;
  164. if (POWER_SW_PRESSED())
  165. k |= K_POWER;
  166. if (k && k != oldk) {
  167. System.keypress = k;
  168. oldk = k;
  169. }
  170. if (!k)
  171. oldk = 0;
  172. }
  173. unsigned char getkey(void) {
  174. unsigned char key = System.keypress;
  175. System.keypress = 0;
  176. return key;
  177. }
  178. /* Power supply monitor */
  179. ISR(ADC_vect)
  180. {
  181. float bat_volt;
  182. static unsigned int adc_buf;
  183. static unsigned char adc_cnt;
  184. static BYTE lvt;
  185. adc_buf += ADC;
  186. if(++adc_cnt < 15)
  187. return;
  188. bat_volt = (float)adc_buf/(float)(adc_cnt)/VI_MULT;
  189. adc_buf = 0;
  190. adc_cnt = 0;
  191. System.bat_volt = bat_volt;
  192. if (FLAGS & F_LVD) {
  193. if (bat_volt > VI_LVH) {
  194. FLAGS &= ~F_LVD;
  195. lvt = 0;
  196. }
  197. } else {
  198. if (bat_volt < VI_LVL) {
  199. if (++lvt >= 3)
  200. FLAGS |= F_LVD;
  201. } else {
  202. lvt = 0;
  203. }
  204. }
  205. }
  206. void sleep(void) {
  207. set_sleep_mode(SLEEP_MODE_IDLE);
  208. sleep_enable();
  209. sleep_cpu();
  210. sleep_disable();
  211. }
  212. /*--------------------------------------------------------------------------*/
  213. /* Controls */
  214. void beep (UINT len, BYTE cnt)
  215. {
  216. while (cnt--) {
  217. BEEP_ON();
  218. set_timer(beep, len);
  219. while(!timer_expired(beep)) {};
  220. BEEP_OFF();
  221. set_timer(beep, len);
  222. while(!timer_expired(beep)) {};
  223. }
  224. }
  225. #define LOG_SIZE 300
  226. struct {
  227. char buf[LOG_SIZE+1];
  228. unsigned int len;
  229. } logbuf;
  230. void log_put(int c){
  231. UINT bw;
  232. if (System.conf.uart_log_mode != UART_LOG_MODE_NMEA)
  233. uart1_put(c);
  234. logbuf.buf[logbuf.len++] = c;
  235. if (logbuf.len >= LOG_SIZE && (FLAGS & F_FILEOPEN)) {
  236. unsigned long int t0 = get_uptime_ms();
  237. unsigned char err = f_write(&system_log, logbuf.buf, logbuf.len, &bw);
  238. io_mark(t0);
  239. if (!err)
  240. logbuf.len = 0;
  241. }
  242. if (logbuf.len > LOG_SIZE) {
  243. logbuf.len--;
  244. }
  245. }
  246. static
  247. void ioinit (void)
  248. {
  249. wdt_enable(WDTO_4S); /* MCUSR was already cleared in wdt_disable_early() (.init3) */
  250. POWER_ON_DDR |= POWER_ON;
  251. PORTA |= POWER_ON;
  252. BUZZER_DDR |= BUZZER;
  253. GPS_OFF();
  254. GPS_DIS_DDR |= GPS_DIS;
  255. LEDR_DDR |= LEDR;
  256. OCR1A = F_CPU/8/100-1; /* Timer1: 100Hz interval (OC1A) */
  257. TCCR1B = _BV(WGM12) | _BV(CS11);
  258. TIMSK1 = _BV(OCIE1A); /* Enable TC1.oca interrupt */
  259. /* ADC */
  260. // ADMUX = 0;
  261. ADMUX = 1; // FIXME only testing battery voltage
  262. ADCSRA = _BV(ADEN)|_BV(ADATE)|_BV(ADIE)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0);
  263. /* uart1 (debug) */
  264. uart1_init();
  265. I2C_init();
  266. expander_init(0, 0x00, 0x00); /* all as outputs */
  267. LCD_Initialize();
  268. LCD_Clear();
  269. LCD_GoTo(0,0);
  270. wdt_reset();
  271. sei();
  272. ADCSRA |= _BV(ADSC);
  273. /* unused pins */
  274. DDRA |= _BV(PA2) | _BV(PA4) | _BV(PA5);
  275. PRR0 |= _BV(PRTIM2) | _BV(PRTIM0);
  276. ACSR = _BV(ACD); /* Disable analog comp */
  277. }
  278. void close_files(unsigned char flush_logs) {
  279. UINT bw;
  280. if (FLAGS & F_FILEOPEN) {
  281. if (flush_logs)
  282. log_session_summary(1);
  283. if (f_close(&gps_log)) {
  284. System.status = STATUS_FILE_CLOSE_ERROR;
  285. System.global_error |= ERROR_FILE_CLOSE;
  286. }
  287. if (gpx_close(&gpx_file)) {
  288. System.status = STATUS_FILE_CLOSE_ERROR;
  289. System.global_error |= ERROR_FILE_CLOSE;
  290. }
  291. if (flush_logs && logbuf.len && !f_write(&system_log, logbuf.buf, logbuf.len, &bw)) {
  292. logbuf.len = 0;
  293. }
  294. if (f_close(&system_log)) {
  295. System.status = STATUS_FILE_CLOSE_ERROR;
  296. System.global_error |= ERROR_FILE_CLOSE;
  297. }
  298. xputs_P(PSTR("File closed\r\n"));
  299. display_event(DISPLAY_EVENT_FILE_CLOSED);
  300. }
  301. FLAGS &= ~F_FILEOPEN;
  302. disk_ioctl(0, CTRL_POWER, 0);
  303. }
  304. static inline void auto_unpause(void) {
  305. if (!System.tracking_auto_paused)
  306. return;
  307. System.tracking_auto_paused = 0;
  308. log_pause_event(0);
  309. beep(50, 4);
  310. }
  311. static inline void auto_pause_activate(void) {
  312. System.tracking_auto_paused = 1;
  313. log_pause_event(1);
  314. beep(50, 3);
  315. }
  316. static inline void auto_pause_process(void) {
  317. if (System.tracking_paused || !get_flag(CONFFLAG_AUTO_PAUSE)) { /* remove auto-pause */
  318. System.tracking_auto_paused = 0;
  319. auto_pause.prev_distance = System.distance;
  320. auto_pause.point_counter = 0;
  321. auto_pause.speed_counter = 0;
  322. return;
  323. }
  324. if (System.speed >= System.conf.auto_pause_speed) { /* unpause when set speed is exceeded for 3 consecutive measurements */
  325. if (++auto_pause.speed_counter >= 3) {
  326. auto_pause.point_counter = 0;
  327. auto_pause.speed_counter = 0;
  328. auto_unpause();
  329. return;
  330. }
  331. } else {
  332. auto_pause.speed_counter = 0;
  333. }
  334. if (++auto_pause.point_counter < System.conf.auto_pause_time)
  335. return;
  336. auto_pause.point_counter = 0;
  337. if ((System.distance - auto_pause.prev_distance)/100 > System.conf.auto_pause_dist) {
  338. if (System.tracking_auto_paused)
  339. auto_unpause(); /* unpause when distance exceeded */
  340. } else {
  341. if (!System.tracking_auto_paused)
  342. auto_pause_activate(); /* pause otherwise */
  343. }
  344. auto_pause.prev_distance = System.distance;
  345. }
  346. void reset_counters(void) {
  347. System.distance = 0;
  348. System.elevation_gain = 0;
  349. System.elevation_loss = 0;
  350. System.elevation_gain_raw = 0;
  351. System.elevation_loss_raw = 0;
  352. System.alt_max = 0;
  353. System.speed_accum_x100 = 0;
  354. System.speed_sample_count = 0;
  355. System.points_written = 0;
  356. System.rejected_count = 0;
  357. System.bat_volt_min = 99.0;
  358. System.time_start = 0;
  359. System.current_pause_start = 0;
  360. System.pause_time = 0;
  361. }
  362. unsigned int get_avg_speed_x100(void) {
  363. if (!System.speed_sample_count)
  364. return 0;
  365. return System.speed_accum_x100 / System.speed_sample_count;
  366. }
  367. /* Average speed the "old" way (distance / moving time), kept only so it can
  368. * be logged alongside get_avg_speed_x100() in the session summary - the two
  369. * should track each other, and a growing gap is worth noticing. */
  370. unsigned int get_dist_avg_speed_x100(void) {
  371. unsigned int moving = get_logging_time();
  372. if (!moving)
  373. return 0;
  374. /* (distance_cm * 3.6) / moving_s, kept as an all-integer x100 fixed-point value */
  375. return (unsigned int)((unsigned long int)System.distance * 36UL / (10UL * moving));
  376. }
  377. time_t get_pause_time(void) {
  378. time_t res = System.pause_time;
  379. if (System.current_pause_start < System.time_start)
  380. System.current_pause_start = System.time_start; /* disallow negative pause time */
  381. if (is_paused() && System.current_pause_start)
  382. res += utc - System.current_pause_start;
  383. return res;
  384. }
  385. unsigned int get_logging_time(void) {
  386. if (!utc || !System.time_start)
  387. return 0;
  388. return utc - System.time_start - get_pause_time();
  389. }
  390. __flash const char __open_msg[] = "Open %s\r\n";
  391. /*-----------------------------------------------------------------------*/
  392. /* Main */
  393. /*-----------------------------------------------------------------------*/
  394. int main (void)
  395. {
  396. UINT bw, len;
  397. time_t tmp_utc, localtime;
  398. FRESULT res;
  399. unsigned char prev_status;
  400. unsigned char already_logging = 0;
  401. static unsigned char fix_ok_prev = 0;
  402. static unsigned char sbas_prev = 0xFF; /* 0xFF: not yet known, suppress the first (non-)transition */
  403. static unsigned long int last_summary_uptime = 0;
  404. ioinit();
  405. xdev_out(log_put);
  406. xputs_P(PSTR("STARTUP\r\n"));
  407. disp_init();
  408. display_event(DISPLAY_EVENT_STARTUP);
  409. settings_load();
  410. reset_counters();
  411. log_boot_record();
  412. menu_push(default_menu);
  413. for (;;) {
  414. wdt_reset();
  415. if (FLAGS & (F_POWEROFF | F_LVD)) {
  416. xputs_P(PSTR("POWEROFF\r\n"));
  417. display_event(DISPLAY_EVENT_POWEROFF);
  418. if (FLAGS & F_LVD) {
  419. display_event(DISPLAY_EVENT_LOW_BATTERY);
  420. _delay_ms(500);
  421. }
  422. POWEROFF();
  423. while (POWER_SW_PRESSED());
  424. _delay_ms(2000); /* wait for switch off */
  425. FLAGS &= ~F_POWEROFF; /* restart if power is not lost */
  426. POWERON();
  427. xputs_P(PSTR("RESTART\r\n"));
  428. }
  429. display_event(DISPLAY_EVENT_INITIALIZED);
  430. log_loop_status(System.status);
  431. utc = 0;
  432. localtime = 0;
  433. prev_status = System.status;
  434. System.status = STATUS_NO_POWER;
  435. beep(250, prev_status); /* Error beep */
  436. /* Wait for supply voltage stabled */
  437. _delay_ms(500);
  438. if (FLAGS & F_LVD)
  439. continue;
  440. /* report error here ( prev_status) */
  441. if (disk_status(0) & STA_NODISK) {
  442. System.status = STATUS_NO_DISK;
  443. continue;
  444. }
  445. res = f_mount(&Fatfs, "", 1);
  446. if (res != FR_OK) {
  447. xprintf(PSTR("FS error %u\r\n"), res);
  448. System.status = STATUS_DISK_ERROR;
  449. System.global_error |= ERROR_DISK;
  450. continue;
  451. }
  452. System.status = STATUS_NO_GPS;
  453. xputs(PSTR("FS Ok\r\n"));
  454. display_event(DISPLAY_EVENT_CARD_INITIALIZED);
  455. beep(50, 1); /* 1 beep */
  456. /* Initialize GPS receiver */
  457. GPS_ON(); /* GPS power on */
  458. FLAGS |= F_POW;
  459. _delay_ms(1);
  460. uart0_init(); /* Enable UART */
  461. _delay_ms(300); /* Delay */
  462. System.gps_initialized = 0;
  463. gps_powered_on();
  464. if (!already_logging && !get_flag(CONFFLAG_LOGGING_AFTER_BOOT)) {
  465. tracking_pause(TRACKING_PAUSE_CMD_PAUSE, 0);
  466. }
  467. for (;;) { /* main loop */
  468. wdt_reset();
  469. gettemp();
  470. /* Check temperature sensor after initialization */
  471. if ((FLAGS & F_GPSOK) && !System.temperature_ok) {
  472. System.global_error |= ERROR_TEMPERATURE;
  473. }
  474. menu();
  475. check_error_and_jump();
  476. display_refresh(0);
  477. if (no_menu())
  478. menu_push(default_menu); /* returned from top-level */
  479. if (System.timers.backlight)
  480. LEDW_ON();
  481. else
  482. LEDW_OFF();
  483. len = get_line(Line, sizeof Line); /* Receive a line from GPS receiver */
  484. if (!len){
  485. if (FLAGS & (F_LVD | F_POWEROFF))
  486. break; /* brownout */
  487. continue;
  488. }
  489. tmp_utc = gps_parse(Line);
  490. if (tmp_utc) {
  491. localtime = tmp_utc + local_time_diff(tmp_utc) * 3600L; /* Local time */
  492. LEDG_ON();
  493. _delay_ms(2);
  494. LEDG_OFF();
  495. }
  496. /* Battery low-water mark, for the session summary */
  497. if (System.bat_volt > 0 && System.bat_volt < System.bat_volt_min)
  498. System.bat_volt_min = System.bat_volt;
  499. /* Fix acquired/lost events (a "fix" requires both a valid GPS status and enough satellites) */
  500. {
  501. unsigned char fix_ok_now = (FLAGS & F_GPSOK) && !System.sat_count_low;
  502. if (fix_ok_now != fix_ok_prev) {
  503. if (fix_ok_now)
  504. log_fix_event();
  505. else
  506. log_fix_lost();
  507. fix_ok_prev = fix_ok_now;
  508. }
  509. }
  510. /* SBAS/DGPS on-off transitions */
  511. if (System.sbas != sbas_prev) {
  512. if (sbas_prev != 0xFF)
  513. log_sbas_transition();
  514. sbas_prev = System.sbas;
  515. }
  516. if (timer_expired(status_log)) {
  517. set_timer(status_log, 60000);
  518. log_status_line();
  519. }
  520. if (get_uptime_ms() - last_summary_uptime >= 3600000UL) {
  521. last_summary_uptime = get_uptime_ms();
  522. log_session_summary(0);
  523. }
  524. if (FLAGS & F_FILEOPEN) {
  525. {
  526. unsigned long int t0 = get_uptime_ms();
  527. f_write(&gps_log, Line, len-1, &bw);
  528. io_mark(t0);
  529. }
  530. if (bw != len-1) {
  531. System.status = STATUS_FILE_WRITE_ERROR;
  532. System.global_error |= ERROR_FILE_WRITE;
  533. break;
  534. }
  535. if (System.location_valid == LOC_VALID_NEW) { /* a new point */
  536. gpx_process_point(&location, &gpx_file);
  537. auto_pause_process();
  538. }
  539. wdt_reset();
  540. if (FLAGS & F_SYNC) {
  541. /* Sync all three log files together, on this same periodic
  542. * timer (IVT_SYNC), rather than after every write: an SD
  543. * f_sync() can stall for 100ms+ and must not happen on
  544. * every line, or it would stall the NMEA UART reception. */
  545. unsigned long int t0 = get_uptime_ms();
  546. unsigned char sync_err = f_sync(&gps_log);
  547. io_mark(t0);
  548. t0 = get_uptime_ms();
  549. sync_err |= f_sync(&gpx_file);
  550. io_mark(t0);
  551. t0 = get_uptime_ms();
  552. sync_err |= f_sync(&system_log);
  553. io_mark(t0);
  554. if (sync_err) {
  555. System.status = STATUS_FILE_SYNC_ERROR;
  556. System.global_error |= ERROR_FILE_SYNC;
  557. break;
  558. }
  559. FLAGS &= ~F_SYNC;
  560. }
  561. if (System.open_new_file) {
  562. close_files(1);
  563. System.open_new_file = 0;
  564. if (!System.tracking_paused)
  565. tracking_pause(TRACKING_PAUSE_CMD_PAUSE, 0);
  566. if (get_flag(CONFFLAG_RESET_ON_NEW_FILE))
  567. reset_counters();
  568. }
  569. if (!System.tracking_paused)
  570. already_logging = 1; /* to avoid pausing on any reset caused by some error */
  571. }
  572. if (System.location_valid == LOC_VALID_NEW) {
  573. System.location_valid = LOC_VALID;
  574. }
  575. if (localtime && !(FLAGS & F_FILEOPEN)) {
  576. char *time = get_iso_time(utc, 1);
  577. iso_time_to_filename(time);
  578. xsprintf(Line, PSTR("%s-NMEA.LOG"), time);
  579. xprintf(__open_msg, Line);
  580. wdt_disable();
  581. if (f_open(&gps_log, Line, FA_WRITE | FA_OPEN_ALWAYS) /* Open log file */
  582. || f_lseek(&gps_log, f_size(&gps_log)) /* Append mode */
  583. || f_write(&gps_log, "\r\n", 2, &bw)) /* Put a blank line as start marker */
  584. {
  585. System.status = STATUS_FILE_OPEN_ERROR;
  586. System.global_error |= ERROR_FILE_OPEN;
  587. break; /* Failed to start logging */
  588. }
  589. xsprintf(Line, PSTR("%s.GPX"), time);
  590. xprintf(__open_msg, Line);
  591. if (f_open(&gpx_file, Line, FA_WRITE | FA_OPEN_ALWAYS) /* Open log file */
  592. || f_lseek(&gpx_file, f_size(&gpx_file)) /* Append mode */
  593. || gpx_init(&gpx_file)) /* Put a blank line as start marker */
  594. {
  595. f_close(&gpx_file);
  596. System.status = STATUS_FILE_OPEN_ERROR;
  597. System.global_error |= ERROR_FILE_OPEN;
  598. break; /* Failed to start logging */
  599. }
  600. xsprintf(Line, PSTR("%s-SYSTEM.LOG"), time);
  601. xprintf(__open_msg, Line);
  602. if (f_open(&system_log, Line, FA_WRITE | FA_OPEN_ALWAYS) /* Open log file */
  603. || f_lseek(&system_log, f_size(&system_log)) /* Append mode */
  604. || f_write(&system_log, "\r\n", 2, &bw)) /* Put a blank line as start marker */
  605. {
  606. f_close(&gpx_file);
  607. f_close(&gps_log);
  608. System.status = STATUS_FILE_OPEN_ERROR;
  609. System.global_error |= ERROR_FILE_OPEN;
  610. break; /* Failed to start logging */
  611. }
  612. wdt_enable(WDTO_4S);
  613. FLAGS |= F_FILEOPEN;
  614. System.status = STATUS_OK;
  615. set_timer(status_log, 60000);
  616. last_summary_uptime = get_uptime_ms();
  617. beep(50, System.tracking_paused?8:2); /* Two beeps. Start logging. */
  618. display_event(DISPLAY_EVENT_FILE_OPEN);
  619. continue;
  620. }
  621. }
  622. wdt_enable(WDTO_4S);
  623. /* Stop GPS receiver */
  624. uart0_deinit();
  625. GPS_OFF();
  626. FLAGS &= ~F_POW;
  627. /* Close file */
  628. close_files(1);
  629. if (System.status != STATUS_FILE_CLOSE_ERROR)
  630. beep(500, 1); /* Long beep on file close succeeded */
  631. settings_store(); /* save eeprom data */
  632. }
  633. }