Completed
Push — master ( d85b64...2a12d0 )
by Jeffrey
03:59
created

dec2dm_lng()   A

Complexity

Conditions 2

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 23
rs 9.0856
cc 2
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
"""Utilities for the APRS Python Module."""
5
6
# These imports are for python3 compatability inside python2
7
from __future__ import absolute_import
8
from __future__ import division
9
from __future__ import print_function
10
11
import logging
12
13
import apex.aprs.constants
14
import apex.aprs.decimaldegrees
15
import apex.kiss.constants
16
17
__author__ = 'Jeffrey Phillips Freeman (WI2ARD)'
18
__maintainer__ = "Jeffrey Phillips Freeman (WI2ARD)"
19
__email__ = "[email protected]"
20
__license__ = 'Apache License, Version 2.0'
21
__copyright__ = 'Copyright 2016, Syncleus, Inc. and contributors'
22
__credits__ = []
23
24
25
def dec2dm_lat(dec):
26
    """Converts DecDeg to APRS Coord format.
27
    See: http://ember2ash.com/lat.htm
28
29
    Source: http://stackoverflow.com/questions/2056750
30
31
    Example:
32
        >>> test_lat = 37.7418096
33
        >>> aprs_lat = dec2dm_lat(test_lat)
34
        >>> aprs_lat
35
        '3744.51N'
36
    """
37
    dec_min = apex.aprs.decimaldegrees.decimal2dm(dec)
38
39
    deg = dec_min[0]
40
    abs_deg = abs(deg)
41
42
    if not deg == abs_deg:
43
        suffix = 'S'
44
    else:
45
        suffix = 'N'
46
47
    retval = ''.join([str(abs_deg), "%.2f" % dec_min[1], suffix])
48
49
    return retval
50
51
52
def dec2dm_lng(dec):
53
    """Converts DecDeg to APRS Coord format.
54
    See: http://ember2ash.com/lat.htm
55
56
    Example:
57
        >>> test_lng = -122.38833
58
        >>> aprs_lng = dec2dm_lng(test_lng)
59
        >>> aprs_lng
60
        '12223.30W'
61
    """
62
    dec_min = apex.aprs.decimaldegrees.decimal2dm(dec)
63
64
    deg = dec_min[0]
65
    abs_deg = abs(deg)
66
67
    if not deg == abs_deg:
68
        suffix = 'W'
69
    else:
70
        suffix = 'E'
71
72
    retval = ''.join([str(abs_deg), "%.2f" % dec_min[1], suffix])
73
74
    return retval
75
76
77
def decode_aprs_ascii_frame(ascii_frame):
78
    """
79
    Breaks an ASCII APRS Frame down to it's constituent parts.
80
81
    :param frame: ASCII APRS Frame.
82
    :type frame: str
83
84
    :returns: Dictionary of APRS Frame parts: source, destination, path, text.
85
    :rtype: dict
86
    """
87
    logging.debug('frame=%s', ascii_frame)
88
    decoded_frame = {}
89
    frame_so_far = ''
90
91
    for char in ascii_frame:
92
        if '>' in char and 'source' not in decoded_frame:
93
            decoded_frame['source'] = frame_so_far
94
            frame_so_far = ''
95
        elif ':' in char and 'path' not in decoded_frame:
96
            decoded_frame['path'] = frame_so_far
97
            frame_so_far = ''
98
        else:
99
            frame_so_far = ''.join([frame_so_far, char])
100
101
    decoded_frame['text'] = frame_so_far
102
    decoded_frame['destination'] = decoded_frame['path'].split(',')[0]
103
104
    return decoded_frame
105
106
107
def format_path(path_list):
108
    """
109
    Formats path from raw APRS KISS frame.
110
111
    :param path_list: List of path elements.
112
    :type path_list: list
113
114
    :return: Formatted APRS path.
115
    :rtype: str
116
    """
117
    return ','.join(path_list)
118
119
120
def format_aprs_frame(frame):
121
    """
122
    Formats APRS frame-as-dict into APRS frame-as-string.
123
124
    :param frame: APRS frame-as-dict
125
    :type frame: dict
126
127
    :return: APRS frame-as-string.
128
    :rtype: str
129
    """
130
    formatted_frame = '>'.join([frame['source'], frame['destination']])
131
    if frame['path']:
132
        formatted_frame = ','.join([formatted_frame, format_path(frame['path'])])
133
    formatted_frame += ':'
134
    formatted_frame += frame['text']
135
    return formatted_frame
136
137
138
def valid_callsign(callsign):
139
    """
140
    Validates callsign.
141
142
    :param callsign: Callsign to validate.
143
    :type callsign: str
144
145
    :returns: True if valid, False otherwise.
146
    :rtype: bool
147
    """
148
    logging.debug('callsign=%s', callsign)
149
150
    if '-' in callsign:
151
        if not callsign.count('-') == 1:
152
            return False
153
        else:
154
            callsign, ssid = callsign.split('-')
155
    else:
156
        ssid = 0
157
158
    logging.debug('callsign=%s ssid=%s', callsign, ssid)
159
160
    if (len(callsign) < 2 or len(callsign) > 6 or len(str(ssid)) < 1 or
161
            len(str(ssid)) > 2):
162
        return False
163
164
    for char in callsign:
165
        if not (char.isalpha() or char.isdigit()):
166
            return False
167
168
    if not str(ssid).isdigit():
169
        return False
170
171
    if int(ssid) < 0 or int(ssid) > 15:
172
        return False
173
174
    return True
175
176
177
def run_doctest():  # pragma: no cover
178
    """Runs doctests for this module."""
179
    import doctest
180
    import apex.aprs.util  # pylint: disable=W0406,W0621
181
    return doctest.testmod(apex.aprs.util)
182
183
184
def hash_frame(frame):
185
    """
186
    Produces an integr value that acts as a hash for the frame
187
    :param frame: A frame packet
188
    :type frame: dict
189
    :return: an integer representing the hash
190
    """
191
    hashing = 0
192
    index = 0
193
    frame_string_prefix = frame['source'] + ">" + frame['destination'] + ":"
194
    for frame_chr in frame_string_prefix:
195
        hashing = ord(frame_chr) << (8*(index % 4)) ^ hashing
196
        index += 1
197
    for byte in frame['text']:
198
        hashing = byte << (8*(index % 4)) ^ hashing
199
        index += 1
200
    return hashing
201
202
203
if __name__ == '__main__':
204
    run_doctest()  # pragma: no cover
205