1 /*
2  *
3  * XASTIR, Amateur Station Tracking and Information Reporting
4  * Copyright (C) 1999,2000  Frank Giannandrea
5  * Copyright (C) 2000-2019 The Xastir Group
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * Look at the README for more information on the program.
22  */
23 
24 
25 //
26 // The code currently supports these types of locally-connected or
27 // network-connected weather stations:
28 //
29 //   Peet Brothers Ultimeter 2000 (Set to Data logging mode)
30 //   Peet Brothers Ultimeter 2000 (Set to Packet mode)
31 //   Peet Brothers Ultimeter 2000 (Set to Complete Record Mode)
32 //   Peet Brothers Ultimeter-II
33 //   Qualimetrics Q-Net?
34 //   Radio Shack WX-200/Huger WM-918/Oregon Scientific WM-918
35 //   Dallas One-Wire Weather Station (via OWW network daemon)
36 //   Davis Weather Monitor II/Wizard III/Vantage Pro (via meteo/db2APRS link)
37 //
38 
39 
40 // Need to modify code to use WX_rain_gauge_type.  Peet brothers.
41 // See http://www.peetbros.com, FAQ's and owner's manuals for
42 // details:
43 //
44 //  Peet Bros Ultimeter II:   0.1"/0.5mm or 0.01"/0.25mm
45 //      Divide by 10 or 100 from the serial output.
46 //
47 //  Peet Bros Ultimeter 2000, 800, & 100:  0.01"/0.25mm or 0.1mm
48 //      If 0.01" gauge, divide by 100.  If 0.1mm gauge, convert to
49 //      proper English units.
50 
51 
52 
53 #ifdef HAVE_CONFIG_H
54   #include "config.h"
55 #endif  // HAVE_CONFIG_H
56 
57 #include "snprintf.h"
58 
59 #include <stdlib.h>
60 #include <stdio.h>
61 #include <math.h>
62 
63 #if TIME_WITH_SYS_TIME
64   #include <sys/time.h>
65   #include <time.h>
66 #else   // TIME_WITH_SYS_TIME
67   #if HAVE_SYS_TIME_H
68     #include <sys/time.h>
69   #else  // HAVE_SYS_TIME_H
70     #include <time.h>
71   #endif // HAVE_SYS_TIME_H
72 #endif  // TIME_WITH_SYS_TIME
73 
74 #include <string.h>
75 
76 #include <Xm/XmAll.h>
77 
78 #include "wx.h"
79 #include "main.h"
80 #include "xastir.h"
81 #include "interface.h"
82 #include "lang.h"
83 #include "util.h"
84 
85 // Must be last include file
86 #include "leak_detection.h"
87 
88 
89 
90 #define MAX_RAW_WX_STRING 800
91 
92 char wx_station_type[100];
93 char raw_wx_string[MAX_RAW_WX_STRING+1];
94 
95 #define MAX_WX_STRING 300
96 #define WX_TYPE 'X'
97 
98 /* rain totals */
99 float rain_minute[60];              // Total rain for each min. of last hour, hundredths of an inch
100 float rain_minute_total = 0.0;      // Total for last hour, hundredths of an inch
101 int rain_minute_last_write = -1;    // Write pointer for rain_minute[] array, set to an invalid number
102 float rain_00 = 0.0;                // hundredths of an inch
103 float rain_24 = 0.0;                // hundredths of an inch
104 float rain_base[24];                // hundredths of an inch
105 int rain_check = 0;                 // Flag for re-checking rain_total each hour
106 
107 float wind_chill = 0;               // holder for wind chill calc
108 
109 // Gust totals
110 float gust[60];                     // High wind gust for each min. of last hour
111 int gust_write_ptr = 0;
112 int gust_read_ptr = 0;
113 int gust_last_write = 0;
114 
115 
116 /* Other WX station data */
117 char wx_dew_point[10];
118 char wx_dew_point_on;
119 char wx_high_wind[10];
120 char wx_high_wind_on;
121 char wx_wind_chill[10];
122 char wx_wind_chill_on;
123 char wx_three_hour_baro[10];  // hPa
124 char wx_three_hour_baro_on;
125 char wx_hi_temp[10];
126 char wx_hi_temp_on;
127 char wx_low_temp[10];
128 char wx_low_temp_on;
129 char wx_heat_index[10];
130 char wx_heat_index_on;
131 
132 
133 
134 
135 
136 /***********************************************************/
137 /* clear rain data                                         */
138 /***********************************************************/
clear_rain_data(void)139 void clear_rain_data(void)
140 {
141   int x;
142 
143 
144   // Clear rain_base queue (starting rain total for each hour)
145   for ( x = 0; x < 24; x++ )
146   {
147     rain_base[x] = 0.0;
148   }
149 
150   rain_00 = 0.0;
151   rain_24 = 0.0;
152   rain_check = 0;   // Set flag so we'll recheck rain_total
153   // a few times at start of each hour
154 
155   // Clear hourly rain queue
156   for ( x = 0; x < 60; x++ )
157   {
158     rain_minute[x] = 0.0;
159   }
160 
161   rain_minute_total = 0.0;
162   rain_minute_last_write = 70;  // Invalid number so we'll know we're just starting.
163 }
164 
165 
166 
167 
168 
169 /**************************************************************/
170 /* compute_rain_hour - rolling average for the last 59.x      */
171 /* minutes of rain.  I/O numbers are in hundredths of an inch.*/
172 /* Output is in "rain_minute_total", a global variable.       */
173 /**************************************************************/
compute_rain_hour(float rain_total)174 void compute_rain_hour(float rain_total)
175 {
176   int current, j;
177   float lowest;
178 
179 
180   // Deposit the _starting_ rain_total for each minute into a separate bucket.
181   // Subtract lowest rain_total in queue from current rain_total to get total
182   // for the last hour.
183 
184 
185   current = get_minutes(); // Fetch the current minute value.  Use this as an index
186   // into our minute "buckets" where we store the data.
187 
188 
189   rain_minute[ (current + 1) % 60 ] = 0.0;   // Zero out the next bucket (probably have data in
190   // there from the previous hour).
191 
192 
193   if (rain_minute[current] == 0.0)           // If no rain_total stored yet in this minute's bucket
194   {
195     rain_minute[current] = rain_total;  // Write into current bucket
196   }
197 
198 
199   // Find the lowest non-zero value for rain_total.  The max value is "rain_total".
200   lowest = rain_total;                    // Set to maximum to get things going
201   for (j = 0; j < 60; j++)
202   {
203     if ( (rain_minute[j] > 0.0) && (rain_minute[j] < lowest) )   // Found a lower non-zero value?
204     {
205       lowest = rain_minute[j];        // Snag it
206     }
207   }
208   // Found it, subtract the two to get total for the last hour
209   rain_minute_total = rain_total - lowest;
210 
211   if (debug_level & 2)
212   {
213     fprintf(stderr,"Rain_total:%0.2f  Hourly:%0.2f  (Low:%0.2f)  ", rain_total, rain_minute_total, lowest);
214   }
215 }
216 
217 
218 
219 
220 
221 /***********************************************************/
222 /* compute_rain - compute rain totals from the total rain  */
223 /* so far.  rain_total (in hundredths of an inch) keeps on */
224 /* incrementing.                                           */
225 /***********************************************************/
compute_rain(float rain_total)226 void compute_rain(float rain_total)
227 {
228   int current, i;
229   float lower;
230 
231 
232   // Skip the routine if input is outlandish (Negative value, zero, or 512 inches!).
233   // We seem to get occasional 0.0 packets from wx200d.  This makes them go away.
234   if ( (rain_total <= 0.0) || (rain_total > 51200.0) )
235   {
236     return;
237   }
238 
239   compute_rain_hour(rain_total);
240 
241   current = get_hours();
242 
243   // Set rain_base:  The first rain_total for each hour.
244   if (rain_base[current] == 0.0)         // If we don't have a start value yet for this hour,
245   {
246     rain_base[current] = rain_total;    // save it away.
247     rain_check = 0;                     // Set up rain_check so we'll do the following
248     // "else" clause a few times at start of each hour.
249   }
250   else    // rain_base has been set, is it wrong?  We recheck three times at start of hour.
251   {
252     if (rain_check < 3)
253     {
254       rain_check++;
255       // Is rain less than base?  It shouldn't be.
256       if (rain_total < rain_base[current])
257       {
258         rain_base[current] = rain_total;
259       }
260 
261       // Difference greater than 10 inches since last reading?  It shouldn't be.
262       if (fabs(rain_total - rain_base[current]) > 1000.0) // Remember:  Hundredths of an inch
263       {
264         rain_base[current] = rain_total;
265       }
266     }
267   }
268   rain_base[ (current + 1) % 24 ] = 0.0;    // Clear next hour's index.
269 
270 
271   // Compute total rain in last 24 hours:  Really we'll compute the total rain
272   // in the last 23 hours plus the portion of an hour we've completed (Sum up
273   // all 24 of the hour totals).  This isn't the perfect way to do it, but to
274   // really do it right we'd need finer increments of time (to get closer to
275   // the goal of 24 hours of rain).
276   lower = rain_total;
277   for ( i = 0; i < 24; i++ )      // Find the lowest non-zero rain_base value in last 24 hours
278   {
279     if ( (rain_base[i] > 0.0) && (rain_base[i] < lower) )
280     {
281       lower = rain_base[i];
282     }
283   }
284   rain_24 = rain_total - lower;    // Hundredths of an inch
285 
286 
287   // Compute rain since midnight.  Note that this uses whatever local time was set
288   // on the machine.  It might not be local midnight if your box is set to GMT.
289   lower = rain_total;
290   for ( i = 0; i <= current; i++ )    // Find the lowest non-zero rain_base value since midnight
291   {
292     if ( (rain_base[i] > 0.0) && (rain_base[i] < lower) )
293     {
294       lower = rain_base[i];
295     }
296   }
297   rain_00 = rain_total - lower;    // Hundredths of an inch
298 
299   // It is the responsibility of the calling program to save
300   // the new totals in the data structure for our station.
301   // We don't return anything except in global variables.
302 
303 
304   if (debug_level & 2)
305   {
306     fprintf(stderr,"24hrs:%0.2f  ", rain_24);
307     fprintf(stderr,"rain_00:%0.2f\n", rain_00);
308   }
309 }
310 
311 
312 
313 
314 
315 /**************************************************************/
316 /* compute_gust - compute max wind gust during last 5 minutes */
317 /*                                                            */
318 /**************************************************************/
compute_gust(float wx_speed,float UNUSED (last_speed),time_t * last_speed_time)319 float compute_gust(float wx_speed, float UNUSED(last_speed), time_t *last_speed_time)
320 {
321   float computed_gust;
322   int current, j;
323 
324 
325   // Deposit max gust for each minute into a different bucket.
326   // Check all buckets for max gust within the last five minutes
327   // (Really 4 minutes plus whatever portion of a minute we've completed).
328 
329   current = get_minutes(); // Fetch the current minute value.  We use this as an index
330   // into our minute "buckets" where we store the data.
331 
332   // If we haven't started collecting yet, set up to do so
333   if (gust_read_ptr == gust_write_ptr)    // We haven't started yet
334   {
335     gust_write_ptr = current;           // Set to write into current bucket
336     gust_last_write = current;
337 
338     gust_read_ptr = current - 1;        // Set read pointer back one, modulus 60
339     if (gust_read_ptr < 0)
340     {
341       gust_read_ptr = 59;
342     }
343 
344     gust[gust_write_ptr] = 0.0;         // Zero the max gust
345     gust[gust_read_ptr] = 0.0;          // for both buckets.
346 
347 //WE7U: Debug
348 //gust[gust_write_ptr] = 45.9;
349   }
350 
351   // Check whether we've advanced at least one minute yet
352   if (current != gust_write_ptr)          // We've advanced to a different minute
353   {
354     gust_write_ptr = current;           // Start writing into a new bucket.
355     gust[gust_write_ptr] = 0.0;         // Zero the new bucket
356 
357     // Check how many bins of real data we have currently.  Note that this '5' is
358     // correct, as we just advanced "current" to the next minute.  We're just pulling
359     // along the read_ptr behind us if we have 5 bins worth of data by now.
360     if ( ((gust_read_ptr + 5) % 60) == gust_write_ptr)  // We have 5 bins of real data
361     {
362       gust_read_ptr = (gust_read_ptr + 1) % 60;  // So advance the read pointer,
363     }
364 
365     // Check for really bad pointers, perhaps the weather station got
366     // unplugged for a while or it's just REALLY slow at sending us data?
367     // We're checking to see if gust_last_write happened in the previous
368     // minute.  If not, we skipped a minute or more somewhere.
369     if ( ((gust_last_write + 1) % 60) != current )
370     {
371       // We lost some time somewhere: Reset the pointers, older gust data is
372       // lost.  Start over collecting new gust data.
373 
374       gust_read_ptr = current - 1;    // Set read pointer back one, modulus 60
375       if (gust_read_ptr < 0)
376       {
377         gust_read_ptr = 59;
378       }
379 
380       gust[gust_read_ptr] = 0.0;
381     }
382     gust_last_write = current;
383   }
384 
385   // Is current wind speed higher than the current minute bucket?
386   if (wx_speed > gust[gust_write_ptr])
387   {
388     gust[gust_write_ptr] = wx_speed;  // Save it in the bucket
389   }
390 
391   // Read the last (up to) five buckets and find the max gust
392   computed_gust=gust[gust_write_ptr];
393   j = gust_read_ptr;
394   while (j != ((gust_write_ptr + 1) % 60) )
395   {
396     if ( computed_gust < gust[j] )
397     {
398       computed_gust = gust[j];
399     }
400     j = (j + 1) % 60;
401   }
402 
403   if (debug_level & 2)
404   {
405     j = gust_read_ptr;
406     while (j != ((gust_write_ptr + 1) % 60) )
407     {
408       fprintf(stderr,"%0.2f   ", gust[j]);
409       j = (j + 1) % 60;
410     }
411     fprintf(stderr,"gust:%0.2f\n", computed_gust);
412   }
413 
414   *last_speed_time = sec_now();
415   return(computed_gust);
416 }
417 
418 
419 
420 
421 
422 //
423 // cycle_weather - keep the weather queues moving even if data from
424 // weather station is scarce.  This is called from main.c:UpdateTime()
425 // on a periodic basis.  This routine also does the 30 second timestamp
426 // for the log files.
427 //
cycle_weather(void)428 void cycle_weather(void)
429 {
430   DataRow *p_station;
431   WeatherRow *weather;
432   float last_speed, computed_gust;
433   time_t last_speed_time;
434 
435 
436   // Find my own local weather data
437   if (search_station_name(&p_station,my_callsign,1))
438   {
439     if (p_station->weather_data != NULL)    // If station has WX data
440     {
441       weather = p_station->weather_data;
442       // Cycle the rain queues, feed in the last rain total we had
443       (void)compute_rain((float)atof(weather->wx_rain_total));
444 
445 
446       // Note:  Some weather stations provide the per-hour, 24-hour,
447       // and since-midnight rain rates already.  Further, some stations
448       // don't even provide total rain (Davis APRS DataLogger and the
449       // db2APRS program), so anything we compute here is actually wrong.
450       // Do NOT clobber these if so.  This flag is set in fill_wx_data
451       // when the station provides its data.
452 
453       if (weather->wx_compute_rain_rates)
454       {
455         // Hourly rain total
456         xastir_snprintf(weather->wx_rain,
457                         sizeof(weather->wx_rain),
458                         "%0.2f",
459                         rain_minute_total);
460 
461         // Last 24 hour rain
462         xastir_snprintf(weather->wx_prec_24,
463                         sizeof(weather->wx_prec_24),
464                         "%0.2f",
465                         rain_24);
466 
467         // Rain since midnight
468         xastir_snprintf(weather->wx_prec_00,
469                         sizeof(weather->wx_prec_00),
470                         "%0.2f",
471                         rain_00);
472       }
473       else
474       {
475         // LaCrosse stations don't provide the since-midnight
476         // numbers and so this will be blank.
477         // So if we have blanks here, fill it in.
478         if ( weather->wx_prec_00[0] == '\0' &&
479              weather->wx_rain_total[0] != '\0')
480         {
481 
482           // Rain since midnight
483           xastir_snprintf(weather->wx_prec_00,
484                           sizeof(weather->wx_prec_00),
485                           "%0.2f",
486                           rain_00);
487         }
488       }
489 
490 
491       /* get last gust speed */
492       if (strlen(weather->wx_gust) > 0)
493       {
494         /* get last speed */
495         last_speed = (float)atof(weather->wx_gust);
496         last_speed_time = weather->wx_speed_sec_time;
497       }
498       else
499       {
500         last_speed = 0.0;
501       }
502 
503       /* wind speed */
504       computed_gust = compute_gust((float)atof(weather->wx_speed),
505                                    last_speed,
506                                    &last_speed_time);
507       weather->wx_speed_sec_time = sec_now();
508       xastir_snprintf(weather->wx_gust,
509                       sizeof(weather->wx_gust),
510                       "%03d",
511                       (int)(computed_gust + 0.5)); // Cheater's way of rounding
512     }
513   }
514 }
515 
516 
517 
518 
519 
520 /***********************************************************/
521 /* clear other wx data                                     */
522 /***********************************************************/
clear_local_wx_data(void)523 void clear_local_wx_data(void)
524 {
525   memset(wx_dew_point,0,sizeof(wx_dew_point));
526   wx_dew_point_on = 0;
527 
528   memset(wx_high_wind,0,sizeof(wx_high_wind));
529   wx_high_wind_on = 0;
530 
531   memset(wx_wind_chill,0,sizeof(wx_wind_chill));
532   wx_wind_chill_on = 0;
533 
534   memset(wx_three_hour_baro,0,sizeof(wx_three_hour_baro));
535   wx_three_hour_baro_on = 0;
536 
537   memset(wx_hi_temp,0,sizeof(wx_hi_temp));
538   wx_hi_temp_on = 0;
539 
540   memset(wx_low_temp,0,sizeof(wx_low_temp));
541   wx_low_temp_on = 0;
542 
543   memset(wx_heat_index,0,sizeof(wx_heat_index));
544   wx_heat_index_on = 0;
545 }
546 
547 
548 
549 
550 
551 /***************************************************/
552 /* Check last WX data received - clear data if old */
553 /***************************************************/
wx_last_data_check(void)554 void wx_last_data_check(void)
555 {
556   DataRow *p_station;
557 
558   p_station = NULL;
559   if (search_station_name(&p_station,my_callsign,1))
560   {
561     if (p_station->weather_data != NULL)
562       if (p_station->weather_data->wx_speed_sec_time+360 < sec_now())
563         if (p_station->weather_data->wx_gust[0] != 0)
564           xastir_snprintf(p_station->weather_data->wx_gust,
565                           sizeof(p_station->weather_data->wx_gust),
566                           "%03d",
567                           0);
568   }
569 }
570 
571 
572 
573 
574 
575 //*********************************************************************
576 // Decode Peet Brothers Ultimeter 2000 weather data (Data logging mode)
577 //
578 // This function is called from db.c:data_add() only.  Used for
579 // decoding incoming packets, not for our own weather station data.
580 //
581 // The Ultimeter 2000 can be in any of three modes, Data Logging Mode,
582 // Packet Mode, or Complete Record Mode.  This routine handles only
583 // the Data Logging Mode.
584 //*********************************************************************
decode_U2000_L(int from,unsigned char * data,WeatherRow * weather)585 void decode_U2000_L(int from, unsigned char *data, WeatherRow *weather)
586 {
587   time_t last_speed_time;
588   float last_speed;
589   float computed_gust;
590   char temp_data1[10];
591   char *temp_conv;
592 
593   last_speed = 0.0;
594   last_speed_time = 0;
595   computed_gust = 0.0;
596 
597   if (debug_level & 1)
598   {
599     fprintf(stderr,"APRS WX3 Peet Bros U-2k (data logging mode): |%s|\n", data);
600   }
601 
602   weather->wx_type = WX_TYPE;
603   xastir_snprintf(weather->wx_station,
604                   sizeof(weather->wx_station),
605                   "U2k");
606 
607   /* get last gust speed */
608   if (strlen(weather->wx_gust) > 0 && !from)
609   {
610     /* get last speed */
611     last_speed = (float)atof(weather->wx_gust);
612     last_speed_time = weather->wx_speed_sec_time;
613   }
614 
615   // 006B 00 58
616   // 00A4 00 46 01FF 380E 2755 02C1 03E8 ---- 0052 04D7    0001 007BM
617   // ^       ^  ^    ^    ^         ^                      ^
618   // 0       6  8    12   16        24                     40
619   /* wind speed */
620   if (data[0] != '-')   // '-' signifies invalid data
621   {
622     substr(temp_data1,(char *)data,4);
623     xastir_snprintf(weather->wx_speed,
624                     sizeof(weather->wx_speed),
625                     "%03.0f",
626                     0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137);
627     if (from)
628     {
629       weather->wx_speed_sec_time = sec_now();
630     }
631     else
632     {
633       /* local station */
634       computed_gust = compute_gust((float)atof(weather->wx_speed),
635                                    last_speed,
636                                    &last_speed_time);
637       weather->wx_speed_sec_time = sec_now();
638       xastir_snprintf(weather->wx_gust,
639                       sizeof(weather->wx_gust),
640                       "%03d",
641                       (int)(0.5 + computed_gust)); // Cheater's way of rounding
642     }
643   }
644   else
645   {
646     if (!from)
647     {
648       weather->wx_speed[0] = 0;
649     }
650   }
651 
652   /* wind direction */
653   //
654   // Note that the first two digits here may be 00, or may be FF
655   // if a direction calibration has been entered.  We should zero
656   // them.
657   //
658   if (data[4] != '-')   // '-' signifies invalid data
659   {
660     substr(temp_data1,(char *)(data+4),4);
661     temp_data1[0] = '0';
662     temp_data1[1] = '0';
663     xastir_snprintf(weather->wx_course,
664                     sizeof(weather->wx_course),
665                     "%03.0f",
666                     ((strtol(temp_data1,&temp_conv,16)/256.0)*360.0));
667   }
668   else
669   {
670     xastir_snprintf(weather->wx_course,
671                     sizeof(weather->wx_course),
672                     "000");
673     if (!from)
674     {
675       weather->wx_course[0]=0;
676     }
677   }
678 
679   /* outdoor temp */
680   if (data[8] != '-')   // '-' signifies invalid data
681   {
682     int temp4;
683 
684     substr(temp_data1,(char *)(data+8),4);
685     temp4 = (int)strtol(temp_data1,&temp_conv,16);
686 
687     if (temp_data1[0] > '7')    // Negative value, convert
688     {
689       temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000;
690     }
691 
692     xastir_snprintf(weather->wx_temp,
693                     sizeof(weather->wx_temp),
694                     "%03d",
695                     (int)((float)((temp4<<16)/65536)/10.0));
696 
697   }
698   else
699   {
700     if (!from)
701     {
702       weather->wx_temp[0]=0;
703     }
704   }
705 
706   /* rain total long term */
707   if (data[12] != '-')   // '-' signifies invalid data
708   {
709     substr(temp_data1,(char *)(data+12),4);
710     xastir_snprintf(weather->wx_rain_total,
711                     sizeof(weather->wx_rain_total),
712                     "%0.2f",
713                     strtol(temp_data1,&temp_conv,16)/100.0);
714     if (!from)
715     {
716       /* local station */
717       compute_rain((float)atof(weather->wx_rain_total));
718       /*last hour rain */
719       xastir_snprintf(weather->wx_rain,
720                       sizeof(weather->wx_rain),
721                       "%0.2f",
722                       rain_minute_total);
723       /*last 24 hour rain */
724       xastir_snprintf(weather->wx_prec_24,
725                       sizeof(weather->wx_prec_24),
726                       "%0.2f",
727                       rain_24);
728       /* rain since midnight */
729       xastir_snprintf(weather->wx_prec_00,
730                       sizeof(weather->wx_prec_00),
731                       "%0.2f",
732                       rain_00);
733     }
734   }
735   else
736   {
737     if (!from)
738     {
739       weather->wx_rain_total[0]=0;
740     }
741   }
742 
743   /* baro */
744   if (data[16] != '-')   // '-' signifies invalid data
745   {
746     substr(temp_data1,(char *)(data+16),4);
747     xastir_snprintf(weather->wx_baro,
748                     sizeof(weather->wx_baro),
749                     "%0.1f",
750                     strtol(temp_data1,&temp_conv,16)/10.0);
751   }
752   else
753   {
754     if (!from)
755     {
756       weather->wx_baro[0]=0;
757     }
758   }
759 
760 
761   /* outdoor humidity */
762   if (data[24] != '-')   // '-' signifies invalid data
763   {
764     substr(temp_data1,(char *)(data+24),4);
765     xastir_snprintf(weather->wx_hum,
766                     sizeof(weather->wx_hum),
767                     "%03.0f",
768                     (strtol(temp_data1,&temp_conv,16)/10.0));
769   }
770   else
771   {
772     if (!from)
773     {
774       weather->wx_hum[0]=0;
775     }
776   }
777 
778   /* todays rain total */
779   if (data[40] != '-')   // '-' signifies invalid data
780   {
781     if (from)
782     {
783       substr(temp_data1,(char *)(data+40),4);
784       xastir_snprintf(weather->wx_prec_00,
785                       sizeof(weather->wx_prec_00),
786                       "%0.2f",
787                       strtol(temp_data1,&temp_conv,16)/100.0);
788     }
789   }
790   else
791   {
792     if (!from)
793     {
794       weather->wx_prec_00[0] = 0;
795     }
796   }
797 }
798 
799 
800 
801 
802 
803 //********************************************************************
804 // Decode Peet Brothers Ultimeter 2000 weather data (Packet mode)
805 //
806 // This function is called from db.c:data_add() only.  Used for
807 // decoding incoming packets, not for our own weather station data.
808 //
809 // The Ultimeter 2000 can be in any of three modes, Data Logging Mode,
810 // Packet Mode, or Complete Record Mode.  This routine handles only
811 // the Packet Mode.
812 //********************************************************************
decode_U2000_P(int from,unsigned char * data,WeatherRow * weather)813 void decode_U2000_P(int from, unsigned char *data, WeatherRow *weather)
814 {
815   time_t last_speed_time;
816   float last_speed;
817   float computed_gust;
818   char temp_data1[10];
819   char *temp_conv;
820   int len;
821 
822   last_speed      = 0.0;
823   last_speed_time = 0;
824   computed_gust   = 0.0;
825   len = (int)strlen((char *)data);
826 
827   if (debug_level & 1)
828   {
829     fprintf(stderr,"APRS WX5 Peet Bros U-2k Packet (Packet mode): |%s|\n",data);
830   }
831 
832   weather->wx_type = WX_TYPE;
833   xastir_snprintf(weather->wx_station,
834                   sizeof(weather->wx_station),
835                   "U2k");
836 
837   /* get last gust speed */
838   if (strlen(weather->wx_gust) > 0 && !from)
839   {
840     /* get last speed */
841     last_speed = (float)atof(weather->wx_gust);
842     last_speed_time = weather->wx_speed_sec_time;
843   }
844 
845   // $ULTW   0031 00 37 02CE  0069 ---- 0000 86A0 0001 ---- 011901CC   0000 0005
846   //         ^       ^  ^     ^    ^                   ^               ^    ^
847   //         0       6  8     12   16                  32              44   48
848 
849   /* wind speed peak over last 5 min */
850   if (data[0] != '-')   // '-' signifies invalid data
851   {
852     substr(temp_data1,(char *)data,4);
853     if (from)
854     {
855       xastir_snprintf(weather->wx_gust,
856                       sizeof(weather->wx_gust),
857                       "%03.0f",
858                       0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137);
859       /* this may be the only wind data */
860       xastir_snprintf(weather->wx_speed,
861                       sizeof(weather->wx_speed),
862                       "%03.0f",
863                       0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137);
864     }
865     else
866     {
867       /* local station and may be the only wind data */
868       if (len < 51)
869       {
870         xastir_snprintf(weather->wx_speed,
871                         sizeof(weather->wx_speed),
872                         "%03.0f",
873                         0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137);
874         computed_gust = compute_gust((float)atof(weather->wx_speed),
875                                      last_speed,
876                                      &last_speed_time);
877         weather->wx_speed_sec_time = sec_now();
878         xastir_snprintf(weather->wx_gust,
879                         sizeof(weather->wx_gust),
880                         "%03d",
881                         (int)(0.5 + computed_gust));
882       }
883     }
884   }
885   else
886   {
887     if (!from)
888     {
889       weather->wx_gust[0] = 0;
890     }
891   }
892 
893   /* wind direction */
894   //
895   // Note that the first two digits here may be 00, or may be FF
896   // if a direction calibration has been entered.  We should zero
897   // them.
898   //
899   if (data[4] != '-')   // '-' signifies invalid data
900   {
901     substr(temp_data1,(char *)(data+4),4);
902     temp_data1[0] = '0';
903     temp_data1[1] = '0';
904     xastir_snprintf(weather->wx_course,
905                     sizeof(weather->wx_course),
906                     "%03.0f",
907                     (strtol(temp_data1,&temp_conv,16)/256.0)*360.0);
908   }
909   else
910   {
911     xastir_snprintf(weather->wx_course,
912                     sizeof(weather->wx_course),
913                     "000");
914     if (!from)
915     {
916       weather->wx_course[0] = 0;
917     }
918   }
919 
920   /* outdoor temp */
921   if (data[8] != '-')   // '-' signifies invalid data
922   {
923     int temp4;
924 
925     substr(temp_data1,(char *)(data+8),4);
926     temp4 = (int)strtol(temp_data1,&temp_conv,16);
927 
928     if (temp_data1[0] > '7')    // Negative value, convert
929     {
930       temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000;
931     }
932 
933     xastir_snprintf(weather->wx_temp,
934                     sizeof(weather->wx_temp),
935                     "%03d",
936                     (int)((float)((temp4<<16)/65536)/10.0));
937   }
938   else
939   {
940     if (!from)
941     {
942       weather->wx_temp[0] = 0;
943     }
944   }
945   /* todays rain total (on some units) */
946   if ((data[44]) != '-')   // '-' signifies invalid data
947   {
948     if (from)
949     {
950       substr(temp_data1,(char *)(data+44),4);
951       xastir_snprintf(weather->wx_prec_00,
952                       sizeof(weather->wx_prec_00),
953                       "%0.2f",
954                       strtol(temp_data1,&temp_conv,16)/100.0);
955     }
956   }
957   else
958   {
959     if (!from)
960     {
961       weather->wx_prec_00[0] = 0;
962     }
963   }
964 
965   /* rain total long term */
966   if (data[12] != '-')   // '-' signifies invalid data
967   {
968     substr(temp_data1,(char *)(data+12),4);
969     xastir_snprintf(weather->wx_rain_total,
970                     sizeof(weather->wx_rain_total),
971                     "%0.2f",
972                     strtol(temp_data1,&temp_conv,16)/100.0);
973     if (!from)
974     {
975       /* local station */
976       compute_rain((float)atof(weather->wx_rain_total));
977       /*last hour rain */
978       xastir_snprintf(weather->wx_rain,
979                       sizeof(weather->wx_rain),
980                       "%0.2f",
981                       rain_minute_total);
982       /*last 24 hour rain */
983       xastir_snprintf(weather->wx_prec_24,
984                       sizeof(weather->wx_prec_24),
985                       "%0.2f",
986                       rain_24);
987       /* rain since midnight */
988       xastir_snprintf(weather->wx_prec_00,
989                       sizeof(weather->wx_prec_00),
990                       "%0.2f",
991                       rain_00);
992     }
993   }
994   else
995   {
996     if (!from)
997     {
998       weather->wx_rain_total[0] = 0;
999     }
1000   }
1001 
1002   /* baro */
1003   if (data[16] != '-')   // '-' signifies invalid data
1004   {
1005     substr(temp_data1,(char *)(data+16),4);
1006     xastir_snprintf(weather->wx_baro,
1007                     sizeof(weather->wx_baro),
1008                     "%0.1f",
1009                     strtol(temp_data1,&temp_conv,16)/10.0);
1010   }
1011   else
1012   {
1013     if (!from)
1014     {
1015       weather->wx_baro[0] = 0;
1016     }
1017   }
1018 
1019   /* outdoor humidity */
1020   if (data[32] != '-')   // '-' signifies invalid data
1021   {
1022     substr(temp_data1,(char *)(data+32),4);
1023     xastir_snprintf(weather->wx_hum,
1024                     sizeof(weather->wx_hum),
1025                     "%03.0f",
1026                     strtol(temp_data1,&temp_conv,16)/10.0);
1027   }
1028   else
1029   {
1030     if (!from)
1031     {
1032       weather->wx_hum[0] = 0;
1033     }
1034   }
1035 
1036   /* 1 min wind speed avg */
1037   if (len > 48 && (data[48]) != '-')   // '-' signifies invalid data
1038   {
1039     substr(temp_data1,(char *)(data+48),4);
1040     xastir_snprintf(weather->wx_speed,
1041                     sizeof(weather->wx_speed),
1042                     "%03.0f",
1043                     0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137);
1044     if (from)
1045     {
1046       weather->wx_speed_sec_time = sec_now();
1047     }
1048     else
1049     {
1050       /* local station */
1051       computed_gust = compute_gust((float)atof(weather->wx_speed),
1052                                    last_speed,
1053                                    &last_speed_time);
1054       weather->wx_speed_sec_time = sec_now();
1055       xastir_snprintf(weather->wx_gust,
1056                       sizeof(weather->wx_gust),
1057                       "%03d",
1058                       (int)(0.5 + computed_gust));
1059     }
1060   }
1061   else
1062   {
1063     if (!from)
1064     {
1065       if (len > 48)
1066       {
1067         weather->wx_speed[0] = 0;
1068       }
1069     }
1070   }
1071 }
1072 
1073 
1074 
1075 
1076 
1077 //*****************************************************************
1078 // Decode Peet Brothers Ultimeter-II weather data
1079 //
1080 // This function is called from db.c:data_add() only.  Used for
1081 // decoding incoming packets, not for our own weather station data.
1082 //*****************************************************************
decode_Peet_Bros(int from,unsigned char * data,WeatherRow * weather,int type)1083 void decode_Peet_Bros(int from, unsigned char *data, WeatherRow *weather, int type)
1084 {
1085   time_t last_speed_time;
1086   float last_speed;
1087   float computed_gust;
1088   char temp_data1[10];
1089   char *temp_conv;
1090 
1091   last_speed    = 0.0;
1092   computed_gust = 0.0;
1093   last_speed_time = 0;
1094 
1095   if (debug_level & 1)
1096   {
1097     fprintf(stderr,"APRS WX4 Peet Bros U-II: |%s|\n",data);
1098   }
1099 
1100   weather->wx_type = WX_TYPE;
1101   xastir_snprintf(weather->wx_station,
1102                   sizeof(weather->wx_station),
1103                   "UII");
1104 
1105   // '*' = MPH
1106   // '#' = km/h
1107   //
1108   // #  5 0B 75 0082 0082
1109   // *  7 00 76 0000 0000
1110   //    ^ ^  ^  ^
1111   //            rain [1/100 inch ?]
1112   //         outdoor temp
1113   //      wind speed [mph / km/h]
1114   //    wind dir
1115 
1116   /* wind direction */
1117   //
1118   // 0x00 is N
1119   // 0x04 is E
1120   // 0x08 is S
1121   // 0x0C is W
1122   //
1123   substr(temp_data1,(char *)data,1);
1124   xastir_snprintf(weather->wx_course,
1125                   sizeof(weather->wx_course),
1126                   "%03.0f",
1127                   (strtol(temp_data1,&temp_conv,16)/16.0)*360.0);
1128 
1129   /* get last gust speed */
1130   if (strlen(weather->wx_gust) > 0 && !from)
1131   {
1132     /* get last speed */
1133     last_speed = (float)atof(weather->wx_gust);
1134     last_speed_time = weather->wx_speed_sec_time;
1135   }
1136 
1137   /* wind speed */
1138   substr(temp_data1,(char *)(data+1),2);
1139   if (type == APRS_WX4)       // '#'  speed in km/h, convert to mph
1140   {
1141     xastir_snprintf(weather->wx_speed,
1142                     sizeof(weather->wx_speed),
1143                     "%03d",
1144                     (int)(0.5 + (float)(strtol(temp_data1,&temp_conv,16)*0.62137)));
1145   }
1146   else     // type == APRS_WX6,  '*'  speed in mph
1147   {
1148     xastir_snprintf(weather->wx_speed,
1149                     sizeof(weather->wx_speed),
1150                     "%03.0f",
1151                     0.5 + (1.0 * strtol(temp_data1,&temp_conv,16)) );
1152   }
1153 
1154   if (from)
1155   {
1156     weather->wx_speed_sec_time = sec_now();
1157   }
1158   else
1159   {
1160     /* local station */
1161     computed_gust = compute_gust((float)atof(weather->wx_speed),
1162                                  last_speed,
1163                                  &last_speed_time);
1164     weather->wx_speed_sec_time = sec_now();
1165     xastir_snprintf(weather->wx_gust,
1166                     sizeof(weather->wx_gust),
1167                     "%03d",
1168                     (int)(0.5 + computed_gust));
1169   }
1170 
1171   /* outdoor temp */
1172   if (data[3] != '-')   // '-' signifies invalid data
1173   {
1174     int temp4;
1175 
1176     substr(temp_data1,(char *)(data+3),2);
1177     temp4 = (int)strtol(temp_data1,&temp_conv,16);
1178 
1179     if (temp_data1[0] > '7')    // Negative value, convert
1180     {
1181       temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000;
1182     }
1183 
1184     xastir_snprintf(weather->wx_temp,
1185                     sizeof(weather->wx_temp),
1186                     "%03.0f",
1187                     (float)(temp4-56) );
1188   }
1189   else
1190   {
1191     if (!from)
1192     {
1193       weather->wx_temp[0] = 0;
1194     }
1195   }
1196 
1197   // Rain divided by 100 for readings in hundredth of an inch
1198   if (data[5] != '-')   // '-' signifies invalid data
1199   {
1200     substr(temp_data1,(char *)(data+5),4);
1201     xastir_snprintf(weather->wx_rain_total,
1202                     sizeof(weather->wx_rain_total),
1203                     "%0.2f",
1204                     strtol(temp_data1,&temp_conv,16)/100.0);
1205     if (!from)
1206     {
1207       /* local station */
1208       compute_rain((float)atof(weather->wx_rain_total));
1209       /*last hour rain */
1210       xastir_snprintf(weather->wx_rain,
1211                       sizeof(weather->wx_rain),
1212                       "%0.2f",
1213                       rain_minute_total);
1214       /*last 24 hour rain */
1215       xastir_snprintf(weather->wx_prec_24,
1216                       sizeof(weather->wx_prec_24),
1217                       "%0.2f",
1218                       rain_24);
1219       /* rain since midnight */
1220       xastir_snprintf(weather->wx_prec_00,
1221                       sizeof(weather->wx_prec_00),
1222                       "%0.2f",
1223                       rain_00);
1224     }
1225   }
1226   else
1227   {
1228     if (!from)
1229     {
1230       weather->wx_rain_total[0] = 0;
1231     }
1232   }
1233 }
1234 
1235 
1236 
1237 
1238 
1239 /**************************************************/
1240 /* RSW num convert.  For Radio Shack WX-200,      */
1241 /* converts two decimal nibbles into integer      */
1242 /* number.                                        */
1243 /**************************************************/
rswnc(unsigned char c)1244 int rswnc(unsigned char c)
1245 {
1246   return( (int)( (c>>4) & 0x0f) * 10 + (int)(c&0x0f) );
1247 }
1248 
1249 
1250 
1251 
1252 
1253 //*********************************************************
1254 // wx fill data field
1255 // from: 0=local station, 1=regular decode (other stations)
1256 // type: type of WX packet
1257 // data: the packet of WX data
1258 // fill: the station data to fill
1259 //
1260 // This function is called only by wx.c:wx_decode()
1261 //
1262 // It is always called with a first parameter of 0, so we
1263 // use this only for our own serially-connected or network
1264 // connected weather station, not for decoding other
1265 // people's weather packets.
1266 //*********************************************************
1267 //
1268 // Note that the length of "data" can be up to MAX_DEVICE_BUFFER,
1269 // which is currently set to 4096.
1270 //
wx_fill_data(int from,int type,unsigned char * data,DataRow * fill)1271 void wx_fill_data(int from, int type, unsigned char *data, DataRow *fill)
1272 {
1273   time_t last_speed_time;
1274   float last_speed;
1275   float computed_gust;
1276   int  temp1;
1277   int  temp2;
1278   int  temp3;
1279   float temp_temp;
1280   char temp[MAX_DEVICE_BUFFER+1];
1281   char temp_data1[10];
1282   char *temp_conv;
1283   int len;
1284   int t2;
1285   int hidx_temp;
1286   int rh2;
1287   int hi_hum;
1288   int heat_index;
1289   WeatherRow *weather;
1290   float tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp9,tmp10,tmp11,tmp12,tmp13,tmp14,tmp15,tmp16,tmp17,tmp18,tmp19;
1291   int tmp7,tmp8;
1292   int dallas_type = 19;
1293 
1294 
1295   last_speed=0.0;
1296   computed_gust=0.0;
1297   last_speed_time=0;
1298 
1299 
1300   len=(int)strlen((char*)data);
1301 
1302   weather = fill->weather_data;  // should always be defined
1303 
1304   switch (type)
1305   {
1306 
1307 //WE7U
1308     /////////////////////////////////////
1309     // Dallas One-Wire Weather Station //
1310     /////////////////////////////////////
1311 
1312 // KB1MTS - Added values for T13 thru T19 for humidity and barometer,
1313 // however only current values (not min or max) are used.
1314 
1315 
1316     case (DALLAS_ONE_WIRE):
1317 
1318       if (debug_level & 1)
1319       {
1320         fprintf(stderr,"APRS WX Dallas One-Wire %s:<%s>\n",fill->call_sign,data);
1321       }
1322 
1323       weather->wx_type=WX_TYPE;
1324       xastir_snprintf(weather->wx_station,
1325                       sizeof(weather->wx_station),
1326                       "OWW");
1327 
1328       if (19 == sscanf((const char *)data,
1329                        "%f %f %f %f %f %f %d %d %f %f %f %f %f %f %f %f %f %f %f",
1330                        &tmp1,
1331                        &tmp2,
1332                        &tmp3,
1333                        &tmp4,
1334                        &tmp5,
1335                        &tmp6,
1336                        &tmp7,
1337                        &tmp8,
1338                        &tmp9,
1339                        &tmp10,
1340                        &tmp11,
1341                        &tmp12,
1342                        &tmp13,
1343                        &tmp14,
1344                        &tmp15,
1345                        &tmp16,
1346                        &tmp17,
1347                        &tmp18,
1348                        &tmp19))
1349       {
1350         dallas_type = 19;
1351       }
1352       else if (12 == sscanf((const char *)data,
1353                             "%f %f %f %f %f %f %d %d %f %f %f %f",
1354                             &tmp1,
1355                             &tmp2,
1356                             &tmp3,
1357                             &tmp4,
1358                             &tmp5,
1359                             &tmp6,
1360                             &tmp7,
1361                             &tmp8,
1362                             &tmp9,
1363                             &tmp10,
1364                             &tmp11,
1365                             &tmp12))
1366       {
1367         dallas_type = 12;
1368       }
1369       else
1370       {
1371         fprintf(stderr,"wx_fill_data:sscanf parsing error\n");
1372       }
1373 
1374 
1375       // The format of the data originates here:
1376       // http://weather.henriksens.net/
1377 
1378       // tmp1: primary temp (C)
1379       // tmp2: temp max (C)
1380       // tmp3: temp min (C)
1381       // tmp4: anemometer (mps)
1382       // tmp5: anemometer gust (peak speed MS)
1383       // tmp6: anemometer speed max * 0.447040972 (max speed MS)
1384       // tmp7: vane bearing - 1 (current wind direction)
1385       // tmp8: vane mode (max dir)
1386       // tmp9: rain rate
1387       // tmp10: rain total today
1388       // tmp11: rain total week
1389       // tmp12: rain since month
1390       // tmp13: Current Humidity
1391       // tmp14: Max Humidity
1392       // tmp15: Min Humidity
1393       // tmp16: Current Barometer
1394       // tmp17: Max Barometer
1395       // tmp18: Min Barometer
1396       // tmp19: Barometer Rate
1397 
1398       // Temperature
1399       xastir_snprintf(weather->wx_temp,
1400                       sizeof(weather->wx_temp),
1401                       "%03d",
1402                       (int)(tmp1 * 9.0 / 5.0 + 32.0 + 0.5));
1403       //fprintf(stderr,"Read: %2.1f C, Storing: %s F\n",tmp1,weather->wx_temp);
1404 
1405       // Wind direction.  Each vane increment equals 22.5 degrees.
1406       xastir_snprintf(weather->wx_course,
1407                       sizeof(weather->wx_course),
1408                       "%03d",
1409                       (int)(tmp7 * 22.5 + 0.5));
1410 
1411       // Check for course = 0.  Change to 360.
1412       if (strncmp(weather->wx_course,"000",3) == 0)
1413       {
1414         xastir_snprintf(weather->wx_course,
1415                         sizeof(weather->wx_course),
1416                         "360");
1417       }
1418 
1419       // Wind speed.  We get it in meters per second, store it
1420       // in mph.
1421       tmp4 = tmp4 * 3600.0 / 1000.0; // kph
1422       tmp4 = tmp4 * 0.62137;         // mph
1423       xastir_snprintf(weather->wx_speed,
1424                       sizeof(weather->wx_speed),
1425                       "%03d",
1426                       (int)(tmp4 + 0.5));
1427 
1428       if (dallas_type == 19)
1429       {
1430         // Humidity.  This is received by percentage.
1431         xastir_snprintf(weather->wx_hum,
1432                         sizeof(weather->wx_hum),
1433                         "%2.1f", (double)(tmp13));
1434 
1435         // Barometer. Sent in inHg
1436         xastir_snprintf(weather->wx_baro,
1437                         sizeof(weather->wx_baro),
1438                         "%4.4f", (float)(tmp16 * 33.864));
1439       }
1440 
1441 
1442 // Rain:  I don't have a rain gauge, and I couldn't tell from the
1443 // "OWW" docs exactly which of the four rain fields did what.  If
1444 // someone can help me with that I'll add rain gauge code for the
1445 // Dallas One-Wire.
1446 
1447 
1448 
1449       break;
1450 
1451     ////////////////////////////////
1452     // Peet Brothers Ultimeter-II //
1453     ////////////////////////////////
1454     case (APRS_WX4):    // '#', Wind speed in km/h
1455     case (APRS_WX6):    // '*', Wind speed in mph
1456 
1457       // This one assumes 0.1" rain gauge.  Must correct in software if
1458       // any other type is used.
1459 
1460       if (debug_level & 1)
1461       {
1462         fprintf(stderr,"APRS WX4 Peet Bros U-II %s:<%s>\n",fill->call_sign,data);
1463       }
1464 
1465       weather->wx_type=WX_TYPE;
1466       xastir_snprintf(weather->wx_station,
1467                       sizeof(weather->wx_station),
1468                       "UII");
1469 
1470       /* wind direction */
1471       //
1472       // 0x00 is N
1473       // 0x04 is E
1474       // 0x08 is S
1475       // 0x0C is W
1476       //
1477       substr(temp_data1,(char *)(data+1),1);
1478       xastir_snprintf(weather->wx_course,
1479                       sizeof(weather->wx_course),
1480                       "%03.0f",
1481                       (strtol(temp_data1,&temp_conv,16)/16.0)*360.0);
1482 
1483       // Check for course == 0.  Change to 360.
1484       if (strncmp(weather->wx_course,"000",3) == 0)
1485       {
1486         xastir_snprintf(weather->wx_course,
1487                         sizeof(weather->wx_course),
1488                         "360");
1489       }
1490 
1491       /* get last gust speed */
1492       if (strlen(weather->wx_gust) > 0 && !from)      // From local station
1493       {
1494         /* get last speed */
1495         last_speed=(float)atof(weather->wx_gust);
1496         last_speed_time=weather->wx_speed_sec_time;
1497       }
1498 
1499       /* wind speed */
1500       substr(temp_data1,(char *)(data+2),2);
1501       if (type == APRS_WX4)   // '#', Data is in km/h, convert to mph
1502       {
1503         xastir_snprintf(weather->wx_speed,
1504                         sizeof(weather->wx_speed),
1505                         "%03d",
1506                         (int)(0.5 + (float)(strtol(temp_data1,&temp_conv,16)*0.62137)));
1507       }
1508       else     // APRS_WX6 or '*', Data is in MPH
1509       {
1510         xastir_snprintf(weather->wx_speed,
1511                         sizeof(weather->wx_speed),
1512                         "%03.0f",
1513                         0.5 + (strtol(temp_data1,&temp_conv,16)*1.0) );
1514       }
1515 
1516       if (from)   // From remote station
1517       {
1518         weather->wx_speed_sec_time = sec_now();
1519       }
1520       else
1521       {
1522         /* local station */
1523         computed_gust = compute_gust((float)atof(weather->wx_speed),
1524                                      last_speed,
1525                                      &last_speed_time);
1526         weather->wx_speed_sec_time = sec_now();
1527         xastir_snprintf(weather->wx_gust,
1528                         sizeof(weather->wx_gust),
1529                         "%03d",
1530                         (int)(0.5 + computed_gust));
1531       }
1532 
1533       /* outdoor temp */
1534       if (data[4]!='-')   // '-' signifies invalid data
1535       {
1536         int temp4;
1537 
1538         substr(temp_data1,(char *)(data+4),2);
1539         temp4 = (int)strtol(temp_data1,&temp_conv,16);
1540 
1541         if (temp_data1[0] > '7')    // Negative value, convert
1542         {
1543           temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000;
1544         }
1545 
1546         xastir_snprintf(weather->wx_temp,
1547                         sizeof(weather->wx_temp),
1548                         "%03.0f",
1549                         (float)(temp4-56) );
1550       }
1551       else
1552       {
1553         if (!from)  // From local station
1554         {
1555           weather->wx_temp[0]=0;
1556         }
1557       }
1558 
1559       /* rain div by 100 for readings 0.1 inch */
1560 // What?  Shouldn't this be /10?
1561 
1562       if (data[6]!='-')   // '-' signifies invalid data
1563       {
1564         substr(temp_data1,(char *)(data+6),4);
1565         if (!from)      // From local station
1566         {
1567           switch (WX_rain_gauge_type)
1568           {
1569             case 1: // 0.1" rain gauge
1570               xastir_snprintf(weather->wx_rain_total,
1571                               sizeof(weather->wx_rain_total),
1572                               "%0.2f",
1573                               strtol(temp_data1,&temp_conv,16)*10.0);
1574               break;
1575             case 3: // 0.1mm rain gauge
1576               xastir_snprintf(weather->wx_rain_total,
1577                               sizeof(weather->wx_rain_total),
1578                               "%0.2f",
1579                               strtol(temp_data1,&temp_conv,16)/2.54);
1580               break;
1581             case 2: // 0.01" rain gauge
1582             case 0: // No conversion
1583             default:
1584               xastir_snprintf(weather->wx_rain_total,
1585                               sizeof(weather->wx_rain_total),
1586                               "%0.2f",
1587                               strtol(temp_data1,&temp_conv,16)*1.0);
1588               break;
1589           }
1590           /* local station */
1591           compute_rain((float)atof(weather->wx_rain_total));
1592           weather->wx_compute_rain_rates=1;
1593           /*last hour rain */
1594           xastir_snprintf(weather->wx_rain,
1595                           sizeof(weather->wx_rain),
1596                           "%0.2f",
1597                           rain_minute_total);
1598           /*last 24 hour rain */
1599           xastir_snprintf(weather->wx_prec_24,
1600                           sizeof(weather->wx_prec_24),
1601                           "%0.2f",
1602                           rain_24);
1603           /* rain since midnight */
1604           xastir_snprintf(weather->wx_prec_00,
1605                           sizeof(weather->wx_prec_00),
1606                           "%0.2f",
1607                           rain_00);
1608         }
1609       }
1610       else
1611       {
1612         if (!from)  // From local station
1613         {
1614           weather->wx_rain_total[0]=0;
1615         }
1616       }
1617       break;
1618 
1619 
1620 
1621     ///////////////////////////////////////////////////////
1622     // Peet Brothers Ultimeter 2000 in data logging mode //
1623     ///////////////////////////////////////////////////////
1624     case (APRS_WX3):
1625       if (debug_level & 1)
1626       {
1627         fprintf(stderr,"APRS WX3 Peet Bros U-2k (data logging mode) %s:<%s>\n",fill->call_sign,data+2);
1628       }
1629 
1630       weather->wx_type=WX_TYPE;
1631       xastir_snprintf(weather->wx_station,
1632                       sizeof(weather->wx_station),
1633                       "U2k");
1634 
1635       /* get last gust speed */
1636       if (strlen(weather->wx_gust) > 0 && !from)      // From local station
1637       {
1638         /* get last speed */
1639         last_speed=(float)atof(weather->wx_gust);
1640         last_speed_time=weather->wx_speed_sec_time;
1641       }
1642 
1643       /* wind speed */
1644       if (data[2]!='-')   // '-' signifies invalid data
1645       {
1646         substr(temp_data1,(char *)(data+2),4);
1647         xastir_snprintf(weather->wx_speed,
1648                         sizeof(weather->wx_speed),
1649                         "%03.0f",
1650                         0.5 + ((strtol(temp_data1,&temp_conv,16) /10.0)*0.62137));
1651         if (from)   // From remote station
1652         {
1653           weather->wx_speed_sec_time = sec_now();
1654         }
1655         else
1656         {
1657           /* local station */
1658           computed_gust = compute_gust((float)atof(weather->wx_speed),
1659                                        last_speed,
1660                                        &last_speed_time);
1661           weather->wx_speed_sec_time = sec_now();
1662           xastir_snprintf(weather->wx_gust,
1663                           sizeof(weather->wx_gust),
1664                           "%03d",
1665                           (int)(0.5 + computed_gust));
1666         }
1667       }
1668       else
1669       {
1670         if (!from)  // From local station
1671         {
1672           weather->wx_speed[0]=0;
1673         }
1674       }
1675 
1676       /* wind direction */
1677       //
1678       // Note that the first two digits here may be 00, or may
1679       // be FF if a direction calibration has been entered.
1680       // We should zero them.
1681       //
1682       if (data[6]!='-')   // '-' signifies invalid data
1683       {
1684         substr(temp_data1,(char *)(data+6),4);
1685         // Zero out the first two bytes
1686         temp_data1[0] = '0';
1687         temp_data1[1] = '0';
1688         xastir_snprintf(weather->wx_course,
1689                         sizeof(weather->wx_course),
1690                         "%03.0f",
1691                         (strtol(temp_data1,&temp_conv,16)/256.0)*360.0);
1692 
1693         // Check for course = 0.  Change to 360.
1694         if (strncmp(weather->wx_course,"000",3) == 0)
1695         {
1696           xastir_snprintf(weather->wx_course,
1697                           sizeof(weather->wx_course),
1698                           "360");
1699         }
1700 
1701       }
1702       else
1703       {
1704         xastir_snprintf(weather->wx_course,
1705                         sizeof(weather->wx_course),
1706                         "000");
1707         if (!from)  // From local station
1708         {
1709           weather->wx_course[0]=0;
1710         }
1711       }
1712 
1713       /* outdoor temp */
1714       if (data[10]!='-')   // '-' signifies invalid data
1715       {
1716         int temp4;
1717 
1718         substr(temp_data1,(char *)(data+10),4);
1719         temp4 = (int)strtol(temp_data1,&temp_conv,16);
1720 
1721         if (temp_data1[0] > '7')    // Negative value, convert
1722         {
1723           temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000;
1724         }
1725 
1726         xastir_snprintf(weather->wx_temp,
1727                         sizeof(weather->wx_temp),
1728                         "%03d",
1729                         (int)((float)((temp4<<16)/65536)/10.0));
1730       }
1731       else
1732       {
1733         if (!from)  // From local station
1734         {
1735           weather->wx_temp[0]=0;
1736         }
1737       }
1738 
1739       /* rain total long term */
1740       if (data[14]!='-')   // '-' signifies invalid data
1741       {
1742         substr(temp_data1,(char *)(data+14),4);
1743         if (!from)    // From local station
1744         {
1745           switch (WX_rain_gauge_type)
1746           {
1747             case 1: // 0.1" rain gauge
1748               xastir_snprintf(weather->wx_rain_total,
1749                               sizeof(weather->wx_rain_total),
1750                               "%0.2f",
1751                               strtol(temp_data1,&temp_conv,16)*10.0);
1752               break;
1753             case 3: // 0.1mm rain gauge
1754               xastir_snprintf(weather->wx_rain_total,
1755                               sizeof(weather->wx_rain_total),
1756                               "%0.2f",
1757                               strtol(temp_data1,&temp_conv,16)/2.54);
1758               break;
1759             case 2: // 0.01" rain gauge
1760             case 0: // No conversion
1761             default:
1762               xastir_snprintf(weather->wx_rain_total,
1763                               sizeof(weather->wx_rain_total),
1764                               "%0.2f",
1765                               strtol(temp_data1,&temp_conv,16)*1.0);
1766               break;
1767           }
1768           /* local station */
1769           compute_rain((float)atof(weather->wx_rain_total));
1770           weather->wx_compute_rain_rates=1;
1771           /*last hour rain */
1772           xastir_snprintf(weather->wx_rain,
1773                           sizeof(weather->wx_rain),
1774                           "%0.2f",
1775                           rain_minute_total);
1776           /*last 24 hour rain */
1777           xastir_snprintf(weather->wx_prec_24,
1778                           sizeof(weather->wx_prec_24),
1779                           "%0.2f",
1780                           rain_24);
1781           /* rain since midnight */
1782           xastir_snprintf(weather->wx_prec_00,
1783                           sizeof(weather->wx_prec_00),
1784                           "%0.2f",
1785                           rain_00);
1786         }
1787       }
1788       else
1789       {
1790         if (!from)  // From local station
1791         {
1792           weather->wx_rain_total[0]=0;
1793         }
1794       }
1795 
1796       /* baro */
1797       if (data[18]!='-')   // '-' signifies invalid data
1798       {
1799         substr(temp_data1,(char *)(data+18),4);
1800         xastir_snprintf(weather->wx_baro,
1801                         sizeof(weather->wx_baro),
1802                         "%0.1f",
1803                         strtol(temp_data1,&temp_conv,16)/10.0);
1804       }
1805 
1806       /* outdoor humidity */
1807       if (data[26]!='-')   // '-' signifies invalid data
1808       {
1809         substr(temp_data1,(char *)(data+26),4);
1810         xastir_snprintf(weather->wx_hum,
1811                         sizeof(weather->wx_hum),
1812                         "%03.0f",
1813                         strtol(temp_data1,&temp_conv,16)/10.0);
1814       }
1815       else
1816       {
1817         if (!from)  // From local station
1818         {
1819           weather->wx_hum[0]=0;
1820         }
1821       }
1822 
1823       // Isn't this replaced by the above switch-case?
1824       // No, I don't think so.  We can get these packets over
1825       // RF as well.
1826       /* todays rain total */
1827       if (strlen((const char *)data) > 45)
1828       {
1829         if (data[42]!='-')   // '-' signifies invalid data
1830         {
1831           if (from)   // From remote station
1832           {
1833             substr(temp_data1,(char *)(data+42),4);
1834             xastir_snprintf(weather->wx_prec_00,
1835                             sizeof(weather->wx_prec_00),
1836                             "%0.2f",
1837                             strtol(temp_data1,&temp_conv,16)/100.0);
1838           }
1839         }
1840         else
1841         {
1842           if (!from)  // From local station
1843           {
1844             weather->wx_prec_00[0]=0;
1845           }
1846         }
1847       }
1848       break;
1849 
1850 
1851 
1852     /////////////////////////////////////////////////
1853     // Peet Brothers Ultimeter 2000 in packet mode //
1854     /////////////////////////////////////////////////
1855     case(APRS_WX5):
1856       if (debug_level & 1)
1857       {
1858         fprintf(stderr,"APRS WX5 Peet Bros U-2k Packet (Packet mode) %s:<%s>\n",fill->call_sign,data);
1859       }
1860 
1861       weather->wx_type=WX_TYPE;
1862       xastir_snprintf(weather->wx_station,
1863                       sizeof(weather->wx_station),
1864                       "U2k");
1865 
1866       /* get last gust speed */
1867       if (strlen(weather->wx_gust) > 0 && !from)      // From local station
1868       {
1869         /* get last speed */
1870         last_speed=(float)atof(weather->wx_gust);
1871         last_speed_time=weather->wx_speed_sec_time;
1872       }
1873 
1874       /* wind speed peak over last 5 min */
1875       if (data[5]!='-')   // '-' signifies invalid data
1876       {
1877         substr(temp_data1,(char *)(data+5),4);
1878         if (from)   // From remote station
1879         {
1880           xastir_snprintf(weather->wx_gust,
1881                           sizeof(weather->wx_gust),
1882                           "%03.0f",
1883                           0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137);
1884           /* this may be the only wind data */
1885           xastir_snprintf(weather->wx_speed,
1886                           sizeof(weather->wx_speed),
1887                           "%03.0f",
1888                           0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137);
1889         }
1890         else
1891         {
1892           /* local station and may be the only wind data */
1893           if (len<56)
1894           {
1895             xastir_snprintf(weather->wx_speed,
1896                             sizeof(weather->wx_speed),
1897                             "%03.0f",
1898                             0.5 + ( strtol(temp_data1,&temp_conv,16)/10.0)*0.62137);
1899             computed_gust = compute_gust((float)atof(weather->wx_speed),
1900                                          last_speed,
1901                                          &last_speed_time);
1902             weather->wx_speed_sec_time = sec_now();
1903             xastir_snprintf(weather->wx_gust,
1904                             sizeof(weather->wx_gust),
1905                             "%03d",
1906                             (int)(0.5 + computed_gust));
1907           }
1908         }
1909       }
1910       else
1911       {
1912         if (!from)  // From local station
1913         {
1914           weather->wx_gust[0]=0;
1915         }
1916       }
1917 
1918       /* wind direction */
1919       //
1920       // Note that the first two digits here may be 00, or may
1921       // be FF if a direction calibration has been entered.
1922       // We should zero them.
1923       //
1924       if (data[9]!='-')   // '-' signifies invalid data
1925       {
1926         substr(temp_data1,(char *)(data+9),4);
1927         temp_data1[0] = '0';
1928         temp_data1[1] = '0';
1929         xastir_snprintf(weather->wx_course,
1930                         sizeof(weather->wx_course),
1931                         "%03.0f",
1932                         (strtol(temp_data1,&temp_conv,16)/256.0)*360.0);
1933 
1934         // Check for course = 0.  Change to 360.
1935         if (strncmp(weather->wx_course,"000",3) == 0)
1936         {
1937           xastir_snprintf(weather->wx_course,
1938                           sizeof(weather->wx_course),
1939                           "360");
1940         }
1941 
1942       }
1943       else
1944       {
1945         xastir_snprintf(weather->wx_course,
1946                         sizeof(weather->wx_course),
1947                         "000");
1948         if (!from)  // From local station
1949         {
1950           weather->wx_course[0]=0;
1951         }
1952       }
1953 
1954       /* outdoor temp */
1955       if (data[13]!='-')   // '-' signifies invalid data
1956       {
1957         int temp4;
1958 
1959         substr(temp_data1,(char *)(data+13),4);
1960         temp4 = (int)strtol(temp_data1,&temp_conv,16);
1961 
1962         if (temp_data1[0] > '7')    // Negative value, convert
1963         {
1964           temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000;
1965         }
1966 
1967         xastir_snprintf(weather->wx_temp,
1968                         sizeof(weather->wx_temp),
1969                         "%03d",
1970                         (int)((float)((temp4<<16)/65536)/10.0));
1971       }
1972       else
1973       {
1974         if (!from)  // From local station
1975         {
1976           weather->wx_temp[0]=0;
1977         }
1978       }
1979       /* todays rain total (on some units) */
1980       if (data[49]!='-')   // '-' signifies invalid data
1981       {
1982         if (from)   // From remote station
1983         {
1984           substr(temp_data1,(char *)(data+49),4);
1985           xastir_snprintf(weather->wx_prec_00,
1986                           sizeof(weather->wx_prec_00),
1987                           "%0.2f",
1988                           strtol(temp_data1,&temp_conv,16)/100.0);
1989         }
1990       }
1991       else
1992       {
1993         if (!from)  // From local station
1994         {
1995           weather->wx_prec_00[0]=0;
1996         }
1997       }
1998 
1999       /* rain total long term */
2000       if (data[17]!='-')   // '-' signifies invalid data
2001       {
2002         substr(temp_data1,(char *)(data+17),4);
2003         if (!from)      // From local station
2004         {
2005           switch (WX_rain_gauge_type)
2006           {
2007             case 1: // 0.1" rain gauge
2008               xastir_snprintf(weather->wx_rain_total,
2009                               sizeof(weather->wx_rain_total),
2010                               "%0.2f",
2011                               strtol(temp_data1,&temp_conv,16)*10.0);
2012               break;
2013             case 3: // 0.1mm rain gauge
2014               xastir_snprintf(weather->wx_rain_total,
2015                               sizeof(weather->wx_rain_total),
2016                               "%0.2f",
2017                               strtol(temp_data1,&temp_conv,16)/2.54);
2018               break;
2019             case 2: // 0.01" rain gauge
2020             case 0: // No conversion
2021             default:
2022               xastir_snprintf(weather->wx_rain_total,
2023                               sizeof(weather->wx_rain_total),
2024                               "%0.2f",
2025                               strtol(temp_data1,&temp_conv,16)*1.0);
2026               break;
2027           }
2028           /* local station */
2029           compute_rain((float)atof(weather->wx_rain_total));
2030           weather->wx_compute_rain_rates=1;
2031           /*last hour rain */
2032           xastir_snprintf(weather->wx_rain,
2033                           sizeof(weather->wx_rain),
2034                           "%0.2f",
2035                           rain_minute_total);
2036           /*last 24 hour rain */
2037           xastir_snprintf(weather->wx_prec_24,
2038                           sizeof(weather->wx_prec_24),
2039                           "%0.2f",
2040                           rain_24);
2041           /* rain since midnight */
2042           xastir_snprintf(weather->wx_prec_00,
2043                           sizeof(weather->wx_prec_00),
2044                           "%0.2f",
2045                           rain_00);
2046         }
2047       }
2048       else
2049       {
2050         if (!from)  // From local station
2051         {
2052           weather->wx_rain_total[0]=0;
2053         }
2054       }
2055 
2056       /* baro */
2057       if (data[21]!='-')   // '-' signifies invalid data
2058       {
2059         substr(temp_data1,(char *)(data+21),4);
2060         xastir_snprintf(weather->wx_baro,
2061                         sizeof(weather->wx_baro),
2062                         "%0.1f",
2063                         strtol(temp_data1, &temp_conv, 16)/10.0);
2064       }
2065       else
2066       {
2067         if (!from)  // From local station
2068         {
2069           weather->wx_baro[0]=0;
2070         }
2071       }
2072 
2073       /* outdoor humidity */
2074       if (data[37]!='-')   // '-' signifies invalid data
2075       {
2076         substr(temp_data1,(char *)(data+37),4);
2077         xastir_snprintf(weather->wx_hum,
2078                         sizeof(weather->wx_hum),
2079                         "%03.0f",
2080                         strtol(temp_data1,&temp_conv,16)/10.0);
2081       }
2082       else
2083       {
2084         if (!from)  // From local station
2085         {
2086           weather->wx_hum[0]=0;
2087         }
2088       }
2089 
2090       /* 1 min wind speed avg */
2091       if (len>53 && (data[53]) != '-')   // '-' signifies invalid data
2092       {
2093         substr(temp_data1,(char *)(data+53),4);
2094         xastir_snprintf(weather->wx_speed,
2095                         sizeof(weather->wx_speed),
2096                         "%03.0f",
2097                         0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137);
2098         if (from)   // From remote station
2099         {
2100           weather->wx_speed_sec_time = sec_now();
2101         }
2102         else
2103         {
2104           /* local station */
2105           computed_gust = compute_gust((float)atof(weather->wx_speed),
2106                                        last_speed,
2107                                        &last_speed_time);
2108           weather->wx_speed_sec_time = sec_now();
2109           xastir_snprintf(weather->wx_gust,
2110                           sizeof(weather->wx_gust),
2111                           "%03d",
2112                           (int)(0.5 + computed_gust));
2113         }
2114       }
2115       else
2116       {
2117         if (!from)      // From local station
2118         {
2119           if (len>53)
2120           {
2121             weather->wx_speed[0]=0;
2122           }
2123         }
2124       }
2125       break;
2126 
2127 
2128 
2129     //////////////////////////////////////////////////////////
2130     // Peet Brothers Ultimeter 2000 in complete record mode //
2131     //////////////////////////////////////////////////////////
2132     //
2133     // In this mode most fields are 4-bytes two's complement.  A
2134     // few fields are 2-bytes wide.
2135     //
2136     // <http://www.peetbros.com/HTML_Pages/faqs.htm>
2137     //
2138     case(PEET_COMPLETE):
2139       if (debug_level & 1)
2140       {
2141         fprintf(stderr,"Peet Bros U-2k Packet (Complete Record Mode) %s:<%s>\n",fill->call_sign,data);
2142       }
2143 
2144       if (!from)      // From local station
2145       {
2146         int done_with_wx_speed = 0;
2147 
2148 
2149         /* decode only for local station */
2150         weather->wx_type=WX_TYPE;
2151         xastir_snprintf(weather->wx_station,
2152                         sizeof(weather->wx_station),
2153                         "U2k");
2154 
2155 
2156         if (data[12]!='-')   // '-' signifies invalid data
2157         {
2158           substr(temp_data1,(char *)(data+12),4);
2159           xastir_snprintf(weather->wx_gust,
2160                           sizeof(weather->wx_gust),
2161                           "%03.0f",
2162                           0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137);
2163         }
2164         else
2165         {
2166           weather->wx_gust[0]=0;
2167         }
2168 
2169 
2170         // Check whether field 115 is available at bytes 452
2171         // through 455.  If so, that's the one-minute wind
2172         // speed average in 0.1kph, which matches the APRS
2173         // spec except for the units (which should be MPH).
2174         if ( (len >= 456) && (data[452] != '-') )   // '-' signifies invalid data
2175         {
2176           substr(temp_data1,(char *)(data+452),4);
2177           xastir_snprintf(weather->wx_speed,
2178                           sizeof(weather->wx_speed),
2179                           "%03.0f",
2180                           0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137);
2181           done_with_wx_speed++;
2182         }
2183 
2184 
2185         // Some Peet units don't have that particular wind
2186         // speed field, so snag what wind speed we can from
2187         // the other wind speed fields, which don't quite
2188         // match the APRS spec as they're instantaneous
2189         // values, not one-minute sustained speeds.
2190 
2191 
2192         // KG9AE
2193         // Peet Bros CR mode wind values should be selected based on which are highest.
2194         /* Wind Speed fields 1, 34, and 71.  Wind direction fields 2, 35, 72. */
2195         if (data[4] !='-')   // '-' signifies invalid data
2196         {
2197           substr(temp_data1, (char *)data+4, 4);
2198           temp1 = 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137;
2199         }
2200         else
2201         {
2202           temp1=0;
2203         }
2204         if (data[136] !='-')   // '-' signifies invalid data
2205         {
2206           substr(temp_data1, (char *)data+136, 4);
2207           temp2 = 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137;
2208         }
2209         else
2210         {
2211           temp2=0;
2212         }
2213         if (data[284] !='-')   // '-' signifies invalid data
2214         {
2215           substr(temp_data1, (char *)data+284, 4);
2216           temp3 = 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137;
2217         }
2218         else
2219         {
2220           temp3=0;
2221         }
2222 
2223         // fprintf(stderr,"WIND: wind1 %d, wind2 %d, wind3 %d\n", temp1, temp2, temp3);
2224 
2225         // Select wind speed and direction based on which
2226         // wind speed is the highest.  Ugh, surely there's a
2227         // way to make this pretty. A function might be
2228         // better.
2229         if ( temp1 >= temp2 && temp1 >= temp3 )
2230         {
2231           // fprintf(stderr,"WIND:      ***\n");
2232 
2233           /* wind speed */
2234           if (!done_with_wx_speed)
2235           {
2236             substr(temp_data1,(char *)(data+4),4);
2237             xastir_snprintf(weather->wx_speed,
2238                             sizeof(weather->wx_speed),
2239                             "%03.0f",
2240                             0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137);
2241           }
2242 
2243           /* wind direction */
2244           //
2245           // Note that the first two digits here may be
2246           // 00, or may be FF if a direction calibration
2247           // has been entered.  We should zero them.
2248           //
2249           if (data[8]!='-')   // '-' signifies invalid data
2250           {
2251             substr(temp_data1,(char *)(data+8),4);
2252             temp_data1[0] = '0';
2253             temp_data1[1] = '0';
2254             xastir_snprintf(weather->wx_course,
2255                             sizeof(weather->wx_course),
2256                             "%03.0f",
2257                             (strtol(temp_data1,&temp_conv,16)/256.0)*360.0);
2258 
2259             // Check for course = 0.  Change to 360.
2260             if (strncmp(weather->wx_course,"000",3) == 0)
2261             {
2262               xastir_snprintf(weather->wx_course,
2263                               sizeof(weather->wx_course),
2264                               "360");
2265             }
2266 
2267           }
2268           else
2269           {
2270             xastir_snprintf(weather->wx_course,
2271                             sizeof(weather->wx_course),
2272                             "000");
2273             weather->wx_course[0]=0;
2274           }
2275         }
2276         else if ( temp2 >= temp1 && temp2 >= temp3 )
2277         {
2278           // fprintf(stderr,"WIND:               ***\n");
2279 
2280           if (!done_with_wx_speed)
2281           {
2282             /* wind speed */
2283             substr(temp_data1,(char *)(data+136),4);
2284             xastir_snprintf(weather->wx_speed,
2285                             sizeof(weather->wx_speed),
2286                             "%03.0f",
2287                             0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137);
2288           }
2289 
2290           /* wind direction */
2291           //
2292           // Note that the first two digits here may be
2293           // 00, or may be FF if a direction calibration
2294           // has been entered.  We should zero them.
2295           //
2296           if (data[140]!='-')   // '-' signifies invalid data
2297           {
2298             substr(temp_data1,(char *)(data+140),4);
2299             temp_data1[0] = '0';
2300             temp_data1[1] = '0';
2301             xastir_snprintf(weather->wx_course,
2302                             sizeof(weather->wx_course),
2303                             "%03.0f",
2304                             (strtol(temp_data1,&temp_conv,16)/256.0)*360.0);
2305 
2306             // Check for course = 0.  Change to 360.
2307             if (strncmp(weather->wx_course,"000",3) == 0)
2308             {
2309               xastir_snprintf(weather->wx_course,
2310                               sizeof(weather->wx_course),
2311                               "360");
2312             }
2313 
2314           }
2315           else
2316           {
2317             xastir_snprintf(weather->wx_course,
2318                             sizeof(weather->wx_course),
2319                             "000");
2320             weather->wx_course[0]=0;
2321           }
2322         }
2323         else if ( temp3 >= temp2 && temp3 >= temp1 )
2324         {
2325           // fprintf(stderr,"WIND:                        ***\n");
2326 
2327           if (!done_with_wx_speed)
2328           {
2329             /* wind speed */
2330             substr(temp_data1,(char *)(data+284),4);
2331             xastir_snprintf(weather->wx_speed,
2332                             sizeof(weather->wx_speed),
2333                             "%03.0f",
2334                             0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137);
2335           }
2336 
2337           /* wind direction */
2338           //
2339           // Note that the first two digits here may be
2340           // 00, or may be FF if a direction calibration
2341           // has been entered.  We should zero them.
2342           //
2343           if (data[288]!='-')   // '-' signifies invalid data
2344           {
2345             substr(temp_data1,(char *)(data+288),4);
2346             temp_data1[0] = '0';
2347             temp_data1[1] = '0';
2348             xastir_snprintf(weather->wx_course,
2349                             sizeof(weather->wx_course),
2350                             "%03.0f",
2351                             (strtol(temp_data1,&temp_conv,16)/256.0)*360.0);
2352 
2353             // Check for course = 0.  Change to 360.
2354             if (strncmp(weather->wx_course,"000",3) == 0)
2355             {
2356               xastir_snprintf(weather->wx_course,
2357                               sizeof(weather->wx_course),
2358                               "360");
2359             }
2360 
2361           }
2362           else
2363           {
2364             xastir_snprintf(weather->wx_course,
2365                             sizeof(weather->wx_course),
2366                             "000");
2367             weather->wx_course[0]=0;
2368           }
2369         }
2370         else    /* Or default to the first value */
2371         {
2372           // fprintf(stderr,"WIND: DEFAULTING!\n");
2373 
2374           if (!done_with_wx_speed)
2375           {
2376             /* wind speed */
2377             substr(temp_data1,(char *)(data+4),4);
2378             xastir_snprintf(weather->wx_speed,
2379                             sizeof(weather->wx_speed),
2380                             "%03.0f",
2381                             0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137);
2382           }
2383 
2384           /* wind direction */
2385           //
2386           // Note that the first two digits here may be
2387           // 00, or may be FF if a direction calibration
2388           // has been entered.  We should zero them.
2389           //
2390           if (data[8]!='-')   // '-' signifies invalid data
2391           {
2392             substr(temp_data1,(char *)(data+8),4);
2393             temp_data1[0] = '0';
2394             temp_data1[1] = '0';
2395             xastir_snprintf(weather->wx_course,
2396                             sizeof(weather->wx_course),
2397                             "%03.0f",
2398                             (strtol(temp_data1,&temp_conv,16)/256.0)*360.0);
2399 
2400             // Check for course = 0.  Change to 360.
2401             if (strncmp(weather->wx_course,"000",3) == 0)
2402             {
2403               xastir_snprintf(weather->wx_course,
2404                               sizeof(weather->wx_course),
2405                               "360");
2406             }
2407 
2408           }
2409           else
2410           {
2411             xastir_snprintf(weather->wx_course,
2412                             sizeof(weather->wx_course),
2413                             "000");
2414             weather->wx_course[0]=0;
2415           }
2416         }
2417 
2418 
2419         /* outdoor temp */
2420         if (data[24]!='-')   // '-' signifies invalid data
2421         {
2422           int temp4;
2423 
2424           substr(temp_data1,(char *)(data+24),4);
2425           temp4 = (int)strtol(temp_data1,&temp_conv,16);
2426 
2427           if (temp_data1[0] > '7')    // Negative value, convert
2428           {
2429             temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000;
2430           }
2431 
2432           xastir_snprintf(weather->wx_temp,
2433                           sizeof(weather->wx_temp),
2434                           "%03d",
2435                           (int)((float)((temp4<<16)/65536)/10.0));
2436         }
2437         else
2438         {
2439           weather->wx_temp[0]=0;
2440         }
2441 
2442 // We don't want to parse this here because compute_rain()
2443 // calculates this for us from the accumulating long-term rain
2444 // total.  If we were to do it here as well, we'll get conflicting
2445 // results.  Since only some units put out today's rain total, we'll
2446 // just rely on our own calculations for it instead.  It'll work
2447 // across more units.
2448         /*
2449                         // todays rain total (on some units)
2450                         if (data[28]!='-') { // '-' signifies invalid data
2451                             substr(temp_data1,(char *)(data+28),4);
2452                             switch (WX_rain_gauge_type) {
2453                                 case 1: // 0.1" rain gauge
2454                                     xastir_snprintf(weather->wx_prec_00,
2455                                         sizeof(weather->wx_prec_00),
2456                                         "%0.2f",
2457                                         (float)strtol(temp_data1,&temp_conv,16)/10.0);
2458                                     break;
2459                                 case 3: // 0.1mm rain gauge
2460                                     xastir_snprintf(weather->wx_prec_00,
2461                                         sizeof(weather->wx_prec_00),
2462                                         "%0.2f",
2463                                         (float)strtol(temp_data1,&temp_conv,16)/254.0);
2464                                     break;
2465                                 case 2: // 0.01" rain gauge
2466                                 case 0: // No conversion
2467                                 default:
2468                                     xastir_snprintf(weather->wx_prec_00,
2469                                         sizeof(weather->wx_prec_00),
2470                                         "%0.2f",
2471                                         (float)strtol(temp_data1,&temp_conv,16)/100.0);
2472                                     break;
2473                             }
2474                         } else
2475                             weather->wx_prec_00[0]=0;
2476         */
2477 
2478         /* rain total long term */
2479         if ((char)data[432]!='-')   // '-' signifies invalid data
2480         {
2481           substr(temp_data1,(char *)(data+432),4);
2482           switch (WX_rain_gauge_type)
2483           {
2484             case 1: // 0.1" rain gauge
2485               xastir_snprintf(weather->wx_rain_total,
2486                               sizeof(weather->wx_rain_total),
2487                               "%0.2f",
2488                               strtol(temp_data1,&temp_conv,16)*10.0);
2489               break;
2490             case 3: // 0.1mm rain gauge
2491               xastir_snprintf(weather->wx_rain_total,
2492                               sizeof(weather->wx_rain_total),
2493                               "%0.2f",
2494                               strtol(temp_data1,&temp_conv,16)/2.54);
2495               break;
2496             case 2: // 0.01" rain gauge
2497             case 0: // No conversion
2498             default:
2499               xastir_snprintf(weather->wx_rain_total,
2500                               sizeof(weather->wx_rain_total),
2501                               "%0.2f",
2502                               strtol(temp_data1,&temp_conv,16)*1.0);
2503               break;
2504           }
2505           /* Since local station only */
2506           compute_rain((float)atof(weather->wx_rain_total));
2507           weather->wx_compute_rain_rates=1;
2508 
2509           /*last hour rain */
2510           xastir_snprintf(weather->wx_rain,
2511                           sizeof(weather->wx_rain),
2512                           "%0.2f",
2513                           rain_minute_total);
2514 
2515           /*last 24 hour rain */
2516           xastir_snprintf(weather->wx_prec_24,
2517                           sizeof(weather->wx_prec_24),
2518                           "%0.2f",
2519                           rain_24);
2520 
2521           /* rain since midnight */
2522           xastir_snprintf(weather->wx_prec_00,
2523                           sizeof(weather->wx_prec_00),
2524                           "%0.2f",
2525                           rain_00);
2526         }
2527         else
2528         {
2529           weather->wx_rain_total[0]=0;
2530         }
2531 
2532         /* baro */
2533         if (data[32]!='-')   // '-' signifies invalid data
2534         {
2535           substr(temp_data1,(char *)(data+32),4);
2536           xastir_snprintf(weather->wx_baro,
2537                           sizeof(weather->wx_baro),
2538                           "%0.1f",
2539                           strtol(temp_data1,&temp_conv,16)/10.0);
2540         }
2541         else
2542         {
2543           weather->wx_baro[0]=0;
2544         }
2545 
2546         /* outdoor humidity */
2547         if (data[52]!='-')   // '-' signifies invalid data
2548         {
2549           substr(temp_data1,(char *)(data+52),4);
2550           xastir_snprintf(weather->wx_hum,
2551                           sizeof(weather->wx_hum),
2552                           "%03.0f",
2553                           strtol(temp_data1,&temp_conv,16)/10.0);
2554         }
2555         else
2556         {
2557           weather->wx_hum[0]=0;
2558         }
2559 
2560         /* dew point */
2561         if (data[60]!='-')   // '-' signifies invalid data
2562         {
2563           int temp4;
2564 
2565           substr(temp_data1,(char *)(data+60),4);
2566           temp4 = (int)strtol(temp_data1,&temp_conv,16);
2567 
2568           if (temp_data1[0] > '7')    // Negative value, convert
2569           {
2570             temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000;
2571           }
2572 
2573           xastir_snprintf(wx_dew_point,
2574                           sizeof(wx_dew_point),
2575                           "%03d",
2576                           (int)((float)((temp4<<16)/65536)/10.0));
2577           wx_dew_point_on = 1;
2578         }
2579 
2580         /*high winds for today*/
2581         if (data[248]!='-')   // '-' signifies invalid data
2582         {
2583           substr(temp_data1,(char *)(data+248),4);
2584           xastir_snprintf(wx_high_wind,
2585                           sizeof(wx_high_wind),
2586                           "%03.0f",
2587                           0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137);
2588           wx_high_wind_on = 1;
2589         }
2590 
2591         /*wind chill */
2592         if (data[20]!='-')   // '-' signifies invalid data
2593         {
2594           int temp4;
2595 
2596           substr(temp_data1,(char *)(data+20),4);
2597           temp4 = (int)strtol(temp_data1,&temp_conv,16);
2598 
2599           if (temp_data1[0] > '7')    // Negative value, convert
2600           {
2601             temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000;
2602           }
2603 
2604           xastir_snprintf(wx_wind_chill,
2605                           sizeof(wx_wind_chill),
2606                           "%03d",
2607                           (int)((float)((temp4<<16)/65536)/10.0));
2608           wx_wind_chill_on = 1;
2609         }
2610 
2611         /*3-Hr Barometric Change */
2612         if (data[36]!='-')   // '-' signifies invalid data
2613         {
2614           int temp4;
2615 
2616           substr(temp_data1,(char *)(data+36),4);
2617           temp4 = (int)strtol(temp_data1,&temp_conv,16);
2618 
2619           if (temp_data1[0] > '7')    // Negative value, convert
2620           {
2621             temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000;
2622           }
2623 
2624           xastir_snprintf(wx_three_hour_baro,
2625                           sizeof(wx_three_hour_baro),
2626                           "%0.2f",
2627 // Old code
2628 //                  (float)((strtol(temp_data1,&temp_conv,16)<<16)/65536)/100.0/3.38639);
2629 // New code, fix by Matt Werner, kb0kqa:
2630                           (float)((temp4<<16)/65536)/10.0);
2631 
2632           wx_three_hour_baro_on = 1;
2633         }
2634 
2635         /* High Temp for Today*/
2636         if (data[276]!='-')   // '-' signifies invalid data
2637         {
2638           int temp4;
2639 
2640           substr(temp_data1,(char *)(data+276),4);
2641           temp4 = (int)strtol(temp_data1,&temp_conv,16);
2642 
2643           if (temp_data1[0] > '7')    // Negative value, convert
2644           {
2645             temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000;
2646           }
2647 
2648           xastir_snprintf(wx_hi_temp,
2649                           sizeof(wx_hi_temp),
2650                           "%03d",
2651                           (int)((float)((temp4<<16)/65536)/10.0));
2652           wx_hi_temp_on = 1;
2653         }
2654         else
2655         {
2656           wx_hi_temp_on = 0;
2657         }
2658 
2659         /* Low Temp for Today*/
2660         if (data[100]!='-')   // '-' signifies invalid data
2661         {
2662           int temp4;
2663 
2664           substr(temp_data1,(char *)(data+100),4);
2665           temp4 = (int)strtol(temp_data1,&temp_conv,16);
2666 
2667           if (temp_data1[0] > '7')    // Negative value, convert
2668           {
2669             temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000;
2670           }
2671 
2672           xastir_snprintf(wx_low_temp,
2673                           sizeof(wx_low_temp),
2674                           "%03d",
2675                           (int)((float)((temp4<<16)/65536)/10.0));
2676           wx_low_temp_on = 1;
2677         }
2678         else
2679         {
2680           wx_low_temp_on = 0;
2681         }
2682 
2683         /* Heat Index Calculation*/
2684         hi_hum=atoi(weather->wx_hum);
2685         rh2= atoi(weather->wx_hum);
2686         rh2=(rh2 * rh2);
2687         hidx_temp=atoi(weather->wx_temp);
2688         t2= atoi(weather->wx_temp);
2689         t2=(t2 * t2);
2690 
2691         if (hidx_temp >= 70)
2692         {
2693           heat_index=-42.379+2.04901523 * hidx_temp+10.1433127 * hi_hum-0.22475541
2694                      * hidx_temp * hi_hum-0.00683783 * t2-0.05481717 * rh2+0.00122874
2695                      * t2 * hi_hum+0.00085282 * hidx_temp * rh2-0.00000199 * t2 * rh2;
2696           xastir_snprintf (wx_heat_index,
2697                            sizeof(wx_heat_index),
2698                            "%03d",
2699                            heat_index);
2700           wx_heat_index_on = 1;
2701         }
2702         else
2703         {
2704           wx_heat_index_on = 0;
2705         }
2706       }
2707       break;
2708 
2709 
2710 
2711     ////////////////////////
2712     // Qualimetrics Q-Net //
2713     ////////////////////////
2714     case(QM_WX):
2715       if (debug_level & 1)
2716       {
2717         fprintf(stderr,"Qualimetrics Q-Net %s:<%s>\n",fill->call_sign,data);
2718       }
2719 
2720       weather->wx_type=WX_TYPE;
2721       xastir_snprintf(weather->wx_station,
2722                       sizeof(weather->wx_station),
2723                       "Q-N");
2724 
2725       // Can this sscanf overflow the "temp" buffer?  I
2726       // changed the length of temp to MAX_DEVICE_BUFFER to
2727       // avoid this problem.
2728       if (6 != sscanf((char *)data,"%19s %d %19s %d %19s %d",temp,&temp1,temp,&temp2,temp,&temp3))
2729       {
2730         fprintf(stderr,"wx_fill_data:sscanf parsing error\n");
2731       }
2732 
2733       /* outdoor temp */
2734       xastir_snprintf(weather->wx_temp,
2735                       sizeof(weather->wx_temp),
2736                       "%03d",
2737                       (int)((temp2/10.0)));
2738 
2739       /* baro */
2740       xastir_snprintf(weather->wx_baro,
2741                       sizeof(weather->wx_baro),
2742                       "%0.1f",
2743                       ((float)temp3/100.0)*33.864);
2744 
2745       /* outdoor humidity */
2746       xastir_snprintf(weather->wx_hum,
2747                       sizeof(weather->wx_hum),
2748                       "%03d",
2749                       temp1);
2750 
2751       if (!from)      // From local station
2752       {
2753         weather->wx_gust[0]=0;
2754         weather->wx_course[0]=0;
2755         weather->wx_rain[0]=0;
2756         weather->wx_prec_00[0]=0;
2757         weather->wx_prec_24[0]=0;
2758         weather->wx_rain_total[0]=0;
2759         weather->wx_gust[0]=0;
2760         weather->wx_speed[0]=0;
2761       }
2762       break;
2763 
2764 
2765 
2766     ///////////////////////////////////////////////////////////
2767     //  Radio Shack WX-200 or Huger/Oregon Scientific WM-918 //
2768     ///////////////////////////////////////////////////////////
2769     case(RSWX200):
2770 
2771       // Notes:  Many people run the wx200d daemon connected to the weather station,
2772       // with Xastir then connected to wx200d.  Note that wx200d changes the protocol
2773       // slightly:  It only sends frames that have changed to the clients.  This means
2774       // even if the weather station is sending regular packets, wx200d won't send
2775       // them along to Xastir if all the bits are the same as the last packet of that
2776       // type.  To fix this I had to tie into the main.c:UpdateTime() function to do
2777       // regular updates at a 30 second rate, to keep the rain and gust queues cycling
2778       // on a regular basis.
2779       //
2780       // 2nd Note:  Some WX-200 weather stations send bogus data.  I had to add in a
2781       // bunch of filtering to keep the global variables from getting corrupted by
2782       // this data.  More filtering may need to be done and/or the limits may need to
2783       // be changed.
2784 
2785       if (!from)      // From local station
2786       {
2787         if (debug_level & 1)
2788         {
2789           fprintf(stderr,"RSWX200 WX (binary)\n");
2790         }
2791 
2792         weather->wx_type=WX_TYPE;
2793         xastir_snprintf(weather->wx_station,
2794                         sizeof(weather->wx_station),
2795                         "RSW");
2796 
2797         switch (data[0])
2798         {
2799           case 0x8f: /* humidity */
2800             if ( (rswnc(data[20]) <= 100) && (rswnc(data[2]) >= 0) )
2801               xastir_snprintf(weather->wx_hum,
2802                               sizeof(weather->wx_hum),
2803                               "%03d",
2804                               rswnc(data[20]));
2805             else
2806               //sprintf(weather->wx_hum,"100");
2807             {
2808               fprintf(stderr,"Humidity out-of-range, ignoring: %03d\n",rswnc(data[20]) );
2809             }
2810             break;
2811 
2812           case 0x9f: /* temp */
2813             /* all data in C ?*/
2814             xastir_snprintf(temp_data1,
2815                             sizeof(temp_data1),
2816                             "%c%d%0.1f",
2817                             ((data[17]&0x08) ? '-' : '+'),(data[17]&0x7),rswnc(data[16])/10.0);
2818             /*fprintf(stderr,"temp data: <%s> %d %d %d\n", temp_data1,((data[17]&0x08)==0x08),(data[17]&0x7),rswnc(data[16]));*/
2819             temp_temp = (float)((atof(temp_data1)*1.8)+32);
2820             if ( (temp_temp >= -99.0) && (temp_temp < 200.0) )
2821             {
2822               xastir_snprintf(weather->wx_temp,
2823                               sizeof(weather->wx_temp),
2824                               "%03d",
2825                               (int)((atof(temp_data1)*1.8)+32));
2826               /*fprintf(stderr,"Temp %s C %0.2f %03d\n",temp_data1,atof(temp_data1),(int)atof(temp_data1));
2827               fprintf(stderr,"Temp F %0.2f %03d\n",(atof(temp_data1)*1.8)+32,(int)(atof(temp_data1)*1.8)+32);
2828               */
2829             }
2830             else      // We don't want to save this one
2831             {
2832               fprintf(stderr,"Temp out-of-range, ignoring: %0.2f\n", temp_temp);
2833             }
2834             xastir_snprintf(temp_data1,
2835                             sizeof(temp_data1),
2836                             "%c%d%d.%d",
2837                             ((data[18]&0x80) ? '-' : '+'),(data[18]&0x70)>>4,(data[18]&0x0f),(data[17] & 0xf0) >> 4);
2838             xastir_snprintf(wx_hi_temp,
2839                             sizeof(wx_hi_temp),
2840                             "%03d",
2841                             (int)((atof(temp_data1)*1.8)+32));
2842             wx_hi_temp_on=1;
2843             xastir_snprintf(temp_data1,
2844                             sizeof(temp_data1),
2845                             "%c%d%d.%d",
2846                             ((data[23]&0x80) ? '-' : '+'),(data[23]&0x70)>>4,(data[23]&0x0f),(data[22] & 0xf0) >> 4);
2847             xastir_snprintf(wx_low_temp,
2848                             sizeof(wx_low_temp),
2849                             "%03d",
2850                             (int)((atof(temp_data1)*1.8)+32));
2851             wx_low_temp_on=1;
2852             break;
2853 
2854           case 0xaf: /* baro/dewpt */
2855             // local baro pressure in mb?
2856             // sprintf(weather->wx_baro,"%02d%02d",rswnc(data[2]),rswnc(data[1]));
2857             // Sea Level Adjusted baro in mb
2858             xastir_snprintf(weather->wx_baro,
2859                             sizeof(weather->wx_baro),
2860                             "%0d%02d%0.1f",
2861                             (data[5]&0x0f),
2862                             rswnc(data[4]),
2863                             rswnc(data[3])/10.0);
2864 
2865             /* dew point in C */
2866             temp_temp = (int)((rswnc(data[18])*1.8)+32);
2867             if ( (temp_temp >= 32.0) && (temp_temp < 150.0) )
2868               xastir_snprintf(wx_dew_point,
2869                               sizeof(wx_dew_point),
2870                               "%03d",
2871                               (int)((rswnc(data[18])*1.8)+32));
2872             else
2873             {
2874               fprintf(stderr,"Dew point out-of-range, ignoring: %0.2f\n", temp_temp);
2875             }
2876             break;
2877 
2878           case 0xbf: /* Rain */
2879             // All data in mm.  Convert to hundredths of an inch.
2880             xastir_snprintf(temp_data1,
2881                             sizeof(temp_data1),
2882                             "%02d%02d",
2883                             rswnc(data[6]),
2884                             rswnc(data[5]));
2885 
2886             temp_temp = (float)(atof(temp_data1) * 3.9370079);
2887 
2888             if ( (temp_temp >= 0) && (temp_temp < 51200.0) )   // Between 0 and 512 inches
2889             {
2890               xastir_snprintf(weather->wx_rain_total,
2891                               sizeof(weather->wx_rain_total),
2892                               "%0.2f",
2893                               atof(temp_data1) * 3.9370079);
2894 
2895               /* Since local station only */
2896               compute_rain((float)atof(weather->wx_rain_total));
2897               weather->wx_compute_rain_rates=1;
2898 
2899               /* Last hour rain */
2900               xastir_snprintf(weather->wx_rain,
2901                               sizeof(weather->wx_rain),
2902                               "%0.2f",
2903                               rain_minute_total);
2904 
2905               /* Last 24 hour rain */
2906               xastir_snprintf(weather->wx_prec_24,
2907                               sizeof(weather->wx_prec_24),
2908                               "%0.2f",
2909                               rain_24);
2910 
2911               /* Rain since midnight */
2912               xastir_snprintf(weather->wx_prec_00,
2913                               sizeof(weather->wx_prec_00),
2914                               "%0.2f",
2915                               rain_00);
2916             }
2917             else
2918             {
2919               fprintf(stderr,"Total Rain out-of-range, ignoring: %0.2f\n", temp_temp);
2920             }
2921             break;
2922 
2923           case 0xcf: /* Wind w/chill*/
2924             /* get last gust speed */
2925             if (strlen(weather->wx_gust) > 0)
2926             {
2927               /* get last speed */
2928               last_speed=(float)atof(weather->wx_gust);
2929               last_speed_time=weather->wx_speed_sec_time;
2930             }
2931             /* all data in m/s */
2932             /* average wind speed */
2933             xastir_snprintf(temp_data1,
2934                             sizeof(temp_data1),
2935                             "%01d%0.1f",
2936                             (data[5]&0xf),
2937                             (float)( rswnc(data[4]) / 10 ));
2938             // Convert to mph
2939             xastir_snprintf(weather->wx_speed,
2940                             sizeof(weather->wx_speed),
2941                             "%03d",
2942                             (int)(0.5 + (atof(temp_data1)*2.2369)));
2943 
2944             /* wind gust */
2945             xastir_snprintf(temp_data1,
2946                             sizeof(temp_data1),
2947                             "%01d%0.1f",
2948                             (data[2]&0xf),
2949                             (float)( rswnc(data[1]) / 10 ));
2950             /*sprintf(weather->wx_gust,"%03d",(int)(0.5 + (atof(temp_data1)*2.2369)));*/
2951 
2952             /* do computed gust, convert to mph */
2953             computed_gust = compute_gust((int)(0.5 + (atof(temp_data1)*2.2369)),
2954                                          last_speed,
2955                                          &last_speed_time);
2956             weather->wx_speed_sec_time = sec_now();
2957             xastir_snprintf(weather->wx_gust,
2958                             sizeof(weather->wx_gust),
2959                             "%03d",
2960                             (int)(0.5 + computed_gust));
2961 
2962             /* high wind gust */
2963             xastir_snprintf(temp_data1,
2964                             sizeof(temp_data1),
2965                             "%01d%0.1f",
2966                             (data[8]&0xf),
2967                             (float)( rswnc(data[7]) / 10 ));
2968             xastir_snprintf(wx_high_wind,
2969                             sizeof(wx_high_wind),
2970                             "%03d",
2971                             (int)(0.5 + (atof(temp_data1)*2.2369)));
2972             wx_high_wind_on = 1;
2973 
2974             xastir_snprintf(weather->wx_course,
2975                             sizeof(weather->wx_course),
2976                             "%03d",
2977                             ( ((rswnc(data[3])*10) + ((data[2]&0xf0)>>4)) %1000 ) );
2978 
2979             // Check for course = 0.  Change to 360.
2980             if (strncmp(weather->wx_course,"000",3) == 0)
2981             {
2982               xastir_snprintf(weather->wx_course,
2983                               sizeof(weather->wx_course),
2984                               "360");
2985             }
2986 
2987             /* wind chill in C */
2988             xastir_snprintf(temp_data1,
2989                             sizeof(temp_data1),
2990                             "%c%d",
2991                             ((data[21]&0x20) ? '-' : '+'),
2992                             rswnc(data[16]));
2993 
2994             temp_temp = (float)((atof(temp_data1)*1.8)+32);
2995             if ( (temp_temp > -200.0) && (temp_temp < 200.0) )
2996               xastir_snprintf(wx_wind_chill,
2997                               sizeof(wx_wind_chill),
2998                               "%03d",
2999                               (int)((atof(temp_data1)*1.8)+32));
3000             else
3001             {
3002               fprintf(stderr,"Wind_chill out-of-range, ignoring: %0.2f\n", temp_temp);
3003             }
3004 
3005             wx_wind_chill_on = 1;
3006             break;
3007           default:
3008             break;
3009         }
3010 
3011         if (strlen(weather->wx_hum) > 0 && strlen(weather->wx_temp) > 0)
3012         {
3013           /* Heat Index Calculation*/
3014           hi_hum=atoi(weather->wx_hum);
3015           rh2= atoi(weather->wx_hum);
3016           rh2=(rh2 * rh2);
3017           hidx_temp=atoi(weather->wx_temp);
3018           t2= atoi(weather->wx_temp);
3019           t2=(t2 * t2);
3020 
3021           if (hidx_temp >= 70)
3022           {
3023             heat_index=(-42.379+2.04901523 * hidx_temp+10.1433127 * hi_hum-0.22475541 * hidx_temp *
3024                         hi_hum-0.00683783 * t2-0.05481717 * rh2+0.00122874 * t2 * hi_hum+0.00085282 *
3025                         hidx_temp * rh2-0.00000199 * t2 * rh2);
3026             xastir_snprintf(wx_heat_index,
3027                             sizeof(wx_heat_index),
3028                             "%03d",
3029                             heat_index);
3030 
3031             wx_heat_index_on=1;
3032           }
3033           else
3034           {
3035             wx_heat_index[0] = 0;
3036           }
3037         }   // end of heat index calculation
3038       }   // end of if (!from)
3039       break;  // End of case for RSWX200 weather station
3040 
3041 
3042     ///////////////////////////////////////////////////////////
3043     //  Davis WMII/WWIII/Vantage Pro via meteo & db2APRS     //
3044     ///////////////////////////////////////////////////////////
3045 
3046     // Note: format is really APRS Spec 'positionless' WX string w/tag for X and Davis
3047 
3048     case(DAVISMETEO) :
3049 
3050 
3051       // todo - need to deal with lack of values, such as c...s...g...t045 string
3052 
3053       memset(weather->wx_course,0,4);    // Keep out fradulent data...
3054       memset(weather->wx_speed,0,4);
3055       memset(weather->wx_temp,0,5);
3056       memset(weather->wx_rain,0,10);
3057       memset(weather->wx_prec_00,0,10);
3058       memset(weather->wx_prec_24,0,10);
3059       memset(weather->wx_rain_total,0,10);
3060       memset(weather->wx_hum,0,5);
3061       memset(weather->wx_baro,0,10);
3062       memset(weather->wx_station,0,MAX_WXSTATION);
3063 
3064       if ((temp_conv=strchr((char *)data,'c')))   // Wind Direction in Degrees
3065       {
3066         xastir_snprintf(weather->wx_course,
3067                         sizeof(weather->wx_course),
3068                         "%s",
3069                         temp_conv+1);
3070         weather->wx_course[3] = '\0';
3071       }
3072 
3073       // Check for course = 0.  Change to 360.
3074       if (strncmp(weather->wx_course,"000",3) == 0)
3075       {
3076         xastir_snprintf(weather->wx_course,
3077                         sizeof(weather->wx_course),
3078                         "360");
3079       }
3080 
3081       if ((temp_conv=strchr((char *)data,'s')))   // Wind Speed in MPH - not snowfall
3082       {
3083         xastir_snprintf(weather->wx_speed,
3084                         sizeof(weather->wx_speed),
3085                         "%s",
3086                         temp_conv+1);
3087         weather->wx_speed[3] = '\0';
3088       }
3089 
3090       if ((temp_conv=strchr((char *)data,'g')))   // Wind Gust in MPH
3091       {
3092         // Don't read if data is "..." (missing gust data)
3093         // If we aren't getting gust data from the station, don't clobber
3094         // the gust data we're computing!
3095         if (strncmp(temp_conv+1,"...",3) != 0)
3096         {
3097           memset(weather->wx_gust,0,4); // keep out fraudulent data
3098           xastir_snprintf(weather->wx_gust,
3099                           sizeof(weather->wx_gust),
3100                           "%s",
3101                           temp_conv+1);
3102           weather->wx_gust[3] = '\0';
3103 
3104           // compute high wind
3105           if(wx_high_wind[0] == '\0' ||   // first time
3106              (get_hours() == 0 && get_minutes() == 0) || // midnite
3107              (atol(weather->wx_gust) > atol(wx_high_wind)))   // gust
3108           {
3109             xastir_snprintf(wx_high_wind,
3110                             sizeof(wx_high_wind),
3111                             "%s",
3112                             weather->wx_gust);
3113           }
3114           wx_high_wind_on=1;
3115         }
3116       }
3117 
3118       if ((temp_conv=strchr((char *)data,'t')))   // Temperature in Degrees F
3119       {
3120         xastir_snprintf(weather->wx_temp,
3121                         sizeof(weather->wx_temp),
3122                         "%s",
3123                         temp_conv+1);
3124         weather->wx_temp[3] = '\0';
3125 
3126         // compute hi temp, since APRS doesn't send that
3127         if(wx_hi_temp[0] == '\0' || // first time
3128             (get_hours() == 0 && get_minutes() == 0) || // midnite
3129             (atol(weather->wx_temp) > atol(wx_hi_temp)))
3130         {
3131           xastir_snprintf(wx_hi_temp,
3132                           sizeof(wx_hi_temp),
3133                           "%s",
3134                           weather->wx_temp);
3135         }
3136         wx_hi_temp_on=1;
3137 
3138         // compute low temp, since APRS doesn't send that
3139         if(wx_low_temp[0] == '\0' || // first time
3140             (get_hours() == 0 && get_minutes() == 0) || // midnite
3141             (atol(weather->wx_temp) < atol(wx_low_temp)))
3142         {
3143           xastir_snprintf(wx_low_temp,
3144                           sizeof(wx_low_temp),
3145                           "%s",
3146                           weather->wx_temp);
3147         }
3148         wx_low_temp_on=1;
3149       }
3150 
3151       if ((temp_conv=strchr((char *)data,'r')))   // Rain per hour
3152       {
3153         xastir_snprintf(weather->wx_rain,
3154                         sizeof(weather->wx_rain),
3155                         "%s",
3156                         temp_conv+1);
3157         weather->wx_rain[3] = '\0';
3158       }
3159 
3160       if ((temp_conv=strchr((char *)data,'p')))   // Rain per 24 hrs/total
3161       {
3162         xastir_snprintf(weather->wx_prec_24,
3163                         sizeof(weather->wx_prec_24),
3164                         "%s",
3165                         temp_conv+1);
3166         weather->wx_prec_24[3] = '\0';
3167       }
3168 
3169       if ((temp_conv=strchr((char *)data,'P')))   // Rain since midnight
3170       {
3171         xastir_snprintf(weather->wx_prec_00,
3172                         sizeof(weather->wx_prec_00),
3173                         "%s",
3174                         temp_conv+1);
3175         weather->wx_prec_00[3] = '\0';
3176       }
3177 
3178       if ((temp_conv=strchr((char *)data,'T')))   // Total Rain since
3179       {
3180         // wx station reset
3181         xastir_snprintf(weather->wx_rain_total,
3182                         sizeof(weather->wx_rain_total),
3183                         "%s",
3184                         temp_conv+1);
3185         weather->wx_rain_total[4] = '\0';
3186       }
3187 
3188       // Ok, here's the deal --- if we got total rain AND we didn't get
3189       // rain-since-midnight, fix it up.
3190       // This is a problem with LaCrosse --- no rain-since-midnight
3191       // provided.  Don't do anything at all if we didn't get total rain
3192       // from the station.  compute_rain *depends* on "total rain" being
3193       // a strictly increasing number that is never reset to zero during
3194       // Xastir's run.
3195       if (strlen(weather->wx_rain_total) >0 )
3196       {
3197         compute_rain((float)atof(weather->wx_rain_total));
3198         if (weather->wx_prec_00[0] == '\0')
3199         {
3200           /* rain since midnight */
3201           xastir_snprintf(weather->wx_prec_00,
3202                           sizeof(weather->wx_prec_00),
3203                           "%0.2f",
3204                           rain_00);
3205         }
3206       }
3207 
3208       // we are should be getting total rain from the station, but
3209       // we are also getting the rates.
3210       // Davis gives 24-hour, since-midnight, and 1-hour rates.
3211       // LaCrosse gives 24 and 1 hour.
3212       // Don't recompute what the station already gave us.
3213       weather->wx_compute_rain_rates=0;
3214 
3215       if ((temp_conv=strchr((char *)data,'h')))   // Humidity %
3216       {
3217 
3218         if (!strncmp(temp_conv+1,"00",2))    // APRS says 00 is
3219         {
3220           xastir_snprintf(weather->wx_hum, // 100% humidity
3221                           sizeof(weather->wx_hum),
3222                           "%s",
3223                           "100");
3224           weather->wx_hum[3] = '\0';
3225         }
3226         else
3227         {
3228           xastir_snprintf(weather->wx_hum, // humidity less than
3229                           sizeof(weather->wx_hum),     // 100%
3230                           "%s",
3231                           temp_conv+1);
3232           weather->wx_hum[2] = '\0';
3233         }
3234       }
3235 
3236       if ((temp_conv=strchr((char *)data,'b')))   // Air Pressure in 1/10 hPa
3237       {
3238         memset(temp_data1,0,sizeof(temp_data1));
3239 
3240         xastir_snprintf(temp_data1,
3241                         sizeof(temp_data1),
3242                         "%s",
3243                         temp_conv+1);
3244         temp_data1[5] = '\0';
3245 
3246         temp_temp = (float)(atof(temp_data1))/10.0;
3247         xastir_snprintf(temp_data1,
3248                         sizeof(temp_data1),
3249                         "%0.1f",
3250                         temp_temp);
3251         xastir_snprintf(weather->wx_baro,
3252                         sizeof(weather->wx_baro),
3253                         "%s",
3254                         temp_data1);
3255       }
3256 
3257       if ((temp_conv=strchr((char *)data,'x')))   // WX Station Identifier
3258       {
3259         xastir_snprintf(weather->wx_station,
3260                         sizeof(weather->wx_station),
3261                         "%s",
3262                         temp_conv+1);
3263         weather->wx_station[MAX_WXSTATION-1] = '\0';
3264       }
3265 
3266       // now compute wind chill
3267       wind_chill = 35.74 + .6215 * atof(weather->wx_temp) -
3268                    35.75 * pow(atof(weather->wx_gust), .16) +
3269                    .4275 * atof(weather->wx_temp) *
3270                    pow(atof(weather->wx_gust), .16);
3271 
3272       if((wind_chill < atof(weather->wx_temp)) &&
3273           (atof(weather->wx_temp) < 50))
3274       {
3275 
3276         xastir_snprintf(wx_wind_chill,
3277                         sizeof(wx_wind_chill),
3278                         "%.0f",
3279                         wind_chill);
3280         wx_wind_chill_on = 1;
3281       }
3282       else
3283       {
3284         wx_wind_chill_on = 0;
3285         wx_wind_chill[0] = '\0';
3286       }
3287 
3288       // The rest of the optional WX data is not used by
3289       // xastir (Luminosity, etc), except for snow, which
3290       // conflicts with wind speed (both are lower case 's')
3291 
3292       if (debug_level & 1)
3293         fprintf(stdout,"Davis Decode: wd-%s,ws-%s,wg-%s,t-%s,rh-%s,r00-%s,r24-%s,rt-%s,h-%s,ap-%s,station-%s\n",
3294 
3295                 weather->wx_course,weather->wx_speed,weather->wx_gust,
3296                 weather->wx_temp,weather->wx_rain,weather->wx_prec_00,
3297                 weather->wx_prec_24,weather->wx_rain_total,
3298                 weather->wx_hum,weather->wx_baro,weather->wx_station);
3299       break;
3300     // This is the output of the Davis APRS Data Logger.  The format
3301     // is in fact exactly the same as a regular APRS weather packet,
3302     // complete with position information.  Ignore that.
3303     // @xxxxxxzDDMM.mmN/DDDMM.mmW_CSE/SPDgGGGtTTTrRRRpRRRPRRRhXXbXXXXX.DsVP
3304     case (DAVISAPRSDL):
3305 
3306       memset(weather->wx_course,0,4);    // Keep out fradulent data...
3307       memset(weather->wx_speed,0,4);
3308       memset(weather->wx_gust,0,4);
3309       memset(weather->wx_temp,0,5);
3310       memset(weather->wx_rain,0,10);
3311       memset(weather->wx_prec_00,0,10);
3312       memset(weather->wx_prec_24,0,10);
3313       memset(weather->wx_rain_total,0,10);
3314       memset(weather->wx_hum,0,5);
3315       memset(weather->wx_baro,0,10);
3316       memset(weather->wx_station,0,MAX_WXSTATION);
3317 
3318       if (sscanf((char *)data,
3319                  "%*27s%3s/%3sg%3st%3sr%3sp%3sP%3sh%2sb%5s.DsVP",
3320                  weather->wx_course,
3321                  weather->wx_speed,
3322                  weather->wx_gust,
3323                  weather->wx_temp,
3324                  weather->wx_rain,
3325                  weather->wx_prec_24,
3326                  weather->wx_prec_00,
3327                  weather->wx_hum,
3328                  weather->wx_baro) == 9)
3329       {
3330         // then we got all the data out of the packet... now process
3331         // First null-terminate all the strings:
3332         weather->wx_course[3]='\0';
3333         weather->wx_speed[3]='\0';
3334         weather->wx_gust[3]='\0';
3335         weather->wx_temp[3]='\0';
3336         weather->wx_rain[3]='\0';
3337         weather->wx_prec_24[3]='\0';
3338         weather->wx_prec_00[3]='\0';
3339         weather->wx_hum[2]='\0';
3340         weather->wx_baro[6]='\0';
3341 
3342 
3343         // NOTE:  Davis APRS Data Logger does NOT provide total rain,
3344         // and so data from compute_rain (which needs total rain) will
3345         // be wrong.  Set this flag to stop that from clobbering our
3346         // good rain rate data.
3347         weather->wx_compute_rain_rates=0;
3348 
3349         // Check for course = 0.  Change to 360.
3350         if (strncmp(weather->wx_course,"000",3) == 0)
3351         {
3352           xastir_snprintf(weather->wx_course,
3353                           sizeof(weather->wx_course),
3354                           "360");
3355         }
3356 
3357         // compute high wind
3358         if(wx_high_wind[0] == '\0' ||   // first time
3359             (get_hours() == 0 && get_minutes() == 0) || // midnite
3360             (atol(weather->wx_gust) > atol(wx_high_wind)))   // gust
3361         {
3362           xastir_snprintf(wx_high_wind,
3363                           sizeof(wx_high_wind),
3364                           "%s",
3365                           weather->wx_gust);
3366         }
3367         wx_high_wind_on=1;
3368 
3369         // compute hi temp, since APRS doesn't send that
3370         if(wx_hi_temp[0] == '\0' || // first time
3371             (get_hours() == 0 && get_minutes() == 0) || // midnite
3372             (atol(weather->wx_temp) > atol(wx_hi_temp)))
3373         {
3374           xastir_snprintf(wx_hi_temp,
3375                           sizeof(wx_hi_temp),
3376                           "%s",
3377                           weather->wx_temp);
3378         }
3379         wx_hi_temp_on=1;
3380 
3381         // compute low temp, since APRS doesn't send that
3382         if(wx_low_temp[0] == '\0' || // first time
3383             (get_hours() == 0 && get_minutes() == 0) || // midnite
3384             (atol(weather->wx_temp) < atol(wx_low_temp)))
3385         {
3386           xastir_snprintf(wx_low_temp,
3387                           sizeof(wx_low_temp),
3388                           "%s",
3389                           weather->wx_temp);
3390         }
3391         wx_low_temp_on=1;
3392 
3393 
3394         // fix up humidity --- 00 in APRS means 100%:
3395         if (strncmp(weather->wx_hum,"00",2)==0)
3396         {
3397           weather->wx_hum[0]='1';
3398           weather->wx_hum[1]=weather->wx_hum[2]='0';
3399           weather->wx_hum[3]='\0';
3400         }
3401 
3402         // fix up barometer.  APRS sends in 10ths of millibars:
3403         temp_temp=(float)(atof(weather->wx_baro))/10.0;
3404         weather->wx_baro[0]='\0'; // zero out so snprintf doesn't append
3405         xastir_snprintf(weather->wx_baro,
3406                         sizeof(weather->wx_baro),
3407                         "%0.1f",
3408                         temp_temp);  // this should terminate Just Fine.
3409 
3410         // now compute wind chill
3411         wind_chill = 35.74 + .6215 * atof(weather->wx_temp) -
3412                      35.75 * pow(atof(weather->wx_gust), .16) +
3413                      .4275 * atof(weather->wx_temp) *
3414                      pow(atof(weather->wx_gust), .16);
3415 
3416         if((wind_chill < atof(weather->wx_temp)) &&
3417             (atof(weather->wx_temp) < 50))
3418         {
3419 
3420           xastir_snprintf(wx_wind_chill,
3421                           sizeof(wx_wind_chill),
3422                           "%.0f",
3423                           wind_chill);
3424           wx_wind_chill_on = 1;
3425         }
3426         else
3427         {
3428           wx_wind_chill_on = 0;
3429           wx_wind_chill[0] = '\0';
3430         }
3431         xastir_snprintf(weather->wx_station,
3432                         sizeof(weather->wx_station),
3433                         "%s",
3434                         (char *) &(data[63]));
3435 
3436         /* Heat Index Calculation*/
3437         hi_hum=atoi(weather->wx_hum);
3438         rh2= atoi(weather->wx_hum);
3439         rh2=(rh2 * rh2);
3440         hidx_temp=atoi(weather->wx_temp);
3441         t2= atoi(weather->wx_temp);
3442         t2=(t2 * t2);
3443 
3444         if (hidx_temp >= 70)
3445         {
3446           heat_index=-42.379+2.04901523 * hidx_temp+10.1433127 * hi_hum-0.22475541
3447                      * hidx_temp * hi_hum-0.00683783 * t2-0.05481717 * rh2+0.00122874
3448                      * t2 * hi_hum+0.00085282 * hidx_temp * rh2-0.00000199 * t2 * rh2;
3449           xastir_snprintf (wx_heat_index,
3450                            sizeof(wx_heat_index),
3451                            "%03d",
3452                            heat_index);
3453           wx_heat_index_on = 1;
3454         }
3455         else
3456         {
3457           wx_heat_index_on = 0;
3458         }
3459 
3460 
3461         if (debug_level & 1)
3462           fprintf(stdout,"Davis APRS DataLogger Decode $Revision$: wd-%s,ws-%s,wg-%s,t-%s,rh-%s,r24-%s,r00-%s,h-%s,ap-%s,station-%s\n",
3463 
3464                   weather->wx_course,weather->wx_speed,weather->wx_gust,
3465                   weather->wx_temp, weather->wx_rain,
3466                   weather->wx_prec_24, weather->wx_prec_00,weather->wx_hum,weather->wx_baro,
3467                   weather->wx_station);
3468       }
3469       break;
3470 
3471   }
3472   // End of big switch
3473 }   // End of wx_fill_data()
3474 
3475 
3476 
3477 
3478 
3479 //**********************************************************
3480 // Decode WX data line
3481 // wx_line: raw wx data to decode
3482 //
3483 // This is called from main.c:UpdateTime() only.  It
3484 // decodes data for serially-connected and network-connected
3485 // WX interfaces only.   It calls wx_fill_data() to do the
3486 // real work once it figures out what type of data it has.
3487 //**********************************************************
3488 //
3489 // Note that the length of "wx_line" can be up to MAX_DEVICE_BUFFER,
3490 // which is currently set to 4096.
3491 //
wx_decode(unsigned char * wx_line,int data_length,int port)3492 void wx_decode(unsigned char *wx_line, int data_length, int port)
3493 {
3494   DataRow *p_station;
3495   int decoded;
3496   int find;
3497   int i;
3498   int len;
3499   char time_data[MAX_TIME];
3500   unsigned int check_sum;
3501   int max;
3502   WeatherRow *weather;
3503   float t1,t2,t3,t4,t5,t6,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19;
3504   int t7,t8;
3505 
3506 
3507   //fprintf(stderr,"wx_decode: %s\n",wx_line);
3508   //fprintf(stderr,"\nwx_decode: %d bytes\n", data_length);
3509 
3510   find=0;
3511 
3512   len = data_length;
3513   if (len == 0)
3514   {
3515     len=strlen((char *)wx_line);
3516   }
3517 
3518   if (len>10 || ((int)wx_line[0]!=0 && port_data[port].data_type==1))
3519   {
3520     if (search_station_name(&p_station,my_callsign,1))
3521     {
3522       if (get_weather_record(p_station))      // DK7IN: only add record if we found something...
3523       {
3524         weather = p_station->weather_data;
3525 
3526         decoded=0;
3527         /* Ok decode wx data */
3528         if (wx_line[0]=='!'
3529             && wx_line[1]=='!'
3530             && is_xnum_or_dash((char *)(wx_line+2),40)
3531             && port_data[port].data_type==0)
3532         {
3533 
3534           /* Found Peet Bros U-2k */
3535           if (debug_level & 1)
3536           {
3537             fprintf(stderr,"Found Peet Bros U-2k WX:%s\n",wx_line+2);
3538           }
3539 
3540           xastir_snprintf(wx_station_type,
3541                           sizeof(wx_station_type),
3542                           "%s",
3543                           langcode("WXPUPSI011"));
3544 
3545           xastir_snprintf(raw_wx_string,
3546                           sizeof(raw_wx_string),
3547                           "%s",
3548                           wx_line);
3549 
3550           raw_wx_string[MAX_RAW_WX_STRING] = '\0';    // Terminate it
3551 
3552           xastir_snprintf(weather->wx_time,
3553                           sizeof(weather->wx_time),
3554                           "%s",
3555                           get_time(time_data));
3556 
3557           weather->wx_sec_time=sec_now();
3558           //weather->wx_data=1;
3559           wx_fill_data(0,APRS_WX3,wx_line,p_station);
3560           decoded=1;
3561         }
3562         else if (((wx_line[0]=='#') || (wx_line[0]=='*'))
3563                  && is_xnum_or_dash((char *)(wx_line+1),13)
3564                  && port_data[port].data_type==0)
3565         {
3566 
3567           /* Found Peet Bros raw U2 data */
3568           xastir_snprintf(wx_station_type,
3569                           sizeof(wx_station_type),
3570                           "%s",
3571                           langcode("WXPUPSI012"));
3572 
3573           if (debug_level & 1)
3574           {
3575             fprintf(stderr,"Found Peet Bros raw U2 data WX#:%s\n",wx_line+1);
3576           }
3577 
3578           xastir_snprintf(raw_wx_string,
3579                           sizeof(raw_wx_string),
3580                           "%s",
3581                           wx_line);
3582 
3583           raw_wx_string[MAX_RAW_WX_STRING] = '\0'; // Terminate it
3584 
3585           xastir_snprintf(weather->wx_time,
3586                           sizeof(weather->wx_time),
3587                           "%s",
3588                           get_time(time_data));
3589           weather->wx_sec_time=sec_now();
3590           //weather->wx_data=1;
3591 
3592           if (wx_line[0]=='#')    // Wind speed in km/h
3593           {
3594             wx_fill_data(0,APRS_WX4,wx_line,p_station);
3595           }
3596           else               // '*', Wind speed in mph
3597           {
3598             wx_fill_data(0,APRS_WX6,wx_line,p_station);
3599           }
3600 
3601           decoded=1;
3602         }
3603         else if (strncmp("$ULTW",(char *)wx_line,5)==0
3604                  && is_xnum_or_dash((char *)(wx_line+5),44)
3605                  && port_data[port].data_type==0)
3606         {
3607 
3608           /* Found Peet Bros raw U2 data */
3609 
3610           xastir_snprintf(wx_station_type,
3611                           sizeof(wx_station_type),
3612                           "%s",
3613                           langcode("WXPUPSI013"));
3614 
3615           if (debug_level & 1)
3616           {
3617             fprintf(stderr,"Found Peet Bros Ultimeter Packet data WX#:%s\n",wx_line+5);
3618           }
3619 
3620           xastir_snprintf(raw_wx_string,
3621                           sizeof(raw_wx_string),
3622                           "%s",
3623                           wx_line);
3624           raw_wx_string[MAX_RAW_WX_STRING] = '\0'; // Terminate it
3625 
3626           weather->wx_sec_time=sec_now();
3627           //weather->wx_data=1;
3628           wx_fill_data(0,APRS_WX5,wx_line,p_station);
3629           decoded=1;
3630         }
3631         else if (wx_line[2]==' ' && wx_line[5]==' ' && wx_line[8]=='/' && wx_line[11]=='/'
3632                  && wx_line[14]==' ' && wx_line[17]==':' && wx_line[20]==':'
3633                  && strncmp(" #0:",(char *)wx_line+23,4)==0 && port_data[port].data_type==0)
3634         {
3635           find=0;
3636           for (i=len; i>23 && !find; i--)
3637           {
3638             if ((int)wx_line[i]==0x03)
3639             {
3640               find=1;
3641               wx_line[i] = 0;
3642             }
3643           }
3644           if (find)
3645           {
3646 
3647             /* found Qualimetrics Q-Net station */
3648 
3649             xastir_snprintf(wx_station_type,
3650                             sizeof(wx_station_type),
3651                             "%s",
3652                             langcode("WXPUPSI016"));
3653 
3654             if (debug_level & 1)
3655             {
3656               fprintf(stderr,"Found Qualimetrics Q-Net station data WX#:%s\n",wx_line+23);
3657             }
3658 
3659             xastir_snprintf(weather->wx_time,
3660                             sizeof(weather->wx_time),
3661                             "%s",
3662                             get_time(time_data));
3663             weather->wx_sec_time=sec_now();
3664             //weather->wx_data=1;
3665             wx_fill_data(0,QM_WX,wx_line+24,p_station);
3666             decoded=1;
3667           }
3668         }
3669 
3670 //WE7U
3671         // else look for ten ASCII decimal point chars in the input, or do an
3672         // sscanf looking for the correct number and types of fields for the
3673         // OWW server in ARNE mode.  6 %f's, 2 %d's, 11 %f's.
3674         else if (sscanf((const char *)wx_line,"%f %f %f %f %f %f %d %d %f %f %f %f %f %f %f %f %f %f %f", &t1,&t2,&t3,&t4,&t5,&t6,&t7,&t8,&t9,&t10,&t11,&t12,&t13,&t14,&t15,&t16,&t17,&t18,&t19) == 19)
3675         {
3676 
3677           // Found Dallas One-Wire Weather Station
3678           if (debug_level & 1)
3679           {
3680             fprintf(stderr,"Found OWW ARNE-mode(19) one-wire weather station data\n");
3681           }
3682 
3683           weather->wx_sec_time=sec_now();
3684           wx_fill_data(0,DALLAS_ONE_WIRE,wx_line,p_station);
3685           decoded=1;
3686         }
3687 
3688         else if (sscanf((const char *)wx_line,"%f %f %f %f %f %f %d %d %f %f %f %f", &t1,&t2,&t3,&t4,&t5,&t6,&t7,&t8,&t9,&t10,&t11,&t12) == 12)
3689         {
3690 
3691           // Found Dallas One-Wire Weather Station
3692           if (debug_level & 1)
3693           {
3694             fprintf(stderr,"Found OWW ARNE-mode(12) one-wire weather station data\n");
3695           }
3696 
3697           weather->wx_sec_time=sec_now();
3698           wx_fill_data(0,DALLAS_ONE_WIRE,wx_line,p_station);
3699           decoded=1;
3700         }
3701 
3702         else if (strncmp("&CR&",(char *)wx_line,4)==0
3703                  && is_xnum_or_dash((char *)(wx_line+5),44)
3704                  && port_data[port].data_type==0)
3705         {
3706 
3707           if (debug_level & 1)
3708           {
3709             fprintf(stderr,"Found Peet Complete station data\n");
3710           }
3711 
3712           xastir_snprintf(wx_station_type,
3713                           sizeof(wx_station_type),
3714                           "%s",
3715                           langcode("WXPUPSI017"));
3716 
3717           xastir_snprintf(raw_wx_string,
3718                           sizeof(raw_wx_string),
3719                           "%s",
3720                           wx_line);
3721 
3722           raw_wx_string[MAX_RAW_WX_STRING] = '\0'; // Terminate it
3723 
3724           weather->wx_sec_time=sec_now();
3725           //weather->wx_data=1;
3726           wx_fill_data(0,PEET_COMPLETE,wx_line,p_station);
3727           decoded=1;
3728         }
3729 
3730         else if (port_data[port].data_type==1)
3731         {
3732 //                    int jj;
3733 
3734           /* binary data type */
3735           if (debug_level & 1)
3736           {
3737             fprintf(stderr,"Found binary data:  %d bytes\n", len);
3738           }
3739 
3740           /* clear raw string */
3741           memset(raw_wx_string,0,sizeof(raw_wx_string));
3742           max=0;
3743           switch (wx_line[0])
3744           {
3745             case 0x8f:
3746               max=34;
3747               break;
3748 
3749             case 0x9f:
3750               max=33;
3751               break;
3752 
3753             case 0xaf:
3754               max=30;
3755               break;
3756 
3757             case 0xbf:
3758               max=13;
3759               break;
3760 
3761             case 0xcf:
3762               max=26;
3763               break;
3764 
3765             default:
3766               break;
3767           }
3768 
3769 //                    fprintf(stderr, "wx_decode binary: ");
3770 //                    for (jj = 0; jj < len+1; jj++) {
3771 //                        fprintf(stderr, "%02x ", wx_line[jj]);
3772 //                    }
3773 //                    fprintf(stderr, "\n");
3774 //                    fprintf(stderr, "Integers: ");
3775 //                    for (jj = 0; jj < max+1; jj++) {
3776 //                        fprintf(stderr, "%0d ", wx_line[jj]);
3777 //                    }
3778 //                    fprintf(stderr, "\n");
3779 
3780 
3781           if (len < (max+1))
3782           {
3783             fprintf(stderr, " Short NET_WX packet, %d bytes\n", len);
3784           }
3785 
3786           if (max > 0 && len >= (max+1) )
3787           {
3788 
3789             // Compute the checksum from the data
3790             check_sum = 0;
3791 
3792             for (i = 0; i < max; i++)
3793             {
3794               check_sum += wx_line[i];
3795             }
3796 //                        fprintf(stderr," Checksum: 0x%02x ", 0x0ff & check_sum);
3797 
3798             if ( wx_line[max] == (0xff & check_sum) )
3799             {
3800 
3801               /* good RS WX-200 data */
3802               //fprintf(stderr,"GOOD RS WX-200 %0X data\n",wx_line[0]);
3803               /* found RS WX-200 */
3804               xastir_snprintf(wx_station_type,
3805                               sizeof(wx_station_type),
3806                               "%s",
3807                               langcode("WXPUPSI025"));
3808               xastir_snprintf(weather->wx_time,
3809                               sizeof(weather->wx_time),
3810                               "%s",
3811                               get_time(time_data));
3812               weather->wx_sec_time=sec_now();
3813               //weather->wx_data=1;
3814               wx_fill_data(0,RSWX200,wx_line,p_station);
3815               decoded=1;
3816             }
3817             else
3818             {
3819 //                            fprintf(stderr, "bad");
3820             }
3821           }
3822         }
3823         else if (wx_line[0]=='@' && strncmp((char *)&(wx_line[63]),".DsVP",5)==0)
3824         {
3825           // this is a Davis Vantage Pro with APRS Data Logger
3826           if (debug_level & 1)
3827           {
3828             fprintf(stdout,"Davis VP APRS Data Logger data found ... %s\n", wx_line);
3829           }
3830           xastir_snprintf(wx_station_type,
3831                           sizeof(wx_station_type),
3832                           "%s",
3833                           langcode("WXPUPSI028"));
3834 
3835           xastir_snprintf(weather->wx_time,
3836                           sizeof(weather->wx_time),
3837                           "%s",
3838                           get_time(time_data));
3839           weather->wx_sec_time=sec_now();
3840           wx_fill_data(0,DAVISAPRSDL,wx_line,p_station);
3841           decoded=1;
3842         }
3843         else      // ASCII data of undetermined type
3844         {
3845 
3846           // Davis Weather via meteo -> db2APRS -> TCP port
3847 
3848           if (strstr((const char *)wx_line, "xDvs"))    // APRS 'postionless' WX data w/ Davis & X tag
3849           {
3850 
3851             if (debug_level & 1)
3852             {
3853               fprintf(stdout,"Davis Data found... %s\n",wx_line);
3854             }
3855 
3856             xastir_snprintf(wx_station_type,
3857                             sizeof(wx_station_type),
3858                             "%s",
3859                             langcode("WXPUPSI026"));
3860             xastir_snprintf(weather->wx_time,
3861                             sizeof(weather->wx_time),
3862                             "%s",
3863                             get_time(time_data));
3864             weather->wx_sec_time=sec_now();
3865             wx_fill_data(0,DAVISMETEO,wx_line,p_station);
3866             decoded=1;
3867           }
3868 
3869           else if (debug_level & 1)
3870           {
3871             fprintf(stderr,"Unknown WX DATA:%s\n",wx_line);
3872           }
3873         }
3874 
3875         if (decoded)
3876         {
3877           /* save data back */
3878 
3879           if (begin_critical_section(&port_data_lock, "wx.c:wx_decode(1)" ) > 0)
3880           {
3881             fprintf(stderr,"port_data_lock, Port = %d\n", port);
3882           }
3883 
3884           port_data[port].decode_errors=0;
3885 
3886           if (end_critical_section(&port_data_lock, "wx.c:wx_decode(2)" ) > 0)
3887           {
3888             fprintf(stderr,"port_data_lock, Port = %d\n", port);
3889           }
3890 
3891           statusline(langcode("BBARSTA032"),1);       // Decoded WX Data
3892           /* redraw now */
3893           //redraw_on_new_data=2;
3894           redraw_on_new_data=1;
3895           fill_wx_data();
3896         }
3897         else
3898         {
3899           /* Undecoded packet */
3900           memset(raw_wx_string,0,sizeof(raw_wx_string));
3901 
3902           if (begin_critical_section(&port_data_lock, "wx.c:wx_decode(3)" ) > 0)
3903           {
3904             fprintf(stderr,"port_data_lock, Port = %d\n", port);
3905           }
3906 
3907           port_data[port].decode_errors++;    // We have errors in decoding
3908           if (port_data[port].decode_errors>10)
3909           {
3910             /* wrong data type? */
3911             port_data[port].data_type++;    // Try another data type. 0=ascii, 1=wx binary
3912             port_data[port].data_type&=0x01;
3913             /*if (debug_level & 1)*/
3914             fprintf(stderr,"Data type %d\n",port_data[port].data_type);
3915             port_data[port].decode_errors=0;
3916           }
3917 
3918           if (end_critical_section(&port_data_lock, "wx.c:wx_decode(4)" ) > 0)
3919           {
3920             fprintf(stderr,"port_data_lock, Port = %d\n", port);
3921           }
3922 
3923         }
3924       }
3925     }
3926   }
3927 }
3928 
3929 
3930 
3931 
3932 
3933 /***********************************************************/
3934 /* fill string with WX data for transmit                   */
3935 /*                            */
3936 /***********************************************************/
3937 
wx_tx_data1(char * st,int st_size)3938 time_t wx_tx_data1(char *st, int st_size)
3939 {
3940   DataRow *p_station;
3941   time_t wx_time;
3942   char temp[100];
3943   WeatherRow *weather;
3944 
3945   st[0] = '\0';
3946   wx_time = 0;
3947   if (search_station_name(&p_station,my_callsign,1))
3948   {
3949     if (get_weather_record(p_station))      // station has wx data
3950     {
3951       weather = p_station->weather_data;
3952 
3953 
3954 //WE7U: For debugging purposes only
3955 //weather->wx_sec_time=sec_now();
3956 //sprintf(weather->wx_course,"359");          // degrees
3957 //sprintf(weather->wx_speed,"001");           // mph
3958 //sprintf(weather->wx_gust,"010");            // mph
3959 //sprintf(weather->wx_temp,"069");            // Farenheit
3960 
3961 //if ( strlen(weather->wx_rain_total) == 0)
3962 //    sprintf(weather->wx_rain_total,"1900.40");
3963 
3964 //sprintf(weather->wx_rain_total,"1987.6");   // hundredths of an inch
3965 //compute_rain(atof(weather->wx_rain_total));
3966 //sprintf(weather->wx_rain_total,"1988.6");
3967 //compute_rain(atof(weather->wx_rain_total));
3968 //sprintf(weather->wx_rain_total,"1990.6");
3969 
3970 //compute_rain(atof(weather->wx_rain_total));
3971 //sprintf(weather->wx_rain,"%0.2f",rain_minute_total);
3972 //sprintf(weather->wx_prec_24,"%0.2f",rain_24);
3973 //sprintf(weather->wx_prec_00,"%0.2f",rain_00);
3974 
3975 //sprintf(weather->wx_rain,"0");            // hundredths of an inch
3976 //sprintf(weather->wx_prec_00,"0");         // hundredths of an inch
3977 //sprintf(weather->wx_prec_24,"0");         // hundredths of an inch
3978 
3979 //sprintf(weather->wx_hum,"92");              // %
3980 //sprintf(weather->wx_baro,"1013.0");         // hPa
3981 //weather->wx_type = WX_TYPE;
3982 //xastir_snprintf(weather->wx_station,sizeof(weather->wx_station),"RSW");
3983 //  359/000g000t065r010P020p030h92b01000
3984 
3985 
3986       if (strlen(weather->wx_course) > 0 && strlen(weather->wx_speed) > 0)
3987       {
3988         // We have enough wx_data
3989         wx_time=weather->wx_sec_time;
3990         xastir_snprintf(temp,
3991                         sizeof(temp),
3992                         "%s",
3993                         weather->wx_course);
3994         if (strlen(temp) > 3)
3995         {
3996           if (debug_level & 1)
3997           {
3998             fprintf(stderr,"wx_course too long: %s\n", temp);
3999           }
4000           xastir_snprintf(temp,
4001                           sizeof(temp),
4002                           "...");
4003         }
4004         if ( (atoi(weather->wx_course) > 360) || (atoi(weather->wx_course) < 0) )
4005         {
4006           if (debug_level & 1)
4007           {
4008             fprintf(stderr,"wx_course out-of-range: %s\n", weather->wx_course);
4009           }
4010           xastir_snprintf(temp,
4011                           sizeof(temp),
4012                           "...");
4013         }
4014         //sprintf(st,"%s/%s",weather->wx_course,weather->wx_speed);
4015         strncat(st, temp, st_size - 1 - strlen(st));
4016         strncat(st, "/", st_size - 1 - strlen(st));
4017 
4018         xastir_snprintf(temp,
4019                         sizeof(temp),
4020                         "%s",
4021                         weather->wx_speed);
4022         if (strlen(temp) > 3)
4023         {
4024           if (debug_level & 1)
4025           {
4026             fprintf(stderr,"wx_speed too long: %s\n", temp);
4027           }
4028           xastir_snprintf(temp,
4029                           sizeof(temp),
4030                           "...");
4031         }
4032         if ( (atoi(weather->wx_speed) < 0) || (atoi(weather->wx_speed) > 999) )
4033         {
4034           if (debug_level & 1)
4035           {
4036             fprintf(stderr,"wx_speed out-of-range: %s\n", weather->wx_speed);
4037           }
4038           xastir_snprintf(temp,
4039                           sizeof(temp),
4040                           "...");
4041         }
4042         strncat(st, temp, st_size - 1 - strlen(st));
4043       }
4044       else
4045       {
4046         // We don't have enough wx_data, may be from a Qualimetrics Q-Net?
4047         wx_time=weather->wx_sec_time;
4048         xastir_snprintf(st,
4049                         st_size,
4050                         ".../...");
4051 
4052 
4053         if (debug_level & 1)
4054         {
4055           fprintf(stderr,"\n\nAt least one field was empty: Course: %s\tSpeed: %s\n", weather->wx_course, weather->wx_speed);
4056           fprintf(stderr,"Will be sending '.../...' instead of real values.\n\n\n");
4057         }
4058 
4059 
4060       }
4061       if (strlen(weather->wx_gust) > 0)
4062       {
4063         xastir_snprintf(temp,
4064                         sizeof(temp),
4065                         "g%s",
4066                         weather->wx_gust);
4067         if (strlen(temp) > 4)
4068         {
4069           if (debug_level & 1)
4070           {
4071             fprintf(stderr,"wx_gust too long: %s\n", temp);
4072           }
4073 
4074           xastir_snprintf(temp,
4075                           sizeof(temp),
4076                           "g...");
4077         }
4078         if (atoi(weather->wx_gust) < 0)
4079         {
4080           if (debug_level & 1)
4081           {
4082             fprintf(stderr,"wx_gust out-of-range: %s\n", weather->wx_gust);
4083           }
4084 
4085           xastir_snprintf(temp,
4086                           sizeof(temp),
4087                           "g...");
4088         }
4089         strncat(st, temp, st_size - 1 - strlen(st));
4090       }
4091       else
4092       {
4093         strncat(st, "g...", st_size - 1 - strlen(st));
4094       }
4095 
4096       if (strlen(weather->wx_temp) > 0)
4097       {
4098         xastir_snprintf(temp,
4099                         sizeof(temp),
4100                         "t%s",
4101                         weather->wx_temp);
4102         if (strlen(temp) > 4)
4103         {
4104           if (debug_level & 1)
4105           {
4106             fprintf(stderr,"wx_temp too long: %s\n", temp);
4107           }
4108 
4109           xastir_snprintf(temp,
4110                           sizeof(temp),
4111                           "t...");
4112         }
4113         if ( (atoi(weather->wx_temp) > 999) || (atoi(weather->wx_temp) < -99) )
4114         {
4115           if (debug_level & 1)
4116           {
4117             fprintf(stderr,"wx_temp out-of-bounds: %s\n", weather->wx_temp);
4118           }
4119 
4120           xastir_snprintf(temp,
4121                           sizeof(temp),
4122                           "t...");
4123         }
4124         strncat(st, temp, st_size - 1 - strlen(st));
4125       }
4126       else
4127       {
4128         strncat(st, "t...", st_size - 1 - strlen(st));
4129       }
4130 
4131       if (strlen(weather->wx_rain) > 0)
4132       {
4133         xastir_snprintf(temp,
4134                         sizeof(temp),
4135                         "r%03d",
4136                         (int)(atof(weather->wx_rain) + 0.5) );  // Cheater's way of rounding
4137         if (strlen(temp)>4)
4138         {
4139           if (debug_level & 1)
4140           {
4141             fprintf(stderr,"wx_rain too long: %s\n", temp);
4142           }
4143 
4144           // Don't transmit this field if it's not valid
4145           xastir_snprintf(temp,
4146                           sizeof(temp),
4147                           "r   ");
4148         }
4149         if (atoi(weather->wx_rain) < 0)
4150         {
4151           if (debug_level & 1)
4152           {
4153             fprintf(stderr,"wx_rain out-of-bounds: %s\n", weather->wx_rain);
4154           }
4155 
4156           // Don't transmit this field if it's not valid
4157           xastir_snprintf(temp,
4158                           sizeof(temp),
4159                           "r...");
4160         }
4161         strncat(st, temp, st_size - 1 - strlen(st));
4162       }
4163       else
4164       {
4165         // Don't transmit this field if it's not valid
4166         //strncat(st, "r...", st_size - 1 - strlen(st));
4167       }
4168 
4169       if (strlen(weather->wx_prec_00) > 0)
4170       {
4171         xastir_snprintf(temp,
4172                         sizeof(temp),
4173                         "P%03d",
4174                         (int)(atof(weather->wx_prec_00) + 0.5) );   // Cheater's way of rounding
4175         if (strlen(temp)>4)
4176         {
4177           if (debug_level & 1)
4178           {
4179             fprintf(stderr,"wx_prec_00 too long: %s\n", temp);
4180           }
4181 
4182           // Don't transmit this field if it's not valid
4183           xastir_snprintf(temp,
4184                           sizeof(temp),
4185                           "P   ");
4186         }
4187         if (atoi(weather->wx_prec_00) < 0)
4188         {
4189           if (debug_level & 1)
4190           {
4191             fprintf(stderr,"wx_prec_00 out-of-bounds: %s\n", weather->wx_prec_00);
4192           }
4193 
4194           // Don't transmit this field if it's not valid
4195           xastir_snprintf(temp,
4196                           sizeof(temp),
4197                           "P...");
4198         }
4199         strncat(st, temp, st_size - 1 - strlen(st));
4200       }
4201       else
4202       {
4203         // Don't transmit this field if it's not valid
4204         //strncat(st, "P...", st_size - 1 - strlen(st));
4205       }
4206 
4207       if (strlen(weather->wx_prec_24) > 0)
4208       {
4209         xastir_snprintf(temp,
4210                         sizeof(temp),
4211                         "p%03d",
4212                         (int)(atof(weather->wx_prec_24) + 0.5) );   // Cheater's way of rounding
4213         if (strlen(temp)>4)
4214         {
4215           if (debug_level & 1)
4216           {
4217             fprintf(stderr,"wx_prec_24 too long: %s\n", temp);
4218           }
4219 
4220           // Don't transmit this field if it's not valid
4221           xastir_snprintf(temp,
4222                           sizeof(temp),
4223                           "p   ");
4224         }
4225         if (atoi(weather->wx_prec_24) < 0)
4226         {
4227           if (debug_level & 1)
4228           {
4229             fprintf(stderr,"wx_prec_24 out-of-bounds: %s\n", weather->wx_prec_24);
4230           }
4231 
4232           // Don't transmit this field if it's not valid
4233           xastir_snprintf(temp,
4234                           sizeof(temp),
4235                           "p...");
4236         }
4237         strncat(st, temp, st_size - 1 - strlen(st));
4238       }
4239       else
4240       {
4241         // Don't transmit this field if it's not valid
4242         //strncat(st, "p...", st_size - 1 - strlen(st));
4243       }
4244 
4245       if (strlen(weather->wx_hum) > 0)
4246       {
4247         if (atoi(weather->wx_hum)>99)
4248         {
4249           xastir_snprintf(temp,
4250                           sizeof(temp),
4251                           "h00");
4252         }
4253         else
4254           xastir_snprintf(temp,
4255                           sizeof(temp),
4256                           "h%02d",
4257                           atoi(weather->wx_hum));
4258 
4259         if (strlen(temp) > 4)
4260         {
4261           if (debug_level & 1)
4262           {
4263             fprintf(stderr,"wx_hum too long: %s\n", temp);
4264           }
4265 
4266           // Don't transmit this field if it's not valid
4267           //xastir_snprintf(temp,sizeof(temp),"h..");
4268         }
4269         if (atoi(weather->wx_hum) < 0)
4270         {
4271           if (debug_level & 1)
4272           {
4273             fprintf(stderr,"wx_hum out-of-bounds: %s\n", weather->wx_hum);
4274           }
4275           // Don't transmit this field if it's not valid
4276           //xastir_snprintf(temp,sizeof(temp),"h..");
4277         }
4278         strncat(st, temp, st_size - 1 - strlen(st));
4279       }
4280       else
4281       {
4282         // Don't transmit this field if it's not valid
4283         //strncat(st, "h..", st_size - 1 - strlen(st));
4284       }
4285 
4286       if (strlen(weather->wx_baro) > 0)
4287       {
4288         xastir_snprintf(temp,
4289                         sizeof(temp),
4290                         "b%05d",
4291                         (int)((atof(weather->wx_baro) * 10.0)) );
4292         if (strlen(temp)>6)
4293         {
4294           if (debug_level & 1)
4295           {
4296             fprintf(stderr,"wx_baro too long: %s\n", temp);
4297           }
4298           // Don't transmit this field if it's not valid
4299           //xastir_snprintf(temp,sizeof(temp),"b.....");
4300         }
4301         if ((int)((atof(weather->wx_baro) * 10.0) < 0))
4302         {
4303           if (debug_level & 1)
4304           {
4305             fprintf(stderr,"wx_baro out-of-bounds: %s\n", weather->wx_baro);
4306           }
4307           // Don't transmit this field if it's not valid
4308           //xastir_snprintf(temp,sizeof(temp),"b.....");
4309         }
4310         strncat(st, temp, st_size - 1 - strlen(st));
4311       }
4312       else
4313       {
4314         // Don't transmit this field if it's not valid
4315         //strncat(st, "b.....", st_size - 1 - strlen(st));
4316       }
4317 
4318       xastir_snprintf(temp,
4319                       sizeof(temp),
4320                       "%c%s",
4321                       weather->wx_type,
4322                       weather->wx_station);
4323       strncat(st, temp, st_size - 1 - strlen(st));
4324     }
4325   }
4326 
4327 
4328   if (debug_level & 1)
4329   {
4330     fprintf(stderr,"Weather String:  %s\n", st);
4331   }
4332 
4333 
4334   return(wx_time);
4335 }
4336 
4337 
4338 
4339 
4340 
4341 /***********************************************************/
4342 /* transmit raw wx data                                    */
4343 /*                                                         */
4344 /***********************************************************/
tx_raw_wx_data(void)4345 void tx_raw_wx_data(void)
4346 {
4347 
4348   if (strlen(raw_wx_string)>10)
4349   {
4350     output_my_data(raw_wx_string,-1,0,0,0,NULL);
4351     if (debug_level & 1)
4352     {
4353       fprintf(stderr,"Sending Raw WX data <%s>\n",raw_wx_string);
4354     }
4355   }
4356 }
4357 
4358 
4359