#!/usr/bin/env python3
import serial
import time
import datetime
import os
import pynmea2
# --- GPS configuration ---
GPS_PORT = "/dev/ttyTHS1"
GPS_BAUD = 9600
# --- Arduino serial configuration ---
ARDUINO_PORT = "/dev/ttyACM0"
ARDUINO_BAUD = 115200
# --- Printing configuration ---
MAX_CHUNK_LENGTH = 12 # threshold for big words
LETTER_DELAY = 0.2 # delay per letter for big words
CHUNK_DELAY = 0.5 # delay between words
# --- Initialize GPS ---
def init_gps():
try:
return serial.Serial(GPS_PORT, GPS_BAUD, timeout=1)
except Exception as e:
print("GPS init error:", e)
return None
# --- Get GPS data ---
def get_gps_data(gps, timeout=10):
if gps is None:
return None, None, None
start = time.time()
while time.time() - start < timeout:
try:
line = gps.readline().decode('ascii', errors='replace')
if line.startswith('$GPGGA') or line.startswith('$GPRMC'):
msg = pynmea2.parse(line)
lat = getattr(msg, 'latitude', None)
lon = getattr(msg, 'longitude', None)
timestamp = getattr(msg, 'timestamp', datetime.datetime.utcnow().time())
if lat and lon:
return lat, lon, timestamp
except Exception:
continue
return None, None, None
# --- Send entry and GPS to Arduino ---
def send_entry_to_arduino(entry_lines, gps):
# --- compact GPS line ---
lat, lon, timestamp = get_gps_data(gps, timeout=10)
if lat is None or lon is None:
gps_line = f"FAILURE|{datetime.datetime.now().strftime('%H:%M:%S')}"
else:
gps_line = f"{lat:.6f},{lon:.6f}|{timestamp}"
# Combine GPS line + entry lines
full_text = gps_line + " " + " ".join(entry_lines)
words = full_text.split()
with serial.Serial(ARDUINO_PORT, ARDUINO_BAUD, timeout=1) as arduino:
time.sleep(2) # allow Arduino to reset
# --- Print GPS line letter by letter ---
for char in gps_line:
arduino.write(char.encode("ascii", "replace"))
arduino.flush()
time.sleep(LETTER_DELAY)
arduino.write(b"\n")
arduino.flush()
time.sleep(CHUNK_DELAY)
# --- Print entry words ---
for word in words[len(gps_line.split()):]:
if len(word) > MAX_CHUNK_LENGTH:
# Big word: print letter by letter
for char in word:
arduino.write(char.encode("ascii", "replace"))
arduino.flush()
time.sleep(LETTER_DELAY)
arduino.write(b" ") # space after big word
arduino.flush()
time.sleep(CHUNK_DELAY)
else:
# Small word: print normally with trailing space
arduino.write((word + " ").encode("ascii", "replace"))
arduino.flush()
time.sleep(CHUNK_DELAY)
# Final newline after all words
arduino.write(b"\n")
arduino.flush()
time.sleep(CHUNK_DELAY)
# --- Show live GPS location ---
def show_location(gps):
print("\n--- LIVE GPS LOCATION --- (CTRL+C to return)\n")
try:
while True:
lat, lon, timestamp = get_gps_data(gps, timeout=5)
os.system('clear')
if lat is None or lon is None:
print("FAILURE TO LOCATE!\n")
else:
print(f"Latitude: {lat:.6f}")
print(f"Longitude: {lon:.6f}")
print(f"UTC Time: {timestamp}")
time.sleep(1)
except KeyboardInterrupt:
pass
# --- Shutdown system ---
def shutdown_system():
print("\nSystem shutting down...\n")
os.system("sudo shutdown now")
# --- Escape backdoor ---
def unlock_desktop():
print("\n[** BACKDOOR ACTIVATED: DESKTOP UNLOCK **]\n")
os.system("sudo systemctl set-default graphical.target")
os.system("sudo systemctl start gdm")
exit(0)
# --- New journal entry ---
def new_entry(gps):
print("\n--- NEW JOURNAL ENTRY ---")
entry_lines = []
print("(Type/paste entry; empty line to finish)\n")
while True:
line = input()
if line.strip().upper() == "ESCAPE":
unlock_desktop()
if line.strip() == "":
break
entry_lines.append(line)
send_entry_to_arduino(entry_lines, gps)
print("\nEntry sent to Arduino.\n")
# --- Main menu ---
def main():
gps = init_gps()
os.system("clear")
while True:
print("================================")
print(" JOURNAL LOGGER MAIN MENU")
print("================================")
print("1. NEW ENTRY")
print("2. LOCATION")
print("3. SHUTDOWN")
print("================================")
choice = input("Select option: ").strip()
if choice.upper() == "ESCAPE":
unlock_desktop()
elif choice == "1":
new_entry(gps)
elif choice == "2":
show_location(gps)
elif choice == "3":
shutdown_system()
else:
print("Invalid selection.\n")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\nExiting safely.\n")