source: trunk/src/data_sources/k2ew/k2misc.c @ 3206

Revision 3206, 53.4 KB checked in by paulf, 12 years ago (diff)

version 2.43 which improves modem handling for new kmi firmware on k2 instruments

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 *   THIS FILE IS UNDER RCS - DO NOT MODIFY UNLESS YOU HAVE
3 *   CHECKED IT OUT USING THE COMMAND CHECKOUT.
4 *
5 *    $Id$
6 *
7 *    Revision history:
8 *     $Log$
9 *     Revision 1.31  2007/12/18 13:36:03  paulf
10 *     version 2.43 which improves modem handling for new kmi firmware on k2 instruments
11 *
12 *     Revision 1.30  2007/02/26 17:16:53  paulf
13 *     made sure time_t are casted to long for heartbeat sprintf()
14 *
15 *     Revision 1.29  2005/07/27 19:28:49  friberg
16 *     2.40 changes for ForceBlockMode and comm stats
17 *
18 *     Revision 1.28  2005/03/26 00:17:46  kohler
19 *     Version 2.38.  Added capability to get network code values from the K2
20 *     headers.  The "Network" parameter in the config file is now optional.
21 *     WMK 3/25/05
22 *
23 *     Revision 1.27  2004/06/04 16:36:04  lombard
24 *     Fixed parts of extended status message.
25 *
26 *     Revision 1.26  2003/07/17 19:23:27  friberg
27 *     Fixed a status message to include network and station name for the k2
28 *     from which the error originated.
29 *
30 *     Revision 1.25  2003/06/06 01:24:33  lombard
31 *     Changed to version 2.34: fix for byte alignment problem in extended status
32 *     structure.
33 *
34 *     Revision 1.24  2003/05/29 13:33:40  friberg
35 *     Added in calls to k2info and fixed GPS status message to include
36 *     the station name. Changed all status messages to include
37 *     network code in addition to station name
38 *
39 *     Revision 1.23  2003/05/15 00:41:47  lombard
40 *     *** empty log message ***
41 *
42 *     Revision 1.22  2002/05/06 18:24:58  kohler
43 *     Fixed typo in log statement in function k2mi_init_blkmde().
44 *
45 *     Revision 1.21  2002/04/22 16:35:55  lucky
46 *     k2ew was being restarted by startstop because it would stop beating its
47 *     heart when re-trying to connect. Made it so that we continue to beat our
48 *     heart even when we go through the retry loop several times.
49 *
50 *     Revision 1.20  2002/01/30 14:28:31  friberg
51 *     added robust comm recovery for time out case
52 *
53 *     Revision 1.19  2001/10/19 18:21:28  kohler
54 *     k2mi_log_pktinfo() now sends msg to statmgr if a pcdrv error occurs.
55 *
56 *     Revision 1.18  2001/10/16 22:03:56  friberg
57 *     Upgraded to version 2.25
58 *
59 *     Revision 1.17  2001/08/08 16:11:48  lucky
60 *     version 2.23
61 *
62 *     Revision 1.15  2001/05/23 00:20:00  kohler
63 *     Now, optionally writes entire K2 header to a binary file.
64 *
65 *     Revision 1.14  2001/05/08 00:14:38  kohler
66 *     Minor logging changes.
67 *
68 *     Revision 1.13  2001/04/23 20:24:10  friberg
69 *     Added station name remapping using the StationId config parameter.
70 *
71 *     Revision 1.12  2000/11/28 00:45:46  kohler
72 *     Cosmetic changes to log file output.
73 *
74 *     Revision 1.11  2000/11/07 19:35:01  kohler
75 *     Modified to complain if no GPS lock for xx hours.
76 *
77 *     Revision 1.10  2000/08/30 17:34:00  lombard
78 *     See ChangeLog entry for 30 August 2000
79 *
80 *     Revision 1.9  2000/07/28 22:36:10  lombard
81 *     Moved heartbeats to separate thread; added DontQuick command; removed
82 *     redo_com() since it doesn't do any good; other minor bug fixes
83 *
84 *     Revision 1.8  2000/07/03 18:00:37  lombard
85 *     Added code to limit age of waiting packets; stops circ buffer overflows
86 *     Added and Deleted some config params.
87 *     Added check of K2 station name against restart file station name.
88 *     See ChangeLog for complete list.
89 *
90 *     Revision 1.7  2000/06/18 20:17:46  lombard
91 *     transport calls for status and hearbteats was inproperly commented out.
92 *
93 *     Revision 1.6  2000/06/09 23:14:23  lombard
94 *     Several bug fixes and improvements; See Changelog entry of 2000-06-09.
95 *
96 *     Revision 1.5  2000/05/17 15:12:42  lombard
97 *     bug fix in ping_test
98 *
99 *     Revision 1.4  2000/05/16 23:39:16  lombard
100 *     bug fixes, removed OutputThread Keepalive, added OnBattery alarm
101 *     made alarms report only once per occurence
102 *
103 *     Revision 1.3  2000/05/12 19:02:19  lombard
104 *     fixed g_stnid typo
105 *
106 *     Revision 1.2  2000/05/12 04:04:05  lombard
107 *     Fixed conversion of disk space units
108 *
109 *     Revision 1.1  2000/05/04 23:48:20  lombard
110 *     Initial revision
111 *
112 *
113 *
114 */
115/*  k2misc.c:  Miscellaneous functions for K2:            */
116/*      init_blkmde, ping_test, get_status, get_params    */
117/*                                                        */
118/*    1/1/99 -- [ET]  File started                        */
119/*                                                        */
120
121#include <stdio.h>
122#include <stdlib.h>
123#include <string.h>
124#include <earthworm.h>
125#include <time.h>
126#include "byteswap.h"
127#include "glbvars.h"
128#include "k2pktdef.h"        /* K2 packet definitions and types */
129#include "k2ewerrs.h"        /* K2-to-Earthworm error codes */
130#include "k2comif.h"         /* K2 COM port interface routines */
131#include "k2pktio.h"         /* K2 packet send/receive routines */
132#include "k2pktman.h"        /* K2 packet management functions */
133#include "k2misc.h"          /* header file for this module */
134#include "terminat.h"        /* for status/termination codes */
135#include "k2info.h"          /* for info packet injection codes */
136
137#define K2MI_INIT_TOUTMS  5000     /* packet timeout during init */
138#define K2MI_PING_TOUTMS  1000     /* receive ping timeout in ms */
139#define K2MI_PARM_TOUTMS  1000     /* receive params timeout in ms */
140#define K2MI_TRAN_TOUTMS  500      /* transmission timeout */
141#define K2MI_FLSH_SHORT   100      /* short flush interval in ms */
142#define K2MI_FLSH_LONG    500      /* long flush interval in ms */
143#define K2MI_MONMODE_MAX  9        /* number of times to try mon-mode cmd */
144#define K2MI_BLKMODE_MAX  6        /* number of times to try block-mode cmd */
145#define K2MI_PKT_SRCNUM   44       /* arbitrary packet source # for file */
146
147/* buffer size for 'k2mi_init_blkmde()' fn: */
148#define K2MI_IBFSIZ ((PACKET_MAX_SIZE-11)/5)
149
150#define MAX_MSG_SIZE      256       /* Large enough for all faults in extended
151                                       status message */
152static char msg[MAX_MSG_SIZE];      /* Buffer for text messages */
153
154static struct PACKET_HDR g_k2mi_hdrblk;          /* received header buffer */
155static unsigned char g_k2mi_buff[PACKET_MAX_SIZE-9]; /* received data buffer */
156static int rep_on_batt = 0, rep_low_batt = 0, rep_hwstat = 0;
157static int rep_temp, rep_disk[2] = {0,0};
158
159/**************************************************************************
160 * k2mi_init_blkmde:  verifies communications with K2 unit. If K2 is      *
161 *       already in block mode, then return. Otherwise, try to establish  *
162 *       communications with the K2                                       *
163 *       Sockets are never retried on timeouts                            *
164 *         *pseqnum - address of sequence number for sent command packet  *
165 *                    which will be incremented                           *
166 *      return value:  K2R_POSITIVE if K2 is already sending stream data  *
167 *                     K2R_NO_ERROR K2 has been switched to block mode    *
168 *                     K2R_ERROR if an error occurred                     *
169 *                     K2R_TIMEOUT if a timeout occured while             *
170 *                         communicating with K2                          *
171 **************************************************************************/
172
173int k2mi_init_blkmde(unsigned char *pseqnum)
174{
175  int blkmde_count = K2MI_BLKMODE_MAX;
176  int monmde_count = K2MI_MONMODE_MAX;
177  int idx, dcnt, slen, rc1, rc2;
178  static const char *monmde_str_arr[]={          /* monitor-mode strings */
179                                 "\\\\\\\\\r", "\r","\\\\\\\r","\\","\r\\\\\\\\\r","\r\\\\\\\\\r", "\r\\\\\\\\\\\r", "\n\r\n\r", "\r\n", "\n\r\n\r\r"};
180  static const char blkmde_str[]="BLOCK\r";      /* block-mode command string */
181
182  idx = 0;                  /* initialize monitor-mode string array index */
183
184
185  do     /* loop while attempting to activate and confirm K2 block mode */
186  {
187        /* Tell heartbeat thread we're happy */
188          g_mt_working = 1;
189
190
191    if (gcfg_debug > 3)
192      logit("e", "flushing...");
193    if (k2c_flush_recv(K2MI_FLSH_SHORT) != K2R_NO_ERROR)
194      return K2R_ERROR;
195    if (gcfg_debug > 3)
196      logit("e", "done\n");
197
198    /* check if data is coming in and if it's valid packets */
199    if ( (rc1 = k2c_rcvflg_tout(K2MI_FLSH_LONG)) == K2R_ERROR)
200    {
201      return rc1;
202    }
203    else if (rc1 == K2R_NO_ERROR )
204    {         /* Data ready to be read */
205      if ( (rc2 = k2pm_recv_wstmpkt(&g_k2mi_hdrblk, g_k2mi_buff,
206                                    gcfg_commtimeout_itvl, 0)) == K2R_POSITIVE)
207      {
208        if (gcfg_debug > 3)
209          logit("e", "k2mi_init_blkmde: stream packet ret on try %d\n",
210                blkmde_count - K2MI_BLKMODE_MAX);
211        return K2R_POSITIVE;   /* Found K2 already streaming in block mode */
212
213      }
214      else if (rc2 == K2R_ERROR)
215        return rc2;
216    }
217
218    /* no valid packets coming in */
219    /* check if K2-ping can be sent and received */
220    if ( (rc1 = k2mi_ping_test(1, pseqnum)) == K2R_NO_ERROR)
221      return rc1;                   /* ping returned OK, comms are up */
222    else if (rc1 == K2R_ERROR)
223      return rc1;                   /* comm error; give up */
224
225    monmde_count = K2MI_MONMODE_MAX;
226    do
227    {    /* loop while attempting to activate and confirm K2 monitor mode */
228
229          /* Tell heartbeat thread we're happy */
230          g_mt_working = 1;
231
232      /* send a monitor-mode string */
233      if ( (slen = strlen(monmde_str_arr[idx])) == 1)
234      {
235        /* if '\' (or '\r') then delay a bit before */
236        if ( (rc1 = k2c_flush_recv(K2MI_FLSH_LONG)) == K2R_ERROR)
237          return rc1;
238      }
239
240      if (gcfg_debug > 2)
241        logit("e", "sending MM %d\n", idx);
242
243      if ( (rc1 = k2c_tran_buff((const unsigned char *)(monmde_str_arr[idx]),
244                                slen, gcfg_commtimeout_itvl, 0)) != slen)
245        return rc1;     /* if error transmitting then return */
246
247      /* increment index into monitor-mode string array */
248      if(++idx >= (sizeof(monmde_str_arr)/sizeof(monmde_str_arr[0])))
249        idx = 0;             /* if past end-of-array then wrap around to beg */
250
251      /* wait a bit for (possible) data to appear */
252      /*  (wait a bit longer if '\' (or '\r') command) */
253      if ( (rc1 = k2c_rcvflg_tout( ((slen==1)?K2MI_FLSH_LONG:K2MI_FLSH_SHORT)))
254           == K2R_ERROR)
255        return rc1;
256
257      /* save any data returned from K2 */
258      if ( (dcnt = k2c_recv_buff(g_k2mi_buff, K2MI_IBFSIZ,
259                                 gcfg_commtimeout_itvl, 0)) > 0)
260      {       /* data was received */
261        /* Tell heartbeat thread we're happy */
262        g_mt_working = 1;
263
264        g_k2mi_buff[dcnt] = '\0';           /* NULL terminate buffer */
265        if (gcfg_debug > 2)
266          logit("e", "received:  %d bytes '%s'\n", dcnt, g_k2mi_buff);
267
268        /* check if returned data contains monitor-mode prompt ('*') */
269        if ( strchr((char *)g_k2mi_buff, (int)'*') != NULL)
270          break;             /* if monitor-mode prompt ('*') then exit loop */
271      }
272      else if (dcnt == K2R_ERROR)
273        return dcnt;
274    }
275    while(--monmde_count);         /* loop if count not expired */
276    /* Now we should be in monitor mode, unless monmde_count expired */
277
278    /* send block-mode command string */
279    slen = strlen(blkmde_str);
280    if (gcfg_debug > 2)
281      logit("e", "%s\n",blkmde_str);
282
283    if ( (rc1 = k2c_tran_buff((unsigned char *)blkmde_str, slen,
284                                          gcfg_commtimeout_itvl,0)) != slen)
285    {    /* error transmitting; return code */
286      return (rc1 < 0) ? rc1 : K2R_ERROR;   /* only use code if negative */
287                                            /* 1/29/2002 -- [ET] */
288    }
289    if ( (rc1 = k2c_flush_recv(K2MI_FLSH_SHORT)) == K2R_ERROR)
290      return rc1;
291  }
292  while (--blkmde_count);           /* loop if count not expired */
293  logit("et", "k2mi_init_blkmde: failed to put k2 in block mode\n");
294  return K2R_ERROR;
295}
296
297/* returns -1 if str not found anywhere in buf, or position of first char of str */
298char * find_string_(char* buf, char * str, int buf_len) 
299{
300int i;
301int len_of_str;
302char *cptr;
303
304len_of_str= strlen(str);
305for (i=0; i< buf_len-len_of_str; i++) {
306   if ( (cptr=strstr(&buf[i], str)) != NULL) {
307      logit("et", "find_string_(): located string %s\n", cptr);
308      return cptr;
309   }
310}
311logit("et", "find_string_(): no %s in buffer\n", str);
312return NULL;
313}
314
315/* returns -1 if MODEM not in buf, or position of first char of MODEM string if found
316        This was written because the raw data stream could have 0s in it which would
317        nullify the strstr test! */
318char * find_MODEM(char * buf, int len) {
319
320char modem_str[]="MODEM";
321
322     return find_string_(buf, modem_str, len);
323}
324char * find_PROMPT(char * buf, int len) {
325char prompt_line_str[] = "\r * ";
326
327     return find_string_(buf, prompt_line_str, len);
328}
329
330
331
332static int block_mode_started = 1;
333
334/**************************************************************************
335 * k2mi_force_blkmde:  forces communications with K2 unit into BLOCK mode.*
336 *       Sockets are never retried on timeouts                            *
337 *      return value:  K2R_POSITIVE has been switched to block mode       *
338 *                     K2R_ERROR if an error occurred                     *
339 *                     K2R_TIMEOUT if a timeout occured while             *
340 *                         communicating with K2                          *
341 **************************************************************************/
342int k2mi_force_blkmde()
343{
344  int blkmde_count = K2MI_BLKMODE_MAX;
345  int monmde_count = K2MI_MONMODE_MAX;
346  int idx, dcnt, slen, rc1, rc2;
347  static const char *monmde_str_arr[]={          /* monitor-mode strings */
348                                 "\n\r\n\r", "\r\n", "\n\r\n\r\r", "\\\\\\\\\r","\\\\\\\r","\\\\\\\\\r","\r\\\\\\\\\r","\n\r\n\r", "\r\n\\\\\\\\\r\r\n", "\\\\\\\\\r\n\r\\\\\\\\\r\n\r\r"};
349  static const char blkmde_str[]="BLOCK\r";      /* block-mode command string */
350  static const char ansmde_str[]="ANSWERMODE\r";      /* answermode command string */
351
352  char *cptr;
353
354  int local_timeout_ms = 250;
355  int prompt_flag=0;
356
357  idx = 0;                  /* initialize monitor-mode string array index */
358
359
360  do     /* loop while attempting to activate and confirm K2 block mode */
361  {
362    /* Tell heartbeat thread we're happy */
363    g_mt_working = 1;
364
365#ifdef FLUSH_IT
366    if (gcfg_debug > 2)
367      logit("et", "k2mi_force_blkmde: flushing recv buffer...");
368    if (k2c_flush_recv(K2MI_FLSH_SHORT) != K2R_NO_ERROR)
369      return K2R_ERROR;
370    if (gcfg_debug > 2)
371      logit("e", "done\n");
372#endif
373
374    monmde_count = K2MI_MONMODE_MAX;
375    do
376    {    /* loop while attempting to activate and confirm K2 monitor mode */
377
378      /* Tell heartbeat thread we're happy */
379      g_mt_working = 1;
380
381      /* send a monitor-mode string */
382
383#ifdef FLUSH_IT
384      if ( (slen = strlen(monmde_str_arr[idx])) == 1)
385      {
386        /* if '\' (or '\r') then delay a bit before */
387        if ( (rc1 = k2c_flush_recv(K2MI_FLSH_LONG)) == K2R_ERROR)
388          return rc1;
389      }
390#endif
391
392      if (gcfg_debug > 2)
393        logit("et", "k2mi_force_blkmde: sending MM %d - string '%s'\n", idx, monmde_str_arr[idx]);
394
395      if ( (rc1 = k2c_tran_buff((const unsigned char *)(monmde_str_arr[idx]),
396                                slen, local_timeout_ms, 0)) != slen)
397        return rc1;     /* if error transmitting then return */
398
399      /* increment index into monitor-mode string array */
400      if(++idx >= (sizeof(monmde_str_arr)/sizeof(monmde_str_arr[0])))
401        idx = 0;             /* if past end-of-array then wrap around to beg */
402
403#ifdef FLUSH_IT
404      /* wait a bit for (possible) data to appear */
405      /*  (wait a bit longer if '\' (or '\r') command) */
406      if ( (rc1 = k2c_rcvflg_tout( ((slen==1)?K2MI_FLSH_LONG:K2MI_FLSH_SHORT)))
407           == K2R_ERROR)
408        return rc1;
409#endif
410
411      /* save any data returned from K2 - make sure not to redo socket conn */
412      if ( (dcnt = k2c_recv_buff(g_k2mi_buff, K2MI_IBFSIZ,
413                                 local_timeout_ms, 0)) > 0)
414      {       /* data was received */
415        /* Tell heartbeat thread we're happy */
416        g_mt_working = 1;
417
418        g_k2mi_buff[dcnt] = '\0';           /* NULL terminate buffer */
419        if (gcfg_debug > 2)
420          logit("et", "k2mi_force_blkmde: received:  %d bytes '%s'\n", dcnt, g_k2mi_buff);
421
422        /* check if returned data contains modem command and its active,
423                actual string provided by Dennis Pumphrey of KMI 2007-05-29 */
424        cptr = find_MODEM((char *)g_k2mi_buff, dcnt);
425
426        if (cptr == NULL && idx==3) {
427          logit("et", "k2mi_force_blkmde: No MODEM strings upon \\r, so assuming BLOCK mode.\n");
428          return K2R_POSITIVE;
429        }
430
431        if (cptr != NULL && strstr((char*) cptr, "MODEM in control and active") != NULL) {
432          if (gcfg_debug > 2)
433            logit("et", "k2mi_force_blkmde: modem in control! not forcing block mode.\n");
434          /* for now, just exit and let the modem do its thing till its done */
435          return K2R_ERROR; 
436          /* later we need to check a config setting if modems should be allowed to take precedent */
437        }
438        if (cptr != NULL && strstr((char*) cptr, "MODEM in control and inactive") != NULL) {
439          if (gcfg_debug > 2)
440            logit("et", "k2mi_force_blkmde: modem in control! but inactive, try forcing block mode.\n");
441            idx=4;
442        }
443
444        /* check if returned data contains monitor-mode prompt ('*') */
445        if ( strchr((char *)g_k2mi_buff, (int)'*') != NULL || find_PROMPT((char *)g_k2mi_buff,dcnt)!=NULL) { 
446          if (gcfg_debug > 2)
447            logit("et", "k2mi_force_blkmde: received:  command prompt\n");
448          prompt_flag=1;
449          break;             /* if monitor-mode prompt ('*') then exit loop */
450        }
451      }
452      else if (dcnt == K2R_ERROR)
453        return dcnt;
454      else if (gcfg_debug>2)
455          logit("et", "k2mi_force_blkmde: received:  %d bytes  after timeout of %d ms'\n", dcnt, local_timeout_ms);
456    }
457    while(--monmde_count);         /* loop if count not expired */
458 
459    /* for tests to see if sending BLOCK at the end works, fire it in regardless of prompt 2007.12.05 */
460    prompt_flag=1;  /* paulf 2007.12.05 */
461    /* Now we should be in monitor mode, unless monmde_count expired */
462    if (block_mode_started && prompt_flag) {
463      unsigned char seqnum = 0;
464      /* send block-mode command string */
465      slen = strlen(blkmde_str);
466      if (gcfg_debug > 2)
467        logit("et", "k2mi_force_blkmde: sending %s\n",blkmde_str);
468
469      if ( (rc1 = k2c_tran_buff((unsigned char *)blkmde_str, slen,
470                                          local_timeout_ms,0)) != slen)
471      {    /* error transmitting; return code */
472        return (rc1 < 0) ? rc1 : K2R_ERROR;   /* only use code if negative */
473                                            /* 1/29/2002 -- [ET] */
474      }
475      return K2R_POSITIVE; /* added 2007-11-07 to kick back faster for CGS firmware */
476
477      /* new send start of streaming here for kicks */
478      logit("et", "k2mi_force_blkmde: sent %s, now sending START_STREAM command\n",blkmde_str);
479
480      rc1 = k2pm_send_strctrl(K2SCC_START_STREAM, &seqnum, 0);
481
482      block_mode_started++;  /* this is for when we alternated testing, could be removed 2007.12.05 */
483    } 
484    if (!prompt_flag) {
485      logit("et", "k2mi_init_blkmde: no command prompt received, failed to go into block mode\n");
486      return K2R_ERROR;
487    }
488    if ( (rc1 = k2c_flush_recv(K2MI_FLSH_SHORT)) == K2R_ERROR)
489      return rc1;
490    if (rc1 == 0) return K2R_POSITIVE;
491  }
492  while (--blkmde_count);           /* loop if count not expired */
493  logit("et", "k2mi_init_blkmde: failed to put k2 in block mode\n");
494  return K2R_ERROR;
495}
496
497
498/**************************************************************************
499 * k2mi_ping_test:  executes ping test on K2                              *
500 *        Sockets are never retried on timeout                            *
501 *         count    - number of pings to send and confirm                 *
502 *         *pseqnum - address of sequence number for sent command packet  *
503 *                    which will be incremented                           *
504 *      return value:  returns K2R_NO_ERROR if `count' pings returned;    *
505 *                     returns K2R_ERROR on error or K2R_TIMEOUT          *
506 **************************************************************************/
507
508int k2mi_ping_test(int count, unsigned char *pseqnum)
509{
510  int rc, slen;
511  static const char ping_test_data[]=
512                               "K2 ping test data \\\\\xC0\xC0\\1234567890";
513
514  if (gcfg_debug > 2)
515    logit("e", "ping test\n");
516
517  /* check receive and flush any waiting data */
518  if (gcfg_debug > 3)
519    logit("e", "flushing...");
520  if ( (rc = k2c_flush_recv(0)) != K2R_NO_ERROR)
521    return rc;
522  if (gcfg_debug > 3)
523    logit("e", "done\n");
524
525  while(1)    /* loop for each ping send/receive test */
526  {           /* send ping packet */
527    slen = strlen(ping_test_data);       /* get string length */
528    if (gcfg_debug > 3)
529      logit("e", "sending ping\n");
530    if ( (rc = k2p_send_packet((unsigned char)PKC_PING, *pseqnum,
531                               K2MI_PKT_SRCNUM, slen,
532                               (unsigned char *)ping_test_data, 0))
533         != K2R_NO_ERROR)
534      break;                 /* if error then exit loop */
535
536    /* wait for expected response packet (ignore SDS auto-packets) */
537    if ( (rc = k2pm_recv_waitpkt(PKR_PING, *pseqnum, K2MI_PKT_SRCNUM,
538                                 &g_k2mi_hdrblk, g_k2mi_buff, PKR_STRDATA,
539                                 gcfg_commtimeout_itvl, 0)) != K2R_POSITIVE)
540    {
541      if (rc == K2R_NO_ERROR)  /* something returned, but not a packet */
542        rc = K2R_TIMEOUT;      /* call it a timeout */
543      break;
544    }
545    if (rc == K2R_POSITIVE)  /* packet returned */
546      rc = K2R_NO_ERROR;     /* switch return value to current convention */
547
548    /* check packet data */
549    if(g_k2mi_hdrblk.dataLength != slen ||
550       strncmp((char *)g_k2mi_buff, ping_test_data, (size_t)slen) != 0)
551    {    /* packet data mismatch */
552      rc = K2R_ERROR;            /* setup error code */
553      logit("et", "k2mi_ping_test: ping data mismatch\n");
554      break;                           /* exit loop */
555    }
556    if(--count <= 0)              /* decrement count */
557      break;                      /* if done then exit loop */
558    ++(*pseqnum);                 /* increment sequence number */
559  }
560  ++(*pseqnum);         /* increment sequence number */
561  if (gcfg_debug > 2)
562    logit("e", "k2mi_ping_test returning %d\n", rc);
563
564  return rc;            /* return OK code */
565}
566
567/**************************************************************************
568 * k2mi_get_params:  fetches general K2 parameters (note that none of     *
569 *      the numeric multi-byte entries are byte-swapped by this function) *
570 *      Never does communication retries.                                 *
571 *         pk2hdr  - address of header block to receive parameter data    *
572 *         *pseqnum - address of sequence number for sent command packet  *
573 *                    which will be incremented                           *
574 *      return value:  returns K2R_POSITIVE on return of param packet     *
575 *                     K2R_NO_ERROR if no fatal errors occured but param  *
576 *                       packet didn't come back;                         *
577 *                     K2R_ERROR on fatal errors; K2R_TIMEOUT on timeout  *
578 **************************************************************************/
579
580int k2mi_get_params(K2_HEADER *pk2hdr, unsigned char *pseqnum)
581{
582  int rc;
583  size_t to_copy;
584
585#ifdef DEBUG
586  if(pk2hdr == NULL)              /* if NULL pointer then */
587  {
588    logit("et", "k2mi_get_params: NULL paramter pk2hdr\n");
589    return K2R_ERROR;
590  }
591#endif
592
593  /* check receive and flush any waiting data */
594  if ( (rc = k2c_flush_recv(0)) != K2R_NO_ERROR)
595    return rc;
596
597  /* send get-K2-parameters command packet */
598  if ( (rc = k2p_send_packet((unsigned char)PKC_GETPARMS, *pseqnum,
599                             K2MI_PKT_SRCNUM, (unsigned short)0,
600                             NULL, 0)) == K2R_NO_ERROR)
601  {      /* send OK; wait for expected response packet (ignore message pkts) */
602    if ( (rc = k2pm_recv_waitpkt((unsigned char)PKR_PARMS, *pseqnum,
603                                 K2MI_PKT_SRCNUM, &g_k2mi_hdrblk,
604                                 g_k2mi_buff, (unsigned char)PKC_MSG,
605                                 gcfg_commtimeout_itvl, 0)) == K2R_POSITIVE)
606    {         /* 'parameters' packet received OK */
607      if (g_k2mi_hdrblk.dataLength == (unsigned short)K2_HEAD_SIZE)
608      {       /* packet size OK */
609        memset(pk2hdr, 0, sizeof(*pk2hdr));
610        /* copy data into K2 parameters header block to be returned */
611        /*  (copy smaller of # of bytes received or struct size) */
612        to_copy = (sizeof(*pk2hdr) < K2_HEAD_SIZE) ?
613          sizeof(*pk2hdr) : K2_HEAD_SIZE;
614        memcpy(pk2hdr, g_k2mi_buff, to_copy);
615      }
616      else    /* unexpected packet size */
617      {
618        logit("et", "k2mi_get_params: wrong sized packet returned from K2\n");
619        return K2R_NO_ERROR;
620      }
621    }
622  }
623  ++(*pseqnum);         /* increment sequence number */
624  return rc;            /* return code */
625}
626
627
628/**************************************************************************
629 * k2mi_get_status:  fetches K2 status block (note that none of the       *
630 *      numeric multi-byte entries are byte-swapped by this function)     *
631 *         pk2stat  - address of STATUS_INFO block to receive status data *
632 *         *pseqnum - address of sequence number for sent command packet  *
633 *                    which will be incremented                           *
634 *      return value:  returns K2R_POSITIVE on return of status packet;   *
635 *                     K2R_NO_ERROR if no fatal errors occured but status *
636 *                       packet didn't return;                            *
637 *                     K2R_ERROR on fatal errors; K2R_TIMEOUT on timeout  *
638 **************************************************************************/
639
640int k2mi_get_status(struct STATUS_INFO *pk2stat, unsigned char *pseqnum)
641{
642  int rc;
643  size_t to_copy;
644
645#ifdef DEBUG
646  if (pk2stat == NULL)             /* if NULL pointer then */
647  {
648    logit("et", "k2mi_get_status: NULL paramter pk2stat\n");
649    return K2R_ERROR;
650  }
651#endif
652
653  /* check receive and flush any waiting data */
654  if ( (rc = k2c_flush_recv(0)) != K2R_NO_ERROR)
655    return rc;
656
657  /* send get-K2-status command packet */
658  if ( (rc = k2p_send_packet((unsigned char)PKC_GETSTATUS, *pseqnum,
659                             K2MI_PKT_SRCNUM, (unsigned short)0,
660                             NULL, 0)) == K2R_NO_ERROR)
661  {      /* send OK; wait for expected response packet (ignore none) */
662    if ( (rc = k2pm_recv_waitpkt((unsigned char)PKR_STATUS, *pseqnum,
663                                 K2MI_PKT_SRCNUM, &g_k2mi_hdrblk,
664                                 g_k2mi_buff, (unsigned char)K2PM_IGNR_NONE,
665                                 gcfg_commtimeout_itvl, 0)) == K2R_POSITIVE)
666    {         /* 'parameters' packet received OK */
667      if (g_k2mi_hdrblk.dataLength == (unsigned short)STATUS_SIZE)
668      {       /* packet size OK */
669        memset(pk2stat, 0, sizeof(*pk2stat));
670        /* copy data into K2 parameters status block to be returned */
671        /*  (copy smaller of # of bytes received or struct size) */
672        to_copy = (sizeof(*pk2stat) < STATUS_SIZE) ?
673          sizeof(*pk2stat) : STATUS_SIZE;
674        memcpy(pk2stat, g_k2mi_buff, to_copy);
675      }
676      else    /* unexpected packet size */
677      {
678        logit("et", "k2mi_get_status: wrong sized packet returned from K2\n");
679        return K2R_NO_ERROR;
680      }
681    }
682  }
683  ++(*pseqnum);         /* increment sequence number */
684  return rc;            /* return code */
685}
686
687/**************************************************************************
688 * k2mi_get_extstatus:  fetches K2 extended status block (note that none  *
689 *      of the numeric multi-byte entries are byte-swapped by this        *
690 *      function)                                                         *
691 *         pk2stat  - address of EXT_STATUS_INFO block to receive         *
692 *         *pseqnum - address of sequence number for sent command packet  *
693 *                    which will be incremented                           *
694 *      return value:  returns K2R_POSITIVE on return of status packet;   *
695 *                     K2R_NO_ERROR if no fatal errors occured but status *
696 *                       packet didn't return;                            *
697 *                     K2R_ERROR on fatal errors; K2R_TIMEOUT on timeout  *
698 **************************************************************************/
699
700int k2mi_get_extstatus(struct EXT2_STATUS_INFO *pk2stat, unsigned char *pseqnum,
701                       int *pext_size)
702{
703  int rc;
704  size_t to_copy;
705
706#ifdef DEBUG
707  if (pk2stat == NULL)             /* if NULL pointer then */
708  {
709    logit("et", "k2mi_get_extstatus: NULL paramter pk2stat\n");
710    return K2R_ERROR;
711  }
712#endif
713
714  /* check receive and flush any waiting data */
715  if ( (rc = k2c_flush_recv(0)) != K2R_NO_ERROR)
716    return rc;
717
718  /* send get-K2-status command packet */
719  if ( (rc = k2p_send_packet((unsigned char)PKC_EXTSTATUS, *pseqnum,
720                             K2MI_PKT_SRCNUM, (unsigned short)0,
721                             NULL,0)) == K2R_NO_ERROR)
722  {      /* send OK; wait for expected response packet (ignore none) */
723    if ( (rc = k2pm_recv_waitpkt((unsigned char)PKR_EXTSTATUS, *pseqnum,
724                                 K2MI_PKT_SRCNUM, &g_k2mi_hdrblk,
725                                 g_k2mi_buff, (unsigned char)K2PM_IGNR_NONE,
726                                 gcfg_commtimeout_itvl, 0)) == K2R_POSITIVE)
727    {         /* 'parameters' packet received OK */
728      if (g_k2mi_hdrblk.dataLength == (unsigned short)EXT_SIZE)
729      {       /* packet size OK */
730        memset(pk2stat, 0, sizeof(*pk2stat));
731        /* copy data into K2 parameters status block to be returned */
732        /*  (copy smaller of # of bytes received or struct size) */
733        to_copy = (sizeof(*pk2stat) < EXT_SIZE) ? sizeof(*pk2stat) : EXT_SIZE;
734        memcpy(pk2stat, g_k2mi_buff, to_copy);
735        *pext_size = EXT_SIZE;
736      }
737      else if (g_k2mi_hdrblk.dataLength == (unsigned short)EXT2_SIZE)
738      {
739          memset(pk2stat, 0, sizeof(*pk2stat));
740          /* copy data into K2 parameters status block to be returned */
741          /*  (copy smaller of # of bytes received or struct size) */
742          to_copy = (sizeof(*pk2stat) < EXT2_SIZE) ? sizeof(*pk2stat) : EXT2_SIZE;
743          memcpy(pk2stat, g_k2mi_buff, to_copy);
744          *pext_size = EXT2_SIZE;
745      }
746    else    /* unexpected packet size */
747      {
748        logit("et","k2mi_get_extstatus: wrong sized packet returned from"
749              " K2 (was %d, should be %d or %d)\n",
750              (int)(g_k2mi_hdrblk.dataLength),EXT_SIZE, EXT2_SIZE);
751        *pext_size = 0;
752        return K2R_NO_ERROR;
753      }
754    }
755  }
756  ++(*pseqnum);         /* increment sequence number */
757  return rc;            /* return code */
758}
759
760/**************************************************************************
761 * k2mi_req_status:  requests K2 status block                             *
762 *         *pseqnum - address of sequence number for sent command packet  *
763 *                    which will be incremented                           *
764 *      return value:  returns K2R_NO_ERROR if request is transmitted     *
765 *                     K2R_ERROR on fatal errors; K2R_TIMEOUT on timeout  *
766 **************************************************************************/
767
768int k2mi_req_status(unsigned char *pseqnum)
769{
770  int rc;
771
772  /* send get-K2-status command packet */
773  rc = k2p_send_packet((unsigned char)PKC_GETSTATUS, *pseqnum,
774                       K2MI_PKT_SRCNUM, (unsigned short)0,
775                       NULL,1);
776  ++(*pseqnum);         /* increment sequence number */
777  return rc;            /* return code */
778}
779
780/**************************************************************************
781 * k2mi_req_extstatus:  requests K2 extended status block                 *
782 *         *pseqnum - address of sequence number for sent command packet  *
783 *                    which will be incremented                           *
784 *      return value:  returns K2R_NO_ERROR if request is transmitted     *
785 *                     K2R_ERROR on fatal errors; K2R_TIMEOUT on timeout  *
786 **************************************************************************/
787
788int k2mi_req_extstatus(unsigned char *pseqnum)
789{
790  int rc;
791
792  /* send get-K2-status command packet */
793  rc = k2p_send_packet((unsigned char)PKC_EXTSTATUS, *pseqnum,
794                       K2MI_PKT_SRCNUM, (unsigned short)0,
795                       NULL,1);
796  ++(*pseqnum);         /* increment sequence number */
797  return rc;            /* return code */
798}
799
800
801/**************************************************************************
802 * k2mi_req_params:  requests K2 paramter block                            *
803 *         *pseqnum - address of sequence number for sent command packet  *
804 *                    which will be incremented                           *
805 *      return value:  returns K2R_NO_ERROR if request is transmitted     *
806 *                     K2R_ERROR on fatal errors; K2R_TIMEOUT on timeout  *
807 **************************************************************************/
808
809int k2mi_req_params(unsigned char *pseqnum)
810{
811  int rc;
812
813  /* send get-K2-params command packet */
814  rc = k2p_send_packet((unsigned char)PKC_GETPARMS, *pseqnum,
815                       K2MI_PKT_SRCNUM, (unsigned short)0,
816                       NULL,1);
817  ++(*pseqnum);         /* increment sequence number */
818  return rc;            /* return code */
819}
820
821
822/**************************************************************************
823 * k2mi_log_pktinfo:  logs information about given packet                 *
824 *         phdrblk  - address of header block for packet                  *
825 *         databuff - address of data buffer for packet                   *
826 **************************************************************************/
827
828void k2mi_log_pktinfo(struct PACKET_HDR *phdrblk, unsigned char *databuff)
829{
830  int slen, index;
831  unsigned long alarm, chanmask = 0x00000001;
832
833  switch(phdrblk->typeCode)
834  {      /* process packet based on type-code */
835  case PKC_MSG:            /* system message packet from K2 */
836    /* Ignore these messages */
837    if (strncmp((char *)databuff, "CAUTION: Acquisition is ON", 26) == 0)
838       break;
839
840    /* Log the message string (if not too long) */
841    logit("et","K2 message received: %s\n",
842          (strlen((char *)databuff) < PACKET_MAX_SIZE-11) ?
843          (char *)databuff: "<unterminated-string>");
844
845    /* If flash memory error is detected, send msg to statmgr */
846    /* Added in version 2.26 by W Kohler, added station name to message in 2.35  */
847    if ( strncmp((char *)databuff, "pcdrv_raw_read, error", 21) == 0 ) 
848    {
849       sprintf(msg, "K2 <%s>: pcdrv_raw_read error (bad flash memory)",
850                g_stnid);
851       k2mi_status_hb(g_error_ltype, K2STAT_BAD_DISK, msg);
852    }
853    if ( strncmp((char *)databuff, "pcdrv_raw_write, error", 22) == 0 )
854    {
855       sprintf(msg, "K2 <%s>: pcdrv_raw_write error (bad flash memory)",
856                g_stnid);
857       k2mi_status_hb(g_error_ltype, K2STAT_BAD_DISK, msg);
858    }
859    break;
860  case PKC_SETALARM:       /* alarm message from K2 */
861    /* display alarm as 32-bit int (if length OK) */
862    if(phdrblk->dataLength == (unsigned short)4)
863    {
864      sprintf(msg, "K2 alarm received for channels: ");
865      slen = strlen(msg);
866      alarm = BYTESWAP_UINT32(((struct K2_ALARM*)databuff)->channelBitMap);
867      for (index = 0; index < ABS_MAX_CHANNELS; index++)
868      {
869        if (alarm & chanmask)
870        {
871          sprintf(&msg[slen], "%d ", index + 1);
872          slen = strlen(msg);
873        }
874        chanmask = chanmask << 1L;
875      }
876      logit("et","%s\n", msg);
877    }
878    else
879      logit("et","K2 alarm: <unexpected data-length>\n");
880    break;
881  case PKR_STRDATA:        /* serial data stream auto packet */
882  case PKR_STRRQDATA:      /* serial data stream requested packet */
883    if ( gcfg_debug > 0 )
884       logit("et","Unexpected SDS (%s) packet, "
885             "seq-num=%hu, src-num=%hu, data-len=%hu\n",
886             ((phdrblk->typeCode == (unsigned char)PKR_STRDATA) ?
887             "PKR_STRDATA" : "PKR_STRRQDATA"),
888             (unsigned short)(phdrblk->seqNo), phdrblk->source,
889             phdrblk->dataLength);
890    break;
891  case PKR_STATUS:
892    if (phdrblk->dataLength == (unsigned short) STATUS_SIZE)
893      k2mi_report_status((struct STATUS_INFO *)databuff);
894    else
895      logit("et", "k2ew: abnormal length status packet received\n");
896    break;
897 case PKR_EXTSTATUS:
898    if (phdrblk->dataLength == (unsigned short)EXT_SIZE)
899      k2mi_report_extstatus((struct EXT2_STATUS_INFO *)databuff, EXT_SIZE);
900    else if (phdrblk->dataLength == (unsigned short)EXT2_SIZE)
901      k2mi_report_extstatus((struct EXT2_STATUS_INFO *)databuff, EXT2_SIZE);
902    else
903    {
904      logit("et", "k2ew: abnormal length extended status packet"
905            " received (%d)\n",(int)(phdrblk->dataLength));
906      if (phdrblk->dataLength == (unsigned short)(EXT_SIZE*2))
907      {  /* extended packet is new double-length size */
908        g_extstatus_avail = 0;    /* clear flag to stop future requests */
909        if(gcfg_debug > 0)
910        {     /* debug enabled; log message */
911          logit("et",
912                   "Extended status packets will no longer be requested\n");
913        }
914      }
915    }
916    break;
917  case PKR_PARMS:
918    if (phdrblk->dataLength == (unsigned short)K2_HEAD_SIZE)
919      k2mi_report_params((K2_HEADER *)databuff);
920    else
921      logit("et", "k2ew: abnormal length params packet received\n");
922    break;
923  case PKR_STRNAK:
924    logit("et", "K2 STR_NAK rcvd: %s\n",
925          k2pm_strnak_errcd(phdrblk, databuff, NULL));
926    break;
927  default:       /* unknown packet type-code, display message */
928    logit("et","Unexpected packet received, type-code=%02hXH, "
929          "seq-num=%hu, src-num=%hu, data-len=%hu\n",
930          (unsigned short)(phdrblk->typeCode),
931          (unsigned short)(phdrblk->seqNo),
932          phdrblk->source, phdrblk->dataLength);
933  }
934}
935
936/*****************************************************************
937 * k2mi_report_status: Report information form K2 status packet  *
938 *         pk2stat - pointer to K2 status structure              *
939 *****************************************************************/
940
941void k2mi_report_status( struct STATUS_INFO *pk2stat)
942{
943  time_t timevar;
944  unsigned short wtemp1, wtemp2;
945  char tempchar, disk[2] = {'A', 'B'};
946  int tempbat, index;
947  double batv, diskfree;
948  static char msg2[MAX_MSG_SIZE];      /* another buffer for text messages */
949
950  if (gcfg_inject_info==1)
951        k2info_send(K2INFO_TYPE_STATUS, (char *) pk2stat);
952  /* System time and clock source */
953  timevar = (time_t)(BYTESWAP_UINT32(pk2stat->systemTime) + K2_TIME_CONV);
954  sprintf(msg, "K2 Time = %s", asctime(gmtime(&timevar)));
955  msg[strlen(msg)-1] = '\0';         /* delete the newline left by ctime() */
956
957  switch (pk2stat->clockSource)
958  {
959  case 0:
960    strcat(msg, " set from RTC");
961    break;
962  case 1:
963    strcat(msg, " set from Keyboard");
964    break;
965  case 2:
966    strcat(msg, " set from External Pulse");
967    break;
968  case 3:
969    strcat(msg, " set from Internal GPS");
970    break;
971  default:
972    strcat(msg, " set from (?)");
973  }
974  logit("et","%s\n", msg);
975
976  /* Battery voltage and hardware status */
977  tempbat = (int) pk2stat->batteryStatus;   /* char, no need to swap */
978  batv = tempbat/10.0;
979  if (tempbat < 0)
980  {
981    batv = -batv;
982  }
983  if (tempbat > 0) /* K2 says battery voltage is zero when it is charging */
984  {
985    logit("et", "K2 HW Status = %s Battery Status: %0.1f V\n",
986          (pk2stat->hardwareStatus == (unsigned char)SF_OK)?"OK":"FAULT", batv);
987    if (gcfg_on_batt && rep_on_batt == 0)
988    {
989    sprintf(msg, "K2 <%s>: lost external power; battery voltage: %0.1f V", 
990                g_stnid, batv);
991    k2mi_status_hb(g_error_ltype, K2STAT_ON_BATT, msg);
992    rep_on_batt = 1;
993    }
994  }
995  else
996  {
997    logit("et", "K2 HW Status = %s Battery Status: charging\n",
998          (pk2stat->hardwareStatus == (unsigned char)SF_OK)?"OK":"FAULT");
999    if (rep_on_batt == 1 && gcfg_on_batt)
1000    {
1001    sprintf(msg, "K2 <%s>: external power restored", g_stnid);
1002    k2mi_status_hb(g_error_ltype, K2STAT_OFF_BATT, msg);
1003    rep_on_batt = 0;
1004    rep_low_batt = 0;
1005    }
1006  }
1007
1008  if (gcfg_battery_alarm > 0 && rep_low_batt == 0 && tempbat > 0
1009      && batv < 0.1 * gcfg_battery_alarm)
1010  {
1011    sprintf(msg, "K2 <%s>: low battery voltage: %0.1f V", 
1012                g_stnid, batv);
1013    k2mi_status_hb(g_error_ltype, K2STAT_LOW_BATT, msg);
1014    rep_low_batt = 1;
1015  }
1016  /* We assume battery voltage goes up only when external power is restored */
1017
1018  if (gcfg_hwstat_alarm && rep_hwstat == 0
1019      && pk2stat->hardwareStatus == (unsigned char) SF_FAULT)
1020  {
1021    sprintf(msg, "K2 <%s> hardware fault", g_stnid);
1022    k2mi_status_hb(g_error_ltype, K2STAT_HW_FAULT, msg);
1023    rep_hwstat = 1;
1024  }
1025  else if (gcfg_hwstat_alarm && rep_hwstat == 1)
1026  {
1027    sprintf(msg, "K2 <%s> hardware fault cleared", g_stnid);
1028    k2mi_status_hb(g_error_ltype, K2STAT_HWFLT_CLR, msg);
1029    rep_hwstat = 0;
1030  }
1031
1032  /* Event and recording error counts */
1033  logit("et", "Events: %hu Recording Errors: %hu\n",
1034        BYTESWAP_UINT16(pk2stat->events),
1035        BYTESWAP_UINT16(pk2stat->recordingErrors));
1036
1037  /* Trigger status */
1038  wtemp1 = BYTESWAP_UINT16(pk2stat->triggerStatus);
1039  sprintf(msg, "Acquisition: ");
1040  if (wtemp1 & 0x0001)
1041  {
1042    strcat(msg, "on (");
1043    if (((wtemp1 & 0x0002) == 0) &&
1044        ((wtemp1 & 0x0004) == 0) &&
1045        ((wtemp1 & 0x0010) == 0))
1046      strcat(msg, "not ");
1047    strcat(msg, "triggered);");
1048  }
1049  else
1050    strcat(msg, "off;");
1051
1052  strcat(msg, "  Alarm: ");
1053  if ((wtemp1 & 0x0008) == 0)
1054    strcat(msg, "not ");
1055  strcat(msg, "triggered.");
1056  logit("et", "%s\n", msg);
1057
1058  /* Disk drive status */
1059  strcpy(msg, "Drive:");
1060  for (index = 0; index < 2; index++)
1061  {
1062    sprintf(&msg[strlen(msg)], " %c: ", 'A' + index);
1063    wtemp1 = BYTESWAP_UINT16(pk2stat->driveStatus[index]);
1064    if (wtemp1 & SF_NOT_READY)
1065    {
1066      strcat(msg, "not ready");
1067      if ( gcfg_disk_alarm[index] > 0.0 && rep_disk[index] == 0)
1068      {
1069        sprintf(msg2, "K2 <%s>: disk %c failure", 
1070                g_stnid, disk[index]);
1071        k2mi_status_hb(g_error_ltype, K2STAT_BAD_DISK, msg2);
1072        rep_disk[index] = 1;
1073      }
1074    }
1075    else
1076    {
1077      if ((wtemp1 & SF_GB) == SF_GB)
1078      {
1079        tempchar = 'G';
1080        diskfree = 1073741824.0;   /* `giga' bytes */
1081      }
1082      else
1083      {
1084        if ((wtemp1 & SF_MB) == SF_MB)
1085        {
1086          tempchar = 'M';
1087          diskfree = 1048576.0;  /* `mega' bytes */
1088        }
1089        else
1090        {
1091          if ((wtemp1 & SF_KB) == SF_KB)
1092          {
1093            tempchar = 'K';
1094            diskfree = 1024.0;  /* `Kilo' bytes */
1095          }
1096        }
1097      }
1098      wtemp2 = wtemp1 & SF_FREE;
1099      diskfree *= (double)wtemp2;
1100      sprintf(&msg[strlen(msg)], "%d %cB FREE", wtemp2, tempchar);
1101
1102      if (gcfg_disk_alarm[index] > 0.0 && diskfree < gcfg_disk_alarm[index]
1103          && rep_disk[index] == 0)
1104      {
1105        sprintf(msg2, "K2 <%s>: low free space on disk A: %d %cB",
1106                g_stnid, wtemp2, tempchar);
1107        k2mi_status_hb(g_error_ltype, K2STAT_LOW_DISK, msg2);
1108        rep_disk[index] = 1;
1109      }
1110      else if (gcfg_disk_alarm[index] > 0.0 && rep_disk[index] == 1
1111               && diskfree >= gcfg_disk_alarm[index] )
1112      {   /* Disk is no longer full */
1113        sprintf(msg2, "K2 <%s>: disk space OK; A: %d %cB",
1114                g_stnid, wtemp2, tempchar);
1115        k2mi_status_hb(g_error_ltype, K2STAT_OK_DISK, msg2);
1116        rep_disk[index] = 0;
1117      }
1118    }
1119  }
1120  logit("et", "%s\n", msg);
1121}
1122
1123/*****************************************************************
1124 * k2mi_report_extstatus: Report information form K2 extended    *
1125 *             status packet                                     *
1126 *   It seems the K2 doesn't actually support this message, so   *
1127 *   don't expect this function to be used: PNL 8/22/00          *
1128 *   Since the data reported here is not included in the params  *
1129 *   structure, we keep this code around, just in case KMI gets  *
1130 *   ambitious and implements what they advertise; hah!          *
1131 *         pk2stat - pointer to K2 extended status structure     *
1132 *****************************************************************/
1133
1134void k2mi_report_extstatus( struct EXT2_STATUS_INFO *pk2stat, int ext_size)
1135{
1136  unsigned short us_dummy;
1137  unsigned long ul_dummy;
1138  unsigned short fault;
1139  time_t timevar;
1140  char msg[20];
1141 
1142  /* The extended status structure is not byte-aligned for Sparc or Intel *
1143   * hardware. So we have to copy out the bytes into dummy variables      *
1144   * before we can manipluate them. Thanks, kinemetrics!                  */
1145
1146  /* Last restart time */
1147  memcpy(&ul_dummy, ((char *)pk2stat) + 2, sizeof(long));
1148  timevar = (time_t)(BYTESWAP_UINT32(ul_dummy) + K2_TIME_CONV);
1149  switch (pk2stat->clockSource)
1150  {
1151  case 0:
1152    strcpy(msg, "RTC");
1153    break;
1154  case 1:
1155    strcpy(msg, "Keyboard");
1156    break;
1157  case 2:
1158    strcpy(msg, "External Pulse");
1159    break;
1160  case 3:
1161    strcpy(msg, "Internal GPS");
1162    break;
1163  default:
1164    strcpy(msg, "(?)");
1165  }
1166  logit("e", "K2 Extended Status Message: last restart: Time = %s set from %s\n",
1167        asctime(gmtime(&timevar)), msg);
1168
1169  /* Fault status */
1170  memcpy(&us_dummy, ((char *)pk2stat) + 6, sizeof(short));
1171  fault = BYTESWAP_UINT16(us_dummy);
1172  strcpy(msg, "K2 fault status: ");
1173  if (fault != (unsigned short)0)
1174  {
1175    if (fault & FAULT_SYSTEM)
1176      strcat(msg, "bad parameters; ");
1177    if (fault & FAULT_FLASH)
1178      strcat(msg, "flash error; ");
1179    if (fault & FAULT_RAM)
1180      sprintf(&msg[strlen(msg)], "ram error at %lX; ",
1181              BYTESWAP_UINT32(pk2stat->lastRAMError));
1182    if (fault & FAULT_PCMCIA)
1183      strcat(msg, "bad/missing PCMCIA; ");
1184    if (fault & FAULT_DSP)
1185      strcat(msg, "failed to load DSP; ");
1186    if (fault & FAULT_PARMBLK)
1187      strcat(msg, "param block CRC error; ");
1188    if (fault & FAULT_FLASH_MAINTENANCE)
1189      strcat(msg, "flash maintenance required;");
1190
1191    /* I assume that a fault here will also be reported by the HW fault bit
1192       in the status message, so we don't bother sending and earthworm status
1193       message here */
1194  }
1195  else
1196    strcat(msg, "OK");
1197
1198  logit("e", "%s\n", msg);
1199
1200  /* inject it if requested to */
1201  if (gcfg_inject_info==1 && ext_size==EXT_SIZE)
1202        k2info_send(K2INFO_TYPE_ESTATUS, (char *) pk2stat);
1203  else if (gcfg_inject_info==1 && ext_size==EXT2_SIZE)
1204        k2info_send(K2INFO_TYPE_E2STATUS, (char *) pk2stat);
1205
1206  if (ext_size == EXT_SIZE) return;
1207 
1208  /* Report additional information in the "extended" extended status packet */
1209
1210  return;
1211}
1212
1213
1214/*****************************************************************
1215 * k2mi_write_header: Write binary K2 header to disk file        *
1216 *         pk2hdr - pointer to K2 header structure               *
1217 *****************************************************************/
1218
1219static void k2mi_write_header( K2_HEADER *k2hdr )
1220{
1221   FILE *fp = fopen( gcfg_header_filename, "wb" );
1222   if ( fp == NULL )
1223   {
1224      logit( "e", "Can't open new K2 header file: <%s>\n", gcfg_header_filename );
1225      return;
1226   }
1227   if ( fwrite( k2hdr, sizeof(K2_HEADER), 1, fp ) < 1 )
1228   {
1229      logit( "e", "Error writing K2 header file: <%s>\n", gcfg_header_filename );
1230      fclose( fp );
1231      return;
1232   }
1233   fclose( fp );           /* All ok */
1234   if (gcfg_debug > 0)
1235      logit( "et", "K2 header file written: <%s>\n", gcfg_header_filename );
1236   return;
1237}
1238
1239
1240/*****************************************************************
1241 * k2mi_report_params: Report some information from K2 param     *
1242 *             packet: temperature and GPS                       *
1243 *         pk2hdr - pointer to K2 param structure                *
1244 *****************************************************************/
1245
1246void k2mi_report_params( K2_HEADER *pk2hdr)
1247{
1248  short batt_voltx10;
1249  double batv;
1250  short temp;
1251
1252/* Write K2 header to a disk file
1253   ******************************/
1254   if (gcfg_header_filename[0] != '\0')
1255      k2mi_write_header( pk2hdr );
1256
1257   if (gcfg_inject_info == 1)
1258        k2info_send(K2INFO_TYPE_HEADER, (char *) pk2hdr);
1259
1260/* System temperature
1261   ******************/
1262  temp = (short)BYTESWAP_UINT16(pk2hdr->roParms.misc.temperature);
1263  logit("et", "Temperature: %d.%1d deg C\n", temp / 10, temp % 10);
1264
1265  if ((int)temp < gcfg_templo_alarm && rep_temp == 0)
1266  {
1267    sprintf(msg, "K2 <%s>: low temperature: %d.%1d C", 
1268                g_stnid, temp / 10, temp % 10);
1269    k2mi_status_hb(g_error_ltype, K2STAT_LOW_TEMP, msg);
1270    rep_temp = 1;
1271  }
1272  else if ((int)temp > gcfg_temphi_alarm && rep_temp == 0)
1273  {
1274    sprintf(msg, "K2 <%s>: high temperature: %d.%1d C", 
1275                g_stnid, temp / 10, temp % 10);
1276    k2mi_status_hb(g_error_ltype, K2STAT_HIGH_TEMP, msg);
1277    rep_temp = 1;
1278  }
1279  else if (rep_temp == 1)
1280  {
1281    sprintf(msg, "K2 <%s>: temperature OK: %d.%1d C", 
1282                g_stnid, temp / 10, temp % 10);
1283    k2mi_status_hb(g_error_ltype, K2STAT_OK_TEMP, msg);
1284    rep_temp = 0;
1285  }
1286
1287/* Log the last GPS lock time and drift. If the GPS hasn't locked
1288   for gcfg_gpslock_alarm hours, send one message to statmgr.
1289   If and when the GPS locks up again, send another msg to statmgr.
1290   ***************************************************************/
1291   {
1292      const int year2000 = 946080000;   /* Jan 1, 2000 in seconds */
1293
1294      time_t now      = time(0);        /* PC clock time */
1295      time_t timevar1 = (time_t)(BYTESWAP_UINT32(pk2hdr->roParms.timing.gpsLastLockTime[0])
1296                         + K2_TIME_CONV);
1297      char *timestr1  = asctime(gmtime(&timevar1));
1298
1299      timestr1[strlen(timestr1)-1] = '\0';
1300      temp = (short)BYTESWAP_UINT32(pk2hdr->roParms.timing.gpsLastDrift[0]);
1301      logit("et", "Last GPS lock: %s  Drift: %d msec\n", timestr1, temp );
1302
1303      if ( (gcfg_gpslock_alarm >= 0.0) && (now > year2000) && (timevar1 > year2000) )
1304      {
1305         static int prev_gpslock  = 1;            /* Assume GPS was locked at startup */
1306         double timeSinceLastLock = (now - timevar1) / 3600.;
1307
1308         if ( timeSinceLastLock >= gcfg_gpslock_alarm )
1309         {
1310            logit( "et", "WARNING. GPS hasn't locked for %.1lf hours.\n", timeSinceLastLock );
1311            if ( prev_gpslock == 1 )
1312            {
1313               sprintf(msg, "K2 <%s>: No GPS lock for %.1lf hours.", 
1314                        g_stnid, timeSinceLastLock );
1315               k2mi_status_hb(g_error_ltype, K2STAT_GPSLOCK, msg);
1316            }
1317            prev_gpslock = 0;
1318         }
1319         else
1320         {
1321            if ( prev_gpslock == 0 ) 
1322            {
1323               sprintf(msg, "K2 <%s>: GPS lock acquired.", g_stnid);
1324               k2mi_status_hb(g_error_ltype, K2STAT_GPSLOCK, msg);
1325            }
1326            prev_gpslock = 1;
1327         }
1328      }
1329   }
1330
1331  /* Battery voltage is reported as negative when supplied from external *
1332   * source. That's what we need here; internal battery voltage is       *
1333   * reported in status block, above */
1334  batt_voltx10 = (signed short)BYTESWAP_UINT16(pk2hdr->roParms.misc.batteryVoltage);
1335
1336  if (batt_voltx10 < 0)
1337  {
1338    batt_voltx10 = -batt_voltx10;
1339    batv = batt_voltx10 / 10.0;
1340    logit("et", "External battery voltage: %0.1f V\n", batv);
1341  }
1342
1343  /* If k2ew used a restart file to read the station name
1344   * (g_validrestart_flag == 1), we must verify that name against
1345   * the K2's idea of station name. If they don't match, someone
1346   * must have used a non-unique restart-file name in the config file.
1347   * If k2ew continues, then the trace data will be labeled with the
1348   * wrong station name: Bad doodoo! */
1349  if (g_validrestart_flag == 1)
1350  {      /* restart file was used */
1351    if(strncmp(g_k2_stnid,pk2hdr->rwParms.misc.stnID,sizeof(g_k2_stnid)-1) != 0
1352                && strncmp(g_stnid,gcfg_stnid_remap,sizeof(g_stnid)-1) != 0)
1353    {         /* original station name and remapped name do not match */
1354      logit("et","k2ew: MAJOR ERROR: K2 station name <%s> does not match "
1355                 "station name <%s>\n"
1356                 "\tfrom restart file (\"%s\"); Terminating!\n",
1357              pk2hdr->rwParms.misc.stnID,g_k2_stnid, gcfg_restart_filename);
1358      g_terminate_flg = 1;        /* set program terminate flag */
1359
1360    }
1361    else      /* name matches OK */
1362      g_validrestart_flag = 2;    /* so we don't do this test again */
1363  }
1364}
1365
1366
1367/*************************************************************
1368 * k2mi_status_hb: sends heartbeat or status messages to     *
1369 *         earthworm transport ring.                         *
1370 *       type: the message type: heartbeat or status         *
1371 *       code: the error code for status messages            *
1372 *       message: message text, if any                       *
1373 *************************************************************/
1374
1375void k2mi_status_hb(unsigned char type, short code, char* message )
1376{
1377  char          outMsg[MAX_MSG_SIZE];  /* The outgoing message.        */
1378  time_t        msgTime;        /* Time of the message.                 */
1379
1380  /*  Get the time of the message                                       */
1381  time( &msgTime );
1382
1383  /*  Build & process the message based on the type                     */
1384  if ( g_heartbeat_logo.type == type )
1385  {
1386    sprintf( outMsg, "%ld %ld\n\0", (long) msgTime, (long) g_pidval );
1387
1388    /*Write the message to the output region                            */
1389    if ( tport_putmsg( &g_tport_region, &g_heartbeat_logo,
1390                       (long) strlen( outMsg ), outMsg ) != PUT_OK )
1391    {
1392      /*     Log an error message                                       */
1393      logit( "et", "k2ew: Failed to send a heartbeat message (%d).\n",
1394             code );
1395    }
1396  }
1397  else
1398  {
1399    if ( message )
1400    {
1401      sprintf( outMsg, "%ld %hd %s\n\0", (long) msgTime, code, message );
1402      logit("et","Error:%d (%s)\n", code, message );
1403    }
1404    else
1405    {
1406      sprintf( outMsg, "%ld %hd\n\0", (long) msgTime, code );
1407      logit("et","Error:%d (No description)\n", code );
1408    }
1409
1410    /*Write the message to the output region                         */
1411    if ( tport_putmsg( &g_tport_region, &g_error_logo,
1412                       (long) strlen( outMsg ), outMsg ) != PUT_OK )
1413    {
1414      /*     Log an error message                                    */
1415      logit( "et", "k2ew: Failed to send an error message (%d).\n",
1416             code );
1417    }
1418  }
1419}
Note: See TracBrowser for help on using the repository browser.