/* !!! Windows */
#define _WINDOWS_

#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#ifndef _BASEWIND_
#include "basewind.h"
#endif

#ifndef _HEAP_
#include "heap.h"
#endif

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

#ifndef _PROC_
#include "proc.h"
#endif

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

#ifndef _SDPROBE_
#include "sdprobe.h"
#endif

#ifndef _SDPROC_
#include "sdproc.h"
#endif

#ifndef _SSHARED_
#include "sshared.h"
#endif

#ifndef _SHAREDAT_
#include "sharedat.h"
#endif

#ifndef _WSCOM_
#include "wscom.h"
#endif

#ifndef __TIME_H
#include "time.h"
#endif

#ifndef _VERSIONS_
#include "versions.h"
#endif

#ifndef  _SDS2ABI_
#include "sds2abi.h"
#endif

#define INI_FILENAME "micepack.ini"

RETCODE PRIVATE Sds2AbiStepPreamble(VOID);
RETCODE reset(VOID);
RETCODE step(VOID);
RETCODE abortEmulation(VOID);
U32 SwapDwordOrder(U32 input);
U16 SwapWordOrder(U16 input);
void iceSetAccessSpace(ADDR_SPACE space);
VOID Sds2AbiInputAvailable(VOID);

STATUS   status;

typedef enum {
   BKPT_UNLOADED, BKPT_XBRK, BKPT_SWB, BKPT_STATUS_END=0x7fff
} BKPT_STATUS;

typedef struct BKPT_ENTRY_TAG {
   struct BKPT_ENTRY_TAG *next;
   struct BKPT_ENTRY_TAG *prev;
   U16 id;
   U16 opcode;
   U32 addr;
   ADDR_SPACE space;
   BKPT_STATUS status;
} BKPT_ENTRY;

BAD_MEMORY  badAddr1, badAddr2;
extern   BOOLEAN bkptHitFlag;  /* Set by bkpt handler when emul stops */
extern   U16   emulationState;
U16   MPBreakCause;
extern   U32   probeVersion;
extern   BKPT_ENTRY *bkptHead;
extern   BKPT_ENTRY *bkptTail;
extern   BKPT_ENTRY *bkptFree;
extern   U16 SRSave;           /* Saved value of SR register */
extern   CPU_TYPE cpuType;


BKPT_OP_68K bkptOpcode = A_LINE;
static U16 MP_MAX_XBRKS;   /* Determined by MICEPack hardware */
			   /* note that this value can't exceed MAX_XBRKS */
extern   U16 numXbrks;   /* Number of execution breakpoints currently active */
extern   U32 xbrkAddr[];
extern   BOOLEAN SRModified;   /* Has SR been patched? */
extern   BOOLEAN bkptEnable;   /* Enables bkpt handler to run when emul stops*/

BOOLEAN flagRunaccStart = FALSE; // keep the state of run_access

static BOOLEAN IDGot = FALSE;
static U8 idInfo[MAX_ID];
//
RETCODE Sds2AbiFwInit(VOID)
{
S8 buf[64];
char    *stopString;
U32  addr;

//   switch (cpuType) {}
   MP_MAX_XBRKS = 2;    // MICEPack-306 can handle up to 2 hardware execution breakpoint

   GetPrivateProfileString("MICEPack-68k", "TrapCodeForEmulator", "0xa0", buf,
      sizeof(buf), INI_FILENAME);
   stopString = NULL;
   bkptOpcode = (BKPT_OP_68K)(strtoul(buf, &stopString, 0));
   if ((bkptOpcode != A_LINE) && (bkptOpcode != F_LINE))
      bkptOpcode = A_LINE;

   // set CAN base address
   GetPrivateProfileString("SystemInfo", "CAN_BaseAddr", "0xffffffff", buf,
      sizeof(buf), INI_FILENAME);
   stopString = NULL;
   addr = (U32)(strtoul(buf, &stopString, 0));
   if (*stopString=='\0' && addr!=0xFFFFFFFF)
      iceSetCanBaseAddr(addr);
   
   return(GOOD);
}
////////////////////////////////////////////////////////////////////////////
// Sds2AbiFwGetBreakCause
//
// Description: get the cause break the emulation
//
// Parameters:
//    Input:   <none>
//    Output:  <cause> cause which break the emulation
////////////////////////////////////////////////////////////////////////////
RETCODE EXPORT Sds2AbiFwGetBreakCause(BREAK_CAUSE *cause)
{
   *cause = MPBreakCause;
   return(GOOD);
}

////////////////////////////////////////////////////////////////////////////
// Sds2AbiFwGetEmuState
//
// Description: get current emulation state
//
// Parameters:
//    Input:   <none>
//    Output:  <state> emulation state
////////////////////////////////////////////////////////////////////////////
RETCODE EXPORT Sds2AbiFwGetEmuState(EMULATION_STATE *iceState)
{
RETCODE  err;

   err=SdnReadMember(SDN_EMULATION_STATE,(U8 *)iceState);
   return(err);
}

/*****************************************************************************
**
** Sds2AbiFwReset
**
** description:
**    Reset target processor and enter emulation mode.
**
** parameters:
**    none
*****************************************************************************/
RETCODE EXPORT Sds2AbiFwReset(CPU_RESET typeOfReset) {
   RETCODE err,err2;
   EMULATION_STATE iceState;
   U32 sim;
   BOOLEAN simValid = FALSE;
   PROBE_TYPE  probeType;

   bkptEnable = FALSE;
   SRModified = FALSE;
   err = Sds2AbiFwLoadRegisters();  // ignore the return since reset is request
   err = reset();
   err2 = Sds2AbiFwUnloadRegisters(TRUE);
   if (!err) err = err2;
   err2 = Sds2AbiFwUnloadBreakpoints();
   if (!err) err = err2;
   err2 = SdnReadMember(SDN_EMULATION_STATE,(U8*)&iceState);
   if (!err) err = err2;

   err2 = SdnReadMember(SDN_PROBE_TYPE, (U8*)&probeType);
   if (!err) err = err2;
   switch (probeType)
      {
      case M68306_MP:
	 sim = 0xfffff000ul;
	 simValid = TRUE;
	 err2  = SdnWriteMember(SDN_SIM_VALID,(U8*)&simValid,GOOD);
	 if (!err) err = err2;
	 err2 = SdnWriteMember(SDN_SIM_ADDRESS,(U8*)&sim,GOOD);
	 break;
      case M68328_MP:
      case M68307_MP:
      case M68302_MP:
	 sim = 0xfff000ul;
	 simValid = TRUE;
	 err2 = SdnWriteMember(SDN_SIM_VALID,(U8*)&simValid,GOOD);
	 if (!err) err = err2;
	 err2 = SdnWriteMember(SDN_SIM_ADDRESS,(U8*)&sim,GOOD);
	 break;
      default:
	 break;
      }

   if (!err) err = err2;
   if (iceState!=EM_HALTED) {       /* Update cause if we were emulating */
      BREAK_CAUSE cause = CAUSE_RESET;
      err2 = SdnWriteMember(SDN_BREAK_CAUSE,(U8*)&cause,GOOD);
      if (!err) err = err2;
   }
   if (typeOfReset==RESET_CPU_AND_UPDATE_STATUS) {
      iceState = EM_HALTED;
      err2 = SdnWriteMember(SDN_EMULATION_STATE,(U8*)&iceState,GOOD);
      if (!err) err = err2;
      err2 = SdnWriteMember(SDN_EMULATION_RESULT,(U8*)&err,err);
      if (!err) err = err2;
   }
   return(err);
}

/*****************************************************************************
**
** Sds2AbiFwCpuReset
**
** description:
**    Reset the processor.  Does not update any registers or unload
**    breakpoints; therefore should be used only during initialization.
**
** parameters:
**    none
*****************************************************************************/
RETCODE EXPORT Sds2AbiFwCpuReset(VOID) {
RETCODE  err;

   SRModified = FALSE;
   err = Sds2AbiFwLoadRegisters();
   return(reset());
}

/*****************************************************************************
**
** Sds2AbiFwLoadBreakpoints
**
** description:
**    Replace user opcodes at breakpoint addresses by BGND instructions
**
** parameters:
**    none
*****************************************************************************/
RETCODE  Sds2AbiFwLoadBreakpoints(BOOLEAN loadNow) {
RETCODE err,err2;
BKPT_ENTRY *entry;
U8 bkptOp[2];
BOOLEAN enable;
U32 FCRegs[2];
ADDR  abiAddr;

//   switch (cpuType) {}
   bkptOp[0] = (U8)(bkptOpcode & 0xff);
   bkptOp[1] = 0;
   iceSetBkptCode(bkptOpcode);
//   
   if ((err = SdnReadMember(SDN_BKPT_ENABLE, (U8*)&enable)) != GOOD)
      return(err);
   if (enable || loadNow) {
      numXbrks = 0;
      for (entry=bkptHead; entry; entry=entry->next) {
	 /* First try setting swb.  If memory not writable, use hw bkpt.*/
	 err = Sds2AbiFwReadMem(entry->addr, entry->space, 2, WORD_SIZE,
	       (U8*)&entry->opcode);
           err=Sds2AbiFillMemAction(entry->addr, entry->space,2,2,WORD_SIZE,
                 TRUE, NULL, bkptOp);
           if (!err) {
              entry->status = BKPT_SWB;
           }
	 else {
	    /* Write error, check if hardware execution breakpoint available */
              err=Sds2AbiFillMemAction(entry->addr, entry->space,2,2,WORD_SIZE,
                    TRUE, NULL, (U8*)&entry->opcode);
	    if (numXbrks >= MP_MAX_XBRKS)
	       {
	       err = ER_TOO_MANY_XBRKS;
	       break;
	       }
	    abiAddr.pos = entry->addr;
	    abiAddr.space = entry->space;
	    iceSetBP(numXbrks+10, abiAddr);
	    xbrkAddr[numXbrks++] = entry->addr;
	    entry->status = BKPT_XBRK;
	    err = GOOD;
	    }
      }
      err2 = Sds2AbiFwRestoreFCRegs(FCRegs);
      if (!err) err = err2;
      if (err) Sds2AbiFwUnloadBreakpoints();   /* Clear any bkpts set */
      iceEnableSwBkpt();
   }
   return(err);
}

/*****************************************************************************
**
** Sds2AbiFwUnloadBreakpoints
**
** description:
**    Restore user memory contents at all breakpoint addresses
**
** parameters:
**    none
*****************************************************************************/
RETCODE  Sds2AbiFwUnloadBreakpoints(VOID) {
   RETCODE err=GOOD, err2;
   BKPT_ENTRY *entry;
   RETCODE hwbp = FALSE;
   numXbrks = 0;
   for (entry=bkptTail; entry; entry=entry->prev) {
      if (entry->status == BKPT_SWB) {
	 err2 = Sds2AbiFillMemAction(entry->addr, entry->space,2,2,WORD_SIZE,FALSE,
	    NULL, (U8*)&entry->opcode);
	 if (!err) err = err2;
	 }
      else {
	 hwbp = TRUE;
	 }
      entry->status = BKPT_UNLOADED;
   }
   if (hwbp) {
      iceClearEvent(10);
      iceClearEvent(11);
      }
   iceDisableSwBkpt();
   return(GOOD);
}

/*****************************************************************************
**
** Sds2AbiFwBkptHit
**
** description:
**    Called when the probe stops emulation.  Unloads registers into shared
**    data members, updates SD_BREAK_CAUSE, and sets SD_EMULATION_STATE.
**
** parameters:
**    byte  comm byte received from probe (one of PCOM_BKPTHIT, PCOM_STEPBKPT,
**          or PCOM_STEPFAIL).
*****************************************************************************/
RETCODE  Sds2AbiFwBkptHit()
{
   RETCODE err=GOOD,err2;
   EMULATION_STATE iceState;
   BREAK_CAUSE cause=CAUSE_NONE;

   err = SdnWriteMember(SDN_BREAK_CAUSE,(U8*)&cause,err);
   err2 = Sds2AbiFwUnloadRegisters(FALSE);
   if (!err) err = err2;
   err2 = Sds2AbiFwUnloadBreakpoints();
   if (!err) err = err2;
   iceState=EM_HALTED;
   err2 = SdnWriteMember(SDN_EMULATION_STATE,(U8*)&iceState,GOOD);
   if (!err) err = err2;
   err = SdnWriteMember(SDN_EMULATION_RESULT,(U8*)&err,err);
   return(err);
}

RETCODE  Sds2AbiFwStep(U32 count) {
   RETCODE err, stepErr;
   BOOLEAN  abortFromEsc;
   BREAK_CAUSE cause = CAUSE_STEP;

   bkptEnable=FALSE;

   while (count--) {
      if ((err = Sds2AbiStepPreamble()) != GOOD) return(err);
      bkptHitFlag=FALSE;
      stepErr = step(); 
      if ((err = Sds2AbiStepPostamble()) != GOOD) return(err);
      if ((err = TskCheckAbort(&abortFromEsc)) != GOOD) return(err);
      if (abortFromEsc!=0) break;
   }
   if ((err = SdnWriteMember(SDN_BREAK_CAUSE,(U8*)&cause,GOOD)) != GOOD)
      return(err);
   if (stepErr!=GOOD)
      return(stepErr);
   else
      return(err);
}

RETCODE PRIVATE Sds2AbiStepPreamble(VOID) {
   RETCODE err;
   BOOLEAN stepMask;
   if ((err = SdnReadMember(SDN_STEP_MASK, (U8*)&stepMask)) != GOOD)
      return(err);
   if (stepMask)
      {
      U32 result;
      if ((err = GetReg(R_SR, &result)) != GOOD) return(err);
      result = SwapDwordOrder(result);
      SRSave = (U16)(result & 0xffffL);
      result |= 0x0700;
      if ((err = SetReg(R_SR, result)) != GOOD) return(err);
      SRModified = TRUE;
      }
   return(GOOD);
}

RETCODE EXPORT Sds2AbiStepPostamble(VOID) {
   RETCODE err;
   if (SRModified)
      {
      U32 result;
      if ((err = GetReg(R_SR, &result)) != GOOD) return(err);
      result = ((U16)SwapDwordOrder(result) & 0xf8ff) | (SRSave & 0x0700);
      if ((err = SetReg(R_SR, result)) != GOOD) return(err);
      SRModified=FALSE;
   }
   return(GOOD);
}

RETCODE  Sds2AbiFwGo(EMULATION_STATE *iceState) {
   RETCODE err;
   BOOLEAN bool=TRUE;

   bkptEnable=TRUE;
   *iceState = EM_HALTED;
   if (numXbrks == 0) {
// remove for MTAT2, gene
//      if ((err = SdnWriteMember(SDN_TRIC_DIAGNOSTIC_MODE,&bool,err)) != GOOD) return(err);
      err = iceMapError(iceGo(0));
      if (err != GOOD) return(err);
      *iceState = EM_RUNNING;
   } else {
      if ((err = Sds2AbiStepPreamble()) != GOOD) return(err);
// remove for MTAT2, gene
//      if ((err = SdnWriteMember(SDN_TRIC_DIAGNOSTIC_MODE,&bool,err)) != GOOD) return(err);
// 1/17/96      Sds2AbiFwLoadBreakpoints(TRUE);
      err = iceMapError(iceGo(0));
      if (err != GOOD) return(err);
      *iceState = EM_RUNNING;
   }
   if ((err=SdnWriteMember(SDN_FW_TRACING_STATUS, &bool, err)) != GOOD) return(err);
   if ((err=SdnWriteMember(SDN_TRACING, &bool, err)) != GOOD) return(err);
   return(GOOD);
}

RETCODE EXPORT Sds2AbiFwGr(EMULATION_STATE *iceState) {
   return(Sds2AbiFwGo(iceState));
}

RETCODE  Sds2AbiFwHalt(VOID) {
   return(abortEmulation());
}

RETCODE EXPORT Sds2AbiRunaccStart(EMULATION_STATE *iceState, U32 *regs) {
   RETCODE err;
   STATIC EMULATION_STATE preEmState=EM_HALTED;

   if (flagRunaccStart) {
      *iceState = preEmState;
      return(GOOD);
   }
   err = SdnReadMember(SDN_EMULATION_STATE,(U8*)iceState);
   if ((!err) && (*iceState != EM_HALTED)) {
      flagRunaccStart = TRUE;
      preEmState = *iceState;
      bkptEnable=FALSE;
      err = abortEmulation();
      if (/* (!err) && */(regs!=NULL)) err = Sds2AbiFwSaveFCRegs(regs);
   }
   return(err);
}

RETCODE EXPORT Sds2AbiRunaccFinish(EMULATION_STATE iceState, U32 *regs) {
   RETCODE err=GOOD;

   if (iceState != EM_HALTED) {
      flagRunaccStart = FALSE;
      if (regs!=NULL) err = Sds2AbiFwRestoreFCRegs(regs);
      if ((!err) || (regs == NULL)) {
//       err = Sds2AbiFwGo(&iceState);
//       if (err) return(err);
	 iceGo(0);
	 return (SdnWriteMember(SDN_EMULATION_STATE, (U8 *)&iceState, GOOD));
      }
   }
   return(err);
}

RETCODE reset(VOID)
{
   status = iceReset();
   return(iceMapError(status));
}

RETCODE step(VOID)
{
RETCODE  err, firstErr;
ADDR  startPC;
U32      pc;

   if ((err = SdnReadMember(SDN_PC, (U8*)&pc)) != GOOD) return(err);
   startPC.pos = pc;
   startPC.space = SPACE_DONT_CARE;
   firstErr = iceStepRange(startPC, startPC);
   if (firstErr != ICE_OK) firstErr = iceMapError(firstErr);
   status = GetReg(R_PC, &pc);
   if (status != ICE_OK) status = iceMapError(status);
   err = SdnWriteMember(SDN_PC, (U8*)&pc, GOOD);
   if (firstErr != GOOD)
      err = firstErr;
   else if (status != GOOD)
      err = status;

   return(err);
}

RETCODE abortEmulation(VOID)
{
   status = iceAbort();
   return(iceMapError(status));
}

VOID Sds2AbiInputAvailable(VOID) {
   EMULATION_STATE iceState;
   BREAK_CAUSE cause;
   U8 goStatus;
   BOOLEAN  bool;
   RETCODE  err;
   S16 buttonID;
   STATIC BOOLEAN pending = FALSE;

   status = iceGetCpuStatus(&goStatus);
   if ((goStatus & 0x01) == 0) {
      if (pending) {
	 pending = FALSE;
	 iceState = EM_RUNNING;
	 err = SdnWriteMember(SDN_EMULATION_STATE,(U8*)&iceState,GOOD);
      }
      /* <gene> */
      if (goStatus & 0x02) {
         bool = 0;
         SdnWriteMember(SDN_TRACING,&bool,GOOD);
      }
      /* <gene> */
      return;
   }
   switch (status) {
      case ICE_BKPT1_HALT:
      case ICE_BKPT2_HALT:
      case ICE_USER_CC:
      case ICE_SW_BKPT_HIT:
	 bkptHitFlag = TRUE;
	 if (bkptEnable) Sds2AbiFwBkptHit();
	 bool = FALSE;
	 SdnWriteMember(SDN_FW_TRACING_STATUS, &bool, GOOD);
	 SdnWriteMember(SDN_TRACING, &bool, GOOD);
	 cause = CAUSE_BKPT;
	 SdnWriteMember(SDN_BREAK_CAUSE,(U8*)&cause,GOOD);
	 return;
      case ICE_TRIG_HALT:
	 cause=CAUSE_BUSBRK;
	 break;
      case ICE_HALT_USER:
	 bkptHitFlag = TRUE;
	 cause = CAUSE_HALT;
	 break;
      case ICE_RBW_HALT:      // vincent: powerviews doesn't support this
      case ICE_BROKE:
	 break;
      case ICE_VIOL_HALT:
	 ErrDisplayErrorEx(ER_MEMORY_VERIFY, FORCE_POPUP, MB_TYPE_OK,
		(S16 FAR *)&buttonID);
	 cause = CAUSE_OVERLAY_ACCESS;
	 break;
      case ICE_EP_PENDING :
	 cause = CAUSE_PENDING;
	 if (!pending) {
	    pending = TRUE;
	    iceState = EM_RUNNING;
	    err = SdnWriteMember(SDN_EMULATION_STATE,(U8*)&iceState,GOOD);
	 }
	 SdnWriteMember(SDN_BREAK_CAUSE,(U8*)&cause,GOOD);
	 return;
      default:
	 cause=CAUSE_NONE;
	 break;
      }
   SdnWriteMember(SDN_BREAK_CAUSE,(U8*)&cause,GOOD);
   Sds2AbiFwUnloadRegisters(FALSE);
   if (bkptEnable) Sds2AbiFwUnloadBreakpoints();
   iceState = EM_HALTED;
   err = SdnWriteMember(SDN_EMULATION_STATE,(U8*)&iceState,GOOD);
   SdnWriteMember(SDN_EMULATION_RESULT,(U8*)&err,GOOD);
   bool = FALSE;
   SdnWriteMember(SDN_FW_TRACING_STATUS, &bool, GOOD);
   SdnWriteMember(SDN_TRACING, &bool, GOOD);
}

RETCODE EXPORT GetID(U8 *id) {
   RETCODE status = GOOD;

   if (!IDGot) {
      status = iceGetID(idInfo);
      IDGot = TRUE;
   }
   memcpy(id,idInfo,sizeof(idInfo));
   return(iceMapError(status));
}

/*****************************************************************************
**
** Sds2AbiFwUpdateProbeVersion
**
** description:
**    Send version packet to probe and write results to shared data members
**
** parameters:
**    none
*****************************************************************************/
RETCODE Sds2AbiFwUpdateProbeVersion(VOID) {
   RETCODE err;
   U8 result[7];
   S8 cpu[64];
   PROBE_TYPE probeType = PROBE_NONE;

   if ((err = Sds2AbiFwCpuReset()) != GOOD) return(err);

   /* find out which processor is installed...tests must be in this order */
   if ((err = GetID(result)) != GOOD) return(err);

//vvv   probeVersion = (U32)(result[2] & 0xff);
//vvv   if (probeVersion < MP_PROBE_VERSION_REQUIRED) return(ER_PROBE_FW_VERSION);
//vvv   if ((err = SdatSetBerrRetry(TRUE)) != GOOD) return(err);

   cpuType = result[2];
   if (cpuType == CPU302V) cpuType = CPU302;

   GetPrivateProfileString("SystemInfo", "MICEpack", "68306", cpu,
      sizeof(cpu), INI_FILENAME);
   if ((stricmp(cpu, "68306") == 0 && cpuType == CPU306) ||
       (stricmp(cpu, "68302") == 0 && cpuType == CPU302) ||
       (stricmp(cpu, "68307") == 0 && cpuType == CPU307) ||
       (stricmp(cpu, "68328") == 0 && cpuType == CPU328))
      ; // micepack.ini, cpu, and F/W are consistent
   else if (cpuType==CPU306 || cpuType==CPU307 || cpuType==CPU328 || cpuType==CPU302)
      return(ER_INI); // F/W does not match with CPU
   else
      return(ER_NOT_CPU); // assertion fail

   Sds2AbiFwReset(ONLY_RESET_CPU);  /* Clear possible error from above memory reads */

   switch (cpuType) {
      case CPU306:
	 probeType = M68306_MP;
	 break;
      case CPU307:
	 probeType = M68307_MP;
	 break;
      case CPU328:
	 probeType = M68328_MP;
	 break;
      case CPU302:
           probeType = M68302_MP;
	 break;
      default:
	 break;
   }      
   if((err=SdnWriteMember(SDN_PROBE_TYPE,(U8*)&probeType,GOOD)) != GOOD)
      return(err);

   // a section of version update code might need to be added here

   return(GOOD);
}

VOID EXPORT Sds2AbiGetCpuType(CPU_TYPE *cpu)
{
   *cpu = cpuType;
}

RETCODE EXPORT SdsCliSync(LPSTR cmdString, U32 argc, U32 argv[])
{
U16   sync, mask;
S8    buf[64];
RETCODE  err;

   switch (argc)
      {
      case 1:
	 err = iceMapError(iceGetSync(&sync));
	 if (err != GOOD) return(err);
	 wsprintf(buf, "Sync start in %s", (sync & 0x01) ? "on" : "off");
	 if ((err = SendMessageToCli(buf)) != GOOD) return(err);
	 wsprintf(buf, "Sync slave out %s", (sync & 0x02) ? "on" : "off");
	 if ((err = SendMessageToCli(buf)) != GOOD) return(err);
	 break;
      case 2:
	 if (stricmp(&cmdString[(int)argv[1]], "input") == 0)
	    {
	    err = iceMapError(iceGetSync(&sync));
	    if (err != GOOD) return(err);
	    wsprintf(buf, "Sync start in %s", (sync & 0x01) ? "on" : "off");
	    if ((err = SendMessageToCli(buf)) != GOOD) return(err);
	    }
	 else if (stricmp(&cmdString[(int)argv[1]], "output") == 0)
	    {
	    err = iceMapError(iceGetSync(&sync));
	    if (err != GOOD) return(err);
	    wsprintf(buf, "Sync slave out %s", (sync & 0x02) ? "on" : "off");
	    if ((err = SendMessageToCli(buf)) != GOOD) return(err);
	    }
	 else return(ER_CLI_SYNTAX);
	 break;
      case 3:
	 if ((status = iceGetSync(&sync)) != ICE_OK) return(iceMapError(status));
	 if (!stricmp(&cmdString[(int)argv[1]], "input")) mask = 0x01;
	 else if (!stricmp(&cmdString[(int)argv[1]], "output")) mask = 0x02;
	       else return(ER_CLI_SYNTAX);
	 if (!stricmp(&cmdString[(int)argv[2]], "on")) sync |= mask;
	 else if (!stricmp(&cmdString[(int)argv[2]], "off")) sync &= (~mask);
	       else return(ER_CLI_SYNTAX);
	 if ((status = iceSetSync(sync)) != ICE_OK) return(iceMapError(status));
	 wsprintf(buf, "Sync start in %s", (sync & 0x01) ? "on" : "off");
	 if ((err = SendMessageToCli(buf)) != GOOD) return(err);
	 wsprintf(buf, "Sync slave out %s", (sync & 0x02) ? "on" : "off");
	 if ((err = SendMessageToCli(buf)) != GOOD) return(err);
	 break;
      default:
	 return (ER_CLI_SYNTAX);
      }
   return(GOOD);
}


