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

Revision 3001, 82.7 KB checked in by dietz, 12 years ago (diff)

Changed version to 2.42 to reflect previous Windows Service-friendly mods

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