55#include < Preferences.h>
66#include < time.h>
77#include < Adafruit_NeoPixel.h>
8+ #include < TinyGPS++.h>
89
910#include " config.h"
1011#include " orbit.h"
1112#include " ui.h"
1213#include " credentials.h"
1314#include " iss_icon.h"
1415
16+
1517// --- GLOBALS ---
1618M5Canvas canvas (&M5Cardputer.Display);
1719Preferences prefs;
@@ -27,6 +29,10 @@ int tzOffsetHours = -6;
2729String satName = " " ;
2830bool tleParsedOK = false ;
2931
32+ TinyGPSPlus gps;
33+ HardwareSerial gpsSerial (1 ); // Use UART 1
34+ bool useGpsModule = false ;
35+
3036// --- LED State Variables ---
3137bool wasVisible = false ; // Tracks state from previous loop
3238bool losTimerActive = false ; // Are we currently showing the Red LOS light?
@@ -47,6 +53,7 @@ enum Screen {
4753 SCREEN_MENU_WIFI,
4854 SCREEN_MENU_SAT,
4955 SCREEN_MENU_LOC,
56+ SCREEN_GPS_INFO,
5057
5158 SCREEN_COUNT // Keep this for the G0 cycling logic
5259};
@@ -162,10 +169,16 @@ void setup() {
162169 obsLonDeg = prefs.getDouble (" lon" , obsLonDeg);
163170 minElevation = prefs.getInt (" minEl" , DEFAULT_MIN_EL);
164171 tzOffsetHours = prefs.getInt (" tzOffset" , -6 );
172+ useGpsModule = prefs.getBool (" useGps" , false ); // Load preference
165173 prefs.end ();
166174
167175 configTime (tzOffsetHours * 3600 , 0 , " pool.ntp.org" );
168176
177+ // Init GPS Serial if enabled
178+ if (useGpsModule) {
179+ gpsSerial.begin (GPS_BAUD, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
180+ }
181+
169182 // Load TLE
170183 String localTle = readFileFromSD (ISS_TLE_PATH);
171184 if (localTle != " ERROR" ) {
@@ -204,6 +217,23 @@ void setup() {
204217void loop () {
205218 M5Cardputer.update ();
206219
220+ // --- GPS PARSING ---
221+ if (useGpsModule) {
222+ while (gpsSerial.available () > 0 ) {
223+ gps.encode (gpsSerial.read ());
224+ }
225+ if (gps.location .isUpdated ()) {
226+ obsLatDeg = gps.location .lat ();
227+ obsLonDeg = gps.location .lng ();
228+ setupOrbitLocation (obsLatDeg, obsLonDeg); // Update SGP4 instantly
229+
230+ // Optional: Sync system time from GPS if valid
231+ if (gps.time .isValid () && gps.date .isValid () && gps.time .age () < 1000 ) {
232+ // You could implement setTime() here if WiFi NTP fails!
233+ }
234+ }
235+ }
236+
207237 // --- 1. KEYBOARD INPUT HANDLING ---
208238 if (M5Cardputer.Keyboard .isChange () && M5Cardputer.Keyboard .isPressed ()) {
209239 Keyboard_Class::KeysState k = M5Cardputer.Keyboard .keysState ();
@@ -220,6 +250,9 @@ void loop() {
220250 currentScreen == SCREEN_MENU_LOC) {
221251 currentScreen = SCREEN_MENU_MAIN; // Submenu -> Main Menu
222252 }
253+ else if (currentScreen == SCREEN_GPS_INFO) { // <--- Add this
254+ currentScreen = SCREEN_MENU_LOC; // Back to Loc Menu
255+ }
223256 else if (currentScreen == SCREEN_MENU_MAIN) {
224257 currentScreen = SCREEN_HOME; // Main Menu -> Home
225258 }
@@ -291,26 +324,58 @@ void loop() {
291324 }
292325 }
293326 // LOCATION MENU
294- else if (currentScreen == SCREEN_MENU_LOC) {
327+ else if (currentScreen == SCREEN_MENU_LOC) {
295328 for (auto c : k.word ) {
329+ // TOGGLE GPS MODE
296330 if (c == ' 1' ) {
297- String l = textInput (String (obsLatDeg), " Lat:" );
298- obsLatDeg = l.toFloat ();
331+ useGpsModule = !useGpsModule;
332+
333+ // Save Preference
299334 prefs.begin (" iss_cfg" , false );
300- prefs.putDouble ( " lat " , obsLatDeg );
335+ prefs.putBool ( " useGps " , useGpsModule );
301336 prefs.end ();
302- setupOrbitLocation (obsLatDeg, obsLonDeg);
337+
338+ // Start/Stop Serial
339+ if (useGpsModule) {
340+ gpsSerial.begin (GPS_BAUD, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
341+ } else {
342+ // Keeping serial open is fine, or you can gpsSerial.end();
343+ }
303344 needsRedraw = true ;
304345 }
305- if (c == ' 2' ) {
306- String lo = textInput (String (obsLonDeg), " Lon:" );
307- obsLonDeg = lo.toFloat ();
308- prefs.begin (" iss_cfg" , false );
309- prefs.putDouble (" lon" , obsLonDeg);
310- prefs.end ();
311- setupOrbitLocation (obsLatDeg, obsLonDeg);
346+
347+ // EDIT LAT (Only if Manual)
348+ if (c == ' 2' ) {
349+ if (!useGpsModule) {
350+ String l = textInput (String (obsLatDeg), " Lat:" );
351+ obsLatDeg = l.toFloat ();
352+ prefs.begin (" iss_cfg" , false );
353+ prefs.putDouble (" lat" , obsLatDeg);
354+ prefs.end ();
355+ setupOrbitLocation (obsLatDeg, obsLonDeg);
356+ }
357+ needsRedraw = true ;
358+ }
359+
360+ // EDIT LON (Only if Manual)
361+ if (c == ' 3' ) {
362+ if (!useGpsModule) {
363+ String lo = textInput (String (obsLonDeg), " Lon:" );
364+ obsLonDeg = lo.toFloat ();
365+ prefs.begin (" iss_cfg" , false );
366+ prefs.putDouble (" lon" , obsLonDeg);
367+ prefs.end ();
368+ setupOrbitLocation (obsLatDeg, obsLonDeg);
369+ }
312370 needsRedraw = true ;
313371 }
372+
373+ if (c == ' 4' ) {
374+ if (useGpsModule) {
375+ currentScreen = SCREEN_GPS_INFO;
376+ needsRedraw = true ;
377+ }
378+ }
314379 }
315380 }
316381 }
@@ -370,14 +435,18 @@ void loop() {
370435 case SCREEN_HOME: drawHomeScreen (canvas); break ;
371436 case SCREEN_LIVE: drawLiveScreen (canvas, tm->tm_year +1900 , tm->tm_mon +1 , tm->tm_mday , tm->tm_hour , tm->tm_min ); break ;
372437 case SCREEN_RADAR: drawRadarScreen (canvas, unixtime); break ;
373- case SCREEN_PASS: drawPassScreen (canvas, unixtime, minElevation); break ;
374-
438+ case SCREEN_PASS:
439+ drawPassScreen (canvas, unixtime, minElevation, obsLatDeg, obsLonDeg);
440+ break ;
375441 case SCREEN_MENU_MAIN: drawMainMenu (canvas); break ;
376442 case SCREEN_MENU_WIFI: drawWifiMenu (canvas, wifiSsid); break ;
377443 case SCREEN_MENU_SAT: drawSatMenu (canvas, minElevation); break ;
378- case SCREEN_MENU_LOC: drawLocationMenu (canvas, obsLatDeg, obsLonDeg); break ;
379-
444+ case SCREEN_MENU_LOC:
445+ drawLocationMenu (canvas, obsLatDeg, obsLonDeg, useGpsModule, gps.location .isValid (), gps.satellites .value ());
446+ break ;
447+ case SCREEN_GPS_INFO: drawGpsInfoScreen (canvas, gps); break ;
380448 default : break ;
449+
381450 }
382451 canvas.pushSprite (0 ,0 );
383452 needsRedraw = false ;
0 commit comments