-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaprs-decoder-macos.sh
More file actions
196 lines (169 loc) · 5.94 KB
/
aprs-decoder-macos.sh
File metadata and controls
196 lines (169 loc) · 5.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#!/bin/bash
# macOS Native APRS Decoder for Mobilinkd TNC
# Uses built-in macOS tools to decode APRS packets from a TNC
# Default settings
PORT=""
BAUD=9600
OUTPUT_FILE="aprs_packets.log"
FORMAT="human"
# Function to display usage
show_usage() {
echo "Usage: $0 --port PORT [--baud BAUD] [--output FILE] [--format FORMAT]"
echo
echo "Options:"
echo " --port PORT Serial port for the TNC (required)"
echo " --baud BAUD Baud rate (default: 9600)"
echo " --output FILE Output log file (default: aprs_packets.log)"
echo " --format FORMAT Output format: human, csv (default: human)"
echo
echo "Example: $0 --port /dev/tty.Mobilinkd-TNC4-SerialPort"
exit 1
}
# Parse command line arguments
while [[ "$#" -gt 0 ]]; do
case $1 in
--port) PORT="$2"; shift ;;
--baud) BAUD="$2"; shift ;;
--output) OUTPUT_FILE="$2"; shift ;;
--format) FORMAT="$2"; shift ;;
--help) show_usage ;;
*) echo "Unknown parameter: $1"; show_usage ;;
esac
shift
done
# Check for required arguments
if [ -z "$PORT" ]; then
echo "Error: Serial port is required"
show_usage
fi
# Check if port exists
if [ ! -e "$PORT" ]; then
echo "Error: Serial port $PORT does not exist"
echo "Available ports:"
ls -l /dev/tty.*
exit 1
fi
# Function to parse APRS packet
parse_packet() {
local packet="$1"
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
# Extract source and destination
local source=$(echo "$packet" | sed -E 's/^([A-Z0-9-]+)\s*>.*/\1/')
local dest=$(echo "$packet" | sed -E 's/^[A-Z0-9-]+\s*>\s*([A-Z0-9-]+).*/\1/')
# Extract path
local path=$(echo "$packet" | sed -E 's/^[A-Z0-9-]+\s*>\s*[A-Z0-9-]+\s*(,[A-Z0-9-*]+)*:.*/\1/')
# Extract content
local content=$(echo "$packet" | sed -E 's/^[A-Z0-9-]+\s*>\s*[A-Z0-9-]+(,[A-Z0-9-*]+)*:(.*)/\2/')
# Determine message type
local msg_type="Other"
local lat=""
local lon=""
local comment=""
# First character of content determines type
local first_char=$(echo "$content" | cut -c1)
case "$first_char" in
"!" | "=")
msg_type="Position"
# Try to extract lat/lon for uncompressed format
if echo "$content" | grep -qE '[!=][0-9]{2}[0-9]{2}\.[0-9]{2}[NS]/[0-9]{3}[0-9]{2}\.[0-9]{2}[EW]'; then
# Extract latitude components
local lat_deg=$(echo "$content" | sed -E 's/^[!=]([0-9]{2}).*/\1/')
local lat_min=$(echo "$content" | sed -E 's/^[!=][0-9]{2}([0-9]{2}\.[0-9]{2}).*/\1/')
local lat_dir=$(echo "$content" | sed -E 's/^[!=][0-9]{2}[0-9]{2}\.[0-9]{2}([NS]).*/\1/')
# Extract longitude components
local lon_deg=$(echo "$content" | sed -E 's/^[!=][0-9]{2}[0-9]{2}\.[0-9]{2}[NS]/([0-9]{3}).*/\1/')
local lon_min=$(echo "$content" | sed -E 's/^[!=][0-9]{2}[0-9]{2}\.[0-9]{2}[NS]/[0-9]{3}([0-9]{2}\.[0-9]{2}).*/\1/')
local lon_dir=$(echo "$content" | sed -E 's/^[!=][0-9]{2}[0-9]{2}\.[0-9]{2}[NS]/[0-9]{3}[0-9]{2}\.[0-9]{2}([EW]).*/\1/')
# Convert to decimal degrees (approximate calculation)
# For exact calculation, would need to use bc or similar
lat_min_dec=$(echo "$lat_min" | awk '{print $1/60}')
lat=$(echo "$lat_deg $lat_min_dec" | awk '{print $1 + $2}')
if [ "$lat_dir" = "S" ]; then
lat=$(echo "$lat" | awk '{print -$1}')
fi
lon_min_dec=$(echo "$lon_min" | awk '{print $1/60}')
lon=$(echo "$lon_deg $lon_min_dec" | awk '{print $1 + $2}')
if [ "$lon_dir" = "W" ]; then
lon=$(echo "$lon" | awk '{print -$1}')
fi
# Extract comment (everything after the position)
comment=$(echo "$content" | sed -E 's/^[!=][0-9]{2}[0-9]{2}\.[0-9]{2}[NS]/[0-9]{3}[0-9]{2}\.[0-9]{2}[EW](.*)/\1/')
fi
;;
">")
msg_type="Status"
comment=$(echo "$content" | cut -c2-)
;;
":")
msg_type="Message"
comment=$(echo "$content" | cut -c2-)
;;
"T")
msg_type="Telemetry"
comment="$content"
;;
*)
comment="$content"
;;
esac
# Output based on format
if [ "$FORMAT" = "human" ]; then
echo "Timestamp: $timestamp"
echo "Source: $source"
echo "Destination: $dest"
[ ! -z "$path" ] && echo "Path: $path"
echo "Type: $msg_type"
[ ! -z "$lat" ] && echo "Position: $lat, $lon"
[ ! -z "$comment" ] && echo "Comment: $comment"
echo "Raw: $packet"
echo ""
elif [ "$FORMAT" = "csv" ]; then
# Escape commas in comment and raw packet
comment=$(echo "$comment" | sed 's/,/;/g')
packet_esc=$(echo "$packet" | sed 's/,/;/g')
echo "$timestamp,$source,$dest,$path,$msg_type,$lat,$lon,$comment,$packet_esc"
fi
}
# Create CSV header if needed
if [ "$FORMAT" = "csv" ] && [ ! -s "$OUTPUT_FILE" ]; then
echo "timestamp,source,destination,path,type,latitude,longitude,comment,raw" > "$OUTPUT_FILE"
fi
echo "Connected to $PORT at $BAUD baud"
echo "Logging to $OUTPUT_FILE"
echo "Press Ctrl+C to stop"
# Configure the serial port using stty (built into macOS)
stty -f "$PORT" $BAUD cs8 -cstopb -parenb
# Open the serial port
exec 3<"$PORT"
# Buffer for incomplete lines
buffer=""
# Trap Ctrl+C to clean up
trap 'echo -e "\nExiting..."; exec 3<&-; exit 0' INT
# Main loop
while true; do
# Read a character
if read -t 0.1 -u 3 char; then
# Add to buffer
buffer="$buffer$char"
# Process complete lines
if [[ "$char" == $'\n' || "$char" == $'\r' ]]; then
if [ ! -z "$buffer" ]; then
# Clean up the buffer
packet=$(echo "$buffer" | tr -d '\r\n')
buffer=""
if [ ! -z "$packet" ]; then
# Parse and display the packet
parse_output=$(parse_packet "$packet")
echo "$parse_output"
# Log to file
if [ "$FORMAT" = "human" ]; then
echo "$parse_output" >> "$OUTPUT_FILE"
elif [ "$FORMAT" = "csv" ]; then
# Last line only for CSV
echo "$parse_output" | tail -n 1 >> "$OUTPUT_FILE"
fi
fi
fi
fi
fi
done