main.c 19 KB

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