USBDM_ErrorCode usbdmInit(TargetType_t targetType = T_CFV1) {
   unsigned int deviceCount;
   unsigned int deviceNum;
   USBDM_ErrorCode rc = USBDM_Init();
   if (rc != BDM_RC_OK) {
      return rc;
   }
   rc = USBDM_FindDevices(&deviceCount);
   print( "usbdmInit(): Usb initialised, found %d device(s)\n", deviceCount);
   print("After USBDM_FindDevices, Time = %f\n", progressTimer->elapsedTime());
   if (rc != BDM_RC_OK) {
      return rc;
   }
   deviceNum  = 0;
   rc = USBDM_Open(deviceNum);
   if (rc != BDM_RC_OK) {
      print( "usbdmInit(): Failed to open %s, device #%d\n", getTargetTypeName(targetType), deviceNum);
      return rc;
   }
   print( "usbdmInit(): Opened %s, device #%d\n", getTargetTypeName(targetType), deviceNum);
   print("After USBDM_Open, Time = %f\n", progressTimer->elapsedTime());
   // Set up sensible default since we can't change this (at the moment)
   USBDM_ExtendedOptions_t bdmOptions = {sizeof(USBDM_ExtendedOptions_t), TARGET_TYPE};
   USBDM_GetDefaultExtendedOptions(&bdmOptions);
   bdmOptions.targetVdd                  = BDM_TARGET_VDD_3V3; // BDM_TARGET_VDD_NONE;
   bdmOptions.autoReconnect              = AUTOCONNECT_ALWAYS; // Aggressively auto-connect
   bdmOptions.guessSpeed                 = FALSE;
   bdmOptions.cycleVddOnConnect          = FALSE;
   bdmOptions.cycleVddOnReset            = FALSE;
   bdmOptions.leaveTargetPowered         = FALSE;
   bdmOptions.bdmClockSource             = CS_DEFAULT;
   bdmOptions.useResetSignal             = FALSE;
   bdmOptions.usePSTSignals              = FALSE;
   bdmOptions.interfaceFrequency         = 1000; // 1MHz
   bdmOptions.powerOnRecoveryInterval    = 100;
   bdmOptions.resetDuration              = 100;
   bdmOptions.resetReleaseInterval       = 100;
   bdmOptions.resetRecoveryInterval      = 100;
   rc = USBDM_SetExtendedOptions(&bdmOptions);
   if (rc != BDM_RC_OK) {
      print( "usbdmInit(): USBDM_SetExtendedOptions() failed\n");
      return rc;
   }
   print("After USBDM_SetExtendedOptions, Time = %f\n", progressTimer->elapsedTime());
   rc = USBDM_SetTargetType(targetType);
   if (rc != BDM_RC_OK) {
      print( "usbdmInit(): USBDM_SetTargetType() failed\n");
      return rc;
   }
   print("After USBDM_SetTargetType, Time = %f\n", progressTimer->elapsedTime());
#if TARGET ==ARM
   if (targetType == ARM) {
      rc = ARM_Initialise();
      if (rc != BDM_RC_OK) {
         print( "ARM_Initialise(): USBDM_SetTargetType() failed\n");
         return rc;
      }
   }
#endif
   USBDM_TargetReset((TargetMode_t)(RESET_DEFAULT|RESET_SPECIAL));
   print("After USBDM_TargetReset, Time = %f\n", progressTimer->elapsedTime());
   if (targetConnect() != BDM_RC_OK) {
      print( "usbdmInit(): Connecting failed - retry\n");
      USBDM_TargetReset((TargetMode_t)(RESET_DEFAULT|RESET_SPECIAL));
      rc = targetConnect();
      if (rc != BDM_RC_OK) {
         print( "targetConnect(): USBDM_SetTargetType() failed\n");
         return rc;
      }
   }
   print("After targetConnect, Time = %f\n", progressTimer->elapsedTime());
   return BDM_RC_OK;
}
//!  2.2.8.6 Get DI Execution/Exit Status
//!
//! @param pdesExitStatus
//!
//! @return \n
//!     DI_OK              => OK \n
//!     DI_ERR_FATAL       => Error see \ref currentErrorString
//!
USBDM_GDI_API
DiReturnT DiExecGetStatus ( pDiExitStatusT pdesExitStatus ) {
   LOGGING;
   USBDM_ErrorCode BDMrc;
   static DiExitCauseT lastStatus = DI_WAIT_USER;

//   Logging::print("DiExecGetStatus()\n");

   // Defaults
   pdesExitStatus->dscCause = DI_WAIT_UNKNOWN;
   pdesExitStatus->dwBpId   = 0x1000400; // bkpt ID?
   pdesExitStatus->szReason = (DiStringT)"unknown state";

// Removed as prevents CW retry strategy
//   CHECK_ERROR_STATE();

   if (bdmOptions.autoReconnect) {
      USBDM_ErrorCode bdmRc = targetConnect(softConnectOptions);

      if (bdmRc != BDM_RC_OK) {
         Logging::print("DiExecGetStatus()=> connect failed\n");
         return setErrorState(DI_ERR_COMMUNICATION, bdmRc);
      }
   }
   else {
      USBDM_GetBDMStatus(&USBDMStatus);
   }
//   pdesExitStatus->szReason = (DiStringT)getBDMStatusName(&USBDMStatus);

   if (USBDMStatus.reset_recent == RESET_DETECTED) {
      Logging::print("DiExecGetStatus()=>Target has been reset\n");
      mtwksDisplayLine("Target RESET detected\n");
   }
   if (bdmOptions.usePSTSignals) {
      // Check processor state using PST signals
      if (USBDMStatus.halt_state) {
         // Processor halted
         pdesExitStatus->dscCause = DI_WAIT_UNKNOWN;
         pdesExitStatus->szReason = (DiStringT)"Debug Halted";
         if (lastStatus != pdesExitStatus->dscCause) {
            Logging::print("DiExecGetStatus(PST) status change => DI_WAIT_UNKNOWN, (%s)\n",
                  pdesExitStatus->szReason);
            }
      }
      else {
         // Processor executing
         pdesExitStatus->dscCause = DI_WAIT_RUNNING;
         pdesExitStatus->szReason = (DiStringT)"Running";
         if (lastStatus != pdesExitStatus->dscCause) {
            Logging::print("DiExecGetStatus(PST) status change => DI_WAIT_RUNNING, (%s)\n",
                  pdesExitStatus->szReason);
            }
      }
   }
   else {
      // Probe D0 register - if fail assume processor running!
      // BUG - If stopped D0 can still be read so CW thinks the target is halted
      //       but is still running.
      unsigned long int dummy;
      BDMrc = USBDM_ReadReg(CFVx_RegD0, &dummy);
      if (BDMrc == BDM_RC_OK) {
         // Processor halted
         pdesExitStatus->dscCause = DI_WAIT_UNKNOWN;
         pdesExitStatus->szReason = (DiStringT)"Debug Halted";
         if (lastStatus != pdesExitStatus->dscCause) {
            Logging::print("DiExecGetStatus() status change => DI_WAIT_UNKNOWN, (%s)\n",
                  pdesExitStatus->szReason);
         }
      }
      else {
         // Processor executing
         pdesExitStatus->dscCause = DI_WAIT_RUNNING;
         pdesExitStatus->szReason = (DiStringT)"Running";
         if (lastStatus != pdesExitStatus->dscCause) {
            Logging::print("DiExecGetStatus() status change => DI_WAIT_RUNNING, (%s)\n",
                  pdesExitStatus->szReason);
         }
      }
   }
   lastStatus = pdesExitStatus->dscCause;
   return setErrorState(DI_OK);
}
//!  2.2.8.6 Get DI Execution/Exit Status
//!
//! @param pdesExitStatus
//!
//! @return \n
//!     DI_OK              => OK \n
//!     DI_ERR_FATAL       => Error see \ref currentErrorString
//!
USBDM_GDI_API
DiReturnT DiExecGetStatus ( pDiExitStatusT pdesExitStatus ) {
   LOGGING;
   USBDM_ErrorCode BDMrc;
   static DiExitCauseT lastStatus = DI_WAIT_USER;

   // Defaults
   pdesExitStatus->dscCause = DI_WAIT_UNKNOWN;
   pdesExitStatus->dwBpId   = 0; // bkpt ID?
   pdesExitStatus->szReason = (DiStringT)"unknown state";
   if (bdmOptions.autoReconnect) {
      USBDM_ErrorCode bdmRc = targetConnect(softConnectOptions);
      if (bdmRc != BDM_RC_OK) {
         Logging::print("=> DI_ERR_COMMUNICATION\n");
         return setErrorState(DI_ERR_COMMUNICATION, bdmRc);
      }
   }
   Logging::print("Calling USBDM_GetBDMStatus()\n");
   USBDM_GetBDMStatus(&USBDMStatus);
//   pdesExitStatus->szReason = (DiStringT)getBDMStatusName(&USBDMStatus);
   if (USBDMStatus.connection_state == SPEED_NO_INFO) {
      Logging::print("=> NO_INFO\n");
      return setErrorState(DI_OK);
//      Logging::print("DiExecGetStatus()=>DI_ERR_COMMUNICATION\n");
//      return setErrorState(DI_ERR_NONFATAL, "Connection with target lost");
   }
   if (USBDMStatus.reset_recent == RESET_DETECTED) {
      Logging::print("=> Target has been reset\n");
      mtwksDisplayLine("Target RESET detected\n");
   }
   unsigned long status;
   BDMrc = USBDM_ReadStatusReg(&status);
   if (BDMrc != BDM_RC_OK) {
      Logging::print("=> Status read failed\n");
      return setErrorState(DI_OK);
//      return setErrorState(DI_ERR_NONFATAL, BDMrc);
   }
   if ((status&CFV1_XCSR_ENBDM) == 0) {
      Logging::print("=> ENBDM=0\n");
      return setErrorState(DI_OK);
//      Logging::print("DiExecGetStatus()=>DI_ERR_NONFATAL\n");
//      return setErrorState(DI_ERR_NONFATAL, "Connection with target lost");
   }
   if ((status&CFV1_XCSR_STOP) != 0) {
      // Stopped - low power sleep, treated as running
//      pdesExitStatus->dscCause = DI_WAIT_EXTERNAL|DI_WAIT_MISCELLANEOUS;
      pdesExitStatus->dscCause = DI_WAIT_RUNNING;
      pdesExitStatus->szReason = (DiStringT)"Target Stopped (Low power)...";
      if (lastStatus != pdesExitStatus->dscCause) {
//         Logging::print("DiExecGetStatus() status change => DI_WAIT_EXTERNAL|DI_WAIT_MISCELLANEOUS, (%s)\n",
         Logging::print("DiExecGetStatus() status change => DI_WAIT_RUNNING, (%s)\n",
               pdesExitStatus->szReason);
      }
   }
   else if ((status&CFV1_XCSR_HALT) != 0) {
      // Halted - in debug halted mode
      pdesExitStatus->dscCause = DI_WAIT_MISCELLANEOUS;
      pdesExitStatus->szReason = (DiStringT)"Debug Halted";
      if (lastStatus != pdesExitStatus->dscCause) {
         Logging::print("Status change => DI_WAIT_MISCELLANEOUS, (%s)\n",
               pdesExitStatus->szReason);
#if (TARGET==CFV1) && defined(CONVERT_RESETS_TO_EXCEPTIONS)
         // Read-write PC on halt
         // This causes Illegal Operand and Address Errors to be converted from
         // Resets to Exceptions.
         // Without this code the debugger is a bit misleading as it halts at the
         // start of the exception handler but then does the reset on resume!
         unsigned long PCValue;
         USBDM_ReadCReg(CFV1_CRegPC, &PCValue);
         USBDM_WriteCReg(CFV1_CRegPC, PCValue);
#endif
      }
   }
   else {
      // Processor executing
      pdesExitStatus->dscCause = DI_WAIT_RUNNING;
      pdesExitStatus->szReason = (DiStringT)"RunningX";
      if (lastStatus != pdesExitStatus->dscCause) {
         Logging::print("Status change => DI_WAIT_RUNNING, (%s)\n",
               pdesExitStatus->szReason);
      }
   }
   lastStatus = pdesExitStatus->dscCause;
   return setErrorState(DI_OK);
}