/// <summary> /// Starts streaming /// </summary> /// <param name="theSummit">the summit system</param> /// <param name="senseConfig">The sense Model from the config file</param> /// <param name="showErrorMessage">True if you want a popup message on errors or false if show no error popup</param> /// <returns>True if success and false if unsuccessful</returns> public bool StartStreaming(SummitSystem theSummit, SenseModel senseConfig, bool showErrorMessage) { APIReturnInfo bufferReturnInfo; try { _log.Info("Start Streaming"); // Start streaming bufferReturnInfo = theSummit.WriteSensingEnableStreams( senseConfig.StreamEnables.TimeDomain, senseConfig.StreamEnables.FFT, senseConfig.StreamEnables.Power, senseConfig.StreamEnables.AdaptiveTherapy, senseConfig.StreamEnables.AdaptiveState, senseConfig.StreamEnables.Accelerometry, senseConfig.StreamEnables.TimeStamp, senseConfig.StreamEnables.EventMarker); if (!CheckForReturnError(bufferReturnInfo, "Stream Enables", showErrorMessage)) { return(false); } } catch (Exception error) { _log.Error(error); return(false); } return(true); }
/// <summary> /// Updates the fft chart with the new sense config files /// </summary> public void UpdateFFTSettings(SenseModel localSenseLeftModelConfig, SenseModel localSenseRightModelConfig) { if (localSenseLeftModelConfig != null && localSenseLeftModelConfig.Sense != null && localSenseLeftModelConfig.Sense.FFT != null) { senseLeftModelConfig = localSenseLeftModelConfig; UpdateLeftUnilateralFFTChannelRadioButtons(); CalculatePowerBins calculatePowerBins = new CalculatePowerBins(_log); fftBinsLeft = calculatePowerBins.CalculateFFTBins(ConfigConversions.FftSizesConvert(localSenseLeftModelConfig.Sense.FFT.FftSize), ConfigConversions.TDSampleRateConvert(localSenseLeftModelConfig.Sense.TDSampleRate)); if (localSenseLeftModelConfig.Sense.FFT.StreamSizeBins != 0) { CalculateNewFFTBinsLeft(); } } if (localSenseRightModelConfig != null && localSenseRightModelConfig.Sense != null && localSenseRightModelConfig.Sense.FFT != null) { senseRightModelConfig = localSenseRightModelConfig; UpdateRightFFTChannelRadioButtons(); CalculatePowerBins calculatePowerBins = new CalculatePowerBins(_log); fftBinsRight = calculatePowerBins.CalculateFFTBins(ConfigConversions.FftSizesConvert(localSenseRightModelConfig.Sense.FFT.FftSize), ConfigConversions.TDSampleRateConvert(localSenseRightModelConfig.Sense.TDSampleRate)); if (localSenseRightModelConfig.Sense.FFT.StreamSizeBins != 0) { CalculateNewFFTBinsRight(); } } }
/// <summary> /// Gets the power band bins and actual hz values. Program shuts down if can't compute /// </summary> /// <param name="localModel">SenseModel</param> /// <returns>List of PowerBandModel class</returns> public List <PowerBandModel> GetPowerBands(SenseModel localModel) { List <PowerBandModel> powerBandsList = new List <PowerBandModel>(); try { bins.Clear(); bins = CalculateFFTBins(localModel.Sense.FFT.FftSize, localModel.Sense.TDSampleRate); binWidth = bins[1] - bins[0]; CalculateUpperBins(); CalculateLowerBins(); } catch (Exception e) { HandleException(e); } for (int i = 0; i < 8;) { try { PowerBandModel powerBandModel = new PowerBandModel(); //Gets the lower index value and upper index value based from the config file value. powerBandModel.lowerIndexBand0 = GetLowerIndex(localModel.Sense.PowerBands[i].ChannelPowerBand[0]); powerBandModel.upperIndexBand0 = GetUpperIndex(localModel.Sense.PowerBands[i].ChannelPowerBand[1]); //This checks to make sure that the upper power bin index is bigger than the lower; cannot have upper index that is less than lower index //if the upper index value is not bigger than the lower, then the upper index is set to lower index for error handling powerBandModel.upperIndexBand0 = CheckThatUpperPowerBandGreaterThanLowerPowerBand(powerBandModel.lowerIndexBand0, powerBandModel.upperIndexBand0); //Actual lower and upper power values are calculated from the users estimated power values from the config file //This is done in the CalculatePowerBins class. Below saves the actual lower and upper power values in each array to 2 decimal places. //These arrays are instantiated in MainViewModel.cs powerBandModel.lowerActualValueHzBand0 = Math.Round(ActualLowerPowerValue, 2); lowerPowerBinActualValues[i] = powerBandModel.lowerActualValueHzBand0; powerBandModel.UpperActualValueHzBand0 = Math.Round(ActualUpperPowerValue, 2); upperPowerBinActualValues[i] = powerBandModel.UpperActualValueHzBand0; //increment i so that the next power band can be set. There are 8 (0-7). There are 4 power channels (0-3); i++; //Repeat this step for next power band powerBandModel.lowerIndexBand1 = GetLowerIndex(localModel.Sense.PowerBands[i].ChannelPowerBand[0]); powerBandModel.upperIndexBand1 = GetUpperIndex(localModel.Sense.PowerBands[i].ChannelPowerBand[1]); powerBandModel.upperIndexBand1 = CheckThatUpperPowerBandGreaterThanLowerPowerBand(powerBandModel.lowerIndexBand1, powerBandModel.upperIndexBand1); powerBandModel.lowerActualValueHzBand1 = Math.Round(ActualLowerPowerValue, 2); lowerPowerBinActualValues[i] = powerBandModel.lowerActualValueHzBand1; powerBandModel.upperActualValueHzBand1 = Math.Round(ActualUpperPowerValue, 2); upperPowerBinActualValues[i] = powerBandModel.upperActualValueHzBand1; i++; powerBandsList.Add(powerBandModel); } catch (Exception e) { HandleException(e); } } return(powerBandsList); }
/// <summary> /// Starts sensing and streaming. Skips starting sensing if Adaptive running. /// </summary> /// <param name="theSummit">Summit System</param> /// <param name="senseConfig">Sense Model</param> /// <param name="showErrorMessage">True if you want a popup message on errors or false if show no error popup</param> /// <returns>True if success and false if unsuccessful</returns> public bool StartSensingAndStreaming(SummitSystem theSummit, SenseModel senseConfig, bool showErrorMessage) { APIReturnInfo bufferReturnInfo; try { _log.Info("Start Sensing and Streaming"); //This checks to see if sensing is already enabled. //If it is, then skip write sensing state and just start streaming SensingState state; theSummit.ReadSensingState(out state); if (!state.State.ToString().Contains("DetectionLd0") && !state.State.ToString().Contains("DetectionLd1")) { _log.Info("Detection is off. Turn sensing on with LD0/LD1 off"); // Start sensing //LDO is false because if it is in adaptive then it will bypass this. If not in adaptive, don't need it. bufferReturnInfo = theSummit.WriteSensingState(ConfigConversions.TDSenseStatesConvert( senseConfig.SenseOptions.TimeDomain, senseConfig.SenseOptions.FFT, senseConfig.SenseOptions.Power, false, false, senseConfig.SenseOptions.AdaptiveState, senseConfig.SenseOptions.LoopRecording, senseConfig.SenseOptions.Unused), ConfigConversions.FFTChannelConvert(senseConfig)); if (!CheckForReturnError(bufferReturnInfo, "Write Sensing State", showErrorMessage)) { return(false); } } else { _log.Warn("Detection is on. SKIP SENSING AND START STREAMING!"); } // Start streaming bufferReturnInfo = theSummit.WriteSensingEnableStreams( senseConfig.StreamEnables.TimeDomain, senseConfig.StreamEnables.FFT, senseConfig.StreamEnables.Power, senseConfig.StreamEnables.AdaptiveTherapy, senseConfig.StreamEnables.AdaptiveState, senseConfig.StreamEnables.Accelerometry, senseConfig.StreamEnables.TimeStamp, senseConfig.StreamEnables.EventMarker); if (!CheckForReturnError(bufferReturnInfo, "Stream Enables", showErrorMessage)) { return(false); } } catch (Exception error) { _log.Error(error); return(false); } return(true); }
/// <summary> /// Gets the TDSampleRate for the TimeDomain Channel /// Calls TD SampleRateConvert from ConfigConversions class /// Checks for disabled time domain channels and returns proper sample rate or disabled for disabled channels /// </summary> /// <param name="sampleRateIsEnabled">Either true or false depending on value for Time Domain Channel IsEnabled value from config file</param> /// <param name="localModel">Sense model</param> /// <returns>If the sampleRateIsEnabled variable is set to false, then it returns the TdSampleRates.Disabled. Otherwise it returns the correct TdSampleRates variable for the corresponding TD sample rate from the config file</returns> private TdSampleRates GetTDSampleRate(bool sampleRateIsEnabled, SenseModel localModel) { TdSampleRates the_sample_rate = ConfigConversions.TDSampleRateConvert(localModel.Sense.TDSampleRate); if (!sampleRateIsEnabled) { the_sample_rate = TdSampleRates.Disabled; } return(the_sample_rate); }
/// <summary> /// Gets the file from the filepath, validates the file, and converts it to the sense model /// </summary> /// <param name="filePath">File path for the sense_config.json file to be used to convert</param> /// <returns>SenseModel if successful or null if unsuccessful</returns> public SenseModel GetSenseModelFromFile(string filePath) { SenseModel model = null; string json = null; try { //read sense config file into string using (StreamReader sr = new StreamReader(filePath)) { json = sr.ReadToEnd(); } } catch (Exception e) { MessageBox.Show("The sense config file could not be read from the file. Please check that it exists.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); _log.Error(e); return(model); } if (string.IsNullOrEmpty(json)) { MessageBox.Show("Sense JSON file is empty. Please check that the sense config is correct.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning); _log.Warn("Sense JSON file is empty after loading file."); return(model); } else { SchemaModel schemaModel = new SchemaModel(); if (ValidateJSON(json, schemaModel.GetSenseSchema())) { //if correct json format, write it into SenseModel try { model = JsonConvert.DeserializeObject <SenseModel>(json); } catch (Exception e) { MessageBox.Show("Could not convert sense config file. Please be sure that sense config file is correct.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); _log.Error(e); return(model); } } else { MessageBox.Show("Could not validate sense config file. Please be sure that sense config file is correct.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning); _log.Warn("Could not validate sense config file."); return(model); } } return(model); }
/// <summary> /// Constructor for fft visualizer /// </summary> /// <param name="summitLeft">Summit system for left</param> /// <param name="summitRight">Summit system for right</param> /// <param name="senseLeftModelConfig">Sense model for left</param> /// <param name="senseRightModelConfig">Sense model for right</param> /// <param name="_log">Caliburn micro log</param> public FFTVisualizerViewModel(SummitSystem summitLeft, SummitSystem summitRight, SenseModel senseLeftModelConfig, SenseModel senseRightModelConfig, ILog _log) { theSummitLeft = summitLeft; theSummitRight = summitRight; if(theSummitLeft != null) { theSummitLeft.DataReceivedFFTHandler += theSummit_DataReceived_FFT_Left; } if(theSummitRight != null) { theSummitRight.DataReceivedFFTHandler += theSummit_DataReceived_FFT_Right; } FFTChartLeftUnilateral.SeriesName = "FFT Left/Unilateral"; FFTChartRight.SeriesName = "FFT Right"; YAxesFFT.Add(new NumericAxisViewModel() { AutoRange = AutoRange.Always, VisibleRange = new DoubleRange(0, 0.5), GrowBy = new DoubleRange(0.1, 0.1), AxisTitle = "FFT Values", Id = "FFTID", FontSize = FONTSIZE, AxisAlignment = AxisAlignment.Left, }); this._log = _log; this.senseLeftModelConfig = senseLeftModelConfig; this.senseRightModelConfig = senseRightModelConfig; UpdateFFTSettings(this.senseLeftModelConfig, this.senseRightModelConfig); FFTScaleOptions.Add(FFT_AUTOSCALE_CHART_OPTION); FFTScaleOptions.Add(FFT_NONE_CHART_OPTION); SelectedFFTScaleOption = FFT_AUTOSCALE_CHART_OPTION; FFTMean = userInputForFFTMean.ToString(); FFTLog10Options.Add(FFT_LOG10_CHART_OPTION); FFTLog10Options.Add(FFT_NONE_CHART_OPTION); SelectedFFTLog10Option = FFT_NONE_CHART_OPTION; UpdateLeftUnilateralFFTChannelRadioButtons(); if(theSummitRight != null) { UpdateRightFFTChannelRadioButtons(); } }
/// <summary> /// Method that loads all of the sense config files based on what was loaded from montage config file /// </summary> /// <returns>List of sense models if successful and null if unsuccessful</returns> private List <SenseModel> LoadSenseJSONFilesForMontage(string baseFilepath, string filetype, MontageModel localMontageModel) { List <SenseModel> localList = new List <SenseModel>(); foreach (MontageFile montageFileObject in localMontageModel.MontageFiles) { string filepath = baseFilepath + montageFileObject.Filename + filetype; SenseModel tempModel = jSONService.GetSenseModelFromFile(filepath); if (tempModel != null) { localList.Add(tempModel); } else { MessageBox.Show("The sense config file: " + montageFileObject.Filename + " could not be loaded up correctly. Please try montage again", "Error", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } } return(localList); }
/// <summary> /// Writes the Sense Model to a json config file in specified path /// </summary> /// <param name="senseModel">Model to be written to json file</param> /// <param name="path">path where the file goes including filename and extension</param> /// <returns>true if success and false if unsuccessful</returns> public bool WriteSenseConfigToFile(SenseModel senseModel, string path) { bool success = false; try { using (StreamWriter file = File.CreateText(path)) { JsonSerializer serializer = new JsonSerializer(); serializer.Serialize(file, senseModel); success = true; } } catch (Exception e) { MessageBox.Show("Could not write sense config to file at the path: " + path + ". Please save your current sense config file if you would like them saved for later use.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning); _log.Error(e); success = false; } return(success); }
/// <summary> /// Converts the fft channel /// </summary> /// <param name="localModel">SenseModel for the fft channel and if timedomain for specific channel is enabled</param> /// <returns>SenseTimeDomainChannel of channel or defaults to channel 0</returns> public static SenseTimeDomainChannel FFTChannelConvert(SenseModel localModel) { SenseTimeDomainChannel fftChannel = SenseTimeDomainChannel.Ch0; switch (localModel.Sense.FFT.Channel) { case 0: if (localModel.Sense.TimeDomains[0].IsEnabled) { fftChannel = SenseTimeDomainChannel.Ch0; } break; case 1: if (localModel.Sense.TimeDomains[1].IsEnabled) { fftChannel = SenseTimeDomainChannel.Ch1; } break; case 2: if (localModel.Sense.TimeDomains[2].IsEnabled) { fftChannel = SenseTimeDomainChannel.Ch2; } break; case 3: if (localModel.Sense.TimeDomains[3].IsEnabled) { fftChannel = SenseTimeDomainChannel.Ch3; } break; default: DisplayErrorMessageAndClose("Couldn't convert FFT Channel"); break; } return(fftChannel); }
/// <summary> /// Connects to CTM starting from the 0th value of the list of CTM's and works its way to the Nth. This considered the right in bilateral /// </summary> /// <param name="theSummitManager">Summit manager</param> /// <param name="theSummit">Summit System</param> /// <param name="senseModel">Model for sense from config file</param> /// <param name="appModel">Model for application from config file</param> /// <param name="_log">Caliburn Micro Logger</param> /// <returns>true if connected or false if not connected</returns> public override bool ConnectCTM(SummitManager theSummitManager, ref SummitSystem theSummit, SenseModel senseModel, AppModel appModel, ILog _log) { _log.Info("Checking USB for unbonded CTMs. Please make sure they are powered on."); theSummitManager?.GetUsbTelemetry(); // Retrieve a list of known and bonded telemetry List <InstrumentInfo> knownTelemetry = theSummitManager?.GetKnownTelemetry(); // Check if any CTMs are currently bonded, poll the USB if not so that the user can be prompted to plug in a CTM over USB if (knownTelemetry?.Count == 0) { do { // Inform user we will loop until a CTM is found on USBs _log.Warn("No bonded CTMs found, please plug a CTM in via USB..."); Thread.Sleep(2000); // Bond with any CTMs plugged in over USB knownTelemetry = theSummitManager?.GetUsbTelemetry(); } while (knownTelemetry?.Count == 0); } // Connect to the first CTM available, then try others if it fails SummitSystem tempSummit = null; try { for (int i = 0; i < theSummitManager.GetKnownTelemetry().Count; i++) { ManagerConnectStatus connectReturn; if (appModel?.CTMBeepEnables == null) { connectReturn = theSummitManager.CreateSummit(out tempSummit, theSummitManager.GetKnownTelemetry()[i], InstrumentPhysicalLayers.Any, senseModel.Mode, senseModel.Ratio, CtmBeepEnables.None); } else if (!appModel.CTMBeepEnables.DeviceDiscovered && !appModel.CTMBeepEnables.GeneralAlert && !appModel.CTMBeepEnables.NoDeviceDiscovered && !appModel.CTMBeepEnables.TelMCompleted && !appModel.CTMBeepEnables.TelMLost) { connectReturn = theSummitManager.CreateSummit(out tempSummit, theSummitManager.GetKnownTelemetry()[i], InstrumentPhysicalLayers.Any, senseModel.Mode, senseModel.Ratio, CtmBeepEnables.None); } else { connectReturn = theSummitManager.CreateSummit(out tempSummit, theSummitManager.GetKnownTelemetry()[i], InstrumentPhysicalLayers.Any, senseModel.Mode, senseModel.Ratio, ConfigConversions.BeepEnablesConvert(appModel)); } // Write out the result _log.Info("Create Summit Result: " + connectReturn.ToString()); // Break if it failed successful if (tempSummit != null && connectReturn.HasFlag(ManagerConnectStatus.Success)) { break; } } } catch (Exception e) { _log.Error(e); } // Make sure telemetry was connected to, if not fail if (tempSummit == null) { // inform user that CTM was not successfully connected to if (hasShownMessageToUser) { MainViewModel.ShowMessageBox("Could not connect to CTM. Check that CTM is placed correctly over INS on chest. If problem persists, please inform researcher of problem.", "Connection to CTM Failed", MessageBoxButton.OK, MessageBoxImage.Error); hasShownMessageToUser = false; } return(false); } else { theSummit = tempSummit; return(true); } }
public List <double> GetLowerBinsInHz(SenseModel localModel) { GetPowerBands(localModel); return(lowerPowerBins); }
/// <summary> /// Gets the upper power bins in Hz for the actual values used by program /// </summary> /// <param name="localModel">sense model</param> /// <returns>Double array containing values</returns> public double[] GetUpperPowerBinActualValues(SenseModel localModel) { GetPowerBands(localModel); return(upperPowerBinActualValues); }
/// <summary> /// Converts the enabled power bands from the sense_config file to the correct api format /// This ensures that power bands that are enabled are only enabled if the corresponding time domain channels is also enabled. /// If there is the case where there is a powerband that is enabled and the corresponding time domain channel is not enabled, then it will proceed as though the power band channel was set to disabled. /// </summary> /// <param name="senseModel">This is the sense model that was converted from the sense_config.json file and contains which power band and time domain channels are enabled</param> /// <returns>Correct BandEnables format for all enabled power bands or else 0 if no power bands are enabled</returns> public static BandEnables PowerBandEnablesConvert(SenseModel senseModel) { BandEnables bandEnables = 0; //Check to make sure Power channel AND respective TD Channel is enabled if (senseModel.Sense.PowerBands[0].IsEnabled && senseModel.Sense.TimeDomains[0].IsEnabled) { bandEnables = BandEnables.Ch0Band0Enabled; } if (senseModel.Sense.PowerBands[1].IsEnabled && senseModel.Sense.TimeDomains[0].IsEnabled) { if (bandEnables.Equals(0)) { bandEnables = BandEnables.Ch0Band1Enabled; } else { bandEnables = bandEnables | BandEnables.Ch0Band1Enabled; } } if (senseModel.Sense.PowerBands[2].IsEnabled && senseModel.Sense.TimeDomains[1].IsEnabled) { if (bandEnables.Equals(0)) { bandEnables = BandEnables.Ch1Band0Enabled; } else { bandEnables = bandEnables | BandEnables.Ch1Band0Enabled; } } if (senseModel.Sense.PowerBands[3].IsEnabled && senseModel.Sense.TimeDomains[1].IsEnabled) { if (bandEnables.Equals(0)) { bandEnables = BandEnables.Ch1Band1Enabled; } else { bandEnables = bandEnables | BandEnables.Ch1Band1Enabled; } } if (senseModel.Sense.PowerBands[4].IsEnabled && senseModel.Sense.TimeDomains[2].IsEnabled) { if (bandEnables.Equals(0)) { bandEnables = BandEnables.Ch2Band0Enabled; } else { bandEnables = bandEnables | BandEnables.Ch2Band0Enabled; } } if (senseModel.Sense.PowerBands[5].IsEnabled && senseModel.Sense.TimeDomains[2].IsEnabled) { if (bandEnables.Equals(0)) { bandEnables = BandEnables.Ch2Band1Enabled; } else { bandEnables = bandEnables | BandEnables.Ch2Band1Enabled; } } if (senseModel.Sense.PowerBands[6].IsEnabled && senseModel.Sense.TimeDomains[3].IsEnabled) { if (bandEnables.Equals(0)) { bandEnables = BandEnables.Ch3Band0Enabled; } else { bandEnables = bandEnables | BandEnables.Ch3Band0Enabled; } } if (senseModel.Sense.PowerBands[7].IsEnabled && senseModel.Sense.TimeDomains[3].IsEnabled) { if (bandEnables.Equals(0)) { bandEnables = BandEnables.Ch3Band1Enabled; } else { bandEnables = bandEnables | BandEnables.Ch3Band1Enabled; } } return(bandEnables); }
/// <summary> /// Need to override to put code in to connect to CTM /// </summary> /// <returns></returns> public abstract bool ConnectCTM(SummitManager theSummitManager, ref SummitSystem theSummit, SenseModel senseModel, AppModel appModel, ILog _log);
private bool ChangeFFTChannelCode(SenseTimeDomainChannel channel, SummitSystem localSummit, SenseModel localSenseModel) { SummitSensing summitSensing = new SummitSensing(_log); if (localSummit != null && !localSummit.IsDisposed && localSenseModel != null) { try { if (!summitSensing.StopSensing(localSummit, false)) { return false; } localSenseModel.Sense.FFT.Channel = (int)channel; if (!summitSensing.StartSensingAndStreaming(localSummit, localSenseModel, false)) { return false; } } catch (Exception e) { _log.Error(e); return false; } } else { //error occurred return false; } return true; }
/// <summary> /// Changes the active group to the group specified. /// </summary> /// <param name="localSummit">Summit System</param> /// <param name="groupToChangeTo">Medtronic Active Group Format to change to</param> /// <param name="localSenseModel">Sense Model that uses the streaming parameters for turning stream on and off</param> /// <returns>Tuple with bool true if success or false if not. string give error message</returns> public async Task <Tuple <bool, string> > ChangeActiveGroup(SummitSystem localSummit, ActiveGroup groupToChangeTo, SenseModel localSenseModel) { if (localSummit == null || localSummit.IsDisposed) { return(Tuple.Create(false, "Error: Summit null or disposed.")); } APIReturnInfo bufferReturnInfo; try { int counter = 5; summitSensing.StopStreaming(localSummit, true); do { bufferReturnInfo = await Task.Run(() => localSummit.StimChangeActiveGroup(groupToChangeTo)); if (counter < 5) { Thread.Sleep(400); } counter--; } while ((bufferReturnInfo.RejectCode != 0) && counter > 0); //Start streaming summitSensing.StartStreaming(localSummit, localSenseModel, true); if ((bufferReturnInfo.RejectCode != 0) && counter == 0) { _log.Warn(":: Error: Medtronic API return error changing active group: " + bufferReturnInfo.Descriptor + ". Reject Code: " + bufferReturnInfo.RejectCode); return(Tuple.Create(false, "Error: Medtronic API return error changing active group: " + bufferReturnInfo.Descriptor + ". Reject Code: " + bufferReturnInfo.RejectCode)); } } catch (Exception e) { _log.Error(e); return(Tuple.Create(false, "Error: Could not change groups")); } return(Tuple.Create(true, "Successfully changed groups")); }
/// <summary> /// Write Sense Configuration Settings /// </summary> /// <param name="localModel">The config file to use for sensing parameters</param> /// <param name="theSummit">Summit system</param> /// <param name="showErrorMessage">True if you want a popup message on errors or false if show no error popup</param> /// <returns>true if successfully configuring sensing or false if unsuccessful</returns> public bool SummitConfigureSensing(SummitSystem theSummit, SenseModel localModel, bool showErrorMessage) { APIReturnInfo bufferReturnInfo; //This checks to see if sensing is already enabled. This can happen if adaptive is already running and we don't need to configure it. //If it is, then skip setting up sensing if (CheckIsAdaptiveRunning(theSummit)) { return(true); } int counter = 5; while (counter > 0) { if (StopSensing(theSummit, showErrorMessage)) { break; } else { _log.Warn("Could not stop sensing before configure sensing. Trying again..."); counter--; Thread.Sleep(500); } } if (counter == 0) { _log.Warn("Could not stop sensing before configure sensing. Returning false"); return(false); } // Create a sensing configuration List <TimeDomainChannel> TimeDomainChannels = new List <TimeDomainChannel>(4); // Channel Specific configuration - 0 TimeDomainChannels.Add(new TimeDomainChannel( GetTDSampleRate(localModel.Sense.TimeDomains[0].IsEnabled, localModel), ConfigConversions.TdMuxInputsConvert(localModel.Sense.TimeDomains[0].Inputs[0]), ConfigConversions.TdMuxInputsConvert(localModel.Sense.TimeDomains[0].Inputs[1]), ConfigConversions.TdEvokedResponseEnableConvert(localModel.Sense.TimeDomains[0].TdEvokedResponseEnable), ConfigConversions.TdLpfStage1Convert(localModel.Sense.TimeDomains[0].Lpf1), ConfigConversions.TdLpfStage2Convert(localModel.Sense.TimeDomains[0].Lpf2), ConfigConversions.TdHpfsConvert(localModel.Sense.TimeDomains[0].Hpf))); // Channel Specific configuration - 1 TimeDomainChannels.Add(new TimeDomainChannel( GetTDSampleRate(localModel.Sense.TimeDomains[1].IsEnabled, localModel), ConfigConversions.TdMuxInputsConvert(localModel.Sense.TimeDomains[1].Inputs[0]), ConfigConversions.TdMuxInputsConvert(localModel.Sense.TimeDomains[1].Inputs[1]), ConfigConversions.TdEvokedResponseEnableConvert(localModel.Sense.TimeDomains[1].TdEvokedResponseEnable), ConfigConversions.TdLpfStage1Convert(localModel.Sense.TimeDomains[1].Lpf1), ConfigConversions.TdLpfStage2Convert(localModel.Sense.TimeDomains[1].Lpf2), ConfigConversions.TdHpfsConvert(localModel.Sense.TimeDomains[1].Hpf))); // Channel Specific configuration - 2 TimeDomainChannels.Add(new TimeDomainChannel( GetTDSampleRate(localModel.Sense.TimeDomains[2].IsEnabled, localModel), ConfigConversions.TdMuxInputsConvert(localModel.Sense.TimeDomains[2].Inputs[0]), ConfigConversions.TdMuxInputsConvert(localModel.Sense.TimeDomains[2].Inputs[1]), ConfigConversions.TdEvokedResponseEnableConvert(localModel.Sense.TimeDomains[2].TdEvokedResponseEnable), ConfigConversions.TdLpfStage1Convert(localModel.Sense.TimeDomains[2].Lpf1), ConfigConversions.TdLpfStage2Convert(localModel.Sense.TimeDomains[2].Lpf2), ConfigConversions.TdHpfsConvert(localModel.Sense.TimeDomains[2].Hpf))); // Channel Specific configuration - 3 TimeDomainChannels.Add(new TimeDomainChannel( GetTDSampleRate(localModel.Sense.TimeDomains[3].IsEnabled, localModel), ConfigConversions.TdMuxInputsConvert(localModel.Sense.TimeDomains[3].Inputs[0]), ConfigConversions.TdMuxInputsConvert(localModel.Sense.TimeDomains[3].Inputs[1]), ConfigConversions.TdEvokedResponseEnableConvert(localModel.Sense.TimeDomains[3].TdEvokedResponseEnable), ConfigConversions.TdLpfStage1Convert(localModel.Sense.TimeDomains[3].Lpf1), ConfigConversions.TdLpfStage2Convert(localModel.Sense.TimeDomains[3].Lpf2), ConfigConversions.TdHpfsConvert(localModel.Sense.TimeDomains[3].Hpf))); // Set up the FFT FftConfiguration fftChannel = new FftConfiguration( ConfigConversions.FftSizesConvert(localModel.Sense.FFT.FftSize), localModel.Sense.FFT.FftInterval, ConfigConversions.FftWindowAutoLoadsConvert(localModel.Sense.FFT.WindowLoad), localModel.Sense.FFT.WindowEnabled, ConfigConversions.FftWeightMultipliesConvert(localModel.Sense.FFT.WeightMultiplies), localModel.Sense.FFT.StreamSizeBins, localModel.Sense.FFT.StreamOffsetBins); // Set up the Power channels List <PowerChannel> powerChannels = new List <PowerChannel>(); //This goes through each power channel and gets the lower power band and upper power band. //Medtronic api uses bin index values for setting power channels instead of actual values in Hz //This calls the CalculatePowerBins class to convert to proper medtronic api values from the user config file //User config file has estimated values in Hz for each channel. //CalculatePowerBins converts them to actual power values and we are able to get the bin index value from that. CalculatePowerBins calculatePowerBins = new CalculatePowerBins(_log); List <PowerBandModel> powerBandsList = calculatePowerBins.GetPowerBands(localModel); if (powerBandsList == null || powerBandsList.Count < 3) { MessageBox.Show("Error calculating power bins. Please check that power bins are correct in the config file and try again.", "Error", MessageBoxButton.OK, MessageBoxImage.Hand); return(false); } for (int i = 0; i < 4; i++) { //Add the lower and upper power bands to the power channel powerChannels.Add(new PowerChannel(powerBandsList[i].lowerIndexBand0, powerBandsList[i].upperIndexBand0, powerBandsList[i].lowerIndexBand1, powerBandsList[i].upperIndexBand1)); } //Gets the enabled power bands from the sense config file and returns the correct api call for all enabled BandEnables theBandEnables = ConfigConversions.PowerBandEnablesConvert(localModel); // Set up the miscellaneous settings MiscellaneousSensing miscsettings = new MiscellaneousSensing(); miscsettings.StreamingRate = ConfigConversions.MiscStreamRateConvert(localModel.Sense.Misc.StreamingRate); miscsettings.LrTriggers = ConfigConversions.MiscloopRecordingTriggersConvert(localModel.Sense.Misc.LoopRecordingTriggersState, localModel.Sense.Misc.LoopRecordingTriggersIsEnabled); miscsettings.LrPostBufferTime = localModel.Sense.Misc.LoopRecordingPostBufferTime; miscsettings.Bridging = ConfigConversions.MiscBridgingConfigConvert(localModel.Sense.Misc.Bridging); //Writes all sensing information here try { bufferReturnInfo = theSummit.WriteSensingTimeDomainChannels(TimeDomainChannels); if (!CheckForReturnError(bufferReturnInfo, "Writing Sensing Time Domain", showErrorMessage)) { return(false); } bufferReturnInfo = theSummit.WriteSensingFftSettings(fftChannel); if (!CheckForReturnError(bufferReturnInfo, "Writing Sensing FFT", showErrorMessage)) { return(false); } bufferReturnInfo = theSummit.WriteSensingPowerChannels(theBandEnables, powerChannels); if (!CheckForReturnError(bufferReturnInfo, "Writing Sensing Power", showErrorMessage)) { return(false); } bufferReturnInfo = theSummit.WriteSensingMiscSettings(miscsettings); if (!CheckForReturnError(bufferReturnInfo, "Writing Sensing Misc", showErrorMessage)) { return(false); } bufferReturnInfo = theSummit.WriteSensingAccelSettings(ConfigConversions.AccelSampleRateConvert(localModel.Sense.Accelerometer.SampleRate, localModel.Sense.Accelerometer.SampleRateDisabled)); if (!CheckForReturnError(bufferReturnInfo, "Writing Sensing Accel", showErrorMessage)) { return(false); } } catch (Exception error) { _log.Error(error); return(false); } return(true); }