Inheritance

Function

The SignalSharingDemoFilter shares its input signal through a GenericSignal object which has been linked to a shared memory block using GenericSignal::ShareAcrossModules(). A dedicated thread waits for signal updates, and sends signal data out to a separate application waiting on a TCP/IP connection.

When the client application is running on a separate machine, full signal data are sent over the network. When the client is running on the same machine, only a reference to a shared memory block is sent. On the application side, unserializing the signal will transparently bind it to the shared memory block if available.

The client application visualizes signal data by plotting normalized signals on a circle.

Client application waiting for data

Client application displaying data

Filter Code

Declaration of internal variables

#include"Thread.h"#include"WaitableEvent.h"#include"Sockets.h"#include"Streambuf.h"structSignalSharingDemoFilter::Private{// A socket for a connection to the client application.ClientTCPSocketmSocket;// A signal to be shared.GenericSignalmSharedSignal;// An event to notify the sender thread when new signal data is available.WaitableEventmSignalAvailable;// An object to wrap a call to SenderThreadFunc().MemberCall<void(Private*)>mSenderThreadCall;// The sender thread.ThreadmSenderThread;Private();voidSenderThreadFunc();};

Sender thread

The sender thread waits for the "signal available" event to be triggered, and then calls Serialize() on the shared signal in order to notify the client.

voidSignalSharingDemoFilter::Private::SenderThreadFunc(){if(mSocket.Connected()){UnbufferedIObuf;buf.SetOutput(&mSocket.Output());std::ostreamclientConnection(&buf);GenericSignal().Serialize(clientConnection);// empty signal to indicate beginning of datawhile(mSignalAvailable.Wait())// will return false when Thread::Terminate() has been called{if(!mSharedSignal.Serialize(clientConnection))// will transmit memory reference, or signal, depending on whether ShareAcrossModules() has been called{bciwarn<<"Could not send signal, giving up";mSenderThread.Terminate();}}GenericSignal().Serialize(clientConnection);// empty signal to indicate end of data}}

Filter Initialize() function

The filter connects to the local or remote network address in the SignalSharingDemoClientAddress parameter and allocates signal data according to input
signal properties. If the connection is through a local socket, the filter switches the signal to shared memory by calling GenericSignal::ShareAcrossModules(). Otherwise, it proceeds with a standard GenericSignal, which is transmitted in full rather than as a shared memory reference.

voidSignalSharingDemoFilter::Initialize(constSignalProperties&Input,constSignalProperties&Output){std::stringaddr=Parameter("SignalSharingDemoClientAddress");if(!addr.empty()){// connect to the client sidep->mSocket.Open(addr);// initialize shared signal from input signal propertiesp->mSharedSignal=GenericSignal(Input);if(!p->mSocket.Connected()){bciwarn<<"Cannot connect to "<<addr;}elseif(p->mSocket.Connected()==Socket::local)// only use shared memory when connected locally{p->mSharedSignal.ShareAcrossModules();bciwarn<<"Locally connected to "<<addr<<", using shared memory";}// otherwise, full data will be transmitted over network (slower)else{bciwarn<<"Remotely connected to "<<addr<<", transmitting data through network";}}}

Filter StartRun() and StopRun() functions

Filter Process() function

The Process() function calls GenericSignal::AssignValues() to assign the shared signal's entries without affecting its shared memory representation. Then, it sets the "signal available" event to the signaled state.

Receiving thread function

voidSignalSharingDemoWidget::Private::ThreadFunc(){while(!mThread.Terminating()){// wait for a connectionwhile(mListeningSocket.Input().Wait()){// accept connectionClientTCPSocketclientSocket;if(mListeningSocket.WaitForAccept(clientSocket,0)){mConnected=true;Invalidate();// calls the widget's update() methodUnbufferedIObuf;buf.SetInput(&clientSocket.Input());std::istreamstream(&buf);while(stream&&clientSocket.Input().Wait())// will be interrupted by Thread::Terminate(){mpSignal.Mutable()->Unserialize(stream);// get current signal contentInvalidate();// call update() on the widget}*mpSignal.Mutable()=GenericSignal();mConnected=false;Invalidate();}}}}

The widget's paintEvent()

voidSignalSharingDemoWidget::paintEvent(QPaintEvent*ev){ev->accept();WithLocked(pSignal=p->mpSignal.Const())// lock the signal while reading from it{if(pSignal->Empty()){QPainterpainter(this);painter.fillRect(ev->rect(),Qt::gray);painter.setPen(Qt::white);painter.drawText(geometry(),Qt::AlignCenter,p->mConnected?"Waiting for signal ...":"Waiting for connection ...");}else{// draw some visualization into the widget...}}}