MSWSP: add two more Property Sets
[wireshark-wip.git] / epan / dissectors / packet-aprs.c
blobc052b56cbc3573c1242f6c77c770e6c5f8309903
1 /* packet-aprs.c
3 * Routines for Amateur Packet Radio protocol dissection
4 * Copyright 2007,2008,2009,2010,2012 R.W. Stearn <richard@rns-stearn.demon.co.uk>
6 * $Id$
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 * This dissector is for APRS (Automatic Packet Reporting System)
30 * Information was drawn from:
31 * http://www.aprs.org/
33 * Inspiration on how to build the dissector drawn from
34 * packet-sdlc.c
35 * packet-x25.c
36 * packet-lapb.c
37 * paket-gprs-llc.c
38 * xdlc.c
39 * with the base file built from README.developers.
42 #include "config.h"
44 #include <string.h>
45 #include <ctype.h>
46 #include <math.h>
48 #include <glib.h>
50 #include <epan/packet.h>
51 #include <epan/prefs.h>
52 #include <epan/wmem/wmem.h>
54 #define AX25_ADDR_LEN 7 /* length of an AX.25 address */
55 #define STRLEN 100
57 void proto_register_aprs(void);
59 /* Initialize the protocol and registered fields */
60 static int proto_aprs = -1;
62 /* aprs timestamp items */
63 static int hf_aprs_dhm = -1;
64 static int hf_aprs_hms = -1;
65 static int hf_aprs_mdhm = -1;
66 static int hf_aprs_tz = -1;
68 /* aprs position items */
69 /* static int hf_aprs_position = -1; */
70 static int hf_aprs_lat = -1;
71 static int hf_aprs_long = -1;
73 /* aprs msg items */
74 static int hf_aprs_msg = -1;
75 static int hf_aprs_msg_rng = -1;
76 static int hf_aprs_msg_cse = -1;
77 static int hf_aprs_msg_spd = -1;
78 static int hf_aprs_msg_dir = -1;
79 static int hf_aprs_msg_brg = -1;
80 static int hf_aprs_msg_nrq = -1;
82 /* aprs compression type items */
83 static int hf_aprs_compression_type = -1;
84 static int hf_aprs_ct_gps_fix = -1;
85 static int hf_aprs_ct_nmea_src = -1;
86 static int hf_aprs_ct_origin = -1;
88 /* phg msg items */
89 static int hf_aprs_msg_phg_p = -1;
90 static int hf_aprs_msg_phg_h = -1;
91 static int hf_aprs_msg_phg_g = -1;
92 static int hf_aprs_msg_phg_d = -1;
94 /* dfs msg items */
95 static int hf_aprs_msg_dfs_s = -1;
96 static int hf_aprs_msg_dfs_h = -1;
97 static int hf_aprs_msg_dfs_g = -1;
98 static int hf_aprs_msg_dfs_d = -1;
100 /* weather items */
101 static int hf_aprs_weather_dir = -1;
102 static int hf_aprs_weather_spd = -1;
103 static int hf_aprs_weather_peak = -1;
104 static int hf_aprs_weather_temp = -1;
105 static int hf_aprs_weather_rain_1 = -1;
106 static int hf_aprs_weather_rain_24 = -1;
107 static int hf_aprs_weather_rain = -1;
108 static int hf_aprs_weather_humidty = -1;
109 static int hf_aprs_weather_press = -1;
110 static int hf_aprs_weather_luminosity = -1;
111 static int hf_aprs_weather_snow = -1;
112 static int hf_aprs_weather_raw_rain = -1;
113 static int hf_aprs_weather_software = -1;
114 static int hf_aprs_weather_unit = -1;
116 /* aod msg items */
117 static int hf_aprs_msg_aod_t = -1;
118 static int hf_aprs_msg_aod_c = -1;
120 /* mic-e msg items */
121 static int hf_aprs_mic_e_dst = -1;
122 static int hf_aprs_mic_e_long_d = -1;
123 static int hf_aprs_mic_e_long_m = -1;
124 static int hf_aprs_mic_e_long_h = -1;
125 static int hf_aprs_mic_e_spd_sp = -1;
126 static int hf_aprs_mic_e_spd_dc = -1;
127 static int hf_aprs_mic_e_spd_se = -1;
128 static int hf_aprs_mic_e_telemetry = -1;
129 static int hf_aprs_mic_e_status = -1;
131 /* Storm items */
132 static int hf_aprs_storm_dir = -1;
133 static int hf_aprs_storm_spd = -1;
134 static int hf_aprs_storm_type = -1;
135 static int hf_aprs_storm_sws = -1;
136 static int hf_aprs_storm_pwg = -1;
137 static int hf_aprs_storm_cp = -1;
138 static int hf_aprs_storm_rhw = -1;
139 static int hf_aprs_storm_rtsw = -1;
140 static int hf_aprs_storm_rwg = -1;
142 /* aprs sundry items */
143 static int hf_aprs_dti = -1;
144 static int hf_aprs_sym_id = -1;
145 static int hf_aprs_sym_code = -1;
146 static int hf_aprs_comment = -1;
147 static int hf_aprs_storm = -1;
149 /* aprs main catgories items */
150 static int hf_ultimeter_2000 = -1;
151 static int hf_aprs_status = -1;
152 static int hf_aprs_object = -1;
153 static int hf_aprs_item = -1;
154 static int hf_aprs_query = -1;
155 static int hf_aprs_telemetry = -1;
156 static int hf_aprs_raw = -1;
157 static int hf_aprs_station = -1;
158 static int hf_aprs_message = -1;
159 static int hf_aprs_agrelo = -1;
160 static int hf_aprs_maidenhead = -1;
161 static int hf_aprs_weather = -1;
162 static int hf_aprs_invalid_test = -1;
163 static int hf_aprs_user_defined = -1;
164 static int hf_aprs_third_party = -1;
165 static int hf_aprs_mic_e_0_current = -1;
166 static int hf_aprs_mic_e_0_old = -1;
167 static int hf_aprs_mic_e_old = -1;
168 static int hf_aprs_mic_e_current = -1;
169 static int hf_aprs_peet_1 = -1;
170 static int hf_aprs_peet_2 = -1;
171 static int hf_aprs_map_feature = -1;
172 static int hf_aprs_shelter_data = -1;
173 static int hf_aprs_space_weather = -1;
176 /* Global preferences */
177 static gboolean gPREF_APRS_LAX = FALSE;
179 /* Initialize the subtree pointers */
180 static gint ett_aprs = -1;
181 static gint ett_aprs_msg = -1;
182 static gint ett_aprs_ct = -1;
183 static gint ett_aprs_weather = -1;
184 static gint ett_aprs_storm = -1;
185 static gint ett_aprs_mic_e = -1;
188 const value_string ctype_vals[] = {
189 { 0, "Compressed" },
190 { 1, "TNC BText" },
191 { 2, "Software (DOS/Mac/Win/+SA)" },
192 { 3, "[tbd]" },
193 { 4, "KPC3" },
194 { 5, "Pico" },
195 { 6, "Other tracker [tbd]" },
196 { 7, "Digipeater conversion" },
197 { 0, NULL }
200 const value_string nmea_vals[] = {
201 { 0, "other" },
202 { 1, "GLL" },
203 { 2, "GGA" },
204 { 3, "RMC" },
205 { 0, NULL }
208 const value_string gps_vals[] = {
209 { 0, "old (last)" },
210 { 1, "current" },
211 { 0, NULL }
214 /* sorted */
215 static const value_string aprs_description[] = {
216 { 0x1c, "Current Mic-E Data (Rev 0 beta)" },
217 { 0x1d, "Old Mic-E Data (Rev 0 beta)" },
218 { '#', "Peet Bros U-II Weather Station" },
219 { '$', "Raw GPS data or Ultimeter 2000" },
220 { '%', "Agrelo DFJr / MicroFinder" },
221 { '&', "[Reserved - Map Feature]" },
222 { '\'', "Old Mic-E Data (current data for TM-D700)" },
223 { ')', "Item" },
224 { '*', "Peet Bros U-II Weather Station" },
225 { '+', "[Reserved - Shelter data with time]" },
226 { ',', "Invalid data or test data" },
227 { '.', "[Reserved - Space weather]" },
228 { '/', "Position + timestamp" },
229 { ':', "Message" },
230 { ';', "Object" },
231 { '<', "Station Capabilities" },
232 { '=', "Position + APRS data extension" },
233 { '>', "Status" },
234 { '?', "Query" },
235 { '@', "Position + timestamp + APRS data extension" },
236 { 'T', "Telemetry data" },
237 { '[', "Maidenhead grid locator beacon (obsolete)" },
238 { '_', "Weather Report (without position)" },
239 { '`', "Current Mic-E Data (not used in TM-D700)" },
240 { '{', "User-Defined APRS packet format" },
241 { '}', "Third-party traffic" },
242 { 0, NULL }
244 static value_string_ext aprs_description_ext = VALUE_STRING_EXT_INIT(aprs_description);
247 * Structure containing pointers to hf_ values for various subfields of
248 * the compression type field.
250 typedef struct {
251 int *hf_ct_gps_fix;
252 int *hf_ct_nmea_src;
253 int *hf_ct_origin;
254 } ct_items_s;
256 static const ct_items_s ct_items_gbl = {
257 /* all items are FT_UINT8 */
258 &hf_aprs_ct_gps_fix,
259 &hf_aprs_ct_nmea_src,
260 &hf_aprs_ct_origin
263 typedef struct {
264 int *hf_msg_phg_p;
265 int *hf_msg_phg_h;
266 int *hf_msg_phg_g;
267 int *hf_msg_phg_d;
268 int *hf_msg_rng;
269 int *hf_msg_dfs_p;
270 int *hf_msg_dfs_h;
271 int *hf_msg_dfs_g;
272 int *hf_msg_dfs_d;
273 int *hf_msg_aod_t;
274 int *hf_msg_aod_c;
275 int *hf_msg_cse;
276 int *hf_msg_spd;
277 int *hf_msg_dir;
278 int *hf_msg_brg;
279 int *hf_msg_nrq;
280 } msg_items_s;
282 static const msg_items_s msg_items_gbl = {
283 /* (All items are FT_STRING */
284 &hf_aprs_msg_phg_p,
285 &hf_aprs_msg_phg_h,
286 &hf_aprs_msg_phg_g,
287 &hf_aprs_msg_phg_d,
288 &hf_aprs_msg_rng,
289 &hf_aprs_msg_dfs_s,
290 &hf_aprs_msg_dfs_h,
291 &hf_aprs_msg_dfs_g,
292 &hf_aprs_msg_dfs_d,
293 &hf_aprs_msg_aod_t,
294 &hf_aprs_msg_aod_c,
295 &hf_aprs_msg_cse,
296 &hf_aprs_msg_spd,
297 &hf_aprs_msg_dir,
298 &hf_aprs_msg_brg,
299 &hf_aprs_msg_nrq
302 typedef struct {
303 int *hf_weather_dir;
304 int *hf_weather_spd;
305 int *hf_weather_peak;
306 int *hf_weather_temp;
307 int *hf_weather_rain_1;
308 int *hf_weather_rain_24;
309 int *hf_weather_rain;
310 int *hf_weather_humidty;
311 int *hf_weather_press;
312 int *hf_weather_luminosity;
313 int *hf_weather_snow;
314 int *hf_weather_raw_rain;
315 int *hf_weather_software;
316 int *hf_weather_unit;
317 } weather_items_s;
319 static const weather_items_s weather_items_gbl = {
320 /* (All items are FT_STRING */
321 &hf_aprs_weather_dir,
322 &hf_aprs_weather_spd,
323 &hf_aprs_weather_peak,
324 &hf_aprs_weather_temp,
325 &hf_aprs_weather_rain_1,
326 &hf_aprs_weather_rain_24,
327 &hf_aprs_weather_rain,
328 &hf_aprs_weather_humidty,
329 &hf_aprs_weather_press,
330 &hf_aprs_weather_luminosity,
331 &hf_aprs_weather_snow,
332 &hf_aprs_weather_raw_rain,
333 &hf_aprs_weather_software,
334 &hf_aprs_weather_unit
337 typedef struct {
338 int *hf_mic_e_dst;
339 int *hf_mic_e_long_d;
340 int *hf_mic_e_long_m;
341 int *hf_mic_e_long_h;
342 int *hf_mic_e_spd_sp;
343 int *hf_mic_e_spd_dc;
344 int *hf_mic_e_spd_se;
345 int *hf_mic_e_sym_code;
346 int *hf_mic_e_sym_id;
347 int *hf_mic_e_telemetry;
348 int *hf_mic_e_status;
349 } mic_e_items_s;
351 static const mic_e_items_s mic_e_items_gbl = {
352 &hf_aprs_mic_e_dst, /* FT_STRING */
353 &hf_aprs_mic_e_long_d, /* FT_GUINT8 */
354 &hf_aprs_mic_e_long_m, /* FT_GUINT8 */
355 &hf_aprs_mic_e_long_h, /* FT_GUINT8 */
356 &hf_aprs_mic_e_spd_sp, /* FT_GUINT8 */
357 &hf_aprs_mic_e_spd_dc, /* FT_GUINT8 */
358 &hf_aprs_mic_e_spd_se, /* FT_GUINT8 */
359 &hf_aprs_sym_code, /* FT_STRING */
360 &hf_aprs_sym_id, /* FT_STRING */
361 &hf_aprs_mic_e_telemetry, /* FT_BYTES */
362 &hf_aprs_mic_e_status /* FT_STRING */
365 typedef struct {
366 int *hf_aprs_storm_dir;
367 int *hf_aprs_storm_spd;
368 int *hf_aprs_storm_type;
369 int *hf_aprs_storm_sws;
370 int *hf_aprs_storm_pwg;
371 int *hf_aprs_storm_cp;
372 int *hf_aprs_storm_rhw;
373 int *hf_aprs_storm_rtsw;
374 int *hf_aprs_storm_rwg;
375 } storm_items_s;
377 /*** XXX: hf[] entries for the following are missing ***/
378 static const storm_items_s storm_items_gbl = {
379 &hf_aprs_storm_dir,
380 &hf_aprs_storm_spd,
381 &hf_aprs_storm_type,
382 &hf_aprs_storm_sws,
383 &hf_aprs_storm_pwg,
384 &hf_aprs_storm_cp,
385 &hf_aprs_storm_rhw,
386 &hf_aprs_storm_rtsw,
387 &hf_aprs_storm_rwg
390 /* MIC-E destination field code table */
391 typedef struct
393 guint8 key;
394 char digit;
395 int msg;
396 char n_s;
397 int long_offset;
398 char w_e;
399 } mic_e_dst_code_table_s;
401 static const mic_e_dst_code_table_s dst_code[] =
403 { '0' << 1, '0', 0, 'S', 0, 'E' },
404 { '1' << 1, '1', 0, 'S', 0, 'E' },
405 { '2' << 1, '2', 0, 'S', 0, 'E' },
406 { '3' << 1, '3', 0, 'S', 0, 'E' },
407 { '4' << 1, '4', 0, 'S', 0, 'E' },
408 { '5' << 1, '5', 0, 'S', 0, 'E' },
409 { '6' << 1, '6', 0, 'S', 0, 'E' },
410 { '7' << 1, '7', 0, 'S', 0, 'E' },
411 { '8' << 1, '8', 0, 'S', 0, 'E' },
412 { '9' << 1, '9', 0, 'S', 0, 'E' },
413 { 'A' << 1, '0', 1, '?', 0, '?' },
414 { 'B' << 1, '1', 1, '?', 0, '?' },
415 { 'C' << 1, '2', 1, '?', 0, '?' },
416 { 'D' << 1, '3', 1, '?', 0, '?' },
417 { 'E' << 1, '4', 1, '?', 0, '?' },
418 { 'F' << 1, '5', 1, '?', 0, '?' },
419 { 'G' << 1, '6', 1, '?', 0, '?' },
420 { 'H' << 1, '7', 1, '?', 0, '?' },
421 { 'I' << 1, '8', 1, '?', 0, '?' },
422 { 'J' << 1, '9', 1, '?', 0, '?' },
423 { 'K' << 1, ' ', 1, '?', 0, '?' },
424 { 'L' << 1, ' ', 0, 'S', 0, 'E' },
425 { 'P' << 1, '0', 1, 'N', 100, 'W' },
426 { 'Q' << 1, '1', 1, 'N', 100, 'W' },
427 { 'R' << 1, '2', 1, 'N', 100, 'W' },
428 { 'S' << 1, '3', 1, 'N', 100, 'W' },
429 { 'T' << 1, '4', 1, 'N', 100, 'W' },
430 { 'U' << 1, '5', 1, 'N', 100, 'W' },
431 { 'V' << 1, '6', 1, 'N', 100, 'W' },
432 { 'W' << 1, '7', 1, 'N', 100, 'W' },
433 { 'X' << 1, '8', 1, 'N', 100, 'W' },
434 { 'Y' << 1, '9', 1, 'N', 100, 'W' },
435 { 'Z' << 1, ' ', 1, 'N', 100, 'W' },
436 { 0, '_', 3, '?', 3, '?' },
440 /* MIC-E message table */
441 typedef struct
443 const char *std;
444 const char *custom;
445 } mic_e_msg_table_s;
447 static const mic_e_msg_table_s mic_e_msg_table[] =
449 { "Emergency", "Emergency" },
450 { "Priority", "Custom 6" },
451 { "Special", "Custom 5" },
452 { "Committed", "Custom 4" },
453 { "Returning", "Custom 3" },
454 { "In Service", "Custom 2" },
455 { "En Route", "Custom 1" },
456 { "Off Duty", "Custom 0" }
459 /* Code to actually dissect the packets */
461 static int
462 dissect_aprs_compression_type( tvbuff_t *tvb,
463 int offset,
464 proto_tree *parent_tree,
465 int hf_aprs_ctype,
466 gint ett_aprs_ctype,
467 const ct_items_s *ct_items
470 proto_tree *tc;
471 proto_tree *compression_tree;
472 int new_offset;
473 int data_len;
474 guint8 compression_type;
477 data_len = 1;
478 new_offset = offset + data_len;
480 if ( parent_tree )
482 compression_type = tvb_get_guint8( tvb, offset ) - 33;
484 tc = proto_tree_add_uint( parent_tree, hf_aprs_ctype, tvb, offset, data_len,
485 compression_type );
486 compression_tree = proto_item_add_subtree( tc, ett_aprs_ctype );
488 proto_tree_add_item( compression_tree, *ct_items->hf_ct_gps_fix, tvb, offset, data_len, ENC_BIG_ENDIAN );
489 proto_tree_add_item( compression_tree, *ct_items->hf_ct_nmea_src, tvb, offset, data_len, ENC_BIG_ENDIAN );
490 proto_tree_add_item( compression_tree, *ct_items->hf_ct_origin, tvb, offset, data_len, ENC_BIG_ENDIAN );
493 return new_offset;
496 static int
497 dissect_aprs_msg( tvbuff_t *tvb,
498 int offset,
499 proto_tree *parent_tree,
500 int hf_aprs_msg_idx,
501 gint ett_aprs_msg_idx,
502 const msg_items_s *msg_items, /* Assumption: all referenced hf[] entries are FT_STRING */
503 int wind,
504 int brg_nrq
507 proto_tree *msg_tree = NULL;
508 guint8 ch;
511 if ( parent_tree )
513 proto_tree *tc;
514 tc = proto_tree_add_item( parent_tree, hf_aprs_msg_idx, tvb, offset, 7, ENC_ASCII|ENC_NA );
515 msg_tree = proto_item_add_subtree( tc, ett_aprs_msg_idx );
518 ch = tvb_get_guint8( tvb, offset );
520 if ( isdigit( ch ) )
522 if ( wind )
523 proto_tree_add_item( msg_tree, *msg_items->hf_msg_dir, tvb, offset, 3, ENC_ASCII|ENC_NA );
524 else
525 proto_tree_add_item( msg_tree, *msg_items->hf_msg_cse, tvb, offset, 3, ENC_ASCII|ENC_NA );
526 offset += 3;
527 /* verify the separator */
528 offset += 1;
529 proto_tree_add_item( msg_tree, *msg_items->hf_msg_spd, tvb, offset, 3, ENC_ASCII|ENC_NA );
530 offset += 3;
532 else
534 switch ( ch )
536 case 'D' : /* dfs */
537 offset += 3;
538 proto_tree_add_item( msg_tree, *msg_items->hf_msg_dfs_p, tvb, offset, 1, ENC_ASCII|ENC_NA );
539 offset += 1;
540 proto_tree_add_item( msg_tree, *msg_items->hf_msg_dfs_h, tvb, offset, 1, ENC_ASCII|ENC_NA );
541 offset += 1;
542 proto_tree_add_item( msg_tree, *msg_items->hf_msg_dfs_g, tvb, offset, 1, ENC_ASCII|ENC_NA );
543 offset += 1;
544 proto_tree_add_item( msg_tree, *msg_items->hf_msg_dfs_d, tvb, offset, 1, ENC_ASCII|ENC_NA );
545 break;
546 case 'P' : /* phgd */
547 offset += 3;
548 proto_tree_add_item( msg_tree, *msg_items->hf_msg_phg_p, tvb, offset, 1, ENC_ASCII|ENC_NA );
549 offset += 1;
550 proto_tree_add_item( msg_tree, *msg_items->hf_msg_phg_h, tvb, offset, 1, ENC_ASCII|ENC_NA );
551 offset += 1;
552 proto_tree_add_item( msg_tree, *msg_items->hf_msg_phg_g, tvb, offset, 1, ENC_ASCII|ENC_NA );
553 offset += 1;
554 proto_tree_add_item( msg_tree, *msg_items->hf_msg_phg_d, tvb, offset, 1, ENC_ASCII|ENC_NA );
555 break;
556 case 'R' : /* rng */
557 proto_tree_add_item( msg_tree, *msg_items->hf_msg_rng, tvb, offset, 7, ENC_ASCII|ENC_NA );
558 break;
559 case 'T' : /* aod */
560 offset += 1;
561 proto_tree_add_item( msg_tree, *msg_items->hf_msg_aod_t, tvb, offset, 2, ENC_ASCII|ENC_NA );
562 offset += 2;
563 /* step over the /C */
564 offset += 2;
565 proto_tree_add_item( msg_tree, *msg_items->hf_msg_aod_c, tvb, offset, 2, ENC_ASCII|ENC_NA );
566 break;
567 default : /* wtf */
568 break;
571 if ( brg_nrq )
573 proto_tree_add_item( msg_tree, *msg_items->hf_msg_brg, tvb, offset, 3, ENC_ASCII|ENC_NA );
574 offset += 3;
575 /* verify the separator */
576 offset += 1;
577 proto_tree_add_item( msg_tree, *msg_items->hf_msg_nrq, tvb, offset, 3, ENC_ASCII|ENC_NA );
578 offset += 3;
581 return offset;
584 static int
585 dissect_aprs_compressed_msg( tvbuff_t *tvb,
586 int offset,
587 proto_tree *parent_tree,
588 int hf_msg_type_idx,
589 gint ett_aprs_msg_idx,
590 const msg_items_s *msg_items
593 proto_tree *tc;
594 proto_tree *msg_tree;
595 int new_offset;
596 int data_len;
597 guint8 ch;
598 guint8 course;
599 double speed;
600 double range;
601 gchar *info_buffer;
604 data_len = 2;
605 new_offset = offset + data_len;
607 if ( parent_tree )
609 tc = proto_tree_add_item( parent_tree, hf_msg_type_idx, tvb, offset, data_len, ENC_ASCII|ENC_NA );
610 msg_tree = proto_item_add_subtree( tc, ett_aprs_msg_idx );
612 ch = tvb_get_guint8( tvb, offset );
613 if ( ch != ' ' )
615 if ( ch == '{' )
616 { /* Pre-Calculated Radio Range */
617 offset += 1;
618 ch = tvb_get_guint8( tvb, offset );
619 range = exp( log( 1.08 ) * (ch - 33) );
620 info_buffer = wmem_strdup_printf( wmem_packet_scope(), "%7.2f", range );
621 proto_tree_add_string( msg_tree, *msg_items->hf_msg_rng, tvb, offset, 1, info_buffer );
623 else
624 if ( ch >= '!' && ch <= 'z' )
625 { /* Course/Speed */
626 course = (ch - 33) * 4;
627 info_buffer = wmem_strdup_printf( wmem_packet_scope(), "%d", course );
628 proto_tree_add_string( msg_tree, *msg_items->hf_msg_cse,
629 tvb, offset, 1, info_buffer );
630 offset += 1;
631 ch = tvb_get_guint8( tvb, offset );
632 speed = exp( log( 1.08 ) * (ch - 33) );
633 info_buffer = wmem_strdup_printf( wmem_packet_scope(), "%7.2f", speed );
634 proto_tree_add_string( msg_tree, *msg_items->hf_msg_spd,
635 tvb, offset, 1, info_buffer );
641 return new_offset;
645 static const mic_e_dst_code_table_s *
646 dst_code_lookup( guint8 ch )
648 guint indx;
650 indx = 0;
651 while ( indx < ( sizeof( dst_code ) / sizeof( mic_e_dst_code_table_s ) )
652 && dst_code[ indx ].key != ch
653 && dst_code[ indx ].key > 0 )
654 indx++;
655 return &( dst_code[ indx ] );
658 static int
659 d28_to_deg( guint8 code, int long_offset )
661 int value;
663 value = code - 28 + long_offset;
664 if ( value >= 180 && value <= 189 )
665 value -= 80;
666 else
667 if ( value >= 190 && value <= 199 )
668 value -= 190;
669 return value;
672 static int
673 d28_to_min( guint8 code )
675 int value;
677 value = code - 28;
678 if ( value >= 60 )
679 value -= 60;
680 return value;
683 static int
684 dissect_mic_e( tvbuff_t *tvb,
685 int offset,
686 packet_info *pinfo,
687 proto_tree *parent_tree,
688 int hf_mic_e_idx,
689 gint ett_mic_e_idx,
690 const mic_e_items_s *mic_e_items
693 proto_tree *tc;
694 proto_tree *mic_e_tree;
695 int new_offset;
696 int data_len;
697 char *info_buffer;
698 char latitude[7] = { '?', '?', '?', '?', '.', '?', '?' };
699 int msg_a;
700 int msg_b;
701 int msg_c;
702 char n_s;
703 int long_offset;
704 char w_e;
705 int cse;
706 int spd;
707 guint8 ssid;
708 const mic_e_dst_code_table_s *dst_code_entry;
710 data_len = tvb_length_remaining( tvb, offset );
711 new_offset = offset + data_len;
713 info_buffer = (char *)wmem_alloc( wmem_packet_scope(), STRLEN );
715 msg_a = 0;
716 msg_b = 0;
717 msg_c = 0;
719 n_s = '?';
720 long_offset = 0;
721 w_e = '?';
722 ssid = 0;
724 if ( pinfo->dst.type == AT_AX25 && pinfo->dst.len == AX25_ADDR_LEN )
726 /* decode the AX.25 destination address */
727 dst_code_entry = dst_code_lookup( ((guint8 *)pinfo->dst.data)[ 0 ] );
728 latitude[ 0 ] = dst_code_entry->digit;
729 msg_a = dst_code_entry->msg & 0x1;
731 dst_code_entry = dst_code_lookup( ((guint8 *)pinfo->dst.data)[ 1 ] );
732 latitude[ 1 ] = dst_code_entry->digit;
733 msg_b = dst_code_entry->msg & 0x1;
735 dst_code_entry = dst_code_lookup( ((guint8 *)pinfo->dst.data)[ 2 ] );
736 latitude[ 2 ] = dst_code_entry->digit;
737 msg_c = dst_code_entry->msg & 0x1;
739 dst_code_entry = dst_code_lookup( ((guint8 *)pinfo->dst.data)[ 3 ] );
740 latitude[ 3 ] = dst_code_entry->digit;
741 n_s = dst_code_entry->n_s;
743 latitude[ 4 ] = '.';
745 dst_code_entry = dst_code_lookup( ((guint8 *)pinfo->dst.data)[ 4 ] );
746 latitude[ 5 ] = dst_code_entry->digit;
747 long_offset = dst_code_entry->long_offset;
749 dst_code_entry = dst_code_lookup( ((guint8 *)pinfo->dst.data)[ 5 ] );
750 latitude[ 6 ] = dst_code_entry->digit;
751 w_e = dst_code_entry->w_e;
753 ssid = (((guint8 *)pinfo->dst.data)[ 6 ] >> 1) & 0x0f;
756 /* decode the mic-e info fields */
757 spd = ((tvb_get_guint8( tvb, offset + 3 ) - 28) * 10) + ((tvb_get_guint8( tvb, offset + 4 ) - 28) / 10);
758 if ( spd >= 800 )
759 spd -= 800;
761 cse = (((tvb_get_guint8( tvb, offset + 4 ) - 28) % 10) * 100) + ((tvb_get_guint8( tvb, offset + 5 ) - 28) * 10);
762 if ( cse >= 400 )
763 cse -= 400;
765 g_snprintf( info_buffer, STRLEN,
766 "Lat: %7.7s%c Long: %03d%02d.%02d%c, Cse: %d, Spd: %d, SSID: %d, Msg %s",
767 latitude,
768 n_s,
769 d28_to_deg( tvb_get_guint8( tvb, offset ), long_offset ),
770 d28_to_min( tvb_get_guint8( tvb, offset + 1 ) ),
771 tvb_get_guint8( tvb, offset + 2 ) - 28,
772 w_e,
773 cse,
774 spd,
775 ssid,
776 mic_e_msg_table[ (msg_a << 2) + (msg_b << 1) + msg_c ].std
779 col_set_str( pinfo->cinfo, COL_INFO, "MIC-E " );
780 col_append_str( pinfo->cinfo, COL_INFO, info_buffer );
782 if ( parent_tree )
784 tc = proto_tree_add_string( parent_tree, hf_mic_e_idx, tvb, offset, data_len, info_buffer );
785 mic_e_tree = proto_item_add_subtree( tc, ett_mic_e_idx );
787 g_snprintf( info_buffer, STRLEN,
788 "Lat %7.7s, Msg A %d, Msg B %d, Msg C %d, N/S %c, Long off %3d, W/E %c, SSID %d",
789 latitude,
790 msg_a,
791 msg_b,
792 msg_c,
793 n_s,
794 long_offset,
795 w_e,
796 ssid
799 proto_tree_add_string( mic_e_tree, *mic_e_items->hf_mic_e_dst, tvb, 0, 0, info_buffer ); /* ?? */
801 proto_tree_add_item( mic_e_tree, *mic_e_items->hf_mic_e_long_d, tvb, offset, 1, ENC_BIG_ENDIAN );
802 offset += 1;
804 proto_tree_add_item( mic_e_tree, *mic_e_items->hf_mic_e_long_m, tvb, offset, 1, ENC_BIG_ENDIAN );
805 offset += 1;
807 proto_tree_add_item( mic_e_tree, *mic_e_items->hf_mic_e_long_h, tvb, offset, 1, ENC_BIG_ENDIAN );
808 offset += 1;
810 proto_tree_add_item( mic_e_tree, *mic_e_items->hf_mic_e_spd_sp, tvb, offset, 1, ENC_BIG_ENDIAN );
811 offset += 1;
813 proto_tree_add_item( mic_e_tree, *mic_e_items->hf_mic_e_spd_dc, tvb, offset, 1, ENC_BIG_ENDIAN );
814 offset += 1;
816 proto_tree_add_item( mic_e_tree, *mic_e_items->hf_mic_e_spd_se, tvb, offset, 1, ENC_BIG_ENDIAN );
817 offset += 1;
819 proto_tree_add_item( mic_e_tree, *mic_e_items->hf_mic_e_sym_code, tvb, offset, 1, ENC_ASCII|ENC_NA );
820 offset += 1;
822 proto_tree_add_item( mic_e_tree, *mic_e_items->hf_mic_e_sym_id, tvb, offset, 1, ENC_ASCII|ENC_NA );
823 offset += 1;
825 if ( offset < new_offset )
827 guint8 c = tvb_get_guint8(tvb, offset);
828 if ( (c == ',') || (c == 0x1d) )
829 proto_tree_add_item( mic_e_tree, *mic_e_items->hf_mic_e_telemetry,
830 tvb, offset, -1, ENC_NA );
831 else
832 proto_tree_add_item( mic_e_tree, *mic_e_items->hf_mic_e_status,
833 tvb, offset, -1, ENC_ASCII|ENC_NA );
838 return new_offset;
841 static int
842 dissect_aprs_storm( tvbuff_t *tvb,
843 int offset,
844 proto_tree *parent_tree,
845 int hf_aprs_storm_idx,
846 gint ett_aprs_storm_idx,
847 const storm_items_s *storm_items
850 proto_tree *storm_tree = NULL;
852 if ( parent_tree )
854 proto_tree *tc;
855 int data_len;
856 char *info_buffer;
857 static const char *storm_format = " (%*.*s)";
859 data_len = tvb_length_remaining( tvb, offset );
860 info_buffer = (char *)wmem_alloc( wmem_packet_scope(), STRLEN );
861 g_snprintf( info_buffer, STRLEN, storm_format, data_len, data_len, tvb_get_ptr( tvb, offset, data_len ) );
862 tc = proto_tree_add_string( parent_tree, hf_aprs_storm_idx, tvb, offset, data_len, info_buffer );
863 storm_tree = proto_item_add_subtree( tc, ett_aprs_storm_idx );
865 proto_tree_add_item( storm_tree, *storm_items->hf_aprs_storm_dir, tvb, offset, 3, ENC_BIG_ENDIAN );
866 offset += 3;
867 offset += 1;
868 proto_tree_add_item( storm_tree, *storm_items->hf_aprs_storm_spd, tvb, offset, 3, ENC_BIG_ENDIAN );
869 offset += 3;
870 proto_tree_add_item( storm_tree, *storm_items->hf_aprs_storm_type, tvb, offset, 3, ENC_BIG_ENDIAN );
871 offset += 3;
872 proto_tree_add_item( storm_tree, *storm_items->hf_aprs_storm_sws, tvb, offset, 4, ENC_BIG_ENDIAN );
873 offset += 4;
874 proto_tree_add_item( storm_tree, *storm_items->hf_aprs_storm_pwg, tvb, offset, 4, ENC_BIG_ENDIAN );
875 offset += 4;
876 proto_tree_add_item( storm_tree, *storm_items->hf_aprs_storm_cp, tvb, offset, 5, ENC_BIG_ENDIAN );
877 offset += 5;
878 proto_tree_add_item( storm_tree, *storm_items->hf_aprs_storm_rhw, tvb, offset, 4, ENC_BIG_ENDIAN );
879 offset += 4;
880 proto_tree_add_item( storm_tree, *storm_items->hf_aprs_storm_rtsw, tvb, offset, 4, ENC_BIG_ENDIAN );
881 offset += 4;
882 proto_tree_add_item( storm_tree, *storm_items->hf_aprs_storm_rwg, tvb, offset, 4, ENC_BIG_ENDIAN );
883 offset += 4;
885 return offset;
888 static int
889 dissect_aprs_weather( tvbuff_t *tvb,
890 int offset,
891 proto_tree *parent_tree,
892 int hf_aprs_weather_idx,
893 gint ett_aprs_weather_idx,
894 const weather_items_s *weather_items
897 proto_tree *tc;
898 proto_tree *weather_tree;
899 int new_offset;
900 int data_len;
901 char *info_buffer;
902 static const char *weather_format = " (%*.*s)";
903 guint8 ch;
906 data_len = tvb_length_remaining( tvb, offset );
907 new_offset = offset + data_len;
909 info_buffer = (char *)wmem_alloc( wmem_packet_scope(), STRLEN );
910 g_snprintf( info_buffer, STRLEN, weather_format, data_len, data_len, tvb_get_ptr( tvb, offset, data_len ) );
912 tc = proto_tree_add_string( parent_tree, hf_aprs_weather_idx, tvb, offset, data_len, info_buffer );
913 weather_tree = proto_item_add_subtree( tc, ett_aprs_weather_idx );
915 ch = tvb_get_guint8( tvb, offset );
916 if ( isdigit( ch ) )
918 proto_tree_add_item( weather_tree, *weather_items->hf_weather_dir, tvb, offset, 3, ENC_ASCII|ENC_NA );
919 offset += 3;
920 /* verify the separator */
921 offset += 1;
922 proto_tree_add_item( weather_tree, *weather_items->hf_weather_spd, tvb, offset, 3, ENC_ASCII|ENC_NA );
923 offset += 3;
926 if ( parent_tree )
928 while ( offset < new_offset )
930 ch = tvb_get_guint8( tvb, offset );
931 switch ( ch )
933 case 'c' :
934 proto_tree_add_item( weather_tree, *weather_items->hf_weather_dir,
935 tvb, offset, 4, ENC_ASCII|ENC_NA );
936 offset += 4;
937 break;
938 case 's' :
939 proto_tree_add_item( weather_tree, *weather_items->hf_weather_spd,
940 tvb, offset, 4, ENC_ASCII|ENC_NA );
941 offset += 4;
942 break;
943 case 'g' :
944 proto_tree_add_item( weather_tree, *weather_items->hf_weather_peak,
945 tvb, offset, 4, ENC_ASCII|ENC_NA );
946 offset += 4;
947 break;
948 case 't' :
949 proto_tree_add_item( weather_tree, *weather_items->hf_weather_temp,
950 tvb, offset, 4, ENC_ASCII|ENC_NA );
951 offset += 4;
952 break;
953 case 'r' :
954 proto_tree_add_item( weather_tree, *weather_items->hf_weather_rain_1,
955 tvb, offset, 4, ENC_ASCII|ENC_NA );
956 offset += 4;
957 break;
958 case 'P' :
959 proto_tree_add_item( weather_tree, *weather_items->hf_weather_rain_24,
960 tvb, offset, 4, ENC_ASCII|ENC_NA );
961 offset += 4;
962 break;
963 case 'p' :
964 proto_tree_add_item( weather_tree, *weather_items->hf_weather_rain,
965 tvb, offset, 4, ENC_ASCII|ENC_NA );
966 offset += 4;
967 break;
968 case 'h' :
969 proto_tree_add_item( weather_tree, *weather_items->hf_weather_humidty,
970 tvb, offset, 3, ENC_ASCII|ENC_NA );
971 offset += 3;
972 break;
973 case 'b' :
974 proto_tree_add_item( weather_tree, *weather_items->hf_weather_press,
975 tvb, offset, 6, ENC_ASCII|ENC_NA );
976 offset += 6;
977 break;
978 case 'l' :
979 case 'L' :
980 proto_tree_add_item( weather_tree, *weather_items->hf_weather_luminosity,
981 tvb, offset, 4, ENC_ASCII|ENC_NA );
982 offset += 4;
983 break;
984 case 'S' :
985 proto_tree_add_item( weather_tree, *weather_items->hf_weather_snow,
986 tvb, offset, 4, ENC_ASCII|ENC_NA );
987 offset += 4;
988 break;
989 case '#' :
990 proto_tree_add_item( weather_tree, *weather_items->hf_weather_raw_rain,
991 tvb, offset, 4, ENC_ASCII|ENC_NA );
992 offset += 4;
993 break;
994 default : {
995 gint lr;
996 /* optional: software type/unit: see if present */
997 lr = new_offset - offset;
998 #if 0 /* fcn'al change: defer */
999 if ( ((lr < 3) || (lr > 5)) ||
1000 ( lr != strspn( tvb_get_string( wmem_packet_scope(), tvb, offset, lr ), "a-zA-Z0-9-_" ) ) )
1002 new_offset = offset; /* Assume rest is a comment: force exit from while */
1003 break; /* from switch */
1005 #endif
1006 proto_tree_add_item( weather_tree, *weather_items->hf_weather_software,
1007 tvb, offset, 1, ENC_ASCII|ENC_NA );
1008 offset += 1;
1009 proto_tree_add_item( weather_tree, *weather_items->hf_weather_unit,
1010 tvb, offset, lr-1, ENC_ASCII|ENC_NA );
1011 offset = new_offset;
1012 break;
1014 } /* switch */
1015 } /* while */
1016 } /* if (parent_tree) */
1017 return new_offset;
1020 static int
1021 aprs_timestamp( proto_tree *aprs_tree, tvbuff_t *tvb, int offset )
1023 int data_len;
1024 const char *tzone;
1025 guint8 ch;
1027 data_len = 8;
1028 tzone = "zulu";
1030 ch= tvb_get_guint8( tvb, offset + 6 );
1031 if ( isdigit( ch ) )
1032 { /* MDHM */
1033 proto_tree_add_item( aprs_tree, hf_aprs_mdhm, tvb, offset, data_len, ENC_ASCII|ENC_NA );
1034 proto_tree_add_string( aprs_tree, hf_aprs_tz, tvb, offset, data_len, tzone );
1036 else
1038 data_len -= 1;
1039 if ( ch == 'h' )
1040 { /* HMS */
1041 proto_tree_add_item( aprs_tree, hf_aprs_hms, tvb, offset, data_len, ENC_ASCII|ENC_NA );
1042 proto_tree_add_string( aprs_tree, hf_aprs_tz, tvb, offset, data_len, tzone );
1044 else
1045 { /* DHM */
1046 switch ( ch )
1048 case 'z' : tzone = "zulu"; break;
1049 case '/' : tzone = "local"; break;
1050 default : tzone = "unknown"; break;
1052 proto_tree_add_item( aprs_tree, hf_aprs_dhm, tvb, offset, data_len, ENC_ASCII|ENC_NA );
1053 proto_tree_add_string( aprs_tree, hf_aprs_tz, tvb, offset + 6, 1, tzone );
1057 return offset + data_len;
1060 static int
1061 aprs_latitude_compressed( proto_tree *aprs_tree, tvbuff_t *tvb, int offset )
1063 if ( aprs_tree )
1065 char *info_buffer;
1066 int temp;
1068 info_buffer = (char *)wmem_alloc( wmem_packet_scope(), STRLEN );
1070 temp = ( tvb_get_guint8( tvb, offset + 0 ) - 33 );
1071 temp = ( tvb_get_guint8( tvb, offset + 1 ) - 33 ) + ( temp * 91 );
1072 temp = ( tvb_get_guint8( tvb, offset + 2 ) - 33 ) + ( temp * 91 );
1073 temp = ( tvb_get_guint8( tvb, offset + 3 ) - 33 ) + ( temp * 91 );
1075 g_snprintf( info_buffer, STRLEN, "%6.2f", 90.0 - (temp / 380926.0) );
1076 proto_tree_add_string( aprs_tree, hf_aprs_lat, tvb, offset, 4, info_buffer );
1078 return offset + 4;
1081 static int
1082 aprs_longitude_compressed( proto_tree *aprs_tree, tvbuff_t *tvb, int offset )
1084 if ( aprs_tree )
1086 char *info_buffer;
1087 int temp;
1089 info_buffer = (char *)wmem_alloc( wmem_packet_scope(), STRLEN );
1091 temp = ( tvb_get_guint8( tvb, offset + 0 ) - 33 );
1092 temp = ( tvb_get_guint8( tvb, offset + 1 ) - 33 ) + ( temp * 91 );
1093 temp = ( tvb_get_guint8( tvb, offset + 2 ) - 33 ) + ( temp * 91 );
1094 temp = ( tvb_get_guint8( tvb, offset + 3 ) - 33 ) + ( temp * 91 );
1096 g_snprintf( info_buffer, STRLEN, "%7.2f", (temp / 190463.0) - 180.0 );
1097 proto_tree_add_string( aprs_tree, hf_aprs_long, tvb, offset, 4, info_buffer );
1099 return offset + 4;
1102 static int
1103 aprs_status( proto_tree *aprs_tree, tvbuff_t *tvb, int offset )
1105 int data_len;
1107 data_len = tvb_length_remaining( tvb, offset );
1109 if ( ( data_len > 7 ) && ( tvb_get_guint8( tvb, offset+6 ) == 'z' ) )
1111 proto_tree_add_item( aprs_tree, hf_aprs_dhm, tvb, offset, 6, ENC_ASCII|ENC_NA );
1112 offset += 6;
1113 data_len -= 6;
1114 proto_tree_add_string( aprs_tree, hf_aprs_tz, tvb, offset, 1, "zulu" );
1115 offset += 1;
1116 data_len -= 1;
1118 proto_tree_add_item( aprs_tree, hf_aprs_status, tvb, offset, data_len, ENC_ASCII|ENC_NA );
1120 return offset + data_len;
1123 static int
1124 aprs_item( proto_tree *aprs_tree, tvbuff_t *tvb, int offset )
1126 char *info_buffer;
1127 int data_len;
1128 char *ch_ptr;
1130 data_len = 10;
1132 info_buffer = tvb_get_string( wmem_packet_scope(), tvb, offset, data_len );
1134 ch_ptr = strchr( info_buffer, '!' );
1135 if ( ch_ptr != NULL )
1137 data_len = (int)(ch_ptr - info_buffer + 1);
1138 *ch_ptr = '\0';
1140 else
1142 ch_ptr = strchr( info_buffer, '!' );
1143 if ( ch_ptr != NULL )
1145 data_len = (int)(ch_ptr - info_buffer + 1);
1146 *ch_ptr = '\0';
1149 proto_tree_add_string( aprs_tree, hf_aprs_item, tvb, offset, data_len, info_buffer );
1151 return offset + data_len;
1154 static int
1155 aprs_3rd_party( proto_tree *aprs_tree, tvbuff_t *tvb, int offset, int data_len )
1157 /* If the type of the hf[] entry pointed to by hfindex is FT_BYTES or FT_STRING */
1158 /* then data_len == -1 is allowed and means "remainder of the tvbuff" */
1159 if ( data_len == -1 )
1161 data_len = tvb_reported_length_remaining( tvb, offset );
1162 #if 0 /* fcn'al change: defer */
1163 if ( data_len <= 0 )
1164 return offset; /* there's no data */
1165 #endif
1167 proto_tree_add_item( aprs_tree, hf_aprs_third_party, tvb, offset, data_len, ENC_NA );
1168 /* tnc-2 */
1169 /* aea */
1170 return offset + data_len;
1173 static int
1174 aprs_default_string( proto_tree *aprs_tree, tvbuff_t *tvb, int offset, int data_len, int hfindex )
1176 /* Assumption: hfindex points to an hf[] entry with type FT_STRING; should be validated ? */
1177 /* If the type of the hf[] entry pointed to by hfindex is FT_STRING */
1178 /* then data_len == -1 is allowed and means "remainder of the tvbuff" */
1179 if ( data_len == -1 )
1181 data_len = tvb_reported_length_remaining( tvb, offset );
1182 #if 0 /* fcn'al change: defer */
1183 if ( data_len <= 0 )
1184 return offset; /* there's no data */
1185 #endif
1187 proto_tree_add_item( aprs_tree, hfindex, tvb, offset, data_len, ENC_ASCII|ENC_NA );
1188 return offset + data_len;
1191 static int
1192 aprs_default_bytes( proto_tree *aprs_tree, tvbuff_t *tvb, int offset, int data_len, int hfindex )
1194 /* Assumption: hfindex points to an hf[] entry with type FT_BYTES; should be validated ? */
1195 /* If the type of the hf[] entry pointed to by hfindex is FT_BYTES */
1196 /* then data_len == -1 is allowed and means "remainder of the tvbuff" */
1197 if ( data_len == -1 )
1199 data_len = tvb_reported_length_remaining( tvb, offset );
1200 #if 0 /* fcn'al change: defer */
1201 if ( data_len <= 0 )
1202 return offset; /* there's no data */
1203 #endif
1205 proto_tree_add_item( aprs_tree, hfindex, tvb, offset, data_len, ENC_NA );
1206 return offset + data_len;
1209 static int
1210 aprs_position( proto_tree *aprs_tree, tvbuff_t *tvb, int offset, gboolean with_msg )
1212 guint8 symbol_table_id = 0;
1213 guint8 symbol_code = 0;
1214 gboolean probably_a_msg = FALSE;
1215 gboolean probably_not_a_msg = FALSE;
1217 if ( isdigit( tvb_get_guint8( tvb, offset ) ) )
1219 offset = aprs_default_string( aprs_tree, tvb, offset, 8, hf_aprs_lat );
1220 symbol_table_id = tvb_get_guint8( tvb, offset );
1221 offset = aprs_default_string( aprs_tree, tvb, offset, 1, hf_aprs_sym_id );
1222 offset = aprs_default_string( aprs_tree, tvb, offset, 9, hf_aprs_long );
1223 symbol_code = tvb_get_guint8( tvb, offset );
1224 offset = aprs_default_string( aprs_tree, tvb, offset, 1, hf_aprs_sym_code );
1225 if ( gPREF_APRS_LAX )
1227 switch ( tvb_get_guint8( tvb, offset ) )
1229 case 'D' : probably_a_msg = TRUE; break;
1230 case 'P' : probably_a_msg = TRUE; break;
1231 case 'R' : probably_a_msg = TRUE; break;
1232 case 'T' : probably_a_msg = TRUE; break;
1233 default : probably_not_a_msg = TRUE; break;
1236 if ( with_msg || probably_a_msg || ! probably_not_a_msg )
1237 offset = dissect_aprs_msg( tvb,
1238 offset,
1239 aprs_tree,
1240 hf_aprs_msg,
1241 ett_aprs_msg,
1242 &msg_items_gbl,
1243 ( symbol_code == '_' ),
1244 ( symbol_table_id == '/' && symbol_code == '\\' )
1247 else
1249 symbol_table_id = tvb_get_guint8( tvb, offset );
1250 offset = aprs_default_string( aprs_tree, tvb, offset, 1, hf_aprs_sym_id );
1251 offset = aprs_latitude_compressed( aprs_tree, tvb, offset );
1252 offset = aprs_longitude_compressed( aprs_tree, tvb, offset );
1253 symbol_code = tvb_get_guint8( tvb, offset );
1254 offset = aprs_default_string( aprs_tree, tvb, offset, 1, hf_aprs_sym_code );
1255 offset = dissect_aprs_compressed_msg( tvb,
1256 offset,
1257 aprs_tree,
1258 hf_aprs_msg,
1259 ett_aprs_msg,
1260 &msg_items_gbl
1262 offset = dissect_aprs_compression_type( tvb,
1263 offset,
1264 aprs_tree,
1265 hf_aprs_compression_type,
1266 ett_aprs_ct,
1267 &ct_items_gbl
1269 if ( symbol_table_id == '/' && symbol_code == '\\' )
1270 offset = aprs_default_string( aprs_tree, tvb, offset, 8, hf_aprs_msg_brg );
1273 if ( symbol_code == '_' )
1274 offset = dissect_aprs_weather( tvb,
1275 offset,
1276 aprs_tree,
1277 hf_aprs_weather,
1278 ett_aprs_weather,
1279 &weather_items_gbl
1281 if ( ( symbol_table_id == '/' && symbol_code == '@' ) || ( symbol_table_id == '\\' && symbol_code == '@' ) )
1282 offset = dissect_aprs_storm( tvb,
1283 offset,
1284 aprs_tree,
1285 hf_aprs_storm,
1286 ett_aprs_storm,
1287 &storm_items_gbl
1290 return offset;
1293 static int
1294 dissect_aprs( tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void *data _U_ )
1296 proto_item *ti;
1297 proto_tree *aprs_tree;
1299 int offset;
1300 guint8 dti;
1301 const guint8 *bufp;
1302 wmem_strbuf_t *sb;
1304 col_set_str( pinfo->cinfo, COL_PROTOCOL, "APRS" );
1305 col_clear( pinfo->cinfo, COL_INFO );
1307 offset = 0;
1309 dti = tvb_get_guint8( tvb, offset );
1311 sb = wmem_strbuf_new_label(wmem_packet_scope());
1313 if (dti != '!')
1314 wmem_strbuf_append(sb, val_to_str_ext_const(dti, &aprs_description_ext, ""));;
1316 switch ( dti )
1318 case '!':
1319 /* Position or Ultimeter 2000 WX Station */
1320 if ( tvb_get_guint8( tvb, offset + 1 ) == '!' )
1322 wmem_strbuf_append(sb, "Ultimeter 2000 WX Station");
1324 else
1326 /* Position "without APRS messaging" */
1327 wmem_strbuf_append(sb, "Position");
1328 bufp = tvb_get_ptr(tvb, offset + 1, 8 + 9 + 1 + 1);
1329 wmem_strbuf_append_printf(sb, " (%8.8s %9.9s %1.1s%1.1s)",
1330 bufp, /* Lat */
1331 bufp + 8 + 1, /* Long */
1332 bufp + 8, /* Symbol table id */
1333 bufp + 8 + 1 + 9 /* Symbol Code */
1336 break;
1338 case '=':
1339 /* Position "with APRS messaging" + Ext APRS message */
1340 bufp = tvb_get_ptr(tvb, offset + 1, 8 + 9 + 1 + 1);
1341 wmem_strbuf_append_printf(sb, " (%8.8s %9.9s %1.1s%1.1s)",
1342 bufp, /* Lat */
1343 bufp + 8 + 1, /* Long */
1344 bufp + 8 , /* Symbol table id */
1345 bufp + 8 + 1 + 9 /* Symbol Code */
1347 break;
1349 case '/':
1350 /* Position + timestamp "without APRS messaging" */
1351 bufp = tvb_get_ptr(tvb, offset + 1, 7 + 8 + 9 + 1 + 1);
1352 wmem_strbuf_append_printf(sb, " (%7.7s %8.8s %9.9s %1.1s%1.1s)",
1353 bufp, /* Timestamp */
1354 bufp + 7 + 1, /*??*/ /* Lat */
1355 bufp + 7 + 8 + 1, /* Long */
1356 bufp + 7 , /* Symbol table id */
1357 bufp + 7 + 1 + 9 /* Symbol Code */
1359 break;
1361 case '@':
1362 /* Position + timestamp "with APRS messaging" + Ext APRS message */
1363 bufp = tvb_get_ptr(tvb, offset + 1, 7 + 8 + 9 + 1 + 1);
1364 wmem_strbuf_append_printf(sb, " (%7.7s %8.8s %9.9s %1.1s%1.1s)",
1365 bufp, /* Timestamp */
1366 bufp + 7 + 1, /*??*/ /* Lat */
1367 bufp + 7 + 8 + 1, /* Long */
1368 bufp + 7 , /* Symbol table id */
1369 bufp + 7 + 1 + 9 /* Symbol Code */
1371 break;
1374 col_add_str( pinfo->cinfo, COL_INFO, wmem_strbuf_get_str(sb) );
1376 /* create display subtree for the protocol */
1377 ti = proto_tree_add_protocol_format( parent_tree , proto_aprs, tvb, 0, -1, "%s", wmem_strbuf_get_str(sb) );
1378 aprs_tree = proto_item_add_subtree( ti, ett_aprs );
1380 proto_tree_add_item( aprs_tree, hf_aprs_dti, tvb, offset, 1, ENC_ASCII|ENC_NA );
1381 offset += 1;
1383 switch ( dti )
1385 case '<' : /* Station Capabilities */
1386 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_station );
1387 break;
1388 case '>' : /* Status */
1389 offset = aprs_status( aprs_tree, tvb, offset );
1390 break;
1391 case '?' : /* Query */
1392 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_query );
1393 break;
1394 case '$' : /* Raw GPS data or Ultimeter 2000 */
1395 if ( tvb_get_guint8( tvb, offset ) == 'U' )
1396 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_ultimeter_2000 );
1397 else
1398 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_raw );
1399 break;
1400 case '%' : /* Agrelo DFJr / MicroFinder */
1401 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_agrelo );
1402 break;
1403 case 'T' : /* Telemetry data */
1404 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_telemetry );
1405 break;
1406 case '[' : /* Maidenhead grid locator beacon (obsolete) */
1407 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_maidenhead );
1408 break;
1409 case '_' : /* Weather Report (without position) */
1410 offset = aprs_timestamp( aprs_tree, tvb, offset );
1411 offset = dissect_aprs_weather( tvb,
1412 offset,
1413 aprs_tree,
1414 hf_aprs_weather,
1415 ett_aprs_weather,
1416 &weather_items_gbl
1418 break;
1419 case ',' : /* Invalid data or test data */
1420 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_invalid_test );
1421 break;
1422 case '{' : /* User-Defined APRS packet format */
1423 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_user_defined );
1424 break;
1425 case '}' : /* Third-party traffic */
1426 offset = aprs_3rd_party( aprs_tree, tvb, offset, -1 );
1427 break;
1428 case ':' : /* Message */
1429 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_message );
1430 break;
1431 case 0x1c : /* Current Mic-E Data (Rev 0 beta) */
1432 offset = dissect_mic_e( tvb,
1433 offset,
1434 pinfo,
1435 aprs_tree,
1436 hf_aprs_mic_e_0_current,
1437 ett_aprs_mic_e,
1438 &mic_e_items_gbl
1440 break;
1441 case 0x1d : /* Old Mic-E Data (Rev 0 beta) */
1442 offset = dissect_mic_e( tvb,
1443 offset,
1444 pinfo,
1445 aprs_tree,
1446 hf_aprs_mic_e_0_old,
1447 ett_aprs_mic_e,
1448 &mic_e_items_gbl
1450 break;
1451 case '\'' : /* Old Mic-E Data (but Current data for TM-D700) */
1452 offset = dissect_mic_e( tvb,
1453 offset,
1454 pinfo,
1455 aprs_tree,
1456 hf_aprs_mic_e_old,
1457 ett_aprs_mic_e,
1458 &mic_e_items_gbl
1460 break;
1461 case '`' : /* Current Mic-E Data (not used in TM-D700) */
1462 offset = dissect_mic_e( tvb,
1463 offset,
1464 pinfo,
1465 aprs_tree,
1466 hf_aprs_mic_e_current,
1467 ett_aprs_mic_e,
1468 &mic_e_items_gbl
1470 break;
1471 case '#' : /* Peet Bros U-II Weather Station */
1472 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_peet_1 );
1473 break;
1474 case '*' : /* Peet Bros U-II Weather Station */
1475 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_peet_2 );
1476 break;
1477 case '&' : /* [Reserved - Map Feature] */
1478 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_map_feature );
1479 break;
1480 case '+' : /* [Reserved - Shelter data with time] */
1481 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_shelter_data );
1482 break;
1483 case '.' : /* [Reserved - Space weather] */
1484 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_space_weather );
1485 break;
1486 case ')' : /* Item */
1487 offset = aprs_item( aprs_tree, tvb, offset );
1488 offset = aprs_position( aprs_tree, tvb, offset, TRUE );
1489 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1490 break;
1491 case ';' : /* Object */
1492 offset = aprs_default_string( aprs_tree, tvb, offset, 10, hf_aprs_object );
1493 offset = aprs_timestamp( aprs_tree, tvb, offset );
1494 offset = aprs_position( aprs_tree, tvb, offset, TRUE );
1495 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1496 break;
1497 case '!' : /* Position or Ultimeter 2000 WX Station */
1498 if ( tvb_get_guint8( tvb, offset ) == '!' )
1499 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_ultimeter_2000 );
1500 else
1502 offset = aprs_position( aprs_tree, tvb, offset, FALSE );
1503 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1505 break;
1506 case '=' : /* Position + Ext APRS message */
1507 offset = aprs_position( aprs_tree, tvb, offset, TRUE );
1508 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1509 break;
1510 case '/' : /* Position + timestamp */
1511 offset = aprs_timestamp( aprs_tree, tvb, offset );
1512 offset = aprs_position( aprs_tree, tvb, offset, FALSE );
1513 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1514 break;
1515 case '@' : /* Position + timestamp + Ext APRS message */
1516 offset = aprs_timestamp( aprs_tree, tvb, offset );
1517 offset = aprs_position( aprs_tree, tvb, offset, TRUE );
1518 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1519 break;
1520 default : break;
1522 return offset;
1525 void
1526 proto_register_aprs( void )
1528 module_t *aprs_module;
1530 /* Setup list of header fields */
1531 static hf_register_info hf[] = {
1532 { &hf_aprs_dti,
1533 { "DTI", "aprs.dti",
1534 FT_STRING, BASE_NONE, NULL, 0x0,
1535 "Data type indicator", HFILL }
1537 { &hf_aprs_sym_code,
1538 { "Symbol code", "aprs.sym_code",
1539 FT_STRING, BASE_NONE, NULL, 0x0,
1540 NULL, HFILL }
1542 { &hf_aprs_sym_id,
1543 { "Symbol table ID", "aprs.sym_id",
1544 FT_STRING, BASE_NONE, NULL, 0x0,
1545 NULL, HFILL }
1548 /* Position */
1549 #if 0
1550 { &hf_aprs_position,
1551 { "Position", "aprs.position",
1552 FT_STRING, BASE_NONE, NULL, 0x0,
1553 NULL, HFILL }
1555 #endif
1556 { &hf_aprs_lat,
1557 { "Latitude", "aprs.position.lat",
1558 FT_STRING, BASE_NONE, NULL, 0x0,
1559 NULL, HFILL }
1561 { &hf_aprs_long,
1562 { "Longitude", "aprs.position.long",
1563 FT_STRING, BASE_NONE, NULL, 0x0,
1564 NULL, HFILL }
1567 /* APRS Messages */
1568 { &hf_aprs_comment,
1569 { "Comment", "aprs.comment",
1570 FT_STRING, BASE_NONE, NULL, 0x0,
1571 NULL, HFILL }
1573 { &hf_ultimeter_2000,
1574 { "Ultimeter 2000", "aprs.ultimeter_2000",
1575 FT_STRING, BASE_NONE, NULL, 0x0,
1576 NULL, HFILL }
1578 { &hf_aprs_status,
1579 { "Status", "aprs.status",
1580 FT_STRING, BASE_NONE, NULL, 0x0,
1581 NULL, HFILL }
1583 { &hf_aprs_object,
1584 { "Object", "aprs.object",
1585 FT_STRING, BASE_NONE, NULL, 0x0,
1586 NULL, HFILL }
1588 { &hf_aprs_item,
1589 { "Item", "aprs.item",
1590 FT_STRING, BASE_NONE, NULL, 0x0,
1591 NULL, HFILL }
1593 { &hf_aprs_query,
1594 { "Query", "aprs.query",
1595 FT_STRING, BASE_NONE, NULL, 0x0,
1596 NULL, HFILL }
1598 { &hf_aprs_telemetry,
1599 { "Telemetry", "aprs.telemetry",
1600 FT_STRING, BASE_NONE, NULL, 0x0,
1601 NULL, HFILL }
1603 { &hf_aprs_raw,
1604 { "Raw", "aprs.raw",
1605 FT_STRING, BASE_NONE, NULL, 0x0,
1606 "Raw NMEA position report format", HFILL }
1608 { &hf_aprs_station,
1609 { "Station", "aprs.station",
1610 FT_STRING, BASE_NONE, NULL, 0x0,
1611 "Station capabilities", HFILL }
1613 { &hf_aprs_message,
1614 { "Message", "aprs.message",
1615 FT_STRING, BASE_NONE, NULL, 0x0,
1616 NULL, HFILL }
1618 { &hf_aprs_agrelo,
1619 { "Agrelo", "aprs.agrelo",
1620 FT_BYTES, BASE_NONE, NULL, 0x0,
1621 "Agrelo DFJr / MicroFinder", HFILL }
1623 { &hf_aprs_maidenhead,
1624 { "Maidenhead", "aprs.maidenhead",
1625 FT_BYTES, BASE_NONE, NULL, 0x0,
1626 "Maidenhead grid locator beacon (obsolete)", HFILL }
1628 { &hf_aprs_invalid_test,
1629 { "Invalid or test", "aprs.invalid_test",
1630 FT_BYTES, BASE_NONE, NULL, 0x0,
1631 "Invalid data or test data", HFILL }
1633 { &hf_aprs_user_defined,
1634 { "User-Defined", "aprs.user_defined",
1635 FT_BYTES, BASE_NONE, NULL, 0x0,
1636 "User-Defined APRS packet format", HFILL }
1638 { &hf_aprs_third_party,
1639 { "Third-party", "aprs.third_party",
1640 FT_BYTES, BASE_NONE, NULL, 0x0,
1641 "Third-party traffic", HFILL }
1643 { &hf_aprs_peet_1,
1644 { "Peet U-II (1)", "aprs.peet_1",
1645 FT_BYTES, BASE_NONE, NULL, 0x0,
1646 "Peet Bros U-II Weather Station", HFILL }
1648 { &hf_aprs_peet_2,
1649 { "Peet U-II (2)", "aprs.peet_2",
1650 FT_BYTES, BASE_NONE, NULL, 0x0,
1651 "Peet Bros U-II Weather Station", HFILL }
1653 { &hf_aprs_map_feature,
1654 { "Map Feature", "aprs.map_feature",
1655 FT_BYTES, BASE_NONE, NULL, 0x0,
1656 "[Reserved - Map Feature", HFILL }
1658 { &hf_aprs_shelter_data,
1659 { "Shelter data", "aprs.shelter_data",
1660 FT_BYTES, BASE_NONE, NULL, 0x0,
1661 "[Reserved - Shelter data with time]", HFILL }
1663 { &hf_aprs_space_weather,
1664 { "Space weather", "aprs.space_weather",
1665 FT_BYTES, BASE_NONE, NULL, 0x0,
1666 "[Reserved - Space weather]", HFILL }
1668 { &hf_aprs_storm,
1669 { "Storm", "aprs.storm",
1670 FT_STRING, BASE_NONE, NULL, 0x0,
1671 NULL, HFILL }
1674 /* Time stamp */
1675 { &hf_aprs_dhm,
1676 { "DHM", "aprs.dhm",
1677 FT_STRING, BASE_NONE, NULL, 0x0,
1678 "Day/Hour/Minute", HFILL }
1680 { &hf_aprs_hms,
1681 { "HMS", "aprs.hms",
1682 FT_STRING, BASE_NONE, NULL, 0x0,
1683 "Hour/Minute/Second", HFILL }
1685 { &hf_aprs_mdhm,
1686 { "MDHM", "aprs.mdhm",
1687 FT_STRING, BASE_NONE, NULL, 0x0,
1688 "Month/Day/Hour/Minute", HFILL }
1690 { &hf_aprs_tz,
1691 { "TZ", "aprs.tz",
1692 FT_STRING, BASE_NONE, NULL, 0x0,
1693 "Time zone", HFILL }
1696 /* Compressed Msg */
1697 { &hf_aprs_compression_type,
1698 { "Compression type", "aprs.ct",
1699 FT_UINT8, BASE_HEX, NULL, 0x0,
1700 NULL, HFILL }
1702 { &hf_aprs_ct_gps_fix,
1703 { "GPS fix type", "aprs.ct.gps_fix",
1704 FT_UINT8, BASE_HEX, VALS(gps_vals), 0x20,
1705 NULL, HFILL }
1707 { &hf_aprs_ct_nmea_src,
1708 { "NMEA source", "aprs.ct.nmea_src",
1709 FT_UINT8, BASE_HEX, VALS(nmea_vals), 0x18,
1710 NULL, HFILL }
1712 { &hf_aprs_ct_origin,
1713 { "Compression origin", "aprs.ct.origin",
1714 FT_UINT8, BASE_HEX, VALS(ctype_vals), 0x07,
1715 NULL, HFILL }
1718 /* Ext Msg */
1719 { &hf_aprs_msg,
1720 { "Extended message", "aprs.msg",
1721 FT_STRING, BASE_NONE, NULL, 0x0,
1722 NULL, HFILL }
1724 { &hf_aprs_msg_rng,
1725 { "Range", "aprs.msg.rng",
1726 FT_STRING, BASE_NONE, NULL, 0x0,
1727 "Pre-calculated radio range", HFILL }
1729 { &hf_aprs_msg_cse,
1730 { "Course", "aprs.msg.cse",
1731 FT_STRING, BASE_NONE, NULL, 0x0,
1732 NULL, HFILL }
1734 { &hf_aprs_msg_spd,
1735 { "Speed", "aprs.msg.spd",
1736 FT_STRING, BASE_NONE, NULL, 0x0,
1737 NULL, HFILL }
1739 { &hf_aprs_msg_dir,
1740 { "Wind direction", "aprs.msg.dir",
1741 FT_STRING, BASE_NONE, NULL, 0x0,
1742 NULL, HFILL }
1744 { &hf_aprs_msg_brg,
1745 { "Bearing", "aprs.msg.brg",
1746 FT_STRING, BASE_NONE, NULL, 0x0,
1747 NULL, HFILL }
1749 { &hf_aprs_msg_nrq,
1750 { "NRQ", "aprs.msg.nrq",
1751 FT_STRING, BASE_NONE, NULL, 0x0,
1752 "Number/Range/Quality", HFILL }
1755 /* Msg PHGD */
1756 { &hf_aprs_msg_phg_p,
1757 { "Power", "aprs.msg.phg.p",
1758 FT_STRING, BASE_NONE, NULL, 0x0,
1759 NULL, HFILL }
1761 { &hf_aprs_msg_phg_h,
1762 { "Height", "aprs.msg.phg.h",
1763 FT_STRING, BASE_NONE, NULL, 0x0,
1764 NULL, HFILL }
1766 { &hf_aprs_msg_phg_g,
1767 { "Gain", "aprs.msg.phg.g",
1768 FT_STRING, BASE_NONE, NULL, 0x0,
1769 NULL, HFILL }
1771 { &hf_aprs_msg_phg_d,
1772 { "Directivity", "aprs.msg.phg.d",
1773 FT_STRING, BASE_NONE, NULL, 0x0,
1774 NULL, HFILL }
1777 /* Msg DFS */
1778 { &hf_aprs_msg_dfs_s,
1779 { "Strength", "aprs.msg.dfs.s",
1780 FT_STRING, BASE_NONE, NULL, 0x0,
1781 NULL, HFILL }
1783 { &hf_aprs_msg_dfs_h,
1784 { "Height", "aprs.msg.dfs.h",
1785 FT_STRING, BASE_NONE, NULL, 0x0,
1786 NULL, HFILL }
1788 { &hf_aprs_msg_dfs_g,
1789 { "Gain", "aprs.msg.dfs.g",
1790 FT_STRING, BASE_NONE, NULL, 0x0,
1791 NULL, HFILL }
1793 { &hf_aprs_msg_dfs_d,
1794 { "Directivity", "aprs.msg.dfs.d",
1795 FT_STRING, BASE_NONE, NULL, 0x0,
1796 NULL, HFILL }
1799 /* Msg AOD */
1800 { &hf_aprs_msg_aod_t,
1801 { "Type", "aprs.msg.aod.t",
1802 FT_STRING, BASE_NONE, NULL, 0x0,
1803 NULL, HFILL }
1805 { &hf_aprs_msg_aod_c,
1806 { "Colour", "aprs.msg.aod.c",
1807 FT_STRING, BASE_NONE, NULL, 0x0,
1808 NULL, HFILL }
1811 /* Weather */
1812 { &hf_aprs_weather,
1813 { "Weather", "aprs.weather",
1814 FT_STRING, BASE_NONE, NULL, 0x0,
1815 "Weather report", HFILL }
1817 { &hf_aprs_weather_dir,
1818 { "Wind direction", "aprs.weather.dir",
1819 FT_STRING, BASE_NONE, NULL, 0x0,
1820 NULL, HFILL }
1822 { &hf_aprs_weather_spd,
1823 { "Wind speed", "aprs.weather.speed",
1824 FT_STRING, BASE_NONE, NULL, 0x0,
1825 "Wind speed (1 minute)", HFILL }
1827 { &hf_aprs_weather_peak,
1828 { "Peak wind speed", "aprs.weather.peak",
1829 FT_STRING, BASE_NONE, NULL, 0x0,
1830 NULL, HFILL }
1832 { &hf_aprs_weather_temp,
1833 { "Temperature (F)", "aprs.weather.temp",
1834 FT_STRING, BASE_NONE, NULL, 0x0,
1835 NULL, HFILL }
1837 { &hf_aprs_weather_rain_1,
1838 { "Rain (last 1 hour)", "aprs.weather.1_hour",
1839 FT_STRING, BASE_NONE, NULL, 0x0,
1840 NULL, HFILL }
1842 { &hf_aprs_weather_rain_24,
1843 { "Rain (last 24 hours)", "aprs.weather.24_hour",
1844 FT_STRING, BASE_NONE, NULL, 0x0,
1845 NULL, HFILL }
1847 { &hf_aprs_weather_rain,
1848 { "Rain", "aprs.weather.rain",
1849 FT_STRING, BASE_NONE, NULL, 0x0,
1850 NULL, HFILL }
1852 { &hf_aprs_weather_humidty,
1853 { "Humidity", "aprs.weather.humidity",
1854 FT_STRING, BASE_NONE, NULL, 0x0,
1855 NULL, HFILL }
1857 { &hf_aprs_weather_press,
1858 { "Pressure", "aprs.weather.pressure",
1859 FT_STRING, BASE_NONE, NULL, 0x0,
1860 NULL, HFILL }
1862 { &hf_aprs_weather_luminosity,
1863 { "Luminosity", "aprs.weather.luminosity",
1864 FT_STRING, BASE_NONE, NULL, 0x0,
1865 NULL, HFILL }
1867 { &hf_aprs_weather_snow,
1868 { "Snow", "aprs.weather.snow",
1869 FT_STRING, BASE_NONE, NULL, 0x0,
1870 NULL, HFILL }
1872 { &hf_aprs_weather_raw_rain,
1873 { "Raw rain", "aprs.weather.raw_rain",
1874 FT_STRING, BASE_NONE, NULL, 0x0,
1875 NULL, HFILL }
1877 { &hf_aprs_weather_software,
1878 { "Software", "aprs.weather.software",
1879 FT_STRING, BASE_NONE, NULL, 0x0,
1880 NULL, HFILL }
1882 { &hf_aprs_weather_unit,
1883 { "Unit", "aprs.weather.unit",
1884 FT_STRING, BASE_NONE, NULL, 0x0,
1885 NULL, HFILL }
1888 /* MIC-E */
1889 { &hf_aprs_mic_e_0_current,
1890 { "Current Mic-E (Rev 0)", "aprs.mic_e_0_current",
1891 FT_STRING, BASE_NONE, NULL, 0x0,
1892 NULL, HFILL }
1894 { &hf_aprs_mic_e_0_old,
1895 { "Old Mic-E (Rev 0)", "aprs.mic_e_0_old",
1896 FT_STRING, BASE_NONE, NULL, 0x0,
1897 NULL, HFILL }
1899 { &hf_aprs_mic_e_old,
1900 { "Old Mic-E", "aprs.mic_e_old",
1901 FT_STRING, BASE_NONE, NULL, 0x0,
1902 "Old Mic-E Data (but Current data for TM-D700)", HFILL }
1904 { &hf_aprs_mic_e_current,
1905 { "Current Mic-E", "aprs.mic_e_current",
1906 FT_STRING, BASE_NONE, NULL, 0x0,
1907 "Current Mic-E Data (not used in TM-D700)", HFILL }
1909 { &hf_aprs_mic_e_dst,
1910 { "Destination Address", "aprs.mic_e.dst",
1911 FT_STRING, BASE_NONE, NULL, 0x0,
1912 NULL, HFILL }
1914 { &hf_aprs_mic_e_long_d,
1915 { "Longitude degrees", "aprs.mic_e.long_d",
1916 FT_UINT8, BASE_HEX, NULL, 0x0,
1917 NULL, HFILL }
1919 { &hf_aprs_mic_e_long_m ,
1920 { "Longitude minutes", "aprs.mic_e.long_m",
1921 FT_UINT8, BASE_HEX, NULL, 0x0,
1922 NULL, HFILL }
1924 { &hf_aprs_mic_e_long_h,
1925 { "Longitude hundreths of minutes", "aprs.mic_e.long_h",
1926 FT_UINT8, BASE_HEX, NULL, 0x0,
1927 NULL, HFILL }
1929 { &hf_aprs_mic_e_spd_sp,
1930 { "Speed (H & T)", "aprs.mic_e.speed_sp",
1931 FT_UINT8, BASE_HEX, NULL, 0x0,
1932 "Speed (hundreds & tens)", HFILL }
1934 { &hf_aprs_mic_e_spd_dc,
1935 { "Spd (U), Cse (H)", "aprs.mic_e.speed_dc",
1936 FT_UINT8, BASE_HEX, NULL, 0x0,
1937 "Speed (tens), Course (hundreds)", HFILL }
1939 { &hf_aprs_mic_e_spd_se,
1940 { "Course (T & U)", "aprs.mic_e.speed_se",
1941 FT_UINT8, BASE_HEX, NULL, 0x0,
1942 "Course (tens & units)", HFILL }
1944 { &hf_aprs_mic_e_telemetry,
1945 { "Telmetry", "aprs.mic_e.telemetry",
1946 FT_BYTES, BASE_NONE, NULL, 0x0,
1947 "Telemetry", HFILL }
1949 { &hf_aprs_mic_e_status,
1950 { "Status", "aprs.mic_e.status",
1951 FT_STRING, BASE_NONE, NULL, 0x0,
1952 NULL, HFILL }
1956 /* Setup protocol subtree array */
1957 static gint *ett[] = {
1958 &ett_aprs,
1959 &ett_aprs_msg,
1960 &ett_aprs_ct,
1961 &ett_aprs_weather,
1962 &ett_aprs_storm,
1963 &ett_aprs_mic_e,
1966 /* Register the protocol name and description */
1967 proto_aprs = proto_register_protocol("Automatic Position Reporting System", "APRS", "aprs");
1969 /* Register the dissector */
1970 new_register_dissector( "aprs", dissect_aprs, proto_aprs);
1972 /* Required function calls to register the header fields and subtrees used */
1973 proto_register_field_array( proto_aprs, hf, array_length(hf ) );
1974 proto_register_subtree_array( ett, array_length( ett ) );
1976 /* Register preferences module */
1977 aprs_module = prefs_register_protocol( proto_aprs, NULL);
1979 /* Register any preference */
1980 prefs_register_bool_preference(aprs_module, "showaprslax",
1981 "Allow APRS violations.",
1982 "Attempt to display common APRS protocol violations correctly",
1983 &gPREF_APRS_LAX );