import machine import time import struct class NMEA(object): def __init__(self, id): self.__id = str(id) class Value(object): def __init__(self, v, u, t=(0,0,0.0)): self.__val = float(v) self.__unit = u self.__time = t def value(self): return self.__val def unit(self): return self.__unit def time(self): return self.__time def rad(self): return self.__val * math.pi / 180 def __repr__(self): return "%f %s" % (self.value(), self.unit()) def __float__(self): return float(self.__val) class Distance(Value): def __init__(self, v, u, t): super().__init__(v, u, t) class Position(Value): def __init__(self, v, u, t): super().__init__(v if u in ("N", "E") else -v, u, t) def __sub__(self, other): return Position(self.value() - other.value()) class Speed(Value): def __init__(self, v, u, t): super().__init__(v, u, t) def to_kmh(self): if self.unit() in ("knot", "N"): return Speed(self.value() * 1.85200, "kmh", self.time()) return self def to_knot(self): if self.unit() in ("kmh", "K"): return Speed(self.value() / 1.85200, "knot", self.time()) return self class Course(Value): def __init__(self, v, t): super().__init__(v, "D", t) class Location(object): def __init__(self): self.__valid = False self.__lat = None self.__long = None self.__alt = None self.__height = None self.__speed = None self.__course = None self.__satellites = -1 def __repr__(self): return "Satelittes: %s, %s\n\tLat/long: %s/%s\n\tAlt/h: %s/%s\n\tSpeed/course: %s/%s" % ( self.__satellites, repr(self.__valid), self.__lat, self.__lat, self.__alt, self.__height, self.__speed, self.__course, ) def set(self, msgid, segment): data = segment.split(",") if msgid == b'$GPGGA': if len(data) >= 6 and data[5] in ("1", "2", "6"): t = self.__time_from_seg(data[0]) self.__set_lat(data[1], data[2], t) self.__set_long(data[3], data[4], t) if self.__satellites < 0 and self.__seg_set(data, 6): self.__satellites = int(data[6]) if self.__seg_set(data, 7): self.__alt = Distance(data[7], "M", t) if self.__seg_set(data, 8): self.__height = Distance(data[8], "M", t) elif msgid == b'$GPGLL': if len(data) >= 6 and data[5] == "A": t = self.__time_from_seg(data[4]) self.__set_lat(data[0], data[1], t) self.__set_long(data[2], data[3], t) elif msgid == b'$GPRMC': if len(data) >= 6 and data[1] == "A": t = self.__time_from_seg(data[0]) self.__set_lat(data[2], data[3], t) self.__set_long(data[4], data[5], t) self.__set_speed(data[6], "N", t) self.__set_course(data[7], t) elif msgid == b'$GPVTG': if len(data) >= 7 and data[2] == "T": self.__set_speed(data[4], data[6], (0, 0, 0.0)) self.__set_course(data[5], data[0], (0, 0, 0.0)) elif msgid == b'$GPGSV': if self.__seg_set(data, 2) and data[0] == data[1]: self.__satellites = int(data[2]) elif msgid == b'$GPMSS': pass self.__valid = False if self.__lat is None or self.__long is None else True return self.valid() def valid(self): return self.__valid def __seg_set(self, d, i): return len(d) >= (i + 1) and len(d[i]) != 0 def __set_speed(self, v, u, t): if len(v) == 0: return None if self.__speed is None or self.__speed.time() < t: self.__speed = Speed(v, u, t) def __set_course(self, v, t): if len(v) == 0: return None print("Course", v, t) if self.__course is None or self.__course.time() < t: self.__course = Course(v, t) def __set_lat(self, v, d, t): if len(v) == 0: return None if self.__lat is None or self.__lat.time() < t: self.__lat = Position(float(v[0:2]) + (float(v[2:]) / 60), d, t) def __set_long(self, v, d, t): if len(v) == 0: return None if self.__long is None or self.__long.time() < t: self.__long = Position(float(v[0:3]) + (float(v[3:]) / 60), d, t) def __time_from_seg(self, ts): return (int(ts[0:2]), int(ts[2:4]), float(ts[4:])) class Data(object): def __init__(self, pins=("P3", "P4"), baud=9600): self.__com = machine.UART(1, pins=pins, baudrate=baud) self.__location = None self.__last_update = time.time() def new_location(self, ttw=5): if time.time() - (self.__last_update + ttw) < 0: return False self.__data = Location() data = [] while self.__com.any(): tmp_data = self.__com.readline() if tmp_data[0:1] == b'$': self.__update(data) data = [tmp_data] elif len(data) != 0: data.append(tmp_data) else: self.__update(data) return self.__data.valid() def get_location(self): return self.__data def __update(self, data): if len(data) == 0: return False data = b''.join(data) if data[len(data)-1:len(data)] not in (b'\n', b'\r'): return False if data[len(data)-1:len(data)] != b'\n': data += '\n' if self.__data.set(data[0:6], ("%s" % (data[7:len(data)-2],))[2:-1]): self.__last_update = time.time()