/****************************************************************************
**
**  Name:  trace.c
**
**  Description:
**     Routines to handle the trace data displaying setup, manages the host
**     trace files and to interface with the trace acquisition drivers.
**
**  Status:  PRELIMINARY
**
**  $Log:   S:/tbird/mt2_68k/trace/trace.c_v  $
** 
**    Rev 1.16   03 Mar 1998 14:37:54   Winky
** Modify FormatFrameToText function, mask 0x0ff -> 0x03.
** 
**    Rev 1.15   03 Mar 1998 11:52:22   Eric
** Fixed bug ID#246
** 
**    Rev 1.14   20 Feb 1998 19:04:08   Eric
** Fixed bug ID#241.
** 
**    Rev 1.13   10 Feb 1998 11:46:02   Eric
** Added HW information in collecting buffer.
** 
**    Rev 1.12   23 Dec 1997 11:43:38   Winky
** Add "preFrame" initial into TrcTraceSearch().
** 
**    Rev 1.11   21 Aug 1997 13:45:52   gene
** To fix relative timestamp bug.
** 
**    Rev 1.10   19 Aug 1997 09:31:44   gene
** Added a new function TrcPreFrameTSSet.
** 
**    Rev 1.9   18 Aug 1997 17:31:44   gene
** 
**    Rev 1.8   15 May 1997 15:06:10   gene
** fixed trace CLI command memory leak problem
** 
**    Rev 1.7   25 Apr 1997 18:29:58   gene
** 
**    Rev 1.6   17 Apr 1997 17:06:32   gene
** 
**    Rev 1.5   09 Apr 1997 09:35:40   gene
** 
**    Rev 1.4   31 Mar 1997 09:48:22   gene
** 
**    Rev 1.3   18 Mar 1997 09:04:50   gene
** 
**    Rev 1.2   04 Mar 1997 13:04:40   gene
** 
**    Rev 1.1   17 Feb 1997 16:54:20   gene
** changed for mtat2
** 
**    Rev 1.0   13 Feb 1997 09:07:24   gene
** Initial revision.
** 
**    Rev 1.4   22 Aug 1996 14:32:06   kevin
** fixed problem of forwardcliread()
** 
**    Rev 1.3   29 May 1996 18:06:34   kevin
** modified TrcCliReadRaw() to show uGroup
** 
**    Rev 1.2   19 Jan 1996 09:46:32   kevin
** backup hInstance while initialization
** 
**    Rev 1.1   18 Sep 1995 14:51:50   kevin
** don't change case of signal events
** 
**    Rev 1.0   07 Sep 1995 11:22:26   gene
** Initial revision.
** 
**    Rev 1.91   08 Nov 1993 20:59:10   mindy
** add max trace buffer support
** 
**    Rev 1.90   28 Jul 1993 09:50:32   john
** Changed output of frequency from 'hz' to 'Hz'.
** Modified code to accept blanks between the number and the M/k(hz)
** designations.
** 
** Added code to prevent incredibly small values from being accepted.
** The code to check valid for valid frequencies was comparing floats
** to doubles, and sometimes giving incorrect answers.
** 
**    Rev 1.89   27 Jul 1993 14:30:22   john
** Modified timestamp header to be right justified with the time display.
** Added chars to the zero frame text to accomodate the new size of the
** timestamp field width.
** Added a space between the time and unit value of the timestamp display.
** 
**    Rev 1.88   26 Jul 1993 12:40:00   paul
** Replace CHECK_ABORT with TskCheckAbort for esc key
** 
**    Rev 1.87   24 Jul 1993 13:35:26   mindy
** minor adjustments to timestamp output
** 
**    Rev 1.86   22 Jul 1993 15:41:12   mindy
** added timestamp support
** 
**    Rev 1.85   13 Jul 1993 19:36:16   doug
** Errors consolidated in errtext/mkerrors.h and use generic error
** 
**    Rev 1.84   01 Jun 1993 12:30:34   ernie
** Added traceInfoDirty flag set by the trace stopped callback.  When
** the presenter asks for trace data that depends on the trace info, the
** information is retrieved at that time.  This improves performance when
** the trace presenter is not open.
** 
**    Rev 1.83   07 Apr 1993 17:16:18   mindy
** FormatFrameToText is now done by making a call to an eventtemplate
** routine this allow us to be able to change the trace display format
** by just changing the ev*.cfg file.
** 
**    Rev 1.82   02 Apr 1993 07:50:56   ernie
** Fixed bit selection for upper word of group T (TPU/GPT bits)
** 
**    Rev 1.81   11 Jan 1993 17:25:10   john
** processor dlls #def's changed, code mod'ed to match
** 
**    Rev 1.80   07 Jan 1993 07:24:50   mindy
** a) numframes wrong if end = start = 0.
** b) format of frame text now includes John's changes - with bug
** fixes included!
** c) Read Trace had major problems with frame placement in raw frame
** buffer.
** 
**    Rev 1.79   17 Dec 1992 10:32:16   john
** fixed comment definition error
** 
**    Rev 1.78   16 Dec 1992 16:36:50   john
** added code to properly format trace for 331
** 
**    Rev 1.77   16 Dec 1992 15:31:44   mindy
** trace moved to fw
** 
**    Rev 1.75   11 Nov 1992 07:01:00   mindy
** fixed initialization bug in trace presenter
** 
**    Rev 1.74   04 Nov 1992 15:21:08   mindy
** fixed ppr7025
** 
**    Rev 1.73   04 Nov 1992 12:03:12   ernie
** Changed low-level trace read function to request only a maximum of 0x10
** frames in each call.  This was necessary to fix a problem with an SX PC
** rebooting unexpectedly in the middle of receiving a large data packet.
** Until the real reason for the rebooting is found, the reduced maximum
** size of trace reads should remain in effect.
** 
**    Rev 1.72   25 Oct 1992 11:16:06   mindy
** When trace clear happened the pre/post counts weren't getting cleared 
** out so get number of frames routines was returning negative number
** of frames.
** 
**    Rev 1.71   21 Oct 1992 17:15:12   mindy
** a) changed max cycles to scan before querying user ppr 6995/6999
** b) change overrun adjustment to just be a constant - no longer call
**    a subroutine.
** c) cleaned up the two zillion warnings
** d) fixed format problems ppr 6965
** 
**    Rev 1.70   14 Oct 1992 14:57:16   mindy
** a) changed update trace to set trace frame to min of trigger and end.
** b) removed kludge in cli get frame area size
** c) if there was only one frame used to figure starting bus cycle - got
**    a UAE.
** d) some trace bits were off. 
** e) fixed some trace caching problems.
** 
**    Rev 1.69   07 Oct 1992 15:00:12   ernie
** Changed both FRAME_OVERRUN and FRAME_OVERRUN_TRIGC to 8 frames.  This
** was necessitated by TMAN hardware changes.  This fixes ppr6890.
** 
**    Rev 1.68   06 Oct 1992 06:36:10   mindy
** a) added valid id check before doing trcupdate.
** b) cache size was too big.
** c) valid cache entry number off by one.
** 
**    Rev 1.67   30 Sep 1992 11:39:12   mindy
** a) Change trace caching to fill cache with start frame - cache_size/2
**    so backward trace gets some benefit too.
** b) Changed get debug emon routine to handle the case where step followed
**    by go both appear in trace buffer.
** 
**    Rev 1.66   23 Sep 1992 06:31:24   mindy
** fixed trc search cli set frame bug
** 
**    Rev 1.65   18 Sep 1992 10:48:54   ernie
** Fixed memory leak in open/close pair.  The eventServerId was not being
** closed in TrcClose().
** 
**    Rev 1.64   16 Sep 1992 18:55:18   mindy
** a) changed all sds calls to use sdn routines.
** b) changed cache size to 256 frames
** 
**    Rev 1.63   16 Sep 1992 09:51:20   mindy
** a) change lowest get trace frames routine to "cache" 100 frames.
** b) changed FormatFrameToText routine to no longer use event template
**    calls - now format is hard coded and very processor specific!!!
** c) debug emon information is calculated once per trace buffer and remains
**    valid until tracing is turned ON.
** 
**    Rev 1.62   11 Sep 1992 12:38:32   ernie
** Changed FRAME_OVERRUN_TRIGC from 8 to 7 frames.  This was necessitated
** by changes to the TMAN xilinx hardware.
** 
**    Rev 1.61   08 Sep 1992 10:27:20   mindy
** added include for events
** 
**    Rev 1.60   31 Aug 1992 05:11:34   mindy
** a) changed valid frame number routine to not return an error for any
**    frame number when no frame is valid because of cycles collected are
**    collected outside of emulation.
** b) fixed how starting bus cycle is retrieved.  Now we just back up to
**    the previous frame qualified and go forward.
** 
**    Rev 1.59   28 Aug 1992 13:13:28   mindy
** cleaned up problems with debugemon info
** 
**    Rev 1.58   27 Aug 1992 15:23:12   mindy
** a) when we open trace we need to calculate the debugEmon pre/post stuff
**    because we are "setting" the trace buffer and there might be trace data
**    collected.
** b) With previous addition I was getting into an infinite loop calculating
**    the debug Emon stuff.
**    Thus I changed how getDebugEmon operates
** c) When setting a frame and there are no "emon"able frames then I just
**    return good - not returning error to user since presenter will handle
**    it better this way.
** d) cli forward_read command changed to avoid getting lock error.
** e) startoffset routine wrong - ernie's fix.
** 
**    Rev 1.57   27 Aug 1992 07:33:30   mindy
** a) added bus cycle user query.  After 60 some cycles if no bus cycle
**    has been found I query user to see if he wants to quit.
** b) tracing set routine changed to wait for SD_TRACING to change to new
**    value rather than just waiting on FW_TRACING_STATUS.
** c) Tracing callback routine uses the new read member without input
**    check so I can get the tracing value that caused the callback not
**    the tracing value that might come in immediately after the first
**    tracing callback happens.
** d) tracing events changed to be a tracing_on and tracing_off event since
**    different presenters need to be registered on one or the other and
**    by the timer the presenter reads the tracing value it could of changed
** 
**    Rev 1.56   25 Aug 1992 11:27:44   mindy
** cleared up some of the warnings
** 
**    Rev 1.55   22 Aug 1992 11:11:36   mindy
** Cleaned up the debug emon on/off calculations.
** Cleaned up the callback routines.
** 
**    Rev 1.54   21 Aug 1992 07:24:42   mindy
** a) fixed post/center number of frames being wrong problem.
**    This done in determining of the trace buffer is full.
** b) Trying to get the callback functions working - there's still a
** problem with the trace stuff not being updated automatically.
** 
**    Rev 1.53   19 Aug 1992 10:25:20   mindy
** can't use desc because CLEAR TRACE event registering too
** 
**    Rev 1.52   19 Aug 1992 07:57:18   mindy
** a) Now register on SD_TRACING and SD_CURRENT_SUBBUFFER since the fw will
**    update these fields only when they are changed.
** b) Removed force status update since it's now done automatically
** c) fixed bug with negative frame numbers in the cli trace read command.
** d) cli read commands return what data they have if an END_OF_BUFFER error
**    is returned.
** 
**    Rev 1.51   11 Aug 1992 09:58:04   mindy
** a) Removed processor specific stuff from trace open - now the configuration
**    information is read from a file: trcXXX.cfg as specified in the *.ini
**    file.
** b) parameters to traceOpen changed.
** c) uncommented out check for valid trace buffer - break when full needs to
**    be working
** d) Sub buffer counter is now incremented after the trigger position is
**    written so calculating "logical" sub buffer number is changed.
** 
**    Rev 1.50   10 Aug 1992 07:45:46   tom
** CLI registration changes.
** 
**    Rev 1.49   06 Aug 1992 07:14:28   mindy
** a) increase frame number to handle largest negative frame number
** b) fixed bug of not being able to reach starting frame
** 
**    Rev 1.49   06 Aug 1992 07:12:40   mindy
** a) incread frame number area (needed more room for -xxxxxx case)
** b) could set frame number to starting frame number.
** 
**    Rev 1.48   03 Aug 1992 09:39:00   mindy
** added 332 support
** 
**    Rev 1.47   28 Jul 1992 06:59:22   mindy
** a) change read raw trace frames not to force bus cycles any more.
**    caller  must now determine what type of cycles they want.
** b) only want always visible evttmptl field types in trace display.
** 
**    Rev 1.46   24 Jul 1992 14:45:08   doug
** using generic shared data
** 
**    Rev 1.45   17 Jul 1992 13:56:40   mindy
** a) cli read frame routines needs to accept and handle negative frame
**    numbers.
** b) trace read frames routines now check for allocating more than 64K
**    of memory.
** c) some trace bits are not to be displayed in trace.
** d) if debugEmon is TRUE then I want to display the emon trace bit.
** 
**    Rev 1.44   10 Jul 1992 08:57:38   mindy
** added include file(s) needed to get rid of 3.1 warnings
** 
**    Rev 1.43   07 Jul 1992 10:09:12   mindy
** made open of template and event common
** 
**    Rev 1.42   07 Jul 1992 10:04:12   mindy
** a) added debug emon support.  Changing debug Emon affects the frame numbering
**    the start align mode - it also changes the number of frames, etc.
** b) changed evttmplt stuff to reference the "default" template.
** 
**    Rev 1.41   25 Jun 1992 12:35:02   mindy
** a) removed swat stuff (timestamp and tsunits, etc)
** b) removed debugEmon routines just left cli routine.
** c) removed go/halt
** d) changed the trace frame numbering stuff to reflect status of
**    debugEmon
** 
**    Rev 1.40   22 Jun 1992 07:56:48   mindy
** added get sub buffer size routine
** 
**    Rev 1.39   15 Jun 1992 08:22:40   mindy
** When tracing is ENABLEd we need to program the trigger hardware.
** 
**    Rev 1.38   28 May 1992 08:00:30   mindy
** I now register on the trigger position once to try and improve the trace
** performance.
** 
**    Rev 1.37   18 May 1992 08:39:12   mindy
** problems in cli trace open
** 
**    Rev 1.36   14 May 1992 11:39:22   mindy
** removed GetErrorText routine and added ErrInitDLL call
** 
**    Rev 1.35   13 May 1992 08:08:40   mindy
** get dll handle since cli might not be initialized
** 
**    Rev 1.34   12 May 1992 12:42:52   mindy
** a) removed unused error codes
** b) added TrcGetErrorText 
** 
**    Rev 1.33   04 May 1992 10:23:44   mindy
** oops!
** 
**    Rev 1.32   04 May 1992 10:17:04   mindy
** a) updated signal information - which signals are valid when bit0-3 are
**    active.
** b) ReadTraceFrames now only searches forward if caller is reading forward.
** c) BackwardReadTrace now calls ForwardReadTrace to shared some code.
** 
**    Rev 1.31   30 Apr 1992 08:30:08   mindy
** Added a check for emon fixing PPR5304.  If EMON is not ON then we setup the
** search parameters to start at the current startFrame and search for the
** first frame with the EMON bit ON.  Also if we see the emon bit turn OFF
** we exit immediately.  This change might mess up the old probe since emon
** signal toggles so beware!!!
** 
**    Rev 1.30   28 Apr 1992 08:28:06   mindy
** a) Fixed ppr5361 - added abort support.
** b) Fixed ppr5542 - tracing status - if trace empty then collecting buffer is
**    always 0.
** c) Added a routine to return the trace cli id so dq commands from cli could
**    work without requiring user to enter a trace id.
** d) trace cli open now just changes the state values if open is called and
**    trace is already opened.  Can no longer do a close/open since that would
**    change the id and if the dq called in and got the trace cli id he would
**    blow up the system!
** 
**    Rev 1.29   23 Apr 1992 11:32:56   mindy
** a) changed memory allocation to use TMalloc
** b) added keyword parsing to cli commands.
** 
**    Rev 1.28   03 Apr 1992 12:01:18   mindy
** removed the portion of the frame to address routine that scans backwards
** through the bus cycles to get the last code read address of the given
** frame isn't a code read.  See rev 1.27's comment.
** 
**    Rev 1.27   03 Apr 1992 08:36:32   mindy
** Added a new routine to determine the address given a frame number - this one
** scans the previous bus cycles to get an address if the incoming frame doesn't
** point to an instruction read - this takes a long time.  I'm going to remove
** this feature for this release but wanted the full code under pvcs.
** 
**    Rev 1.26   31 Mar 1992 14:51:02   mindy
** a) added new routine to count number of instruction boundaries occur
**    between current and next refill. This is processor specific and should
**    be moved. !!!
** b) no reason to do extra lmemcpy if foundFrames == current index (idx)
** 
**    Rev 1.25   27 Mar 1992 11:07:24   mindy
** a) take out buffer validity check until break on full is working so
** I can access all buffers. !!!
** b) foundOne not filled in correctly for bus cycles.
** c) execution breakpoint changed event names.
** 
**    Rev 1.24   17 Mar 1992 08:47:54   mindy
** wrong frame number was being include in the raw trace structure.
** 
**    Rev 1.23   13 Mar 1992 08:57:32   mindy
** a) changed interface to getting raw frames.
** b) setting trace frame number and search frame number had a an unsigned
**    verses signed problem.
** 
**    Rev 1.22   11 Mar 1992 10:41:20   mindy
** added code to handle special status fields like refill- and status-
** that are not qualified.
** 
**    Rev 1.21   28 Feb 1992 07:55:50   mindy
** in go/halt now am using real bkptexec.h names
** 
**    Rev 1.20   27 Feb 1992 11:24:26   mindy
** a)
** a) leave DebugEmon TRUE
** b) when trace frames hits the end of the logical trace buffer - the
**    number of frames until the end was calculated wrong - off by one.
** c) valid trace buffers include the currently active buffer.
** 
**    Rev 1.19   18 Feb 1992 14:10:52   mindy
** Made numerious changes to support the new trace presenter - now have
** a backward read and forward read no longer have trctraceread().
** 
**    Rev 1.18   29 Jan 1992 16:50:52   ernie
** a) FIxed problem in search trace when trace store was divided into multiple
**    trace buffers.
** b) Hopefully fixed the off by one problems when calculating trigger, start
**    end position. Probably haven't seen the last of these type of problems.
** 
**    Rev 1.17   27 Jan 1992 11:28:14   mindy
** removed dummy dq server routines
** 
**    Rev 1.16   27 Jan 1992 10:00:32   ernie
** a) Fixed problem in search trace.
** b) num of frames routine returns the number of frames (no longer inc
**    by one).
** c) Code added to calculate the correct trigger frame when we switch 
**    into a trace buffer via the trigger and continue feature.
** 
**    Rev 1.15   23 Jan 1992 14:04:42   ernie
** Trying to clean up the handling of an empty trace buffer.
** 
**    Rev 1.14   22 Jan 1992 13:23:56   doug
** Added code to unlock data segment in LibMain
** 
**    Rev 1.13   17 Jan 1992 11:10:48   courtney
** Revised return code of LibMain to be compatible with Windows.
** 
**    Rev 1.12   14 Jan 1992 11:36:10   ernie
** a) frame overrun is really 11 not 10
** b) !!! leaving debugEmon TRUE to avoid LONG delays when emon bits
**    from test probe is bad.
** c) frame number for bus cycles is the last frame (i.e.: the frame
**    with the qualifier bit set).
** d) Changed the way tracing is set.
** e) read frame number in cli trace read and trace search need atol not atoi
** f) cli open default opens in clock cycles (quicker then bus cycles)
** g) added a routine to deterine if start of trace buffer is offset by
**    a sub buffer. (i.e.: previous trace buffer ended in an even subbuffer).
** h) beefed up handing an empty trace buffer.
** 
**    Rev 1.11   07 Jan 1992 10:05:40   mindy
** a) Changed all references of BOOL to BOOLEAN so now BOOLEAN are all
**    8 bits.
** b) Removed "until we have a probe" kludges
** c) added a temp. version of go and halt (for debug)
** d) fixed bit of looking at wrong group to determine qualifier bits
**    and emon bit.
** e) fixed defines for frame and sub buffer fields within the trigger position.
** 
**    Rev 1.10   11 Dec 1991 14:48:10   mindy
** a) trace is now the only server in trace.dll so LibMain moved in and 
** got rid of initializing trace server.
** b) cleaned up the errors - assigned text and sent to Tom.
** 
**    Rev 1.9   06 Dec 1991 10:22:14   mindy
** changed to use common routines in swat.c.
** 
**    Rev 1.8   02 Dec 1991 11:01:10   mindy
** a) use global errors for mem lock and alloc errors.
** b) replaced kludged timestamp with swat stuff
** c) added timestamp unit support (including cli commands)
** 
**    Rev 1.7   20 Nov 1991 11:07:14   mindy
** a) Added timestamp trace server support.  This affected the header and
**    outputting of bus and clock trace frames.  The current timestamp
**    value is kluded and needs to be replaced with pa/cc calls(!!!).
** b) added timestamp cli routine.
** c) changed numerious server calls because they didn't return an error if
**    the MemLock failed.
** d) Added trace search cli routines.
** e) Now check to see if search event exists - rather than just telling
**    event server it's the active event because that creates a "new" one
**    if it doesn't exist.  In this case I think the user would want to
**    know he had a "blank" event.
** f) Removed DadSetDqFrame callers will just call trace server directly.
**    All of these Dad routines need to be removed (!!!).
** 
**    Rev 1.6   15 Nov 1991 15:03:42   mindy
** a) changed error # to conform to system numbers.
** b) put prototypes in alphabetical order
** c) added cli command routines
** d) added trace search routines.
** 
**    Rev 1.5   07 Nov 1991 14:26:00   mindy
** Put present copy back under PVCS so I could mark version I sent to
** MHS.
** 
**    Rev 1.4   01 Nov 1991 09:16:46   mindy
** new version to support final trace presenter
** 
**    Rev 1.3   17 Sep 1991 07:53:34   ernie
** Lots of changes for PDR2 release:
** 1. Trace data now returned as 128 bits, regardless of valid data width.
** 2. Trigger position information has changed format.
** 3. Still need to compute and flag valid/invalid frames.
** 
**    Rev 1.2   06 Sep 1991 08:50:44   mindy
** Trace server now goes to the box to get real data.  Template stuff not
** complete.
** 
**    Rev 1.1   31 Jul 1991 14:45:36   john
** Updated to copy used for basic system release.
** 
**    Rev 1.0   26 Jul 1991 15:53:32   jim
** Initial revision.
**
**  $Header:   S:/tbird/mt2_68k/trace/trace.c_v   1.16   03 Mar 1998 14:37:54   Winky  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/

#include "ctype.h"
#include "math.h"
#include "stdlib.h"

#ifndef __STRING_H
#include <string.h>
#endif

#ifndef _BASEWIND_
#include "basewind.h"
#endif
#ifndef _BKPTEXEC_
#include "bkptexec.h"
#endif
#ifndef _ENLIB_
#include "enlib.h"
#endif

#ifndef _PVTASK_
#include "pvtask.h"
#endif

#ifndef _HEAP_
#include "heap.h"
#endif
#ifndef _TRACE_
#include "trace.h"
#endif
#ifndef _TRIG_
#include "trig.h"
#endif
#ifndef _EVTTMPLT_
#include "evttmplt.h"
#endif
#ifndef _EVENT_
#include "event.h"
#endif
#ifndef _DASM_
#include "dasm.h"
#endif
#ifndef _EVENTS_
#include "events.h"
#endif
#ifndef _CLISRV_
#include "clisrv.h"
#endif
#ifndef _SDPROBE_
#include "sdprobe.h"
#endif
#ifndef _SSHARED_
#include "sshared.h"
#endif
#ifndef _TBIRDMEM_
#include "tbirdmem.h"
#endif
#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif
#ifndef _LOCAL_
#include "local.h"
#endif
#ifndef _PROC_
#include "proc.h"
#endif
#ifndef _MP_TRACE_
#include "mp_trc.h"
#endif
#ifndef _MP_TRIG_
#include "mp_trig.h"
#endif
#ifndef _SDS2ABI_
#include "sds2abi.h"
#endif

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/

#define  MAX_TEXT_PER_FRAME   256L
#define  MAX_FOR_BUS_CYCLE    50
#define  MAX_CYCLES_TO_SCAN   500
#define  FRAME_NUM_AREA_SIZE  10
#define  EVENT_NAME_LENGTH    64
#define  EMON_BIT_MASK        0x10  /* bit 4 is emon bit in all processors */

//#define  TIMESTAMP_TEXT        "   timestamp"
//#define  TIMESTAMP_LEN         12   /* max number of digits in timestamp */
//#define  END_OF_LINE_TEXT      "\r\n"

#define  TIMESTAMP_OPT        0x01
#define  TPORT_OPT            0x02
#define  STATUS_OPT           0x08
#define  TRACE_OPT            0x10
#define  ACTION_OPT           0x20
#define  LEVEL_OPT            0x40
#define  EVENT_OPT            0x80

typedef struct {
   U16                traceBuffer;     /* active trace buffer */
   S32                startFrame;      /* logical frame in trace buffer */
   TRACE_CYCLES       cycleMode;       /* bus,clock, etc types of cycles */
   FRAME_DISPLAY_MODE frameMode;       /* Frame numbering scheme */
                                       /* header for bus and clock cycles */
   S8 header[NUM_HDR_LINES*MAX_HDR_LINE+1];

   DESCRIPTOR         templateId;      /* Id of active template */
   DESCRIPTOR         dqId;            /* Id of active dq server */
   
   DESCRIPTOR         traceSemaId;     /* Id of trace semaphore */
   DESCRIPTOR         activeBufDesc;   /* desc for active buffer */
   DESCRIPTOR         emonDesc;        /* desc for emon status */
   DESCRIPTOR         frameTypeDesc;   /* desc for trace frame type */
   DESCRIPTOR         traceFrameDesc;  /* desc for trace start frame */
   DESCRIPTOR         traceLenDesc;    /* desc for length of trace read */
   DESCRIPTOR         traceStoreDesc;  /* desc to read trace store memory */

   BOOLEAN            debugEmon;       /* send back EMON off cycles */

   U16                searchBuffer;     /* buffer to search */
   S32                searchStartFrame; /* logical starting search frame */
   S8 searchEvent[EVENT_NAME_LENGTH]; /* name of event to use in search */
   DESCRIPTOR         eventServerId;    /* event server for search event */
   BOOLEAN            timestampOn;   /* determines if timestamp field is on */
   S8                 tsMode;       /* RELATIVETOFRAME or DELTA ts mode */
   S32                zeroedFrame; /* frameNum to start abs. TS from. */
} TRACE_DESC_BLOCK;

#define  TIMESTAMP_TEXT        " timestamp "
#define  STATUS_TEXT           " status "
#define  TRACE_TEXT            " trace-bit "
#define  LEVEL_TEXT            " SL"
#define  EVENT_TEXT            " bus-event"
#define  EVENT_2TEXT           " 76543210  "
#define  ACTION_TEXT           " action "
#define  TRC_TEXT              " trc trc"
#define  TRC_2TEXT             " on  off"
#define  TC0TC1_TEXT           " tc0 tc0 tc1 tc1"
#define  TC0TC1_2TEXT          " inc rst inc rst"
#define  TC0TM1_TEXT           " tc0 tc0 tm1 tm1 tm1"
#define  TC0TM1_2TEXT          " inc rst on  off rst"
#define  TM0TC1_TEXT           " tm0 tm0 tm0 tc1 tc1"
#define  TM0TC1_2TEXT          " on  off rst inc rst"
#define  TM0TM1_TEXT           " tm0 tm0 tm0 tm1 tm1 tm1"
#define  TM0TM1_2TEXT          " on  off rst on  off rst"
#define  TIMESTAMP_LEN         12  /* max number of digits in timestamp */
#define  STATUS_LEN            8   /* max number of digits in timestamp */
#define  TRACE_LEN             11  /* max number of digits in timestamp */
#define  LEVEL_LEN             3   /* max number of digits in timestamp */
#define  EVENT_LEN             10  /* max number of digits in timestamp */
#define  ACTION_LEN            15  /* max number of digits in timestamp */
#define  END_OF_LINE_TEXT      "\r\n"

                        /****************************
                         *                          *
                         *    EXTERNAL VARIABLES    *
                         *                          *
                         ****************************/
RETCODE EXPORT TrcInit(HANDLE hLib);
U16   GetMaxValidTraceBuffer(VOID);

                        /****************************
                         *                          *
                         *     LOCAL STORAGE        *
                         *                          *
                         ****************************/

static S8 optionFlag=0;
static HANDLE cliServerHandle = 0;  /* return address for CLI results */
static U32 numRetrieved;
static S32 startingFrame, endingFrame, currentFrame;
static DESCRIPTOR traceId=0, saveLastTraceId = 0;
static BOOLEAN traceInfoDirty=TRUE;
static float systemPeriod, krystalFrequency = 32768.;
HANDLE hLib;

static long double zeroedFrameTS,preFrameTS;
static U8 trcMark=0;
static S32 trcMarkFrameOn=0,trcMark2FrameOn=0, trcMarkFrameOff=0;
static DESCRIPTOR theTrigger = NULL;
   
                        /****************************
                         *                          *
                         *     LOCAL PROTOTYPES     *
                         *                          *
                         ****************************/
VOID FAR PASCAL SubBufferUpdate(DESCRIPTOR desc);
VOID FAR PASCAL TraceClearCallback(U32 event);
VOID FAR PASCAL TracingStateChange(DESCRIPTOR desc);
RETCODE  SetupBufferCheck(U16 buffer, BOOLEAN emon);
RETCODE  ValidFrameNumber(U16 buffer, S32 frame, BOOLEAN emon);
U16      CalculateTraceBufferFromSubBuffer(U16 subBuffer);
RETCODE  ReadTrace(DESCRIPTOR id, S32 numFrames, BOOLEAN raw, LPSTR *buffer);
RETCODE  FormatFrameToText(DESCRIPTOR tmpltId, TRACE_INFO *framePtr,
                           S32 prevFrame, DESCRIPTOR id, LPSTR dataPtr);
RETCODE  FormulateHeader(TRACE_DESC_BLOCK FAR *trace);
RETCODE  GetHardwareState(VOID);
VOID     InitializeTraceState(DESCRIPTOR id, TRACE_CYCLES tMode, 
                          FRAME_DISPLAY_MODE fMode);

RETCODE initOptionFlag(VOID);
RETCODE setOptionFlag2Profile(VOID);
RETCODE PRIVATE FormulateHeaderFields(TRACE_DESC_BLOCK FAR *trace,
            U8 startField, U8 numFields,U16 *linePos);
RETCODE TrcGetActionText(ACTION_MASK *actionMask, LPSTR dataPtr);

                        /****************************
                         *                          *
                         *      EXECUTABLE CODE     *
                         *                          *
                         ****************************/

#pragma argsused
int FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg, WORD cbHeapSize,
    LPSTR lpszCmdLine) {
   FARPROC lpProc;
   DESCRIPTOR desc;
   U32 value;
   if (cbHeapSize != 0)  UnlockData(0);   /* allows heap to grow */
   lpProc = MakeProcInstance((FARPROC)TracingStateChange, hInstance);
   SdnRegister(SDN_TRACING,lpProc,&desc);
   lpProc = MakeProcInstance((FARPROC)SubBufferUpdate, hInstance);
   SdnRegister(SDN_CURRENT_SUBBUFFER,lpProc,&desc);
   lpProc = MakeProcInstance((FARPROC)TraceClearCallback, hInstance);
   EnlRegister(EVENT_TRACE_CLEAR_TRACE, (EVCALLBACK)lpProc,&desc);
   value = 20;   /* update every 3 seconds */
   SdnWriteMember(SDN_UPDATES_PER_MINUTE, (U8 FAR *)&value, GOOD);
   ErrInitDLL(MODULE_TRACE,"trace.dll");
   /* initialize successfully */
   hLib = hInstance;

   initOptionFlag();

   return(TRUE);
}

/**************************************************************************
**
** InitCServer
**
***************************************************************************/
RETCODE EXPORT InitCServer(HANDLE cliHandle, HANDLE dllHandle) {
   CSERVER_NEW_REGISTRATION FAR * msgBufPtr;

   cliServerHandle = cliHandle;
   msgBufPtr =
      (CSERVER_NEW_REGISTRATION FAR *)TMalloc(sizeof(CSERVER_VARIABLE_VALUE));
   if (msgBufPtr == NULL) {
      return(ER_OUT_OF_MEMORY);
   }

   msgBufPtr->stringResourceHandle = dllHandle;

   msgBufPtr->serverNameIndex = 10;
   msgBufPtr->dllNameIndex = 11;
   msgBufPtr->numberOfCommandsIndex = 12;
   msgBufPtr->commandStartIndex = 13;
   SendMessage(cliHandle, CLI_NEW_SVR_REGISTRATION, CLI_NEW_SVR_REGISTRATION,
      (DWORD)msgBufPtr);
   return(GOOD);
}

/*****************************************************************************
**
**    TrcTraceOpen
**
*****************************************************************************/
RETCODE EXPORT TrcTraceOpen(DESCRIPTOR FAR *id, LPSTR fileName,
                            TRACE_CYCLES cycleMode,
                            FRAME_DISPLAY_MODE frameMode) {
   TRACE_DESC_BLOCK FAR *trace;
   MEMBER_INDEX       memberIndex;   
   MEMBER_NAME memberName[SD_MAX_NAME];
   RETCODE err;
      /* Only support HW trace for now */
   if (lstrcmp((LPSTR)fileName, "hwtrc") != 0) return(ER_ONLY_HW_SUPPORT);
   if( frameMode != TRIGGER_ALIGN ) return(ER_NOT_SUPPORTED);

   /*
    *** Get memory for trace info
    */
   if ((trace = (TRACE_DESC_BLOCK FAR *) TMalloc(sizeof(*trace))) == NULL)
      return(ER_OUT_OF_MEMORY);

//   if( (err=TrigTriggerOpen(&theTrigger,"","default")) != GOOD )
//      return(err);
   /*
    *** Open an event template and set active template to default
    */
   if( (err=EvtOpenEvent(&trace->eventServerId,"default")) != GOOD ) 
      return(err);

   if( (err = TmpltOpenTemplate(&trace->templateId)) != GOOD )
      return(err);

   if( (err = SdRegisterSemaphore(SD_TRACE_SEMAPHORE, NULLPTR,
                 &trace->traceSemaId)) != GOOD) return(err);
   
   if( (err = SdGetMemberIndex(trace->traceSemaId,&memberIndex)) 
      != GOOD) return(err);
   
   wsprintf(memberName,"%s %d", SD_TRACE_START_FRAME, memberIndex);
   if((err=SdRegister(memberName,NULLPTR,&trace->traceFrameDesc))!=GOOD)
      return(err);

   wsprintf(memberName,"%s %d", SD_FRAME_TYPE, memberIndex);
   if((err=SdRegister(memberName,NULLPTR,&trace->frameTypeDesc))
      !=GOOD) return(err);
   wsprintf(memberName,"%s %d", SD_ACTIVE_BUFFER, memberIndex);
   if((err=SdRegister(memberName,NULLPTR,&trace->activeBufDesc))!=GOOD)
      return(err);

// vincent   wsprintf(memberName,"%s %d", SD_BUFFER_EMON, memberIndex);
// vincent   if((err=SdRegister(memberName,NULLPTR,&trace->emonDesc))!=GOOD)
// vincent      return(err);
   
   wsprintf(memberName,"%s %d", SD_TRACE_BUFF_LEN, memberIndex);
   if((err=SdRegister(memberName,NULLPTR,&trace->traceLenDesc))!=GOOD)
      return(err);

   wsprintf(memberName,"%s %d", SD_TRACE_STORE, memberIndex);
   if((err=SdRegister(memberName,NULLPTR,&trace->traceStoreDesc))!=GOOD)
      return(err);

//   initOptionFlag();

   InitializeTraceState((DESCRIPTOR)trace, cycleMode, frameMode);

   if((err=SdWriteMember(trace->frameTypeDesc,(U8 FAR *)&trace->cycleMode,
      GOOD)) != GOOD ) return(err);
   if((err=SdWriteMember(trace->activeBufDesc,(U8 FAR *)&trace->traceBuffer,
      GOOD)) != GOOD ) return(err);
// vincent   if((err=SdWriteMember(trace->emonDesc,(U8 FAR *)&trace->debugEmon,GOOD))
// vincent      != GOOD ) return(err);

   /* formulate the header given the template */
   FormulateHeader(trace);
   
   *id = (DESCRIPTOR)trace;
   saveLastTraceId = *id;

   preFrameTS=0.;             /* Judy 7/22/97 */
   return(GOOD);
}

/*****************************************************************************
**
**    TrcTraceClose
**
*****************************************************************************/
RETCODE EXPORT TrcTraceClose(DESCRIPTOR id) {
   TRACE_DESC_BLOCK FAR *trace;
   RETCODE err;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   if( (err = TmpltTemplateClose(trace->templateId)) != GOOD ) return(err);
   if( (err = EvtCloseEvent(trace->eventServerId)) != GOOD ) return(err);
   if((err=SdUnRegister(trace->traceFrameDesc))!=GOOD) return(err);
   if((err=SdUnRegister(trace->frameTypeDesc))!=GOOD) return(err);
   if((err=SdUnRegister(trace->activeBufDesc))!=GOOD) return(err);
// vincent   if((err=SdUnRegister(trace->emonDesc))!=GOOD) return(err);
   if((err=SdUnRegister(trace->traceLenDesc))!=GOOD) return(err);
   if((err=SdUnRegister(trace->traceStoreDesc))!=GOOD) return(err);
   if((err=SdUnRegisterSemaphore(trace->traceSemaId))!=GOOD) return(err);

   setOptionFlag2Profile();

   TFree((LPSTR)id);
   return(GOOD);
}

/*****************************************************************************
**
**    TrcTraceTemplateSet
**
*****************************************************************************/
RETCODE EXPORT TrcTraceTemplateSet(DESCRIPTOR id, LPSTR name) {
   return(TmpltSetTemplateName(((TRACE_DESC_BLOCK FAR*)id)->templateId,name));
}

/*****************************************************************************
**
**    TrcTraceTemplateGet
**
*****************************************************************************/
RETCODE EXPORT TrcTraceTemplateGet(DESCRIPTOR id, LPSTR name, U16 maxLen) {
   return(TmpltGetTemplateName(((TRACE_DESC_BLOCK FAR*)id)->templateId, 
                               name, maxLen));
}

/*****************************************************************************
**
**   TrcTraceReadRaw
**
*****************************************************************************/
RETCODE EXPORT TrcTraceReadRaw(DESCRIPTOR id, S32 numFrames,
                               U32 FAR *numGotten, LPSTR *buffer) {
   RETCODE err;
   numRetrieved = 0;
   err=ReadTrace(id,numFrames,TRUE,buffer);
   *numGotten = numRetrieved;
   return(err);
}

/*****************************************************************************
** 
**    TrcForwardRead
** 
*****************************************************************************/
RETCODE EXPORT TrcForwardRead(DESCRIPTOR id, U32 numFrames,
  S32 FAR *startFrame, S32 FAR *endFrame, LPSTR *buffer, U16 FAR *textLen) {
   RETCODE err;
   err = ReadTrace(id, numFrames, FALSE, buffer);
   *startFrame = startingFrame;
   *endFrame = endingFrame;
   *textLen = lstrlen(*buffer);
   return(err);
}
/*****************************************************************************
** 
**    TrcForwardReadPrn
** 
*****************************************************************************/
RETCODE EXPORT TrcForwardReadPrn(DESCRIPTOR id, U32 numFrames,
  S32 FAR *startFrame, S32 FAR *endFrame, LPSTR *buffer, U16 FAR *textLen) {
   RETCODE err;
   err = ReadTrace(id, numFrames, TRUE, buffer);
   *startFrame = startingFrame;
   *endFrame = endingFrame;
   *textLen = lstrlen(*buffer);
   return(err);
}
      
/*****************************************************************************
** 
**    TrcBackwardRead
** 
*****************************************************************************/
RETCODE EXPORT TrcBackwardRead(DESCRIPTOR id, U32 numFrames,
   S32 FAR *startFrame, S32 FAR *endFrame, LPSTR *buffer, U16 FAR *textLen) {
   RETCODE err;
   preFrameTS=0.;             /* Judy 7/22/97 */
   err = ReadTrace(id, 0-numFrames, FALSE, buffer);
   *startFrame = startingFrame;
   *endFrame = endingFrame;
   *textLen = lstrlen(*buffer);
   return(err);
}

/*****************************************************************************
**
**  TrcTraceBufferInfoGet
**
*****************************************************************************/
RETCODE EXPORT TrcTraceBufferInfoGet(DESCRIPTOR id, S32 FAR *oldest,
                                     S32 FAR *youngest, S32 FAR *trigger) {
   TRACE_DESC_BLOCK FAR *trace;
   RETCODE err;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   *oldest = 0;
   *youngest = 0;
   *trigger = 0;
   if((err=SetupBufferCheck(trace->traceBuffer,trace->debugEmon))!=GOOD)
      return(err);
   if((err=SdnReadMember(SDN_BUFFER_OLDEST,(U8 FAR *)oldest))!=GOOD) 
      return(err);
   if((err=SdnReadMember(SDN_BUFFER_YOUNGEST,(U8 FAR *)youngest))!=GOOD) 
      return(err);
   return(GOOD);
}
                                     
/*****************************************************************************
**
**    TrcFrameNumberAreaSizeGet
**
*****************************************************************************/
RETCODE EXPORT TrcFrameNumberAreaSizeGet(U16 FAR *size) {
   *size = FRAME_NUM_AREA_SIZE;
   return(GOOD);
}

/*****************************************************************************
**
**    TrcSubBufferSizeGet
**
*****************************************************************************/
RETCODE EXPORT TrcSubBufferSizeGet(U16 FAR *size) {
   U8 tmodCompatibility;
   RETCODE err;
   *size = 128;   
   if((err=SdnReadMember(SDN_TRACE_0_COMPATIBILITY,&tmodCompatibility))!=GOOD)
      return(err);
   if( tmodCompatibility >= TMOD_40MHZ ) *size *= 2;
   return(GOOD);
}

/*****************************************************************************
**
**    TrcGetHeader
**
*****************************************************************************/
RETCODE EXPORT TrcGetHeader(DESCRIPTOR id, LPSTR header, U16 maxLen) {
   TRACE_DESC_BLOCK FAR *trace;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   if((NUM_HDR_LINES*MAX_HDR_LINE+1) > maxLen) return(ER_NOT_ENOUGH_STORAGE);
   FormulateHeader(trace);
   lstrcpy(header,trace->header);
   return(GOOD);
}

/*****************************************************************************
**
**    TrcReadFrameGet
**
*****************************************************************************/
RETCODE EXPORT TrcReadFrameGet(DESCRIPTOR id, S32 FAR *frame) {
   TRACE_DESC_BLOCK FAR *trace;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   *frame = trace->startFrame;
   return(GOOD);
}
  
/*****************************************************************************
**
**    TrcReadFrameSet
**
*****************************************************************************/
RETCODE EXPORT TrcReadFrameSet(DESCRIPTOR id, S32 frame) {
   RETCODE err;
   TRACE_DESC_BLOCK FAR *trace;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   if((err=ValidFrameNumber(trace->traceBuffer,frame,trace->debugEmon))!=GOOD)
      return(err);
   trace->startFrame = frame;
   return(GOOD);
}

/*****************************************************************************
**
**    TrcNumFramesGet
**
*****************************************************************************/
RETCODE EXPORT TrcNumFramesGet(DESCRIPTOR id, U32 FAR *frames) {
   TRACE_DESC_BLOCK FAR *trace;
   S32 oldest, youngest;
   RETCODE err;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   if((err=SetupBufferCheck(trace->traceBuffer,trace->debugEmon))!=GOOD)
      return(err);
   if((err=SdnReadMember(SDN_BUFFER_OLDEST,(U8 FAR *)&oldest))!=GOOD) 
      return(err);
   if((err=SdnReadMember(SDN_BUFFER_YOUNGEST,(U8 FAR *)&youngest))!=GOOD) 
      return(err);
   if( (oldest == 0) && (youngest == 0) ) *frames = 0;
   else *frames = youngest - oldest + 1;
   return(GOOD);
}

/*****************************************************************************
**
**    TrcReadBufferGet
**
*****************************************************************************/
RETCODE EXPORT TrcReadBufferGet(DESCRIPTOR id, U16 FAR *buffer) {
   *buffer = ((TRACE_DESC_BLOCK FAR*)id)->traceBuffer;
   return(GOOD);
}

/*****************************************************************************
**
**    TrcReadBufferSet
**
*****************************************************************************/
RETCODE EXPORT TrcReadBufferSet(DESCRIPTOR id, U16 buffer) {
   TRACE_DESC_BLOCK FAR *trace;
   RETCODE err;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   if((err=SetupBufferCheck(buffer,trace->debugEmon))!=GOOD) return(err);
   trace->traceBuffer = buffer;
   if((err=SdWriteMember(trace->activeBufDesc,(U8 FAR *)&trace->traceBuffer,
      GOOD)) != GOOD ) return(err);

   /* check startFrame against new trace buffer's limits */
   if((err=ValidFrameNumber(buffer,trace->startFrame,trace->debugEmon))!=GOOD)
      trace->startFrame = 0;  /* logical trigger frame */
   return(GOOD);
}

/*****************************************************************************
**
**    TrcTracingGet
**
*****************************************************************************/
RETCODE EXPORT TrcTracingGet(BOOLEAN FAR *value) {
   return(SdnReadMember(SDN_TRACING,value));
//   return(SdnReadMember(SDN_FW_TRACING_STATUS,value));
}

/*****************************************************************************
**
**    TrcTracingSet
**
*****************************************************************************/
RETCODE EXPORT TrcTracingSet(BOOLEAN value) {
   BOOLEAN timedOut, currentTracing;

   return(SdnWriteCmdReadResponse(SDN_SET_TRACING, &value, GOOD,
                     SDN_FW_TRACING_STATUS, 0, &timedOut));
}

//   BOOLEAN timedOut, currentTracing;
//   LOOP_VAR repeatCount=500;
//   RETCODE err;
//   BOOLEAN  abortFromEsc;
//
//
//   if( value ) {
//      /* if turning tracing ON need to first program trigger hw */
//      if((err=TrigTriggerProgram())!=GOOD) return(err);
//   }
//   return (GOOD);
//vvv    if((err=SdnReadMember(SDN_TRACING,&currentTracing))!=GOOD) return(err);
//vvv    /* our work is already done */
//vvv    if( currentTracing == value ) {
//vvv       return(GOOD);
//vvv    }
//vvv 
//vvv    if((err=SdnWriteCmdReadResponse(SDN_SET_TRACING, &value, GOOD, 
//vvv                      SDN_FW_TRACING_STATUS, 0, &timedOut))!= GOOD ) {
//vvv          return(err);
//vvv    }
//vvv    /* just because SD_FW_TRACING_STATUS has been updated doesn't mean
//vvv       SD_TRACING has changed.  So after getting confirmation that fw
//vvv       has completed it's attempt to change TRACING we need to wait for
//vvv       SD_TRACING to change.  Will also add a timeout so we don't get
//vvv       hung here.
//vvv    */
//vvv    while( repeatCount-- ) {
//vvv       LOOP_VAR delay;
//vvv       if((err=SdnReadMember(SDN_TRACING,&currentTracing))!=GOOD) return(err);
//vvv       if( currentTracing == value ) break;
//vvv 
//vvv       err = TskCheckAbort(&abortFromEsc);
//vvv       if(err!=GOOD) break;
//vvv       if (abortFromEsc!=0) {
//vvv          err=ER_ABORT_FROM_ESC;
//vvv          break;
//vvv       }
//vvv 
//vvv       for(delay=0xfff;delay;delay--);   /* delay for next check */
//vvv    }
//vvv    return(err);
//}

/*****************************************************************************
**
**    TrcMaxValidTraceBuffers
**
*****************************************************************************/
RETCODE EXPORT TrcMaxValidTraceBuffers(U16 FAR *numBuffers) {
   RETCODE err;
   *numBuffers = GetMaxValidTraceBuffer();
   if((err=SdnWriteMember(SDN_MAX_TRACE_BUFFER,(U8 FAR *)numBuffers,GOOD))!=GOOD)
   return(err);
}
 
/*****************************************************************************
**
**    TrcTraceCycleGet
**
*****************************************************************************/
RETCODE EXPORT TrcTraceCycleGet(DESCRIPTOR id, TRACE_CYCLES FAR *type) {
   *type = ((TRACE_DESC_BLOCK FAR*)id)->cycleMode;
   return(GOOD);
}

/*****************************************************************************
**
**    TrcTraceCycleSet
**
*****************************************************************************/
RETCODE EXPORT TrcTraceCycleSet(DESCRIPTOR id, TRACE_CYCLES type) {
   TRACE_DESC_BLOCK FAR *trace;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   preFrameTS=0.;             /* Judy 7/22/97 */
   trace->cycleMode = type;
   return(
      SdWriteMember(trace->frameTypeDesc,(U8 FAR *)&trace->cycleMode,GOOD));
}

/*****************************************************************************
**
**    TrcTraceBufferClear
**
*****************************************************************************/
RETCODE EXPORT TrcTraceBufferClear(VOID) {
   RETCODE err;
   BOOLEAN enable = TRUE;
   preFrameTS=0.;             /* Judy 7/22/97 */
   if((err=SdnWriteMember(SDN_CLEAR_TRACE,(U8 FAR *)&enable,GOOD))!=GOOD)
      return(err);
   if((err=EnlEventNotify(EVENT_TRACE_CLEAR_TRACE)) != GOOD ) return(err); 
   return(GOOD);
}

/*****************************************************************************
** 
**    TrcFrameDisplayModeSet
**
*****************************************************************************/
RETCODE EXPORT TrcFrameDisplayModeSet(DESCRIPTOR id, FRAME_DISPLAY_MODE mode){
   if( mode != TRIGGER_ALIGN ) return(ER_NOT_SUPPORTED);
   ((TRACE_DESC_BLOCK FAR*)id)->frameMode = mode;
   preFrameTS=0.;             /* Judy 7/22/97 */
   return(GOOD);
}

/*****************************************************************************
** 
**    TrcFrameDisplayModeGet
**
*****************************************************************************/
RETCODE EXPORT TrcFrameDisplayModeGet(DESCRIPTOR id, 
                  FRAME_DISPLAY_MODE FAR *mode){
   *mode = ((TRACE_DESC_BLOCK FAR*)id)->frameMode;
   return(GOOD);
}

/*****************************************************************************
** 
**    TrcSearchBufferGet
** 
*****************************************************************************/
RETCODE EXPORT TrcSearchBufferGet(DESCRIPTOR id, U16 FAR *buffer) {
   *buffer = ((TRACE_DESC_BLOCK FAR*)id)->searchBuffer;
   return(GOOD);
}
      
/*****************************************************************************
** 
**    TrcSearchBufferSet
** 
*****************************************************************************/
RETCODE EXPORT TrcSearchBufferSet(DESCRIPTOR id, U16 buffer) {
   TRACE_DESC_BLOCK FAR *trace;
   RETCODE err;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   if((err=SetupBufferCheck(buffer,trace->debugEmon))!=GOOD)
      return(err);
   trace->searchBuffer = buffer;
   /* check startFrame against new trace buffer's limits */
   if((err=ValidFrameNumber(buffer,trace->searchStartFrame,trace->debugEmon))
      != GOOD ) 
      return(SdnReadMember(SDN_BUFFER_OLDEST,
               (U8 FAR *)&trace->searchStartFrame));
   return(GOOD);
}
      
/*****************************************************************************
** 
**    TrcSearchEventGet
** 
*****************************************************************************/
RETCODE EXPORT TrcSearchEventGet(DESCRIPTOR id, LPSTR event, U16 maxLen) {
   TRACE_DESC_BLOCK FAR *trace;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   if( (lstrlen(trace->searchEvent)+1) > maxLen ) 
      return(ER_NOT_ENOUGH_STORAGE);
   lstrcpy(event,trace->searchEvent);
   return(GOOD);
}
      
/*****************************************************************************
** 
**    TrcSearchEventSet
** 
*****************************************************************************/
RETCODE EXPORT TrcSearchEventSet(DESCRIPTOR id, LPSTR event) {
   if( lstrlen(event) > EVENT_NAME_LENGTH-1 ) return(ER_NOT_ENOUGH_STORAGE);
   lstrcpy(((TRACE_DESC_BLOCK FAR*)id)->searchEvent,event);
   return(GOOD);
}
      
/*****************************************************************************
** 
**    TrcSearchFrameGet
** 
*****************************************************************************/
RETCODE EXPORT TrcSearchFrameGet(DESCRIPTOR id, S32 FAR *frame) {
   TRACE_DESC_BLOCK FAR *trace;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   *frame = trace->searchStartFrame;
   return(GOOD);
}
      
/*****************************************************************************
** 
**    TrcSearchFrameSet
** 
*****************************************************************************/
RETCODE EXPORT TrcSearchFrameSet(DESCRIPTOR id, S32 frame) {
   RETCODE err;
   TRACE_DESC_BLOCK FAR *trace;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   if((err=ValidFrameNumber(trace->searchBuffer,frame,trace->debugEmon))
      !=GOOD) return(err);
   trace->searchStartFrame = frame;
   return(GOOD);
}
      
/*****************************************************************************
**
**    TrcTraceSearch
** 
*****************************************************************************/
RETCODE EXPORT TrcTraceSearch(DESCRIPTOR id, BOOLEAN FAR *found) {
   TRACE_DESC_BLOCK FAR *trace;
   BOOLEAN timedOut, exists;
   LOOP_VAR group;
   EVENT_GROUP_INFO sdEvent;
   RETCODE err;
   BOOLEAN   abortFromEsc;


   /* Get pointer to the Trace Setup Info */
   *found = FALSE;
   preFrameTS = 0.;     // Winky 12/23/97
   trace = (TRACE_DESC_BLOCK FAR *)id;
   if( (err=SdnWriteMember(SDN_SEARCH_BUFFER,(U8 FAR *)&trace->searchBuffer,
      GOOD)) != GOOD ) return(err);
// vincent   if( (err=SdnWriteMember(SDN_SEARCH_EMON,(U8 FAR *)&trace->debugEmon,
// vincent      GOOD)) != GOOD ) return(err);
   if((err=EvtDoesEventExist(trace->searchEvent,&exists))!=GOOD) return(err);
   if( !exists ) return(ER_NO_SUCH_EVENT);
   if( (err=EvtSetActiveEvent(trace->eventServerId,trace->searchEvent)) 
        != GOOD ) return(err);
   for (group=0; group<NUM_GROUPS; group++) {
      if( (err=EvtGetEventGroupInfo(trace->eventServerId,group,&sdEvent)) 
         != GOOD ) return(err);
      if((err=SdnWriteMember(SDN_SEARCH_EVENT+group,(U8 FAR*)&sdEvent,GOOD))
         != GOOD) return(err);
   }

   err = TskCheckAbort(&abortFromEsc);
   if(err!=GOOD) return err;
   if (abortFromEsc!=0)
      return ER_ABORT_FROM_ESC;


   if( (err = SdnWriteCmdReadResponse(SDN_SEARCH_START_FRAME, 
      &trace->searchStartFrame, GOOD, SDN_FOUND_SEARCH_EVENT, 40, 
         &timedOut)) != GOOD ) return(err);
   if( (err = SdnReadMember(SDN_FOUND_SEARCH_EVENT, (U8 FAR *)found))!=GOOD )
      return(err);
   if((err=SdnReadMember(SDN_SEARCH_START_FRAME,
      (U8 FAR *)&trace->searchStartFrame)) != GOOD ) return(err);
   return(GOOD);
}

/*****************************************************************************
** 
**    TrcUpdateTrace
**
*****************************************************************************/
RETCODE EXPORT TrcUpdateTrace(DESCRIPTOR id) {
   U16 traceBuffer;
   S32 oldest,youngest,trigger;
   RETCODE err;
   if((err=TrcCollectingBufferGet(&traceBuffer)) != GOOD )
      return(err);
   if((err=TrcReadBufferSet(id, traceBuffer)) != GOOD ) return(err);
   if((err=TrcTraceBufferInfoGet(id,&oldest,&youngest,&trigger))!=GOOD)
      return(err);
   if((err=TrcReadFrameSet(id, min(trigger,youngest))) != GOOD ) return(err);
   return(GOOD);
}

/*****************************************************************************
**
**    TrcCollectingBufferGet
**
*****************************************************************************/
RETCODE EXPORT TrcCollectingBufferGet(U16 FAR *traceBuffer) {
   RETCODE err;
   BOOLEAN traceIsEmpty;
   //Fixed bug ID#198 by Eric 2/3/98
   S32 oldest,youngest;
   U32 frameNo=0,num;
   TRACE_FRAME frames[0x20];
   //eof Eric 2/3/98

   *traceBuffer = 0;
   //Fixed bug ID#198 by Eric 2/3/98
   if ((err=Sds2AbiGetTraceFrames(*traceBuffer,frameNo,&num,(TRACE_FRAME *)&frames)
    ) != GOOD) {
     oldest=0;
     youngest=0;
     SdnWriteMember(SDN_BUFFER_YOUNGEST,&youngest,GOOD);
     SdnWriteMember(SDN_BUFFER_OLDEST,&oldest,GOOD);
     return(err);
   }
   //eof Eric 2/3/98
   if((err=SdnReadMember(SDN_TRACE_EMPTY,&traceIsEmpty))!=GOOD ) return(err);
   if(traceIsEmpty) return(GOOD);
   /* don't want to read bonus info if no trace data */
   if((err=SdnReadMember(SDN_CURRENT_SUBBUFFER,(U8 FAR *)traceBuffer))!=GOOD)
      return(err);
   *traceBuffer = CalculateTraceBufferFromSubBuffer(*traceBuffer);
   return(GOOD);
 }

/*****************************************************************************
**
**    TrcGetFrameInstAddress
**
*****************************************************************************/
RETCODE EXPORT TrcGetFrameInstAddress(DESCRIPTOR id, S32 frame, 
                              DESCRIPTOR FAR *addr, BOOLEAN FAR *frameIsInst){
   TRACE_DESC_BLOCK FAR *trace;
   RETCODE err;
   BOOLEAN  timedOut;
   U32 addrOffset;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   if((err=SdnWriteMember(SDN_LINKCURS_BUFFER,(U8 FAR *)&trace->traceBuffer,
      GOOD)) !=GOOD) return(err);
// vincent   if((err=SdnWriteMember(SDN_LINKCURS_EMON,(U8 FAR *)&trace->debugEmon,
// vincent      GOOD)) !=GOOD) return(err);
   if((err=SdnWriteCmdReadResponse(SDN_LINKCURS_FRAME, &frame, 
              GOOD, SDN_LINKCURS_INST, 10, &timedOut)) != GOOD ) 
      return(err);
   if((err=SdnReadMember(SDN_LINKCURS_ADDRESS,(U8 FAR *)&addrOffset))!=GOOD) 
      return(err);
   if((err=SdnReadMember(SDN_LINKCURS_INST,frameIsInst))!=GOOD) 
      return(err);
   
   if ((err = AdrCreateAddress(addr)) != GOOD)
      return err;
   if ((err = AdrSetAddrSpace(*addr,SPACE_SP)) != GOOD)
      return err;
   return(AdrSetAddrOffset(*addr,addrOffset));
}

/*****************************************************************************
**
**    TrcTimestampGet
**
*****************************************************************************/
RETCODE EXPORT TrcTimestampGet(DESCRIPTOR id, BOOLEAN FAR *value) {
   TRACE_DESC_BLOCK FAR *trace;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   *value = trace->timestampOn;
   return(GOOD);
}

/*****************************************************************************
**
**    TrcTimestampSet
**
*****************************************************************************/
RETCODE EXPORT TrcTimestampSet(DESCRIPTOR id, BOOLEAN value) {
   TRACE_DESC_BLOCK FAR *trace;

   trace = (TRACE_DESC_BLOCK FAR *)id;
   trace->timestampOn = value;
   optionFlag &= ~((U8)TIMESTAMP_OPT);
   optionFlag |= (value == TRUE) ? TIMESTAMP_OPT : 0;
   FormulateHeader(trace);
   preFrameTS=0.;             /* Judy 7/22/97 */
   return(EnlEventNotify(EVENT_TRACE_HEADER_CHANGED));
}

/*****************************************************************************
**
**    TrcTimestampModeGet
**
*****************************************************************************/
RETCODE EXPORT TrcTimestampModeGet(DESCRIPTOR id, TIMESTAMP_MODE FAR *value) {
   TRACE_DESC_BLOCK FAR *trace;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   *value = trace->tsMode;
   return(GOOD);
}

/*****************************************************************************
**
**    TrcTimestampModeSet
**
*****************************************************************************/
RETCODE EXPORT TrcTimestampModeSet(DESCRIPTOR id, TIMESTAMP_MODE value) {
   TRACE_DESC_BLOCK FAR *trace;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   trace->tsMode = value;
   preFrameTS=0.;             /* Judy 7/22/97 */
   TrcTimestampSet(id,TRUE);  /* force re-generation of header - new data */
/*   TrcTimestampSet(id,FALSE);   force re-generation of header - new data */
   return(GOOD);
}

/*****************************************************************************
**
**    TrcTimestampZeroFrameGet
**
*****************************************************************************/
RETCODE EXPORT TrcTimestampZeroFrameGet(DESCRIPTOR id, S32 FAR *frame) {
   TRACE_DESC_BLOCK FAR *trace;

   trace = (TRACE_DESC_BLOCK FAR *)id;
   *frame = trace->zeroedFrame;
   return(GOOD);
}
  
/*****************************************************************************
**
**    TrcTimestampZeroFrameSet
**
*****************************************************************************/
RETCODE EXPORT TrcTimestampZeroFrameSet(DESCRIPTOR id, S32 frame) {
   RETCODE err;
   TRACE_DESC_BLOCK FAR *trace;
   U32 zFrameTS;
   U8 zFrameTSM;
   U8 bufTime[40];

   trace = (TRACE_DESC_BLOCK FAR *)id;
   if((err=ValidFrameNumber(trace->traceBuffer,frame,trace->debugEmon))!=GOOD)
      return(err);
   trace->zeroedFrame = frame;
   TrcTimestampSet(id,TRUE);  /* force re-generation of header - new data */
   Sds2AbiReadFrameStamp(0, trace->zeroedFrame, &zFrameTS, &zFrameTSM);
   itoa(zFrameTSM, bufTime, 10);
   ultoa(zFrameTS, bufTime+1, 10);
   zeroedFrameTS = _atold(bufTime);
   return(GOOD);
}

/*****************************************************************************
**
**    TrcSystemCrystalGet
**
*****************************************************************************/
static S8 freqPrefix[4] = {' ','k','M'};
RETCODE EXPORT TrcSystemCrystalGet(LPSTR freqText) {
   U16 index=0;
   float freq = krystalFrequency;
   while( freq > 1000 ) {
      freq = freq / 1000;
      index++;
   }
   sprintf(freqText,"%6.3f%cHz ", freq, freqPrefix[index]);
   return(GOOD);
}
  
/*****************************************************************************
**
**    TrcSystemCrystalSet
**
*****************************************************************************/
RETCODE EXPORT TrcSystemCrystalSet(LPSTR freqText) {
   float freq;
   float multiplier=1;
   LPSTR ptr = freqText;
   LOOP_VAR i, len;
   len = strlen(ptr);
   for( i = 0; i < len; i++ ) {
      if( isdigit(ptr[i]) || (ptr[i]=='.') ||
                 (ptr[i]==',') || (ptr[i] == ' ')) continue;
      if( (ptr[i] == 'k') || (ptr[i] == 'K') ) multiplier = 1000;
      if( ptr[i] == 'M' ) multiplier = 1000000.;
      ptr[i] = '\0';
      break;
   }
   if( sscanf(ptr,"%f",&freq) == 1 ) {
      freq *= multiplier;
      if( (freq==(float)0) || (freq > (float)40000000.) || (freq < (float).01))
         return(ER_BAD_FREQUENCY);
      krystalFrequency = freq;
      systemPeriod = 1 / krystalFrequency;
      return(EnlEventNotify(EVENT_TRACE_HEADER_CHANGED)); // new ts data.
   }   
   return(ER_BAD_FREQUENCY);
}

/*************************** CLI FUNCTIONS ******************************/
RETCODE EXPORT TrcSetPreFrameTS() {
   RETCODE err=GOOD;
   preFrameTS=0.;
   return(err);
}   
RETCODE EXPORT TrcGetCliId(DESCRIPTOR FAR *trcCliId) {
   RETCODE err=GOOD;
   if( !traceId )
      err=TrcTraceOpen(&traceId,"hwtrc", CLOCK_CYCLE, TRIGGER_ALIGN);
   *trcCliId = traceId;
   return(err);
}   

RETCODE EXPORT TrcCliForwardRead( LPSTR cmdString, U32 argc, U32 argv[] ) {
   LPSTR lpBuff = NULL;
   RETCODE err, err1;
   U16 len;
   S8 resultBuff[128];
   S32 start,end;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( argc == 2 ) {
      err=
      TrcForwardRead(traceId,(U32)atoi(&cmdString[(U16)argv[1]]),&start,
                     &end,&lpBuff,&len);
   }
   else {  /* just return one trace frame if no number of frames given */
      err=TrcForwardRead(traceId, 10, &start, &end, &lpBuff, &len);
   }
   if( err && (err != ER_END_OF_BUFFER) ) return(err);
   if( start == end ) {
      lstrcpy(resultBuff,"No frames found");
      return(SendCliResults(resultBuff,cliServerHandle));
   }
   err1 = SendCliResults(lpBuff,cliServerHandle);
   if (lpBuff != NULL) TFree(lpBuff);
   if (!err) err = err1;
   return(err);
}

RETCODE EXPORT TrcCliBackwardRead( LPSTR cmdString, U32 argc, U32 argv[] ) {
   LPSTR lpBuff;
   RETCODE err;
   U16 len;
   S32 start,end;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( argc == 2 ) {
      err=TrcBackwardRead(traceId,(U32)atoi(&cmdString[(U16)argv[1]]), 
                  &start,&end,&lpBuff,&len);
   }
   else {  /* just return one trace frame if no number of frames given */
      err=TrcBackwardRead(traceId, 10, &start, &end, &lpBuff, &len);
   }
   if( err && (err != ER_END_OF_BUFFER) ) return(err);
   err=SendCliResults(lpBuff,cliServerHandle);
   TFree(lpBuff);
   return(err);
}

RETCODE EXPORT TrcCliReadRaw( LPSTR cmdString, U32 argc, U32 argv[] ) {
   TRACE_INFO *frames;
   RETCODE err;
   LPSTR results, ptr;
   LOOP_VAR i;
   U32 numFrames;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( argc == 2 ) {
      if( (err=TrcTraceReadRaw(traceId, (U32)atoi(&cmdString[(U16)argv[1]]),
         &numFrames,(LPSTR *)&frames)) != GOOD ) return(err);
   }
   else {  /* just return one trace frame if no number of frames given */
      if((err=TrcTraceReadRaw(traceId,1,&numFrames,(LPSTR*)&frames)) != GOOD )
         return(err);
   }
   results = TMalloc(numFrames*75);
   ptr = results;
   *ptr = NULL;
   for( i=0; i<numFrames; i++ ) {
      wsprintf(ptr,"   %8ld     %08lX    %08lX    %08lX    %08lX\r\n",
         frames[i].frameNumber,frames[i].rGroup,
         frames[i].sGroup, frames[i].tGroup, frames[i].uGroup);
      ptr = results + lstrlen(results);
   }
   err = SendCliResults(results,cliServerHandle);
   TFree(results);
   TFree((LPSTR)frames);
   return(err);
}


#pragma argsused
RETCODE EXPORT TrcCliBufferInfo(LPSTR cmdString, U32 argc, U32 argv[]) {
   S32 oldest, youngest, trigger;
   S8 resultBuff[128];
   RETCODE err;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( (err=TrcTraceBufferInfoGet(traceId, &oldest, &youngest, &trigger)) 
      != GOOD ) return(err);
   wsprintf(resultBuff,"start: %ld; end: %ld; trigger: %ld", 
                        oldest, youngest, trigger);
   return(SendCliResults(resultBuff,cliServerHandle));
}

#define START_ALIGN_TEXT "START_ALIGN"
#define TRIGGER_ALIGN_TEXT "TRIGGER_ALIGN"
#define NO_ALIGN_TEXT "NO_ALIGN"
FRAME_DISPLAY_MODE parseFrameMode(LPSTR ptr) {
   FRAME_DISPLAY_MODE mode;
   if( ptr[0] == '0' )
      mode = START_ALIGN;
   else if( ptr[0] == '1' )
      mode = TRIGGER_ALIGN;
   else if( ptr[0] == '2' )
      mode = NO_ALIGN;
   else if(strncmpi(ptr, START_ALIGN_TEXT, strlen(ptr))==0) 
      mode = START_ALIGN;
   else if(strncmpi(ptr, TRIGGER_ALIGN_TEXT, strlen(ptr))==0) 
      mode = TRIGGER_ALIGN;
   else 
      mode = NO_ALIGN;      
   return(mode);
}

RETCODE EXPORT TrcCliFrameMode(LPSTR cmdString, U32 argc, U32 argv[]) {
   FRAME_DISPLAY_MODE mode;
   S8 resultBuff[128];
   RETCODE err;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( argc == 2 ) {
      mode = parseFrameMode(&cmdString[(U16)argv[1]]);
      if( (err=TrcFrameDisplayModeSet(traceId, mode)) != GOOD ) return(err);
   }
   if( (err=TrcFrameDisplayModeGet(traceId,&mode)) != GOOD ) return(err);
   if( mode == START_ALIGN ) lstrcpy(resultBuff,START_ALIGN_TEXT);
   else if( mode == TRIGGER_ALIGN ) lstrcpy(resultBuff,TRIGGER_ALIGN_TEXT);
   else lstrcpy(resultBuff,NO_ALIGN_TEXT);
   return(SendCliResults(resultBuff,cliServerHandle));
}

#define BUS_CYCLE_TEXT "BUS_CYCLE"
#define CLOCK_CYCLE_TEXT "CLOCK_CYCLE"
TRACE_CYCLES parseTraceCycleMode(LPSTR ptr) {
   TRACE_CYCLES mode;
   if( ptr[0] == '0' )
      mode = BUS_CYCLE;
   else if( ptr[0] == '1' )
      mode = CLOCK_CYCLE;
   else if(strncmpi(ptr, BUS_CYCLE_TEXT, strlen(ptr))==0) 
      mode = BUS_CYCLE;
   else if(strncmpi(ptr, CLOCK_CYCLE_TEXT, strlen(ptr))==0) 
      mode = CLOCK_CYCLE;
   else
      mode = BINARY_CYCLE;
   return(mode);
}

RETCODE EXPORT TrcCliTraceCycle(LPSTR cmdString, U32 argc, U32 argv[]) {
   TRACE_CYCLES mode;
   S8 resultBuff[128];
   RETCODE err;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( argc == 2 ) {
      mode = parseTraceCycleMode(&cmdString[(U16)argv[1]]);
      if( (err=TrcTraceCycleSet(traceId, mode)) != GOOD )
         return(err);
   }
   if( (err=TrcTraceCycleGet(traceId,&mode)) != GOOD ) return(err);
   if( mode == BUS_CYCLE ) lstrcpy(resultBuff,BUS_CYCLE_TEXT);
   else if( mode == CLOCK_CYCLE ) lstrcpy(resultBuff,CLOCK_CYCLE_TEXT);
   else lstrcpy(resultBuff,"BINARY_CYCLE");
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT TrcCliReadBuffer(LPSTR cmdString, U32 argc, U32 argv[]) {
   U16 trcBuffer;
   S8 resultBuff[128];
   RETCODE err;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( argc == 2 ) {
      if((err=TrcReadBufferSet(traceId,atoi(&cmdString[(U16)argv[1]])))!=GOOD)
         return(err);
   }
   if( (err=TrcReadBufferGet(traceId,&trcBuffer)) != GOOD ) return(err);
   wsprintf(resultBuff,"%d", trcBuffer);
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT TrcCliSearchBuffer(LPSTR cmdString, U32 argc, U32 argv[]) {
   U16 trcBuffer;
   S8 resultBuff[128];
   RETCODE err;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( argc == 2 ) {
      if((err=TrcSearchBufferSet(traceId,atoi(&cmdString[(U16)argv[1]])))
         !=GOOD) return(err);
   }
   if( (err=TrcSearchBufferGet(traceId,&trcBuffer))!=GOOD ) return(err);
   wsprintf(resultBuff,"%d", trcBuffer);
   return(SendCliResults(resultBuff,cliServerHandle));
}

#pragma argsused
RETCODE EXPORT TrcCliGetCollectingBuffer(LPSTR cmdString, U32 argc, 
                                         U32 argv[]) {
   U16 buffer;
   S8 resultBuff[128];
   RETCODE err;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( (err=TrcCollectingBufferGet(&buffer)) != GOOD ) return(err);
   wsprintf(resultBuff,"last collected trace buffer: %d", buffer);
   return(SendCliResults(resultBuff,cliServerHandle));
}

#pragma argsused
RETCODE EXPORT TrcCliNumFrames(LPSTR cmdString, U32 argc, U32 argv[]) {
   U32 numFrames;
   S8 resultBuff[128];
   RETCODE err;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( (err=TrcNumFramesGet(traceId,&numFrames)) != GOOD ) return(err);
   wsprintf(resultBuff,"%ld", numFrames);
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT TrcCliReadFrame(LPSTR cmdString, U32 argc, U32 argv[]) {
   S8 *ptr;
   S32 frame;
   S8 resultBuff[128];
   RETCODE err;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( (argc == 3) || (argc == 2) ) {
      if( cmdString[(U16)argv[1]] == '-' ) {
         strcpy(resultBuff,"-");
         strcat(resultBuff,&cmdString[(U16)argv[2]]);
      }
      else {
         strcpy(resultBuff,&cmdString[(U16)argv[1]]);
      }         
      frame = strtol(resultBuff,&ptr,0);
      if( lstrlen(ptr) != 0 ) return(ER_INVALID_FRAME);
      if( (err=TrcReadFrameSet(traceId,frame)) != GOOD ) return(err);
   }
   if( (err=TrcReadFrameGet(traceId,&frame)) != GOOD ) return(err);
   wsprintf(resultBuff,"%ld", frame);
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT TrcCliSearchFrame(LPSTR cmdString, U32 argc, U32 argv[]) {
   S8 *ptr;
   S32 frame;
   S8 resultBuff[128];
   RETCODE err;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( (argc == 3) || (argc == 2) ) {
      if( cmdString[(U16)argv[1]] == '-' ) {
         strcpy(resultBuff,"-");
         strcat(resultBuff,&cmdString[(U16)argv[2]]);
      }
      else {
         strcpy(resultBuff,&cmdString[(U16)argv[1]]);
      }         
      frame = strtol(resultBuff,&ptr,0);
      if( lstrlen(ptr) != 0 ) return(ER_INVALID_FRAME);
      if( (err=TrcSearchFrameSet(traceId,frame)) != GOOD ) return(err);
   }
   if( (err=TrcSearchFrameGet(traceId,&frame)) != GOOD ) return(err);
   wsprintf(resultBuff,"%ld", frame);
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT TrcCliSearchEvent(LPSTR cmdString, U32 argc, U32 argv[]) {
   S8 resultBuff[128];
   RETCODE err;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( argc == 2 ) {
      if( (err=TrcSearchEventSet(traceId, &cmdString[(U16)argv[1]]))!=GOOD ) 
         return(err);
   }
   if((err=TrcSearchEventGet(traceId,resultBuff,128)) != GOOD) return(err);
   return(SendCliResults(resultBuff,cliServerHandle));
}

#pragma argsused
RETCODE EXPORT TrcCliTraceSearch(LPSTR cmdString, U32 argc, U32 argv[]) {
   S8 resultBuff[128];
   BOOLEAN found;
   RETCODE err;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( (err=TrcTraceSearch(traceId, &found)) != GOOD ) return(err);
   if( found ) {
      S32 frame;
      U16 buffer;
      if( (err=TrcSearchBufferGet(traceId, &buffer)) != GOOD ) return(err);
      if( (err=TrcReadBufferSet(traceId, buffer)) != GOOD ) return(err);
      if( (err=TrcSearchFrameGet(traceId, &frame)) != GOOD ) return(err);
      if( (err=TrcReadFrameSet(traceId, frame)) != GOOD ) return(err);
      wsprintf(resultBuff,"Search found match at FRAME: %6ld",frame);
   }
   else lstrcpy(resultBuff,"Search found NO match");
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT TrcCliDebugEmon(LPSTR cmdString, U32 argc, U32 argv[]) {
   S8 resultBuff[128];
   RETCODE err;
   TRACE_DESC_BLOCK FAR *trace;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   trace = (TRACE_DESC_BLOCK FAR *)traceId;
   if( argc == 2 ) {
      BOOLEAN value;
      value = ParseBoolean(&cmdString[(U16)argv[1]]);
      if( trace->debugEmon != value ) {
         if((err=SetupBufferCheck(trace->traceBuffer,value))!=GOOD)
            return(err);
         trace->debugEmon = value;
         FormulateHeader(trace);
         if((err=EnlEventNotify(EVENT_TRACE_HEADER_CHANGED)) != GOOD ) 
            return(err); 
      }
   }
   if( trace->debugEmon ) lstrcpy(resultBuff,"DEBUG EMON ON");
   else lstrcpy(resultBuff,"DEBUG EMON OFF");
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT TrcCliTracing(LPSTR cmdString, U32 argc, U32 argv[]) {
   BOOLEAN value;
   S8 resultBuff[128];
   RETCODE err;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( argc == 2 ) {
      value = ParseBoolean(&cmdString[(U16)argv[1]]);
      if((err=TrcTracingSet(value))!=GOOD) return(err);
   }
   if( (err=TrcTracingGet(&value)) != GOOD ) return(err);
   if( value ) lstrcpy(resultBuff,"TRACING");
   else lstrcpy(resultBuff,"NOT TRACING");
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT TrcCliTraceTemplate(LPSTR cmdString, U32 argc, U32 argv[]) {
   S8 resultBuff[128];
   RETCODE err;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( argc == 2 ) {
      if( (err=TrcTraceTemplateSet(traceId, &cmdString[(U16)argv[1]]))!=GOOD) 
         return(err);
   }
   if((err=TrcTraceTemplateGet(traceId,resultBuff,128)) != GOOD) return(err);
   return(SendCliResults(resultBuff,cliServerHandle));
}

#pragma argsused
RETCODE EXPORT TrcCliGetHeader(LPSTR cmdString, U32 argc, U32 argv[]) {
   S8 resultBuff[NUM_HDR_LINES*MAX_HDR_LINE+1];
   RETCODE err;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if((err=TrcGetHeader(traceId,resultBuff,NUM_HDR_LINES*MAX_HDR_LINE+1)) 
      != GOOD) return(err);
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT TrcCliOpen( LPSTR cmdString, U32 argc, U32 argv[] ) {
   RETCODE err;
   TRACE_CYCLES tMode;
   FRAME_DISPLAY_MODE fMode;
   S8 fileName[128];
   if( argc == 4 ) {
      tMode = parseTraceCycleMode(&cmdString[(U16)argv[2]]);
      fMode = parseFrameMode(&cmdString[(U16)argv[3]]);
      lstrcpy(fileName,&cmdString[(U16)argv[1]]);
   }
   else {
      tMode = CLOCK_CYCLE;
      fMode = TRIGGER_ALIGN;
      lstrcpy(fileName,"hwtrc");
      if( argc == 2 ) traceId = saveLastTraceId;
   }
   if( !traceId ) {
      err = TrcTraceOpen(&traceId,
               fileName,                    /* trace file name */
               tMode,                       /* cycle mode */
               fMode);                      /* frame mode */
   }
   else {
      err=GOOD;
      if( argc != 2 ) 
         InitializeTraceState(traceId, tMode, fMode);
   }
   if( err != GOOD ) return(err);
   return(SendCliResults((LPSTR)"trace opened",cliServerHandle));
}

#pragma argsused
RETCODE EXPORT TrcCliClose( LPSTR cmdString, U32 argc, U32 argv[] ) {
   RETCODE err=GOOD;
   if( traceId ){
      err = TrcTraceClose(traceId);
      traceId = 0;
   }
   return(err);
}

#pragma argsused
RETCODE EXPORT TrcCliClearTrace( LPSTR cmdString, U32 argc, U32 argv[] ) {
   return(TrcTraceBufferClear());
}

RETCODE EXPORT TrcCliGetFrameInstAddress(LPSTR cmdString, U32 argc, 
                     U32 argv[]) {
   DESCRIPTOR addr;
   BOOLEAN instFrame;
   S32 frame;
   S8 resultBuff[128];
   U32 offset;
   RETCODE err;
   S8 *ptr;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( (argc == 3) || (argc == 2) ) {
      if( cmdString[(U16)argv[1]] == '-' ) {
         strcpy(resultBuff,"-");
         strcat(resultBuff,&cmdString[(U16)argv[2]]);
      }
      else {
         strcpy(resultBuff,&cmdString[(U16)argv[1]]);
      }         
      frame = strtol(resultBuff,&ptr,0);
      if( lstrlen(ptr) != 0 ) return(ER_INVALID_FRAME);
      if((err=TrcGetFrameInstAddress(traceId,frame,&addr,&instFrame))!=GOOD) 
         return(err);
      if((err=AdrGetAddrOffset(addr,&offset))!=GOOD) return(err);
      if( instFrame )
         wsprintf(resultBuff,
         "frame:  %ld   contains instruction address:   %lX", frame, offset);
      else
         wsprintf(resultBuff,
            " frame:  %ld  is NOT an instruction read frame", frame);
      return(SendCliResults(resultBuff,cliServerHandle));
   }
   return(ER_CLI_SYNTAX);
}

#pragma argsused
RETCODE EXPORT TrcCliUpdateTrace( LPSTR cmdString, U32 argc, U32 argv[] ) {
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   return(TrcUpdateTrace(traceId));
}

#pragma argsused
RETCODE EXPORT TrcCliFrameNumberAreaSizeGet(LPSTR cmdString, U32 argc,
                                            U32 argv[] ) {
   S8 resultBuff[128];
   U16 num;
   RETCODE err;
   if((err = TrcFrameNumberAreaSizeGet(&num))!=GOOD) return(err);
   wsprintf(resultBuff,"frame number area:  %d",num);
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT TrcCliGetTimestamp(LPSTR cmdString, U32 argc, U32 argv[]) {
   S8 resultBuff[128];
   RETCODE err;
   TRACE_DESC_BLOCK FAR *trace;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   trace = (TRACE_DESC_BLOCK FAR *)traceId;
   if( argc == 2 ) {
      BOOLEAN value;
      value = ParseBoolean(&cmdString[(U16)argv[1]]);
      if( trace->timestampOn != value ) {
         if( (err=TrcTimestampSet(traceId,value)) != GOOD ) return(err);
      }
   }
   if( trace->timestampOn ) lstrcpy(resultBuff,"timestamp on");
   else lstrcpy(resultBuff,"timestamp off");
   return(SendCliResults(resultBuff,cliServerHandle));
}

#define RELATIVE_TEXT "RELATIVE"
#define DELTA_TEXT "DELTA"
#define ABSOLUATE_TEXT "ABSOLUATE"
TIMESTAMP_MODE parseTimestampMode(LPSTR ptr) {
   TIMESTAMP_MODE mode;
   if( ptr[0] == '0' )
      mode = RELATIVETOFRAME;
   else if( ptr[0] == '1' )
      mode = DELTA;
   else if( ptr[0] == '2' )
      mode = ABSOLUATE;
   else if(strncmpi(ptr, RELATIVE_TEXT, strlen(ptr))==0) 
      mode = RELATIVETOFRAME;
   else if(strncmpi(ptr, DELTA_TEXT, strlen(ptr))==0) 
      mode = DELTA;
   else if(strncmpi(ptr, ABSOLUATE_TEXT, strlen(ptr))==0)
      mode = ABSOLUATE;
   return(mode);
}

RETCODE EXPORT TrcCliTimestampMode(LPSTR cmdString, U32 argc,
                                          U32 argv[]) {
   S8 resultBuff[128];
   RETCODE err;
   TRACE_DESC_BLOCK FAR *trace;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   trace = (TRACE_DESC_BLOCK FAR *)traceId;
   if( argc == 2 ) {
      TIMESTAMP_MODE value;
      value = parseTimestampMode(&cmdString[(U16)argv[1]]);
      if( trace->tsMode != value ) {
         if( (err=TrcTimestampModeSet(traceId,value))!=GOOD ) return(err);
      }
   }
   if( trace->tsMode == RELATIVETOFRAME )
      lstrcpy(resultBuff,"relative to frame");
   else lstrcpy(resultBuff,"delta");
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT TrcCliGetZeroFrame(LPSTR cmdString, U32 argc, U32 argv[]) {
   S8 *ptr;
   S32 frame;
   S8 resultBuff[128];
   RETCODE err;
   if( !traceId ) return(ER_NO_TRACE_OPEN);
   if( (argc == 3) || (argc == 2) ) {
      if( cmdString[(U16)argv[1]] == '-' ) {
         strcpy(resultBuff,"-");
         strcat(resultBuff,&cmdString[(U16)argv[2]]);
      }
      else {
         strcpy(resultBuff,&cmdString[(U16)argv[1]]);
      }         
      frame = strtol(resultBuff,&ptr,0);
      if( lstrlen(ptr) != 0 ) return(ER_INVALID_FRAME);
      if( (err=TrcTimestampZeroFrameSet(traceId,frame)) != GOOD ) return(err);
   }
   if( (err=TrcTimestampZeroFrameGet(traceId,&frame)) != GOOD ) return(err);
   wsprintf(resultBuff,"%ld", frame);
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT TrcCliGetfrequency(LPSTR cmdString, U32 argc, U32 argv[]) {
   S8 resultBuff[128];
   RETCODE err;
   if( argc == 2 ) {
      if( (err=TrcSystemCrystalSet(&cmdString[(U16)argv[1]])) != GOOD )
         return(err);
   }
   if( (err=TrcSystemCrystalGet(resultBuff)) != GOOD ) return(err);
   return(SendCliResults(resultBuff,cliServerHandle));
}

RETCODE EXPORT CliFlashRom(LPSTR cmdString, U32 argc, U32 argv[] ) {
   S8 *ptr;
   U8 resultBuff[128], i, tmpBuff[33], tBuff[3];
   RETCODE err;
   if( argc > 1 ) {
     if((err = Sds2AbiReadFRom(tmpBuff))!=GOOD) return(err);
      for (i=0; i< argc-1; i++) {
          strcpy(tBuff,&cmdString[(U16)argv[i+1]]);
          resultBuff[i] = (S8)strtol(tBuff,&ptr,16);
          }
     for (; i<32; i++)
         resultBuff[i]=tmpBuff[i];
     if((err = Sds2AbiWriteFRom(resultBuff))!=GOOD) return(err);
   }
   tmpBuff[0]='\0';
   if((err = Sds2AbiReadFRom(tmpBuff))!=GOOD) return(err);
   for (i=0; i<32 ;i++) {
       itoa((tmpBuff[i] & 0xf0), resultBuff+i*3, 16);
       itoa((tmpBuff[i] & 0x0f), resultBuff+i*3+1, 16);
       resultBuff[i*3+2]=' ';
   }
   resultBuff[i*3]='\0';
   return(SendCliResults(resultBuff,cliServerHandle));
}

/*************************** LOCAL FUNCTIONS ******************************/
/**************************************************************************
**
** ValidFrameNumber
**
** Description:
**    Determines if the incoming physical frame is valid for the given
**    trace buffer. The frame number is compared against the oldest
**    and youngest frames for the given buffer.
**
***************************************************************************/
RETCODE  ValidFrameNumber(U16 buffer, S32 frame, BOOLEAN emon){   
   RETCODE err;
   S32 oldest, youngest;
   if((err=SetupBufferCheck(buffer,emon))!=GOOD) return(err);
   if((err=SdnReadMember(SDN_BUFFER_OLDEST,(U8 FAR *)&oldest))!=GOOD) 
      return(err);
   if((err=SdnReadMember(SDN_BUFFER_YOUNGEST,(U8 FAR *)&youngest))!=GOOD) 
      return(err);
   if( (frame < oldest) || (frame >youngest) ) return(ER_INVALID_FRAME);
   return(GOOD);
}

char levelCode[4]={'0','1','2','3'};
char *traceCode[2]={"0","1"};
/* format : start1, len1, start2, len2, ...... */
U8   CFG302[]={1, 2, 3, 14, 17, 8, 25, 2};
U8   CFG306[]={1, 2, 3, 15, 18, 8, 26, 2};
U8   CFG307[]={1, 2, 3, 13, 16, 8, 24, 2};
U8   CFG328[]={1, 2, 3, 11, 14, 8, 22, 2};  /* not surport */

RETCODE  FormatFrameToText(DESCRIPTOR tmpltId, TRACE_INFO *framePtr,
                           S32 prevFrame, DESCRIPTOR id, LPSTR dataPtr) {
   S8 lineBuff[128];
   RETCODE err;
   PROBE_TYPE specificProcessor;
   LOOP_VAR i,j;
   U16 tmp, trcStart, trcStop;
   ACTION_MASK actionMask[8];
   U8 *cfgFields;
   BOOLEAN useEvt;

   U32 FrameTS;  /* test <Judy 7/22/97> */
   U8 FrameTSM;  /* test <Judy 7/22/97> */

   ProcReturnSpecificProcessor(&specificProcessor);
   switch (specificProcessor) {
   case M68302_MP:
      cfgFields = CFG302;
      break;
   case M68306_MP:
      cfgFields = CFG306;
      break;
   case M68307_MP:
      cfgFields = CFG307;
      break;
   case M68328_MP:
      cfgFields = CFG302;  // not surport
      break;
   }

   wsprintf(lineBuff," %8ld ", framePtr->frameNumber);
   lstrcat(dataPtr,lineBuff);
// vincent   if((err=TrcGetTimestampText(id,framePtr->frameNumber,prevFrame,dataPtr))
// vincent       != GOOD ) return(err);
//   if((err=TmpltGetFormattedTrace(tmpltId,dataPtr,
//                                  (XILINX_GROUP FAR *)&framePtr->rGroup))
//      != GOOD ) return(err);

   tmp= framePtr->leGroup & 0xff;
   if (tmp != 0) {
      if( (err=TrigTriggerOpen(&theTrigger,"","default")) != GOOD )
         return(err);
      TrigEventSet(theTrigger,tmp);
      // Winky 3/2/98 : 0x0ff -> 0x03
      TrigSeqLevelSet(theTrigger,(framePtr->leGroup >> 8) & 0x03);

      TrigEventEnableGet(theTrigger,&useEvt);
   } else
      useEvt = FALSE;

   for (i=0x80, j=7; j>=0; i>>=1, j--) {
       actionMask[j]=0;
       if ((tmp & i) != 0) {
          TrcActionGet(j,(framePtr->leGroup >> 8) & 0x03,&actionMask[j]);
       }
   }
   for (i=tmp=trcStart=trcStop=0;i<8;i++) {
       tmp |= ((actionMask[i] & TRC_QUAL_MASK) == TRC_QUAL_MASK) ? 1 : 0;
       trcStart|=((actionMask[i] & TRC_START_MASK) == TRC_START_MASK) ? 1 : 0;
       trcStop|=((actionMask[i] & TRC_STOP_MASK) == TRC_STOP_MASK) ? 1 : 0;
   }
   if (tmp != 1) {
      if (framePtr->frameNumber < 0)
         trcMark=(trcMarkFrameOn > framePtr->frameNumber) ? 0: 1;
      else
         trcMark=(trcMarkFrameOn > framePtr->frameNumber) ? 1: 0;
      if (trcStart == 1) {
          trcMark2FrameOn=(trcMarkFrameOn==framePtr->frameNumber) ?
                          trcMark2FrameOn : trcMarkFrameOn;
          trcMarkFrameOn=framePtr->frameNumber;
          trcMark=1;
         }
      if (trcStop == 1) {
         trcMarkFrameOff=framePtr->frameNumber;
         trcMark=0;
      }
   }
   if (tmp == 1 && useEvt)
      lstrcat(dataPtr,"@ ");
   else {
      if (trcMark == 1 ||
         ((framePtr->frameNumber < 0) &&
          ((trcMarkFrameOn <= framePtr->frameNumber) ||
           (trcMark2FrameOn !=0 && trcMark2FrameOn <= framePtr->frameNumber)) &&
          (trcMarkFrameOff > framePtr->frameNumber)) ||
         ((framePtr->frameNumber > 0) &&
          ((trcMarkFrameOn >= framePtr->frameNumber) ||
           (trcMark2FrameOn !=0 && trcMark2FrameOn >= framePtr->frameNumber)) &&
          (trcMarkFrameOff < framePtr->frameNumber)))
         lstrcat(dataPtr,"* ");
      else
         lstrcat(dataPtr,"  ");
   }

   if (optionFlag & TIMESTAMP_OPT)
      if((err=TrcGetTimestampText(id,framePtr->tsGroup,framePtr->tshGroup,
                prevFrame,dataPtr)) != GOOD ) return(err);

/* <Judy 7/29/97> test */
        Sds2AbiReadFrameStamp(0, framePtr->frameNumber, &FrameTS, &FrameTSM);
/* eof <Judy 7/29/97> */

   if((err=TmpltGetFormattedFields(tmpltId,dataPtr,
              (XILINX_GROUP FAR *)&framePtr->rGroup,
              cfgFields[0],cfgFields[1])) != GOOD ) return(err);

   if (optionFlag & STATUS_OPT) {
      if((err=TmpltGetFormattedFields(tmpltId,dataPtr,
                    (XILINX_GROUP FAR *)&framePtr->rGroup,
                    cfgFields[2],cfgFields[3])) != GOOD ) return(err);
   }

   if (optionFlag & TRACE_OPT) {
      if((err=TmpltGetFormattedFields(tmpltId,dataPtr,
                    (XILINX_GROUP FAR *)&framePtr->rGroup,
                    cfgFields[4],cfgFields[5])) != GOOD ) return(err);
   }

   if (optionFlag & TPORT_OPT) {
      if((err=TmpltGetFormattedFields(tmpltId,dataPtr,
                    (XILINX_GROUP FAR *)&framePtr->rGroup,
                    cfgFields[6],cfgFields[7])) != GOOD ) return(err);
   }

   if (optionFlag & LEVEL_OPT) {
      wsprintf(lineBuff," %c ", levelCode[(framePtr->leGroup >> 8) & 0x03]);
      lstrcat(dataPtr,lineBuff);
   }

   if ((optionFlag & EVENT_OPT)!=0) {
      lstrcat(dataPtr," ");
      tmp= framePtr->leGroup & 0xff;
      for (i=0x80, j=0; j<8; i>>=1, j++) {
          if ((tmp & i) == 0)
             lstrcat(dataPtr,traceCode[0]);
          else
             lstrcat(dataPtr,traceCode[1]);
         }
      lstrcat(dataPtr," ");
   }

   if ((optionFlag & ACTION_OPT) && ((framePtr->leGroup & 0x0ff) != 0) &&
         useEvt) {
      TrcGetActionText(actionMask, dataPtr);
   }

   lstrcat(dataPtr,END_OF_LINE_TEXT);
   return(GOOD);
}

RETCODE ReadTrace(DESCRIPTOR id, S32 numFrames, BOOLEAN raw, LPSTR *buffer){
   S32 numFramesRead, prevFrame;
   U32 nBytes, absFrameCount;
   TRACE_DESC_BLOCK FAR *trace;
   TRACE_INFO *framePtr;
   LPSTR dataPtr;
   RETCODE err,readErr;
   LOOP_VAR i, frameIdx, startIdx;
   BOOLEAN timedOut, backwards, gotPrev = FALSE;
   BOOLEAN  abortFromEsc;


   trace = (TRACE_DESC_BLOCK FAR *)id;
   startingFrame = endingFrame = 0;  /* special case - frames found */
   absFrameCount = numFrames;
   backwards = (numFrames < 0);
   if( backwards ) absFrameCount = 0 - numFrames;
   numFrames = 0;
   if( (absFrameCount > 256) && !raw ) return(ER_TOO_MANY_FRAMES);
   if( (*buffer = TMalloc((
      (raw?sizeof(TRACE_INFO):MAX_TEXT_PER_FRAME)*absFrameCount)+1))
      == NULL) return(ER_OUT_OF_MEMORY);
   if((framePtr=(TRACE_INFO FAR *)TMalloc(sizeof(TRACE_INFO)*absFrameCount))
      == NULL ) {
      TFree(*buffer);
      *buffer = NULL;
      return(ER_OUT_OF_MEMORY);
   }
   dataPtr = *buffer;
   *dataPtr = '\0';   /* initialize string to be empty */
   frameIdx = 0;
   if( backwards ) frameIdx = (LOOP_VAR)absFrameCount;
   while( absFrameCount ) {
      S32 curFrameCount = min(absFrameCount,0x20);
      TRACE_INFO timestampMarker;
      if( (err = SdWriteMember(trace->traceFrameDesc,
         (U8 FAR *)&trace->startFrame, GOOD)) != GOOD ) {
         TFree((LPSTR)framePtr);
         return(err);
      }
      if( backwards ) /* doing backwards read */
         curFrameCount = 0 - curFrameCount;  /* made count negative */
      readErr=SdWriteCmdReadResponse(trace->traceLenDesc,&curFrameCount,
        GOOD, trace->traceStoreDesc, 0,&timedOut);
      if((err=SdReadMember(trace->traceLenDesc,
         (U8 FAR *)&numFramesRead))!=GOOD) return(err);
      // fw returns 1 even if none read!!!!
      if( numFramesRead == 1 || numFramesRead == 0) {
         if( !numFrames ) {   /* if we haven't read any frames */
            TFree((LPSTR)framePtr);
            return(readErr);
            //return(ER_DQ_NO_FRAMES_AVAILABLE);//Fixed bug ID#246 by Eric 3/3/98
         }
         break;
      }
      if( (err = SdReadPartialMember(trace->traceStoreDesc, 0,
                                     sizeof(TRACE_INFO),
                                     ((U8 FAR *)&timestampMarker)))
           != GOOD ) {
         TFree((LPSTR)framePtr);
         return(err);
      }
      if( timestampMarker.rGroup != 0xffffffffL ) {
         TFree((LPSTR)framePtr);
         return(ER_BAD_TRACE_INFO);
      }
      if( !gotPrev || backwards ) {
         prevFrame = timestampMarker.frameNumber;
         gotPrev = TRUE;
      }
      numFramesRead--;   // remove timestamp entry
      nBytes = sizeof(TRACE_INFO) * numFramesRead;
      numFrames += numFramesRead;
      if( backwards ) frameIdx -= (LOOP_VAR)numFramesRead;
      if( (err = SdReadPartialMember(trace->traceStoreDesc,sizeof(TRACE_INFO),
          nBytes, ((U8 FAR *)&framePtr[frameIdx]))) != GOOD ) {
         TFree((LPSTR)framePtr);
         return(err);
      }
      // frameIdx = 0 is timestampMarker.
      if( backwards ) startingFrame = framePtr[frameIdx].frameNumber-1;
      else startingFrame = framePtr[(U16)numFrames-1].frameNumber+1;
      if( TrcReadFrameSet(id,startingFrame) != GOOD ) break;
      if( !backwards ) frameIdx += (LOOP_VAR)numFramesRead;
      absFrameCount -= numFramesRead;
   }
   startIdx = 0;
   if( backwards ) startIdx = frameIdx;
   startingFrame = framePtr[startIdx].frameNumber;
   endingFrame = framePtr[(U16)(startIdx+numFrames-1)].frameNumber;
   if( raw ) {
      for( i=startIdx; i < (startIdx+numFrames); i++ ) {
         memcpy(dataPtr,(LPSTR)&framePtr[i],sizeof(TRACE_INFO));
         dataPtr += sizeof(TRACE_INFO);
         numRetrieved++;   

         err = TskCheckAbort(&abortFromEsc);
         if(err!=GOOD)        { break; }
         if (abortFromEsc!=0) { err = ER_ABORT_FROM_ESC; break; }

      }
   }
   else {
      for( i=startIdx; i < (startIdx+numFrames); i++ ) {
         if((err=FormatFrameToText(trace->templateId,&framePtr[i], prevFrame,
                                   id,dataPtr)) != GOOD) break;
         prevFrame = framePtr[i].frameNumber;

         err = TskCheckAbort(&abortFromEsc);
         if(err!=GOOD)        {  break; }
         if (abortFromEsc!=0) { err = ER_ABORT_FROM_ESC; break; }
      }
   }
   TFree((LPSTR)framePtr);   
   return(err);
}

/**************************************************************************
**
** FormulateHeader
**
** Description:
**    Using the template server given formulates the header string
**    for displaying bus and clock cycles.
**
** Parameters:
**    input:
**       template:      template server id
**       header:        pointer to header storage
**    output:
**       header:        storage contains header text
**
***************************************************************************/
RETCODE FormulateHeader(TRACE_DESC_BLOCK FAR *trace) {
//   U8 displayLen;
   U16 linePos, tempPos;
   RETCODE err;
   LOOP_VAR i,j;
   COUNTER_TYPE tcMode;
   PROBE_TYPE specificProcessor;
   U8 *cfgFields;

   ProcReturnSpecificProcessor(&specificProcessor);
   switch (specificProcessor) {
   case M68302_MP:
      cfgFields = CFG302;
      break;
   case M68306_MP:
      cfgFields = CFG306;
      break;
   case M68307_MP:
      cfgFields = CFG307;
      break;
   case M68328_MP:
      cfgFields = CFG302;  // not surport
      break;
   }

   for( i=0; i < NUM_HDR_LINES*MAX_HDR_LINE; i++ ) 
      trace->header[i] = ' ';  /* fill header with spaces */
   trace->header[i] = '\0';
   linePos = 2;
   for( i=0; i < NUM_HDR_LINES; i++ ) {
      trace->header[(MAX_HDR_LINE*(i+1))-2] = '\r';
      trace->header[(MAX_HDR_LINE*(i+1))-1] = '\n';
   }

// if( trace->timestampOn ) {
//    for( i=0; i<lstrlen(TIMESTAMP_TEXT); i++ )
//       trace->header[MAX_HDR_LINE+i] = TIMESTAMP_TEXT[i];
//    linePos += (TIMESTAMP_LEN + 1);
// }
   
   if (optionFlag & TIMESTAMP_OPT) {
      for( i=0; i<lstrlen(TIMESTAMP_TEXT); i++ ) 
         trace->header[MAX_HDR_LINE+linePos+i] = TIMESTAMP_TEXT[i];
      linePos += TIMESTAMP_LEN+1;
   }

   if ((err=FormulateHeaderFields(trace,cfgFields[0],cfgFields[1],&linePos)) != GOOD)
      return(err);

   if (optionFlag & STATUS_OPT) {
      if ((err=FormulateHeaderFields(trace,cfgFields[2],cfgFields[3],&linePos)) != GOOD)
         return(err);
   }

   if (optionFlag & TRACE_OPT) {
      if ((err=FormulateHeaderFields(trace,cfgFields[4],cfgFields[5],&linePos)) != GOOD)
         return(err);
   }

   if (optionFlag & TPORT_OPT) {
      if ((err=FormulateHeaderFields(trace,cfgFields[6],cfgFields[7],&linePos)) != GOOD)
         return(err);
   }

   if((optionFlag & LEVEL_OPT)!=0) {
      for( i=0; i<lstrlen(LEVEL_TEXT); i++ )
         trace->header[MAX_HDR_LINE+linePos+i] = LEVEL_TEXT[i];
      linePos += LEVEL_LEN;
   }
   if((optionFlag & EVENT_OPT)!=0) {
      for( i=0; i<lstrlen(EVENT_TEXT); i++ )
         trace->header[MAX_HDR_LINE+linePos+i] = EVENT_TEXT[i];
      for( i=0; i<lstrlen(EVENT_2TEXT); i++ )
         trace->header[MAX_HDR_LINE*2+linePos+i] = EVENT_2TEXT[i];
      linePos += EVENT_LEN;
   }

   if (optionFlag & ACTION_OPT) {
      j=linePos;
      for( i=0; i<lstrlen(TRC_TEXT); i++ )
         trace->header[MAX_HDR_LINE+linePos+i] = TRC_TEXT[i];
      for( i=0; i<lstrlen(TRC_2TEXT); i++ )
         trace->header[MAX_HDR_LINE*2+linePos+i] = TRC_2TEXT[i];
      linePos += lstrlen(TRC_TEXT);
      TrcCounterFunctionGet(&tcMode);
      switch(tcMode) {
         case COUNT_COUNT:
            for( i=0; i<lstrlen(TC0TC1_TEXT); i++ )
               trace->header[MAX_HDR_LINE+linePos+i] = TC0TC1_TEXT[i];
            for( i=0; i<lstrlen(TC0TC1_2TEXT); i++ )
               trace->header[MAX_HDR_LINE*2+linePos+i] = TC0TC1_2TEXT[i];
            break;
         case COUNT_TIMER:
            for( i=0; i<lstrlen(TM0TC1_TEXT); i++ )
               trace->header[MAX_HDR_LINE+linePos+i] = TM0TC1_TEXT[i];
            for( i=0; i<lstrlen(TM0TC1_2TEXT); i++ )
               trace->header[MAX_HDR_LINE*2+linePos+i] = TM0TC1_2TEXT[i];
            break;
         case TIMER_COUNT:
            for( i=0; i<lstrlen(TC0TM1_TEXT); i++ )
               trace->header[MAX_HDR_LINE+linePos+i] = TC0TM1_TEXT[i];
            for( i=0; i<lstrlen(TC0TM1_2TEXT); i++ )
               trace->header[MAX_HDR_LINE*2+linePos+i] = TC0TM1_2TEXT[i];
            break;
         case TIMER_TIMER:
            for( i=0; i<lstrlen(TM0TM1_TEXT); i++ )
               trace->header[MAX_HDR_LINE+linePos+i] = TM0TM1_TEXT[i];
            for( i=0; i<lstrlen(TM0TM1_2TEXT); i++ )
               trace->header[MAX_HDR_LINE*2+linePos+i] = TM0TM1_2TEXT[i];
            break;
      }
   }

   return(GOOD);
}

/**************************************************************************
**
** InitializeTraceState
**
** Description:
**    Using the template server given formulates the header string
**    for displaying bus and clock cycles.
**
** Parameters:
**    input:
**       template:      template server id
**       header:        pointer to header storage
**    output:
**       header:        storage contains header text
**
***************************************************************************/
VOID InitializeTraceState(DESCRIPTOR id, TRACE_CYCLES tMode, 
                          FRAME_DISPLAY_MODE fMode) {
   TRACE_DESC_BLOCK FAR *trace;
   trace = (TRACE_DESC_BLOCK FAR *)id;
   trace->debugEmon = FALSE;
   trace->cycleMode = tMode;
   trace->frameMode = fMode;

   trace->searchEvent[0] = '\0'; /* if we end up calculating the emon ON
                                    info this needs to be initialized first */
   TrcUpdateTrace(id);   /* incase trace was collected already */

   trace->searchBuffer = trace->traceBuffer;
   trace->searchStartFrame = trace->startFrame;
// vincent   trace->timestampOn = TRUE;
   trace->timestampOn = ((optionFlag & TIMESTAMP_OPT)==0) ? 0 : 1;
   trace->tsMode = RELATIVETOFRAME;
   trace->zeroedFrame = 0;
}

RETCODE GetHardwareState(VOID) {
   BOOLEAN value = TRUE, timedOut;
   RETCODE err;
   if((err=SdnWriteCmdReadResponse(SDN_TRACE_GET_STATUS,&value,GOOD,
                         SDN_TRACE_GET_STATUS,10,&timedOut))!= GOOD )
      return(err);                            
   traceInfoDirty=TRUE;  /* Force recalculation next time buffer info needed */
   return(GOOD);
}

VOID FAR PASCAL TracingStateChange(DESCRIPTOR desc)  {
   static BOOLEAN oldTracingValue=0;
   BOOLEAN tracing;
   RETCODE err;
   err = SdReadMemberNoInputCheck(desc, (U8 FAR*)&tracing);
   if( err ) { ErrDisplayError(err, CHECK_MODE); return; }
   if( oldTracingValue != tracing ) {
      U32 eventType=EVENT_TRACE_TRACING_ON;
      oldTracingValue = tracing;
      if( tracing == FALSE ) {
      /* Must have just stopped tracing - so now we need to update
         the tracing status information.
       */
         trcMark = trcMarkFrameOn = 0;
         trcMark2FrameOn = trcMarkFrameOff = 0;
         eventType = EVENT_TRACE_TRACING_OFF;
         if((err=GetHardwareState())!=GOOD) {
            ErrDisplayError(err, CHECK_MODE);
            return;
         }
      }
      /* will only pass notification on if tracing is STOPPING! */
      if((err=EnlEventNotify(eventType))!=GOOD)
         ErrDisplayError(err, CHECK_MODE);
   }
}

U16 CalculateTraceBufferFromSubBuffer(U16 subBuffer) {
   U16 traceBuffer;
   BOOLEAN tracing;
   RETCODE err;
   traceBuffer = subBuffer / NumSubBufsPerTraceBuffer();
   if((err=TrcTracingGet(&tracing))!= GOOD ) return(err);
   if( !tracing ) {  /* if we have stopped tracing current subbuffer points */
             /* to next trace buffer - so decrement trace buffer to get last 
                collected trace buffer. */
      if( !traceBuffer ) {
         traceBuffer = NumTraceBuffers() - 1; 
      }
      else traceBuffer--;
   }
   /* else if we are tracing then just return currently active trace buffer */
   return(traceBuffer);
}

VOID FAR PASCAL SubBufferUpdate(DESCRIPTOR desc)  {
   RETCODE err;
   static U16 oldBuffer=0;
   U16 curSub, curBuf;
   if((err=SdReadMember(desc, (U8 FAR*)&curSub))!=GOOD) {
      ErrDisplayError(err, CHECK_MODE);
      return;
   }
   curBuf = CalculateTraceBufferFromSubBuffer(curSub);
   if( curBuf != oldBuffer ) {
      oldBuffer = curBuf;
      if( (err=EnlEventNotify(EVENT_TRACE_NEW_SUB_BUFFER)) != GOOD )
         ErrDisplayError(err, CHECK_MODE);
   }
}

#pragma argsused
VOID FAR PASCAL TraceClearCallback(U32 event) {
   RETCODE err;
   if((err=GetHardwareState())!=GOOD)
      ErrDisplayError(err, CHECK_MODE);
}


RETCODE SetupBufferCheck(U16 buffer, BOOLEAN emon) {
   BOOLEAN curEmon, timedOut;
   RETCODE err;
   U16 curBuffer;
   /* if emon ptr is NIL then use emon that's there. */
   if((err=SdnReadMember(SDN_BUFFER_CHECK,(U8 FAR *)&curBuffer))!=GOOD)
      return(err);
// vincent   if((err=SdnReadMember(SDN_BUFFER_CHECK_EMON,(U8 FAR *)&curEmon))!=GOOD) 
// vincent      return(err);
// vincent   if( emon != curEmon ) {
// vincent      if((err=SdnWriteMember(SDN_BUFFER_CHECK_EMON,(U8 FAR *)&emon,GOOD))
// vincent         !=GOOD) return(err);
// vincent      traceInfoDirty=TRUE;   /* Force recalculation */
// vincent   }
   if(traceInfoDirty || ( curBuffer != buffer )) {
      if((err=SdnWriteCmdReadResponse(SDN_BUFFER_CHECK, &buffer, 
         GOOD, SDN_BUFFER_YOUNGEST, 0, &timedOut)) != GOOD ) 
         return(err);
      traceInfoDirty=FALSE;
   }
   return(GOOD);
}

float timeScalar[6]={1., 1000., 1000., 1000., 60., 60};
LPSTR timeUnit[6]={"ns", "us",  "ms",  "s ", "m ", "h "};
RETCODE EXPORT TrcGetTimestampText(DESCRIPTOR id, U32 curTStamp, U8 hcurTStamp,
                                   S32 prevFrame, LPSTR dataPtr) {
/*  period = 1 / frequency
*  Each frame is a clock : thus frameNumber * period is timestamp value
*  when timestamp is centered around trigger (i.e.: trigger's frame number
*  is zero).
*
*  Units need to change depending on what looks best. */
   long double time, spcTime, absTime;
   S8 tmpBuf[40];
   TRACE_DESC_BLOCK FAR *trace;
   U8  bufTime[40],i;

   trace = (TRACE_DESC_BLOCK FAR *)id;
/*   if( !trace->timestampOn ) return(GOOD);    no timestamp field-just get out */
   if (hcurTStamp !=0) {
      time=(long double)hcurTStamp;
      time=time * 65536. * 65536.;
      time= time+(long double)curTStamp;
      spcTime=time;
      /*
      itoa(hcurTStamp, bufTime, 16);
      ultoa(curTStamp, bufTime+1, 16);
      spcTime = time = _atold(bufTime);*/
   } else {
      spcTime = time = curTStamp;
   }

   if( trace->tsMode == RELATIVETOFRAME )
      time -= zeroedFrameTS;
   else
   if ( trace->tsMode == DELTA)
      time -= preFrameTS;
   absTime = time * 50.;
   if( time != 0 && (preFrameTS !=0 || trace->tsMode != DELTA)) {
      for(i=0; i<6; i++) {
         absTime/= timeScalar[i];
/*       ultoa((unsigned long)absTime,bufTime,10); */
         ltoa((long)absTime,bufTime,10);
         if( strlen(bufTime) < TIMESTAMP_LEN-3) {
            sprintf(tmpBuf,"%9s",bufTime);
            sprintf(tmpBuf+strlen(tmpBuf), "%s  ", timeUnit[i]);
            break;
         }
      }
      lstrcat(dataPtr,tmpBuf);
   }
   else lstrcat(dataPtr,"-----------  ");
   preFrameTS = spcTime;
   return(GOOD);
}

RETCODE EXPORT TrcOptionFlagGet(DESCRIPTOR id, U16 mode, BOOLEAN FAR *flag) {
   S8 tflag;
   tflag=1;
   *flag= ((optionFlag & (tflag << mode))== 0 ) ? 0 : 1;
   return(GOOD);
}

/*****************************************************************************
**
**    TrcOptionFlagSet
** Note: toggle flag
*****************************************************************************/
RETCODE EXPORT TrcOptionFlagSet(DESCRIPTOR id, U16 mode) {
   S8 flag,getFlag;
   flag=1;
   flag <<= mode;
   getFlag= ((optionFlag & flag)== 0 ) ? 0 : 1;
   if (getFlag==0)
      optionFlag |= flag;
   else {
      flag = ~flag;
      optionFlag &= flag;
   }
   if ((optionFlag & TIMESTAMP_OPT)==0)
      TrcTimestampSet(id, FALSE);
   else
      TrcTimestampSet(id, TRUE);
//   SetOptionFlag2Profle();
   return(GOOD);
}

/*****************************************************************************
**
**    TrcPreFrameTSSet
*****************************************************************************/
RETCODE EXPORT TrcPreFrameTSSet() {
   preFrameTS=0.;
   return(GOOD);
}   
#define INI_NAME "micepack.ini"
#define SEC_NAME "TraceInfo"
/*****************************************************************************
**
**    initOptionFlag
**
*****************************************************************************/
RETCODE initOptionFlag() {
   S8 str[32];

   optionFlag = 0;

//   if(!GetProfileString("PowerViews","pwrviewdir","",profile,
//     sizeof(profile))) lstrcpy(profile,INI_NAME);

   GetPrivateProfileString(SEC_NAME,"timestamp","",(LPSTR)str,
          sizeof(str), INI_NAME);
   if(strncmpi(str, "on", strlen(str))==0)
      optionFlag |= TIMESTAMP_OPT;

   GetPrivateProfileString(SEC_NAME,"showStatus","",(LPSTR)str,
          sizeof(str), INI_NAME);
   if(strncmpi(str, "on", strlen(str))==0)
      optionFlag |= STATUS_OPT;

   GetPrivateProfileString(SEC_NAME,"showTraceBit","",(LPSTR)str,
          sizeof(str), INI_NAME);
   if(strncmpi(str, "on", strlen(str))==0)
      optionFlag |= TRACE_OPT;

   GetPrivateProfileString(SEC_NAME,"showAction","",(LPSTR)str,
          sizeof(str), INI_NAME);
   if(strncmpi(str, "on", strlen(str))==0)
      optionFlag |= ACTION_OPT;

   GetPrivateProfileString(SEC_NAME,"showSequenceLevel","",(LPSTR)str,
          sizeof(str), INI_NAME);
   if(strncmpi(str, "on", strlen(str))==0)
      optionFlag |= LEVEL_OPT;

   GetPrivateProfileString(SEC_NAME,"showBusEvent","",(LPSTR)str,
          sizeof(str), INI_NAME);
   if(strncmpi(str, "on", strlen(str))==0)
      optionFlag |= EVENT_OPT;

   GetPrivateProfileString(SEC_NAME,"showTracePort","",(LPSTR)str,
          sizeof(str), INI_NAME);
   if(strncmpi(str, "on", strlen(str))==0)
      optionFlag |= TPORT_OPT;

/*   trcMark=0; */
   return(GOOD);
}

/*****************************************************************************
**
**    setOptionFlag2Profile
**
*****************************************************************************/
#define onStr "on"
#define offStr "off"

RETCODE setOptionFlag2Profile() {

   if((optionFlag & TIMESTAMP_OPT)==0)
      WritePrivateProfileString(SEC_NAME,"timestamp",offStr,INI_NAME);
   else
      WritePrivateProfileString(SEC_NAME,"timestamp",onStr,INI_NAME);

   if((optionFlag & STATUS_OPT)==0)
      WritePrivateProfileString(SEC_NAME,"showStatus",offStr,INI_NAME);
   else
      WritePrivateProfileString(SEC_NAME,"showStatus",onStr,INI_NAME);

   if((optionFlag & TRACE_OPT)==0)
      WritePrivateProfileString(SEC_NAME,"showTraceBit",offStr,INI_NAME);
   else
      WritePrivateProfileString(SEC_NAME,"showTraceBit",onStr,INI_NAME);

   if((optionFlag & ACTION_OPT)==0)
      WritePrivateProfileString(SEC_NAME,"showAction",offStr,INI_NAME);
   else
      WritePrivateProfileString(SEC_NAME,"showAction",onStr,INI_NAME);

   if((optionFlag & LEVEL_OPT)==0)
      WritePrivateProfileString(SEC_NAME,"showSequenceLevel",offStr,INI_NAME);
   else
      WritePrivateProfileString(SEC_NAME,"showSequenceLevel",onStr,INI_NAME);

   if((optionFlag & EVENT_OPT)==0)
      WritePrivateProfileString(SEC_NAME,"showBusEvent",offStr,INI_NAME);
   else
      WritePrivateProfileString(SEC_NAME,"showBusEvent",onStr,INI_NAME);

   if((optionFlag & TPORT_OPT)==0)
      WritePrivateProfileString(SEC_NAME,"showTracePort",offStr,INI_NAME);
   else
      WritePrivateProfileString(SEC_NAME,"showTracePort",onStr,INI_NAME);

   return(GOOD);
}

RETCODE PRIVATE FormulateHeaderFields(TRACE_DESC_BLOCK FAR *trace,
                           U8 startField, U8 numFields,U16 *linePos) {
   S8  fieldName[MAX_FIELD_NAME];
   U16 trailing, tempPos;
   BOOLEAN visible;
   U8 displayLen, i;
   RETCODE err;

   while(numFields--) {
      if( (err=TmpltGetNameGivenFieldNumber(trace->templateId, startField++,
               fieldName, MAX_FIELD_NAME)) != GOOD ) return(err);
      if( (err=TmpltGetVisible(trace->templateId, &visible)) != GOOD )
         return(err);
      if(!visible) continue;
      if( (err=TmpltGetDisplayLength(trace->templateId, &displayLen))!=GOOD )
         return(err);
      if( (err=TmpltGetTrailingBlanks(trace->templateId, &trailing)) != GOOD )
         return(err);
      if( lstrlen(fieldName) > displayLen ) {
         S8 title[CHARS_IN_TITLE+1];
         if( (err=TmpltGetTitle(trace->templateId,title))!=GOOD ) return(err);
         
         if( displayLen > 1 )
            tempPos = *linePos + (displayLen/2);    /* center title */
         else
            tempPos = *linePos;
         for( i=0; i < NUM_HDR_LINES; i++ ) 
            trace->header[(i*MAX_HDR_LINE)+tempPos] = title[i];
      } else {
         tempPos = *linePos + (displayLen/2) - (lstrlen(fieldName)/2);
         for( i=0; i<lstrlen(fieldName); i++ ) 
            trace->header[MAX_HDR_LINE+tempPos+i] = fieldName[i];
      }
      *linePos += (displayLen + trailing);
      if( *linePos > MAX_HDR_LINE ) return(ER_TOO_MANY_FIELDS);
   }
   return(GOOD);
}

RETCODE TrcGetActionText(ACTION_MASK *actionMask, LPSTR dataPtr) {
   U8 actionFlag, actionFlagMask;
   LOOP_VAR i, j;
   COUNTER_TYPE tcMode;

   /* actionFlag= bit 7: TRC_START_MASK
                  bit 6: TRC_STOP_MASK
                  bit 5: TMR0_RST_MASK    | TC1_RST_MASK
                  bit 4: TMR0_START_MASK  | CNT1_INC_MASK
                  bit 3: TMR0_STOP_MASK   |
                  bit 2: TMR1_RST_MASK    | TC0_RST_MASK
                  bit 1: TMR1_START_MASK  | CNT0_INC_MASK
                  bit 0: TMR1_STOP_MASK   |                 */
   actionFlag=0;
   for (i=0; i<8; i++) {
       actionFlag |= ((actionMask[i] & TRC_START_MASK)==TRC_START_MASK)          ? 0x80 : 0x00;
       actionFlag |= ((actionMask[i] & TRC_STOP_MASK)==TRC_STOP_MASK)            ? 0x40 : 0x00;
   }
   actionFlagMask=0xc0;
   TrcCounterFunctionGet(&tcMode);
   switch(tcMode) {
      case COUNT_COUNT:
           for (i=0; i<8; i++) {
               actionFlag |= ((actionMask[i] & CNT0_INC_MASK)==CNT0_INC_MASK)     ? 0x20 : 0x00;
               actionFlag |= ((actionMask[i] & TC0_RST_MASK)==TC0_RST_MASK)       ? 0x10 : 0x00;
               actionFlag |= ((actionMask[i] & CNT1_INC_MASK)==CNT1_INC_MASK)     ? 0x04 : 0x00;
               actionFlag |= ((actionMask[i] & TC1_RST_MASK)==TC1_RST_MASK)       ? 0x02 : 0x00;
           }
         actionFlagMask|=0x36;
         break;
      case COUNT_TIMER:
           for (i=0; i<8; i++) {
               actionFlag |= ((actionMask[i] & TMR0_START_MASK)==TMR0_START_MASK) ? 0x20 : 0x00;
               actionFlag |= ((actionMask[i] & TMR0_STOP_MASK)==TMR0_STOP_MASK)   ? 0x10 : 0x00;
               actionFlag |= ((actionMask[i] & TC0_RST_MASK)==TC0_RST_MASK)       ? 0x08 : 0x00;
               actionFlag |= ((actionMask[i] & CNT1_INC_MASK)==CNT1_INC_MASK)     ? 0x04 : 0x00;
               actionFlag |= ((actionMask[i] & TC1_RST_MASK)==TC1_RST_MASK)       ? 0x02 : 0x00;
           }
         actionFlagMask|=0x3e;
         break;
      case TIMER_COUNT:
           for (i=0; i<8; i++) {
               actionFlag |= ((actionMask[i] & CNT0_INC_MASK)==CNT0_INC_MASK)     ? 0x20 : 0x00;
               actionFlag |= ((actionMask[i] & TC0_RST_MASK)==TC0_RST_MASK)       ? 0x10 : 0x00;
               actionFlag |= ((actionMask[i] & TMR1_START_MASK)==TMR1_START_MASK) ? 0x08 : 0x00;
               actionFlag |= ((actionMask[i] & TMR1_STOP_MASK)==TMR1_STOP_MASK)   ? 0x04 : 0x00;
               actionFlag |= ((actionMask[i] & TC1_RST_MASK)==TC1_RST_MASK)       ? 0x02 : 0x00;
           }
         actionFlagMask|=0x3e;
         break;
      case TIMER_TIMER:
           for (i=0; i<8; i++) {
               actionFlag |= ((actionMask[i] & TMR0_START_MASK)==TMR0_START_MASK) ? 0x20 : 0x00;
               actionFlag |= ((actionMask[i] & TMR0_STOP_MASK)==TMR0_STOP_MASK)   ? 0x10 : 0x00;
               actionFlag |= ((actionMask[i] & TC0_RST_MASK)==TC0_RST_MASK)       ? 0x08 : 0x00;
               actionFlag |= ((actionMask[i] & TMR1_START_MASK)==TMR1_START_MASK) ? 0x04 : 0x00;
               actionFlag |= ((actionMask[i] & TMR1_STOP_MASK)==TMR1_STOP_MASK)   ? 0x02 : 0x00;
               actionFlag |= ((actionMask[i] & TC1_RST_MASK)==TC1_RST_MASK)       ? 0x01 : 0x00;
           }
         actionFlagMask|=0x3f;
         break;
      default:
         break;
   }
   lstrcat(dataPtr,"  ");
   for (i=0x80, j=0; j<8; i>>=1, j++) {
       if ((actionFlagMask & i) !=0 ) {
          if ((actionFlag & i) == 0)
             lstrcat(dataPtr,traceCode[0]);
          else
             lstrcat(dataPtr,traceCode[1]);
          lstrcat(dataPtr,"   ");
       }
   }
 return(GOOD);
}

/******************************** E O F ***********************************/
