main.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  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. /* Number of consecutive epochs (nmea_epoch_complete() pulses) a new
  236. * fix-acquired/lost state must hold before it's logged - coalesces the rapid
  237. * flapping seen on marginal reception (e.g. 2D/3D/no-fix alternating for
  238. * about a minute) into at most one or two log lines instead of one per flip. */
  239. #define FIX_HOLD_EPOCHS 5
  240. #define LOG_SIZE 300
  241. struct {
  242. char buf[LOG_SIZE+1];
  243. unsigned int len;
  244. } logbuf;
  245. void log_put(int c){
  246. UINT bw;
  247. if (System.conf.uart_log_mode != UART_LOG_MODE_NMEA)
  248. uart1_put(c);
  249. logbuf.buf[logbuf.len++] = c;
  250. if (logbuf.len >= LOG_SIZE && (FLAGS & F_FILEOPEN)) {
  251. unsigned long int t0 = get_uptime_ms();
  252. unsigned char err = f_write(&system_log, logbuf.buf, logbuf.len, &bw);
  253. io_mark(t0);
  254. if (!err)
  255. logbuf.len = 0;
  256. }
  257. if (logbuf.len > LOG_SIZE) {
  258. logbuf.len--;
  259. }
  260. }
  261. static
  262. void ioinit (void)
  263. {
  264. wdt_enable(WDTO_4S); /* MCUSR was already cleared in wdt_disable_early() (.init3) */
  265. POWER_ON_DDR |= POWER_ON;
  266. PORTA |= POWER_ON;
  267. BUZZER_DDR |= BUZZER;
  268. GPS_OFF();
  269. GPS_DIS_DDR |= GPS_DIS;
  270. LEDR_DDR |= LEDR;
  271. OCR1A = F_CPU/8/100-1; /* Timer1: 100Hz interval (OC1A) */
  272. TCCR1B = _BV(WGM12) | _BV(CS11);
  273. TIMSK1 = _BV(OCIE1A); /* Enable TC1.oca interrupt */
  274. /* ADC */
  275. // ADMUX = 0;
  276. ADMUX = 1; // FIXME only testing battery voltage
  277. ADCSRA = _BV(ADEN)|_BV(ADATE)|_BV(ADIE)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0);
  278. /* uart1 (debug) */
  279. uart1_init();
  280. I2C_init();
  281. expander_init(0, 0x00, 0x00); /* all as outputs */
  282. LCD_Initialize();
  283. LCD_Clear();
  284. LCD_GoTo(0,0);
  285. wdt_reset();
  286. sei();
  287. ADCSRA |= _BV(ADSC);
  288. /* unused pins */
  289. DDRA |= _BV(PA2) | _BV(PA4) | _BV(PA5);
  290. PRR0 |= _BV(PRTIM2) | _BV(PRTIM0);
  291. ACSR = _BV(ACD); /* Disable analog comp */
  292. }
  293. void close_files(unsigned char flush_logs) {
  294. UINT bw;
  295. if (FLAGS & F_FILEOPEN) {
  296. if (flush_logs)
  297. log_session_summary(1);
  298. if (f_close(&gps_log)) {
  299. System.status = STATUS_FILE_CLOSE_ERROR;
  300. System.global_error |= ERROR_FILE_CLOSE;
  301. }
  302. if (gpx_close(&gpx_file)) {
  303. System.status = STATUS_FILE_CLOSE_ERROR;
  304. System.global_error |= ERROR_FILE_CLOSE;
  305. }
  306. if (flush_logs && logbuf.len && !f_write(&system_log, logbuf.buf, logbuf.len, &bw)) {
  307. logbuf.len = 0;
  308. }
  309. if (f_close(&system_log)) {
  310. System.status = STATUS_FILE_CLOSE_ERROR;
  311. System.global_error |= ERROR_FILE_CLOSE;
  312. }
  313. xputs_P(PSTR("File closed\r\n"));
  314. display_event(DISPLAY_EVENT_FILE_CLOSED);
  315. }
  316. FLAGS &= ~F_FILEOPEN;
  317. disk_ioctl(0, CTRL_POWER, 0);
  318. }
  319. void reset_counters(void) {
  320. System.distance = 0;
  321. System.elevation_gain = 0;
  322. System.elevation_loss = 0;
  323. System.elevation_gain_raw = 0;
  324. System.elevation_loss_raw = 0;
  325. System.alt_max = 0;
  326. System.speed_accum_x100 = 0;
  327. System.speed_sample_count = 0;
  328. System.points_written = 0;
  329. System.rejected_count = 0;
  330. System.points_paused = 0;
  331. System.points_skipped = 0;
  332. System.points_accepted = 0;
  333. System.bat_volt_min = 99.0;
  334. System.time_start = 0;
  335. System.current_pause_start = 0;
  336. System.pause_time = 0;
  337. }
  338. unsigned int get_avg_speed_x100(void) {
  339. if (!System.speed_sample_count)
  340. return 0;
  341. return System.speed_accum_x100 / System.speed_sample_count;
  342. }
  343. /* Average speed the "old" way (distance / moving time), kept only so it can
  344. * be logged alongside get_avg_speed_x100() in the session summary - the two
  345. * should track each other, and a growing gap is worth noticing. */
  346. unsigned int get_dist_avg_speed_x100(void) {
  347. unsigned int moving = get_logging_time();
  348. if (!moving)
  349. return 0;
  350. /* (distance_cm * 3.6) / moving_s, kept as an all-integer x100 fixed-point value */
  351. return (unsigned int)((unsigned long int)System.distance * 36UL / (10UL * moving));
  352. }
  353. /* A fix normally arrives about once a second; treat a longer gap between
  354. * accepted points as a fix having been lost and reacquired (regardless of
  355. * why the epochs in between were rejected/absent - fix loss, a 2D fix, poor
  356. * HDOP, or the receiver simply not producing lines). Shared by
  357. * gpx_process_point() (resets the Kalman/averaging warm-up, the same as
  358. * after power-on - a freshly reacquired fix can carry a wildly wrong
  359. * position/altitude for a few seconds) and auto_pause_process() (resets the
  360. * stationary-time counter - otherwise it keeps counting through the gap
  361. * with no visibility into how long the gap was or whether the device kept
  362. * moving during it, and can trip a pause within moments of reacquiring a
  363. * fix that was actually lost while the device was genuinely still moving).
  364. * Called at most once per accepted point (the main loop below calls it
  365. * before both), so a single static last-seen time is enough - two callers
  366. * checking independently would each need their own copy and could disagree
  367. * about where the gap boundary was. */
  368. #define FIX_GAP_SECONDS 3
  369. unsigned char fix_gap_detected(time_t point_time) {
  370. static time_t last_point_time = 0;
  371. unsigned char gap = last_point_time && point_time - last_point_time > FIX_GAP_SECONDS;
  372. last_point_time = point_time;
  373. return gap;
  374. }
  375. /* Call exactly once, at the moment tracking_paused/tracking_auto_paused
  376. * actually transitions to true (auto_pause_activate(), tracking_pause()) -
  377. * not deferred until the next accepted point, which may never come before
  378. * the pause ends (a near-stationary point, which is exactly what triggers a
  379. * pause, is also exactly what a min-distance/Kalman/distdiff reject in
  380. * gpx_process_point() would drop) or may come from a much later, unrelated
  381. * pause, corrupting current_pause_start into a stale value that then leaks
  382. * into get_pause_time() and the pause_time carried forward on resume. */
  383. void pause_time_start(void) {
  384. System.current_pause_start = utc;
  385. }
  386. /* Call exactly once, at the moment tracking_paused/tracking_auto_paused
  387. * actually transitions to false (auto_unpause(), tracking_pause()) - folds
  388. * this pause's duration into the permanent accumulator and clears the
  389. * start, so a later summary/query while not paused never reuses it. */
  390. void pause_time_end(void) {
  391. /* Same time_start floor as get_pause_time() - a pause that started (and
  392. * possibly also ended) before the first fix contributes no pause time,
  393. * since logging itself hadn't started yet either. */
  394. if (System.current_pause_start && System.current_pause_start >= System.time_start)
  395. System.pause_time += utc - System.current_pause_start;
  396. System.current_pause_start = 0;
  397. }
  398. time_t get_pause_time(void) {
  399. time_t res = System.pause_time;
  400. /* current_pause_start is 0 whenever there's no in-progress pause to add -
  401. * either genuinely not paused, or paused but reset_counters() cleared it
  402. * (along with time_start) after pause_time_start() ran for this pause.
  403. * The time_start floor guards the one remaining case reset_counters()
  404. * doesn't cover: pause_time_start() ran before the first fix (e.g. the
  405. * boot-time "don't log until moving" pause), leaving current_pause_start
  406. * at an earlier (possibly 0) utc than time_start - only time since
  407. * logging actually started counts as pause time. */
  408. if (is_paused() && System.current_pause_start && System.current_pause_start >= System.time_start)
  409. res += utc - System.current_pause_start;
  410. return res;
  411. }
  412. unsigned int get_logging_time(void) {
  413. if (!utc || !System.time_start)
  414. return 0;
  415. return utc - System.time_start - get_pause_time();
  416. }
  417. unsigned char tracking_is_paused(void) {
  418. return System.tracking_paused || System.tracking_auto_paused;
  419. }
  420. __flash const char __open_msg[] = "Open %s\r\n";
  421. /*-----------------------------------------------------------------------*/
  422. /* Main */
  423. /*-----------------------------------------------------------------------*/
  424. int main (void)
  425. {
  426. UINT bw, len;
  427. time_t tmp_utc, localtime;
  428. FRESULT res;
  429. unsigned char prev_status;
  430. unsigned char already_logging = 0;
  431. static unsigned char fix_ok_prev = 0;
  432. static unsigned char fix_hold_counter = 0;
  433. static unsigned char dgps_prev = 0xFF; /* 0xFF: not yet known, suppress the first (non-)transition */
  434. static unsigned long int last_summary_uptime = 0;
  435. ioinit();
  436. xdev_out(log_put);
  437. xputs_P(PSTR("STARTUP\r\n"));
  438. disp_init();
  439. display_event(DISPLAY_EVENT_STARTUP);
  440. settings_load();
  441. reset_counters();
  442. log_boot_record();
  443. request_immediate_sync(); /* flush the boot/config lines as soon as a log file opens, not after up to IVT_SYNC seconds */
  444. menu_push(default_menu);
  445. for (;;) {
  446. wdt_reset();
  447. if (FLAGS & (F_POWEROFF | F_LVD)) {
  448. xputs_P(PSTR("POWEROFF\r\n"));
  449. display_event(DISPLAY_EVENT_POWEROFF);
  450. if (FLAGS & F_LVD) {
  451. display_event(DISPLAY_EVENT_LOW_BATTERY);
  452. _delay_ms(500);
  453. }
  454. POWEROFF();
  455. while (POWER_SW_PRESSED());
  456. _delay_ms(2000); /* wait for switch off */
  457. FLAGS &= ~F_POWEROFF; /* restart if power is not lost */
  458. POWERON();
  459. xputs_P(PSTR("RESTART\r\n"));
  460. }
  461. display_event(DISPLAY_EVENT_INITIALIZED);
  462. log_loop_status(System.status);
  463. request_immediate_sync(); /* flush the just-logged loop/error status promptly */
  464. utc = 0;
  465. localtime = 0;
  466. prev_status = System.status;
  467. System.status = STATUS_NO_POWER;
  468. beep(250, prev_status); /* Error beep */
  469. /* Wait for supply voltage stabled */
  470. _delay_ms(500);
  471. if (FLAGS & F_LVD)
  472. continue;
  473. /* report error here ( prev_status) */
  474. if (disk_status(0) & STA_NODISK) {
  475. System.status = STATUS_NO_DISK;
  476. continue;
  477. }
  478. res = f_mount(&Fatfs, "", 1);
  479. if (res != FR_OK) {
  480. xprintf(PSTR("FS error %u\r\n"), res);
  481. System.status = STATUS_DISK_ERROR;
  482. System.global_error |= ERROR_DISK;
  483. continue;
  484. }
  485. System.status = STATUS_NO_GPS;
  486. xputs(PSTR("FS Ok\r\n"));
  487. display_event(DISPLAY_EVENT_CARD_INITIALIZED);
  488. beep(50, 1); /* 1 beep */
  489. /* Initialize GPS receiver */
  490. GPS_ON(); /* GPS power on */
  491. FLAGS |= F_POW;
  492. _delay_ms(1);
  493. uart0_init(); /* Enable UART */
  494. _delay_ms(300); /* Delay */
  495. System.gps_initialized = 0;
  496. gps_powered_on();
  497. if (!already_logging && !get_flag(CONFFLAG_LOGGING_AFTER_BOOT)) {
  498. tracking_pause(TRACKING_PAUSE_CMD_PAUSE, 0);
  499. }
  500. for (;;) { /* main loop */
  501. wdt_reset();
  502. gettemp();
  503. /* Check temperature sensor after initialization */
  504. if ((FLAGS & F_GPSOK) && !System.temperature_ok) {
  505. System.global_error |= ERROR_TEMPERATURE;
  506. }
  507. menu();
  508. check_error_and_jump();
  509. display_refresh(0);
  510. if (no_menu())
  511. menu_push(default_menu); /* returned from top-level */
  512. if (System.timers.backlight)
  513. LEDW_ON();
  514. else
  515. LEDW_OFF();
  516. len = get_line(Line, sizeof Line); /* Receive a line from GPS receiver */
  517. if (!len){
  518. if (FLAGS & (F_LVD | F_POWEROFF))
  519. break; /* brownout */
  520. continue;
  521. }
  522. tmp_utc = gps_parse(Line);
  523. if (tmp_utc) {
  524. localtime = tmp_utc + local_time_diff(tmp_utc) * 3600L; /* Local time */
  525. LEDG_ON();
  526. _delay_ms(2);
  527. LEDG_OFF();
  528. }
  529. /* Battery low-water mark, for the session summary */
  530. if (System.bat_volt > 0 && System.bat_volt < System.bat_volt_min)
  531. System.bat_volt_min = System.bat_volt;
  532. /* Fix acquired/lost events (a "fix" requires both a valid GPS status and enough
  533. * satellites). Gated on nmea_epoch_complete() so sats=/hdop= are never read from a
  534. * stale epoch, and debounced so a single bad epoch on marginal reception doesn't log
  535. * a FIX/FIX LOST pair by itself - the new state must hold for FIX_HOLD_EPOCHS epochs. */
  536. if (nmea_epoch_complete()) {
  537. unsigned char fix_ok_now = (FLAGS & F_GPSOK) && !System.sat_count_low;
  538. if (fix_ok_now == fix_ok_prev) {
  539. fix_hold_counter = 0;
  540. } else if (++fix_hold_counter >= FIX_HOLD_EPOCHS) {
  541. fix_hold_counter = 0;
  542. fix_ok_prev = fix_ok_now;
  543. if (fix_ok_now) {
  544. log_fix_event();
  545. } else {
  546. log_fix_lost();
  547. request_immediate_sync();
  548. }
  549. }
  550. }
  551. /* DGPS-quality-fix on-off transitions (the receiver's own doing,
  552. * e.g. from SBAS - not necessarily caused by our own SBAS-search
  553. * request, CONFFLAG_ENABLE_SBAS) */
  554. if (System.dgps != dgps_prev) {
  555. if (dgps_prev != 0xFF)
  556. log_dgps_transition();
  557. dgps_prev = System.dgps;
  558. }
  559. if (timer_expired(status_log)) {
  560. set_timer(status_log, 60000);
  561. log_status_line();
  562. }
  563. if (get_uptime_ms() - last_summary_uptime >= 3600000UL) {
  564. last_summary_uptime = get_uptime_ms();
  565. log_session_summary(0);
  566. }
  567. if (FLAGS & F_FILEOPEN) {
  568. {
  569. unsigned long int t0 = get_uptime_ms();
  570. f_write(&gps_log, Line, len-1, &bw);
  571. io_mark(t0);
  572. }
  573. if (bw != len-1) {
  574. System.status = STATUS_FILE_WRITE_ERROR;
  575. System.global_error |= ERROR_FILE_WRITE;
  576. break;
  577. }
  578. if (System.location_valid == LOC_VALID_NEW) { /* a new point */
  579. if (fix_gap_detected(location.time)) {
  580. auto_pause_reset_gap();
  581. gpx_reset_gap();
  582. }
  583. auto_pause_process();
  584. gpx_process_point(&location, &gpx_file);
  585. }
  586. wdt_reset();
  587. if (FLAGS & F_SYNC) {
  588. /* Sync all three log files together, on this same periodic
  589. * timer (IVT_SYNC), rather than after every write: an SD
  590. * f_sync() can stall for 100ms+ and must not happen on
  591. * every line, or it would stall the NMEA UART reception. */
  592. unsigned long int t0 = get_uptime_ms();
  593. unsigned char sync_err = f_sync(&gps_log);
  594. io_mark(t0);
  595. t0 = get_uptime_ms();
  596. sync_err |= f_sync(&gpx_file);
  597. io_mark(t0);
  598. t0 = get_uptime_ms();
  599. sync_err |= f_sync(&system_log);
  600. io_mark(t0);
  601. if (sync_err) {
  602. System.status = STATUS_FILE_SYNC_ERROR;
  603. System.global_error |= ERROR_FILE_SYNC;
  604. break;
  605. }
  606. FLAGS &= ~F_SYNC;
  607. }
  608. if (System.open_new_file) {
  609. close_files(1);
  610. System.open_new_file = 0;
  611. if (!System.tracking_paused)
  612. tracking_pause(TRACKING_PAUSE_CMD_PAUSE, 0);
  613. if (get_flag(CONFFLAG_RESET_ON_NEW_FILE))
  614. reset_counters();
  615. }
  616. if (!System.tracking_paused)
  617. already_logging = 1; /* to avoid pausing on any reset caused by some error */
  618. }
  619. if (System.location_valid == LOC_VALID_NEW) {
  620. System.location_valid = LOC_VALID;
  621. }
  622. if (localtime && !(FLAGS & F_FILEOPEN)) {
  623. char *time = get_iso_time(utc, 1);
  624. iso_time_to_filename(time);
  625. xsprintf(Line, PSTR("%s-NMEA.LOG"), time);
  626. xprintf(__open_msg, Line);
  627. wdt_disable();
  628. if (f_open(&gps_log, Line, FA_WRITE | FA_OPEN_ALWAYS) /* Open log file */
  629. || f_lseek(&gps_log, f_size(&gps_log)) /* Append mode */
  630. || f_write(&gps_log, "\r\n", 2, &bw)) /* Put a blank line as start marker */
  631. {
  632. System.status = STATUS_FILE_OPEN_ERROR;
  633. System.global_error |= ERROR_FILE_OPEN;
  634. break; /* Failed to start logging */
  635. }
  636. xsprintf(Line, PSTR("%s.GPX"), time);
  637. xprintf(__open_msg, Line);
  638. if (f_open(&gpx_file, Line, FA_WRITE | FA_OPEN_ALWAYS) /* Open log file */
  639. || f_lseek(&gpx_file, f_size(&gpx_file)) /* Append mode */
  640. || gpx_init(&gpx_file)) /* Put a blank line as start marker */
  641. {
  642. f_close(&gpx_file);
  643. System.status = STATUS_FILE_OPEN_ERROR;
  644. System.global_error |= ERROR_FILE_OPEN;
  645. break; /* Failed to start logging */
  646. }
  647. xsprintf(Line, PSTR("%s-SYSTEM.LOG"), time);
  648. xprintf(__open_msg, Line);
  649. if (f_open(&system_log, Line, FA_WRITE | FA_OPEN_ALWAYS) /* Open log file */
  650. || f_lseek(&system_log, f_size(&system_log)) /* Append mode */
  651. || f_write(&system_log, "\r\n", 2, &bw)) /* Put a blank line as start marker */
  652. {
  653. f_close(&gpx_file);
  654. f_close(&gps_log);
  655. System.status = STATUS_FILE_OPEN_ERROR;
  656. System.global_error |= ERROR_FILE_OPEN;
  657. break; /* Failed to start logging */
  658. }
  659. wdt_enable(WDTO_4S);
  660. FLAGS |= F_FILEOPEN;
  661. System.status = STATUS_OK;
  662. set_timer(status_log, 60000);
  663. last_summary_uptime = get_uptime_ms();
  664. beep(50, System.tracking_paused?8:2); /* Two beeps. Start logging. */
  665. display_event(DISPLAY_EVENT_FILE_OPEN);
  666. continue;
  667. }
  668. }
  669. wdt_enable(WDTO_4S);
  670. /* Stop GPS receiver */
  671. uart0_deinit();
  672. GPS_OFF();
  673. FLAGS &= ~F_POW;
  674. /* Close file */
  675. close_files(1);
  676. if (System.status != STATUS_FILE_CLOSE_ERROR)
  677. beep(500, 1); /* Long beep on file close succeeded */
  678. settings_store(); /* save eeprom data */
  679. }
  680. }