init
This commit is contained in:
+3669
File diff suppressed because it is too large
Load Diff
+969
@@ -0,0 +1,969 @@
|
||||
#if defined(TARGET_HAS_ThirdPartyGNEEDaccessAPI)
|
||||
|
||||
#include "ovasCConfigurationgNautilusInterface.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AcquisitionServer {
|
||||
|
||||
/*_________________________________________________
|
||||
|
||||
Insert callback to specific widget here
|
||||
Example with a button that launch a calibration of the device:
|
||||
*/
|
||||
|
||||
//Callback connected to a dedicated gtk button (button_select_channels_bipolar_car_noise):
|
||||
static void ChannelSettingsCB(GtkButton* button, void* data) { static_cast<CConfigurationgNautilusInterface*>(data)->buttonChannelSettingsPressedCB(); }
|
||||
|
||||
//Callback connected to a dedicated gtk button (button_select_sensitivity_filters):
|
||||
static void SensitivityFiltersCB(GtkButton* button, void* data) { static_cast<CConfigurationgNautilusInterface*>(data)->buttonSensitivityFiltersPressedCB(); }
|
||||
|
||||
//Callback connected to a dedicated gtk button (button_sensitivity_filters_apply):
|
||||
static void SensitivityFiltersApplyCB(GtkButton* button, void* data)
|
||||
{
|
||||
static_cast<CConfigurationgNautilusInterface*>(data)->buttonSensitivityFiltersApplyPressedCB();
|
||||
}
|
||||
|
||||
//Callback connected to a dedicated gtk button (button_channel_apply):
|
||||
static void ChannelSettingsApplyCB(GtkButton* button, void* data)
|
||||
{
|
||||
static_cast<CConfigurationgNautilusInterface*>(data)->buttonChannelSettingsApplyPressedCB();
|
||||
}
|
||||
|
||||
//Callback actually called:
|
||||
void CConfigurationgNautilusInterface::buttonChannelSettingsPressedCB()
|
||||
{
|
||||
// Connect to the hardware, ask for calibration, verify the return code, etc.
|
||||
|
||||
GtkWidget* dialog = GTK_WIDGET(gtk_builder_get_object(m_builder,"dialog_select_channels_bipolar_car_noise"));
|
||||
gint resp = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
|
||||
gtk_widget_hide(dialog);
|
||||
}
|
||||
|
||||
//Callback actually called:
|
||||
void CConfigurationgNautilusInterface::buttonSensitivityFiltersPressedCB()
|
||||
{
|
||||
// get bandpass and notch filters for currenty selected sampling rate and set to filter list in corresponding dialog
|
||||
GtkWidget* dialog = GTK_WIDGET(gtk_builder_get_object(m_builder,"dialog_sensitivity_filters"));
|
||||
gint resp = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
|
||||
gtk_widget_hide(dialog);
|
||||
}
|
||||
|
||||
|
||||
//Callback actually called:
|
||||
void CConfigurationgNautilusInterface::buttonSensitivityFiltersApplyPressedCB()
|
||||
{
|
||||
// get handle to sensitivity and filters dialog and close it
|
||||
GtkWidget* dialog = GTK_WIDGET(gtk_builder_get_object(m_builder,"dialog_sensitivity_filters"));
|
||||
gtk_widget_hide(dialog);
|
||||
}
|
||||
|
||||
|
||||
//Callback actually called:
|
||||
void CConfigurationgNautilusInterface::buttonChannelSettingsApplyPressedCB()
|
||||
{
|
||||
// get handle to channel settings dialog and close it
|
||||
GtkWidget* dialog = GTK_WIDGET(gtk_builder_get_object(m_builder,"dialog_select_channels_bipolar_car_noise"));
|
||||
gtk_widget_hide(dialog);
|
||||
|
||||
// get number of channels selected and set range as number of channels starting at number of channels
|
||||
uint16_t nChannels = 0;
|
||||
char tmp[30];
|
||||
for (uint32_t i = 0; i < GDS_GNAUTILUS_CHANNELS_MAX; ++i)
|
||||
{
|
||||
// set electrode names as channel names in channel selection dialog
|
||||
sprintf_s(&tmp[0], 30, "checkbutton_channel_%d", (i + 1));
|
||||
GtkButton* checkButton = GTK_BUTTON(gtk_builder_get_object(m_builder,tmp));
|
||||
if (checkButton)
|
||||
{
|
||||
if ((gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkButton))) && (gtk_widget_get_visible(GTK_WIDGET(checkButton)))) { nChannels += 1; }
|
||||
}
|
||||
}
|
||||
|
||||
GtkSpinButton* button = GTK_SPIN_BUTTON(gtk_builder_get_object(m_builder,"spinbutton_number_of_channels"));
|
||||
gtk_spin_button_set_range(button, nChannels, nChannels);
|
||||
gtk_spin_button_set_value(button, nChannels);
|
||||
}
|
||||
|
||||
// catch combobox sampling rate changed signal and call function which handles event
|
||||
static void sample_rate_changed_cb(GtkComboBox* comboBox, void* data) { static_cast<CConfigurationgNautilusInterface*>(data)->comboboxSampleRateChangedCB(); }
|
||||
|
||||
// Callback actually called
|
||||
void CConfigurationgNautilusInterface::comboboxSampleRateChangedCB()
|
||||
{
|
||||
// get hardware filters according to sampling frequency currently selected
|
||||
const bool res = getFiltersForNewSamplingRate();
|
||||
if (!res) { } // error logged in getFiltersForNewSamplingRate
|
||||
}
|
||||
|
||||
// catch noise reduction checkbox toggled signal and call function which handles event
|
||||
static void noise_reduction_changed_cb(GtkCheckButton* pCheckbutton, void* data)
|
||||
{
|
||||
static_cast<CConfigurationgNautilusInterface*>(data)->checkbuttonNoiseReductionChangedCB();
|
||||
}
|
||||
|
||||
// Callback actually called
|
||||
void CConfigurationgNautilusInterface::checkbuttonNoiseReductionChangedCB()
|
||||
{
|
||||
// activate/deactivate noise reduction checkboxes in dialog_select_channels_bipolar_car_noise
|
||||
GtkCheckButton* buttonNoise = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,"checkbutton_noise_reduction"));
|
||||
const gboolean buttonValue = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttonNoise));
|
||||
char tmp[45];
|
||||
for (uint16_t i = 0; i < GDS_GNAUTILUS_CHANNELS_MAX; ++i)
|
||||
{
|
||||
sprintf_s(&tmp[0], 45, "checkbutton_noise_channel_%d", (i + 1));
|
||||
GtkCheckButton* buttonNoiseChannel = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,tmp));
|
||||
|
||||
if (buttonNoiseChannel)
|
||||
{
|
||||
if (gtk_widget_get_visible(GTK_WIDGET(buttonNoiseChannel))) { gtk_widget_set_sensitive(GTK_WIDGET(buttonNoiseChannel), buttonValue); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// catch car checkbox toggled signal and call function which handles event
|
||||
static void car_changed_cb(GtkCheckButton* /*button*/, void* data) { static_cast<CConfigurationgNautilusInterface*>(data)->checkbuttonCARChangedCB(); }
|
||||
|
||||
// Callback actually called
|
||||
void CConfigurationgNautilusInterface::checkbuttonCARChangedCB()
|
||||
{
|
||||
// activate/deactivate car checkboxes in dialog_select_channels_bipolar_car_noise
|
||||
GtkCheckButton* buttonCAR = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,"checkbutton_car"));
|
||||
const gboolean buttonValue = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttonCAR));
|
||||
char tmp[45];
|
||||
for (uint16_t i = 0; i < GDS_GNAUTILUS_CHANNELS_MAX; ++i)
|
||||
{
|
||||
sprintf_s(&tmp[0], 45, "checkbutton_car_channel_%d", (i + 1));
|
||||
GtkCheckButton* buttonCarChannel = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,tmp));
|
||||
if (buttonCarChannel)
|
||||
{
|
||||
if (gtk_widget_get_visible(GTK_WIDGET(buttonCarChannel))) { gtk_widget_set_sensitive(GTK_WIDGET(buttonCarChannel), buttonValue); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get hardware related settings from GDS
|
||||
bool CConfigurationgNautilusInterface::getHardwareSettings()
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
uint32_t i;
|
||||
|
||||
// get network channel and set in dialog and set one as active in dialog
|
||||
size_t supportedNwChannelsCount;
|
||||
// get number of supported network channels to allocate memory to hold supported network channels
|
||||
m_gdsResult = GDS_GNAUTILUS_GetSupportedNetworkChannels(m_deviceHandle, m_deviceNames, nullptr, &supportedNwChannelsCount);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
uint32_t* supportedNwChannels = new uint32_t[supportedNwChannelsCount];
|
||||
m_gdsResult = GDS_GNAUTILUS_GetSupportedNetworkChannels(m_deviceHandle, m_deviceNames, supportedNwChannels, &supportedNwChannelsCount);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
// get network channel currently used between base station and headstage
|
||||
uint32_t val;
|
||||
m_gdsResult = GDS_GNAUTILUS_GetNetworkChannel(m_deviceHandle, m_deviceNames, &val);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// put network channels to combobox
|
||||
GtkComboBox* comboBoxNetworkChannel = GTK_COMBO_BOX(gtk_builder_get_object(m_builder, "combobox_network_channel"));
|
||||
GtkTreeModel* listStoreNetworkChannel = gtk_combo_box_get_model(comboBoxNetworkChannel);
|
||||
gtk_list_store_clear(GTK_LIST_STORE(listStoreNetworkChannel));
|
||||
std::stringstream networkChannel;
|
||||
if (m_comboBoxNetworkChannels.size() > 0) m_comboBoxNetworkChannels.clear();
|
||||
|
||||
// fill network channel combobox with available network channels
|
||||
for (i = 0; i < supportedNwChannelsCount; ++i)
|
||||
{
|
||||
networkChannel << supportedNwChannels[i];
|
||||
gtk_list_store_append(GTK_LIST_STORE(listStoreNetworkChannel), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(listStoreNetworkChannel), &iter, 0, networkChannel.str().c_str(), -1);
|
||||
networkChannel.clear();
|
||||
networkChannel.str("");
|
||||
|
||||
m_comboBoxNetworkChannels.push_back(supportedNwChannels[i]);
|
||||
}
|
||||
|
||||
const auto it = find(m_comboBoxNetworkChannels.begin(), m_comboBoxNetworkChannels.end(), val);
|
||||
const size_t nwChIndex = distance(m_comboBoxNetworkChannels.begin(), it);
|
||||
gtk_combo_box_set_active(comboBoxNetworkChannel, nwChIndex);
|
||||
|
||||
delete [] supportedNwChannels;
|
||||
|
||||
// get supported sample rates
|
||||
size_t nSampling;
|
||||
|
||||
// get number of supported sample rates
|
||||
m_gdsResult = GDS_GNAUTILUS_GetSupportedSamplingRates(m_deviceHandle, m_deviceNames, nullptr, &nSampling);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t* sampling = new uint32_t[nSampling];
|
||||
// get supported sample rates
|
||||
m_gdsResult = GDS_GNAUTILUS_GetSupportedSamplingRates(m_deviceHandle, m_deviceNames, sampling, &nSampling);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// set sample rates as content of combo box in corresponding dialog
|
||||
GtkComboBox* comboBoxSamplings = GTK_COMBO_BOX(gtk_builder_get_object(m_builder, "combobox_sampling_frequency"));
|
||||
GtkTreeModel* listStoreSamplings = gtk_combo_box_get_model(comboBoxSamplings);
|
||||
gtk_list_store_clear(GTK_LIST_STORE(listStoreSamplings));
|
||||
for (i = 0; i < nSampling; ++i)
|
||||
{
|
||||
std::string str = std::to_string(sampling[i]);
|
||||
gtk_list_store_append(GTK_LIST_STORE(listStoreSamplings), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(listStoreSamplings), &iter, 0, str.c_str(), -1);
|
||||
}
|
||||
gtk_combo_box_set_active(comboBoxSamplings, 0);
|
||||
|
||||
const bool functionReturn = getFiltersForNewSamplingRate();
|
||||
if (!functionReturn) { return false; }
|
||||
|
||||
size_t nSensitivities;
|
||||
// get number of sensitivities
|
||||
m_gdsResult = GDS_GNAUTILUS_GetSupportedSensitivities(m_deviceHandle, m_deviceNames, nullptr, &nSensitivities);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
// get sensitivities
|
||||
double* sensitivities = new double[nSensitivities];
|
||||
m_gdsResult = GDS_GNAUTILUS_GetSupportedSensitivities(m_deviceHandle, m_deviceNames, sensitivities, &nSensitivities);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
// set items in dialog item combobox_select_sensitivity
|
||||
GtkComboBox* comboBoxSensitivities = GTK_COMBO_BOX(gtk_builder_get_object(m_builder, "combobox_select_sensitivity"));
|
||||
GtkTreeModel* listStoreSensitivities = gtk_combo_box_get_model(comboBoxSensitivities);
|
||||
gtk_list_store_clear(GTK_LIST_STORE(listStoreSensitivities));
|
||||
for (i = 0; i < nSensitivities; ++i)
|
||||
{
|
||||
std::string str = std::to_string(sensitivities[i] / 1000);
|
||||
gtk_list_store_append(GTK_LIST_STORE(listStoreSensitivities), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(listStoreSensitivities), &iter, 0, str.c_str(), -1);
|
||||
m_comboBoxSensitivityValues.push_back(sensitivities[i]);
|
||||
}
|
||||
gtk_combo_box_set_active(comboBoxSensitivities, 0);
|
||||
|
||||
delete [] sensitivities;
|
||||
|
||||
size_t nInputSources;
|
||||
// first get number of supported input sources (call with third parameter set to NULL)
|
||||
m_gdsResult = GDS_GNAUTILUS_GetSupportedInputSources(m_deviceHandle, m_deviceNames, nullptr, &nInputSources);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
// allocate memory to hold input sources
|
||||
GDS_GNAUTILUS_INPUT_SIGNAL* inputSources = new GDS_GNAUTILUS_INPUT_SIGNAL[nInputSources];
|
||||
// now get input sources
|
||||
m_gdsResult = GDS_GNAUTILUS_GetSupportedInputSources(m_deviceHandle, m_deviceNames, inputSources, &nInputSources);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// set values to combobox_input_source (there are only three allowed at the moment, see code below)
|
||||
GtkComboBox* comboBoxInputSources = GTK_COMBO_BOX(gtk_builder_get_object(m_builder, "combobox_input_source"));
|
||||
GtkTreeModel* listStoreInputSources = gtk_combo_box_get_model(comboBoxInputSources);
|
||||
gtk_list_store_clear(GTK_LIST_STORE(listStoreInputSources));
|
||||
for (i = 0; i < nInputSources; ++i)
|
||||
{
|
||||
if (inputSources[i] == 0)
|
||||
{
|
||||
// electrode input
|
||||
m_comboBoxInputSources.push_back(inputSources[i]);
|
||||
gtk_list_store_append(GTK_LIST_STORE(listStoreInputSources), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(listStoreInputSources), &iter, 0, "Electrode", -1);
|
||||
}
|
||||
else if (inputSources[i] == 1)
|
||||
{
|
||||
// shortcut
|
||||
m_comboBoxInputSources.push_back(inputSources[i]);
|
||||
gtk_list_store_append(GTK_LIST_STORE(listStoreInputSources), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(listStoreInputSources), &iter, 0, "Shortcut", -1);
|
||||
}
|
||||
else if (inputSources[i] == 5)
|
||||
{
|
||||
// test signal
|
||||
m_comboBoxInputSources.push_back(inputSources[i]);
|
||||
gtk_list_store_append(GTK_LIST_STORE(listStoreInputSources), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(listStoreInputSources), &iter, 0, "Test Signal", -1);
|
||||
}
|
||||
}
|
||||
gtk_combo_box_set_active(comboBoxInputSources, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// get channel names for hardware currently connected (cannot be changed as electrode grid is fixed)
|
||||
bool CConfigurationgNautilusInterface::getChannelNames()
|
||||
{
|
||||
uint32_t nMountedModules;
|
||||
size_t nElectrodeNames;
|
||||
char tmp[30];
|
||||
std::stringstream bipolarEntry;
|
||||
|
||||
// get number of mounted modules and electrode names currently available
|
||||
nMountedModules = 0;
|
||||
nElectrodeNames = 0;
|
||||
m_gdsResult = GDS_GNAUTILUS_GetChannelNames(m_deviceHandle, m_deviceNames, &nMountedModules,NULL, &nElectrodeNames);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
// set array of electrode names according to names currently available
|
||||
char (*electrodeNames)[GDS_GNAUTILUS_ELECTRODE_NAME_LENGTH_MAX] = new char[nElectrodeNames][GDS_GNAUTILUS_ELECTRODE_NAME_LENGTH_MAX];
|
||||
// get electrode names
|
||||
m_gdsResult = GDS_GNAUTILUS_GetChannelNames(m_deviceHandle, m_deviceNames, &nMountedModules, electrodeNames, &nElectrodeNames);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
GtkComboBox* comboBoxBipolarChannels = GTK_COMBO_BOX(gtk_builder_get_object(m_builder,"combobox_channel_1"));
|
||||
GtkTreeModel* listStoreBipolarChannels = gtk_combo_box_get_model(comboBoxBipolarChannels);
|
||||
gtk_list_store_clear(GTK_LIST_STORE(listStoreBipolarChannels));
|
||||
|
||||
bipolarEntry << "none";
|
||||
GtkTreeIter it;
|
||||
gtk_list_store_append(GTK_LIST_STORE(listStoreBipolarChannels), &it);
|
||||
gtk_list_store_set(GTK_LIST_STORE(listStoreBipolarChannels), &it, 0, bipolarEntry.str().c_str(), -1);
|
||||
for (uint16_t i = 0; i < GDS_GNAUTILUS_CHANNELS_MAX; ++i)
|
||||
{
|
||||
// set electrode names as channel names in channel selection dialog
|
||||
sprintf_s(&tmp[0], 30, "checkbutton_channel_%d", (i + 1));
|
||||
GtkButton* buttonChannel = GTK_BUTTON(gtk_builder_get_object(m_builder,tmp));
|
||||
if ((buttonChannel) && (i < nElectrodeNames))
|
||||
{
|
||||
gtk_button_set_label(buttonChannel, &electrodeNames[i][0]);
|
||||
gtk_list_store_append(GTK_LIST_STORE(listStoreBipolarChannels), &it);
|
||||
gtk_list_store_set(GTK_LIST_STORE(listStoreBipolarChannels), &it, 0, &electrodeNames[i][0], -1);
|
||||
}
|
||||
else if ((buttonChannel) && (i >= nElectrodeNames))
|
||||
{
|
||||
gtk_widget_set_sensitive(GTK_WIDGET(buttonChannel), false);
|
||||
gtk_button_set_label(buttonChannel, "");
|
||||
}
|
||||
}
|
||||
for (uint16_t i = 0; i < GDS_GNAUTILUS_CHANNELS_MAX; ++i)
|
||||
{
|
||||
sprintf_s(&tmp[0], 30, "combobox_channel_%d", (i + 1));
|
||||
comboBoxBipolarChannels = GTK_COMBO_BOX(gtk_builder_get_object(m_builder,tmp));
|
||||
if (comboBoxBipolarChannels)
|
||||
{
|
||||
gtk_combo_box_set_model(comboBoxBipolarChannels, listStoreBipolarChannels);
|
||||
gtk_combo_box_set_active(comboBoxBipolarChannels, 0);
|
||||
}
|
||||
}
|
||||
// adapt number of recorded channels in main configuration dialog according to number of actual selected channels
|
||||
GtkSpinButton* buttonNChannels = GTK_SPIN_BUTTON(gtk_builder_get_object(m_builder,"spinbutton_number_of_channels"));
|
||||
gtk_spin_button_set_range(buttonNChannels, nElectrodeNames, nElectrodeNames);
|
||||
gtk_spin_button_set_value(buttonNChannels, nElectrodeNames);
|
||||
|
||||
// set electrode names as channel names
|
||||
m_channelNames.clear();
|
||||
for (size_t i = 0; i < nElectrodeNames; ++i) { m_channelNames[i] = electrodeNames[i]; }
|
||||
|
||||
delete [] electrodeNames;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// get channels currenly available for g.Nautilus used
|
||||
bool CConfigurationgNautilusInterface::getAvailableChannels()
|
||||
{
|
||||
char tmp[30];
|
||||
|
||||
// get channels currently available on connected device
|
||||
BOOL availableChannels[GDS_GNAUTILUS_CHANNELS_MAX];
|
||||
m_gdsResult = GDS_GNAUTILUS_GetAvailableChannels(m_deviceHandle, m_deviceNames, &availableChannels);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_availableChannels.resize(GDS_GNAUTILUS_CHANNELS_MAX);
|
||||
|
||||
for (uint16_t i = 0; i < GDS_GNAUTILUS_CHANNELS_MAX; ++i)
|
||||
{
|
||||
sprintf_s(&tmp[0], 30, "checkbutton_channel_%d", (i + 1));
|
||||
GtkCheckButton* buttonChannel = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,tmp));
|
||||
sprintf_s(&tmp[0], 30, "label_channel_%d", (i + 1));
|
||||
GtkLabel* labelChannel = GTK_LABEL(gtk_builder_get_object(m_builder,tmp));
|
||||
sprintf_s(&tmp[0], 30, "combobox_channel_%d", (i + 1));
|
||||
GtkComboBox* comboBoxChannel = GTK_COMBO_BOX(gtk_builder_get_object(m_builder,tmp));
|
||||
sprintf_s(&tmp[0], 30, "checkbutton_car_channel_%d", (i + 1));
|
||||
GtkCheckButton* buttonCARChannel = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,tmp));
|
||||
sprintf_s(&tmp[0], 30, "checkbutton_noise_channel_%d", (i + 1));
|
||||
GtkCheckButton* buttonNoiseChannel = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,tmp));
|
||||
if (availableChannels[i] == 1)
|
||||
{
|
||||
if (buttonChannel)
|
||||
{
|
||||
gtk_widget_set_visible(GTK_WIDGET(buttonChannel), true);
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(buttonChannel), true);
|
||||
gtk_widget_set_visible(GTK_WIDGET(labelChannel), true);
|
||||
gtk_widget_set_visible(GTK_WIDGET(comboBoxChannel), true);
|
||||
gtk_widget_set_visible(GTK_WIDGET(buttonCARChannel), true);
|
||||
gtk_widget_set_visible(GTK_WIDGET(buttonNoiseChannel), true);
|
||||
}
|
||||
m_availableChannels[i] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buttonChannel)
|
||||
{
|
||||
gtk_widget_set_visible(GTK_WIDGET(buttonChannel), false);
|
||||
gtk_widget_set_visible(GTK_WIDGET(labelChannel), false);
|
||||
gtk_widget_set_visible(GTK_WIDGET(comboBoxChannel), false);
|
||||
gtk_widget_set_visible(GTK_WIDGET(buttonCARChannel), false);
|
||||
gtk_widget_set_visible(GTK_WIDGET(buttonNoiseChannel), false);
|
||||
}
|
||||
m_availableChannels[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// if sampling rate changed filters in filter settings dialog have to be updated according to new sampling rate
|
||||
bool CConfigurationgNautilusInterface::getFiltersForNewSamplingRate()
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
|
||||
// get current sample rate
|
||||
GtkComboBox* comboBoxSampling = GTK_COMBO_BOX(gtk_builder_get_object(m_builder, "combobox_sampling_frequency"));
|
||||
const char* sSampling = gtk_combo_box_get_active_text(comboBoxSampling);
|
||||
double sampling = atof(sSampling);
|
||||
|
||||
size_t nBandPassFilters, nNotchFilters;
|
||||
std::stringstream filterDesc;
|
||||
filterDesc << "no bandpass filter";
|
||||
|
||||
// get number of bandpass filters and allocate filter array correspondingly
|
||||
m_gdsResult = GDS_GNAUTILUS_GetBandpassFilters(m_deviceHandle, m_deviceNames, nullptr, &nBandPassFilters);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
GDS_FILTER_INFO* bandPassFilters = new GDS_FILTER_INFO[nBandPassFilters];
|
||||
// get bandpass filters
|
||||
m_gdsResult = GDS_GNAUTILUS_GetBandpassFilters(m_deviceHandle, m_deviceNames, bandPassFilters, &nBandPassFilters);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage;
|
||||
return false;
|
||||
}
|
||||
// get number of notch filters and allocate filter array correspondingly
|
||||
m_gdsResult = GDS_GNAUTILUS_GetNotchFilters(m_deviceHandle, m_deviceNames, nullptr, &nNotchFilters);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
GDS_FILTER_INFO* notchFilters = new GDS_FILTER_INFO[nNotchFilters];
|
||||
// get notch filters
|
||||
m_gdsResult = GDS_GNAUTILUS_GetNotchFilters(m_deviceHandle, m_deviceNames, notchFilters, &nNotchFilters);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// set filters as combobox entries depending on the current sample rate selected
|
||||
GtkComboBox* comboBoxBandPass = GTK_COMBO_BOX(gtk_builder_get_object(m_builder,"combobox_select_bandpass_filter"));
|
||||
GtkTreeModel* listStoreBandPass = gtk_combo_box_get_model(comboBoxBandPass);
|
||||
gtk_list_store_clear(GTK_LIST_STORE(listStoreBandPass));
|
||||
|
||||
GtkComboBox* comboBoxNotch = GTK_COMBO_BOX(gtk_builder_get_object(m_builder,"combobox_select_notch_filter"));
|
||||
GtkTreeModel* listStoreNotch = gtk_combo_box_get_model(comboBoxNotch);
|
||||
gtk_list_store_clear(GTK_LIST_STORE(listStoreNotch));
|
||||
|
||||
if (m_comboBoxBandpassFilterIdx.size() > 0) m_comboBoxBandpassFilterIdx.clear();
|
||||
if (m_comboBoxNotchFilterIdx.size() > 0) m_comboBoxNotchFilterIdx.clear();
|
||||
if (m_comboBoxSensitivityValues.size() > 0) m_comboBoxSensitivityValues.clear();
|
||||
|
||||
// fill bandpass filter combobox with available filters
|
||||
gtk_list_store_append(GTK_LIST_STORE(listStoreBandPass), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(listStoreBandPass), &iter, 0, filterDesc.str().c_str(), -1);
|
||||
filterDesc.clear();
|
||||
filterDesc.str("");
|
||||
|
||||
m_comboBoxBandpassFilterIdx.push_back(-1);
|
||||
for (size_t i = 0; i < nBandPassFilters; ++i)
|
||||
{
|
||||
if (sampling == bandPassFilters[i].SamplingRate)
|
||||
{
|
||||
if (bandPassFilters[i].TypeId == 1) filterDesc << "Butterworth - ";
|
||||
if (bandPassFilters[i].TypeId == 2) filterDesc << "Chebyshev - ";
|
||||
|
||||
filterDesc << bandPassFilters[i].Order << " - [";
|
||||
filterDesc << bandPassFilters[i].LowerCutoffFrequency << "; ";
|
||||
filterDesc << bandPassFilters[i].UpperCutoffFrequency << "] - ";
|
||||
filterDesc << bandPassFilters[i].SamplingRate;
|
||||
gtk_list_store_append(GTK_LIST_STORE(listStoreBandPass), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(listStoreBandPass), &iter, 0, filterDesc.str().c_str(), -1);
|
||||
m_comboBoxBandpassFilterIdx.push_back(i);
|
||||
}
|
||||
filterDesc.clear();
|
||||
filterDesc.str("");
|
||||
}
|
||||
gtk_combo_box_set_active(comboBoxBandPass, m_bandpassFilterIdx + 1); // +1 because -1 is for "no filter".
|
||||
|
||||
// fill notch filter combobox with available fliters
|
||||
filterDesc << "no notch filter";
|
||||
gtk_list_store_append(GTK_LIST_STORE(listStoreNotch), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(listStoreNotch), &iter, 0, filterDesc.str().c_str(), -1);
|
||||
filterDesc.clear();
|
||||
filterDesc.str("");
|
||||
|
||||
m_comboBoxNotchFilterIdx.push_back(-1);
|
||||
for (size_t i = 0; i < nNotchFilters; ++i)
|
||||
{
|
||||
if (sampling == notchFilters[i].SamplingRate)
|
||||
{
|
||||
if (notchFilters[i].TypeId == 1) filterDesc << "Butterworth - ";
|
||||
if (notchFilters[i].TypeId == 2) filterDesc << "Chebyshev - ";
|
||||
|
||||
filterDesc << notchFilters[i].Order << " - [";
|
||||
filterDesc << notchFilters[i].LowerCutoffFrequency << "; ";
|
||||
filterDesc << notchFilters[i].UpperCutoffFrequency << "] - ";
|
||||
filterDesc << notchFilters[i].SamplingRate;
|
||||
gtk_list_store_append(GTK_LIST_STORE(listStoreNotch), &iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(listStoreNotch), &iter, 0, filterDesc.str().c_str(), -1);
|
||||
m_comboBoxNotchFilterIdx.push_back(i);
|
||||
}
|
||||
filterDesc.clear();
|
||||
filterDesc.str("");
|
||||
}
|
||||
gtk_combo_box_set_active(comboBoxNotch, m_notchFilterIdx + 1); // +1 because -1 is for "no filter".
|
||||
|
||||
delete [] bandPassFilters;
|
||||
delete [] notchFilters;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// If you added more reference attribute, initialize them here
|
||||
CConfigurationgNautilusInterface::CConfigurationgNautilusInterface(IDriverContext& ctx, const char* gtkBuilderFilename, std::string& deviceSerial,
|
||||
int& inputSource, uint32_t& networkChannel, int& bandpassFilterIdx, int& notchFilterIdx,
|
||||
double& sensitivity, bool& digitalInputEnabled, bool& noiseReductionEnabled,
|
||||
bool& carEnabled, bool& accelerationDataEnabled, bool& counterEnabled,
|
||||
bool& linkQualityEnabled, bool& batteryLevelEnabled, bool& validationIndicatorEnabled,
|
||||
std::vector<uint16_t>& selectedChannels, std::vector<int>& bipolarChannels,
|
||||
std::vector<bool>& cars, std::vector<bool>& noiseReduction)
|
||||
: CConfigurationBuilder(gtkBuilderFilename), m_driverCtx(ctx), m_deviceSerial(deviceSerial), m_inputSource(inputSource), m_networkChannel(networkChannel),
|
||||
m_bandpassFilterIdx(bandpassFilterIdx), m_notchFilterIdx(notchFilterIdx), m_sensitivity(sensitivity), m_digitalInputEnabled(digitalInputEnabled),
|
||||
m_noiseReductionEnabled(noiseReductionEnabled), m_carEnabled(carEnabled), m_accelerationDataEnabled(accelerationDataEnabled),
|
||||
m_counterEnabled(counterEnabled), m_linkQualityEnabled(linkQualityEnabled), m_batteryLevelEnabled(batteryLevelEnabled),
|
||||
m_validationIndicatorEnabled(validationIndicatorEnabled), m_selectedChannels(selectedChannels), m_bipolarChannels(bipolarChannels), m_cars(cars),
|
||||
m_noiseReduction(noiseReduction) { m_connectionOpen = false; }
|
||||
|
||||
bool CConfigurationgNautilusInterface::preConfigure()
|
||||
{
|
||||
if (! CConfigurationBuilder::preConfigure()) { return false; }
|
||||
|
||||
// Connect here all callbacks
|
||||
// Example:
|
||||
// g_signal_connect(gtk_builder_get_object(m_builder, "button_calibrate"), "pressed", G_CALLBACK(button_calibrate_pressed_cb), this);
|
||||
|
||||
// Insert here the pre-configure code.
|
||||
// For example, you may want to check if a device is currently connected
|
||||
// and if more than one are connected. Then you can list in a dedicated combo-box
|
||||
// the device currently connected so the user can choose which one he wants to acquire from.
|
||||
|
||||
bool functionReturn;
|
||||
|
||||
// open connection to device if not done yet before reading filters, channel names etc.
|
||||
if (!m_connectionOpen)
|
||||
{
|
||||
// open device handle and get connected device
|
||||
functionReturn = openDevice();
|
||||
if (!functionReturn) { return false; } // error logged in openDevice;
|
||||
}
|
||||
|
||||
// get settings for connected hardware
|
||||
functionReturn = getHardwareSettings();
|
||||
if (!functionReturn) { return false; }
|
||||
// error logged in getHardwareSettings
|
||||
|
||||
// get available channels
|
||||
functionReturn = getAvailableChannels();
|
||||
if (!functionReturn) { return false; } // error logged in getAvailableChannels
|
||||
|
||||
functionReturn = getChannelNames();
|
||||
if (!functionReturn) { return false; } // error logged in getChannelNames
|
||||
|
||||
// activate checkboxes in g.Nautilus Configuration dialog
|
||||
GtkCheckButton* buttonEventChannel = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder, "checkbutton_event_channel"));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(buttonEventChannel), m_digitalInputEnabled);
|
||||
|
||||
GtkCheckButton* buttonNoiseReduction = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder, "checkbutton_noise_reduction"));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(buttonNoiseReduction), m_noiseReductionEnabled);
|
||||
|
||||
GtkCheckButton* buttonCAR = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder, "checkbutton_car"));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(buttonCAR), m_carEnabled);
|
||||
|
||||
// activate/deactivate channel, noise reduction and CAR checkboxes in dialog_select_channels_bipolar_car_noise
|
||||
// as well as bipolar combo boxes according to available channels
|
||||
const gboolean noiseReduction = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttonNoiseReduction));
|
||||
const gboolean car = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(buttonCAR));
|
||||
char tmp[45];
|
||||
for (uint16_t i = 0; i < GDS_GNAUTILUS_CHANNELS_MAX; ++i)
|
||||
{
|
||||
sprintf_s(&tmp[0], 45, "checkbutton_channel_%d", (i + 1));
|
||||
GtkCheckButton* button = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,tmp));
|
||||
if ((button) && (m_availableChannels[i])) gtk_widget_set_sensitive(GTK_WIDGET(button), true);
|
||||
else if (button) gtk_widget_set_sensitive(GTK_WIDGET(button), false);
|
||||
|
||||
sprintf_s(&tmp[0], 45, "checkbutton_noise_channel_%d", (i + 1));
|
||||
button = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,tmp));
|
||||
if ((button) && (m_availableChannels[i])) gtk_widget_set_sensitive(GTK_WIDGET(button), noiseReduction);
|
||||
else if (button) gtk_widget_set_sensitive(GTK_WIDGET(button), false);
|
||||
|
||||
sprintf_s(&tmp[0], 45, "checkbutton_car_channel_%d", (i + 1));
|
||||
button = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,tmp));
|
||||
if ((button) && (m_availableChannels[i])) gtk_widget_set_sensitive(GTK_WIDGET(button), car);
|
||||
else if (button) gtk_widget_set_sensitive(GTK_WIDGET(button), false);
|
||||
|
||||
sprintf_s(&tmp[0], 45, "combobox_channel_%d", (i + 1));
|
||||
GtkComboBox* comboBox = GTK_COMBO_BOX(gtk_builder_get_object(m_builder,tmp));
|
||||
if ((comboBox) && (m_availableChannels[i])) gtk_widget_set_sensitive(GTK_WIDGET(comboBox), true);
|
||||
else if (comboBox) gtk_widget_set_sensitive(GTK_WIDGET(comboBox), false);
|
||||
}
|
||||
|
||||
GtkCheckButton* accelerationData = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder, "checkbutton_acceleration_data"));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(accelerationData), m_accelerationDataEnabled);
|
||||
|
||||
GtkCheckButton* counter = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder, "checkbutton_counter"));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(counter), m_counterEnabled);
|
||||
|
||||
GtkCheckButton* linkQuality = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder, "checkbutton_link_quality"));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linkQuality), m_linkQualityEnabled);
|
||||
|
||||
GtkCheckButton* batteryLevel = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder, "checkbutton_battery_level"));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(batteryLevel), m_batteryLevelEnabled);
|
||||
|
||||
GtkCheckButton* validationIndicator = GTK_CHECK_BUTTON(
|
||||
gtk_builder_get_object(m_builder, "checkbutton_validation_indicator"));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(validationIndicator), m_validationIndicatorEnabled);
|
||||
|
||||
g_signal_connect(gtk_builder_get_object(m_builder,"button_select_channels_bipolar_car_noise"), "pressed", G_CALLBACK(ChannelSettingsCB), this);
|
||||
g_signal_connect(gtk_builder_get_object(m_builder,"button_select_sensitivity_filters"), "pressed", G_CALLBACK(SensitivityFiltersCB), this);
|
||||
|
||||
g_signal_connect(gtk_builder_get_object(m_builder,"button_select_sensitivity_filters_apply"), "pressed", G_CALLBACK(SensitivityFiltersApplyCB), this);
|
||||
g_signal_connect(gtk_builder_get_object(m_builder,"button_channel_apply"), "pressed", G_CALLBACK(ChannelSettingsApplyCB), this);
|
||||
|
||||
// set device serial in device serial text entry in g.Nautilus Configuration dialog
|
||||
GtkEntry* deviceSerial = GTK_ENTRY(gtk_builder_get_object(m_builder, "entry_device_serial"));
|
||||
gtk_entry_set_text(deviceSerial, m_deviceSerial.c_str());
|
||||
gtk_entry_set_editable(deviceSerial, false);
|
||||
|
||||
// deactivate buttons if no device is detected
|
||||
if (gtk_entry_get_text_length(deviceSerial) < 13)
|
||||
{
|
||||
GtkWidget* button = GTK_WIDGET(gtk_builder_get_object(m_builder,"button_select_channels_bipolar_car_noise"));
|
||||
gtk_widget_set_sensitive(button, false);
|
||||
|
||||
button = GTK_WIDGET(gtk_builder_get_object(m_builder,"button_select_sensitivity_filters"));
|
||||
gtk_widget_set_sensitive(button, false);
|
||||
}
|
||||
|
||||
// catch event when sample rate is changed to adjust available filters
|
||||
g_signal_connect(gtk_builder_get_object(m_builder, "combobox_sampling_frequency"), "changed", G_CALLBACK(sample_rate_changed_cb), this);
|
||||
|
||||
// catch events when car and noise reduction checkboxes are toggled in main config dialog to enable/disable corresponding checkboxes in related dialog
|
||||
g_signal_connect(gtk_builder_get_object(m_builder, "checkbutton_noise_reduction"), "toggled", G_CALLBACK(noise_reduction_changed_cb), this);
|
||||
g_signal_connect(gtk_builder_get_object(m_builder, "checkbutton_car"), "toggled", G_CALLBACK(car_changed_cb), this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConfigurationgNautilusInterface::postConfigure()
|
||||
{
|
||||
if (m_applyConfig)
|
||||
{
|
||||
// If the user pressed the "apply" button, you need to save the changes made in the configuration.
|
||||
// For example, you can save the connection ID of the selected device:
|
||||
// m_connectionID = <value-from-gtk-widget>
|
||||
GtkCheckButton* checkButton;
|
||||
uint16_t i;
|
||||
gboolean buttonValue = false;
|
||||
gdouble nChannels = 0;
|
||||
|
||||
// get serial number from configuration dialog
|
||||
GtkEntry* entrySerial = GTK_ENTRY(gtk_builder_get_object(m_builder, "entry_device_serial"));
|
||||
m_deviceSerial = gtk_entry_get_text(entrySerial);
|
||||
|
||||
// get selected input source from dialog
|
||||
GtkComboBox* inputSources = GTK_COMBO_BOX(gtk_builder_get_object(m_builder, "combobox_input_source"));
|
||||
size_t idx = gtk_combo_box_get_active(inputSources);
|
||||
m_inputSource = m_comboBoxInputSources[idx];
|
||||
|
||||
// get selected channels
|
||||
char tmp[45];
|
||||
m_selectedChannels.clear();
|
||||
for (i = 0; i < GDS_GNAUTILUS_CHANNELS_MAX; ++i)
|
||||
{
|
||||
sprintf_s(&tmp[0], 45, "checkbutton_channel_%d", (i + 1));
|
||||
checkButton = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,tmp));
|
||||
if (checkButton)
|
||||
{
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkButton)))
|
||||
{
|
||||
m_selectedChannels.push_back(i + 1);
|
||||
nChannels += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_selectedChannels.push_back(0);
|
||||
m_channelNames.erase(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get bipolar channels
|
||||
m_bipolarChannels.clear();
|
||||
for (i = 0; i < GDS_GNAUTILUS_CHANNELS_MAX; ++i)
|
||||
{
|
||||
sprintf_s(&tmp[0], 45, "combobox_channel_%d", (i + 1));
|
||||
GtkComboBox* bipolarChannels = GTK_COMBO_BOX(gtk_builder_get_object(m_builder,tmp));
|
||||
if (bipolarChannels)
|
||||
{
|
||||
// bipolar is 0 based for the channels, -1 indicates no bipolar derivation
|
||||
m_bipolarChannels.push_back(gtk_combo_box_get_active(bipolarChannels) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// set bandpass and notch filter indices to correponding variables
|
||||
GtkComboBox* bandpassFilters = GTK_COMBO_BOX(gtk_builder_get_object(m_builder,"combobox_select_bandpass_filter"));
|
||||
idx = gtk_combo_box_get_active(bandpassFilters);
|
||||
m_bandpassFilterIdx = m_comboBoxBandpassFilterIdx.at(idx);
|
||||
|
||||
GtkComboBox* notchFilters = GTK_COMBO_BOX(gtk_builder_get_object(m_builder,"combobox_select_notch_filter"));
|
||||
idx = gtk_combo_box_get_active(notchFilters);
|
||||
m_notchFilterIdx = m_comboBoxNotchFilterIdx.at(idx);
|
||||
|
||||
// sensitivity
|
||||
GtkComboBox* sensitivities = GTK_COMBO_BOX(gtk_builder_get_object(m_builder,"combobox_select_sensitivity"));
|
||||
idx = gtk_combo_box_get_active(sensitivities);
|
||||
m_sensitivity = m_comboBoxSensitivityValues.at(idx);
|
||||
|
||||
// digital inputs
|
||||
checkButton = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,"checkbutton_event_channel"));
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkButton)) == 1) { m_digitalInputEnabled = true; }
|
||||
else { m_digitalInputEnabled = false; }
|
||||
|
||||
// noise reduction
|
||||
checkButton = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,"checkbutton_noise_reduction"));
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkButton)) == 1) { m_noiseReductionEnabled = true; }
|
||||
else { m_noiseReductionEnabled = false; }
|
||||
|
||||
// if noise reduction is active, check for which channels noise reduction is enabled
|
||||
m_noiseReduction.clear();
|
||||
for (i = 0; i < GDS_GNAUTILUS_CHANNELS_MAX; ++i)
|
||||
{
|
||||
sprintf_s(&tmp[0], 45, "checkbutton_noise_channel_%d", (i + 1));
|
||||
checkButton = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,tmp));
|
||||
if (checkButton)
|
||||
{
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkButton)) == 1) { m_noiseReduction.push_back(true); }
|
||||
else { m_noiseReduction.push_back(false); }
|
||||
}
|
||||
}
|
||||
|
||||
// CAR
|
||||
checkButton = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,"checkbutton_car"));
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkButton)) == 1) m_carEnabled = true;
|
||||
else m_carEnabled = false;
|
||||
|
||||
// if CAR is active, check for which channels CAR is enabled
|
||||
m_cars.clear();
|
||||
for (i = 0; i < GDS_GNAUTILUS_CHANNELS_MAX; ++i)
|
||||
{
|
||||
sprintf_s(&tmp[0], 45, "checkbutton_car_channel_%d", (i + 1));
|
||||
checkButton = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,tmp));
|
||||
if (checkButton)
|
||||
{
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkButton)) == 1) m_cars.push_back(true);
|
||||
else m_cars.push_back(false);
|
||||
}
|
||||
}
|
||||
|
||||
// acceleration data
|
||||
checkButton = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,"checkbutton_acceleration_data"));
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkButton)) == 1) { m_accelerationDataEnabled = true; }
|
||||
else { m_accelerationDataEnabled = false; }
|
||||
|
||||
// counter
|
||||
checkButton = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,"checkbutton_counter"));
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkButton)) == 1) { m_counterEnabled = true; }
|
||||
else { m_counterEnabled = false; }
|
||||
|
||||
// link quality
|
||||
checkButton = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,"checkbutton_link_quality"));
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkButton)) == 1) { m_linkQualityEnabled = true; }
|
||||
else { m_linkQualityEnabled = false; }
|
||||
|
||||
// battery level
|
||||
checkButton = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,"checkbutton_battery_level"));
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkButton)) == 1) { m_batteryLevelEnabled = true; }
|
||||
else { m_batteryLevelEnabled = false; }
|
||||
|
||||
// validation indicator
|
||||
checkButton = GTK_CHECK_BUTTON(gtk_builder_get_object(m_builder,"checkbutton_validation_indicator"));
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkButton)) == 1) { m_validationIndicatorEnabled = true; }
|
||||
else { m_validationIndicatorEnabled = false; }
|
||||
|
||||
// network channel
|
||||
GtkComboBox* comboBoxNetworkChannel = GTK_COMBO_BOX(gtk_builder_get_object(m_builder,"combobox_network_channel"));
|
||||
const char* networkChannel = gtk_combo_box_get_active_text(comboBoxNetworkChannel);
|
||||
m_networkChannel = uint32_t(atoi(networkChannel));
|
||||
|
||||
// set number of channels in main configuration dialog (spinbutton still remains disabled, user cannot change value there)
|
||||
GtkSpinButton* buttonChannels = GTK_SPIN_BUTTON(gtk_builder_get_object(m_builder, "spinbutton_number_of_channels"));
|
||||
gtk_spin_button_set_value(buttonChannels, nChannels);
|
||||
gtk_spin_button_set_range(buttonChannels, nChannels, nChannels);
|
||||
}
|
||||
if (m_connectionOpen)
|
||||
{
|
||||
// close connection handle
|
||||
const bool functionReturn = closeDevice();
|
||||
if (!functionReturn)
|
||||
{
|
||||
// error logged in closeDevice
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (! CConfigurationBuilder::postConfigure()
|
||||
) { return false; } // normal header is filled (Subject ID, Age, Gender, channels, sampling frequency), ressources are realesed
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConfigurationgNautilusInterface::openDevice()
|
||||
{
|
||||
GDS_ENDPOINT hostEp, localEp;
|
||||
GDS_DEVICE_CONNECTION_INFO* connectedDevicesInfo;
|
||||
size_t nDevices;
|
||||
std::string deviceSerial;
|
||||
BOOL openExclusively = true;
|
||||
BOOL isCreator;
|
||||
m_deviceNames = new char[1][DEVICE_NAME_LENGTH_MAX];
|
||||
|
||||
uint8_t byteIP[4];
|
||||
byteIP[0] = 1;
|
||||
byteIP[1] = 0;
|
||||
byteIP[2] = 0;
|
||||
byteIP[3] = 127;
|
||||
char tmpIP[16];
|
||||
|
||||
_snprintf_s(tmpIP, IP_ADDRESS_LENGTH_MAX, "%d.%d.%d.%d", byteIP[3], byteIP[2], byteIP[1], byteIP[0]);
|
||||
|
||||
for (size_t i = 0; i < IP_ADDRESS_LENGTH_MAX; ++i)
|
||||
{
|
||||
hostEp.IpAddress[i] = tmpIP[i];
|
||||
localEp.IpAddress[i] = tmpIP[i];
|
||||
}
|
||||
|
||||
hostEp.Port = 50223;
|
||||
localEp.Port = 50224;
|
||||
|
||||
// get connected device
|
||||
m_gdsResult = GDS_GetConnectedDevices(hostEp, localEp, &connectedDevicesInfo, &nDevices);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nDevices; ++i)
|
||||
{
|
||||
// if devices are in use they cannot be used for a new acquisition
|
||||
if ((connectedDevicesInfo[i].InUse) && (i < nDevices)) continue;
|
||||
// only one device can be used for data acquisition, as g.Nautilus cannot be synchronized
|
||||
if ((connectedDevicesInfo[i].InUse) && (connectedDevicesInfo[i].ConnectedDevicesLength > 1)) continue;
|
||||
GDS_DEVICE_INFO* deviceInfo = connectedDevicesInfo[i].ConnectedDevices;
|
||||
if (deviceInfo[0].DeviceType == GDS_DEVICE_TYPE_GNAUTILUS)
|
||||
{
|
||||
deviceSerial = deviceInfo[0].Name;
|
||||
nDevices = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nDevices == 0)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << "No g.Nautilus connected\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
strncpy_s(m_deviceNames[0], deviceSerial.c_str(), DEVICE_NAME_LENGTH_MAX);
|
||||
m_deviceSerial = deviceSerial;
|
||||
|
||||
// connect to device
|
||||
m_gdsResult = GDS_Connect(hostEp, localEp, m_deviceNames, nDevices, openExclusively, &m_deviceHandle, &isCreator);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// free connected devices list allocated by GDS_GetConnectedDevices
|
||||
m_gdsResult = GDS_FreeConnectedDevicesList(&connectedDevicesInfo, nDevices);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_connectionOpen = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConfigurationgNautilusInterface::closeDevice()
|
||||
{
|
||||
// disconnect device
|
||||
m_gdsResult = GDS_Disconnect(&m_deviceHandle);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_connectionOpen = false;
|
||||
delete [] m_deviceNames;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace AcquisitionServer
|
||||
} // namespace OpenViBE
|
||||
#endif // TARGET_HAS_ThirdPartyGNEEDaccessAPI
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(TARGET_HAS_ThirdPartyGNEEDaccessAPI)
|
||||
|
||||
#include "../ovasCConfigurationBuilder.h"
|
||||
#include "ovasIDriver.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <GDSClientAPI.h>
|
||||
#include <GDSClientAPI_gNautilus.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AcquisitionServer {
|
||||
/**
|
||||
* \class CConfigurationgNautilusInterface
|
||||
* \author g.tec medical engineering GmbH (g.tec medical engineering GmbH)
|
||||
* \date Wed Aug 12 16:37:18 2015
|
||||
* \brief The CConfigurationgNautilusInterface handles the configuration dialog specific to the g.NEEDaccess device.
|
||||
*
|
||||
* TODO: details
|
||||
*
|
||||
* \sa CDrivergNautilusInterface
|
||||
*/
|
||||
class CConfigurationgNautilusInterface final : public CConfigurationBuilder
|
||||
{
|
||||
public:
|
||||
|
||||
// you may have to add to your constructor some reference parameters
|
||||
// for example, a connection ID:
|
||||
//CConfigurationgNautilusInterface(IDriverContext& ctx, const char* gtkBuilderFilename, uint32_t& rConnectionId);
|
||||
CConfigurationgNautilusInterface(IDriverContext& ctx, const char* gtkBuilderFilename, std::string& deviceSerial, int& inputSource, uint32_t& networkChannel,
|
||||
int& bandpassFilterIdx, int& notchFilterIdx, double& sensitivity, bool& digitalInputEnabled, bool& noiseReductionEnabled,
|
||||
bool& carEnabled, bool& accelerationDataEnabled, bool& counterEnabled, bool& linkQualityEnabled, bool& batteryLevelEnabled,
|
||||
bool& validationIndicatorEnabled, std::vector<uint16_t>& selectedChannels, std::vector<int>& bipolarChannels,
|
||||
std::vector<bool>& cars, std::vector<bool>& noiseReduction);
|
||||
|
||||
bool preConfigure() override;
|
||||
bool postConfigure() override;
|
||||
|
||||
//button callback functions
|
||||
void buttonChannelSettingsPressedCB();
|
||||
void buttonChannelSettingsApplyPressedCB();
|
||||
void buttonSensitivityFiltersPressedCB();
|
||||
void buttonSensitivityFiltersApplyPressedCB();
|
||||
bool getHardwareSettings();
|
||||
bool getChannelNames();
|
||||
bool getAvailableChannels();
|
||||
bool getFiltersForNewSamplingRate();
|
||||
void comboboxSampleRateChangedCB();
|
||||
void checkbuttonNoiseReductionChangedCB();
|
||||
void checkbuttonCARChangedCB();
|
||||
|
||||
protected:
|
||||
|
||||
IDriverContext& m_driverCtx;
|
||||
std::string& m_deviceSerial;
|
||||
int& m_inputSource;
|
||||
uint32_t& m_networkChannel;
|
||||
int& m_bandpassFilterIdx;
|
||||
int& m_notchFilterIdx;
|
||||
double& m_sensitivity;
|
||||
bool& m_digitalInputEnabled;
|
||||
bool& m_noiseReductionEnabled;
|
||||
bool& m_carEnabled;
|
||||
bool& m_accelerationDataEnabled;
|
||||
bool& m_counterEnabled;
|
||||
bool& m_linkQualityEnabled;
|
||||
bool& m_batteryLevelEnabled;
|
||||
bool& m_validationIndicatorEnabled;
|
||||
std::vector<uint16_t>& m_selectedChannels;
|
||||
std::vector<int>& m_bipolarChannels;
|
||||
std::vector<bool>& m_cars;
|
||||
std::vector<bool>& m_noiseReduction;
|
||||
std::vector<int> m_comboBoxBandpassFilterIdx;
|
||||
std::vector<int> m_comboBoxNotchFilterIdx;
|
||||
std::vector<double> m_comboBoxSensitivityValues;
|
||||
std::vector<int> m_comboBoxInputSources;
|
||||
std::vector<size_t> m_comboBoxNetworkChannels;
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
* Insert here all specific attributes, such as a connection ID.
|
||||
* use references to directly modify the corresponding attribute of the driver
|
||||
* Example:
|
||||
*/
|
||||
// uint32_t& m_connectionID;
|
||||
bool openDevice();
|
||||
bool closeDevice();
|
||||
GDS_HANDLE m_deviceHandle;
|
||||
GDS_RESULT m_gdsResult;
|
||||
std::vector<bool> m_availableChannels;
|
||||
char (*m_deviceNames)[DEVICE_NAME_LENGTH_MAX];
|
||||
bool m_connectionOpen = false;
|
||||
};
|
||||
} // namespace AcquisitionServer
|
||||
} // namespace OpenViBE
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyGNEEDaccessAPI
|
||||
+462
@@ -0,0 +1,462 @@
|
||||
#if defined(TARGET_HAS_ThirdPartyGNEEDaccessAPI)
|
||||
|
||||
#include "ovasCDrivergNautilusInterface.h"
|
||||
#include "ovasCConfigurationgNautilusInterface.h"
|
||||
|
||||
#include <toolkit/ovtk_all.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AcquisitionServer {
|
||||
|
||||
// global functions, event handles and variables
|
||||
void OnDataReadyEventHandler(GDS_HANDLE handle, void* data);
|
||||
HANDLE dataReadyEventHandle;
|
||||
|
||||
CDrivergNautilusInterface::CDrivergNautilusInterface(IDriverContext& ctx)
|
||||
: IDriver(ctx), m_settings("AcquisitionServer_Driver_gNautilusInterface", m_driverCtx.getConfigurationManager()), m_Device(NULL)
|
||||
{
|
||||
m_header.setSamplingFrequency(250);
|
||||
m_header.setChannelCount(32);
|
||||
|
||||
// The following class allows saving and loading driver settings from the acquisition server .conf file
|
||||
m_settings.add("Header", &m_header);
|
||||
// To save your custom driver settings, register each variable to the SettingsHelper
|
||||
//m_settings.add("SettingName", &variable);
|
||||
m_settings.add("DeviceIndex", &m_deviceIdx);
|
||||
m_settings.add("InputSource", &m_inputSource);
|
||||
m_settings.add("NetworkChannel", &m_networkChannel);
|
||||
m_settings.add("Sensitivity", &m_sensitivity);
|
||||
m_settings.add("NotchFilterIndex", &m_notchFilterIdx);
|
||||
m_settings.add("BandPassFilterIndex", &m_bandPassFilterIdx);
|
||||
m_settings.add("DigitalInputEnabled", &m_digitalInputEnabled);
|
||||
m_settings.add("NoiseReductionEnabled", &m_noiseReductionEnabled);
|
||||
m_settings.add("CAREnabled", &m_carEnabled);
|
||||
m_settings.add("AccelerationEnabled", &m_accelerationDataEnabled);
|
||||
m_settings.add("CounterEnabled", &m_counterEnabled);
|
||||
m_settings.add("LinqQualityEnabled", &m_linkQualityEnabled);
|
||||
m_settings.add("BatteryLevelEnabled", &m_batteryLevelEnabled);
|
||||
m_settings.add("ValidationIndicatorEnabled", &m_validationIndicatorEnabled);
|
||||
|
||||
m_settings.load();
|
||||
}
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
bool CDrivergNautilusInterface::initialize(const uint32_t nSamplePerSentBlock, IDriverCallback& callback)
|
||||
{
|
||||
if (m_driverCtx.isConnected() || !m_header.isChannelCountSet() || !m_header.isSamplingFrequencySet()) { return false; }
|
||||
|
||||
if (nSamplePerSentBlock > 250)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << "Sample count per sent block cannot be higher than 250 samples for g.Nautilus\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// initialize basic GDS functions before the first GDS function itself is called
|
||||
GDS_Initialize();
|
||||
|
||||
// get number of channels actually acquired
|
||||
m_nAcquiredChannel = 0;
|
||||
for (size_t i = 0; i < GDS_GNAUTILUS_CHANNELS_MAX; ++i)
|
||||
{
|
||||
if (find(m_selectedChannels.begin(), m_selectedChannels.end(), (i + 1)) != m_selectedChannels.end())
|
||||
{
|
||||
m_header.setChannelUnits(m_nAcquiredChannel, OVTK_UNIT_Volts, OVTK_FACTOR_Micro);
|
||||
m_nAcquiredChannel += 1;
|
||||
}
|
||||
}
|
||||
|
||||
m_header.setChannelCount(m_nAcquiredChannel);
|
||||
|
||||
// g.Nautilus provides some extra channel, add them to the channels count
|
||||
// and provide corresponding names
|
||||
uint32_t nAcquiredChannel = m_nAcquiredChannel;
|
||||
if (m_accelerationDataEnabled)
|
||||
{
|
||||
m_header.setChannelCount(nAcquiredChannel + 3);
|
||||
m_header.setChannelName(nAcquiredChannel, "CH_Accel_x");
|
||||
m_header.setChannelName(nAcquiredChannel + 1, "CH_Accel_y");
|
||||
m_header.setChannelName(nAcquiredChannel + 2, "CH_Accel_z");
|
||||
m_header.setChannelUnits(nAcquiredChannel, OVTK_UNIT_Meter_Per_Second_Squared, OVTK_FACTOR_Base);
|
||||
m_header.setChannelUnits(nAcquiredChannel + 1, OVTK_UNIT_Meter_Per_Second_Squared, OVTK_FACTOR_Base);
|
||||
m_header.setChannelUnits(nAcquiredChannel + 2, OVTK_UNIT_Meter_Per_Second_Squared, OVTK_FACTOR_Base);
|
||||
nAcquiredChannel = m_header.getChannelCount();
|
||||
}
|
||||
if (m_counterEnabled)
|
||||
{
|
||||
m_header.setChannelCount(nAcquiredChannel + 1);
|
||||
m_header.setChannelName(nAcquiredChannel, "CH_Counter");
|
||||
m_header.setChannelUnits(nAcquiredChannel,OVTK_UNIT_Dimensionless,OVTK_FACTOR_Base);
|
||||
nAcquiredChannel = m_header.getChannelCount();
|
||||
}
|
||||
if (m_linkQualityEnabled)
|
||||
{
|
||||
m_header.setChannelCount(nAcquiredChannel + 1);
|
||||
m_header.setChannelName(nAcquiredChannel, "CH_LQ");
|
||||
m_header.setChannelUnits(nAcquiredChannel,OVTK_UNIT_10_2_Percent,OVTK_FACTOR_Base);
|
||||
nAcquiredChannel = m_header.getChannelCount();
|
||||
}
|
||||
if (m_batteryLevelEnabled)
|
||||
{
|
||||
m_header.setChannelCount(nAcquiredChannel + 1);
|
||||
m_header.setChannelName(nAcquiredChannel, "CH_Battery");
|
||||
m_header.setChannelUnits(nAcquiredChannel,OVTK_UNIT_10_2_Percent,OVTK_FACTOR_Base);
|
||||
nAcquiredChannel = m_header.getChannelCount();
|
||||
}
|
||||
if (m_digitalInputEnabled)
|
||||
{
|
||||
m_header.setChannelCount(nAcquiredChannel + 1);
|
||||
m_header.setChannelName(nAcquiredChannel, "CH_Event");
|
||||
m_header.setChannelUnits(nAcquiredChannel,OVTK_UNIT_Dimensionless,OVTK_FACTOR_Base);
|
||||
nAcquiredChannel = m_header.getChannelCount();
|
||||
}
|
||||
if (m_validationIndicatorEnabled)
|
||||
{
|
||||
m_header.setChannelCount(nAcquiredChannel + 1);
|
||||
m_header.setChannelName(nAcquiredChannel, "CH_Valid");
|
||||
m_header.setChannelUnits(nAcquiredChannel,OVTK_UNIT_Dimensionless,OVTK_FACTOR_Base);
|
||||
nAcquiredChannel = m_header.getChannelCount();
|
||||
}
|
||||
|
||||
// initialize connection and open connection handle and get serial of connected g.Nautilus
|
||||
GDS_DEVICE_CONNECTION_INFO* devicesInfo;
|
||||
size_t nDevices = 0;
|
||||
GDS_ENDPOINT hostEp;
|
||||
GDS_ENDPOINT localEp;
|
||||
uint8_t byteIP[4];
|
||||
char tempIP[16];
|
||||
|
||||
byteIP[0] = 1;
|
||||
byteIP[1] = 0;
|
||||
byteIP[2] = 0;
|
||||
byteIP[3] = 127;
|
||||
|
||||
_snprintf_s(tempIP, IP_ADDRESS_LENGTH_MAX, "%d.%d.%d.%d", byteIP[3], byteIP[2], byteIP[1], byteIP[0]);
|
||||
|
||||
for (size_t i = 0; i < IP_ADDRESS_LENGTH_MAX; ++i)
|
||||
{
|
||||
hostEp.IpAddress[i] = tempIP[i];
|
||||
localEp.IpAddress[i] = tempIP[i];
|
||||
}
|
||||
|
||||
hostEp.Port = 50223;
|
||||
localEp.Port = 50224;
|
||||
|
||||
bool found = false;
|
||||
m_gdsResult = GDS_GetConnectedDevices(hostEp, localEp, &devicesInfo, &nDevices);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < nDevices; ++i)
|
||||
{
|
||||
// if devices are in use they cannot be used for a new acquisition
|
||||
if ((devicesInfo[i].InUse) && (i < nDevices)) { continue; }
|
||||
// only one device can be used for data acquisition, as g.Nautilus cannot be synchronized
|
||||
if ((devicesInfo[i].InUse) && (devicesInfo[i].ConnectedDevicesLength > 1)) { continue; }
|
||||
GDS_DEVICE_INFO* info = devicesInfo[i].ConnectedDevices;
|
||||
if (info[0].DeviceType == GDS_DEVICE_TYPE_GNAUTILUS)
|
||||
{
|
||||
// check if device used for configuration is still available
|
||||
if (!strcmp(info[0].Name, m_deviceSerial.c_str()))
|
||||
{
|
||||
m_nDevice = 1;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found == false)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << "No g.Nautilus device found\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
char (*names)[DEVICE_NAME_LENGTH_MAX] = new char[1][DEVICE_NAME_LENGTH_MAX];
|
||||
bool openExclusively = true;
|
||||
BOOL isCreator;
|
||||
|
||||
strncpy_s(names[0], m_deviceSerial.c_str(), DEVICE_NAME_LENGTH_MAX);
|
||||
|
||||
// connect to device
|
||||
m_gdsResult = GDS_Connect(hostEp, localEp, names, m_nDevice, openExclusively, &m_Device, &isCreator);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Info << "Connected to device : " << m_deviceSerial << "\n";
|
||||
|
||||
m_deviceCfg.SamplingRate = m_header.getSamplingFrequency();
|
||||
m_deviceCfg.NumberOfScans = nSamplePerSentBlock;
|
||||
m_deviceCfg.NetworkChannel = m_networkChannel;
|
||||
m_deviceCfg.AccelerationData = m_accelerationDataEnabled;
|
||||
m_deviceCfg.BatteryLevel = m_batteryLevelEnabled;
|
||||
m_deviceCfg.CAR = m_carEnabled;
|
||||
m_deviceCfg.Counter = m_counterEnabled;
|
||||
m_deviceCfg.DigitalIOs = m_digitalInputEnabled;
|
||||
m_deviceCfg.LinkQualityInformation = m_linkQualityEnabled;
|
||||
m_deviceCfg.NoiseReduction = m_noiseReductionEnabled;
|
||||
m_deviceCfg.Slave = 0;
|
||||
m_deviceCfg.ValidationIndicator = m_validationIndicatorEnabled;
|
||||
m_deviceCfg.InputSignal = GDS_GNAUTILUS_INPUT_SIGNAL(m_inputSource);
|
||||
|
||||
for (size_t i = 0; i < GDS_GNAUTILUS_CHANNELS_MAX; ++i)
|
||||
{
|
||||
if (find(m_selectedChannels.begin(), m_selectedChannels.end(), (i + 1)) != m_selectedChannels.end()) { m_deviceCfg.Channels[i].Enabled = true; }
|
||||
else { m_deviceCfg.Channels[i].Enabled = false; }
|
||||
m_deviceCfg.Channels[i].Sensitivity = m_sensitivity;
|
||||
if (i < m_cars.size()) { m_deviceCfg.Channels[i].UsedForCar = m_cars[i]; }
|
||||
else { m_deviceCfg.Channels[i].UsedForCar = false; }
|
||||
if (i < m_noiseReduction.size()) { m_deviceCfg.Channels[i].UsedForNoiseReduction = m_noiseReduction[i]; }
|
||||
else { m_deviceCfg.Channels[i].UsedForNoiseReduction = false; }
|
||||
m_deviceCfg.Channels[i].BandpassFilterIndex = m_bandPassFilterIdx;
|
||||
m_deviceCfg.Channels[i].NotchFilterIndex = m_notchFilterIdx;
|
||||
if (i < m_bipolarChannels.size()) { m_deviceCfg.Channels[i].BipolarChannel = m_bipolarChannels[i]; }
|
||||
else { m_deviceCfg.Channels[i].BipolarChannel = false; }
|
||||
}
|
||||
|
||||
// Free memory allocated for list of connected devices by GDS_GetConnectedDevices
|
||||
m_gdsResult = GDS_FreeConnectedDevicesList(&devicesInfo, nDevices);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Builds up a buffer to store acquired samples. This buffer
|
||||
// will be sent to the acquisition server later...
|
||||
m_sample = new float[nAcquiredChannel * m_deviceCfg.NumberOfScans];
|
||||
if (!m_sample)
|
||||
{
|
||||
delete [] m_sample;
|
||||
m_sample = nullptr;
|
||||
return false;
|
||||
}
|
||||
// set up data buffer for gds getdata function
|
||||
m_Buffer = new float[nAcquiredChannel * m_deviceCfg.NumberOfScans];
|
||||
if (!m_Buffer)
|
||||
{
|
||||
delete [] m_Buffer;
|
||||
m_Buffer = nullptr;
|
||||
return false;
|
||||
}
|
||||
m_bufferSize = nAcquiredChannel * m_deviceCfg.NumberOfScans;
|
||||
|
||||
// Saves parameters
|
||||
m_callback = &callback;
|
||||
m_nSamplePerSentBlock = nSamplePerSentBlock;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDrivergNautilusInterface::start()
|
||||
{
|
||||
if (!m_driverCtx.isConnected() || m_driverCtx.isStarted()) { return false; }
|
||||
|
||||
// if no device was found return
|
||||
if (m_nDevice != 1) { return false; }
|
||||
|
||||
GDS_CONFIGURATION_BASE* config = new GDS_CONFIGURATION_BASE[m_nDevice];
|
||||
config[0].Configuration = &m_deviceCfg;
|
||||
config[0].DeviceInfo.DeviceType = GDS_DEVICE_TYPE_GNAUTILUS;
|
||||
strcpy_s(config[0].DeviceInfo.Name, m_deviceSerial.c_str());
|
||||
size_t nScan = 0;
|
||||
size_t channelsPerDevice = 0;
|
||||
size_t bufferSizeInSamples = 0;
|
||||
|
||||
// set device configuration
|
||||
m_gdsResult = GDS_SetConfiguration(m_Device, config, m_nDevice);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// initialize data ready event and set data ready event handle
|
||||
dataReadyEventHandle = nullptr;
|
||||
dataReadyEventHandle = CreateEvent(nullptr, false, false, nullptr);
|
||||
m_gdsResult = GDS_SetDataReadyCallback(m_Device, (GDS_Callback)OnDataReadyEventHandler, m_deviceCfg.NumberOfScans,NULL);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// set number of scans getdata function will return
|
||||
m_availableScans = m_deviceCfg.NumberOfScans;
|
||||
|
||||
// ...
|
||||
// request hardware to start
|
||||
// sending data
|
||||
// ...
|
||||
// start acquisition
|
||||
m_gdsResult = GDS_StartAcquisition(m_Device);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
// start data stream from server
|
||||
m_gdsResult = GDS_StartStreaming(m_Device);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_gdsResult = GDS_GetDataInfo(m_Device, &nScan, nullptr, &channelsPerDevice, &bufferSizeInSamples);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDrivergNautilusInterface::loop()
|
||||
{
|
||||
if (!m_driverCtx.isConnected() || !m_driverCtx.isStarted()) { return true; }
|
||||
|
||||
const CStimulationSet stimSet;
|
||||
|
||||
if (m_driverCtx.isStarted())
|
||||
{
|
||||
const DWORD ret = WaitForSingleObject(dataReadyEventHandle, 5000);
|
||||
if (ret == WAIT_TIMEOUT)
|
||||
{
|
||||
// if data ready event is not triggered in 5000ms add a timeout handler
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << "No data received in 5 seconds\n";
|
||||
return false;
|
||||
}
|
||||
// when data is ready call get data function with amount of scans to return
|
||||
m_gdsResult = GDS_GetData(m_Device, &m_availableScans, m_Buffer, m_bufferSize);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// put data from receiving buffer to application buffer
|
||||
for (size_t i = 0; i < m_header.getChannelCount(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < m_nSamplePerSentBlock; ++j) { m_sample[i * m_nSamplePerSentBlock + j] = m_Buffer[j * (m_header.getChannelCount()) + i]; }
|
||||
}
|
||||
}
|
||||
|
||||
// ...
|
||||
// receive samples from hardware
|
||||
// put them the correct way in the sample array
|
||||
// whether the buffer is full, send it to the acquisition server
|
||||
//...
|
||||
m_callback->setSamples(m_sample);
|
||||
|
||||
// When your sample buffer is fully loaded,
|
||||
// it is advised to ask the acquisition server
|
||||
// to correct any drift in the acquisition automatically.
|
||||
m_driverCtx.correctDriftSampleCount(m_driverCtx.getSuggestedDriftCorrectionSampleCount());
|
||||
|
||||
// ...
|
||||
// receive events from hardware
|
||||
// and put them the correct way in a CStimulationSet object
|
||||
//...
|
||||
m_callback->setStimulationSet(stimSet);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDrivergNautilusInterface::stop()
|
||||
{
|
||||
if (!m_driverCtx.isConnected()) return false;
|
||||
if (!m_driverCtx.isStarted()) return false;
|
||||
|
||||
// ...
|
||||
// request the hardware to stop
|
||||
// sending data
|
||||
// ...
|
||||
|
||||
|
||||
// stop streaming
|
||||
m_gdsResult = GDS_StopStreaming(m_Device);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// stop data acquisiton
|
||||
m_gdsResult = GDS_StopAcquisition(m_Device);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDrivergNautilusInterface::uninitialize()
|
||||
{
|
||||
if (!m_driverCtx.isConnected() || m_driverCtx.isStarted()) { return false; }
|
||||
|
||||
// ...
|
||||
// uninitialize hardware here
|
||||
// ...
|
||||
|
||||
m_gdsResult = GDS_Disconnect(&m_Device);
|
||||
if (m_gdsResult.ErrorCode != GDS_ERROR_SUCCESS)
|
||||
{
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Error << m_gdsResult.ErrorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
delete [] m_sample;
|
||||
m_sample = nullptr;
|
||||
m_callback = nullptr;
|
||||
|
||||
// uninitialize basic GDS functions after last GDS function is called
|
||||
GDS_Uninitialize();
|
||||
|
||||
m_driverCtx.getLogManager() << Kernel::LogLevel_Info << "Disconnected from device : " << m_deviceSerial << "\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
bool CDrivergNautilusInterface::isConfigurable()
|
||||
{
|
||||
return true; // change to false if your device is not configurable
|
||||
}
|
||||
|
||||
bool CDrivergNautilusInterface::configure()
|
||||
{
|
||||
// Change this line if you need to specify some references to your driver attribute that need configuration, e.g. the connection ID.
|
||||
CConfigurationgNautilusInterface config(m_driverCtx, Directories::getDataDir() + "/applications/acquisition-server/interface-gNautilusInterface.ui",
|
||||
m_deviceSerial, m_inputSource, m_networkChannel, m_bandPassFilterIdx, m_notchFilterIdx, m_sensitivity,
|
||||
m_digitalInputEnabled, m_noiseReductionEnabled, m_carEnabled, m_accelerationDataEnabled, m_counterEnabled,
|
||||
m_linkQualityEnabled, m_batteryLevelEnabled, m_validationIndicatorEnabled, m_selectedChannels, m_bipolarChannels,
|
||||
m_cars, m_noiseReduction);
|
||||
|
||||
if (!config.configure(m_header)) { return false; }
|
||||
m_settings.save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnDataReadyEventHandler(GDS_HANDLE handle, void* data)
|
||||
{
|
||||
// signals data is ready on GDS acquisition buffer
|
||||
if (!SetEvent(dataReadyEventHandle))
|
||||
{
|
||||
// insert error handling if necessary
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AcquisitionServer
|
||||
} // namespace OpenViBE
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyGNEEDaccessAPI
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(TARGET_HAS_ThirdPartyGNEEDaccessAPI)
|
||||
|
||||
#include "ovasIDriver.h"
|
||||
#include "../ovasCHeader.h"
|
||||
#include <openvibe/ov_all.h>
|
||||
|
||||
#include "../ovasCSettingsHelper.h"
|
||||
#include "../ovasCSettingsHelperOperators.h"
|
||||
|
||||
#include <GDSClientAPI.h>
|
||||
#include <GDSClientAPI_gNautilus.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <Windows.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AcquisitionServer {
|
||||
/**
|
||||
* \class CDrivergNautilusInterface
|
||||
* \author g.tec medical engineering GmbH (g.tec medical engineering GmbH)
|
||||
* \date Wed Aug 12 16:37:18 2015
|
||||
* \brief The CDrivergNautilusInterface allows the acquisition server to acquire data from a g.NEEDaccess device.
|
||||
*
|
||||
* TODO: details
|
||||
*
|
||||
* \sa CConfigurationgNautilusInterface
|
||||
*/
|
||||
class CDrivergNautilusInterface final : public IDriver
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CDrivergNautilusInterface(IDriverContext& ctx);
|
||||
~CDrivergNautilusInterface() override { }
|
||||
const char* getName() override { return "g.tec g.Nautilus using g.NEEDaccess"; }
|
||||
|
||||
bool initialize(const uint32_t nSamplePerSentBlock, IDriverCallback& callback) override;
|
||||
bool uninitialize() override;
|
||||
|
||||
bool start() override;
|
||||
bool stop() override;
|
||||
bool loop() override;
|
||||
|
||||
bool isConfigurable() override;
|
||||
bool configure() override;
|
||||
const IHeader* getHeader() override { return &m_header; }
|
||||
|
||||
bool isFlagSet(const EDriverFlag flag) const override { return flag == EDriverFlag::IsUnstable; }
|
||||
|
||||
protected:
|
||||
|
||||
SettingsHelper m_settings;
|
||||
|
||||
IDriverCallback* m_callback = nullptr;
|
||||
|
||||
// Replace this generic Header with any specific header you might have written
|
||||
CHeader m_header;
|
||||
|
||||
uint32_t m_nSamplePerSentBlock = 4;
|
||||
float* m_sample = nullptr;
|
||||
uint32_t m_deviceIdx = uint32_t(-1);
|
||||
uint32_t m_actualDeviceIdx = 0;
|
||||
uint32_t m_bufferSize = 0;
|
||||
size_t m_availableScans = 0;
|
||||
float* m_Buffer = nullptr;
|
||||
|
||||
int m_notchFilterIdx = -1;
|
||||
int m_bandPassFilterIdx = -1;
|
||||
|
||||
double m_sensitivity = 0;
|
||||
int m_inputSource = 0;
|
||||
uint32_t m_networkChannel = 11;
|
||||
bool m_digitalInputEnabled = true;
|
||||
bool m_noiseReductionEnabled = false;
|
||||
bool m_carEnabled = false;
|
||||
bool m_accelerationDataEnabled = true;
|
||||
bool m_counterEnabled = true;
|
||||
bool m_linkQualityEnabled = true;
|
||||
bool m_batteryLevelEnabled = true;
|
||||
bool m_validationIndicatorEnabled = true;
|
||||
std::vector<uint16_t> m_selectedChannels;
|
||||
std::vector<int> m_bipolarChannels;
|
||||
std::vector<bool> m_noiseReduction;
|
||||
std::vector<bool> m_cars;
|
||||
uint32_t m_nAcquiredChannel = 32;
|
||||
|
||||
GDS_HANDLE m_Device;
|
||||
GDS_RESULT m_gdsResult;
|
||||
GDS_GNAUTILUS_CONFIGURATION m_deviceCfg;
|
||||
std::string m_deviceSerial;
|
||||
uint32_t m_nDevice = 0;
|
||||
};
|
||||
} // namespace AcquisitionServer
|
||||
} // namespace OpenViBE
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyGNEEDaccessAPI
|
||||
Reference in New Issue
Block a user