From a8e16ad1131c3540be132450b1e2bde878f7a836 Mon Sep 17 00:00:00 2001 From: Rossen Georgiev Date: Sun, 30 Nov 2014 12:49:18 +0000 Subject: [PATCH] separated base91 into a submodule --- aprs/base91.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ aprs/parse.py | 30 +++++++----------------------- aprs/version.py | 2 +- 3 files changed, 54 insertions(+), 24 deletions(-) create mode 100644 aprs/base91.py diff --git a/aprs/base91.py b/aprs/base91.py new file mode 100644 index 0000000..7bc1583 --- /dev/null +++ b/aprs/base91.py @@ -0,0 +1,46 @@ +""" +Provides facilities for covertion from/to base91 +""" +from math import log +from re import findall + +def to_decimal(text): + """ + Takes a base91 char string and returns decimal + """ + + if not isinstance(text, str): + raise TypeError("expected str") + + if findall(r"[\x00-\x20\x7c-\xff]", text): + raise ValueError("invalid character in sequence") + + decimal = 0 + length = len(text) - 1 + for i, char in enumerate(text): + decimal += (ord(char) - 33) * (91 ** (length - i)) + + return decimal if text != '' else 0 + + +def from_decimal(n, padding=1): + """ + Takes a decimal and returns base91 char string. + With optional padding to a specific length. + """ + text = [] + + if not isinstance(n, (int, long)) is not int or n < 0: + raise ValueError("non-positive integer error") + elif not isinstance(n, (int, long)) or padding < 1: + raise ValueError("padding must be integer and >0") + elif n > 0: + for d in [91**e for e in reversed(range(int(log(n) / log(91)) + 1))]: + q = n / d + n = n % d + text.append(chr(33 + q)) + + # add padding if necessary + text = ['!'] * (padding-len(text)) + text + + return "".join(text) diff --git a/aprs/parse.py b/aprs/parse.py index 98263fa..e1a45cc 100644 --- a/aprs/parse.py +++ b/aprs/parse.py @@ -8,6 +8,7 @@ import logging from datetime import datetime from .exceptions import (UnknownFormat, ParseError) +import base91 __all__ = ['parse'] @@ -37,19 +38,6 @@ MTYPE_TABLE_CUSTOM = { } -def base91(text): - """ - Takes a base91 char string and returns decimal - """ - - decimal = 0 - length = len(text) - for i in range(length): - decimal += (ord(text[i]) - 33) * (91.0 ** (length-1-i)) - - return decimal if text != '' else '' - - def parse(raw_sentence): """ Parses an APRS packet and returns a dict with decoded data @@ -334,7 +322,7 @@ def parse(raw_sentence): if match: body, altitude, extra = match[0] - altitude = base91(altitude) - 10000 + altitude = base91.to_decimal(altitude) - 10000 parsed.update({'altitude': altitude}) body = body + extra @@ -526,8 +514,8 @@ def parse(raw_sentence): symbol_table = packet[0] symbol = packet[9] - latitude = 90 - (base91(packet[1:5]) / 380926) - longitude = -180 + (base91(packet[5:9]) / 190463) + latitude = 90 - (base91.to_decimal(packet[1:5]) / 380926.0) + longitude = -180 + (base91.to_decimal(packet[5:9]) / 190463.0) # parse csT @@ -659,18 +647,14 @@ def _parse_comment_telemetry(text): Looks for base91 telemetry found in comment field Returns [remaining_text, telemetry] """ - match = re.findall(r"^(.*?)\|([!-{]{6,14})\|(.*)$", text) + match = re.findall(r"^(.*?)\|([!-{]{4,14})\|(.*)$", text) if match and len(match[0][1]) % 2 == 0: text, telemetry, post = match[0] text += post - temp = [''] * 7 + temp = [0] * 7 for i in range(7): - try: - temp[i] = base91(telemetry[i*2:i*2+2]) - temp[i] = int(temp[i]) if temp[i].is_integer() else temp[i] - except: - continue + temp[i] = base91.to_decimal(telemetry[i*2:i*2+2]) parsed = { 'telemetry': { diff --git a/aprs/version.py b/aprs/version.py index 02f8497..e2f45ae 100644 --- a/aprs/version.py +++ b/aprs/version.py @@ -1 +1 @@ -__version__ = '0.6.4' +__version__ = '0.6.5'