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

Revision 3206, 84.2 KB checked in by paulf, 11 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.41  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.40  2007/05/15 23:29:24  dietz
13 *     Changed version to 2.42 to reflect previous Windows Service-friendly mods
14 *
15 *     Revision 1.39  2007/05/10 00:14:50  dietz
16 *     wrapped all SIGBREAK statements in #ifdef SIGBREAK for solaris
17 *
18 *     Revision 1.38  2007/05/09 23:56:27  dietz
19 *     Added a CtrlHandler (Windows only) to catch/ignore user logoff events
20 *     so that k2ew console windows will survive user logouts when Earthworm
21 *     is started with startstop_service. Also modified to log a descriptive
22 *     message instead of a numeric value for handled signals.
23 *
24 *     Revision 1.37  2005/09/15 13:56:19  friberg
25 *     version 2.41 of k2ew has logging messages cleaned up
26 *
27 *     Revision 1.36  2005/07/27 19:28:49  friberg
28 *     2.40 changes for ForceBlockMode and comm stats
29 *
30 *     Revision 1.35  2005/05/27 15:04:59  friberg
31 *     new version 2.39 fixes restart file issue with netcode and location codes
32 *
33 *     Revision 1.34  2005/03/26 00:17:46  kohler
34 *     Version 2.38.  Added capability to get network code values from the K2
35 *     headers.  The "Network" parameter in the config file is now optional.
36 *     WMK 3/25/05
37 *
38 *     Revision 1.33  2005/03/25 00:38:01  kohler
39 *     Now logging chan/net/loc codes from K2 header.  WMK
40 *
41 *     Revision 1.32  2005/01/04 22:03:18  friberg
42 *     comments for version 2.33 fixed
43 *
44 *     Revision 1.31  2004/06/04 16:53:44  lombard
45 *     Tweaked some startup message formats.
46 *
47 *     Revision 1.30  2004/06/03 23:30:00  lombard
48 *     Added printing of LocationNames during startup
49 *
50 *     Revision 1.29  2004/06/03 16:54:01  lombard
51 *     Updated for location code (SCNL) and TYPE_TRACEBUF2 messages.
52 *
53 *     Revision 1.28  2003/08/22 20:12:13  friberg
54 *     added check for terminate flag to redo_socket in k2c_tcp.c
55 *     to prevent k2ew_tcp from taking too long to exit when in this
56 *     function call and a terminate signal arrives.
57 *
58 *     Revision 1.27  2003/07/17 19:23:27  friberg
59 *     Fixed a status message to include network and station name for the k2
60 *     from which the error originated.
61 *
62 *     Revision 1.26  2003/06/06 01:24:13  lombard
63 *     Changed to version 2.34: fix for byte alignment problem in extended status
64 *     structure.
65 *
66 *     Revision 1.25  2003/05/29 13:33:40  friberg
67 *     see release notes, added new directive InjectInfo and cleaned
68 *     up exit messages at startup
69 *
70 *     Revision 1.24  2003/05/15 00:42:45  lombard
71 *     Changed to version 2.31: fixed handling of channel map.
72 *
73 *     Revision 1.23  2002/05/06 18:29:15  kohler
74 *     Changed version from 2.29 to 2.30.
75 *
76 *     Revision 1.22  2002/04/30 18:15:44  lucky
77 *     Fixed version string to 2.29
78 *
79 *     Revision 1.21  2002/01/30 14:28:31  friberg
80 *     added robust comm recovery for time out case
81 *
82 *     Revision 1.20  2002/01/17 22:02:32  kohler
83 *     Changed version to 2.27
84 *
85 *     Revision 1.19  2002/01/17 21:57:20  kohler
86 *     Changed type of g_mt_working and g_ot_working to volatile.
87 *
88 *     Revision 1.18  2001/10/19 18:23:49  kohler
89 *     Changed version string to "2.26".  Updated comments.
90 *
91 *     Revision 1.17  2001/10/16 22:03:56  friberg
92 *     Upgraded to version 2.25
93 *
94 *     Revision 1.16  2001/08/08 16:11:48  lucky
95 *     version 2.23
96 *
97 *     Revision 1.14  2001/05/23 00:19:28  kohler
98 *     New config parameter: HeaderFile
99 *
100 *     Revision 1.13  2001/05/08 23:16:14  dietz
101 *     Changed to shut down gracefully if the transport flag is
102 *     set to TERMINATE or g_pidval.
103 *
104 *     Revision 1.12  2001/05/08 00:13:07  kohler
105 *     Minor logging changes.
106 *
107 *     Revision 1.11  2001/04/23 20:18:53  friberg
108 *     Added station name remapping using StationID parameter.
109 *
110 *     Revision 1.10  2000/11/28 01:12:20  kohler
111 *     Cosmetic changes to log file format.
112 *
113 *     Revision 1.9  2000/11/07 19:41:29  kohler
114 *     Added new global variable: gcfg_gpslock_alarm
115 *
116 *     Revision 1.8  2000/08/30 17:34:00  lombard
117 *     See ChangeLog entry for 30 August 2000
118 *
119 *     Revision 1.7  2000/08/12 18:10:04  lombard
120 *     Fixed bug in cb_check_waits that caused circular buffer overflows
121 *     Added cb_dumb_buf() to dump buffer indexes to file for debugging
122 *
123 *     Revision 1.6  2000/07/28 22:36:10  lombard
124 *     Moved heartbeats to separate thread; added DontQuick command; removed
125 *     redo_com() since it doesn't do any good; other minor bug fixes
126 *
127 *     Revision 1.5  2000/07/03 18:00:37  lombard
128 *     Added code to limit age of waiting packets; stops circ buffer overflows
129 *     Added and Deleted some config params.
130 *     Added check of K2 station name against restart file station name.
131 *     See ChangeLog for complete list.
132 *
133 *     Revision 1.4  2000/06/09 23:14:23  lombard
134 *     Several bug fixes and improvements; See Changelog entry of 2000-06-09.
135 *
136 *     Revision 1.3  2000/05/16 23:39:16  lombard
137 *     bug fixes, removed OutputThread Keepalive, added OnBattery alarm
138 *     made alarms report only once per occurence
139 *
140 *     Revision 1.2  2000/05/09 23:59:07  lombard
141 *     Added restart mechanism
142 *
143 *     Revision 1.1  2000/05/04 23:48:19  lombard
144 *     Initial revision
145 *
146 *
147 *
148 */
149/*  k2ewmain.c:  Main (top-level) module for K2-to-Earthworm          */
150/*                                                                    */
151/*     k2ew = K2-to-Earthworm Interface Module                        */
152/*                                                                    */
153/*     COPYRIGHT 1998, 1999: Instrumental Software Technologies, Inc. */
154/*     ALL RIGHTS RESERVED. Please contact ISTI for use of this code. */
155/*     It is free to all academic institutions and federal government */
156/*     agencies.                                                      */
157/*                                                                    */
158/*     Author:  Eric Thomas                                           */
159/*     Contact: support@isti.com                                      */
160/*                                                                    */
161/*   3/29/99 -- [ET]  Version 1.00 release                            */
162/*   3/15/00 -- Pete Lombard: mods to allow socket and Unix serial    */
163/*                comms.                                              */
164/*                                                                    */
165/*   3/22/2001 -- Paul Friberg Version 2.11 - added in Station Name   */
166/*              remapping feature(what is it with the month of March?) */
167/*
168     7/22/2001 -- [ET]  Version 2.20:  Improved handling of resend
169         requests (more focus on oldest waiting packet); added commands
170         "MaxBlkResends", "MaxReqPending", "ResumeReqVal",  "WaitResendVal",
171         "RestartComm"; improved debug log output messages; added logging of
172         K2 channel names; changed "# of packets lost" value so that it is
173         only the total after a restart (to be consistent with the "# of
174         packets received OK" total); added "Program start time", "# of
175         packet retries", "Packet error rating" and "Time of last output
176         seq err" to the summary listings; added logging of "in-process"
177         summary listing at each status output interval.
178
179     7/23/2001 -- [ET]  Version 2.22:  Changed default value for
180         'MaxReqPending' command from 10 to 6 (as per recommendation
181         of Dennis Pumphrey).
182
183      8/7/2001 -- [ET]  Version 2.23:  Added "ChannelNames" and
184         "InvPolFlags" parameters.
185
186      8/8/2001 -- [ET]  Version 2.24:  Changed so that the "ChannelNames"
187         remapping occurs even when a restart file is used; made handling
188         of station names in the code more straightforward.
189
190     8/22/2001 -- [ET]  Version 2.25:  Fixed "# of packets lost" total
191         displayed so that it works correctly after a restart file has
192         been used.
193
194     10/19/2001 -- Will Kohler  Version 2.26:  If a pcdrv_raw_read or
195         pcdrv_raw_write error message is received from the K2, the
196         program now sends a K2STAT_BAD_DISK message to statmgr.
197
198     01/17/2002 -- Will Kohler  Version 2.27:  Changed types of variables
199         g_mt_working and g_ot_working to "volatile".
200
201      1/29/2002 -- [ET]  Version 2.28:  Improved recovery after timeout by
202         adding call to 'k2mi_init_blkmde()' to attempt to restore block
203         mode in the K2 (needed if modem took over K2's I/O).
204
205      5/6/2002  -- Will Kohler  Version 2.30:  Added a line to function
206         k2c_init_io() in file k2c_tcp.c so that heartbeats are sent to
207         statmgr while k2ew is attempting to make a socket connection to
208         the K2.
209
210      5/13/2003 -- [PNL] Version 2.31: Changed parsing of the channel bitmask
211        from STREAM_K2_RW_PARMS.TxChanMap  instead of
212        MISC_RW_PARMS.channel_bitmap, which is the acquisition mask.
213        Added ability to handle 40-byte extended status packet in addition
214        to old 12-byte extended status packet.
215
216      05/26/2003 Paul Friberg Version 2.32: cleaned up GPS lock error
217        message to echo network and station name (previously it was impossible
218        to tag this message to any particular K2). Also added network code to
219        all error messages emanating from a K2. They now all read:
220                "K2 <NN-SSSS>: error/warn message"
221        All changes made in k2misc.c                   
222
223      05/27/2003 Paul Friberg Version 2.33: added in k2 info packets for
224        status monitoring of K2's. Only tested on Solaris. New config
225        item in .d file is InjectInfo (defaults to OFF if not present).
226        This new feature is for use in SeisNetWatch to monitor parameters
227        of K2s. K2 parameters and status packets are injected into the
228        wavering as TYPE_K2INFO and this message should be configured as
229        a local message in the earthworm.d file.
230       
231        Also fixed first three calls to k2ew_enter_exitmsg() which sent out
232        status messages without the station name...because comms were not
233        yet established with the K2. I added the config file name in there
234        since that usually has some station specific moniker in it.
235
236
237      06/05/2003 Pete Lombard Version 2.34: added code to handle byte
238        alignment problems with extended status packet, in k2misc.c     
239
240      07/17/2003 Paul Friberg Version 2.35: fixed a message about
241        write and read errors that was getting sent to the status
242        manager without any information about the K2 network/station
243        name that it was corresponding to.
244
245      08/22/2003 Paul Friberg Version 2.36: modified the redo_socket()
246        call to more properly obey the SIGTERM signal. This was hanging
247        up the restart caused by startstop_solaris and causing k2ew_tcp
248        under Solaris to go into a Zombie state. The fix was to look
249        at the g_terminate flag and if set, exit with an error. Previously
250        the program would continue on for another try if the g_dontquit
251        flag was set!
252
253      06/02/2004 Pete Lombard Version 2.37: added support for location
254        code (SCNL) and TYPE_TRACEBUF2 messages. Location codes are
255        specified in the LocationNames config parameter, similar to
256        ChannelNames. Added LCFlag to control the action taken on missing
257        location or channel names.
258
259      3/25/05 Will Kohler Version 2.38: K2ew will now, optionally,
260        obtain network code from the K2 headers, rather than from the
261        configuration file.  For this to work, network codes need to
262        be entered into the K2 using Altus File Assistant. A different
263        network code may be entered for each stream.  The K2 must be
264        running application firmware version 3.02 or later.
265        The "Network" parameter, in the config file, is now optional.
266
267        2005-05-27 Paul Friberg Version 2.39: fixed previous version for issues
268        with the restart file. If the restart file was being used, then
269        the above network code assignment was not taking. The change
270        was to add network and location code to the line, instead of
271        just recording the Channel name in the restart file. The old
272        Channel identifier is retired and is replaced by NCL. If
273        the restart file Channel line is encountered, it will cause
274        k2ew to exit (this will alert to problems when k2ew is
275        upgraded to this new version). The fix will be to remove any
276        restart files before upgrading.
277        THIS VERSION ONLY COMPILED on SOLARIS by Paul Friberg
278        Will Kohler tested the above version on Windows
279
280        2005-06-01 Paul Friberg Version 2.40: added in a new directive
281        ForceBlockMode to wrest control from the modem for K2s configured
282        with both a modem and a serial data stream feed. This feature is
283        off by default, but can be turned on by setting ForceBlockMode 1
284        inside the configuration file.  Also added new communications
285        statistics message for pickup by k2ewagent.
286
287        2005-09-15 Paul Friberg Version 2.41: cleaned up all of the
288        exit messages that could get emailed to a user. The messages now
289        all indicate the station name or the config filename so that
290        the K2 having the error can be identified.
291
292        2007-12-17 Paul Friberg Version 2.43: new dual feed k2 with
293        modems improvements. This requires a new firmware upgrade
294        from KMI that was completed in August of 2007.
295 
296*/
297
298
299#include <stdio.h>
300#include <stdlib.h>
301#include <stdarg.h>
302#include <string.h>
303#include <signal.h>
304#include <earthworm.h>       /* Earthworm main include file */
305#include <time.h>
306#include <transport.h>       /* Earthworm shared-memory transport routines */
307#include "time_ew.h"         /* Earthworm time conversion routines */
308#include "k2comif.h"         /* K2 communication interface routines */
309#include "k2pktio.h"         /* K2 packet send/receive routines */
310#include "k2pktman.h"        /* K2 packet management and SDS functions */
311#include "byteswap.h"        /* integer byte-swap macros */
312#include "k2ewerrs.h"        /* K2-to-Earthworm error codes */
313#include "k2cirbuf.h"        /* K2 circular buffer routines */
314#include "k2misc.h"          /* miscellaneous K2 functions */
315#include "k2info.h"          /* K2 info functions */
316#include "k2ewrstrt.h"
317#include "getconfig.h"       /* command configuration file processing fn */
318#include "outptthrd.h"       /* 'output' thread function declaration */
319#include "terminat.h"        /* program termination defines and functions */
320#include "heartbt.h"         /* 'heartbeat' thread function declaration */
321#include "glbvars.h"         /* externs to globals & 'K2_MAX_STREAMS' define */
322
323#define K2EW_VERSION_STR "2.43" /* version string for program */
324
325#define K2_STMDEBUG_FLG 0       /* 1 for stream input debug display enabled */
326
327#define K2_NUM_RETRIES    3     /* # of times to retry failed commands */
328#define K2_PING_COUNT     10    /* # of pings to send/recv for test */
329/* #define K2_WAITFOR_MS     5000  * max # of msec to wait for start of data */
330/* #define K2_CBENTS_PERSTM  2000  * # of circ buff entries per stream */
331/* #define K2_PKTAHEAD_LIM   30    * max # of packets "ahead" allowed */
332/* #define K2_MAX_WAITENTS   30    * max # of "waiting" entries allowed */
333/* #define K2_MAX_BLKRESENDS 2     * max # resend requests per block */
334/* #define K2_WAIT_RESENDVAL 50    * # data seq between resend reqs (was 20) */
335/* #define K2_MAX_REQ_PEND   3     * max number of pending resend requests */
336
337/* macro calculates, for the given packet stream and data sequence numbers, */
338/*  an index value relative to the current packet position */
339#define K2M_PCKT_RELIDX(stm,dseq) \
340   (((long)(dseq)-(long)cur_dataseq)*g_numstms+(unsigned char)(stm)-cur_stmnum)
341
342/* Internal function prototypes */
343void k2ew_signal_hdlr(int signum);/* function to handle "signal" events */
344void k2ew_signal_string(int signum, char *str, int len); 
345                                  /* provide useful string for signal logging */
346void k2ew_log_cfgparams(void);    /* output config values to log file */
347
348static int k2ew_signal_val=-1;    /* initialize value from signal function */
349
350char g_progname_str[]="K2EW";     /* global program name string */
351int g_terminate_flg = 0;          /* = 1 to initiate program termination */
352int g_numstms = 0;                /* number of data streams coming in */
353int g_smprate = 0;                /* sample rate (& entries per SDS pkt) */
354char g_k2_stnid[STN_ID_LENGTH+1];      /* station-ID string read from K2 */
355char g_stnid[STN_ID_LENGTH+1];         /* station-ID string in use */
356unsigned long g_pktout_okcount=0L;/* # of packets sent to Earthworm OK */
357unsigned long g_seq_errcnt=0L;    /* number of output sequence errors */
358unsigned long g_skip_errcnt=0L;   /* number of packets skipped */
359unsigned long g_trk_dataseq=0L;   /* output thread tracked data seqence */
360unsigned char g_trk_stmnum=(unsigned char)0; /* outputthread tracked stream */
361time_t g_seq_errtime = (time_t)0; /* time of last output sequence error */
362int g_validrestart_flag = 0;      /* 1 if restart file is valid */
363int g_extstatus_avail = 1;        /* set to 0 if extended status fails */
364
365
366
367SHM_INFO g_tport_region;          /* transport region struct for Earthworm */
368MSG_LOGO g_heartbeat_logo;        /* Transport logo for heartbeat messages */
369MSG_LOGO g_error_logo;            /* Transport logo for error messages */
370unsigned char g_heart_ltype = 0;  /* logo type for heartbeat msgs */
371unsigned char g_error_ltype = 0;  /* logo type for error messages */
372unsigned char g_trace_ltype = 0;  /* logo type value for trace messages */
373unsigned char g_instid_val = 0;   /* installation ID value from/for EW */
374volatile int g_mt_working = 1;    /* =1 says main thread is working */
375volatile int g_ot_working = 0;    /* =1 says output thread is working */
376unsigned g_output_threadid=(unsigned)-1;    /* ID for output thread */
377unsigned g_hrtbt_threadid=(unsigned)-1;     /* ID for heartbeat thread */
378pid_t g_pidval = 0;                 /* Our PID for heartbeat messages */
379int g_wait_count = 0;             /* number of "wait" blocks in buffer */
380int g_req_pend = 0;               /* number of resend requests pending */
381
382/* array of channel ID strings, 1 for each logical stream expected */
383char g_stmids_arr[K2_MAX_STREAMS][CHANNEL_ID_LENGTH+1];
384/* array of network code strings, 1 for each logical stream expected */
385char g_netcode_arr[K2_MAX_STREAMS][K2_NETBUFF_SIZE+2];
386
387/* global configuration variables set in 'getconfig.c': */
388s_gen_io gen_io;                       /* general IO params structure */
389char gcfg_module_name[MAXNAMELEN+2]="";     /* module name for k2ew */
390unsigned char gcfg_module_idnum=0;     /* module id for k2ew */
391char gcfg_ring_name[MAXNAMELEN+2]="";  /* specified name of ring buffer */
392long gcfg_ring_key=0L;                 /* key to ring buffer k2ew dumps data */
393int gcfg_heartbeat_itvl = 30;          /* heartbeat interval (secs) */
394int gcfg_logfile_flgval=1;             /* output to logfile enable flag */
395char gcfg_network_buff[K2_NETBUFF_SIZE+2]="";  /* network name buffer */
396int gcfg_base_pinno = 0;               /* pin number for stream 0 */
397int gcfg_status_itvl = 1800;           /* status interval (seconds) */
398int gcfg_commtimeout_itvl = 5000;      /* communication timeout (millisecs) */
399int gcfg_pktwait_lim = 60;             /* Maximum time to wait for packet */
400int gcfg_max_blkresends = 4;           /* max # resend requests per block */
401int gcfg_max_reqpending = 6;           /* max # of pending resend requests */
402int gcfg_resume_reqval = 2;            /* # blks needed to resume requests */
403int gcfg_wait_resendval = 20;          /* # data seq between resend reqs */
404int gcfg_restart_commflag = 0;         /* 1 to restart comm after timeout */
405int gcfg_ext_status = 0;               /* flag to get extended status msgs */
406int gcfg_on_batt = 0;                  /* flag for sending `on battery' msg */
407int gcfg_battery_alarm = -1;           /* battery low-voltage alarm, 0.1 V */
408int gcfg_extern_alarm = -1;            /* External low-voltage alarm, 0.1 V; not used */
409double gcfg_disk_alarm[2] = {-1.0, -1.0}; /* disk A space low alarm, bytes */
410int gcfg_hwstat_alarm = 0;             /* hardware status alarm flag */
411int gcfg_templo_alarm = -1000;         /* low temperature alarm, 0.1 deg C */
412int gcfg_temphi_alarm = 1000;          /* high temperature alarm, 0.1 deg C */
413double gcfg_gpslock_alarm = -1.0;      /* report if no GPS synch for this many hours */
414char gcfg_restart_filename[MAXNAMELEN+2] = "";   /* Restart file name */
415char gcfg_header_filename[MAXNAMELEN+2]  = "";   /* K2 header file name */
416int gcfg_restart_maxage = 0;           /* Maximum age of restart file in sec */
417char gcfg_stnid_remap[STN_ID_LENGTH+1];  /* remapping value for station-ID */
418                   /* array of "ChannelNames" remapping name strings: */
419char *gcfg_chnames_arr[K2_MAX_STREAMS];
420                   /* array of invert-polarity flags; 1 per channel: */
421int gcfg_invpol_arr[K2_MAX_STREAMS];
422                   /* array of "LocationNames": */
423char *gcfg_locnames_arr[K2_MAX_STREAMS];
424int gcfg_lc_flag = 0;                  /* =1 to use "--" if no loc code for K2 chan;
425                                          =2 to die if no loc code for K2 chan */
426int gcfg_dont_quit = 0;                /* =0 if we should quit on timeout */
427int gcfg_inject_info = 0;              /* inject K2INFO packets into ring  if == 1 */
428int gcfg_force_blkmde =0;              /* force a K2 into block mode at startup, for troublesome modem connected K2's */
429int gcfg_debug = 0;                    /* k2ew debug level */
430
431
432/* Put whole function here to avoid having to ifdef a prototype. */
433#ifdef _WINNT
434BOOL CtrlHandler( DWORD fdwCtrlType )
435{
436  switch( fdwCtrlType )
437  {
438    case CTRL_LOGOFF_EVENT:  /* intercept user logoff events with no action */
439      return(TRUE);          /* because we want k2ew to keep running!       */
440
441    default:
442      return(FALSE);         /* pass other events to other signal handlers */
443  }
444}
445#endif /* _WINNT */
446
447/**************************************************************************
448 * main                                                                   *
449 **************************************************************************/
450
451int main(int argc,char **argv)
452{
453  static int count;
454  static int rc,cb_rc;
455  static int ext_size;
456  static int numacq_chan;
457  static int dcount,wait_resenditvl,numticks,idnum,resendcnt,rr_resendcnt,
458                                             resume_numpend,rerequest_idnum;
459  static int no_req = 0, timeout_logged = 0;
460  static int ch_cfg_err = 0;
461  static unsigned long cur_dataseq,dataseq,rr_dataseq,msk,strmmsk,
462                       acqmsk, rstrt_dataseq =0, last_sec = 0;
463  static long idx,c;
464  static unsigned long pktin_okcount,missing_errcnt,unexpect_errcnt,
465                       request_errcnt,resync_errcnt,packet_errcnt,
466                       receive_errcnt,retried_pckcnt,last_pktin_okcount,
467                       last_pktout_okcount,last_seq_errcnt,
468                       last_retried_pckcnt,last_missing_errcnt,comm_retries;
469  static unsigned char seqnum,cur_stmnum,stmnum,rr_stmnum,
470                       rstrt_stmnum = 0;
471  static K2_HEADER k2hdr;
472  static struct STATUS_INFO k2stat;
473  static struct EXT2_STATUS_INFO k2extstat;
474  static struct StrDataHdr datahdr;
475  static long databuff[K2PM_MIN_DBUFSIZ+2];
476  static time_t prog_start_time, timevar, last_stat_time = (time_t)0; 
477  static time_t last_force_block, last_attempted_force_block, now;
478  static char msg_txt[180];
479  static struct tm tmblk;
480
481
482  time(&prog_start_time);         /* save program start time */
483  gcfg_stnid_remap[0]='\0';
484  g_k2_stnid[0] ='\0';
485  last_force_block = 0;
486  last_attempted_force_block = 0;
487
488  if (argc != 2)
489  {
490    fprintf(stderr, "Usage: %s <configfile>\n", argv[0]);
491    exit (EW_FAILURE);
492  }
493
494  if (get_config(argv[1]) == -1)  /* process configuration file */
495  {
496    fprintf(stderr, "k2ew: error processing config file <%s>\n", argv[1]);
497    return 1;    /* if error then exit program (error reported in function) */
498  }
499
500         /* calculate number of pending waiting blocks that must be  */
501         /*  gotten down to before resend requests are resumed after */
502         /*  'MaxReqPending' has been reached:                       */
503  if((resume_numpend=gcfg_max_reqpending-gcfg_resume_reqval) < 0)
504    resume_numpend = 0;           /* if negative then make it zero */
505
506  /* initialize output log file */
507  logit_init(argv[1],(short)gcfg_module_idnum, 1024, gcfg_logfile_flgval);
508  logit("et","K2-to-Earthworm Module, Version %s\n",K2EW_VERSION_STR);
509  logit("et","with SCNL and TRACEBUF2 messages\n");
510  logit("et","Processed configuration file <%s>\n",argv[1]);
511
512  k2ew_log_cfgparams();      /* output configuration values to log file */
513
514  /* attach to Earthworm shared memory ring buffer */
515  /*  (fn will display error message and abort if error) */
516  tport_attach(&g_tport_region,gcfg_ring_key);
517  logit("et","Attached to ring key:  %ld\n",gcfg_ring_key);
518
519  /* setup logo type values for Eartworm messages */
520  if(GetType("TYPE_ERROR",&g_error_ltype) != 0 ||
521     GetType("TYPE_HEARTBEAT",&g_heart_ltype) != 0 ||
522     GetType("TYPE_TRACEBUF2",&g_trace_ltype) != 0)
523  {      /* error fetching logo type values; show error message and abort */
524    sprintf (msg_txt, "Error fetching logo type values for EW messages: %s",argv[1]);
525    k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
526    k2ew_exit(0);                 /* exit program with code value */
527  }
528
529
530  /* get installation ID value */
531  if(GetLocalInst(&g_instid_val) != 0)
532  {      /* error fetching installation ID value; show error message & abort */
533    sprintf (msg_txt, "Error fetching installation ID value: %s",argv[1]);
534    k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
535    k2ew_exit(0);                 /* exit program with code value */
536  }
537
538
539  /* setup things for heartbeat messages */
540  g_pidval = getpid();
541  g_heartbeat_logo.type = g_heart_ltype;
542  g_heartbeat_logo.mod = gcfg_module_idnum;
543  g_heartbeat_logo.instid = g_instid_val;
544
545  /* setup things for error messages */
546  g_error_logo.type = g_error_ltype;
547  g_error_logo.mod = gcfg_module_idnum;
548  g_error_logo.instid = g_instid_val;
549
550  g_mt_working = 1;
551  /* startup the heartbeat thread */
552  if (StartThread(k2ew_heartbeat_fn, (unsigned)0, &g_hrtbt_threadid) == -1)
553  {
554    sprintf (msg_txt, "Unable to startup heartbeat thread--aborting: %s",argv[1]);
555    k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
556    k2ew_exit(0);                 /* exit program with code value */
557  }
558
559  if (gcfg_restart_filename[0] != '\0')
560    k2ew_read_rsfile(&g_validrestart_flag, &rstrt_dataseq, &rstrt_stmnum);
561  if (gcfg_debug > 1)
562    logit("et", "restart flag: %d\n", g_validrestart_flag);
563
564  /* Initialize IO to the K2: sockets or serial comms */
565  if ( (rc = k2c_init_io( &gen_io, gcfg_commtimeout_itvl )) != K2R_NO_ERROR)
566  {      /* comms initialization failed */
567    sprintf (msg_txt, "Unable to initialize IO port: %s",argv[1]);
568    k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
569    k2ew_exit(0);                  /* exit program with code value */
570  }
571  if (gcfg_debug > 0)
572    logit("et","Initialized IO port\n");
573
574  /* get comm link to K2 going */
575  if (gcfg_force_blkmde == 1) 
576  {
577     if(k2mi_force_blkmde() < K2R_NO_ERROR)
578     {      /* error code returned; show error message and exit program */
579       sprintf (msg_txt, "Unable to force block mode with K2: %s",argv[1]);
580       k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
581       k2ew_exit(0);                  /* exit program with code value */
582     }
583     logit("et","Forced block mode with K2\n");
584     time(&last_force_block);
585  }
586
587  seqnum = (unsigned char)0;       /* initialize K2 packet sequence number */
588  if(k2mi_init_blkmde(&seqnum) < K2R_NO_ERROR)
589  {      /* error code returned; show error message and exit program */
590    sprintf (msg_txt, "Unable to establish communications link with K2: %s",argv[1]);
591    k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
592    k2ew_exit(0);                  /* exit program with code value */
593  }
594  logit("et","Established communications link with K2\n");
595
596  /*  if (init_rc != K2R_POSITIVE)
597      g_validrestart_flag = 0;  */   /* Commented out: try using any K2
598                                         response for valid restart */
599
600  if (g_validrestart_flag == 0)
601  {
602    /* stop streaming and acquiring */
603    logit("et", "Initializing K2 stream control...\n");
604    count = K2_NUM_RETRIES;        /* initialize retry count */
605    while( (rc = k2pm_stop_streaming(&seqnum, 1)) < K2R_NO_ERROR)
606    {      /* loop while function fails */
607      if (--count <= 0)
608      {         /* too many attempts; indicate failure */
609        sprintf (msg_txt, "Unable to initialize K2 stream control: %s",argv[1]);
610        k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
611        k2ew_exit(0);                /* exit program with code value */
612      }
613    }
614    if (gcfg_debug > 0)
615      logit("et","Initialized K2 stream control\n");
616
617    /* test COM link */
618    logit("et", "Testing K2 communications link...");
619    count = K2_NUM_RETRIES;        /* initialize retry count */
620    while ( (rc = k2mi_ping_test(K2_PING_COUNT,&seqnum)) != K2R_NO_ERROR)
621    {      /* loop while ping test fails */
622      if (--count <= 0)
623      {         /* too many attempts; indicate failure */
624        sprintf (msg_txt, "Error testing K2 communications links: %s",argv[1]);
625        k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
626        k2ew_exit(0);                /* exit program with code value */
627      }
628    }
629    logit("e", "OK\n");
630
631    /* get K2 header parameters; needed to configure this program */
632    if (gcfg_debug > 0)
633       logit("et", "Reading K2 header parameters...\n");
634    count = K2_NUM_RETRIES;        /* initialize retry count */
635    while ( (rc = k2mi_get_params(&k2hdr, &seqnum)) != K2R_POSITIVE)
636    {      /* loop while read command fails */
637      if (--count <= 0)
638      {         /* too many attempts; indicate failure */
639        sprintf (msg_txt, "Error reading K2 parameters: %s",argv[1]);
640        k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
641        k2ew_exit(0);                /* exit program with code value */
642      }
643    }
644
645    /* get K2 status */
646    if (gcfg_debug > 0)
647      logit("et", "Reading K2 status...\n");
648    count = K2_NUM_RETRIES;        /* initialize retry count */
649    while ( (rc = k2mi_get_status(&k2stat,&seqnum)) != K2R_POSITIVE)
650    {      /* loop while read command fails */
651      if (--count <= 0)
652      {         /* too many attempts; signal failure */
653        sprintf (msg_txt, "Error reading K2 status: %s",argv[1]);
654        k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
655        k2ew_exit(0);                /* exit program with code value */
656      }
657    }
658    /* get K2 extended status */
659    if (gcfg_ext_status != 0)
660    {
661      logit("et", "Reading K2 extended status...\n");
662      count = 1;        /* initialize retry count */
663      while ( (rc = k2mi_get_extstatus(&k2extstat, &seqnum, &ext_size)) 
664              != K2R_POSITIVE)
665      {      /* loop while read command fails */
666        if (gcfg_debug > 3)
667          logit("e", "k2mi_get_extstatus returned %d\n", rc);
668        if (--count <= 0)
669        {         /* too many attempts; signal failure */
670          if (rc == K2R_NO_ERROR)
671          {
672            logit("et", "Extended status not available from K2\n");
673            g_extstatus_avail = 0;
674            break;
675          }
676          sprintf (msg_txt, "Error reading K2 extended status: %s",argv[1]);
677          k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
678          k2ew_exit(0);                /* exit program with code value */
679        }
680      }
681    }
682    k2mi_report_params(&k2hdr);
683    last_stat_time = timevar;
684
685    /* get aquisition channel count and sample rate */
686    numacq_chan = BYTESWAP_UINT16(k2hdr.rwParms.misc.nchannels);
687    g_smprate = BYTESWAP_UINT16(k2hdr.rwParms.stream.SampleRate);
688    /* save copy of station-ID string received from K2 */
689    strncpy(g_k2_stnid,k2hdr.rwParms.misc.stnID,sizeof(g_k2_stnid)-1);
690    g_k2_stnid[sizeof(g_k2_stnid)-1] = '\0';     /* make sure of null */
691        /* 2001.081 remapping of station id now possible from config */
692    if (strlen(gcfg_stnid_remap) > 0 &&
693                                   strcmp(g_k2_stnid,gcfg_stnid_remap) != 0)
694    {    /* different station name given in config file */
695      logit("et","Original K2 Station ID = \"%s\"\n",g_k2_stnid);
696      logit("et","K2 Station ID remapped to \"%s\"\n",gcfg_stnid_remap);
697      strncpy(g_stnid,gcfg_stnid_remap,sizeof(g_stnid)-1);
698      g_stnid[sizeof(g_stnid)-1] = '\0';    /* make sure null terminated */
699    }
700    else      /* no station name remap */
701    {                   /* put received name into use: */
702      strncpy(g_stnid,g_k2_stnid,sizeof(g_stnid)-1);
703      g_stnid[sizeof(g_stnid)-1] = '\0';    /* make sure null terminated */
704    }
705
706    /* save streaming and acquisition channel bitmap masks */
707    strmmsk = BYTESWAP_UINT32(k2hdr.rwParms.stream.TxChanMap);
708    acqmsk = BYTESWAP_UINT32(k2hdr.rwParms.misc.channel_bitmap);
709
710    /* Determine which channel and network codes to stuff */
711    /* into the EW headers */
712    stmnum = (unsigned char)0;          /* initialize stream number */
713    msk = (unsigned long)1;           /* initialize bit mask position */
714    for(idnum=0; (unsigned char)idnum<K2_MAX_STREAMS; ++idnum)
715    {      /* for each possible stream */
716      if((msk & strmmsk) != (unsigned long)0)
717      {    /* channel is selected as a logical stream */
718
719        /* fill in 'g_stmids_arr[][]' array with channel ID strings from */
720        /*  the K2 (or substitute ID strings for any in the K2 that are  */
721        /*  empty); one channel ID entry for each logical stream in use  */
722        if(k2hdr.rwParms.channel[idnum].id[0] != '\0')
723        {       /* channel ID in K2 is not blank; copy it over */
724          strncpy(g_stmids_arr[stmnum], k2hdr.rwParms.channel[idnum].id,
725                  sizeof(g_stmids_arr[0])-1);
726          /* make sure string is NULL terminated */
727          g_stmids_arr[stmnum][sizeof(g_stmids_arr[0])-1] = '\0';
728        }
729        else    /* channel ID in K2 is blank; generate substitute ID string */
730          sprintf(g_stmids_arr[stmnum], "C%02d",idnum + 1);
731
732        /* Fill in the g_netcode_arr[][] array with the network code from */
733        /* the config file, if any.  If no netcode was specified in the   */
734        /* config file, use netcodes from the K2 headers.                 */
735        if ( gcfg_network_buff != 0)
736        {       /* Network code is specified in the config file; copy it over */
737          strcpy(g_netcode_arr[stmnum], gcfg_network_buff);
738          logit("et", "Using Network code %s from .d config file for stream %d\n", g_netcode_arr[stmnum], stmnum);
739        }
740        else    /* No network code in the config file; copy from K2 headers */
741        {
742          strncpy(g_netcode_arr[stmnum], k2hdr.rwParms.channel[idnum].networkcode,
743                  sizeof(g_netcode_arr[0])-1);
744          /* make sure string is NULL terminated */
745          g_netcode_arr[stmnum][sizeof(g_netcode_arr[0])-1] = '\0';
746          logit("et", "Using Network code %s from K2 for stream %d\n", g_netcode_arr[stmnum], stmnum);
747        }
748
749        /* The above looks weird, but apparently it is correct. One would  *
750         * think that g_stmids_arr[] should be indexed by idnum so that    *
751         * "channel numbers" and "stream numbers" would match. But the K2  *
752         * doesn't work that way. The first channel configured for         *
753         * streaming is stream #0; the second is stream #1, etc.,          *
754         * independent of the channel numbers. PNL 6/2/2004                */
755
756        if(++stmnum >= (unsigned char)numacq_chan)
757          break;        /* if ID for last stream filled then exit loop */
758      }
759      msk <<= 1;        /* shift to bit position for next channel */
760    }
761    /* Remember the number of streaming channels */
762    g_numstms = stmnum;
763   
764    while(stmnum < K2_MAX_STREAMS)          /* fill in remaining entries */
765      strcpy(g_stmids_arr[stmnum++],"???"); /*  with dummy strings */
766
767    /* show parameter and status information */
768    logit("et","K2 Station ID = \"%s\"\n",g_stnid);
769    msk = (unsigned long)1;           /* initialize bit mask position */
770    for ( idnum = 0; idnum < K2_MAX_STREAMS; idnum++ )
771    {      /* for each possible stream */
772       if((msk & strmmsk) != (unsigned long)0)
773       {    /* channel is selected as a logical stream */
774           logit( "et", "K2 Chan.Net.Loc Code: %s.%s.%s (channel %d)\n",
775                 k2hdr.rwParms.channel[idnum].id,
776                 k2hdr.rwParms.channel[idnum].networkcode,
777                 k2hdr.rwParms.channel[idnum].locationcode, idnum );
778       }
779       msk <<= 1;        /* shift to bit position for next channel */
780    }
781    logit("et","K2 Instrument Code = %hu\n",
782          (unsigned short)(k2hdr.roParms.instrumentCode));
783    logit("et","K2 Header Version = %hu.%02hu\n",(unsigned short)
784          BYTESWAP_UINT16(k2hdr.roParms.headerVersion) / (unsigned short)100,
785          (unsigned short)
786          BYTESWAP_UINT16(k2hdr.roParms.headerVersion) % (unsigned short)100);
787    logit("et","K2 Serial Number = %hu\n",
788          (unsigned short)BYTESWAP_UINT16(k2hdr.rwParms.misc.serialNumber));
789    logit("et","K2 Site ID = \"%s\"\n",k2hdr.rwParms.misc.siteID);
790    logit("et","K2 SDS Timeout = %hd\n",
791          (short)BYTESWAP_UINT16(k2hdr.rwParms.stream.Timeout));
792    logit("et","K2 Number of Acquired Channels = %d; Streaming Channels = %d\n",
793          numacq_chan, g_numstms);
794    logit("et","K2 Channel Acquisition Bitmap = %04lXH\n",acqmsk);
795    logit("et","K2 Channel Streaming Bitmap = %04lXH\n",strmmsk);
796
797    k2mi_report_status(&k2stat);
798    if(gcfg_ext_status && g_extstatus_avail)
799      k2mi_report_extstatus(&k2extstat, ext_size);
800
801    /* Initialize packet numbers if we don't read them from restart file */
802    g_trk_stmnum = cur_stmnum = (unsigned char)0;
803    g_trk_dataseq = cur_dataseq = (unsigned long)0;
804  }
805  else
806  {   /* Set parameters from restart file */
807    logit("et","Using stream parameters from restart file\n");
808        /* 2001.081 remapping of station id now possible from config */
809    if (gcfg_stnid_remap != NULL && strlen(gcfg_stnid_remap) > 0 &&
810                                   strcmp(g_k2_stnid,gcfg_stnid_remap) != 0)
811    {    /* different station name given in config file */
812      logit("et","Original K2 Station ID = \"%s\"\n",g_k2_stnid);
813      logit("et","K2 Station ID remapped to \"%s\"\n",gcfg_stnid_remap);
814      strncpy(g_stnid,gcfg_stnid_remap,sizeof(g_stnid)-1);
815      g_stnid[sizeof(g_stnid)-1] = '\0';    /* make sure null terminated */
816    }
817    else      /* no station name remap */
818    {                   /* put received name into use: */
819      strncpy(g_stnid,g_k2_stnid,sizeof(g_stnid)-1);
820      g_stnid[sizeof(g_stnid)-1] = '\0';    /* make sure null terminated */
821      logit("et","K2 Station ID = \"%s\"\n",g_stnid);
822    }
823    logit("et","K2 Number of Streams = %d\n",g_numstms);
824
825    /* dataseq and stmnum have been incremented from the last tracebuf message
826     * by output thread before writing restart file, so these numbers here
827     * are the numbers for the next expected packet */
828    g_trk_dataseq = cur_dataseq = rstrt_dataseq;
829    g_trk_stmnum = cur_stmnum = rstrt_stmnum;
830  }
831
832  if(g_numstms < 1 || (unsigned char)g_numstms > K2_MAX_STREAMS)
833  {      /* stream count out of range; show error message and abort program */
834    sprintf (msg_txt, "Illegal number of K2 streams--aborting: %s",argv[1]);
835    k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
836    k2ew_exit(0);                  /* exit program with code value */
837  }
838  if(g_smprate < 1)
839  {      /* sample rate out of range; show error message and abort program */
840    sprintf (msg_txt, "Illegal K2 sample rate--aborting: %s",argv[1]);
841    k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
842    k2ew_exit(0);                  /* exit program with code value */
843  }
844
845  /* setup the k2info logo if necessary */
846  if (gcfg_inject_info == 1) 
847  {
848    if (k2info_init() == -1)
849    {
850      sprintf (msg_txt, "Error fetching logo type values for K2INFO messages: %s",argv[1]);
851      k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
852      k2ew_exit(0);                 /* exit program with code value */
853    }
854  }
855
856  /* substitute in any "ChannelNames" items that were given; *
857   * check the LocationNames                                 */
858  for(idnum=0; idnum<g_numstms; ++idnum)
859  {      /* for each channel (stream) */
860    if(gcfg_chnames_arr[idnum] != NULL &&
861       gcfg_chnames_arr[idnum][0] != '\0') {
862        /* there is a configured channel name for this stream */
863      if (strncmp(g_stmids_arr[idnum],gcfg_chnames_arr[idnum],
864                  CHANNEL_ID_LENGTH) != 0)
865      {   
866          logit("et","Renaming channel (stream %d) from \"%s\" to \"%s\"\n",
867                idnum,g_stmids_arr[idnum],gcfg_chnames_arr[idnum]);
868          /* copy in new channel name: */
869          strncpy(g_stmids_arr[idnum],gcfg_chnames_arr[idnum], 
870                  CHANNEL_ID_LENGTH);
871          /* make sure string is NULL terminated: */
872          g_stmids_arr[idnum][CHANNEL_ID_LENGTH] = '\0';
873      }
874    }
875    else   /* there is no configured channel name for this stream */
876    {
877        logit("et", "No configured name for channel \"%s\" (stream %d)\n",
878              g_stmids_arr[idnum], idnum);
879        ch_cfg_err++;
880    }
881    if (gcfg_locnames_arr[idnum] != NULL &&
882        gcfg_locnames_arr[idnum][0] != '\0')
883    {   /* there is a location code configured for this stream */
884        logit("et", "Using location code \"%s\" for channel \"%s\" (stream %d)\n",
885              gcfg_locnames_arr[idnum], g_stmids_arr[idnum], idnum);
886    }
887    else 
888    {
889        if (gcfg_lc_flag == 1)
890        {
891            logit("et", "Using default location code \"%s\" for channel \"%s\" (stream %d)\n",
892                  LOC_NULL_STRING, g_stmids_arr[idnum], idnum);
893            gcfg_locnames_arr[idnum] = strdup(LOC_NULL_STRING);
894        }
895        else if (gcfg_lc_flag == 2)
896        {
897            logit("et", "No location code configured for channel \"%s\" (stream %d)\n",
898                  g_stmids_arr[idnum], idnum);
899            ch_cfg_err++;
900        }
901    }
902  }
903  if (ch_cfg_err && gcfg_lc_flag == 2) {
904      sprintf (msg_txt, "Error in channel/location name configuration: %s",argv[1]);
905      k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
906      k2ew_exit(0);                 /* exit program with code value */
907  }
908
909  for ( stmnum = 0; stmnum < g_numstms; stmnum++ )
910  {    /* for each channel name; log name */
911    logit("et","Using Chan.Net.Loc Code: ");
912    logit("e","%s.%s.%s",g_stmids_arr[stmnum],
913                         g_netcode_arr[stmnum],
914                         gcfg_locnames_arr[stmnum]);
915    logit( "e", " (stream %d)\n", stmnum );
916  }
917
918  rc = 0;          /* check if any channels (streams) are to be inverted */
919  for(stmnum=0; stmnum<(unsigned char)g_numstms; ++stmnum)
920  {      /* for each invert-polarity flag */
921    if(gcfg_invpol_arr[stmnum] != 0)
922    {    /* invert-polarity flag is set*/
923      rc = 1;      /* indicate that at least one flag set */
924      break;       /* exit loop */
925    }
926  }
927  if(rc != 0)
928  { /* at least one invert-polarity flag is set */
929    logit("et","Inverted Channels = ");
930    rc = 0;        /* initialize flag for first item */
931    for(stmnum=0; stmnum<(unsigned char)g_numstms; ++stmnum)
932    {    /* for each channel (stream) */
933      if(gcfg_invpol_arr[stmnum] != 0)
934      {  /* invert-polarity flag for channel (stream) is set */
935        if(rc == 0)          /* if first one then */
936          rc = 1;            /* set flag */
937        else                 /* if not first one then */
938          logit("e",", ");   /* put in separator */
939        logit("e","%s.%s",g_stmids_arr[stmnum], gcfg_locnames_arr[stmnum]);
940      }
941    }
942    logit("e","\n");         /* put in line terminator */
943  }
944
945  /* calculate retry interval for waiting packets */
946  wait_resenditvl = g_numstms * gcfg_wait_resendval;
947
948  /* initialize circular buffer to twice the WaitTime per stream */
949  if ( (rc = k2cb_init_buffer(g_numstms * gcfg_pktwait_lim * 2,
950                                                g_smprate)) != K2R_NO_ERROR)
951  {      /* error code returned; show error message and abort program */
952    sprintf (msg_txt, "Error initializing circular buffer: %s",argv[1]);
953    k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
954    k2ew_exit(0);                 /* exit program */
955  }
956
957  if (g_validrestart_flag == 0)
958  {
959    /* start acquisition and streaming */
960    logit("et", "Starting K2 acquisition and streaming...\n");
961    count = K2_NUM_RETRIES;        /* initialize retry count */
962    while ( (rc = k2pm_start_streaming(&seqnum, 1)) != K2R_POSITIVE)
963    {      /* loop while function fails */
964      if (--count <= 0)
965      {         /* too many attempts; indicate failure */
966        sprintf (msg_txt, "Error starting K2 serial data stream output: %s",argv[1]);
967        k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
968        k2ew_exit(0);               /* exit program with code value */
969      }
970    }
971    if (gcfg_debug > 0)
972      logit("et","Started K2 acquisition and serial data stream output\n");
973  }
974
975  /* wait for start of data */
976  if (k2c_rcvflg_tout(gcfg_commtimeout_itvl) == K2R_ERROR)
977  {
978    sprintf (msg_txt, "No stream data seen from K2 on startup: %s",argv[1]);
979    k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
980    k2ew_exit(0);               /* exit program with code value */
981  }
982
983  /* install handler function for various "signal" events */
984  signal(SIGINT,k2ew_signal_hdlr);     /* <Ctrl-C> interrupt */
985  signal(SIGTERM,k2ew_signal_hdlr);    /* program termination request */
986#ifdef SIGBREAK
987  signal(SIGBREAK,k2ew_signal_hdlr);   /* keyboard break (sent by logoff & "X") */
988#endif
989  signal(SIGABRT,k2ew_signal_hdlr);    /* abnormal termination */
990  signal(SIGFPE,k2ew_signal_hdlr);     /* arithmetic error */
991#ifdef SIGPIPE
992  signal(SIGPIPE, SIG_IGN);            /* Ignore SIGPIPE if we have it */
993#endif
994
995  /* install handler to intercept/ignore the Windows CTRL_LOGOFF_EVENT */
996#ifdef _WINNT
997  SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE ); 
998#endif _WINNT
999
1000  logit("et","Beginning K2 data processing...\n");
1001
1002  /* startup the output thread */
1003  if (StartThread(k2ew_outputthread_fn, (unsigned)0, &g_output_threadid) == -1)
1004  {
1005    sprintf (msg_txt, "Unable to startup output thread--aborting: %s",argv[1]);
1006    k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
1007    k2ew_exit(0);                 /* exit program with code value */
1008  }
1009
1010  /* read data blocks */
1011  k2ew_signal_val = -1;      /* initialize signal ID from handler function */
1012  g_pktout_okcount =         /* initialize packets-delivered-OK count */
1013    g_seq_errcnt =             /* initialize output sequence error count */
1014    missing_errcnt =           /* initialize "missing packets" error count */
1015    unexpect_errcnt =          /* initialize "unexpected packet" error count */
1016    g_skip_errcnt =            /* initialize "packet skipped" error count */
1017    request_errcnt =           /* initialize "request resend" error count */
1018    resync_errcnt =            /* initialize "resync" error count */
1019    packet_errcnt =            /* initialize "packet data" error count */
1020    receive_errcnt =           /* initialize "received data" error count */
1021    retried_pckcnt =           /* initialize "# of packet retries" count */
1022    pktin_okcount =            /* initialize packets-received-OK count */
1023    last_pktin_okcount =       /* init 'last' packets-received-OK count */
1024    last_pktout_okcount =      /* init 'last' packets-sent-OK count */
1025    last_seq_errcnt =          /* init 'last' sequence error count */
1026    last_retried_pckcnt =      /* init 'last' "# of packet retries" count */
1027    comm_retries =              /* init # of communications retries count */
1028    last_missing_errcnt = 0L;  /* init 'last' missing packets error count */
1029  g_req_pend = 0;              /* initialize pending request count */
1030  cb_rc = K2R_NO_ERROR;      /* initialize circular buffer fn return code */
1031  rerequest_idnum = K2CB_DBFIDX_NONE;       /* init re-request ID number */
1032  g_terminate_flg = 0;       /* initialize program-terminate flag */
1033
1034  /********************** Main Packet Loop ****************************/
1035  do          /* loop while reading serial data stream packets */
1036  {
1037    time(&timevar);
1038
1039         /* Request a status report from K2, if it's time */
1040    if(gcfg_status_itvl > 0 && difftime(timevar,last_stat_time) >
1041                                                   (double)gcfg_status_itvl)
1042    {
1043                                  /* send request for status packet */
1044      if((rc=k2mi_req_status(&seqnum)) != K2R_NO_ERROR)
1045        break;          /* if send failed then exit loop (and program) */
1046
1047      if(g_extstatus_avail &&     /* if OK then send req for ext status */
1048                           (rc=k2mi_req_extstatus(&seqnum)) != K2R_NO_ERROR)
1049      {  /* sending of request failed */
1050        break;          /* exit loop (and program) */
1051      }
1052
1053      /* Get K2 params for status report, and to check K2 station *
1054       * name against restart-file station name.                  */
1055      if ( (rc = k2mi_req_params(&seqnum)) != K2R_NO_ERROR)
1056        break;
1057
1058      if(last_stat_time > 0)
1059      {  /* not the first time through */
1060        unsigned long okcnt,rtycnt;
1061              /* log "in-process" summary stats */
1062        logit("et","In-Process Summary:\n");
1063        gmtime_ew(&prog_start_time,&tmblk);      /* conv & log start time */
1064        logit("e","Program start time:  %4d%02d%02d_UTC_%02d:%02d:%02d\n",
1065                (tmblk.tm_year+TM_YEAR_CORR),(tmblk.tm_mon+1),tmblk.tm_mday,
1066                                   tmblk.tm_hour,tmblk.tm_min,tmblk.tm_sec);
1067        logit("e","Count totals:\n-------------\n");
1068        logit("e","# of packets received OK    :  %lu\n",pktin_okcount);
1069        logit("e","# of packets sent to EW     :  %lu\n",g_pktout_okcount);
1070        logit("e","# of output sequence errors :  %lu\n",g_seq_errcnt);
1071        if(g_seq_errtime > (time_t)0)
1072        {     /* last output sequence error time has been filled in */
1073          gmtime_ew(&g_seq_errtime,&tmblk);                /* convert time */
1074          logit("e","Time of last output seq err :  "      /* log GM time */
1075                    "%4d%02d%02d_UTC_%02d:%02d:%02d\n",
1076                (tmblk.tm_year+TM_YEAR_CORR),(tmblk.tm_mon+1),tmblk.tm_mday,
1077                                   tmblk.tm_hour,tmblk.tm_min,tmblk.tm_sec);
1078        }
1079        logit("e","Number of packet retries    :  %lu\n",retried_pckcnt);
1080        logit("e","Packet error rating         :  %1.3lf%%\n",
1081                                                        ((pktin_okcount!=0)?
1082                           (double)retried_pckcnt/pktin_okcount*100.0:0.0));
1083        logit("e","Missing packet(s) events    :  %lu\n",missing_errcnt);
1084        logit("e","Number of packets skipped   :  %lu\n",g_skip_errcnt);
1085        logit("e","Request resend failures     :  %lu\n",request_errcnt);
1086        logit("e","Number of stream resyncs    :  %lu\n",resync_errcnt);
1087        logit("e","Number of comm timeouts     :  %lu\n",comm_retries);
1088        logit("e","Since last summary:\n------------------\n");
1089        logit("e","# of packets received OK    :  %lu\n",
1090                                  (okcnt=pktin_okcount-last_pktin_okcount));
1091        logit("e","# of packets sent to EW     :  %lu\n",
1092                                      g_pktout_okcount-last_pktout_okcount);
1093        logit("e","# of output sequence errors :  %lu\n",
1094                                              g_seq_errcnt-last_seq_errcnt);
1095        logit("e","Number of packet retries    :  %lu\n",
1096                               (rtycnt=retried_pckcnt-last_retried_pckcnt));
1097        logit("e","Packet error rating         :  %1.3lf%%\n",((okcnt!=0)?
1098                                           (double)rtycnt/okcnt*100.0:0.0));
1099        logit("e","Missing packet(s) events    :  %lu\n",
1100                                        missing_errcnt-last_missing_errcnt);
1101        last_pktin_okcount = pktin_okcount;           /* set 'last' vars */
1102        last_pktout_okcount = g_pktout_okcount;       /*  for next time  */
1103        last_seq_errcnt = g_seq_errcnt;
1104        last_retried_pckcnt = retried_pckcnt;
1105        last_missing_errcnt = missing_errcnt;
1106        /* if we are injecting status info for k2ewagent, populate a comm info struct and send it */
1107        if (gcfg_inject_info==1)
1108        {
1109            struct COMM_INFO ci;
1110            ci.program_start_time=prog_start_time;
1111            ci.last_info_time=last_stat_time;
1112            time(&ci.comm_info_time);
1113            ci.total_pkt_received = pktin_okcount;
1114            ci.total_pkt_sent = g_pktout_okcount;
1115            ci.total_pkt_output_seqerr = g_seq_errcnt;
1116            ci.last_output_seqerr_time = g_seq_errtime;
1117            ci.total_pkt_retries = retried_pckcnt;
1118            ci.total_pkt_skipped = g_skip_errcnt;
1119            ci.total_pkt_request_resend_failure = request_errcnt;
1120            ci.total_comm_retries = comm_retries;
1121            ci.total_pkt_missing_err = missing_errcnt;
1122            ci.total_error_rating = (float) ((pktin_okcount!=0)?(float)retried_pckcnt/pktin_okcount*100.0:0.0);
1123            ci.last_pkt_received = okcnt;
1124            ci.last_pkt_sent = g_pktout_okcount-last_pktout_okcount;
1125            ci.last_pkt_retries = rtycnt;
1126            ci.last_error_rating = (float) (okcnt!=0)?(float)rtycnt/okcnt*100.0:0.0;
1127            k2info_send(K2INFO_TYPE_COMM, (char *) &ci);
1128        }
1129      }
1130
1131      last_stat_time = timevar;
1132    }
1133
1134    if((rc=k2pm_get_stmblk(&datahdr,databuff,&dcount,1)) == K2R_POSITIVE)
1135    {    /* SDS block retrieved OK */
1136      /* Tell the world, maybe */
1137      if(timeout_logged)
1138      {
1139        logit("et", "Resumed communicating with K2\n");
1140        timeout_logged = 0;
1141      }
1142      if(datahdr.StreamNum >= (unsigned char)g_numstms)
1143      {       /* received stream number is out of range */
1144        logit("et", "Received stream number (%d) out of range (1 - %d)\n",
1145              (int)datahdr.StreamNum, g_numstms);
1146        rc = K2ERR_BAD_STMNUM;         /* setup error code */
1147      }
1148      else
1149      {
1150        if (dcount != g_smprate)
1151        {     /* received data count mismatches */
1152          logit("et", "Received datacount (%d) not expected (%d)\n",
1153                dcount, g_smprate);
1154          rc = K2ERR_BAD_DATACNT;      /* setup error code */
1155        }
1156      }
1157    }
1158         /* check if terminate flag set by signal handler */
1159    if(g_terminate_flg)      /* if terminate flag set then */
1160      break;                 /* exit loop (and program) */
1161
1162    /* stream data block received; now deal with it */
1163    if (rc == K2R_POSITIVE )
1164    {    /* SDS block received and checked */
1165      if (gcfg_debug > 2)
1166      {  /* logging level enabled; show message */
1167        logit("et", "Received:  stm#=%hu, dseq=%lu, secs=%lu, ms=%hu\n",
1168                       (unsigned short)(datahdr.StreamNum), datahdr.DataSeq,
1169                                            datahdr.Seconds, datahdr.Msecs);
1170      }
1171
1172      if(gcfg_invpol_arr[datahdr.StreamNum] != 0)
1173      {  /* invert polarity flag for channel (stream) is enabled */
1174        for(count=0; count<dcount; ++count)
1175        {     /* for each data value in array */
1176          databuff[count] *= -1;       /* invert polarity of data value */
1177        }
1178      }
1179
1180      if(datahdr.StreamNum == cur_stmnum && datahdr.DataSeq == cur_dataseq)
1181      {  /* packet stream and data sequence numbers match expected values */
1182                   /* enter received data block into circular buffer */
1183        if((cb_rc=k2cb_block_in(datahdr.StreamNum, datahdr.DataSeq,
1184                                  datahdr.Seconds, datahdr.Msecs, databuff))
1185                                                            != K2R_NO_ERROR)
1186        {          /* error code returned */
1187          break;             /* exit loop (and program) */
1188        }
1189        ++pktin_okcount;          /* increment packet-received-OK count */
1190        /* increment current stream (and data sequence) numbers */
1191        if(++cur_stmnum >= (unsigned char)g_numstms)
1192        {          /* increment puts it past last stream number */
1193          cur_stmnum = (unsigned char)0;  /* wrap-around to first stream number */
1194          ++cur_dataseq;               /* increment data sequence number */
1195        }
1196        last_sec = datahdr.Seconds; /* Save the packet time for later */
1197      }
1198      else
1199      {     /* stream and data sequence numbers do not match "current" */
1200        if ( (idx = K2M_PCKT_RELIDX(datahdr.StreamNum, datahdr.DataSeq)) > 0L)
1201        {   /* packet position is "ahead" of current packet expected */
1202          if(cur_dataseq >= 10)   /* if not one of first packets then */
1203            ++missing_errcnt;     /* inc "missing packets" error count */
1204          if ((int)(datahdr.DataSeq - cur_dataseq) <= gcfg_pktwait_lim)
1205          {      /* packet position is not too far "ahead" of current pkt */
1206            if(gcfg_debug > 0)
1207            {      /* debug output enabled; log message */
1208              logit("et","Detected %ld missing packet", idx);
1209              if ( idx != 1 ) logit( "e", "s" );
1210              logit("e"," (errorcount=%lu)\n", missing_errcnt);
1211            }
1212            if(cur_dataseq >= 10)      /* if not one of first packets then */
1213              retried_pckcnt += idx;   /* add to # of packet retries count */
1214            for (c = 0; c < idx; ++c)
1215            {      /* for each position passed-by */
1216                        /* put a "waiting" block into circular buffer */
1217                        /*  (resend of block will be requested elsewhere) */
1218              if ( (cb_rc = k2cb_blkwait_in(cur_stmnum, cur_dataseq)) !=
1219                                                               K2R_NO_ERROR)
1220              {
1221                break;     /* if error then exit loop */
1222              }
1223              ++g_wait_count;     /* increment waiting list entry count */
1224                   /* increment current stream (and data sequence) numbers */
1225              if (++cur_stmnum >= (unsigned char)g_numstms)
1226              {         /* increment puts it past last stream number */
1227                cur_stmnum = (unsigned char)0;  /* wrap-around to 0 */
1228                ++cur_dataseq;              /* increment data sequence number */
1229              }
1230            }
1231          }
1232          else   /* packet position is too far "ahead" of current packet; */
1233          {
1234            ++resync_errcnt;           /* increment "resync" error count */
1235            /*  show message and resync to new packet position */
1236            logit("et","Too many missing packets (%ld) detected "
1237                  "(errorcount=%lu)\nResync-ing (count=%lu) to:  "
1238                  "stm#=%hu, dseq=%lu, secs=%lu\n", idx,
1239                  missing_errcnt, resync_errcnt,
1240                  (unsigned short)(datahdr.StreamNum),
1241                  datahdr.DataSeq, datahdr.Seconds);
1242            k2cb_check_waits((unsigned long)-1); /* Clear all wait pkts */
1243          }
1244              /* put "current" packet position in sync with received */
1245          cur_stmnum = datahdr.StreamNum;    /* take new stream number */
1246          cur_dataseq = datahdr.DataSeq;     /* take new data sequence # */
1247              /* enter received data block into circular buffer */
1248          if((cb_rc=k2cb_block_in(datahdr.StreamNum, datahdr.DataSeq,
1249                                             datahdr.Seconds, datahdr.Msecs,
1250                                                 databuff)) != K2R_NO_ERROR)
1251          {      /* error code returned */
1252            break;           /* exit loop (and program) */
1253          }
1254          ++pktin_okcount;        /* increment packet-received-OK count */
1255          /* increment current stream (and data sequence) numbers */
1256          if (++cur_stmnum >= (unsigned char)g_numstms)
1257          {      /* increment puts it past last stream number */
1258            cur_stmnum = (unsigned char)0;
1259            ++cur_dataseq;           /* increment data sequence number */
1260          }
1261          last_sec = datahdr.Seconds; /* Save the packet time for later */
1262        }
1263        else
1264        {   /* packet position is "behind" current packet expected */
1265          if((rc=k2cb_fill_waitblk(datahdr.StreamNum, datahdr.DataSeq,
1266                                    datahdr.Seconds, datahdr.Msecs,databuff,
1267                                         &rerequest_idnum)) == K2R_NO_ERROR)
1268          {      /* "waiting" block filled OK */
1269            if(g_wait_count > 0)  /* if count greater than zero then */
1270              --g_wait_count;     /* decrement waiting list entry count */
1271            if(g_req_pend > 0)    /* if count greater than zero then */
1272              --g_req_pend;       /* decrement pending request count */
1273            ++pktin_okcount;      /* increment packet-received-OK count */
1274            if(gcfg_debug > 0)
1275            {
1276              logit("et","\"Waiting\" data block received:  stm#=%hu, "
1277                    "dseq=%lu, secs=%lu, ms=%hu\n",
1278                    (unsigned short)(datahdr.StreamNum),
1279                    datahdr.DataSeq, datahdr.Seconds, datahdr.Msecs);
1280            }
1281          }
1282          else
1283          {      /* "waiting" block not filled */
1284            if(rc == K2ERR_CB_NOTFOUND)
1285            {    /* no matching "waiting" block was found */
1286              /* Is this packet time later than the last known packet time?
1287               * If so, the K2 has reset its sequence number. We will
1288               * enter this packet in the CB, and reset our counters for
1289               * the next packet. We also need to clear out the CB of old
1290               * wait packets, since the K2 doesn't recognize their sequence
1291               * numbers any more.
1292               */
1293              if (datahdr.Seconds > last_sec)
1294              {
1295                logit("et",
1296                      "K2 sequence number reset; updating k2ew sequence numbers\n",
1297                      "\tand clearing old wait entries from circular buffer\n");
1298                ++resync_errcnt;           /* increment "resync" error count */
1299                sprintf(msg_txt, "K2 <%s> has restarted", g_stnid);
1300                k2mi_status_hb(g_error_ltype, K2STAT_RESTART, msg_txt);
1301                k2cb_check_waits((unsigned long)-1);  /* Clear wait pkts */
1302                   /* put "current" packet position in sync with received */
1303                cur_stmnum = datahdr.StreamNum;    /* take new stream number */
1304                cur_dataseq = datahdr.DataSeq;     /* take new data sequence # */
1305                   /* enter received data block into circular buffer */
1306                if((cb_rc=k2cb_block_in(datahdr.StreamNum, datahdr.DataSeq,
1307                                             datahdr.Seconds, datahdr.Msecs,
1308                                                 databuff)) != K2R_NO_ERROR)
1309                {      /* error code returned */
1310                  break;           /* exit loop (and program) */
1311                }
1312                ++pktin_okcount;        /* increment packet-received-OK count */
1313                /* increment current stream (and data sequence) numbers */
1314                if (++cur_stmnum >= (unsigned char)g_numstms)
1315                {      /* increment puts it past last stream number */
1316                  cur_stmnum = (unsigned char)0;
1317                  ++cur_dataseq;           /* increment data sequence number */
1318                }
1319                last_sec = datahdr.Seconds; /* Save packet time for later */
1320              }
1321              else
1322              {
1323                ++unexpect_errcnt;       /* inc "unexpected pkt" error count */
1324                if (gcfg_debug > 0)
1325                   logit("et","Unexpected data block (count=%lu) received "
1326                         "and discarded:  stm#=%hu, dseq=%lu, secs=%lu, "
1327                         "ms=%hu\n", unexpect_errcnt,
1328                         (unsigned short)(datahdr.StreamNum),
1329                         datahdr.DataSeq, datahdr.Seconds, datahdr.Msecs);
1330              }
1331            }
1332            else
1333            {    /* other (more serious) error code returned */
1334              cb_rc = rc;       /* save code for processing below */
1335              break;            /* exit loop (and program) */
1336            }
1337          }
1338        }
1339      }
1340
1341      /* update "tick" counters on any waiting blocks in circ buffer */
1342      if((idnum=k2cb_tick_waitents(wait_resenditvl,&stmnum,&dataseq,
1343                                 &numticks,&resendcnt)) == K2CB_DBFIDX_NONE)
1344      {  /* waiting list empty; make sure resend request counter agrees */
1345        g_req_pend = 0;
1346      }
1347      if(rerequest_idnum != K2CB_DBFIDX_NONE)
1348      {  /* re-request of waiting packet was specified */
1349                             /* get information for re-requested packet */
1350        if(k2cb_get_entry(rerequest_idnum,&rr_stmnum,&rr_dataseq,NULL,
1351                                             &rr_resendcnt) == K2R_POSITIVE)
1352        {     /* waiting list not empty & info on re-req packet fetched OK */
1353          idnum = K2CB_DBFIDX_NONE;    /* clear to avoid request below */
1354          if(++rr_resendcnt > 1)       /* inc (local) resend req count */
1355            ++retried_pckcnt;          /* if > 1 then inc retried pck cnt */
1356          if (gcfg_debug > 0)
1357          {        /* debug is enabled; show message */
1358            logit("et","Re-requesting resend (#%d) of packet:  stm#=%d, "
1359                       "dseq=%lu (pending=%d)\n",rr_resendcnt,
1360                                    (int)rr_stmnum,rr_dataseq,g_req_pend);
1361          }
1362          if((rc=k2pm_req_stmblk(rr_stmnum,rr_dataseq,1)) != K2R_NO_ERROR)
1363          {      /* resend-request function returned error */
1364            ++request_errcnt;        /* inc "request resend" error count */
1365            logit("et","Error (count=%lu) requesting resend of packet "
1366                  "(stm#=%d, dseq=%lu)\n",request_errcnt,
1367                  (int)rr_stmnum,rr_dataseq);
1368
1369          }
1370                        /* increment resend and clear tick count for block */
1371          if (k2cb_incwt_resendcnt(rerequest_idnum) != K2R_POSITIVE)
1372          {
1373            logit("et", "IDnum (%d) not found by 'k2cb_incwt_resendcnt()'\n",
1374                                                           rerequest_idnum);
1375          }
1376        }
1377        else
1378        {
1379          logit("et", "IDnum (%d) not found by 'k2cb_get_entry()'\n",
1380                                                           rerequest_idnum);
1381        }
1382        rerequest_idnum = K2CB_DBFIDX_NONE;      /* clear specifier */
1383      }
1384      if(idnum != K2CB_DBFIDX_NONE)
1385      {       /* waiting list not empty */
1386        if(resendcnt == 0 || numticks >= wait_resenditvl)
1387        {     /* no resend-requests have yet happened or time for next one */
1388          if(++resendcnt <= gcfg_max_blkresends)
1389          {   /* not too many resend requests so far (for this block) */
1390                   /* if this is not the first resend request for block */
1391                   /*  then bypass the 'MaxReqPending' limit and push   */
1392                   /*  this resend request through                      */
1393            if(resendcnt <= 1)
1394            {      /* this is first resend request for block */
1395              if(g_req_pend >= gcfg_max_reqpending)
1396              {    /* at or beyond maximum allowed new resend requests */
1397                if(no_req == 0)
1398                {       /* new resent requests are currently enabled */
1399                  no_req = 1;     /* stop new resend requests for now */
1400                  if(gcfg_debug > 1)
1401                  {
1402                    logit("et","New resend requests paused (%d waiting)\n",
1403                                                                g_req_pend);
1404                  }
1405                }
1406              }
1407              else if(no_req != 0 && g_req_pend <= resume_numpend)
1408              {    /* new resend requests may now be resumed */
1409                no_req = 0;
1410                if(gcfg_debug > 1)
1411                {
1412                  logit("et","New resend requests resumed (%d waiting)\n",
1413                                                                g_req_pend);
1414                }
1415              }
1416            }
1417            if(no_req == 0 || resendcnt > 1)
1418            {      /* new resend reqs are enabled or not first for block */
1419              if(resendcnt <= 1)  /* if first resend for block then */
1420                ++g_req_pend;     /* inc total # of resend req count */
1421
1422              /* if there is a resend request, then we need to make sure the serial port has control,
1423                not sure we need to do this EACH resend request ,
1424                so, only do this if we haven't succeeded in forcing it in the last FORCE_TIMEOUT_CHECK secs or
1425                        if we last_attempted to force it within 10 seconds of the last time we tried */
1426
1427#define FORCE_TIMEOUT_CHECK 20  /* this is in seconds */
1428
1429              time(&now);
1430              if (gcfg_force_blkmde == 1 && ((now - last_force_block) > FORCE_TIMEOUT_CHECK) ) 
1431              {
1432                 if( (now - last_attempted_force_block >= 10) && k2mi_force_blkmde() == K2R_ERROR)
1433                 {     
1434                   logit ("et", "Unable to force block mode with K2 as requested for resend requests\n");
1435                   time(&last_attempted_force_block);
1436                   continue;
1437                 } else {
1438                   logit("et","Forced block mode with K2 for resend requests, will not try again for %d secs\n", FORCE_TIMEOUT_CHECK);
1439                   time(&last_force_block);
1440                 }
1441              }
1442              if (gcfg_debug > 0)
1443              {
1444                logit("et","Requesting resend (#%d) of packet:  stm#=%d, "
1445                    "dseq=%lu (pending=%d)\n",resendcnt,(int)stmnum,dataseq,
1446                                                                g_req_pend);
1447              }
1448              if((rc=k2pm_req_stmblk(stmnum, dataseq, 1)) != K2R_NO_ERROR)
1449              {      /* resend-request function returned error */
1450                ++request_errcnt;        /* inc "request resend" error count */
1451                logit("et","Error (count=%lu) requesting resend of packet "
1452                      "(stm#=%d, dseq=%lu)\n",request_errcnt,
1453                      (int)stmnum, dataseq);
1454
1455              }
1456                        /* increment resend and clear tick count for block */
1457              if (k2cb_incwt_resendcnt(idnum) != K2R_POSITIVE)
1458              {
1459                logit("et", "IDnum (%d) not found by k2cb_incwt_resendcnt\n",
1460                                                                     idnum);
1461              }
1462              if(resendcnt > 1)        /* if resend req count > 1 then   */
1463                ++retried_pckcnt;      /* increment retried packet count */
1464            }
1465          }
1466          else
1467          {   /* too many resends have occurred; change status to "skip" */
1468            ++g_skip_errcnt;      /* inc "packet skipped" error count */
1469            ++retried_pckcnt;     /* increment retried packet count */
1470            logit("et","Excessive resend count (skipcount=%lu), "
1471                  "skipping:  stm#=%d, dseq=%lu\n",g_skip_errcnt,
1472                  (int)stmnum, dataseq);
1473            /* set wait entry to "skip" */
1474            if (k2cb_skip_waitent(stmnum,dataseq) != K2R_POSITIVE)
1475            {
1476              logit("et", "k2cb_skip_waitent unable to find entry: "
1477                  "stm#=%d, dseq=%lu\n",(int)stmnum,dataseq);
1478            }
1479            else
1480            {
1481              if(g_wait_count > 0)     /* if count greater than zero then */
1482                --g_wait_count;        /* decrement waiting list entry count */
1483            }
1484          }
1485        }
1486      }
1487    }
1488    else
1489    {    /* error retrieving SDS block or number of data entries mismatches */
1490      if(rc != K2R_ERROR && rc != K2R_TIMEOUT)
1491      {       /* returned code is not one the "fatal" errors */
1492        if(rc == K2R_PAYLOAD_ERR || rc == K2ERR_BAD_STMNUM ||
1493                                                    rc == K2ERR_BAD_DATACNT)
1494        {     /* SDS packet was received and its header interpreted OK   */
1495              /*  but there was an error in its payload data, its stream */
1496              /*  number was out of range, its data count was wrong, its */
1497              /*  data size was wrong or its CRC was bad                 */
1498          ++packet_errcnt;       /* increment "packet data" error count */
1499          logit("et","Error %d (count=%lu) on received packet (stm#=%hu, "
1500                     "dseq=%lu)\n", rc, packet_errcnt,
1501                       (unsigned short)(datahdr.StreamNum),datahdr.DataSeq);
1502          if(rerequest_idnum == K2CB_DBFIDX_NONE &&
1503              datahdr.StreamNum > (unsigned char)0 && datahdr.DataSeq > 0 &&
1504                                         (datahdr.StreamNum != cur_stmnum ||
1505                                            datahdr.DataSeq != cur_dataseq))
1506          {        /* no re-request of wait block pending, stream  */
1507                   /*  and data sequence number of received packet */
1508                   /*  are valid and packet is not "current"       */
1509            rerequest_idnum =          /* look for matching waiting entry */
1510                        k2cb_get_waitent(datahdr.StreamNum,datahdr.DataSeq);
1511          }
1512        }
1513        else
1514        {     /* received data not recognized as SDS packet */
1515          ++receive_errcnt;       /* increment "received data" error count */
1516          logit("et","Error (count=%lu) processing received data\n",
1517                receive_errcnt);
1518        }
1519      }
1520      else if (rc == K2R_TIMEOUT)
1521      {
1522        if (gcfg_dont_quit == 0)
1523        {
1524          g_terminate_flg = 1;  /* Tell the output thread to terminate */
1525          sprintf (msg_txt, "Timed out communicating with K2, aborting %s: %s",g_stnid, argv[1]);
1526          k2ew_enter_exitmsg(K2TERM_K2_COMMERR,   msg_txt); /* log & enter exit message */
1527          break;                   /* exit loop (and program) */
1528        }
1529        else  /* gcfg_dont_quit == 1 */
1530        {
1531          if (timeout_logged == 0)
1532          {   /* this is a "new" timeout event */
1533            comm_retries++;
1534            logit("et", "Timed out communicating with K2; continuing\n");
1535            timeout_logged = 1;
1536            if(gcfg_restart_commflag != 0)
1537            {      /* flag is set; close and then reopen comm to K2 */
1538              logit("et","Closing and reopening communications with K2"
1539                         " after timeout\n");
1540              k2c_close_io();         /* close IO port */
1541                                      /* reopen IO port */
1542                   /* Initialize IO to the K2: sockets or serial comms */
1543              if((rc=k2c_init_io(&gen_io,gcfg_commtimeout_itvl)) !=
1544                                                               K2R_NO_ERROR)
1545              {    /* comms initialization failed */
1546                sprintf (msg_txt, "Unable to reopen IO port for %s: %s",g_stnid, argv[1]);
1547                k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
1548                break;                 /* exit loop (and program) */
1549              }
1550              if (gcfg_force_blkmde == 1) 
1551              {
1552                 if(k2mi_force_blkmde() < K2R_NO_ERROR)
1553                 {     
1554                   logit ("et", "Unable to force block mode with K2 as requested");
1555                   break;
1556                 }
1557                 logit("et","Forced block mode with K2\n");
1558                 time(&last_force_block);
1559              }
1560              /* confirm or restart block mode in the K2: */
1561              if(k2mi_init_blkmde(&seqnum) < K2R_NO_ERROR)
1562              {    /* error code returned; show error msg and exit prog */
1563                sprintf (msg_txt, "Unable to re-establish communications link with K2 %s: %s",
1564                        g_stnid, argv[1]);
1565                k2ew_enter_exitmsg(K2TERM_K2_STARTUP, msg_txt);
1566                break;                 /* exit loop (and program) */
1567              }
1568              logit("et", "Communications with K2 reopened OK\n");
1569            }
1570          }
1571        }
1572      }
1573      else
1574      {
1575        g_terminate_flg = 1;  /* Tell the output thread to terminate */
1576        sprintf (msg_txt, "Error communicating with K2 %s, aborting: %s",
1577                        g_stnid, argv[1]);
1578        k2ew_enter_exitmsg(K2TERM_K2_COMMERR,  msg_txt);  /* log & enter exit message */
1579        break;                   /* exit loop (and program) */
1580      }
1581    }
1582
1583    if (cb_rc != K2R_NO_ERROR)   /* if circular buffer write fn error then */
1584    {
1585      g_terminate_flg = 1;  /* Tell the output thread to terminate */
1586      break;                      /* exit loop (and program) */
1587    }
1588
1589    /* check from terminate request from Earthworm */
1590    if ( tport_getflag(&g_tport_region) == TERMINATE  ||
1591         tport_getflag(&g_tport_region) == g_pidval     )
1592    {         /* terminate request received */
1593      g_terminate_flg = 1;
1594      sprintf (msg_txt, "Terminate request received from Earthworm for %s, Exiting: %s",
1595                        g_stnid, argv[1]);
1596      k2ew_enter_exitmsg(K2TERM_EW_TERM,  msg_txt);     /* log & enter exit message */
1597      break;                      /* exit loop (and program) */
1598    }
1599
1600  }
1601  while (g_terminate_flg == 0);     /* loop until terminate flag is set */
1602  /************************* End of Main Loop *************************/
1603
1604  if (k2ew_signal_val != -1)
1605  {      /* loop termination was caused by "signal" event */
1606    char sigstr[32];
1607    k2ew_signal_string( k2ew_signal_val, sigstr, 32 );
1608    sprintf (msg_txt, "Signal %s detected. Exiting program: %s", 
1609                       sigstr, argv[1]);
1610    k2ew_enter_exitmsg(K2TERM_SIG_TRAP, msg_txt);
1611  }
1612  else
1613  {
1614    if (cb_rc != K2R_NO_ERROR)
1615    {    /* circular buffer write function returned error code */
1616      /* Dump the circular buffer indexes to file for debugging */
1617      k2cb_dump_buf();
1618
1619      k2ew_enter_exitmsg(K2TERM_K2_CIRBUFF,        /* log & enter exit message */
1620                             "Error writing to circular data buffer:  %s for %s\n",
1621                                                    k2ew_get_errmsg(cb_rc), argv[1]);
1622    }
1623  }
1624
1625  logit("et","Ending K2 data processing\n");
1626  sleep_ew(1500);  /* give the output thread some time to write restart file */
1627  if (gcfg_debug > 1)
1628    logit("e", "shutdown indicators rc %d, rsfile %s\n", rc,
1629          gcfg_restart_filename);
1630
1631  /* If there's no restartfile, or if we have an error other than due to
1632   * a handled signal, turn off streaming on the K2 */
1633  if (gcfg_restart_filename[0] == '\0' ||
1634      ( rc == K2R_ERROR && k2ew_signal_val == -1))
1635  {
1636    /* stop streaming and acquiring */
1637    logit("et", "Shutting down stream output...\n");
1638    count = K2_NUM_RETRIES;        /* initialize retry count */
1639    while(1)
1640    {      /* loop while function fails */
1641      if ( (rc = k2pm_stop_streaming(&seqnum, 0)) == K2R_POSITIVE)
1642      {    /* function succeeded; show OK message */
1643        logit("et","Stopped K2 serial data stream output\n");
1644        break;            /* exit loop */
1645      }
1646      if (--count <= 0)
1647      {         /* too many attempts; indicate failure */
1648        logit("et","Error stopping K2 serial data stream output\n");
1649        break;            /* exit loop */
1650      }
1651    }
1652  }
1653  else
1654    if (gcfg_debug)
1655      logit("et", "Leaving K2 in streaming mode\n");
1656
1657  logit("et","End of Program Summary:\n");
1658  gmtime_ew(&prog_start_time,&tmblk);       /* conv & log start time */
1659  logit("e","Program start time:  %4d%02d%02d_UTC_%02d:%02d:%02d\n",
1660                (tmblk.tm_year+TM_YEAR_CORR),(tmblk.tm_mon+1),tmblk.tm_mday,
1661                                   tmblk.tm_hour,tmblk.tm_min,tmblk.tm_sec);
1662  logit("e","Count totals:\n-------------\n");
1663  logit("e","# of packets received OK    :  %lu\n",pktin_okcount);
1664  logit("e","# of packets lost           :  %lu\n",
1665                                   (cur_dataseq-rstrt_dataseq) * g_numstms +
1666                                 (cur_stmnum-rstrt_stmnum) - pktin_okcount);
1667  logit("e","# of packets sent to EW     :  %lu\n",g_pktout_okcount);
1668  logit("e","# of output sequence errors :  %lu\n",g_seq_errcnt);
1669  if(g_seq_errtime > (time_t)0)
1670  {      /* last output sequence error time has been filled in */
1671    gmtime_ew(&g_seq_errtime,&tmblk);                 /* convert time */
1672    logit("e","Time of last output seq err :  "       /* log GM time */
1673              "%4d%02d%02d_UTC_%02d:%02d:%02d\n",
1674                (tmblk.tm_year+TM_YEAR_CORR),(tmblk.tm_mon+1),tmblk.tm_mday,
1675                                   tmblk.tm_hour,tmblk.tm_min,tmblk.tm_sec);
1676  }
1677  logit("e","Number of packet retries    :  %lu\n",retried_pckcnt);
1678  logit("e","Packet error rating         :  %1.3lf%%\n",
1679       ((pktin_okcount!=0)?(double)retried_pckcnt/pktin_okcount*100.0:0.0));
1680  logit("e","Missing packet(s) events    :  %lu\n",missing_errcnt);
1681  logit("e","Number of packets skipped   :  %lu\n",g_skip_errcnt);
1682  logit("e","Request resend failures     :  %lu\n",request_errcnt);
1683  logit("e","Number of stream resyncs    :  %lu\n",resync_errcnt);
1684  logit("e","Number of unexpected packets:  %lu\n",unexpect_errcnt);
1685  logit("e","Bad received data count     :  %lu\n",receive_errcnt);
1686  logit("e","Bad packet data count       :  %lu\n",packet_errcnt);
1687
1688  if (cb_rc)
1689    k2ew_exit(1);        /* do a core dump for circ. buffer errors */
1690  else
1691    k2ew_exit(0);        /* exit program (with cleanup & 'statmgr' msg) */
1692  return 0;              /* "return" statement to keep compiler happy */
1693}
1694
1695
1696/**************************************************************************
1697 * k2ew_signal_hdlr:  function to handle "signal" events                  *
1698 *         signum - ID value of signal that caused event                  *
1699 **************************************************************************/
1700
1701void k2ew_signal_hdlr(int signum)
1702{
1703  signal(signum,k2ew_signal_hdlr);     /* call fn to reset signal handling */
1704  k2ew_signal_val = signum;            /* save signal ID value */
1705  g_terminate_flg = 1;                 /* set flag to terminate program */
1706}
1707
1708/**************************************************************************
1709 * k2ew_signal_string:  function to provide a meaningful character string *
1710 *                      to "signal" events which are being handled        *
1711 **************************************************************************/
1712
1713void k2ew_signal_string( int signum, char *str, int len )
1714{
1715  if     (signum==SIGINT  ) strncpy( str, "SIGINT (ctrl-C)",                len-1 );
1716  else if(signum==SIGTERM ) strncpy( str, "SIGTERM (termination request)",  len-1 );
1717  else if(signum==SIGABRT ) strncpy( str, "SIGABRT (abnormal termination)", len-1 );
1718  else if(signum==SIGFPE  ) strncpy( str, "SIGFPE (arithmetic error)",      len-1 );
1719#ifdef SIGBREAK
1720  else if(signum==SIGBREAK) strncpy( str, "SIGBREAK (console closed)",      len-1 );
1721#endif
1722  else                      sprintf( str, "event (%d)", signum );
1723  str[len-1] = 0;
1724}
1725
1726/**************************************************************************
1727 * k2ew_log_cfgparams:  logs the configuration parameters                 *
1728 **************************************************************************/
1729
1730void k2ew_log_cfgparams()
1731{
1732  int i;
1733
1734  logit("et","Configuration file command values:\n");
1735  switch (gen_io.mode)
1736  {
1737    case IO_COM_NT:
1738      logit("e","Using <COM%d> at %d baud\n",gen_io.com_io.commsel,
1739            gen_io.com_io.speed );
1740      break;
1741    case IO_TCP:
1742      logit("e", "Using TCP address <%s> and port %d\n",
1743            gen_io.tcp_io.k2_address, gen_io.tcp_io.k2_port );
1744      break;
1745    case IO_TTY_UN:
1746      logit("e", "Using TTY port <%s> at %d baud\n", gen_io.tty_io.ttyname,
1747            gen_io.tty_io.speed);
1748    break;
1749  }
1750  logit("e","ModuleId=\"%s\" (%d), RingName=\"%s\" (%ld), HeartbeatInt=%d\n",
1751                     gcfg_module_name,(int)gcfg_module_idnum,gcfg_ring_name,
1752                                         gcfg_ring_key,gcfg_heartbeat_itvl);
1753  logit("e","LogFile=%d, Debug=%d\n",gcfg_logfile_flgval,gcfg_debug);
1754  logit("e","CommTimeout=%d, WaitTime=%d\n",gcfg_commtimeout_itvl,
1755                                                          gcfg_pktwait_lim);
1756  logit("e","DontQuit=%d, RestartComm=%d\n",gcfg_dont_quit,
1757                                                     gcfg_restart_commflag);
1758  logit("e","RestartFile=\"%s\", MaxRestartAge=%d\n",gcfg_restart_filename,
1759                                                       gcfg_restart_maxage);
1760  logit("e","MaxBlkResends=%d, WaitResendVal=%d\n",
1761                                   gcfg_max_blkresends,gcfg_wait_resendval);
1762  logit("e","MaxReqPending=%d, ResumeReqVal=%d\n",
1763                                    gcfg_max_reqpending,gcfg_resume_reqval);
1764  logit("e","Network=\"%s\", ",gcfg_network_buff );
1765  logit("e","BasePinno=%d\n", gcfg_base_pinno);
1766  logit("e","StatusInterval=%d, ExtStatus=%d\n",gcfg_status_itvl/60,
1767                                                           gcfg_ext_status);
1768  logit("e","HighTempAlarm=%d, LowTempAlarm=%d, LowBattAlarm=%d\n",
1769                    gcfg_temphi_alarm,gcfg_templo_alarm,gcfg_battery_alarm);
1770  logit("e","OnBattery=%d, MinDiskKB=%.0lf,%.0lf\n",gcfg_on_batt,
1771                           gcfg_disk_alarm[0]/1024,gcfg_disk_alarm[1]/1024);
1772  logit("e","StationID=\"%s\"\n",gcfg_stnid_remap);
1773  logit("e","ChannelNames=");
1774  i = 0;
1775  while(1)
1776  {      /* for each channel (stream) name */
1777    if(gcfg_chnames_arr[i] != NULL)
1778      logit("e","\"%s\"",gcfg_chnames_arr[i]);
1779    else
1780      logit("e","\"\"");
1781    if(++i >= K2_MAX_STREAMS)     /* if no more channels then */
1782      break;                      /* exit loop */
1783    logit("e",",");               /* put in separator */
1784  }
1785  logit("e","\n");
1786  logit("e","LocationNames=");
1787  i = 0;
1788  while(1)
1789  {      /* for each channel (stream) name */
1790    if(gcfg_locnames_arr[i] != NULL)
1791      logit("e","\"%s\"",gcfg_locnames_arr[i]);
1792    else
1793      logit("e","\"\"");
1794    if(++i >= K2_MAX_STREAMS)     /* if no more channels then */
1795      break;                      /* exit loop */
1796    logit("e",",");               /* put in separator */
1797  }
1798  logit("e","\n");
1799  logit("e","InvPolFlags=");
1800  i = 0;
1801  while(1)
1802  {      /* for each channel (stream) */
1803    logit("e","%d",gcfg_invpol_arr[i]);
1804    if(++i >= K2_MAX_STREAMS)     /* if no more channels then */
1805      break;                      /* exit loop */
1806    logit("e",",");               /* put in separator */
1807  }
1808  logit("e","\n");
1809}
1810
Note: See TracBrowser for help on using the repository browser.