Page 1 of 1

Source Module Development

Posted: 25 Apr 2006, 06:08
by luisgomes
Hi everyone,

I've just joined the BCI 2000 community, and i'm hoping i can contribute to this project!

In my Research Unit, we have a Lifelines Trackit ambulatory EEG recording, which I intend to use with BCI 2000. Therefore, i'm coding a Source Module to use it. Sadly, Lifelines doesn't provide an application interface but only an Interface Specification (for programmers to implement this API by themselves) so I had to code a library to do all the serial RS232 communication with the Trackit box.

I'm now following the tutorial on programming a Source Module found in the Implementation doc, and there i find the requirement for (at least) 3 functions, for acquisition setup, start, and stop.

The first function, TachyonStart, "configures the card and starts acquisition to some internal buffer". Therefore, is the API supposed to have its own thread for data acquisition and the TachyonWaitForData function merely collects the data from the buffer which TachyonStart updates? Or is it OK to just start data acquisition on TachyonWaitForData?

Also, i have another problem. Trackit requires that an HeartBeat packet is sent periodically so that data keeps being sent to the Host, so i would have to periodically notify this thread in order to send a heartbeat ?

I come from an UNIX development environment, so win32 programming is fairly uncharted land for me.. I wanted to know if you have an example source of one of these APIs, so I could understand their structure.

Thank you,
Luis

Posted: 25 Apr 2006, 08:45
by mellinger
Luis,

thank you for this interesting question.

In the example from the BCI2000 implementation document, the internal buffer mentioned in the description of TachyonStart() might or might not be identical to the buffer returned from TachyonWaitForData().
TachyonWaitForData() might return part of this buffer -- or an extra one -- from its first argument. Internally, the "Tachyon" device driver would probably use an interrupt handler called whenever the AD card's hardware buffer is half-filled. Upon entry, the TachyonWaitForData() function would suspend whatever thread it is called from, and the interrupt handler would wake that thread when it has been called the appropriate number of times, i.e. when the requested amount of data has been acquired by the hardware. Any API interfacing with an AD card is likely to work that way, albeit a true API is usually more complicated by various operation modes, configuration parameters, and so on.

However, the example was meant to illustrate the basic ideas of a BCI2000 source module, not to suggest how to write a hardware interface. If your data comes over the serial line, I recommend you have a look at the BCI2000/shared/SerialStream class interface which will provide you with an iostream interface to the serial port. From there, you may handle data as if dealing with a UNIX /dev/tty wrapped up into a C++ iostream, and then use a Process() function that looks something like

Code: Select all

void Process( ignored_input_signal, output_signal )
{
  while( output_signal_is_not_yet_filled_with_data )
  {
    mSerialConnection << whatever_a_HeartBeat_may_be;
    mSerialConnection >> whatever_may_fit_a_data_packet;
    store_packet_data_to_output_signal;
  }
}
If the Trackit device works as I guess, this code will block on the second statement within the while loop, waiting for the latest acquired data block to occur. This way, you can do without an additional thread.
The "whatever_may_fit_a_data_packet" should be an instance of a class that knows how to read itself from an iostream, and provides an appropriate global scope operator>>( std::istream&, your_class ).

Regards,
Juergen