ovasCConfigurationOpenBCI.cpp 10.4 KB
Newer Older
1 2 3 4
/*
 * OpenBCI driver for OpenViBE
 *
 * \author Jeremy Frey
5
 * \author Yann Renard
6 7
 *
 */
jfrey's avatar
jfrey committed
8
#include "ovasCConfigurationOpenBCI.h"
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
#include <algorithm>
#include <string>

#if defined TARGET_OS_Windows
 #include <windows.h>
 #include <winbase.h>
 #include <cstdio>
 #include <cstdlib>
 #include <commctrl.h>
 #include <winsock2.h> // htons and co.
 //#define TERM_SPEED 57600
 #define TERM_SPEED CBR_115200 // OpenBCI is a bit faster than others
#elif defined TARGET_OS_Linux
 #include <cstdio>
 #include <unistd.h>
 #include <fcntl.h>
 #include <termios.h>
 #include <sys/select.h>
 #include <netinet/in.h> // htons and co.
 #include <unistd.h>
 #define TERM_SPEED B115200
#else
#endif
jfrey's avatar
jfrey committed
32

33
#define boolean OpenViBE::boolean
jfrey's avatar
jfrey committed
34 35 36 37
using namespace OpenViBE;
using namespace OpenViBE::Kernel;
using namespace OpenViBEAcquisitionServer;

38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
#define MAXIMUM_SERIAL_TTY     (32)
#define MAXIMUM_SERIAL_USB_TTY (256-MAXIMUM_SERIAL_TTY)

uint32 OpenViBEAcquisitionServer::CConfigurationOpenBCI::getMaximumTTYCount(void)
{
	return MAXIMUM_SERIAL_USB_TTY + MAXIMUM_SERIAL_TTY;
}

CString OpenViBEAcquisitionServer::CConfigurationOpenBCI::getTTYFileName(const uint32 ui32TTYNumber)
{
	char l_sBuffer[1024];
#if defined TARGET_OS_Windows
	::sprintf(l_sBuffer, "\\\\.\\COM%u", ui32TTYNumber);
#elif defined TARGET_OS_Linux
	if(ui32TTYNumber<MAXIMUM_SERIAL_USB_TTY)
	{
		::sprintf(l_sBuffer, "/dev/ttyUSB%u", ui32TTYNumber);
	}
	else
	{
		::sprintf(l_sBuffer, "/dev/ttyS%u", ui32TTYNumber-MAXIMUM_SERIAL_USB_TTY);
	}
#else
	::sprintf(l_sBuffer, "");
#endif
	return l_sBuffer;
}

bool OpenViBEAcquisitionServer::CConfigurationOpenBCI::isTTYFile(const CString& sFileName)
{
#if defined TARGET_OS_Windows
	HANDLE l_pFile=::CreateFile(
		(LPCSTR)sFileName,
		GENERIC_READ,
		0,
		0,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		0);
	if(l_pFile == INVALID_HANDLE_VALUE || l_pFile == NULL)
	{
		return false;
	}
	CloseHandle(l_pFile);
	return true;
#elif defined TARGET_OS_Linux
	int l_iFile=::open(sFileName, O_RDONLY);
	if(l_iFile < 0)
	{
		return false;
	}
	close(l_iFile);
	return true;
#else
	// Caution, this path will claim all serial ports do exist because there was no platform specific implementation
	return true;
#endif
}
static void checkbutton_daisy_module_cb(::GtkToggleButton* pButton, CConfigurationOpenBCI* pConfigurationOpenBCI)
{
	pConfigurationOpenBCI->checkbuttonDaisyModuleCB(gtk_toggle_button_get_active(pButton)?CConfigurationOpenBCI::DaisyStatus_Active:CConfigurationOpenBCI::DaisyStatus_Inactive);
}

jfrey's avatar
jfrey committed
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
CConfigurationOpenBCI::CConfigurationOpenBCI(const char* sGtkBuilderFileName, OpenViBE::uint32& rUSBIndex)
	:CConfigurationBuilder(sGtkBuilderFileName)
	,m_rUSBIndex(rUSBIndex)
{
	m_pListStore=gtk_list_store_new(1, G_TYPE_STRING);
}

CConfigurationOpenBCI::~CConfigurationOpenBCI(void)
{
	g_object_unref(m_pListStore);
}

boolean CConfigurationOpenBCI::preConfigure(void)
{
	if(!CConfigurationBuilder::preConfigure())
	{
		return false;
	}

120
#if 0
121
	::GtkEntry* l_pEntryComInit=GTK_ENTRY(gtk_builder_get_object(m_pBuilderConfigureInterface, "entry_com_init"));
122 123 124 125 126 127 128 129 130 131 132 133 134 135
	::gtk_entry_set_text(l_pEntryComInit, m_sAdditionalCommands.toASCIIString());
#else
	std::string l_sAdditionalCommands=m_sAdditionalCommands.toASCIIString();
	std::replace(l_sAdditionalCommands.begin(), l_sAdditionalCommands.end(), '\255', '\n');
	::GtkTextView* l_pTextViewComInit=GTK_TEXT_VIEW(gtk_builder_get_object(m_pBuilderConfigureInterface, "text_view_com_init"));
	::GtkTextBuffer* l_pTextBufferComInit=::gtk_text_view_get_buffer(l_pTextViewComInit);
	::gtk_text_buffer_set_text(l_pTextBufferComInit, l_sAdditionalCommands.c_str(), -1);
#endif

	::GtkSpinButton* l_pSpinButtonReadBoardReplyTimeout=GTK_SPIN_BUTTON(gtk_builder_get_object(m_pBuilderConfigureInterface, "spinbutton_read_board_reply_timeout"));
	::gtk_spin_button_set_value(l_pSpinButtonReadBoardReplyTimeout, m_iReadBoardReplyTimeout);

	::GtkSpinButton* l_pSpinButtonFlushBoardReplyTimeout=GTK_SPIN_BUTTON(gtk_builder_get_object(m_pBuilderConfigureInterface, "spinbutton_flush_board_reply_timeout"));
	::gtk_spin_button_set_value(l_pSpinButtonFlushBoardReplyTimeout, m_iFlushBoardReplyTimeout);
136

137 138
	::GtkToggleButton* l_pToggleButtonDaisyModule=GTK_TOGGLE_BUTTON(gtk_builder_get_object(m_pBuilderConfigureInterface, "checkbutton_daisy_module"));
	::gtk_toggle_button_set_active(l_pToggleButtonDaisyModule, m_bDaisyModule?true:false);
139 140 141 142

	::g_signal_connect(::gtk_builder_get_object(m_pBuilderConfigureInterface, "checkbutton_daisy_module"), "toggled", G_CALLBACK(checkbutton_daisy_module_cb), this);
	this->checkbuttonDaisyModuleCB(m_bDaisyModule?DaisyStatus_Active:DaisyStatus_Inactive);

jfrey's avatar
jfrey committed
143 144 145 146
	::GtkComboBox* l_pComboBox=GTK_COMBO_BOX(gtk_builder_get_object(m_pBuilderConfigureInterface, "combobox_device"));

	g_object_unref(m_pListStore);
	m_pListStore=gtk_list_store_new(1, G_TYPE_STRING);
147
	m_vComboSlotIndexToSerialPort.clear();
jfrey's avatar
jfrey committed
148 149 150 151 152

	gtk_combo_box_set_model(l_pComboBox, GTK_TREE_MODEL(m_pListStore));

	boolean l_bSelected=false;

153 154 155 156
	m_vComboSlotIndexToSerialPort[0]=-1;
	::gtk_combo_box_append_text(l_pComboBox, "Automatic");

	for(uint32 i=0, j=1; i<CConfigurationOpenBCI::getMaximumTTYCount(); i++)
jfrey's avatar
jfrey committed
157
	{
158 159
		CString l_sFileName = CConfigurationOpenBCI::getTTYFileName(i);
		if(CConfigurationOpenBCI::isTTYFile(l_sFileName))
jfrey's avatar
jfrey committed
160
		{
161 162 163 164 165 166 167 168
			m_vComboSlotIndexToSerialPort[j]=i;
			::gtk_combo_box_append_text(l_pComboBox, l_sFileName.toASCIIString());
			if(m_rUSBIndex==i)
			{
				::gtk_combo_box_set_active(l_pComboBox, j);
				l_bSelected=true;
			}
			j++;
jfrey's avatar
jfrey committed
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
		}
	}

	if(!l_bSelected)
	{
		::gtk_combo_box_set_active(l_pComboBox, 0);
	}

	return true;
}

boolean CConfigurationOpenBCI::postConfigure(void)
{
	::GtkComboBox* l_pComboBox=GTK_COMBO_BOX(gtk_builder_get_object(m_pBuilderConfigureInterface, "combobox_device"));

	if(m_bApplyConfiguration)
	{
186
		int l_iUSBIndex=m_vComboSlotIndexToSerialPort[gtk_combo_box_get_active(l_pComboBox)];
jfrey's avatar
jfrey committed
187 188
		if(l_iUSBIndex>=0)
		{
189
			m_rUSBIndex=(uint32)l_iUSBIndex;
jfrey's avatar
jfrey committed
190
		}
191 192 193 194 195 196
		else
		{
			m_rUSBIndex=(uint32)-1;
		}

#if 0
197
		::GtkEntry* l_pEntryComInit=GTK_ENTRY(gtk_builder_get_object(m_pBuilderConfigureInterface, "entry_com_init"));
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
		m_sAdditionalCommands=::gtk_entry_get_text(l_pEntryComInit);
#else
		::GtkTextView* l_pTextViewComInit=GTK_TEXT_VIEW(gtk_builder_get_object(m_pBuilderConfigureInterface, "text_view_com_init"));
		::GtkTextBuffer* l_pTextBufferComInit=::gtk_text_view_get_buffer(l_pTextViewComInit);
		::GtkTextIter l_oStartIter;
		::GtkTextIter l_oEndIter;
		::gtk_text_buffer_get_start_iter(l_pTextBufferComInit, &l_oStartIter);
		::gtk_text_buffer_get_end_iter(l_pTextBufferComInit, &l_oEndIter);
		std::string l_sAdditionalCommands=::gtk_text_buffer_get_text(l_pTextBufferComInit, &l_oStartIter, &l_oEndIter, FALSE);
		std::replace(l_sAdditionalCommands.begin(), l_sAdditionalCommands.end(), '\n', '\255');
		m_sAdditionalCommands = l_sAdditionalCommands.c_str();
#endif

		::GtkSpinButton* l_pSpinButtonReadBoardReplyTimeout=GTK_SPIN_BUTTON(gtk_builder_get_object(m_pBuilderConfigureInterface, "spinbutton_read_board_reply_timeout"));
		gtk_spin_button_update(GTK_SPIN_BUTTON(l_pSpinButtonReadBoardReplyTimeout));
		m_iReadBoardReplyTimeout=::gtk_spin_button_get_value_as_int(l_pSpinButtonReadBoardReplyTimeout);

		::GtkSpinButton* l_pSpinButtonFlushBoardReplyTimeout=GTK_SPIN_BUTTON(gtk_builder_get_object(m_pBuilderConfigureInterface, "spinbutton_flush_board_reply_timeout"));
		gtk_spin_button_update(GTK_SPIN_BUTTON(l_pSpinButtonFlushBoardReplyTimeout));
		m_iFlushBoardReplyTimeout=::gtk_spin_button_get_value_as_int(l_pSpinButtonFlushBoardReplyTimeout);

219
		::GtkToggleButton* l_pToggleButtonDaisyModule=GTK_TOGGLE_BUTTON(gtk_builder_get_object(m_pBuilderConfigureInterface, "checkbutton_daisy_module"));
220
		m_bDaisyModule=::gtk_toggle_button_get_active(l_pToggleButtonDaisyModule)?true:false;
jfrey's avatar
jfrey committed
221 222 223 224 225 226 227 228
	}

	if(!CConfigurationBuilder::postConfigure())
	{
		return false;
	}
	return true;
}
229

230
boolean CConfigurationOpenBCI::setAdditionalCommands(const CString& sAdditionalCommands)
231
{
232
        m_sAdditionalCommands=sAdditionalCommands;
233 234 235
        return true;
}

236
CString CConfigurationOpenBCI::getAdditionalCommands(void) const
237
{
238
        return m_sAdditionalCommands;
239 240
}

241
boolean CConfigurationOpenBCI::setReadBoardReplyTimeout(uint32 iReadBoardReplyTimeout)
242
{
243
        m_iReadBoardReplyTimeout=iReadBoardReplyTimeout;
244 245 246
        return true;
}

247 248 249 250 251 252 253 254 255 256
uint32 CConfigurationOpenBCI::getReadBoardReplyTimeout(void) const
{
        return m_iReadBoardReplyTimeout;
}

boolean CConfigurationOpenBCI::setFlushBoardReplyTimeout(uint32 iFlushBoardReplyTimeout)
{
        m_iFlushBoardReplyTimeout=iFlushBoardReplyTimeout;
        return true;
}
257

258
uint32 CConfigurationOpenBCI::getFlushBoardReplyTimeout(void) const
259
{
260
        return m_iFlushBoardReplyTimeout;
261 262 263 264 265 266
}

bool CConfigurationOpenBCI::setDaisyModule(bool bDaisyModule)
{
        m_bDaisyModule=bDaisyModule;
        return true;
267
}
268 269 270 271

bool CConfigurationOpenBCI::getDaisyModule(void) const
{
        return m_bDaisyModule;
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
}

void CConfigurationOpenBCI::checkbuttonDaisyModuleCB(EDaisyStatus eStatus)
{
	SDaisyInformation l_oDaisyInformation=this->getDaisyInformation(eStatus);

	char l_sBuffer[1024];

	::sprintf(l_sBuffer, "%i EEG Channels", l_oDaisyInformation.iEEGChannelCount);
	::gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(m_pBuilderConfigureInterface, "label_status_eeg_channel_count")), l_sBuffer);

	::sprintf(l_sBuffer, "%i Accelerometer Channels", l_oDaisyInformation.iAccChannelCount);
	::gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(m_pBuilderConfigureInterface, "label_status_acc_channel_count")), l_sBuffer);

	::sprintf(l_sBuffer, "%i Hz Sampling Rate", l_oDaisyInformation.iSamplingRate);
	::gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(m_pBuilderConfigureInterface, "label_status_sampling_rate")), l_sBuffer);

	::gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(m_pBuilderConfigureInterface, "spinbutton_number_of_channels")), l_oDaisyInformation.iEEGChannelCount+l_oDaisyInformation.iAccChannelCount);
}

CConfigurationOpenBCI::SDaisyInformation CConfigurationOpenBCI::getDaisyInformation(EDaisyStatus eStatus)
{
	SDaisyInformation l_oResult;
	switch(eStatus)
	{
		case DaisyStatus_Inactive:
			l_oResult.iEEGChannelCount = DefaultEEGChannelCount;
			l_oResult.iAccChannelCount = DefaultAccChannelCount;
			l_oResult.iSamplingRate = DefaultSamplingRate;
			break;

		case DaisyStatus_Active:
			l_oResult.iEEGChannelCount = DefaultEEGChannelCount*2;
			l_oResult.iAccChannelCount = DefaultAccChannelCount;
			l_oResult.iSamplingRate = DefaultSamplingRate/2;
			break;

		default:
			l_oResult.iEEGChannelCount = 0;
			l_oResult.iAccChannelCount = 0;
			l_oResult.iSamplingRate = 0;
			break;
	}

	return l_oResult;
}