4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
35 * A portable GPS locator / geocaching finder using the Cortex-M3 based
36 * Luminary Micro LM3S1968 evaluation board.
38 * \author Andrea Righi <arighi@develer.com>
43 #include <drv/lcd_rit128x96.h>
44 #include <drv/timer.h>
46 #include <drv/flash_lm3s.h>
49 #include <kern/proc.h>
56 #include <gfx/gfx_p.h> /* BM_PLOT() */
64 #define KEY_MASK (K_UP | K_DOWN | K_LEFT | K_RIGHT | K_OK)
65 extern Font font_gohu;
66 static uint8_t raster[RAST_SIZE(LCD_WIDTH, LCD_HEIGHT)];
67 static Bitmap lcd_bitmap;
69 #define SCRSVR_TIME 60000
70 static ticks_t scrsvr_timestamp;
71 static bool is_lcd_off;
73 /* Serial and NMEA stuff */
74 static Serial ser_port;
75 static nmeap_context_t nmea;
79 static bool nmea_update;
83 static long target_lat, target_lon;
86 #define GPS_POS_MAGIC 0xdeadbeef
87 static FlashLM3S flash;
89 static void flash_load_target(void)
93 kfile_seek(&flash.fd, -FLASH_PAGE_SIZE_BYTES, KSM_SEEK_END);
94 kfile_read(&flash.fd, &magic, sizeof(magic));
95 if (magic == GPS_POS_MAGIC)
97 kfile_read(&flash.fd, &target_lat, sizeof(target_lat));
98 kfile_read(&flash.fd, &target_lon, sizeof(target_lon));
102 static void flash_save_target(void)
104 const uint32_t magic = GPS_POS_MAGIC;
106 kfile_seek(&flash.fd, -FLASH_PAGE_SIZE_BYTES, KSM_SEEK_END);
107 kfile_write(&flash.fd, &magic, sizeof(magic));
108 kfile_write(&flash.fd, &target_lat, sizeof(target_lat));
109 kfile_write(&flash.fd, &target_lon, sizeof(target_lon));
110 kfile_flush(&flash.fd);
113 /* Status LED management */
114 static void led_init(void)
116 SYSCTL_RCGC2_R = SYSCTL_RCGC2_GPIOG;
117 (void)SYSCTL_RCGC2_R;
118 GPIO_PORTG_DIR_R = 0x04;
119 GPIO_PORTG_DEN_R = 0x04;
122 INLINE void led_on(void)
124 GPIO_PORTG_DATA_R |= 0x04;
127 INLINE void led_off(void)
129 GPIO_PORTG_DATA_R &= ~0x04;
132 /* Display management */
133 INLINE void video_off(void)
135 unsigned long delta =
136 (long)ticks_to_ms(timer_clock_unlocked()) -
137 (long)scrsvr_timestamp;
139 if (!is_lcd_off && delta > SCRSVR_TIME)
146 INLINE void video_on(void)
153 scrsvr_timestamp = ticks_to_ms(timer_clock_unlocked());
156 INLINE void repaint(Bitmap *bm)
158 rit128x96_blitBitmap(bm);
161 INLINE keymask_t keypad_peek(void)
163 keymask_t key = kbd_peek();
174 /* Status LED thread */
175 static void NORETURN led_process(void)
193 static void nmea_callback(nmeap_context_t *context, void *data, void *user_data)
199 lat = (long)gga.latitude;
200 lon = (long)gga.longitude;
205 static void NORETURN ser_process(void)
209 nmea_poll(&nmea, &ser_port.fd);
210 kfile_clearerr(&ser_port.fd);
214 /* Target position screen */
215 static void target(Bitmap *bm)
217 const long STEP = 10000000,
218 MAX_LAT = 90000000, MIN_LAT = -90000000,
219 MAX_LON = 180000000, MIN_LON = -180000000;
220 long step = STEP, target;
221 int row = 0, pos = 1;
226 text_xprintf(bm, 0, 0,
227 STYLEF_UNDERLINE | TEXT_CENTER | TEXT_FILL,
233 text_xprintf(bm, 3, 0, TEXT_FILL,
234 "Lat: %02ld.%06ld %c %s",
235 ABS(target_lat) / 1000000L,
236 ABS(target_lat) % 1000000,
237 target_lat >= 0 ? 'N' : 'S',
238 row == 0 ? "<-" : "");
239 text_xprintf(bm, row ? 4 : 6, 0,
240 TEXT_FILL | TEXT_CENTER, " ");
241 text_xprintf(bm, row ? 6 : 4, 0,
244 pos + 7 : pos + 6, '^');
245 text_xprintf(bm, 5, 0, TEXT_FILL,
246 "Lon: %03ld.%06ld %c %s",
247 ABS(target_lon) / 1000000L,
248 ABS(target_lon) % 1000000L,
249 target_lon >= 0 ? 'E' : 'W',
250 row == 1 ? "<-" : "");
258 target = target_lat + step;
259 if (target <= MAX_LAT)
261 if (target_lat < 0 && target > 0)
262 target_lat = ABS(target_lat) +
270 target = target_lon + step;
271 if (target <= MAX_LON)
273 if (target_lon < 0 && target > 0)
274 target_lon = ABS(target_lon) +
281 else if (key & K_DOWN)
285 target = target_lat - step;
286 if (target >= MIN_LAT)
288 if (target_lat > 0 && target < 0)
289 target_lat = -ABS(target_lat) -
297 target = target_lon - step;
298 if (target >= MIN_LON)
300 if (target_lon > 0 && target < 0)
301 target_lon = -ABS(target_lon) -
308 else if (key & K_LEFT)
316 else if (key & K_RIGHT)
328 /* Move to longigude */
335 /* Compass management */
336 static void draw_compass(Bitmap *bm)
338 const int R = LCD_HEIGHT / 3, R_SMALL = 10;
339 long x, y, x1, y1, x2, y2, d;
342 d = distance(lat / 1E6, lon / 1E6, target_lat / 1E6, target_lon / 1E6);
344 x = (long)((float)R * (1 + sin(deg2rad((float)prev_b))));
345 y = (long)((float)R * (1 - cos(deg2rad((float)prev_b))));
347 x1 = R - R_SMALL + (long)((float)R_SMALL *
348 (1 + sin(deg2rad((float)prev_b - 120.0))));
349 y1 = R - R_SMALL + (long)((float)R_SMALL *
350 (1 - cos(deg2rad((float)prev_b - 120.0))));
351 x2 = R - R_SMALL + (long)((float)R_SMALL *
352 (1 + sin(deg2rad((float)prev_b + 120.0))));
353 y2 = R - R_SMALL + (long)((float)R_SMALL *
354 (1 - cos(deg2rad((float)prev_b + 120.0))));
357 /* Print direction heading and degrees */
358 text_xprintf(bm, 0, 5, 0, "%s", "N");
359 text_xprintf(bm, 0, 0, TEXT_RIGHT, "%s", compass_heading(prev_b));
360 text_xprintf(bm, 1, 0, TEXT_RIGHT, "%ld deg.", prev_b);
362 text_xprintf(bm, 2, 0, TEXT_RIGHT, "%ld %s",
363 d >= 1000 ? d / 1000 : d,
364 d >= 1000 ? "Km" : "m");
365 /* Print current and target position */
366 text_xprintf(bm, 6, 0, TEXT_FILL, "%02ld.%06ld%c%03ld.%06ld%c",
369 lat >= 0 ? 'N' : 'S',
372 lon >= 0 ? 'E' : 'W');
373 text_xprintf(bm, 7, 0, TEXT_FILL, "%02ld.%06ld%c%03ld.%06ld%c",
374 ABS(target_lat) / 1000000L,
375 ABS(target_lat) % 1000000,
376 target_lat >= 0 ? 'N' : 'S',
377 ABS(target_lon) / 1000000L,
378 ABS(target_lon) % 1000000L,
379 target_lon >= 0 ? 'E' : 'W');
380 /* Draw the circle */
381 for (i = 0; i < 360; i++)
383 (long)((float)R * (1 + sin(deg2rad((float)i)))),
384 (long)((float)R * (1 - cos(deg2rad((float)i)))));
385 /* Draw the needle */
386 gfx_rectFill(bm, R - 2, R - 2, R + 2, R + 2);
387 gfx_line(bm, R, R, x1, y1);
388 gfx_line(bm, R, R, x2, y2);
389 gfx_line(bm, x1, y1, x, y);
390 gfx_line(bm, x2, y2, x, y);
395 static void compass(Bitmap *bm)
404 b = bearing(lat / 1E6, lon / 1E6,
405 target_lat / 1E6, target_lon / 1E6);
406 inc = ABS(b - prev_b) < 360 - ABS(b - prev_b) ? 1 : -1;
407 /* Compass animation */
412 prev_b = (prev_b + inc) % 360;
417 if (keypad_peek() & KEY_MASK)
423 if (keypad_peek() & KEY_MASK)
428 /* GPS receiver status */
429 static const char *gps_fix[] =
442 static void gps_data(Bitmap *bm)
455 text_xprintf(bm, 3, 0,
456 TEXT_CENTER | TEXT_FILL, "No GPS data");
460 gmtime_r(&rmc.time, &tm);
462 text_xprintf(bm, 0, 0, TEXT_FILL,
466 lat >= 0 ? 'N' : 'S');
467 text_xprintf(bm, 1, 0, TEXT_FILL,
471 lon >= 0 ? 'E' : 'W');
472 text_xprintf(bm, 2, 0, TEXT_FILL,
473 "Alt. %d", gga.altitude);
474 text_xprintf(bm, 3, 0, TEXT_FILL,
475 "Speed: %d", vtg.km_speed);
476 if (gga.quality < countof(gps_fix))
477 text_xprintf(bm, 4, 0, TEXT_FILL,
479 gps_fix[gga.quality]);
481 text_xprintf(bm, 4, 0, TEXT_FILL,
482 "Fix: %d", gga.quality);
483 text_xprintf(bm, 5, 0, TEXT_FILL,
486 strftime(buf, sizeof(buf),
487 "Date: %Y-%m-%d %a", &tm);
488 text_xprintf(bm, 6, 0, TEXT_FILL, "%s", buf);
489 strftime(buf, sizeof(buf),
490 "Time: %H:%M:%S (UTC)", &tm);
491 text_xprintf(bm, 7, 0, TEXT_FILL, "%s", buf);
495 if (keypad_peek() & KEY_MASK)
502 static void about(Bitmap *bm)
506 text_xprintf(bm, 7, 0,
507 STYLEF_UNDERLINE | TEXT_CENTER | TEXT_FILL,
508 "http://www.bertos.org");
512 const uint8_t *p = &logo[BITMAP_HEADER_SIZE];
513 uint8_t h = logo[BITMAP_HEIGHT_OFFSET];
514 uint8_t w = logo[BITMAP_WIDTH_OFFSET];
517 for (r = 0; r < h; r++)
520 (128 - w) / 2, 70 - r, w, 1);
524 while (!(keypad_peek() & KEY_MASK))
528 static struct MenuItem main_items[] =
530 {(const_iptr_t)"Target", 0, (MenuHook)target, (iptr_t)&lcd_bitmap},
531 {(const_iptr_t)"Compass", 0, (MenuHook)compass, (iptr_t)&lcd_bitmap},
532 {(const_iptr_t)"GPS data", 0, (MenuHook)gps_data, (iptr_t)&lcd_bitmap},
533 {(const_iptr_t)"About...", 0, (MenuHook)about, (iptr_t)&lcd_bitmap},
534 {(const_iptr_t)0, 0, NULL, (iptr_t)NULL}
537 static struct Menu main_menu =
539 main_items, "DevelGPS v0.1", MF_STICKY | MF_SAVESEL, &lcd_bitmap, 0
542 static void init(void)
550 scrsvr_timestamp = ticks_to_ms(timer_clock_unlocked());
553 flash_lm3sInit(&flash);
556 ser_init(&ser_port, SER_UART1);
557 ser_setbaudrate(&ser_port, 38400);
559 nmeap_init(&nmea, NULL);
560 nmeap_addParser(&nmea, "GPGGA", nmea_gpgga, nmea_callback, &gga);
561 nmeap_addParser(&nmea, "GPRMC", nmea_gprmc, nmea_callback, &rmc);
562 nmeap_addParser(&nmea, "GPVTG", nmea_gpvtg, nmea_callback, &vtg);
565 gfx_bitmapInit(&lcd_bitmap, raster, LCD_WIDTH, LCD_HEIGHT);
566 gfx_setFont(&lcd_bitmap, &font_gohu);
567 repaint(&lcd_bitmap);
576 proc_new(led_process, NULL, KERN_MINSTACKSIZE * 2, NULL);
577 proc_new(ser_process, NULL, KERN_MINSTACKSIZE * 2, NULL);
581 iptr_t res = menu_handle(&main_menu);
582 if (res != MENU_TIMEOUT)