Completed
Pull Request — master (#2)
by Jeffrey
04:10
created

dec2dm_lat()   B

Complexity

Conditions 3

Size

Total Lines 27

Duplication

Lines 27
Ratio 100 %

Importance

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