GPS device with text LCD display and track logging to GPX file on SD Card
Dependencies: MODGPS SDFileSystem TextLCD mbed
- Haicom HI-203E Serial GPS Receiver
- Text LCD Display 2x40 (1x HD44780, 4x HD44100)
- RS-232 Level Shifter (MAX232)
- Adafruit Micro-SD breakout board+
mbed Pin # | mbed Pin Function | Peripheral Pin |
---|---|---|
p5 | SPI MOSI / SDFileSystem | SD Card Data In |
p6 | SPI MISO / SDFileSystem | SD Card Data Out |
p7 | SPI SCK / SDFileSystem | SD Card Clk |
p8 | SPI CS / SDFileSystem | SD Card Data CS |
p12 | GPIO / TextLCD | LCD RS |
p14 | GPIO / TextLCD | LCD EN |
p21 | GPIO / InterruptIn | Button switch to GND (start/stop logging) |
p22 | GPIO / TextLCD | LCD D4 |
p23 | GPIO / TextLCD | LCD D5 |
p24 | GPIO / TextLCD | LCD D6 |
p25 | GPIO / TextLCD | LCD D7 |
p27 | UART RX / GPS | GPS TX |
main.cpp@1:1b62ee4c7e05, 2013-02-17 (annotated)
- Committer:
- mprinke
- Date:
- Sun Feb 17 17:42:16 2013 +0000
- Revision:
- 1:1b62ee4c7e05
- Parent:
- 0:e8ad47e9a9b4
initial version
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mprinke | 0:e8ad47e9a9b4 | 1 | /* mbed GPS Logger using SD Card and Text LCD display |
mprinke | 0:e8ad47e9a9b4 | 2 | * |
mprinke | 0:e8ad47e9a9b4 | 3 | * Copyright (c) 2013 m.prinke, MIT License |
mprinke | 0:e8ad47e9a9b4 | 4 | * |
mprinke | 0:e8ad47e9a9b4 | 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software |
mprinke | 0:e8ad47e9a9b4 | 6 | * and associated documentation files (the "Software"), to deal in the Software without restriction, |
mprinke | 0:e8ad47e9a9b4 | 7 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, |
mprinke | 0:e8ad47e9a9b4 | 8 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is |
mprinke | 0:e8ad47e9a9b4 | 9 | * furnished to do so, subject to the following conditions: |
mprinke | 0:e8ad47e9a9b4 | 10 | * |
mprinke | 0:e8ad47e9a9b4 | 11 | * The above copyright notice and this permission notice shall be included in all copies or |
mprinke | 0:e8ad47e9a9b4 | 12 | * substantial portions of the Software. |
mprinke | 0:e8ad47e9a9b4 | 13 | * |
mprinke | 0:e8ad47e9a9b4 | 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING |
mprinke | 0:e8ad47e9a9b4 | 15 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
mprinke | 0:e8ad47e9a9b4 | 16 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
mprinke | 0:e8ad47e9a9b4 | 17 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
mprinke | 0:e8ad47e9a9b4 | 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
mprinke | 0:e8ad47e9a9b4 | 19 | * |
mprinke | 0:e8ad47e9a9b4 | 20 | * @file main.cpp |
mprinke | 0:e8ad47e9a9b4 | 21 | * @purpose GPS Logger using SD Card and Text LCD display |
mprinke | 0:e8ad47e9a9b4 | 22 | * @version 0.1 |
mprinke | 0:e8ad47e9a9b4 | 23 | * @date Feb 2013 |
mprinke | 0:e8ad47e9a9b4 | 24 | * @author M. Prinke |
mprinke | 0:e8ad47e9a9b4 | 25 | */ |
mprinke | 0:e8ad47e9a9b4 | 26 | /** |
mprinke | 0:e8ad47e9a9b4 | 27 | * Time and position data from GPS receiver is displayed on a text LCD. |
mprinke | 0:e8ad47e9a9b4 | 28 | * GPS tracks can be written to a logfile (GPX format) on SD Card. |
mprinke | 0:e8ad47e9a9b4 | 29 | * Logging is started/stopped using a toggle button. |
mprinke | 0:e8ad47e9a9b4 | 30 | * Everytime logging is started, a new file with the filename pattern /sd/gpslog<nnnn>.gpx |
mprinke | 0:e8ad47e9a9b4 | 31 | * is created, where <nnnn> is decimal number in the range 0000 to 9999 which is incremented. |
mprinke | 0:e8ad47e9a9b4 | 32 | * Searching for a new unique filename is started from zero. |
mprinke | 0:e8ad47e9a9b4 | 33 | * |
mprinke | 0:e8ad47e9a9b4 | 34 | * LED1: GPS status (blinking: fix invalid; on: fix valid) |
mprinke | 0:e8ad47e9a9b4 | 35 | * LED2: Logging status (off: stopped; on: logging) |
mprinke | 0:e8ad47e9a9b4 | 36 | * |
mprinke | 0:e8ad47e9a9b4 | 37 | * To Do: |
mprinke | 0:e8ad47e9a9b4 | 38 | * - Adjustable logging cycle time (read from config file on SD Card?) |
mprinke | 0:e8ad47e9a9b4 | 39 | * - Start new track segment after loss of GPS fix |
mprinke | 0:e8ad47e9a9b4 | 40 | * - Add support for GSA message (2D/3D fix, dilution of precision) |
mprinke | 0:e8ad47e9a9b4 | 41 | */ |
mprinke | 0:e8ad47e9a9b4 | 42 | |
mprinke | 0:e8ad47e9a9b4 | 43 | #include "mbed.h" |
mprinke | 0:e8ad47e9a9b4 | 44 | #include "GPS.h" |
mprinke | 0:e8ad47e9a9b4 | 45 | #include "TextLCD.h" |
mprinke | 0:e8ad47e9a9b4 | 46 | #include "SDFileSystem.h" |
mprinke | 0:e8ad47e9a9b4 | 47 | |
mprinke | 0:e8ad47e9a9b4 | 48 | #define GPS_BAUDRATE 4800 |
mprinke | 0:e8ad47e9a9b4 | 49 | #define LOGGING_CYCLE_SEC 5 |
mprinke | 0:e8ad47e9a9b4 | 50 | |
mprinke | 0:e8ad47e9a9b4 | 51 | DigitalOut led_fix(LED1); // GPS fix (blinking - no data/no fix; on: fix) |
mprinke | 0:e8ad47e9a9b4 | 52 | DigitalOut led_log(LED2); // logging active |
mprinke | 0:e8ad47e9a9b4 | 53 | InterruptIn button(p21); // button connects pin to GND |
mprinke | 0:e8ad47e9a9b4 | 54 | Serial pc(USBTX, USBRX); // tx, rx |
mprinke | 0:e8ad47e9a9b4 | 55 | GPS gps(NC, p27); // tx, rx |
mprinke | 0:e8ad47e9a9b4 | 56 | TextLCD lcd(p12, p14, p22, p23, p24, p25, TextLCD::LCD40x2); // rs, e, d4-d7 |
mprinke | 0:e8ad47e9a9b4 | 57 | SDFileSystem sd(p5, p6, p7, p8, "sd"); // mosi, miso, sclk, cs |
mprinke | 0:e8ad47e9a9b4 | 58 | |
mprinke | 0:e8ad47e9a9b4 | 59 | bool g_logging = false; |
mprinke | 0:e8ad47e9a9b4 | 60 | bool g_changed = false; |
mprinke | 0:e8ad47e9a9b4 | 61 | uint32_t g_trkpt_no = 0; |
mprinke | 0:e8ad47e9a9b4 | 62 | |
mprinke | 0:e8ad47e9a9b4 | 63 | /** |
mprinke | 0:e8ad47e9a9b4 | 64 | * Function to create a unique filename |
mprinke | 0:e8ad47e9a9b4 | 65 | * |
mprinke | 0:e8ad47e9a9b4 | 66 | * @param fn pointer to a filename buffer |
mprinke | 0:e8ad47e9a9b4 | 67 | * @param number part of filename (returned by reference) |
mprinke | 0:e8ad47e9a9b4 | 68 | * @return 0 on success, -1 if no unused filename could be created. |
mprinke | 0:e8ad47e9a9b4 | 69 | */ |
mprinke | 0:e8ad47e9a9b4 | 70 | int get_filename(char *fn, uint16_t *number) |
mprinke | 0:e8ad47e9a9b4 | 71 | { |
mprinke | 0:e8ad47e9a9b4 | 72 | FILE *fp; |
mprinke | 0:e8ad47e9a9b4 | 73 | |
mprinke | 0:e8ad47e9a9b4 | 74 | for (int n=0; n < 9999; n++) { |
mprinke | 0:e8ad47e9a9b4 | 75 | sprintf(fn, "/sd/gpslog%04d.gpx", n); |
mprinke | 0:e8ad47e9a9b4 | 76 | if ((fp = fopen(fn, "r")) == NULL) { |
mprinke | 0:e8ad47e9a9b4 | 77 | *number = n; |
mprinke | 0:e8ad47e9a9b4 | 78 | // file does not exist yet |
mprinke | 0:e8ad47e9a9b4 | 79 | return 0; |
mprinke | 0:e8ad47e9a9b4 | 80 | } else { |
mprinke | 0:e8ad47e9a9b4 | 81 | fclose(fp); |
mprinke | 0:e8ad47e9a9b4 | 82 | } |
mprinke | 0:e8ad47e9a9b4 | 83 | } |
mprinke | 0:e8ad47e9a9b4 | 84 | |
mprinke | 0:e8ad47e9a9b4 | 85 | // filename pattern exhausted |
mprinke | 0:e8ad47e9a9b4 | 86 | return -1; |
mprinke | 0:e8ad47e9a9b4 | 87 | } |
mprinke | 0:e8ad47e9a9b4 | 88 | |
mprinke | 0:e8ad47e9a9b4 | 89 | /** |
mprinke | 0:e8ad47e9a9b4 | 90 | * Callback function for button interrupt |
mprinke | 0:e8ad47e9a9b4 | 91 | * |
mprinke | 0:e8ad47e9a9b4 | 92 | * Debounce button and set change flag. |
mprinke | 0:e8ad47e9a9b4 | 93 | */ |
mprinke | 0:e8ad47e9a9b4 | 94 | void change_logging(void) |
mprinke | 0:e8ad47e9a9b4 | 95 | { |
mprinke | 0:e8ad47e9a9b4 | 96 | wait_ms(50); // button debounce |
mprinke | 0:e8ad47e9a9b4 | 97 | while (!button); // wait until button released |
mprinke | 0:e8ad47e9a9b4 | 98 | g_changed = true; |
mprinke | 0:e8ad47e9a9b4 | 99 | } |
mprinke | 0:e8ad47e9a9b4 | 100 | |
mprinke | 0:e8ad47e9a9b4 | 101 | /** |
mprinke | 0:e8ad47e9a9b4 | 102 | * Write GPX file header (including start of track segment) |
mprinke | 0:e8ad47e9a9b4 | 103 | * |
mprinke | 0:e8ad47e9a9b4 | 104 | * @param fp file pointer |
mprinke | 0:e8ad47e9a9b4 | 105 | * @param t time structure |
mprinke | 0:e8ad47e9a9b4 | 106 | * @param fileno file number |
mprinke | 0:e8ad47e9a9b4 | 107 | * @return result of last file write access |
mprinke | 0:e8ad47e9a9b4 | 108 | */ |
mprinke | 0:e8ad47e9a9b4 | 109 | int write_gpx_header(FILE *fp, GPS_Time t, uint16_t fileno) |
mprinke | 0:e8ad47e9a9b4 | 110 | { |
mprinke | 0:e8ad47e9a9b4 | 111 | g_trkpt_no = 0; //< reset trackpoint number |
mprinke | 0:e8ad47e9a9b4 | 112 | |
mprinke | 0:e8ad47e9a9b4 | 113 | fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); |
mprinke | 0:e8ad47e9a9b4 | 114 | fprintf(fp, "<gpx\n"); |
mprinke | 0:e8ad47e9a9b4 | 115 | fprintf(fp, " version=\"1.0\"\n"); |
mprinke | 0:e8ad47e9a9b4 | 116 | fprintf(fp, " creator=\"mbed GPS Logger\"\n"); |
mprinke | 0:e8ad47e9a9b4 | 117 | fprintf(fp, " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"); |
mprinke | 0:e8ad47e9a9b4 | 118 | fprintf(fp, " xmlns=\"http://www.topografix.com/GPX/1/0\"\n"); |
mprinke | 0:e8ad47e9a9b4 | 119 | fprintf(fp, " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">\n"); |
mprinke | 0:e8ad47e9a9b4 | 120 | fprintf(fp, "<time>%04d-%02d-%02dT%02d:%02d:%02dZ</time>\n", t.year, t.month, t.day, t.hour, t.minute, t.second); |
mprinke | 0:e8ad47e9a9b4 | 121 | fprintf(fp, "<trk>\n"); |
mprinke | 0:e8ad47e9a9b4 | 122 | fprintf(fp, " <name>track%04d</name>\n", fileno); |
mprinke | 0:e8ad47e9a9b4 | 123 | return fprintf(fp, "<trkseg>\n"); |
mprinke | 0:e8ad47e9a9b4 | 124 | } |
mprinke | 0:e8ad47e9a9b4 | 125 | |
mprinke | 0:e8ad47e9a9b4 | 126 | /** |
mprinke | 0:e8ad47e9a9b4 | 127 | * Write GPX trackpoint - add your geo-referenced data here |
mprinke | 0:e8ad47e9a9b4 | 128 | * |
mprinke | 0:e8ad47e9a9b4 | 129 | * @param fp file pointer |
mprinke | 0:e8ad47e9a9b4 | 130 | * @param t time structure |
mprinke | 0:e8ad47e9a9b4 | 131 | * @return result of last file write access |
mprinke | 0:e8ad47e9a9b4 | 132 | */ |
mprinke | 0:e8ad47e9a9b4 | 133 | int write_gpx_trkpt(FILE *fp, GPS_Time t) |
mprinke | 0:e8ad47e9a9b4 | 134 | { |
mprinke | 0:e8ad47e9a9b4 | 135 | fprintf(fp, " <trkpt lat=\"%.4f\" lon=\"%.4f\">\n", gps.latitude(), gps.longitude()); |
mprinke | 0:e8ad47e9a9b4 | 136 | fprintf(fp, " <ele>%.1f</ele>\n", gps.altitude() * 1000.0); |
mprinke | 0:e8ad47e9a9b4 | 137 | fprintf(fp, " <time>%04d-%02d-%02dT%02d:%02d:%02dZ</time>\n", t.year, t.month, t.day, t.hour, t.minute, t.second); |
mprinke | 0:e8ad47e9a9b4 | 138 | fprintf(fp, " <name>TP%06d</name>\n", g_trkpt_no++); |
mprinke | 0:e8ad47e9a9b4 | 139 | return fprintf(fp, " </trkpt>\n"); |
mprinke | 0:e8ad47e9a9b4 | 140 | } |
mprinke | 0:e8ad47e9a9b4 | 141 | |
mprinke | 0:e8ad47e9a9b4 | 142 | /** |
mprinke | 0:e8ad47e9a9b4 | 143 | * Write GPX file footer (including end of track segment) |
mprinke | 0:e8ad47e9a9b4 | 144 | * |
mprinke | 0:e8ad47e9a9b4 | 145 | * @param fp file pointer |
mprinke | 0:e8ad47e9a9b4 | 146 | * @return result of last file write access |
mprinke | 0:e8ad47e9a9b4 | 147 | */ |
mprinke | 0:e8ad47e9a9b4 | 148 | int write_gpx_footer(FILE *fp) |
mprinke | 0:e8ad47e9a9b4 | 149 | { |
mprinke | 0:e8ad47e9a9b4 | 150 | fprintf(fp, "</trkseg>\n"); |
mprinke | 0:e8ad47e9a9b4 | 151 | fprintf(fp, "</trk>\n"); |
mprinke | 0:e8ad47e9a9b4 | 152 | return fprintf(fp, "</gpx>\n"); |
mprinke | 0:e8ad47e9a9b4 | 153 | } |
mprinke | 0:e8ad47e9a9b4 | 154 | |
mprinke | 0:e8ad47e9a9b4 | 155 | |
mprinke | 0:e8ad47e9a9b4 | 156 | int main() { |
mprinke | 0:e8ad47e9a9b4 | 157 | GPS_Time t; |
mprinke | 0:e8ad47e9a9b4 | 158 | char filename[30]; |
mprinke | 0:e8ad47e9a9b4 | 159 | uint16_t fileno; |
mprinke | 0:e8ad47e9a9b4 | 160 | FILE *fp = NULL; |
mprinke | 0:e8ad47e9a9b4 | 161 | uint16_t log_wait = 0; |
mprinke | 0:e8ad47e9a9b4 | 162 | |
mprinke | 0:e8ad47e9a9b4 | 163 | button.mode(PullUp); |
mprinke | 0:e8ad47e9a9b4 | 164 | button.fall(&change_logging); |
mprinke | 0:e8ad47e9a9b4 | 165 | gps.baud(GPS_BAUDRATE); |
mprinke | 0:e8ad47e9a9b4 | 166 | lcd.cls(); |
mprinke | 0:e8ad47e9a9b4 | 167 | |
mprinke | 0:e8ad47e9a9b4 | 168 | while (1) { |
mprinke | 0:e8ad47e9a9b4 | 169 | // Wait for the GPS NMEA data to become valid. |
mprinke | 0:e8ad47e9a9b4 | 170 | // (Status flag in RMC message) |
mprinke | 0:e8ad47e9a9b4 | 171 | while (!gps.isTimeValid()) { |
mprinke | 0:e8ad47e9a9b4 | 172 | led_fix = !led_fix; |
mprinke | 0:e8ad47e9a9b4 | 173 | lcd.locate(21, 0); |
mprinke | 0:e8ad47e9a9b4 | 174 | lcd.printf("[no fix]"); |
mprinke | 0:e8ad47e9a9b4 | 175 | wait(1); |
mprinke | 0:e8ad47e9a9b4 | 176 | } |
mprinke | 0:e8ad47e9a9b4 | 177 | |
mprinke | 0:e8ad47e9a9b4 | 178 | gps.timeNow(&t); |
mprinke | 0:e8ad47e9a9b4 | 179 | #if defined(DEBUG) |
mprinke | 0:e8ad47e9a9b4 | 180 | pc.printf("The time/date is %02d:%02d:%02d %02d/%02d/%04d\r\n", |
mprinke | 0:e8ad47e9a9b4 | 181 | t.hour, t.minute, t.second, t.day, t.month, t.year); |
mprinke | 0:e8ad47e9a9b4 | 182 | #endif |
mprinke | 0:e8ad47e9a9b4 | 183 | lcd.locate(0, 0); |
mprinke | 0:e8ad47e9a9b4 | 184 | lcd.printf("%02d:%02d:%02d %02d/%02d/%04d %9s %10s", |
mprinke | 0:e8ad47e9a9b4 | 185 | t.hour, t.minute, t.second, t.day, t.month, t.year, |
mprinke | 0:e8ad47e9a9b4 | 186 | (gps.getGPSquality() > 0 ? "[fix] " : "[no fix]"), |
mprinke | 0:e8ad47e9a9b4 | 187 | (g_logging ? "[logging]" : "[stopped]")); |
mprinke | 0:e8ad47e9a9b4 | 188 | |
mprinke | 0:e8ad47e9a9b4 | 189 | // Check if at least four satellites produce a position fix and a valid quality. |
mprinke | 0:e8ad47e9a9b4 | 190 | if (gps.numOfSats() < 4 && gps.getGPSquality() != 0) { |
mprinke | 0:e8ad47e9a9b4 | 191 | // No fix or poor quality |
mprinke | 0:e8ad47e9a9b4 | 192 | led_fix = !led_fix; |
mprinke | 0:e8ad47e9a9b4 | 193 | } else { |
mprinke | 0:e8ad47e9a9b4 | 194 | // Fix valid and good quality |
mprinke | 0:e8ad47e9a9b4 | 195 | led_fix = 1; |
mprinke | 0:e8ad47e9a9b4 | 196 | #if defined(DEBUG) |
mprinke | 0:e8ad47e9a9b4 | 197 | pc.printf("Lat = %.4f Lon = %.4f Alt = %.1fkm\r\n", |
mprinke | 0:e8ad47e9a9b4 | 198 | gps.latitude(), gps.longitude(), gps.altitude()); |
mprinke | 0:e8ad47e9a9b4 | 199 | #endif |
mprinke | 0:e8ad47e9a9b4 | 200 | lcd.locate(0, 1); |
mprinke | 0:e8ad47e9a9b4 | 201 | lcd.printf("Lat: %07.4f Lon: %08.4f Alt: %.0fm ", |
mprinke | 0:e8ad47e9a9b4 | 202 | gps.latitude(), gps.longitude(), gps.altitude() * 1000.0); |
mprinke | 0:e8ad47e9a9b4 | 203 | |
mprinke | 0:e8ad47e9a9b4 | 204 | if (g_logging) { |
mprinke | 0:e8ad47e9a9b4 | 205 | if (log_wait-- == 0) { |
mprinke | 0:e8ad47e9a9b4 | 206 | log_wait = LOGGING_CYCLE_SEC - 1; |
mprinke | 0:e8ad47e9a9b4 | 207 | if (write_gpx_trkpt(fp, t) < 0) { |
mprinke | 0:e8ad47e9a9b4 | 208 | // write error |
mprinke | 0:e8ad47e9a9b4 | 209 | fclose(fp); |
mprinke | 0:e8ad47e9a9b4 | 210 | g_logging = false; |
mprinke | 0:e8ad47e9a9b4 | 211 | led_log = 0; |
mprinke | 0:e8ad47e9a9b4 | 212 | } |
mprinke | 0:e8ad47e9a9b4 | 213 | } |
mprinke | 0:e8ad47e9a9b4 | 214 | } |
mprinke | 0:e8ad47e9a9b4 | 215 | } |
mprinke | 0:e8ad47e9a9b4 | 216 | wait(1); |
mprinke | 0:e8ad47e9a9b4 | 217 | |
mprinke | 0:e8ad47e9a9b4 | 218 | // Logging state changed |
mprinke | 0:e8ad47e9a9b4 | 219 | if (g_changed) { |
mprinke | 0:e8ad47e9a9b4 | 220 | if (!g_logging) { |
mprinke | 0:e8ad47e9a9b4 | 221 | // Start logging |
mprinke | 0:e8ad47e9a9b4 | 222 | if (get_filename(filename, &fileno) != 0) { |
mprinke | 0:e8ad47e9a9b4 | 223 | error("Could not create file with unique name\n"); |
mprinke | 0:e8ad47e9a9b4 | 224 | } else { |
mprinke | 0:e8ad47e9a9b4 | 225 | // open file for writing |
mprinke | 0:e8ad47e9a9b4 | 226 | fp = fopen(filename, "w"); |
mprinke | 0:e8ad47e9a9b4 | 227 | if (fp == NULL) { |
mprinke | 0:e8ad47e9a9b4 | 228 | error("Could not open file for write\n"); |
mprinke | 0:e8ad47e9a9b4 | 229 | } else { |
mprinke | 0:e8ad47e9a9b4 | 230 | if (write_gpx_header(fp, t, fileno)) { |
mprinke | 0:e8ad47e9a9b4 | 231 | g_logging = true; |
mprinke | 0:e8ad47e9a9b4 | 232 | led_log = 1; |
mprinke | 0:e8ad47e9a9b4 | 233 | } |
mprinke | 0:e8ad47e9a9b4 | 234 | } |
mprinke | 0:e8ad47e9a9b4 | 235 | } |
mprinke | 0:e8ad47e9a9b4 | 236 | } else { |
mprinke | 0:e8ad47e9a9b4 | 237 | // Stop logging |
mprinke | 0:e8ad47e9a9b4 | 238 | write_gpx_footer(fp); |
mprinke | 0:e8ad47e9a9b4 | 239 | // close file |
mprinke | 0:e8ad47e9a9b4 | 240 | fclose(fp); |
mprinke | 0:e8ad47e9a9b4 | 241 | g_logging = false; |
mprinke | 0:e8ad47e9a9b4 | 242 | led_log = 0; |
mprinke | 0:e8ad47e9a9b4 | 243 | } |
mprinke | 0:e8ad47e9a9b4 | 244 | g_changed = false; |
mprinke | 0:e8ad47e9a9b4 | 245 | } // if (changed) |
mprinke | 0:e8ad47e9a9b4 | 246 | |
mprinke | 0:e8ad47e9a9b4 | 247 | } // while (1) |
mprinke | 0:e8ad47e9a9b4 | 248 | } |