<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.bci2000.org/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Tytbutler</id>
	<title>BCI2000 Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://www.bci2000.org/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Tytbutler"/>
	<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php/Special:Contributions/Tytbutler"/>
	<updated>2026-06-29T20:59:39Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000&amp;diff=11773</id>
		<title>User Tutorial:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000&amp;diff=11773"/>
		<updated>2025-03-14T04:33:33Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: fixed example&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Red text blocks contain detailed instructions for the higher-level instructions preceding them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example comprehensively demonstrates many of the capabilities of UnityBCI2000, and as such, is more than what is necessary for many usecases. If you just want to use BCI2000 as a logging backend for an existing Unity application, see [[User Tutorial:UnityBCI2000 Barebones]].&lt;br /&gt;
&lt;br /&gt;
===Download Unity===&lt;br /&gt;
&lt;br /&gt;
Download Unity Hub from [https://unity3d.com Unity].&lt;br /&gt;
&lt;br /&gt;
===Setting Up BCI2000===&lt;br /&gt;
&lt;br /&gt;
Follow the instructions starting with [https://www.bci2000.org/mediawiki/index.php/Programming_Howto:Install_Prerequisites] to download BCI2000. &lt;br /&gt;
&lt;br /&gt;
===Setting Up UnityBCI2000===&lt;br /&gt;
Download UnityBCI2000 from its GitHub page, [https://github.com/neurotechcenter/UnityBCI2000]. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the &amp;quot;Releases&amp;quot; section on the right side of the page. This tutorial is intended to be used with UnityBCI2000 version 2.0.0, so scroll to that release and click on the files BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to download them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Download Tutorial Project===&lt;br /&gt;
Download the CursorTask3 repository from [https://github.com/Personator01/CursorTask3 GitHub].&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Either:&lt;br /&gt;
	-Clone the git repository&lt;br /&gt;
	-Download the respository directly from GitHub&lt;br /&gt;
		-&amp;gt; Click the green &amp;quot;Code&amp;quot; button &lt;br /&gt;
		-&amp;gt; Select &amp;quot;Download ZIP&amp;quot;&lt;br /&gt;
		-&amp;gt; Extract the zip file&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The download directory contains two versions of the CursorTask3 project. One, CursorTask3-BCI2K, contains an example implementation of the task with BCI2000 integration. The other, CursorTask3-NoBCI2K, contains the same task without BCI2000 integration. This tutorial is a step by step guide on turning that second project into the first. &lt;br /&gt;
&lt;br /&gt;
===Opening the project===&lt;br /&gt;
Open the project in the Unity Editor, and open the CursorTask scene.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Open Unity Hub.&lt;br /&gt;
Click the &amp;quot;Add&amp;quot; button in the top right corner.&lt;br /&gt;
Navigate to the CursorTask3 directory downloaded previously.&lt;br /&gt;
Select the CursorTask3-NoBCI2K directory to add it to Unity Hub.&lt;br /&gt;
Click the CursorTask3-NoBCI2K project in the Unity Hub.&lt;br /&gt;
If prompted to select a version of Unity to use or install, select Unity 2022.3. The specific release number of Unity 2022.3 should not matter, so select the one labeled &amp;quot;LTS&amp;quot; for consistency.&lt;br /&gt;
The lower panel (the asset browser) should already show the Assets/Scenes directory, which contains a single scene called SampleScene.&lt;br /&gt;
Double-click SampleScene. This should open a scene with a box containing various lights and objects.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you wish to view the completed implementation, repeat these steps, but instead open the CursorTask3-BCI2K directory. Note that in order to use the completed implementation, you will still need to set the Operator Path value of the UnityBCI2000 component of the BCI2000 game object.&lt;br /&gt;
&lt;br /&gt;
===Adding UnityBCI2000 to the project===&lt;br /&gt;
Add BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to your project&#039;s assets.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click Assets &amp;gt; Open Containing Folder to open your project directory.&lt;br /&gt;
Place the BCI2000RemoteNETStandard.dll and UnityBCI2000.cs files in the Assets folder.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add an empty GameObject called &#039;BCI2000&#039;. This will hold the scripts for controlling BCI2000. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click GameObject &amp;gt; Create Empty to create an empty GameObject, and name it &#039;BCI2000&#039;. (The object&#039;s specific name does not actually matter, it is only needed in order to reference it within other scripts)&lt;br /&gt;
You will notice that it now appears in the Scene Hierarchy panel, on the left side of the screen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the UnityBCI2000 component to the object.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the object in the Hierarchy panel. This will open it in the Inspector panel (the panel on the right side of the screen)&lt;br /&gt;
In the inspector, below the new object&#039;s Transform component, click the &amp;quot;Add Component&amp;quot; button, which will open up a small window for adding components.&lt;br /&gt;
Within this window, select Scripts &amp;gt; Unity BCI2000 to add the UnityBCI2000 component.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Configuring UnityBCI2000===&lt;br /&gt;
The inspector panel now contains the configuration options for UnityBCI2000. Set the options as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Local Operator&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This will start the operator on your computer when the Unity scene initializes. If we were instead connecting to an already-running instance of BCI2000, or an instance on another computer, this box would be deselected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Path&amp;lt;/code&amp;gt;: The path to the Operator executable. This will look something like this on Windows (C://path/to/bci2000/prog/Operator.exe)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Address&amp;lt;/code&amp;gt;: 127.0.0.1&lt;br /&gt;
&lt;br /&gt;
This is the address of the machine on which BCI2000 is running. Since we are running BCI2000 on the same computer as Unity, we leave it as 127.0.0.1, the loopback address.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Port&amp;lt;/code&amp;gt;: 3999&lt;br /&gt;
&lt;br /&gt;
This is the port on which BCI2000 is listening for commands. By default, it is 3999.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Modules&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to start the requested Signal Source, Signal Processing, and Application modules when the Unity scene initializes. Similarly to Start Local Operator, we would deselect this box if connecting to an already-running instance. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to start a data collection run when the scene starts. Since we will be using BCI2000 itself to set experiment parameters, we will instead wait for BCI2000 to start from Unity, and thus will leave the box unchecked. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Stop With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to stop collecting data when the scene stops. Since we will be controlling BCI2000 directly, rather than entirely through Unity, we will leave this unchecked.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Shutdown With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to shut down alongside the Unity scene. Whether or not this value is set ultimately doesn&#039;t matter much, especially if Start Local Operator is checked. The data will be saved whether or not BCI2000 shuts down. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 1&amp;lt;/code&amp;gt;: SignalGenerator&lt;br /&gt;
&lt;br /&gt;
The signal source module to start. We will use SignalGenerator, which generates a signal without any connected hardware.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 2&amp;lt;/code&amp;gt;: DummySignalProcessing&lt;br /&gt;
&lt;br /&gt;
The signal processing module to start. We will use DummySignalProcessing, as there is no processing to do.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 3&amp;lt;/code&amp;gt;: DummyApplication&lt;br /&gt;
&lt;br /&gt;
The Application module to start. Since we are using Unity, we will use DummyApplication.&lt;br /&gt;
&lt;br /&gt;
===Setting References===&lt;br /&gt;
In order for the game&#039;s scripts to communicate with BCI2000, they need to hold a reference to the UnityBCI2000 component.&lt;br /&gt;
There are three scripts which will need to communicate with BCI2000. They are &amp;lt;code&amp;gt;GameControl.cs, BallControl.cs, and MCursorControl.cs&amp;lt;/code&amp;gt;.&lt;br /&gt;
These scripts are each located within the Assets directory of the Unity project. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
As before, select Assets &amp;gt; Open Containing Folder to open the project directory, then open the Assets folder. &lt;br /&gt;
For each script, open it in a text editor.&lt;br /&gt;
Add a data member of type UnityBCI2000 to the class, like so:&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
Place the member definition above the Awake() method, for readability.&lt;br /&gt;
Within the Awake() method, set this reference to the UnityBCI2000 component.&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Each of the three scripts should contain a section like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
	void Awake() {&lt;br /&gt;
		bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
		...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding Events===&lt;br /&gt;
[https://www.bci2000.org/mediawiki/index.php/Programming_Reference:Events Events] are the primary way that non-signal experiment data is recorded in BCI2000. They are timestamped integer values which are encoded alongside the signal data in BCI2000 output files. Due to BCI2000&#039;s design, events must be added during a very specific part of its startup sequence, which is immediately after the BCI2000 operator starts, and before any of the modules start. As such, we cannot simply call &amp;lt;code&amp;gt;AddEvent()&amp;lt;/code&amp;gt; whenever we want. Furthermore, the order in which Unity objects initialize is undefined, so it cannot even be guaranteed that calling &amp;lt;code&amp;gt;AddEvent&amp;lt;/code&amp;gt; at a specific time will be consistent across multiple projects. As such, UnityBCI2000 provides a couple of methods for sending commands at well-defined points within the startup sequence. These two methods, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; allow BCI2000 commands to be sent while the operator is in the state Idle (immediately before starting its modules) and when the operator is in the state Connected (after starting and connecting to the modules. Below is an example of using those methods to add and show an event in BCI2000.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Script : MonoBehaviour {&lt;br /&gt;
    UnityBCI2000 bci;&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000Object&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;AnEvent&amp;quot;, 32);&lt;br /&gt;
	});&lt;br /&gt;
    }&lt;br /&gt;
    void Start() {&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;AnEvent&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As seen above, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; take a delegate (C#&#039;s term for a callback/closure/functor/etc.) with a single parameter of type &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt; (in this case called &amp;quot;remote&amp;quot;). The lambda expression given to the call to &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; uses the method &amp;lt;code&amp;gt;BCI2000Remote.AddEvent()&amp;lt;/code&amp;gt; to add an event called &amp;quot;AnEvent&amp;quot; with a bit width of 32 bits. The call to &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; tells BCI2000 to show the event&#039;s value in a graphical window. A description of the BCI2000Remote class can be found [https://www.bci2000.org/mediawiki/index.php/Contributions:BCI2000RemoteNET here], and API documentation can be found [https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html here].&lt;br /&gt;
&lt;br /&gt;
We will now add the events relevant to the Cursor Task. Open the &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt; script, and modify its &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; to add the events &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; with bit width 1. Additionally, add the events &amp;lt;code&amp;gt;TrialNumber&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetPositionX&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;TargetPositionY&amp;lt;/code&amp;gt; with width 16. These will encode the task state and number of trials.&lt;br /&gt;
We also need to set a parameter value so that the signal will be set to the mouse position. Using &amp;lt;code&amp;gt;BCI2000Remote.SetParameter()&amp;lt;/code&amp;gt;, we will set the &amp;lt;code&amp;gt;ModulateAmplitude&amp;lt;/code&amp;gt; parameter to 1.&lt;br /&gt;
&lt;br /&gt;
Open the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, and within the &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; function, add events &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt;, with width 16. Show these events in a visualization window with &amp;lt;code&amp;gt;Visualize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your two scripts should now look like this: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs &lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TrialNumber&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetPositionY&amp;quot;, 16);&lt;br /&gt;
	    remote.SetParameter(&amp;quot;ModulateAmplitude&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
	    });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionY&amp;quot;, 16);&lt;br /&gt;
	    });&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionX&amp;quot;);&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionY&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using BCI2000 Parameters===&lt;br /&gt;
====Adding Parameters====&lt;br /&gt;
BCI2000&#039;s operator contains an interface for changing experiment parameters before running a task. By making use of this interface we can change the behavior of the task dynamically, without needing to rebuild the Unity project each time. In order to do this we need to define the parameters and add them to BCI2000, and later read their values after the operator has a chance to change them. &amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;This section is not strictly necessary. The project will function the same whether this is done or not, just without the option to change parameters at runtime. &amp;lt;/span&amp;gt; &lt;br /&gt;
&lt;br /&gt;
First, we define add parameters to BCI2000. Similarly to events, parameters must be added while the Operator is in the &amp;lt;code&amp;gt;Idle&amp;lt;/code&amp;gt; state, so we add them inside of &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt;, like below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public int someParameter = 5;&lt;br /&gt;
void Awake() {&lt;br /&gt;
    bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	remote.AddParameter(&amp;quot;Application:ParameterPlace&amp;quot;, &amp;quot;SomeParameter&amp;quot;, someParameter.ToString()); &lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
The first argument to the method is the section into which the parameter is placed, that is, on which tab and under which heading the parameter will appear within the Operator&#039;s parameter editor window (note that the section is not a scope, all parameter names must be unique). The second argument is the parameter name itself. The third argument is the default value of the parameter. We pass in the value of the parameter, so when it appears in the Operator, its default value is 5 (or another value if it has been changed in the Unity Editor). Note that all parameters are handled as strings, so we need to convert its value to a string when sending it.&lt;br /&gt;
&lt;br /&gt;
For &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;, we will add parameters corresponding to the Pre-Feedback, Feedback, and Post-Feedback durations, Target Radius, and Number of Trials.&lt;br /&gt;
For &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt;, we will add parameters corresponding to the Acceleration Scale, Coefficient of Restitution, Coefficient of Drag, and Attraction Curve Coefficient (how quickly the Ball moves to follow the Mouse Cursor).&lt;br /&gt;
For &amp;lt;code&amp;gt;MCursorControl.cs&amp;lt;/code&amp;gt;, we will add a parameter corresponding to the Rolling Maximum Amount.&lt;br /&gt;
&lt;br /&gt;
Your scripts should look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		remote.AddEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
		...&lt;br /&gt;
&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;PreFeedbackDuration&amp;quot;, preFeedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;FeedbackDuration&amp;quot;, feedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;PostFeedbackDuration&amp;quot;, postFeedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;TargetRadius&amp;quot;, targetRadius.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;Trials&amp;quot;, n_trials.ToString());&lt;br /&gt;
		});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;AccelerationScale&amp;quot;, accelerationScale.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;CoeffOfRestitution&amp;quot;, coefficientOfRestitution.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;CoeffOfDrag&amp;quot;, coefficientOfDrag.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;AccelerationCurve&amp;quot;, attractionCurveCoefficient.ToString());&lt;br /&gt;
		})}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; MCursorControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;RollingMaximumAmount&amp;quot;, rollingMaximumAmount.ToString());&lt;br /&gt;
		});&lt;br /&gt;
}&lt;br /&gt;
		&lt;br /&gt;
&lt;br /&gt;
====Reading and Validating Parameters====&lt;br /&gt;
Since we set the parameters within the BCI2000 operator, we need some way to read them back into Unity after they have been set. Specifically, we need to read them after the operator clicks the &amp;quot;Set Config&amp;quot; button within the BCI2000 Operator. How this timing synchronization is covered in the section [[Reacting to BCI2000 state changes]]. In this section we will cover reading and validating parameters.&lt;br /&gt;
&lt;br /&gt;
A method called &amp;lt;code&amp;gt;SetConfig&amp;lt;/code&amp;gt; is provided in each of the scripts in which we added parameters previously. This method will be called after the operator changes parameters. In this method we will read in parameters and parse them into valid values. Using the same example parameter as before:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void SetConfig() {&lt;br /&gt;
    try {&lt;br /&gt;
	someParameter = int.Parse(bci.Control.GetParameter(&amp;quot;SomeParameter&amp;quot;));&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
	bci.Error(&amp;quot;Could not parse parameter SomeParameter as int&amp;quot;);&lt;br /&gt;
	throw e;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that since we are now working outside the BCI2000 startup sequence, we use &amp;lt;code&amp;gt;UnityBCI2000.Control&amp;lt;/code&amp;gt; to call &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt; methods directly, rather than using &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt;. We also wrap the call within a try/catch block so that we can report erroneous parameters back to the operator. This is optional, but it keeps your project from failing silently and is otherwise useful for doing things like distributing your Unity project as a standalone executable, where logging errors can only be done through the BCI2000 operator. You can also write a helper function which handles parsing and error reporting for you:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int GetParseParameterInt(string paramName) {&lt;br /&gt;
    int p_val = bci.Control.GetParameter(&amp;quot;SomeParameter&amp;quot;);&lt;br /&gt;
    try {&lt;br /&gt;
	someParameter = int.Parse(p_val);&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
	bci.Error($&amp;quot;Could not parse parameter {paramName} (value {p_val}) as int&amp;quot;);&lt;br /&gt;
	throw e;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Unfortunately, since the version of C# used by Unity does not support type-parameterized parsing, you must write one of these helper functions for each type of data you want to store in a parameter (int, float, double, etc.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Read back the parameters added in the previous step. Your scripts should look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs &lt;br /&gt;
void SetConfig() {&lt;br /&gt;
	try {&lt;br /&gt;
	   preFeedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;PreFeedbackDuration&amp;quot;));&lt;br /&gt;
	   feedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;FeedbackDuration&amp;quot;));&lt;br /&gt;
	   postFeedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;PostFeedbackDuration&amp;quot;));&lt;br /&gt;
	   targetRadius = float.Parse(bci.Control.GetParameter(&amp;quot;TargetRadius&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse one of PreFeedbackDuration, FeedbackDuration, PostFeedbackDuration, or TargetRadius as a float&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
	try {&lt;br /&gt;
	   n_trials = int.Parse(bci.Control.GetParameter(&amp;quot;Trials&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse Trials as an int&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if (preFeedbackDuration &amp;lt; COUNTDOWN_DURATION) {&lt;br /&gt;
	   bci.Error(&amp;quot;preFeedbackDuration must be greater than or equal to 2.25&amp;quot;);&lt;br /&gt;
	   throw new Exception(&amp;quot;preFeedbackDuration must be greater than or equal to 2.25&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
    public void SetConfig() {&lt;br /&gt;
	try {&lt;br /&gt;
	   accelerationScale = float.Parse(bci.Control.GetParameter(&amp;quot;AccelerationScale&amp;quot;));&lt;br /&gt;
	   coefficientOfRestitution = float.Parse(bci.Control.GetParameter(&amp;quot;CoeffOfRestitution&amp;quot;));&lt;br /&gt;
	   coefficientOfDrag = float.Parse(bci.Control.GetParameter(&amp;quot;CoeffOfDrag&amp;quot;));&lt;br /&gt;
	   attractionCurveCoefficient = float.Parse(bci.Control.GetParameter(&amp;quot;AccelerationCurve&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse one of AccelerationScale, CoeffOfRestitution, CoeffOfDrag, AccelerationCurve as float&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; MCursorControl.cs&lt;br /&gt;
public void SetConfig() {&lt;br /&gt;
    try {&lt;br /&gt;
       rollingMaximumAmount = int.Parse(bci.Control.GetParameter(&amp;quot;RollingMaximumAmount&amp;quot;));&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
       bci.Error(&amp;quot;Could not parse parameter RollingMaximumAmount as int&amp;quot;);&lt;br /&gt;
       throw e;&lt;br /&gt;
    }&lt;br /&gt;
    signalsX = new int[rollingMaximumAmount];&lt;br /&gt;
    signalsY = new int[rollingMaximumAmount];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;, we also verify that the Pre-Feedback Duration is longer than the duration of the countdown that happens before each trial, and report errors to BCI2000 accordingly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Reacting to BCI2000 state changes===&lt;br /&gt;
Since we will be controlling the Unity task from BCI2000, we need some way to wait for BCI2000 to be in a specific state, for example, waiting for the operator to click Start and put the Operator Module into the Running state. UnityBCI2000 provides a method for this, the &amp;lt;code&amp;gt;UnityBCI2000.PollSystemState&amp;lt;/code&amp;gt; method. In order to wait for the Operator Module to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bci.PollSystemState(BCI2000Remote.SystemState.Running);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will check once per frame whether or not the Operator is in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state, and only continue once BCI2000 is in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state. Note that since &amp;lt;code&amp;gt;SystemState&amp;lt;/code&amp;gt; is a member of &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt;, we also need to add a &amp;lt;code&amp;gt;using BCI2000RemoteNET&amp;lt;/code&amp;gt; statement to our script.&lt;br /&gt;
&lt;br /&gt;
In our case, we need to react to the operator setting the parameters, starting the data collection, and stopping the data collection. These correspond to the Operator Module entering the &amp;lt;code&amp;gt;Resting&amp;lt;/code&amp;gt; state, entering the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state, and exiting the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt; script, we will wait for the system to be in the &amp;lt;code&amp;gt;Resting&amp;lt;/code&amp;gt; state at the start of the &amp;lt;code&amp;gt;ControLoop&amp;lt;/code&amp;gt; method, and wait for the system to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state immediately before the entering the trial loop. Note that this code is within a coroutine and we do not want it to block, so we use a &amp;lt;code&amp;gt;yield return&amp;lt;/code&amp;gt; statement.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
&lt;br /&gt;
    IEnumerator ControlLoop() {&lt;br /&gt;
	while (True) {&lt;br /&gt;
&lt;br /&gt;
	   yield return bci.PollSystemState(BCI2000Remote.SystemState.Resting);&lt;br /&gt;
&lt;br /&gt;
	   try {&lt;br /&gt;
		...&lt;br /&gt;
	   } catch (Exception e) {&lt;br /&gt;
		continue;&lt;br /&gt;
	   }&lt;br /&gt;
	&lt;br /&gt;
	   int trials = 0;&lt;br /&gt;
&lt;br /&gt;
	   yield return bci.PollSystemState(BCI2000Remote.SystemState.Running);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	   yield return new WaitForSeconds(preRunDuration);&lt;br /&gt;
	   while (IsContinue() &amp;amp;&amp;amp; trials &amp;lt; n_trials) {&lt;br /&gt;
		...&lt;br /&gt;
	   }&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need to check for the operator stopping data collection, so we modify the &amp;lt;code&amp;gt;IsContinue()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bool IsContinue () {&lt;br /&gt;
	return bci.Control.GetSystemState() == BCI2000Remote.SystemState.Running;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remember to add &amp;lt;code&amp;gt;using BCI2000RemoteNET;&amp;lt;/code&amp;gt; to the top of the script, so you can access the &amp;lt;code&amp;gt;SystemState&amp;lt;/code&amp;gt; enum.&lt;br /&gt;
&lt;br /&gt;
===Reading the control signal===&lt;br /&gt;
We will be using the control signal to control the cursor. Open the &amp;lt;code&amp;gt;MCursorControl.cs&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
The commented out section of the &amp;lt;code&amp;gt;GetPos()&amp;lt;/code&amp;gt; method contains the code required to turn the control signal waveform coming from the Signal Source and Signal Processing modules into screen coordinates. &lt;br /&gt;
Uncomment the commented part and delete the line &amp;lt;code&amp;gt;Ray r = camera.ScreenPointToRay(Input.MousePosition);&amp;lt;/code&amp;gt;.&lt;br /&gt;
Change the &amp;lt;code&amp;gt;double signalX = 0;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;double signalY = 0;&amp;lt;/code&amp;gt; to. &lt;br /&gt;
&lt;br /&gt;
Your &amp;lt;code&amp;gt;GetPos()&amp;lt;/code&amp;gt; method should look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    Vector3 GetPos() {&lt;br /&gt;
	double signalX = bci.Control.GetSignal(1, bci.CurrentSampleOffset());&lt;br /&gt;
	double signalY = bci.Control.GetSignal(2, bci.CurrentSampleOffset());&lt;br /&gt;
	signalsX[signalIndex] = signalX;&lt;br /&gt;
	signalsY[signalIndex] = signalY;&lt;br /&gt;
	&lt;br /&gt;
	signalIndex = signalIndex + 1 &amp;gt;= rollingMaximumAmount ? 0 : signalIndex + 1;&lt;br /&gt;
	double max_x = signalsX.Max();&lt;br /&gt;
	double max_y = signalsY.Max();&lt;br /&gt;
	Ray r = camera.ScreenPointToRay(new Vector3((float) max_x * Screen.width, (float) max_y * Screen.height, 0));&lt;br /&gt;
	float p;&lt;br /&gt;
	if (!plane.Raycast(r, out p)) {&lt;br /&gt;
	   throw new Exception(&amp;quot;error casting ray to plane, invalid mouse position?&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	return r.GetPoint(p);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the use of the &amp;lt;code&amp;gt;UnityBCI2000.CurrentSampleOffset()&amp;lt;/code&amp;gt; method. This is a special method which gets the offset into the current block such that the sample is exactly one block length later than when it was collected by the hardware. This is to normalize the latency between when the hardware collects the signal and the software receives the signal, due to how BCI2000 processes data in blocks.&lt;br /&gt;
&lt;br /&gt;
===Sending events back to BCI2000===&lt;br /&gt;
&lt;br /&gt;
The primary way to communicate game state back to BCI2000 is via the use of Events, which are integer values encoded alongside the signal data.&lt;br /&gt;
&lt;br /&gt;
We will send the events that we added in a previous section.&lt;br /&gt;
&lt;br /&gt;
First, we will send back the current position of the cursor. Within the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, within the &amp;lt;code&amp;gt;Update()&amp;lt;/code&amp;gt; method, immediately after &amp;lt;code&amp;gt;Move()&amp;lt;/code&amp;gt; is called, set the &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt; events. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
void Update() {&lt;br /&gt;
    ...&lt;br /&gt;
    if (isTrialRunning) {&lt;br /&gt;
	...&lt;br /&gt;
	Move();&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;CursorPositionX&amp;quot;, (uint) ((transform.position.x + 7) * 1000));&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;CursorPositionY&amp;quot;, (uint) ((transform.position.y + 4.5) * 1000));&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that we transform the value of the cursor&#039;s position. This is because events in BCI2000 are represented as unsigned integers, so, for example, the cursor&#039;s range of movement in the x axis, -7 to 7, would not be directly representable within a BCI2000 event, so we add 7 so it is positive, and multiply by 1000 so that we have a more precise measure of the cursor&#039;s position. The range of [-7,7] becomes [0,14000].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We will also set the events corresponding to the game state within &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;. First we will set &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt; to represent when the game is in these states. To do this, at the beginning and end of &amp;lt;code&amp;gt;PreTrial()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Trial()&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PostTrial()&amp;lt;/code&amp;gt;, we will set the corresponding event values to 1 and 0, respectively.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator PreTrial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PreFeedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
IEnumerator Trial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
IEnumerator PostTrial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PostFeedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also set the events which happen at the end of each trial. The &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt; event is activated when the subject hits the target, and the &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; event is activated when the subject runs out of time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator Trial() {&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 0);&lt;br /&gt;
    if (lastTrialSucceeded) {&lt;br /&gt;
	bci.Control.PulseEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
    } else {&lt;br /&gt;
	bci.Control.PulseEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Notice that we use &amp;lt;code&amp;gt;BCI2000Remote.PulseEvent()&amp;lt;/code&amp;gt; rather than &amp;lt;code&amp;gt;BCI2000Remote.SetEvent()&amp;lt;/code&amp;gt;. This results in the event being set to the value &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for exactly one sample duration, then returning to zero.&lt;br /&gt;
&lt;br /&gt;
We will also record the position of the target. Similarly to the cursor, we will transform the target&#039;s coordinates to be a positive integer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator PreTrial() {&lt;br /&gt;
    ...&lt;br /&gt;
    target.SetActive(true);&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;TargetPositionX&amp;quot;, (uint) ((target.transform.position.x + 7) * 1000));&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;TargetPositionY&amp;quot;, (uint) ((target.transform.position.y + 4.5) * 1000));&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The last event we need to set is the trial number.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
IEnumerator ControlLoop() {&lt;br /&gt;
    ...&lt;br /&gt;
    while (IsContinue() &amp;amp;&amp;amp; trials &amp;lt; n_trials) {&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;TrialNumber&amp;quot;, trials + 1);&lt;br /&gt;
	...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Unity Player Settings===&lt;br /&gt;
Additionally, due to how Unity detects changes in BCI2000 state, it must be allowed to run in the background.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity menu bar:&lt;br /&gt;
    Edit &amp;gt; Project Settings &amp;gt; Player &amp;gt; Resolution and Presentation&lt;br /&gt;
Check the &amp;quot;Run In Background&amp;quot; box.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Usage===&lt;br /&gt;
&lt;br /&gt;
Now, when the Unity application runs, BCI2000 will open. From here, parameters can be set via the Config window, then clicking Set Config and Start will start data collection.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000&amp;diff=11772</id>
		<title>User Tutorial:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000&amp;diff=11772"/>
		<updated>2025-03-14T03:57:46Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Fixed broken code block&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Red text blocks contain detailed instructions for the higher-level instructions preceding them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example comprehensively demonstrates many of the capabilities of UnityBCI2000, and as such, is more than what is necessary for many usecases. If you just want to use BCI2000 as a logging backend for an existing Unity application, see [[User Tutorial:UnityBCI2000 Barebones]].&lt;br /&gt;
&lt;br /&gt;
===Download Unity===&lt;br /&gt;
&lt;br /&gt;
Download Unity Hub from [https://unity3d.com Unity].&lt;br /&gt;
&lt;br /&gt;
===Setting Up BCI2000===&lt;br /&gt;
&lt;br /&gt;
Follow the instructions starting with [https://www.bci2000.org/mediawiki/index.php/Programming_Howto:Install_Prerequisites] to download BCI2000. &lt;br /&gt;
&lt;br /&gt;
===Setting Up UnityBCI2000===&lt;br /&gt;
Download UnityBCI2000 from its GitHub page, [https://github.com/neurotechcenter/UnityBCI2000]. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the &amp;quot;Releases&amp;quot; section on the right side of the page. This tutorial is intended to be used with UnityBCI2000 version 2.0.0, so scroll to that release and click on the files BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to download them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Download Tutorial Project===&lt;br /&gt;
Download the CursorTask3 repository from [https://github.com/Personator01/CursorTask3 GitHub].&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Either:&lt;br /&gt;
	-Clone the git repository&lt;br /&gt;
	-Download the respository directly from GitHub&lt;br /&gt;
		-&amp;gt; Click the green &amp;quot;Code&amp;quot; button &lt;br /&gt;
		-&amp;gt; Select &amp;quot;Download ZIP&amp;quot;&lt;br /&gt;
		-&amp;gt; Extract the zip file&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The download directory contains two versions of the CursorTask3 project. One, CursorTask3-BCI2K, contains an example implementation of the task with BCI2000 integration. The other, CursorTask3-NoBCI2K, contains the same task without BCI2000 integration. This tutorial is a step by step guide on turning that second project into the first. &lt;br /&gt;
&lt;br /&gt;
===Opening the project===&lt;br /&gt;
Open the project in the Unity Editor, and open the CursorTask scene.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Open Unity Hub.&lt;br /&gt;
Click the &amp;quot;Add&amp;quot; button in the top right corner.&lt;br /&gt;
Navigate to the CursorTask3 directory downloaded previously.&lt;br /&gt;
Select the CursorTask3-NoBCI2K directory to add it to Unity Hub.&lt;br /&gt;
Click the CursorTask3-NoBCI2K project in the Unity Hub.&lt;br /&gt;
If prompted to select a version of Unity to use or install, select Unity 2022.3. The specific release number of Unity 2022.3 should not matter, so select the one labeled &amp;quot;LTS&amp;quot; for consistency.&lt;br /&gt;
The lower panel (the asset browser) should already show the Assets/Scenes directory, which contains a single scene called SampleScene.&lt;br /&gt;
Double-click SampleScene. This should open a scene with a box containing various lights and objects.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you wish to view the completed implementation, repeat these steps, but instead open the CursorTask3-BCI2K directory. Note that in order to use the completed implementation, you will still need to set the Operator Path value of the UnityBCI2000 component of the BCI2000 game object.&lt;br /&gt;
&lt;br /&gt;
===Adding UnityBCI2000 to the project===&lt;br /&gt;
Add BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to your project&#039;s assets.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click Assets &amp;gt; Open Containing Folder to open your project directory.&lt;br /&gt;
Place the BCI2000RemoteNETStandard.dll and UnityBCI2000.cs files in the Assets folder.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add an empty GameObject called &#039;BCI2000&#039;. This will hold the scripts for controlling BCI2000. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click GameObject &amp;gt; Create Empty to create an empty GameObject, and name it &#039;BCI2000&#039;. (The object&#039;s specific name does not actually matter, it is only needed in order to reference it within other scripts)&lt;br /&gt;
You will notice that it now appears in the Scene Hierarchy panel, on the left side of the screen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the UnityBCI2000 component to the object.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the object in the Hierarchy panel. This will open it in the Inspector panel (the panel on the right side of the screen)&lt;br /&gt;
In the inspector, below the new object&#039;s Transform component, click the &amp;quot;Add Component&amp;quot; button, which will open up a small window for adding components.&lt;br /&gt;
Within this window, select Scripts &amp;gt; Unity BCI2000 to add the UnityBCI2000 component.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Configuring UnityBCI2000===&lt;br /&gt;
The inspector panel now contains the configuration options for UnityBCI2000. Set the options as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Local Operator&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This will start the operator on your computer when the Unity scene initializes. If we were instead connecting to an already-running instance of BCI2000, or an instance on another computer, this box would be deselected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Path&amp;lt;/code&amp;gt;: The path to the Operator executable. This will look something like this on Windows (C://path/to/bci2000/prog/Operator.exe)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Address&amp;lt;/code&amp;gt;: 127.0.0.1&lt;br /&gt;
&lt;br /&gt;
This is the address of the machine on which BCI2000 is running. Since we are running BCI2000 on the same computer as Unity, we leave it as 127.0.0.1, the loopback address.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Port&amp;lt;/code&amp;gt;: 3999&lt;br /&gt;
&lt;br /&gt;
This is the port on which BCI2000 is listening for commands. By default, it is 3999.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Modules&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to start the requested Signal Source, Signal Processing, and Application modules when the Unity scene initializes. Similarly to Start Local Operator, we would deselect this box if connecting to an already-running instance. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to start a data collection run when the scene starts. Since we will be using BCI2000 itself to set experiment parameters, we will instead wait for BCI2000 to start from Unity, and thus will leave the box unchecked. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Stop With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to stop collecting data when the scene stops. Since we will be controlling BCI2000 directly, rather than entirely through Unity, we will leave this unchecked.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Shutdown With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to shut down alongside the Unity scene. Whether or not this value is set ultimately doesn&#039;t matter much, especially if Start Local Operator is checked. The data will be saved whether or not BCI2000 shuts down. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 1&amp;lt;/code&amp;gt;: SignalGenerator&lt;br /&gt;
&lt;br /&gt;
The signal source module to start. We will use SignalGenerator, which generates a signal without any connected hardware.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 2&amp;lt;/code&amp;gt;: DummySignalProcessing&lt;br /&gt;
&lt;br /&gt;
The signal processing module to start. We will use DummySignalProcessing, as there is no processing to do.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 3&amp;lt;/code&amp;gt;: DummyApplication&lt;br /&gt;
&lt;br /&gt;
The Application module to start. Since we are using Unity, we will use DummyApplication.&lt;br /&gt;
&lt;br /&gt;
===Setting References===&lt;br /&gt;
In order for the game&#039;s scripts to communicate with BCI2000, they need to hold a reference to the UnityBCI2000 component.&lt;br /&gt;
There are three scripts which will need to communicate with BCI2000. They are &amp;lt;code&amp;gt;GameControl.cs, BallControl.cs, and MCursorControl.cs&amp;lt;/code&amp;gt;.&lt;br /&gt;
These scripts are each located within the Assets directory of the Unity project. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
As before, select Assets &amp;gt; Open Containing Folder to open the project directory, then open the Assets folder. &lt;br /&gt;
For each script, open it in a text editor.&lt;br /&gt;
Add a data member of type UnityBCI2000 to the class, like so:&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
Place the member definition above the Awake() method, for readability.&lt;br /&gt;
Within the Awake() method, set this reference to the UnityBCI2000 component.&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Each of the three scripts should contain a section like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
	void Awake() {&lt;br /&gt;
		bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
		...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding Events===&lt;br /&gt;
[https://www.bci2000.org/mediawiki/index.php/Programming_Reference:Events Events] are the primary way that non-signal experiment data is recorded in BCI2000. They are timestamped integer values which are encoded alongside the signal data in BCI2000 output files. Due to BCI2000&#039;s design, events must be added during a very specific part of its startup sequence, which is immediately after the BCI2000 operator starts, and before any of the modules start. As such, we cannot simply call &amp;lt;code&amp;gt;AddEvent()&amp;lt;/code&amp;gt; whenever we want. Furthermore, the order in which Unity objects initialize is undefined, so it cannot even be guaranteed that calling &amp;lt;code&amp;gt;AddEvent&amp;lt;/code&amp;gt; at a specific time will be consistent across multiple projects. As such, UnityBCI2000 provides a couple of methods for sending commands at well-defined points within the startup sequence. These two methods, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; allow BCI2000 commands to be sent while the operator is in the state Idle (immediately before starting its modules) and when the operator is in the state Connected (after starting and connecting to the modules. Below is an example of using those methods to add and show an event in BCI2000.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Script : MonoBehaviour {&lt;br /&gt;
    UnityBCI2000 bci;&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000Object&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;AnEvent&amp;quot;, 32);&lt;br /&gt;
	});&lt;br /&gt;
    }&lt;br /&gt;
    void Start() {&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;AnEvent&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As seen above, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; take a delegate (C#&#039;s term for a callback/closure/functor/etc.) with a single parameter of type &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt; (in this case called &amp;quot;remote&amp;quot;). The lambda expression given to the call to &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; uses the method &amp;lt;code&amp;gt;BCI2000Remote.AddEvent()&amp;lt;/code&amp;gt; to add an event called &amp;quot;AnEvent&amp;quot; with a bit width of 32 bits. The call to &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; tells BCI2000 to show the event&#039;s value in a graphical window. A description of the BCI2000Remote class can be found [https://www.bci2000.org/mediawiki/index.php/Contributions:BCI2000RemoteNET here], and API documentation can be found [https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html here].&lt;br /&gt;
&lt;br /&gt;
We will now add the events relevant to the Cursor Task. Open the &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt; script, and modify its &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; to add the events &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; with bit width 1. Additionally, add the events &amp;lt;code&amp;gt;TrialNumber&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetPositionX&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;TargetPositionY&amp;lt;/code&amp;gt; with width 16. These will encode the task state and number of trials.&lt;br /&gt;
We also need to set a parameter value so that the signal will be set to the mouse position. Using &amp;lt;code&amp;gt;BCI2000Remote.SetParameter()&amp;lt;/code&amp;gt;, we will set the &amp;lt;code&amp;gt;ModulateAmplitude&amp;lt;/code&amp;gt; parameter to 1.&lt;br /&gt;
&lt;br /&gt;
Open the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, and within the &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; function, add events &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt;, with width 16. Show these events in a visualization window with &amp;lt;code&amp;gt;Visualize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your two scripts should now look like this: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs &lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TrialNumber&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetPositionY&amp;quot;, 16);&lt;br /&gt;
	    remote.SetParameter(&amp;quot;ModulateAmplitude&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
	    });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionY&amp;quot;, 16);&lt;br /&gt;
	    });&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionX&amp;quot;);&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionY&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using BCI2000 Parameters===&lt;br /&gt;
====Adding Parameters====&lt;br /&gt;
BCI2000&#039;s operator contains an interface for changing experiment parameters before running a task. By making use of this interface we can change the behavior of the task dynamically, without needing to rebuild the Unity project each time. In order to do this we need to define the parameters and add them to BCI2000, and later read their values after the operator has a chance to change them. &amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;This section is not strictly necessary. The project will function the same whether this is done or not, just without the option to change parameters at runtime. &amp;lt;/span&amp;gt; &lt;br /&gt;
&lt;br /&gt;
First, we define add parameters to BCI2000. Similarly to events, parameters must be added while the Operator is in the &amp;lt;code&amp;gt;Idle&amp;lt;/code&amp;gt; state, so we add them inside of &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt;, like below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public int someParameter = 5;&lt;br /&gt;
void Awake() {&lt;br /&gt;
    bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	remote.AddParameter(&amp;quot;Application:ParameterPlace&amp;quot;, &amp;quot;SomeParameter&amp;quot;, someParameter.ToString()); &lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
The first argument to the method is the section into which the parameter is placed, that is, on which tab and under which heading the parameter will appear within the Operator&#039;s parameter editor window (note that the section is not a scope, all parameter names must be unique). The second argument is the parameter name itself. The third argument is the default value of the parameter. We pass in the value of the parameter, so when it appears in the Operator, its default value is 5 (or another value if it has been changed in the Unity Editor). Note that all parameters are handled as strings, so we need to convert its value to a string when sending it.&lt;br /&gt;
&lt;br /&gt;
For &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;, we will add parameters corresponding to the Pre-Feedback, Feedback, and Post-Feedback durations, Target Radius, and Number of Trials.&lt;br /&gt;
For &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt;, we will add parameters corresponding to the Acceleration Scale, Coefficient of Restitution, Coefficient of Drag, and Attraction Curve Coefficient (how quickly the Ball moves to follow the Mouse Cursor).&lt;br /&gt;
For &amp;lt;code&amp;gt;MCursorControl.cs&amp;lt;/code&amp;gt;, we will add a parameter corresponding to the Rolling Maximum Amount.&lt;br /&gt;
&lt;br /&gt;
Your scripts should look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		remote.AddEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
		...&lt;br /&gt;
&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;PreFeedbackDuration&amp;quot;, preFeedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;FeedbackDuration&amp;quot;, feedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;PostFeedbackDuration&amp;quot;, postFeedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;TargetRadius&amp;quot;, targetRadius.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;Trials&amp;quot;, n_trials.ToString());&lt;br /&gt;
		});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;AccelerationScale&amp;quot;, accelerationScale.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;CoeffOfRestitution&amp;quot;, coefficientOfRestitution.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;CoeffOfDrag&amp;quot;, coefficientOfDrag.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;AccelerationCurve&amp;quot;, attractionCurveCoefficient.ToString());&lt;br /&gt;
		})}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; MCursorControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;RollingMaximumAmount&amp;quot;, rollingMaximumAmount.ToString());&lt;br /&gt;
		});&lt;br /&gt;
}&lt;br /&gt;
		&lt;br /&gt;
&lt;br /&gt;
====Reading and Validating Parameters====&lt;br /&gt;
Since we set the parameters within the BCI2000 operator, we need some way to read them back into Unity after they have been set. Specifically, we need to read them after the operator clicks the &amp;quot;Set Config&amp;quot; button within the BCI2000 Operator. How this timing synchronization is covered in the section [[Reacting to BCI2000 state changes]]. In this section we will cover reading and validating parameters.&lt;br /&gt;
&lt;br /&gt;
A method called &amp;lt;code&amp;gt;SetConfig&amp;lt;/code&amp;gt; is provided in each of the scripts in which we added parameters previously. This method will be called after the operator changes parameters. In this method we will read in parameters and parse them into valid values. Using the same example parameter as before:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void SetConfig() {&lt;br /&gt;
    try {&lt;br /&gt;
	someParameter = int.Parse(bci.Control.GetParameter(&amp;quot;SomeParameter&amp;quot;));&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
	bci.Error(&amp;quot;Could not parse parameter SomeParameter as int&amp;quot;);&lt;br /&gt;
	throw e;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that since we are now working outside the BCI2000 startup sequence, we use &amp;lt;code&amp;gt;UnityBCI2000.Control&amp;lt;/code&amp;gt; to call &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt; methods directly, rather than using &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt;. We also wrap the call within a try/catch block so that we can report erroneous parameters back to the operator. This is optional, but it keeps your project from failing silently and is otherwise useful for doing things like distributing your Unity project as a standalone executable, where logging errors can only be done through the BCI2000 operator. You can also write a helper function which handles parsing and error reporting for you:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int GetParseParameterInt(string paramName) {&lt;br /&gt;
    int p_val = bci.Control.GetParameter(&amp;quot;SomeParameter&amp;quot;);&lt;br /&gt;
    try {&lt;br /&gt;
	someParameter = int.Parse(p_val);&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
	bci.Error($&amp;quot;Could not parse parameter {paramName} (value {p_val}) as int&amp;quot;);&lt;br /&gt;
	throw e;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Unfortunately, since the version of C# used by Unity does not support type-parameterized parsing, you must write one of these helper functions for each type of data you want to store in a parameter (int, float, double, etc.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Read back the parameters added in the previous step. Your scripts should look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs &lt;br /&gt;
void SetConfig() {&lt;br /&gt;
	try {&lt;br /&gt;
	   preFeedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;PreFeedbackDuration&amp;quot;));&lt;br /&gt;
	   feedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;FeedbackDuration&amp;quot;));&lt;br /&gt;
	   postFeedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;PostFeedbackDuration&amp;quot;));&lt;br /&gt;
	   targetRadius = float.Parse(bci.Control.GetParameter(&amp;quot;TargetRadius&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse one of PreFeedbackDuration, FeedbackDuration, PostFeedbackDuration, or TargetRadius as a float&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
	try {&lt;br /&gt;
	   n_trials = int.Parse(bci.Control.GetParameter(&amp;quot;Trials&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse Trials as an int&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if (preFeedbackDuration &amp;lt; COUNTDOWN_DURATION) {&lt;br /&gt;
	   bci.Error(&amp;quot;preFeedbackDuration must be greater than or equal to 2.25&amp;quot;);&lt;br /&gt;
	   throw new Exception(&amp;quot;preFeedbackDuration must be greater than or equal to 2.25&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
    public void SetConfig() {&lt;br /&gt;
	try {&lt;br /&gt;
	   accelerationScale = float.Parse(bci.Control.GetParameter(&amp;quot;AccelerationScale&amp;quot;));&lt;br /&gt;
	   coefficientOfRestitution = float.Parse(bci.Control.GetParameter(&amp;quot;CoeffOfRestitution&amp;quot;));&lt;br /&gt;
	   coefficientOfDrag = float.Parse(bci.Control.GetParameter(&amp;quot;CoeffOfDrag&amp;quot;));&lt;br /&gt;
	   attractionCurveCoefficient = float.Parse(bci.Control.GetParameter(&amp;quot;AccelerationCurve&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse one of AccelerationScale, CoeffOfRestitution, CoeffOfDrag, AccelerationCurve as float&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; MCursorControl.cs&lt;br /&gt;
public void SetConfig() {&lt;br /&gt;
    try {&lt;br /&gt;
       rollingMaximumAmount = int.Parse(bci.Control.GetParameter(&amp;quot;RollingMaximumAmount&amp;quot;));&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
       bci.Error(&amp;quot;Could not parse parameter RollingMaximumAmount as int&amp;quot;);&lt;br /&gt;
       throw e;&lt;br /&gt;
    }&lt;br /&gt;
    signalsX = new int[rollingMaximumAmount];&lt;br /&gt;
    signalsY = new int[rollingMaximumAmount];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;, we also verify that the Pre-Feedback Duration is longer than the duration of the countdown that happens before each trial, and report errors to BCI2000 accordingly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Reacting to BCI2000 state changes===&lt;br /&gt;
Since we will be controlling the Unity task from BCI2000, we need some way to wait for BCI2000 to be in a specific state, for example, waiting for the operator to click Start and put the Operator Module into the Running state. UnityBCI2000 provides a method for this, the &amp;lt;code&amp;gt;UnityBCI2000.PollSystemState&amp;lt;/code&amp;gt; method. In order to wait for the Operator Module to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Running));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will check once per frame whether or not the Operator is in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state, and only continue once BCI2000 is in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state. Note that since &amp;lt;code&amp;gt;SystemState&amp;lt;/code&amp;gt; is a member of &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt;, we also need to add a &amp;lt;code&amp;gt;using BCI2000RemoteNET&amp;lt;/code&amp;gt; statement to our script.&lt;br /&gt;
&lt;br /&gt;
In our case, we need to react to the operator setting the parameters, starting the data collection, and stopping the data collection. These correspond to the Operator Module entering the &amp;lt;code&amp;gt;Resting&amp;lt;/code&amp;gt; state, entering the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state, and exiting the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt; script, we will wait for the system to be in the &amp;lt;code&amp;gt;Resting&amp;lt;/code&amp;gt; state at the start of the &amp;lt;code&amp;gt;ControLoop&amp;lt;/code&amp;gt; method, and wait for the system to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state immediately before the entering the trial loop. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
&lt;br /&gt;
    IEnumerator ControlLoop() {&lt;br /&gt;
	while (True) {&lt;br /&gt;
&lt;br /&gt;
	   StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Resting));&lt;br /&gt;
&lt;br /&gt;
	   try {&lt;br /&gt;
		...&lt;br /&gt;
	   } catch (Exception e) {&lt;br /&gt;
		continue;&lt;br /&gt;
	   }&lt;br /&gt;
	&lt;br /&gt;
	   int trials = 0;&lt;br /&gt;
&lt;br /&gt;
	   StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Running));&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	   yield return new WaitForSeconds(preRunDuration);&lt;br /&gt;
	   while (IsContinue() &amp;amp;&amp;amp; trials &amp;lt; n_trials) {&lt;br /&gt;
		...&lt;br /&gt;
	   }&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need to check for the operator stopping data collection, so we modify the &amp;lt;code&amp;gt;IsContinue()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bool IsContinue () {&lt;br /&gt;
	return bci.Control.GetSystemState() == BCI2000Remote.SystemState.Running;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remember to add &amp;lt;code&amp;gt;using BCI2000RemoteNET;&amp;lt;/code&amp;gt; to the top of the script, so you can access the &amp;lt;code&amp;gt;SystemState&amp;lt;/code&amp;gt; enum.&lt;br /&gt;
&lt;br /&gt;
===Reading the control signal===&lt;br /&gt;
We will be using the control signal to control the cursor. Open the &amp;lt;code&amp;gt;MCursorControl.cs&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
The commented out section of the &amp;lt;code&amp;gt;GetPos()&amp;lt;/code&amp;gt; method contains the code required to turn the control signal waveform coming from the Signal Source and Signal Processing modules into screen coordinates. &lt;br /&gt;
Uncomment the commented part and delete the line &amp;lt;code&amp;gt;Ray r = camera.ScreenPointToRay(Input.MousePosition);&amp;lt;/code&amp;gt;.&lt;br /&gt;
Change the &amp;lt;code&amp;gt;double signalX = 0;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;double signalY = 0;&amp;lt;/code&amp;gt; to. &lt;br /&gt;
&lt;br /&gt;
Your &amp;lt;code&amp;gt;GetPos()&amp;lt;/code&amp;gt; method should look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    Vector3 GetPos() {&lt;br /&gt;
	double signalX = bci.Control.GetSignal(1, bci.CurrentSampleOffset());&lt;br /&gt;
	double signalY = bci.Control.GetSignal(2, bci.CurrentSampleOffset());&lt;br /&gt;
	signalsX[signalIndex] = signalX;&lt;br /&gt;
	signalsY[signalIndex] = signalY;&lt;br /&gt;
	&lt;br /&gt;
	signalIndex = signalIndex + 1 &amp;gt;= rollingMaximumAmount ? 0 : signalIndex + 1;&lt;br /&gt;
	double max_x = signalsX.Max();&lt;br /&gt;
	double max_y = signalsY.Max();&lt;br /&gt;
	Ray r = camera.ScreenPointToRay(new Vector3((float) max_x * Screen.width, (float) max_y * Screen.height, 0));&lt;br /&gt;
	float p;&lt;br /&gt;
	if (!plane.Raycast(r, out p)) {&lt;br /&gt;
	   throw new Exception(&amp;quot;error casting ray to plane, invalid mouse position?&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	return r.GetPoint(p);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the use of the &amp;lt;code&amp;gt;UnityBCI2000.CurrentSampleOffset()&amp;lt;/code&amp;gt; method. This is a special method which gets the offset into the current block such that the sample is exactly one block length later than when it was collected by the hardware. This is to normalize the latency between when the hardware collects the signal and the software receives the signal, due to how BCI2000 processes data in blocks.&lt;br /&gt;
&lt;br /&gt;
===Sending events back to BCI2000===&lt;br /&gt;
&lt;br /&gt;
The primary way to communicate game state back to BCI2000 is via the use of Events, which are integer values encoded alongside the signal data.&lt;br /&gt;
&lt;br /&gt;
We will send the events that we added in a previous section.&lt;br /&gt;
&lt;br /&gt;
First, we will send back the current position of the cursor. Within the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, within the &amp;lt;code&amp;gt;Update()&amp;lt;/code&amp;gt; method, immediately after &amp;lt;code&amp;gt;Move()&amp;lt;/code&amp;gt; is called, set the &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt; events. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
void Update() {&lt;br /&gt;
    ...&lt;br /&gt;
    if (isTrialRunning) {&lt;br /&gt;
	...&lt;br /&gt;
	Move();&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;CursorPositionX&amp;quot;, (uint) ((transform.position.x + 7) * 1000));&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;CursorPositionY&amp;quot;, (uint) ((transform.position.y + 4.5) * 1000));&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that we transform the value of the cursor&#039;s position. This is because events in BCI2000 are represented as unsigned integers, so, for example, the cursor&#039;s range of movement in the x axis, -7 to 7, would not be directly representable within a BCI2000 event, so we add 7 so it is positive, and multiply by 1000 so that we have a more precise measure of the cursor&#039;s position. The range of [-7,7] becomes [0,14000].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We will also set the events corresponding to the game state within &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;. First we will set &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt; to represent when the game is in these states. To do this, at the beginning and end of &amp;lt;code&amp;gt;PreTrial()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Trial()&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PostTrial()&amp;lt;/code&amp;gt;, we will set the corresponding event values to 1 and 0, respectively.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator PreTrial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PreFeedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
IEnumerator Trial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
IEnumerator PostTrial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PostFeedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also set the events which happen at the end of each trial. The &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt; event is activated when the subject hits the target, and the &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; event is activated when the subject runs out of time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator Trial() {&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 0);&lt;br /&gt;
    if (lastTrialSucceeded) {&lt;br /&gt;
	bci.Control.PulseEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
    } else {&lt;br /&gt;
	bci.Control.PulseEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Notice that we use &amp;lt;code&amp;gt;BCI2000Remote.PulseEvent()&amp;lt;/code&amp;gt; rather than &amp;lt;code&amp;gt;BCI2000Remote.SetEvent()&amp;lt;/code&amp;gt;. This results in the event being set to the value &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for exactly one sample duration, then returning to zero.&lt;br /&gt;
&lt;br /&gt;
We will also record the position of the target. Similarly to the cursor, we will transform the target&#039;s coordinates to be a positive integer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator PreTrial() {&lt;br /&gt;
    ...&lt;br /&gt;
    target.SetActive(true);&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;TargetPositionX&amp;quot;, (uint) ((target.transform.position.x + 7) * 1000));&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;TargetPositionY&amp;quot;, (uint) ((target.transform.position.y + 4.5) * 1000));&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The last event we need to set is the trial number.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
IEnumerator ControlLoop() {&lt;br /&gt;
    ...&lt;br /&gt;
    while (IsContinue() &amp;amp;&amp;amp; trials &amp;lt; n_trials) {&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;TrialNumber&amp;quot;, trials + 1);&lt;br /&gt;
	...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Unity Player Settings===&lt;br /&gt;
Additionally, due to how Unity detects changes in BCI2000 state, it must be allowed to run in the background.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity menu bar:&lt;br /&gt;
    Edit &amp;gt; Project Settings &amp;gt; Player &amp;gt; Resolution and Presentation&lt;br /&gt;
Check the &amp;quot;Run In Background&amp;quot; box.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Usage===&lt;br /&gt;
&lt;br /&gt;
Now, when the Unity application runs, BCI2000 will open. From here, parameters can be set via the Config window, then clicking Set Config and Start will start data collection.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=11534</id>
		<title>Contributions:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=11534"/>
		<updated>2024-08-16T14:51:25Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
UnityBCI2000 is an extension for the Unity game/3D application development platform that enables control of and communication with the BCI2000 brain-computer interface research platform. It consists of a .NET library for communication with the BCI2000 operator and a Unity package which provides integration with Unity itself.&lt;br /&gt;
&lt;br /&gt;
==Prerequisites==&lt;br /&gt;
Alongside UnityBCI2000, install Unity per the instructions at [https://unity.com/download the Unity website], and the [[Programming_Howto:Building_and_Customizing_BCI2000|BCI2000 setup tutorial]].&lt;br /&gt;
&lt;br /&gt;
==Adding UnityBCI2000 to a Unity Project==&lt;br /&gt;
Download the latest release of UnityBCI2000 from [https://github.com/neurotechcenter/UnityBCI2000 GitHub]. Place the &amp;lt;code&amp;gt;UnityBCI2000.cs&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;BCI2000RemoteNETStandard.dll&amp;lt;/code&amp;gt; files in the &amp;lt;code&amp;gt;Assets&amp;lt;/code&amp;gt; folder of the Unity project.&lt;br /&gt;
&lt;br /&gt;
Add the &amp;lt;code&amp;gt;UnityBCI2000.cs&amp;lt;/code&amp;gt; script to a Unity object as a component.&lt;br /&gt;
&lt;br /&gt;
For a comprehensive tutorial of integrating BCI2000 with a Unity project, see [[User Tutorial:UnityBCI2000]]. &lt;br /&gt;
&lt;br /&gt;
For a minimal tutorial on using BCI2000 as a logging service for Unity, see [[User Tutorial:UnityBCI2000 Barebones]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Documentation==&lt;br /&gt;
[https://bci2000.org/BCI2000Unity/classUnityBCI2000.html Interface documentation]&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=11533</id>
		<title>Contributions:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=11533"/>
		<updated>2024-08-16T14:50:46Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
UnityBCI2000 is an extension for the Unity game/3D application development platform that enables control of and communication with the BCI2000 brain-computer interface research platform. It consists of a .NET library for communication with the BCI2000 operator and a Unity package which provides integration with Unity itself.&lt;br /&gt;
&lt;br /&gt;
==Prerequisites==&lt;br /&gt;
Alongside UnityBCI2000, install Unity per the instructions at [https://unity.com/download the Unity website], and the [[Programming_Howto:Install_Prerequisites|BCI2000 setup tutorial]].&lt;br /&gt;
&lt;br /&gt;
==Adding UnityBCI2000 to a Unity Project==&lt;br /&gt;
Download the latest release of UnityBCI2000 from [https://github.com/neurotechcenter/UnityBCI2000 GitHub]. Place the &amp;lt;code&amp;gt;UnityBCI2000.cs&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;BCI2000RemoteNETStandard.dll&amp;lt;/code&amp;gt; files in the &amp;lt;code&amp;gt;Assets&amp;lt;/code&amp;gt; folder of the Unity project.&lt;br /&gt;
&lt;br /&gt;
Add the &amp;lt;code&amp;gt;UnityBCI2000.cs&amp;lt;/code&amp;gt; script to a Unity object as a component.&lt;br /&gt;
&lt;br /&gt;
For a comprehensive tutorial of integrating BCI2000 with a Unity project, see [[User Tutorial:UnityBCI2000]]. &lt;br /&gt;
&lt;br /&gt;
For a minimal tutorial on using BCI2000 as a logging service for Unity, see [[User Tutorial:UnityBCI2000 Barebones]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Documentation==&lt;br /&gt;
[https://bci2000.org/BCI2000Unity/classUnityBCI2000.html Interface documentation]&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=11532</id>
		<title>Contributions:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=11532"/>
		<updated>2024-08-16T14:50:20Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
UnityBCI2000 is an extension for the Unity game/3D application development platform that enables control of and communication with the BCI2000 brain-computer interface research platform. It consists of a .NET library for communication with the BCI2000 operator and a Unity package which provides integration with Unity itself.&lt;br /&gt;
&lt;br /&gt;
==Prerequisites==&lt;br /&gt;
Alongside UnityBCI2000, install Unity per the instructions at [https://unity.com/download the Unity website], and the [[https://www.bci2000.org/mediawiki/index.php/Programming_Howto:Install_Prerequisites|BCI2000 setup tutorial]].&lt;br /&gt;
&lt;br /&gt;
==Adding UnityBCI2000 to a Unity Project==&lt;br /&gt;
Download the latest release of UnityBCI2000 from [https://github.com/neurotechcenter/UnityBCI2000 GitHub]. Place the &amp;lt;code&amp;gt;UnityBCI2000.cs&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;BCI2000RemoteNETStandard.dll&amp;lt;/code&amp;gt; files in the &amp;lt;code&amp;gt;Assets&amp;lt;/code&amp;gt; folder of the Unity project.&lt;br /&gt;
&lt;br /&gt;
Add the &amp;lt;code&amp;gt;UnityBCI2000.cs&amp;lt;/code&amp;gt; script to a Unity object as a component.&lt;br /&gt;
&lt;br /&gt;
For a comprehensive tutorial of integrating BCI2000 with a Unity project, see [[User Tutorial:UnityBCI2000]]. &lt;br /&gt;
&lt;br /&gt;
For a minimal tutorial on using BCI2000 as a logging service for Unity, see [[User Tutorial:UnityBCI2000 Barebones]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Documentation==&lt;br /&gt;
[https://bci2000.org/BCI2000Unity/classUnityBCI2000.html Interface documentation]&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=11531</id>
		<title>Contributions:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=11531"/>
		<updated>2024-08-16T13:37:27Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
UnityBCI2000 is an extension for the Unity game/3D application development platform that enables control of and communication with the BCI2000 brain-computer interface research platform. It consists of a .NET library for communication with the BCI2000 operator and a Unity package which provides integration with Unity itself.&lt;br /&gt;
&lt;br /&gt;
==Prerequisites==&lt;br /&gt;
Alongside UnityBCI2000, install Unity per the instructions at [https://unity.com/download the Unity website], and the [BCI2000 setup tutorial https://www.bci2000.org/mediawiki/index.php/Programming_Howto:Install_Prerequisites].&lt;br /&gt;
&lt;br /&gt;
==Adding UnityBCI2000 to a Unity Project==&lt;br /&gt;
Download the latest release of UnityBCI2000 from [https://github.com/neurotechcenter/UnityBCI2000 GitHub]. Place the &amp;lt;code&amp;gt;UnityBCI2000.cs&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;BCI2000RemoteNETStandard.dll&amp;lt;/code&amp;gt; files in the &amp;lt;code&amp;gt;Assets&amp;lt;/code&amp;gt; folder of the Unity project.&lt;br /&gt;
&lt;br /&gt;
Add the &amp;lt;code&amp;gt;UnityBCI2000.cs&amp;lt;/code&amp;gt; script to a Unity object as a component.&lt;br /&gt;
&lt;br /&gt;
For a comprehensive tutorial of integrating BCI2000 with a Unity project, see [[User Tutorial:UnityBCI2000]]. &lt;br /&gt;
&lt;br /&gt;
For a minimal tutorial on using BCI2000 as a logging service for Unity, see [[User Tutorial:UnityBCI2000 Barebones]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Documentation==&lt;br /&gt;
[https://bci2000.org/BCI2000Unity/classUnityBCI2000.html Interface documentation]&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=11530</id>
		<title>Contributions:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=11530"/>
		<updated>2024-08-16T13:37:15Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
UnityBCI2000 is an extension for the Unity game/3D application development platform that enables control of and communication with the BCI2000 brain-computer interface research platform. It consists of a .NET library for communication with the BCI2000 operator and a Unity package which provides integration with Unity itself.&lt;br /&gt;
&lt;br /&gt;
==Prerequisites==&lt;br /&gt;
Alongside UnityBCI2000, install Unity per the instructions at [https://unity.com/download the Unity website], and the [BCI2000 setup tutorial https://www.bci2000.org/mediawiki/index.php/Programming_Howto:Install_Prerequisites].&lt;br /&gt;
&lt;br /&gt;
==Adding UnityBCI2000 to a Unity Project==&lt;br /&gt;
Download the latest release of UnityBCI2000 from [https://github.com/neurotechcenter/UnityBCI2000 GitHub]. Place the &amp;lt;code&amp;gt;UnityBCI2000.cs&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;BCI2000RemoteNETStandard.dll&amp;lt;/code&amp;gt; files in the &amp;lt;code&amp;gt;Assets&amp;lt;/code&amp;gt; folder of the Unity project.&lt;br /&gt;
&lt;br /&gt;
Add the &amp;lt;code&amp;gt;UnityBCI2000.cs&amp;lt;/code&amp;gt; script to a Unity object as a component.&lt;br /&gt;
&lt;br /&gt;
For a comprehensive tutorial of integrating BCI2000 with a Unity project, see [[User Tutorial:UnityBCI2000]]. &lt;br /&gt;
For a minimal tutorial on using BCI2000 as a logging service for Unity, see [[User Tutorial:UnityBCI2000 Barebones]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Documentation==&lt;br /&gt;
[https://bci2000.org/BCI2000Unity/classUnityBCI2000.html Interface documentation]&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000&amp;diff=11529</id>
		<title>User Tutorial:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000&amp;diff=11529"/>
		<updated>2024-08-16T02:31:51Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Red text blocks contain detailed instructions for the higher-level instructions preceding them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example comprehensively demonstrates many of the capabilities of UnityBCI2000, and as such, is more than what is necessary for many usecases. If you just want to use BCI2000 as a logging backend for an existing Unity application, see [[User Tutorial:UnityBCI2000 Barebones]].&lt;br /&gt;
&lt;br /&gt;
===Download Unity===&lt;br /&gt;
&lt;br /&gt;
Download Unity Hub from [https://unity3d.com Unity].&lt;br /&gt;
&lt;br /&gt;
===Setting Up BCI2000===&lt;br /&gt;
&lt;br /&gt;
Follow the instructions starting with [https://www.bci2000.org/mediawiki/index.php/Programming_Howto:Install_Prerequisites] to download BCI2000. &lt;br /&gt;
&lt;br /&gt;
===Setting Up UnityBCI2000===&lt;br /&gt;
Download UnityBCI2000 from its GitHub page, [https://github.com/neurotechcenter/UnityBCI2000]. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the &amp;quot;Releases&amp;quot; section on the right side of the page. This tutorial is intended to be used with UnityBCI2000 version 2.0.0, so scroll to that release and click on the files BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to download them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Download Tutorial Project===&lt;br /&gt;
Download the CursorTask3 repository from [https://github.com/Personator01/CursorTask3 GitHub].&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Either:&lt;br /&gt;
	-Clone the git repository&lt;br /&gt;
	-Download the respository directly from GitHub&lt;br /&gt;
		-&amp;gt; Click the green &amp;quot;Code&amp;quot; button &lt;br /&gt;
		-&amp;gt; Select &amp;quot;Download ZIP&amp;quot;&lt;br /&gt;
		-&amp;gt; Extract the zip file&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The download directory contains two versions of the CursorTask3 project. One, CursorTask3-BCI2K, contains an example implementation of the task with BCI2000 integration. The other, CursorTask3-NoBCI2K, contains the same task without BCI2000 integration. This tutorial is a step by step guide on turning that second project into the first. &lt;br /&gt;
&lt;br /&gt;
===Opening the project===&lt;br /&gt;
Open the project in the Unity Editor, and open the CursorTask scene.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Open Unity Hub.&lt;br /&gt;
Click the &amp;quot;Add&amp;quot; button in the top right corner.&lt;br /&gt;
Navigate to the CursorTask3 directory downloaded previously.&lt;br /&gt;
Select the CursorTask3-NoBCI2K directory to add it to Unity Hub.&lt;br /&gt;
Click the CursorTask3-NoBCI2K project in the Unity Hub.&lt;br /&gt;
If prompted to select a version of Unity to use or install, select Unity 2022.3. The specific release number of Unity 2022.3 should not matter, so select the one labeled &amp;quot;LTS&amp;quot; for consistency.&lt;br /&gt;
The lower panel (the asset browser) should already show the Assets/Scenes directory, which contains a single scene called SampleScene.&lt;br /&gt;
Double-click SampleScene. This should open a scene with a box containing various lights and objects.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you wish to view the completed implementation, repeat these steps, but instead open the CursorTask3-BCI2K directory. Note that in order to use the completed implementation, you will still need to set the Operator Path value of the UnityBCI2000 component of the BCI2000 game object.&lt;br /&gt;
&lt;br /&gt;
===Adding UnityBCI2000 to the project===&lt;br /&gt;
Add BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to your project&#039;s assets.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click Assets &amp;gt; Open Containing Folder to open your project directory.&lt;br /&gt;
Place the BCI2000RemoteNETStandard.dll and UnityBCI2000.cs files in the Assets folder.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add an empty GameObject called &#039;BCI2000&#039;. This will hold the scripts for controlling BCI2000. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click GameObject &amp;gt; Create Empty to create an empty GameObject, and name it &#039;BCI2000&#039;. (The object&#039;s specific name does not actually matter, it is only needed in order to reference it within other scripts)&lt;br /&gt;
You will notice that it now appears in the Scene Hierarchy panel, on the left side of the screen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the UnityBCI2000 component to the object.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the object in the Hierarchy panel. This will open it in the Inspector panel (the panel on the right side of the screen)&lt;br /&gt;
In the inspector, below the new object&#039;s Transform component, click the &amp;quot;Add Component&amp;quot; button, which will open up a small window for adding components.&lt;br /&gt;
Within this window, select Scripts &amp;gt; Unity BCI2000 to add the UnityBCI2000 component.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Configuring UnityBCI2000===&lt;br /&gt;
The inspector panel now contains the configuration options for UnityBCI2000. Set the options as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Local Operator&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This will start the operator on your computer when the Unity scene initializes. If we were instead connecting to an already-running instance of BCI2000, or an instance on another computer, this box would be deselected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Path&amp;lt;/code&amp;gt;: The path to the Operator executable. This will look something like this on Windows (C://path/to/bci2000/prog/Operator.exe)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Address&amp;lt;/code&amp;gt;: 127.0.0.1&lt;br /&gt;
&lt;br /&gt;
This is the address of the machine on which BCI2000 is running. Since we are running BCI2000 on the same computer as Unity, we leave it as 127.0.0.1, the loopback address.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Port&amp;lt;/code&amp;gt;: 3999&lt;br /&gt;
&lt;br /&gt;
This is the port on which BCI2000 is listening for commands. By default, it is 3999.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Modules&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to start the requested Signal Source, Signal Processing, and Application modules when the Unity scene initializes. Similarly to Start Local Operator, we would deselect this box if connecting to an already-running instance. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to start a data collection run when the scene starts. Since we will be using BCI2000 itself to set experiment parameters, we will instead wait for BCI2000 to start from Unity, and thus will leave the box unchecked. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Stop With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to stop collecting data when the scene stops. Since we will be controlling BCI2000 directly, rather than entirely through Unity, we will leave this unchecked.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Shutdown With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to shut down alongside the Unity scene. Whether or not this value is set ultimately doesn&#039;t matter much, especially if Start Local Operator is checked. The data will be saved whether or not BCI2000 shuts down. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 1&amp;lt;/code&amp;gt;: SignalGenerator&lt;br /&gt;
&lt;br /&gt;
The signal source module to start. We will use SignalGenerator, which generates a signal without any connected hardware.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 2&amp;lt;/code&amp;gt;: DummySignalProcessing&lt;br /&gt;
&lt;br /&gt;
The signal processing module to start. We will use DummySignalProcessing, as there is no processing to do.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 3&amp;lt;/code&amp;gt;: DummyApplication&lt;br /&gt;
&lt;br /&gt;
The Application module to start. Since we are using Unity, we will use DummyApplication.&lt;br /&gt;
&lt;br /&gt;
===Setting References===&lt;br /&gt;
In order for the game&#039;s scripts to communicate with BCI2000, they need to hold a reference to the UnityBCI2000 component.&lt;br /&gt;
There are three scripts which will need to communicate with BCI2000. They are &amp;lt;code&amp;gt;GameControl.cs, BallControl.cs, and MCursorControl.cs&amp;lt;/code&amp;gt;.&lt;br /&gt;
These scripts are each located within the Assets directory of the Unity project. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
As before, select Assets &amp;gt; Open Containing Folder to open the project directory, then open the Assets folder. &lt;br /&gt;
For each script, open it in a text editor.&lt;br /&gt;
Add a data member of type UnityBCI2000 to the class, like so:&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
Place the member definition above the Awake() method, for readability.&lt;br /&gt;
Within the Awake() method, set this reference to the UnityBCI2000 component.&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Each of the three scripts should contain a section like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
	void Awake() {&lt;br /&gt;
		bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
		...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding Events===&lt;br /&gt;
[https://www.bci2000.org/mediawiki/index.php/Programming_Reference:Events Events] are the primary way that non-signal experiment data is recorded in BCI2000. They are timestamped integer values which are encoded alongside the signal data in BCI2000 output files. Due to BCI2000&#039;s design, events must be added during a very specific part of its startup sequence, which is immediately after the BCI2000 operator starts, and before any of the modules start. As such, we cannot simply call &amp;lt;code&amp;gt;AddEvent()&amp;lt;/code&amp;gt; whenever we want. Furthermore, the order in which Unity objects initialize is undefined, so it cannot even be guaranteed that calling &amp;lt;code&amp;gt;AddEvent&amp;lt;/code&amp;gt; at a specific time will be consistent across multiple projects. As such, UnityBCI2000 provides a couple of methods for sending commands at well-defined points within the startup sequence. These two methods, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; allow BCI2000 commands to be sent while the operator is in the state Idle (immediately before starting its modules) and when the operator is in the state Connected (after starting and connecting to the modules. Below is an example of using those methods to add and show an event in BCI2000.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Script : MonoBehaviour {&lt;br /&gt;
    UnityBCI2000 bci;&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000Object&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;AnEvent&amp;quot;, 32);&lt;br /&gt;
	});&lt;br /&gt;
    }&lt;br /&gt;
    void Start() {&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;AnEvent&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As seen above, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; take a delegate (C#&#039;s term for a callback/closure/functor/etc.) with a single parameter of type &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt; (in this case called &amp;quot;remote&amp;quot;). The lambda expression given to the call to &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; uses the method &amp;lt;code&amp;gt;BCI2000Remote.AddEvent()&amp;lt;/code&amp;gt; to add an event called &amp;quot;AnEvent&amp;quot; with a bit width of 32 bits. The call to &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; tells BCI2000 to show the event&#039;s value in a graphical window. A description of the BCI2000Remote class can be found [https://www.bci2000.org/mediawiki/index.php/Contributions:BCI2000RemoteNET here], and API documentation can be found [https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html here].&lt;br /&gt;
&lt;br /&gt;
We will now add the events relevant to the Cursor Task. Open the &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt; script, and modify its &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; to add the events &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; with bit width 1. Additionally, add the events &amp;lt;code&amp;gt;TrialNumber&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetPositionX&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;TargetPositionY&amp;lt;/code&amp;gt; with width 16. These will encode the task state and number of trials.&lt;br /&gt;
We also need to set a parameter value so that the signal will be set to the mouse position. Using &amp;lt;code&amp;gt;BCI2000Remote.SetParameter()&amp;lt;/code&amp;gt;, we will set the &amp;lt;code&amp;gt;ModulateAmplitude&amp;lt;/code&amp;gt; parameter to 1.&lt;br /&gt;
&lt;br /&gt;
Open the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, and within the &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; function, add events &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt;, with width 16. Show these events in a visualization window with &amp;lt;code&amp;gt;Visualize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your two scripts should now look like this: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs &lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TrialNumber&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetPositionY&amp;quot;, 16);&lt;br /&gt;
	    remote.SetParameter(&amp;quot;ModulateAmplitude&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
	    });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionY&amp;quot;, 16);&lt;br /&gt;
	    });&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionX&amp;quot;);&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionY&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using BCI2000 Parameters===&lt;br /&gt;
====Adding Parameters====&lt;br /&gt;
BCI2000&#039;s operator contains an interface for changing experiment parameters before running a task. By making use of this interface we can change the behavior of the task dynamically, without needing to rebuild the Unity project each time. In order to do this we need to define the parameters and add them to BCI2000, and later read their values after the operator has a chance to change them. &amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;This section is not strictly necessary. The project will function the same whether this is done or not, just without the option to change parameters at runtime. &amp;lt;/span&amp;gt; &lt;br /&gt;
&lt;br /&gt;
First, we define add parameters to BCI2000. Similarly to events, parameters must be added while the Operator is in the &amp;lt;code&amp;gt;Idle&amp;lt;/code&amp;gt; state, so we add them inside of &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt;, like below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public int someParameter = 5;&lt;br /&gt;
void Awake() {&lt;br /&gt;
    bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	remote.AddParameter(&amp;quot;Application:ParameterPlace&amp;quot;, &amp;quot;SomeParameter&amp;quot;, someParameter.ToString()); &lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
The first argument to the method is the section into which the parameter is placed, that is, on which tab and under which heading the parameter will appear within the Operator&#039;s parameter editor window (note that the section is not a scope, all parameter names must be unique). The second argument is the parameter name itself. The third argument is the default value of the parameter. We pass in the value of the parameter, so when it appears in the Operator, its default value is 5 (or another value if it has been changed in the Unity Editor). Note that all parameters are handled as strings, so we need to convert its value to a string when sending it.&lt;br /&gt;
&lt;br /&gt;
For &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;, we will add parameters corresponding to the Pre-Feedback, Feedback, and Post-Feedback durations, Target Radius, and Number of Trials.&lt;br /&gt;
For &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt;, we will add parameters corresponding to the Acceleration Scale, Coefficient of Restitution, Coefficient of Drag, and Attraction Curve Coefficient (how quickly the Ball moves to follow the Mouse Cursor).&lt;br /&gt;
For &amp;lt;code&amp;gt;MCursorControl.cs&amp;lt;/code&amp;gt;, we will add a parameter corresponding to the Rolling Maximum Amount.&lt;br /&gt;
&lt;br /&gt;
Your scripts should look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		remote.AddEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
		...&lt;br /&gt;
&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;PreFeedbackDuration&amp;quot;, preFeedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;FeedbackDuration&amp;quot;, feedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;PostFeedbackDuration&amp;quot;, postFeedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;TargetRadius&amp;quot;, targetRadius.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;Trials&amp;quot;, n_trials.ToString());&lt;br /&gt;
		});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;AccelerationScale&amp;quot;, accelerationScale.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;CoeffOfRestitution&amp;quot;, coefficientOfRestitution.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;CoeffOfDrag&amp;quot;, coefficientOfDrag.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;AccelerationCurve&amp;quot;, attractionCurveCoefficient.ToString());&lt;br /&gt;
		})}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; MCursorControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;RollingMaximumAmount&amp;quot;, rollingMaximumAmount.ToString());&lt;br /&gt;
		});&lt;br /&gt;
}&lt;br /&gt;
		&lt;br /&gt;
&lt;br /&gt;
====Reading and Validating Parameters====&lt;br /&gt;
Since we set the parameters within the BCI2000 operator, we need some way to read them back into Unity after they have been set. Specifically, we need to read them after the operator clicks the &amp;quot;Set Config&amp;quot; button within the BCI2000 Operator. How this timing synchronization is covered in the section [[Reacting to BCI2000 state changes]]. In this section we will cover reading and validating parameters.&lt;br /&gt;
&lt;br /&gt;
A method called &amp;lt;code&amp;gt;SetConfig&amp;lt;/code&amp;gt; is provided in each of the scripts in which we added parameters previously. This method will be called after the operator changes parameters. In this method we will read in parameters and parse them into valid values. Using the same example parameter as before:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void SetConfig() {&lt;br /&gt;
    try {&lt;br /&gt;
	someParameter = int.Parse(bci.Control.GetParameter(&amp;quot;SomeParameter&amp;quot;));&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
	bci.Error(&amp;quot;Could not parse parameter SomeParameter as int&amp;quot;);&lt;br /&gt;
	throw e;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that since we are now working outside the BCI2000 startup sequence, we use &amp;lt;code&amp;gt;UnityBCI2000.Control&amp;lt;/code&amp;gt; to call &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt; methods directly, rather than using &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt;. We also wrap the call within a try/catch block so that we can report erroneous parameters back to the operator. This is optional, but it keeps your project from failing silently and is otherwise useful for doing things like distributing your Unity project as a standalone executable, where logging errors can only be done through the BCI2000 operator. You can also write a helper function which handles parsing and error reporting for you:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int GetParseParameterInt(string paramName) {&lt;br /&gt;
    int p_val = bci.Control.GetParameter(&amp;quot;SomeParameter&amp;quot;);&lt;br /&gt;
    try {&lt;br /&gt;
	someParameter = int.Parse(p_val);&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
	bci.Error($&amp;quot;Could not parse parameter {paramName} (value {p_val}) as int&amp;quot;);&lt;br /&gt;
	throw e;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Unfortunately, since the version of C# used by Unity does not support type-parameterized parsing, you must write one of these helper functions for each type of data you want to store in a parameter (int, float, double, etc.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Read back the parameters added in the previous step. Your scripts should look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs &lt;br /&gt;
void SetConfig() {&lt;br /&gt;
	try {&lt;br /&gt;
	   preFeedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;PreFeedbackDuration&amp;quot;));&lt;br /&gt;
	   feedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;FeedbackDuration&amp;quot;));&lt;br /&gt;
	   postFeedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;PostFeedbackDuration&amp;quot;));&lt;br /&gt;
	   targetRadius = float.Parse(bci.Control.GetParameter(&amp;quot;TargetRadius&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse one of PreFeedbackDuration, FeedbackDuration, PostFeedbackDuration, or TargetRadius as a float&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
	try {&lt;br /&gt;
	   n_trials = int.Parse(bci.Control.GetParameter(&amp;quot;Trials&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse Trials as an int&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if (preFeedbackDuration &amp;lt; COUNTDOWN_DURATION) {&lt;br /&gt;
	   bci.Error(&amp;quot;preFeedbackDuration must be greater than or equal to 2.25&amp;quot;);&lt;br /&gt;
	   throw new Exception(&amp;quot;preFeedbackDuration must be greater than or equal to 2.25&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
    public void SetConfig() {&lt;br /&gt;
	try {&lt;br /&gt;
	   accelerationScale = float.Parse(bci.Control.GetParameter(&amp;quot;AccelerationScale&amp;quot;));&lt;br /&gt;
	   coefficientOfRestitution = float.Parse(bci.Control.GetParameter(&amp;quot;CoeffOfRestitution&amp;quot;));&lt;br /&gt;
	   coefficientOfDrag = float.Parse(bci.Control.GetParameter(&amp;quot;CoeffOfDrag&amp;quot;));&lt;br /&gt;
	   attractionCurveCoefficient = float.Parse(bci.Control.GetParameter(&amp;quot;AccelerationCurve&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse one of AccelerationScale, CoeffOfRestitution, CoeffOfDrag, AccelerationCurve as float&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; MCursorControl.cs&lt;br /&gt;
public void SetConfig() {&lt;br /&gt;
    try {&lt;br /&gt;
       rollingMaximumAmount = int.Parse(bci.Control.GetParameter(&amp;quot;RollingMaximumAmount&amp;quot;));&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
       bci.Error(&amp;quot;Could not parse parameter RollingMaximumAmount as int&amp;quot;);&lt;br /&gt;
       throw e;&lt;br /&gt;
    }&lt;br /&gt;
    signalsX = new int[rollingMaximumAmount];&lt;br /&gt;
    signalsY = new int[rollingMaximumAmount];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;, we also verify that the Pre-Feedback Duration is longer than the duration of the countdown that happens before each trial, and report errors to BCI2000 accordingly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Reacting to BCI2000 state changes===&lt;br /&gt;
Since we will be controlling the Unity task from BCI2000, we need some way to wait for BCI2000 to be in a specific state, for example, waiting for the operator to click Start and put the Operator Module into the Running state. UnityBCI2000 provides a method for this, the &amp;lt;code&amp;gt;UnityBCI2000.PollSystemState&amp;lt;/code&amp;gt; method. In order to wait for the Operator Module to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Running));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will check once per frame whether or not the Operator is in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state, and only continue once BCI2000 is in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state. Note that since &amp;lt;code&amp;gt;SystemState&amp;lt;/code&amp;gt; is a member of &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt;, we also need to add a &amp;lt;code&amp;gt;using BCI2000RemoteNET&amp;lt;/code&amp;gt; statement to our script.&lt;br /&gt;
&lt;br /&gt;
In our case, we need to react to the operator setting the parameters, starting the data collection, and stopping the data collection. These correspond to the Operator Module entering the &amp;lt;code&amp;gt;Resting&amp;lt;/code&amp;gt; state, entering the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state, and exiting the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt; script, we will wait for the system to be in the &amp;lt;code&amp;gt;Resting&amp;lt;/code&amp;gt; state at the start of the &amp;lt;code&amp;gt;ControLoop&amp;lt;/code&amp;gt; method, and wait for the system to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state immediately before the entering the trial loop. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
&lt;br /&gt;
    IEnumerator ControlLoop() {&lt;br /&gt;
	while (True) {&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: red&amp;quot;&amp;gt;&lt;br /&gt;
	   StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Resting));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	   try {&lt;br /&gt;
		...&lt;br /&gt;
	   } catch (Exception e) {&lt;br /&gt;
		continue;&lt;br /&gt;
	   }&lt;br /&gt;
	&lt;br /&gt;
	   int trials = 0;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: red&amp;quot;&amp;gt;&lt;br /&gt;
	   StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Running));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	   yield return new WaitForSeconds(preRunDuration);&lt;br /&gt;
	   while (IsContinue() &amp;amp;&amp;amp; trials &amp;lt; n_trials) {&lt;br /&gt;
		...&lt;br /&gt;
	   }&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need to check for the operator stopping data collection, so we modify the &amp;lt;code&amp;gt;IsContinue()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bool IsContinue () {&lt;br /&gt;
	return bci.Control.GetSystemState() == BCI2000Remote.SystemState.Running;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remember to add &amp;lt;code&amp;gt;using BCI2000RemoteNET;&amp;lt;/code&amp;gt; to the top of the script, so you can access the &amp;lt;code&amp;gt;SystemState&amp;lt;/code&amp;gt; enum.&lt;br /&gt;
&lt;br /&gt;
===Reading the control signal===&lt;br /&gt;
We will be using the control signal to control the cursor. Open the &amp;lt;code&amp;gt;MCursorControl.cs&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
The commented out section of the &amp;lt;code&amp;gt;GetPos()&amp;lt;/code&amp;gt; method contains the code required to turn the control signal waveform coming from the Signal Source and Signal Processing modules into screen coordinates. &lt;br /&gt;
Uncomment the commented part and delete the line &amp;lt;code&amp;gt;Ray r = camera.ScreenPointToRay(Input.MousePosition);&amp;lt;/code&amp;gt;.&lt;br /&gt;
Change the &amp;lt;code&amp;gt;double signalX = 0;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;double signalY = 0;&amp;lt;/code&amp;gt; to. &lt;br /&gt;
&lt;br /&gt;
Your &amp;lt;code&amp;gt;GetPos()&amp;lt;/code&amp;gt; method should look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    Vector3 GetPos() {&lt;br /&gt;
	double signalX = bci.Control.GetSignal(1, bci.CurrentSampleOffset());&lt;br /&gt;
	double signalY = bci.Control.GetSignal(2, bci.CurrentSampleOffset());&lt;br /&gt;
	signalsX[signalIndex] = signalX;&lt;br /&gt;
	signalsY[signalIndex] = signalY;&lt;br /&gt;
	&lt;br /&gt;
	signalIndex = signalIndex + 1 &amp;gt;= rollingMaximumAmount ? 0 : signalIndex + 1;&lt;br /&gt;
	double max_x = signalsX.Max();&lt;br /&gt;
	double max_y = signalsY.Max();&lt;br /&gt;
	Ray r = camera.ScreenPointToRay(new Vector3((float) max_x * Screen.width, (float) max_y * Screen.height, 0));&lt;br /&gt;
	float p;&lt;br /&gt;
	if (!plane.Raycast(r, out p)) {&lt;br /&gt;
	   throw new Exception(&amp;quot;error casting ray to plane, invalid mouse position?&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	return r.GetPoint(p);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the use of the &amp;lt;code&amp;gt;UnityBCI2000.CurrentSampleOffset()&amp;lt;/code&amp;gt; method. This is a special method which gets the offset into the current block such that the sample is exactly one block length later than when it was collected by the hardware. This is to normalize the latency between when the hardware collects the signal and the software receives the signal, due to how BCI2000 processes data in blocks.&lt;br /&gt;
&lt;br /&gt;
===Sending events back to BCI2000===&lt;br /&gt;
&lt;br /&gt;
The primary way to communicate game state back to BCI2000 is via the use of Events, which are integer values encoded alongside the signal data.&lt;br /&gt;
&lt;br /&gt;
We will send the events that we added in a previous section.&lt;br /&gt;
&lt;br /&gt;
First, we will send back the current position of the cursor. Within the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, within the &amp;lt;code&amp;gt;Update()&amp;lt;/code&amp;gt; method, immediately after &amp;lt;code&amp;gt;Move()&amp;lt;/code&amp;gt; is called, set the &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt; events. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
void Update() {&lt;br /&gt;
    ...&lt;br /&gt;
    if (isTrialRunning) {&lt;br /&gt;
	...&lt;br /&gt;
	Move();&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;CursorPositionX&amp;quot;, (uint) ((transform.position.x + 7) * 1000));&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;CursorPositionY&amp;quot;, (uint) ((transform.position.y + 4.5) * 1000));&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that we transform the value of the cursor&#039;s position. This is because events in BCI2000 are represented as unsigned integers, so, for example, the cursor&#039;s range of movement in the x axis, -7 to 7, would not be directly representable within a BCI2000 event, so we add 7 so it is positive, and multiply by 1000 so that we have a more precise measure of the cursor&#039;s position. The range of [-7,7] becomes [0,14000].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We will also set the events corresponding to the game state within &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;. First we will set &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt; to represent when the game is in these states. To do this, at the beginning and end of &amp;lt;code&amp;gt;PreTrial()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Trial()&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PostTrial()&amp;lt;/code&amp;gt;, we will set the corresponding event values to 1 and 0, respectively.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator PreTrial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PreFeedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
IEnumerator Trial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
IEnumerator PostTrial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PostFeedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also set the events which happen at the end of each trial. The &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt; event is activated when the subject hits the target, and the &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; event is activated when the subject runs out of time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator Trial() {&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 0);&lt;br /&gt;
    if (lastTrialSucceeded) {&lt;br /&gt;
	bci.Control.PulseEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
    } else {&lt;br /&gt;
	bci.Control.PulseEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Notice that we use &amp;lt;code&amp;gt;BCI2000Remote.PulseEvent()&amp;lt;/code&amp;gt; rather than &amp;lt;code&amp;gt;BCI2000Remote.SetEvent()&amp;lt;/code&amp;gt;. This results in the event being set to the value &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for exactly one sample duration, then returning to zero.&lt;br /&gt;
&lt;br /&gt;
We will also record the position of the target. Similarly to the cursor, we will transform the target&#039;s coordinates to be a positive integer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator PreTrial() {&lt;br /&gt;
    ...&lt;br /&gt;
    target.SetActive(true);&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;TargetPositionX&amp;quot;, (uint) ((target.transform.position.x + 7) * 1000));&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;TargetPositionY&amp;quot;, (uint) ((target.transform.position.y + 4.5) * 1000));&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The last event we need to set is the trial number.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
IEnumerator ControlLoop() {&lt;br /&gt;
    ...&lt;br /&gt;
    while (IsContinue() &amp;amp;&amp;amp; trials &amp;lt; n_trials) {&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;TrialNumber&amp;quot;, trials + 1);&lt;br /&gt;
	...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Unity Player Settings===&lt;br /&gt;
Additionally, due to how Unity detects changes in BCI2000 state, it must be allowed to run in the background.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity menu bar:&lt;br /&gt;
    Edit &amp;gt; Project Settings &amp;gt; Player &amp;gt; Resolution and Presentation&lt;br /&gt;
Check the &amp;quot;Run In Background&amp;quot; box.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Usage===&lt;br /&gt;
&lt;br /&gt;
Now, when the Unity application runs, BCI2000 will open. From here, parameters can be set via the Config window, then clicking Set Config and Start will start data collection.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000&amp;diff=11528</id>
		<title>User Tutorial:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000&amp;diff=11528"/>
		<updated>2024-08-16T02:31:25Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Red text blocks contain detailed instructions for the higher-level instructions preceding them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example comprehensively demonstrates many of the capabilities of UnityBCI2000, and as such, is more than what is necessary for many usecases. If you just want to use BCI2000 as a logging backend for an existing Unity application, see the Barebones UnityBCI2000 tutorial.&lt;br /&gt;
&lt;br /&gt;
===Download Unity===&lt;br /&gt;
&lt;br /&gt;
Download Unity Hub from [https://unity3d.com Unity].&lt;br /&gt;
&lt;br /&gt;
===Setting Up BCI2000===&lt;br /&gt;
&lt;br /&gt;
Follow the instructions starting with [https://www.bci2000.org/mediawiki/index.php/Programming_Howto:Install_Prerequisites] to download BCI2000. &lt;br /&gt;
&lt;br /&gt;
===Setting Up UnityBCI2000===&lt;br /&gt;
Download UnityBCI2000 from its GitHub page, [https://github.com/neurotechcenter/UnityBCI2000]. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the &amp;quot;Releases&amp;quot; section on the right side of the page. This tutorial is intended to be used with UnityBCI2000 version 2.0.0, so scroll to that release and click on the files BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to download them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Download Tutorial Project===&lt;br /&gt;
Download the CursorTask3 repository from [https://github.com/Personator01/CursorTask3 GitHub].&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Either:&lt;br /&gt;
	-Clone the git repository&lt;br /&gt;
	-Download the respository directly from GitHub&lt;br /&gt;
		-&amp;gt; Click the green &amp;quot;Code&amp;quot; button &lt;br /&gt;
		-&amp;gt; Select &amp;quot;Download ZIP&amp;quot;&lt;br /&gt;
		-&amp;gt; Extract the zip file&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The download directory contains two versions of the CursorTask3 project. One, CursorTask3-BCI2K, contains an example implementation of the task with BCI2000 integration. The other, CursorTask3-NoBCI2K, contains the same task without BCI2000 integration. This tutorial is a step by step guide on turning that second project into the first. &lt;br /&gt;
&lt;br /&gt;
===Opening the project===&lt;br /&gt;
Open the project in the Unity Editor, and open the CursorTask scene.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Open Unity Hub.&lt;br /&gt;
Click the &amp;quot;Add&amp;quot; button in the top right corner.&lt;br /&gt;
Navigate to the CursorTask3 directory downloaded previously.&lt;br /&gt;
Select the CursorTask3-NoBCI2K directory to add it to Unity Hub.&lt;br /&gt;
Click the CursorTask3-NoBCI2K project in the Unity Hub.&lt;br /&gt;
If prompted to select a version of Unity to use or install, select Unity 2022.3. The specific release number of Unity 2022.3 should not matter, so select the one labeled &amp;quot;LTS&amp;quot; for consistency.&lt;br /&gt;
The lower panel (the asset browser) should already show the Assets/Scenes directory, which contains a single scene called SampleScene.&lt;br /&gt;
Double-click SampleScene. This should open a scene with a box containing various lights and objects.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you wish to view the completed implementation, repeat these steps, but instead open the CursorTask3-BCI2K directory. Note that in order to use the completed implementation, you will still need to set the Operator Path value of the UnityBCI2000 component of the BCI2000 game object.&lt;br /&gt;
&lt;br /&gt;
===Adding UnityBCI2000 to the project===&lt;br /&gt;
Add BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to your project&#039;s assets.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click Assets &amp;gt; Open Containing Folder to open your project directory.&lt;br /&gt;
Place the BCI2000RemoteNETStandard.dll and UnityBCI2000.cs files in the Assets folder.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add an empty GameObject called &#039;BCI2000&#039;. This will hold the scripts for controlling BCI2000. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click GameObject &amp;gt; Create Empty to create an empty GameObject, and name it &#039;BCI2000&#039;. (The object&#039;s specific name does not actually matter, it is only needed in order to reference it within other scripts)&lt;br /&gt;
You will notice that it now appears in the Scene Hierarchy panel, on the left side of the screen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the UnityBCI2000 component to the object.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the object in the Hierarchy panel. This will open it in the Inspector panel (the panel on the right side of the screen)&lt;br /&gt;
In the inspector, below the new object&#039;s Transform component, click the &amp;quot;Add Component&amp;quot; button, which will open up a small window for adding components.&lt;br /&gt;
Within this window, select Scripts &amp;gt; Unity BCI2000 to add the UnityBCI2000 component.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Configuring UnityBCI2000===&lt;br /&gt;
The inspector panel now contains the configuration options for UnityBCI2000. Set the options as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Local Operator&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This will start the operator on your computer when the Unity scene initializes. If we were instead connecting to an already-running instance of BCI2000, or an instance on another computer, this box would be deselected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Path&amp;lt;/code&amp;gt;: The path to the Operator executable. This will look something like this on Windows (C://path/to/bci2000/prog/Operator.exe)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Address&amp;lt;/code&amp;gt;: 127.0.0.1&lt;br /&gt;
&lt;br /&gt;
This is the address of the machine on which BCI2000 is running. Since we are running BCI2000 on the same computer as Unity, we leave it as 127.0.0.1, the loopback address.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Port&amp;lt;/code&amp;gt;: 3999&lt;br /&gt;
&lt;br /&gt;
This is the port on which BCI2000 is listening for commands. By default, it is 3999.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Modules&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to start the requested Signal Source, Signal Processing, and Application modules when the Unity scene initializes. Similarly to Start Local Operator, we would deselect this box if connecting to an already-running instance. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to start a data collection run when the scene starts. Since we will be using BCI2000 itself to set experiment parameters, we will instead wait for BCI2000 to start from Unity, and thus will leave the box unchecked. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Stop With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to stop collecting data when the scene stops. Since we will be controlling BCI2000 directly, rather than entirely through Unity, we will leave this unchecked.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Shutdown With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to shut down alongside the Unity scene. Whether or not this value is set ultimately doesn&#039;t matter much, especially if Start Local Operator is checked. The data will be saved whether or not BCI2000 shuts down. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 1&amp;lt;/code&amp;gt;: SignalGenerator&lt;br /&gt;
&lt;br /&gt;
The signal source module to start. We will use SignalGenerator, which generates a signal without any connected hardware.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 2&amp;lt;/code&amp;gt;: DummySignalProcessing&lt;br /&gt;
&lt;br /&gt;
The signal processing module to start. We will use DummySignalProcessing, as there is no processing to do.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 3&amp;lt;/code&amp;gt;: DummyApplication&lt;br /&gt;
&lt;br /&gt;
The Application module to start. Since we are using Unity, we will use DummyApplication.&lt;br /&gt;
&lt;br /&gt;
===Setting References===&lt;br /&gt;
In order for the game&#039;s scripts to communicate with BCI2000, they need to hold a reference to the UnityBCI2000 component.&lt;br /&gt;
There are three scripts which will need to communicate with BCI2000. They are &amp;lt;code&amp;gt;GameControl.cs, BallControl.cs, and MCursorControl.cs&amp;lt;/code&amp;gt;.&lt;br /&gt;
These scripts are each located within the Assets directory of the Unity project. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
As before, select Assets &amp;gt; Open Containing Folder to open the project directory, then open the Assets folder. &lt;br /&gt;
For each script, open it in a text editor.&lt;br /&gt;
Add a data member of type UnityBCI2000 to the class, like so:&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
Place the member definition above the Awake() method, for readability.&lt;br /&gt;
Within the Awake() method, set this reference to the UnityBCI2000 component.&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Each of the three scripts should contain a section like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
	void Awake() {&lt;br /&gt;
		bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
		...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding Events===&lt;br /&gt;
[https://www.bci2000.org/mediawiki/index.php/Programming_Reference:Events Events] are the primary way that non-signal experiment data is recorded in BCI2000. They are timestamped integer values which are encoded alongside the signal data in BCI2000 output files. Due to BCI2000&#039;s design, events must be added during a very specific part of its startup sequence, which is immediately after the BCI2000 operator starts, and before any of the modules start. As such, we cannot simply call &amp;lt;code&amp;gt;AddEvent()&amp;lt;/code&amp;gt; whenever we want. Furthermore, the order in which Unity objects initialize is undefined, so it cannot even be guaranteed that calling &amp;lt;code&amp;gt;AddEvent&amp;lt;/code&amp;gt; at a specific time will be consistent across multiple projects. As such, UnityBCI2000 provides a couple of methods for sending commands at well-defined points within the startup sequence. These two methods, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; allow BCI2000 commands to be sent while the operator is in the state Idle (immediately before starting its modules) and when the operator is in the state Connected (after starting and connecting to the modules. Below is an example of using those methods to add and show an event in BCI2000.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Script : MonoBehaviour {&lt;br /&gt;
    UnityBCI2000 bci;&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000Object&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;AnEvent&amp;quot;, 32);&lt;br /&gt;
	});&lt;br /&gt;
    }&lt;br /&gt;
    void Start() {&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;AnEvent&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As seen above, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; take a delegate (C#&#039;s term for a callback/closure/functor/etc.) with a single parameter of type &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt; (in this case called &amp;quot;remote&amp;quot;). The lambda expression given to the call to &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; uses the method &amp;lt;code&amp;gt;BCI2000Remote.AddEvent()&amp;lt;/code&amp;gt; to add an event called &amp;quot;AnEvent&amp;quot; with a bit width of 32 bits. The call to &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; tells BCI2000 to show the event&#039;s value in a graphical window. A description of the BCI2000Remote class can be found [https://www.bci2000.org/mediawiki/index.php/Contributions:BCI2000RemoteNET here], and API documentation can be found [https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html here].&lt;br /&gt;
&lt;br /&gt;
We will now add the events relevant to the Cursor Task. Open the &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt; script, and modify its &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; to add the events &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; with bit width 1. Additionally, add the events &amp;lt;code&amp;gt;TrialNumber&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetPositionX&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;TargetPositionY&amp;lt;/code&amp;gt; with width 16. These will encode the task state and number of trials.&lt;br /&gt;
We also need to set a parameter value so that the signal will be set to the mouse position. Using &amp;lt;code&amp;gt;BCI2000Remote.SetParameter()&amp;lt;/code&amp;gt;, we will set the &amp;lt;code&amp;gt;ModulateAmplitude&amp;lt;/code&amp;gt; parameter to 1.&lt;br /&gt;
&lt;br /&gt;
Open the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, and within the &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; function, add events &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt;, with width 16. Show these events in a visualization window with &amp;lt;code&amp;gt;Visualize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your two scripts should now look like this: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs &lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TrialNumber&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetPositionY&amp;quot;, 16);&lt;br /&gt;
	    remote.SetParameter(&amp;quot;ModulateAmplitude&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
	    });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionY&amp;quot;, 16);&lt;br /&gt;
	    });&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionX&amp;quot;);&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionY&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using BCI2000 Parameters===&lt;br /&gt;
====Adding Parameters====&lt;br /&gt;
BCI2000&#039;s operator contains an interface for changing experiment parameters before running a task. By making use of this interface we can change the behavior of the task dynamically, without needing to rebuild the Unity project each time. In order to do this we need to define the parameters and add them to BCI2000, and later read their values after the operator has a chance to change them. &amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;This section is not strictly necessary. The project will function the same whether this is done or not, just without the option to change parameters at runtime. &amp;lt;/span&amp;gt; &lt;br /&gt;
&lt;br /&gt;
First, we define add parameters to BCI2000. Similarly to events, parameters must be added while the Operator is in the &amp;lt;code&amp;gt;Idle&amp;lt;/code&amp;gt; state, so we add them inside of &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt;, like below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public int someParameter = 5;&lt;br /&gt;
void Awake() {&lt;br /&gt;
    bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	remote.AddParameter(&amp;quot;Application:ParameterPlace&amp;quot;, &amp;quot;SomeParameter&amp;quot;, someParameter.ToString()); &lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
The first argument to the method is the section into which the parameter is placed, that is, on which tab and under which heading the parameter will appear within the Operator&#039;s parameter editor window (note that the section is not a scope, all parameter names must be unique). The second argument is the parameter name itself. The third argument is the default value of the parameter. We pass in the value of the parameter, so when it appears in the Operator, its default value is 5 (or another value if it has been changed in the Unity Editor). Note that all parameters are handled as strings, so we need to convert its value to a string when sending it.&lt;br /&gt;
&lt;br /&gt;
For &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;, we will add parameters corresponding to the Pre-Feedback, Feedback, and Post-Feedback durations, Target Radius, and Number of Trials.&lt;br /&gt;
For &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt;, we will add parameters corresponding to the Acceleration Scale, Coefficient of Restitution, Coefficient of Drag, and Attraction Curve Coefficient (how quickly the Ball moves to follow the Mouse Cursor).&lt;br /&gt;
For &amp;lt;code&amp;gt;MCursorControl.cs&amp;lt;/code&amp;gt;, we will add a parameter corresponding to the Rolling Maximum Amount.&lt;br /&gt;
&lt;br /&gt;
Your scripts should look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		remote.AddEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
		...&lt;br /&gt;
&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;PreFeedbackDuration&amp;quot;, preFeedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;FeedbackDuration&amp;quot;, feedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;PostFeedbackDuration&amp;quot;, postFeedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;TargetRadius&amp;quot;, targetRadius.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;Trials&amp;quot;, n_trials.ToString());&lt;br /&gt;
		});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;AccelerationScale&amp;quot;, accelerationScale.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;CoeffOfRestitution&amp;quot;, coefficientOfRestitution.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;CoeffOfDrag&amp;quot;, coefficientOfDrag.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;AccelerationCurve&amp;quot;, attractionCurveCoefficient.ToString());&lt;br /&gt;
		})}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; MCursorControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;RollingMaximumAmount&amp;quot;, rollingMaximumAmount.ToString());&lt;br /&gt;
		});&lt;br /&gt;
}&lt;br /&gt;
		&lt;br /&gt;
&lt;br /&gt;
====Reading and Validating Parameters====&lt;br /&gt;
Since we set the parameters within the BCI2000 operator, we need some way to read them back into Unity after they have been set. Specifically, we need to read them after the operator clicks the &amp;quot;Set Config&amp;quot; button within the BCI2000 Operator. How this timing synchronization is covered in the section [[Reacting to BCI2000 state changes]]. In this section we will cover reading and validating parameters.&lt;br /&gt;
&lt;br /&gt;
A method called &amp;lt;code&amp;gt;SetConfig&amp;lt;/code&amp;gt; is provided in each of the scripts in which we added parameters previously. This method will be called after the operator changes parameters. In this method we will read in parameters and parse them into valid values. Using the same example parameter as before:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void SetConfig() {&lt;br /&gt;
    try {&lt;br /&gt;
	someParameter = int.Parse(bci.Control.GetParameter(&amp;quot;SomeParameter&amp;quot;));&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
	bci.Error(&amp;quot;Could not parse parameter SomeParameter as int&amp;quot;);&lt;br /&gt;
	throw e;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that since we are now working outside the BCI2000 startup sequence, we use &amp;lt;code&amp;gt;UnityBCI2000.Control&amp;lt;/code&amp;gt; to call &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt; methods directly, rather than using &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt;. We also wrap the call within a try/catch block so that we can report erroneous parameters back to the operator. This is optional, but it keeps your project from failing silently and is otherwise useful for doing things like distributing your Unity project as a standalone executable, where logging errors can only be done through the BCI2000 operator. You can also write a helper function which handles parsing and error reporting for you:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int GetParseParameterInt(string paramName) {&lt;br /&gt;
    int p_val = bci.Control.GetParameter(&amp;quot;SomeParameter&amp;quot;);&lt;br /&gt;
    try {&lt;br /&gt;
	someParameter = int.Parse(p_val);&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
	bci.Error($&amp;quot;Could not parse parameter {paramName} (value {p_val}) as int&amp;quot;);&lt;br /&gt;
	throw e;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Unfortunately, since the version of C# used by Unity does not support type-parameterized parsing, you must write one of these helper functions for each type of data you want to store in a parameter (int, float, double, etc.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Read back the parameters added in the previous step. Your scripts should look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs &lt;br /&gt;
void SetConfig() {&lt;br /&gt;
	try {&lt;br /&gt;
	   preFeedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;PreFeedbackDuration&amp;quot;));&lt;br /&gt;
	   feedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;FeedbackDuration&amp;quot;));&lt;br /&gt;
	   postFeedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;PostFeedbackDuration&amp;quot;));&lt;br /&gt;
	   targetRadius = float.Parse(bci.Control.GetParameter(&amp;quot;TargetRadius&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse one of PreFeedbackDuration, FeedbackDuration, PostFeedbackDuration, or TargetRadius as a float&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
	try {&lt;br /&gt;
	   n_trials = int.Parse(bci.Control.GetParameter(&amp;quot;Trials&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse Trials as an int&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if (preFeedbackDuration &amp;lt; COUNTDOWN_DURATION) {&lt;br /&gt;
	   bci.Error(&amp;quot;preFeedbackDuration must be greater than or equal to 2.25&amp;quot;);&lt;br /&gt;
	   throw new Exception(&amp;quot;preFeedbackDuration must be greater than or equal to 2.25&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
    public void SetConfig() {&lt;br /&gt;
	try {&lt;br /&gt;
	   accelerationScale = float.Parse(bci.Control.GetParameter(&amp;quot;AccelerationScale&amp;quot;));&lt;br /&gt;
	   coefficientOfRestitution = float.Parse(bci.Control.GetParameter(&amp;quot;CoeffOfRestitution&amp;quot;));&lt;br /&gt;
	   coefficientOfDrag = float.Parse(bci.Control.GetParameter(&amp;quot;CoeffOfDrag&amp;quot;));&lt;br /&gt;
	   attractionCurveCoefficient = float.Parse(bci.Control.GetParameter(&amp;quot;AccelerationCurve&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse one of AccelerationScale, CoeffOfRestitution, CoeffOfDrag, AccelerationCurve as float&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; MCursorControl.cs&lt;br /&gt;
public void SetConfig() {&lt;br /&gt;
    try {&lt;br /&gt;
       rollingMaximumAmount = int.Parse(bci.Control.GetParameter(&amp;quot;RollingMaximumAmount&amp;quot;));&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
       bci.Error(&amp;quot;Could not parse parameter RollingMaximumAmount as int&amp;quot;);&lt;br /&gt;
       throw e;&lt;br /&gt;
    }&lt;br /&gt;
    signalsX = new int[rollingMaximumAmount];&lt;br /&gt;
    signalsY = new int[rollingMaximumAmount];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;, we also verify that the Pre-Feedback Duration is longer than the duration of the countdown that happens before each trial, and report errors to BCI2000 accordingly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Reacting to BCI2000 state changes===&lt;br /&gt;
Since we will be controlling the Unity task from BCI2000, we need some way to wait for BCI2000 to be in a specific state, for example, waiting for the operator to click Start and put the Operator Module into the Running state. UnityBCI2000 provides a method for this, the &amp;lt;code&amp;gt;UnityBCI2000.PollSystemState&amp;lt;/code&amp;gt; method. In order to wait for the Operator Module to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Running));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will check once per frame whether or not the Operator is in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state, and only continue once BCI2000 is in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state. Note that since &amp;lt;code&amp;gt;SystemState&amp;lt;/code&amp;gt; is a member of &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt;, we also need to add a &amp;lt;code&amp;gt;using BCI2000RemoteNET&amp;lt;/code&amp;gt; statement to our script.&lt;br /&gt;
&lt;br /&gt;
In our case, we need to react to the operator setting the parameters, starting the data collection, and stopping the data collection. These correspond to the Operator Module entering the &amp;lt;code&amp;gt;Resting&amp;lt;/code&amp;gt; state, entering the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state, and exiting the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt; script, we will wait for the system to be in the &amp;lt;code&amp;gt;Resting&amp;lt;/code&amp;gt; state at the start of the &amp;lt;code&amp;gt;ControLoop&amp;lt;/code&amp;gt; method, and wait for the system to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state immediately before the entering the trial loop. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
&lt;br /&gt;
    IEnumerator ControlLoop() {&lt;br /&gt;
	while (True) {&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: red&amp;quot;&amp;gt;&lt;br /&gt;
	   StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Resting));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	   try {&lt;br /&gt;
		...&lt;br /&gt;
	   } catch (Exception e) {&lt;br /&gt;
		continue;&lt;br /&gt;
	   }&lt;br /&gt;
	&lt;br /&gt;
	   int trials = 0;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: red&amp;quot;&amp;gt;&lt;br /&gt;
	   StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Running));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	   yield return new WaitForSeconds(preRunDuration);&lt;br /&gt;
	   while (IsContinue() &amp;amp;&amp;amp; trials &amp;lt; n_trials) {&lt;br /&gt;
		...&lt;br /&gt;
	   }&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need to check for the operator stopping data collection, so we modify the &amp;lt;code&amp;gt;IsContinue()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bool IsContinue () {&lt;br /&gt;
	return bci.Control.GetSystemState() == BCI2000Remote.SystemState.Running;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remember to add &amp;lt;code&amp;gt;using BCI2000RemoteNET;&amp;lt;/code&amp;gt; to the top of the script, so you can access the &amp;lt;code&amp;gt;SystemState&amp;lt;/code&amp;gt; enum.&lt;br /&gt;
&lt;br /&gt;
===Reading the control signal===&lt;br /&gt;
We will be using the control signal to control the cursor. Open the &amp;lt;code&amp;gt;MCursorControl.cs&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
The commented out section of the &amp;lt;code&amp;gt;GetPos()&amp;lt;/code&amp;gt; method contains the code required to turn the control signal waveform coming from the Signal Source and Signal Processing modules into screen coordinates. &lt;br /&gt;
Uncomment the commented part and delete the line &amp;lt;code&amp;gt;Ray r = camera.ScreenPointToRay(Input.MousePosition);&amp;lt;/code&amp;gt;.&lt;br /&gt;
Change the &amp;lt;code&amp;gt;double signalX = 0;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;double signalY = 0;&amp;lt;/code&amp;gt; to. &lt;br /&gt;
&lt;br /&gt;
Your &amp;lt;code&amp;gt;GetPos()&amp;lt;/code&amp;gt; method should look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    Vector3 GetPos() {&lt;br /&gt;
	double signalX = bci.Control.GetSignal(1, bci.CurrentSampleOffset());&lt;br /&gt;
	double signalY = bci.Control.GetSignal(2, bci.CurrentSampleOffset());&lt;br /&gt;
	signalsX[signalIndex] = signalX;&lt;br /&gt;
	signalsY[signalIndex] = signalY;&lt;br /&gt;
	&lt;br /&gt;
	signalIndex = signalIndex + 1 &amp;gt;= rollingMaximumAmount ? 0 : signalIndex + 1;&lt;br /&gt;
	double max_x = signalsX.Max();&lt;br /&gt;
	double max_y = signalsY.Max();&lt;br /&gt;
	Ray r = camera.ScreenPointToRay(new Vector3((float) max_x * Screen.width, (float) max_y * Screen.height, 0));&lt;br /&gt;
	float p;&lt;br /&gt;
	if (!plane.Raycast(r, out p)) {&lt;br /&gt;
	   throw new Exception(&amp;quot;error casting ray to plane, invalid mouse position?&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	return r.GetPoint(p);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the use of the &amp;lt;code&amp;gt;UnityBCI2000.CurrentSampleOffset()&amp;lt;/code&amp;gt; method. This is a special method which gets the offset into the current block such that the sample is exactly one block length later than when it was collected by the hardware. This is to normalize the latency between when the hardware collects the signal and the software receives the signal, due to how BCI2000 processes data in blocks.&lt;br /&gt;
&lt;br /&gt;
===Sending events back to BCI2000===&lt;br /&gt;
&lt;br /&gt;
The primary way to communicate game state back to BCI2000 is via the use of Events, which are integer values encoded alongside the signal data.&lt;br /&gt;
&lt;br /&gt;
We will send the events that we added in a previous section.&lt;br /&gt;
&lt;br /&gt;
First, we will send back the current position of the cursor. Within the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, within the &amp;lt;code&amp;gt;Update()&amp;lt;/code&amp;gt; method, immediately after &amp;lt;code&amp;gt;Move()&amp;lt;/code&amp;gt; is called, set the &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt; events. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
void Update() {&lt;br /&gt;
    ...&lt;br /&gt;
    if (isTrialRunning) {&lt;br /&gt;
	...&lt;br /&gt;
	Move();&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;CursorPositionX&amp;quot;, (uint) ((transform.position.x + 7) * 1000));&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;CursorPositionY&amp;quot;, (uint) ((transform.position.y + 4.5) * 1000));&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that we transform the value of the cursor&#039;s position. This is because events in BCI2000 are represented as unsigned integers, so, for example, the cursor&#039;s range of movement in the x axis, -7 to 7, would not be directly representable within a BCI2000 event, so we add 7 so it is positive, and multiply by 1000 so that we have a more precise measure of the cursor&#039;s position. The range of [-7,7] becomes [0,14000].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We will also set the events corresponding to the game state within &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;. First we will set &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt; to represent when the game is in these states. To do this, at the beginning and end of &amp;lt;code&amp;gt;PreTrial()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Trial()&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PostTrial()&amp;lt;/code&amp;gt;, we will set the corresponding event values to 1 and 0, respectively.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator PreTrial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PreFeedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
IEnumerator Trial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
IEnumerator PostTrial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PostFeedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also set the events which happen at the end of each trial. The &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt; event is activated when the subject hits the target, and the &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; event is activated when the subject runs out of time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator Trial() {&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 0);&lt;br /&gt;
    if (lastTrialSucceeded) {&lt;br /&gt;
	bci.Control.PulseEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
    } else {&lt;br /&gt;
	bci.Control.PulseEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Notice that we use &amp;lt;code&amp;gt;BCI2000Remote.PulseEvent()&amp;lt;/code&amp;gt; rather than &amp;lt;code&amp;gt;BCI2000Remote.SetEvent()&amp;lt;/code&amp;gt;. This results in the event being set to the value &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for exactly one sample duration, then returning to zero.&lt;br /&gt;
&lt;br /&gt;
We will also record the position of the target. Similarly to the cursor, we will transform the target&#039;s coordinates to be a positive integer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator PreTrial() {&lt;br /&gt;
    ...&lt;br /&gt;
    target.SetActive(true);&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;TargetPositionX&amp;quot;, (uint) ((target.transform.position.x + 7) * 1000));&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;TargetPositionY&amp;quot;, (uint) ((target.transform.position.y + 4.5) * 1000));&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The last event we need to set is the trial number.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
IEnumerator ControlLoop() {&lt;br /&gt;
    ...&lt;br /&gt;
    while (IsContinue() &amp;amp;&amp;amp; trials &amp;lt; n_trials) {&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;TrialNumber&amp;quot;, trials + 1);&lt;br /&gt;
	...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Unity Player Settings===&lt;br /&gt;
Additionally, due to how Unity detects changes in BCI2000 state, it must be allowed to run in the background.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity menu bar:&lt;br /&gt;
    Edit &amp;gt; Project Settings &amp;gt; Player &amp;gt; Resolution and Presentation&lt;br /&gt;
Check the &amp;quot;Run In Background&amp;quot; box.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Usage===&lt;br /&gt;
&lt;br /&gt;
Now, when the Unity application runs, BCI2000 will open. From here, parameters can be set via the Config window, then clicking Set Config and Start will start data collection.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000_Barebones&amp;diff=11527</id>
		<title>User Tutorial:UnityBCI2000 Barebones</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000_Barebones&amp;diff=11527"/>
		<updated>2024-08-16T02:31:14Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Red text blocks contain detailed instructions for the higher-level instructions preceding them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This tutorial goes over how to use BCI2000 as a logging service for an existing Unity project. For a more comprehensive tutorial on integrating Unity with BCI2000, see [[User Tutorial:UnityBCI2000]]. This tutorial will use a sample Unity project, the same as the full tutorial.&lt;br /&gt;
&lt;br /&gt;
===Download Unity===&lt;br /&gt;
&lt;br /&gt;
Download Unity Hub from [https://unity3d.com Unity].&lt;br /&gt;
&lt;br /&gt;
===Setting Up BCI2000===&lt;br /&gt;
&lt;br /&gt;
Follow the instructions starting with [https://www.bci2000.org/mediawiki/index.php/Programming_Howto:Install_Prerequisites] to download BCI2000. &lt;br /&gt;
&lt;br /&gt;
===Setting Up UnityBCI2000===&lt;br /&gt;
Download UnityBCI2000 from its GitHub page, [https://github.com/neurotechcenter/UnityBCI2000]. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the &amp;quot;Releases&amp;quot; section on the right side of the page. This tutorial is intended to be used with UnityBCI2000 version 2.0.0, so scroll to that release and click on the files BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to download them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Download Tutorial Project===&lt;br /&gt;
Download the CursorTask3 repository from [https://github.com/Personator01/CursorTask3 GitHub].&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Either:&lt;br /&gt;
	-Clone the git repository&lt;br /&gt;
	-Download the respository directly from GitHub&lt;br /&gt;
		-&amp;gt; Click the green &amp;quot;Code&amp;quot; button &lt;br /&gt;
		-&amp;gt; Select &amp;quot;Download ZIP&amp;quot;&lt;br /&gt;
		-&amp;gt; Extract the zip file&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The download directory contains two versions of the CursorTask3 project. One, CursorTask3-BCI2K, contains an example implementation of the task with BCI2000 integration. The other, CursorTask3-NoBCI2K, contains the same task without BCI2000 integration. This tutorial is a step by step guide on turning that second project into the first. &lt;br /&gt;
&lt;br /&gt;
===Opening the project===&lt;br /&gt;
Open the project in the Unity Editor, and open the CursorTask scene.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Open Unity Hub.&lt;br /&gt;
Click the &amp;quot;Add&amp;quot; button in the top right corner.&lt;br /&gt;
Navigate to the CursorTask3 directory downloaded previously.&lt;br /&gt;
Select the CursorTask3-NoBCI2K directory to add it to Unity Hub.&lt;br /&gt;
Click the CursorTask3-NoBCI2K project in the Unity Hub.&lt;br /&gt;
If prompted to select a version of Unity to use or install, select Unity 2022.3. The specific release number of Unity 2022.3 should not matter, so select the one labeled &amp;quot;LTS&amp;quot; for consistency.&lt;br /&gt;
The lower panel (the asset browser) should already show the Assets/Scenes directory, which contains a single scene called SampleScene.&lt;br /&gt;
Double-click SampleScene. This should open a scene with a box containing various lights and objects.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you wish to view the completed implementation, repeat these steps, but instead open the CursorTask3-BCI2K-Barebones directory. Note that in order to use the completed implementation, you will still need to set the Operator Path value of the UnityBCI2000 component of the BCI2000 game object.&lt;br /&gt;
&lt;br /&gt;
===Adding UnityBCI2000 to the project===&lt;br /&gt;
Add BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to your project&#039;s assets.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click Assets &amp;gt; Open Containing Folder to open your project directory.&lt;br /&gt;
Place the BCI2000RemoteNETStandard.dll and UnityBCI2000.cs files in the Assets folder.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add an empty GameObject called &#039;BCI2000&#039;. This will hold the scripts for controlling BCI2000. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click GameObject &amp;gt; Create Empty to create an empty GameObject, and name it &#039;BCI2000&#039;. (The object&#039;s specific name does not actually matter, it is only needed in order to reference it within other scripts)&lt;br /&gt;
You will notice that it now appears in the Scene Hierarchy panel, on the left side of the screen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the UnityBCI2000 component to the object.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the object in the Hierarchy panel. This will open it in the Inspector panel (the panel on the right side of the screen)&lt;br /&gt;
In the inspector, below the new object&#039;s Transform component, click the &amp;quot;Add Component&amp;quot; button, which will open up a small window for adding components.&lt;br /&gt;
Within this window, select Scripts &amp;gt; Unity BCI2000 to add the UnityBCI2000 component.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Configuring UnityBCI2000===&lt;br /&gt;
The inspector panel now contains the configuration options for UnityBCI2000. Set the options as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Local Operator&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This will start the operator on your computer when the Unity scene initializes. If we were instead connecting to an already-running instance of BCI2000, or an instance on another computer, this box would be deselected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Path&amp;lt;/code&amp;gt;: The path to the Operator executable. This will look something like this on Windows (C://path/to/bci2000/prog/Operator.exe)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Address&amp;lt;/code&amp;gt;: 127.0.0.1&lt;br /&gt;
&lt;br /&gt;
This is the address of the machine on which BCI2000 is running. Since we are running BCI2000 on the same computer as Unity, we leave it as 127.0.0.1, the loopback address.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Port&amp;lt;/code&amp;gt;: 3999&lt;br /&gt;
&lt;br /&gt;
This is the port on which BCI2000 is listening for commands. By default, it is 3999.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Modules&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to start the requested Signal Source, Signal Processing, and Application modules when the Unity scene initializes. Similarly to Start Local Operator, we would deselect this box if connecting to an already-running instance. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start With Scene&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to start a data collection run when the scene starts. Since we will be using BCI2000 itself to set experiment parameters, we will instead wait for BCI2000 to start from Unity, and thus will leave the box unchecked. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Stop With Scene&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to stop collecting data when the scene stops. Since we will be controlling BCI2000 directly, rather than entirely through Unity, we will leave this unchecked.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Shutdown With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to shut down alongside the Unity scene. Whether or not this value is set ultimately doesn&#039;t matter much, especially if Start Local Operator is checked. The data will be saved whether or not BCI2000 shuts down. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 1&amp;lt;/code&amp;gt;: SignalGenerator&lt;br /&gt;
&lt;br /&gt;
The signal source module to start. We will use SignalGenerator, which generates a signal without any connected hardware.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 2&amp;lt;/code&amp;gt;: DummySignalProcessing&lt;br /&gt;
&lt;br /&gt;
The signal processing module to start. We will use DummySignalProcessing, as there is no processing to do.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 3&amp;lt;/code&amp;gt;: DummyApplication&lt;br /&gt;
&lt;br /&gt;
The Application module to start. Since we are using Unity, we will use DummyApplication.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Setting References===&lt;br /&gt;
In order for the game&#039;s scripts to communicate with BCI2000, they need to hold a reference to the UnityBCI2000 component.&lt;br /&gt;
There are three scripts which will need to communicate with BCI2000. They are &amp;lt;code&amp;gt;GameControl.cs, BallControl.cs, and MCursorControl.cs&amp;lt;/code&amp;gt;.&lt;br /&gt;
These scripts are each located within the Assets directory of the Unity project. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
As before, select Assets &amp;gt; Open Containing Folder to open the project directory, then open the Assets folder. &lt;br /&gt;
For each script, open it in a text editor.&lt;br /&gt;
Add a data member of type UnityBCI2000 to the class, like so:&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
Place the member definition above the Awake() method, for readability.&lt;br /&gt;
Within the Awake() method, set this reference to the UnityBCI2000 component.&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Each of the three scripts should contain a section like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
	void Awake() {&lt;br /&gt;
		bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
		...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding Events===&lt;br /&gt;
[https://www.bci2000.org/mediawiki/index.php/Programming_Reference:Events Events] are the primary way that non-signal experiment data is recorded in BCI2000. They are timestamped integer values which are encoded alongside the signal data in BCI2000 output files. Due to BCI2000&#039;s design, events must be added during a very specific part of its startup sequence, which is immediately after the BCI2000 operator starts, and before any of the modules start. As such, we cannot simply call &amp;lt;code&amp;gt;AddEvent()&amp;lt;/code&amp;gt; whenever we want. Furthermore, the order in which Unity objects initialize is undefined, so it cannot even be guaranteed that calling &amp;lt;code&amp;gt;AddEvent&amp;lt;/code&amp;gt; at a specific time will be consistent across multiple projects. As such, UnityBCI2000 provides a couple of methods for sending commands at well-defined points within the startup sequence. These two methods, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; allow BCI2000 commands to be sent while the operator is in the state Idle (immediately before starting its modules) and when the operator is in the state Connected (after starting and connecting to the modules. Below is an example of using those methods to add and show an event in BCI2000.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Script : MonoBehaviour {&lt;br /&gt;
    UnityBCI2000 bci;&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000Object&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;AnEvent&amp;quot;, 32);&lt;br /&gt;
	});&lt;br /&gt;
    }&lt;br /&gt;
    void Start() {&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;AnEvent&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As seen above, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; take a delegate (C#&#039;s term for a callback/closure/functor/etc.) with a single parameter of type &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt; (in this case called &amp;quot;remote&amp;quot;). The lambda expression given to the call to &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; uses the method &amp;lt;code&amp;gt;BCI2000Remote.AddEvent()&amp;lt;/code&amp;gt; to add an event called &amp;quot;AnEvent&amp;quot; with a bit width of 32 bits. The call to &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; tells BCI2000 to show the event&#039;s value in a graphical window. A description of the BCI2000Remote class can be found [https://www.bci2000.org/mediawiki/index.php/Contributions:BCI2000RemoteNET here], and API documentation can be found [https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html here].&lt;br /&gt;
&lt;br /&gt;
We will now add the events relevant to the Cursor Task. Open the &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt; script, and modify its &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; to add the events &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; with bit width 1. Additionally, add the events &amp;lt;code&amp;gt;TrialNumber&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetPositionX&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;TargetPositionY&amp;lt;/code&amp;gt; with width 16. These will encode the task state and number of trials.&lt;br /&gt;
We also need to set a parameter value so that the signal will be set to the mouse position. Using &amp;lt;code&amp;gt;BCI2000Remote.SetParameter()&amp;lt;/code&amp;gt;, we will set the &amp;lt;code&amp;gt;ModulateAmplitude&amp;lt;/code&amp;gt; parameter to 1.&lt;br /&gt;
&lt;br /&gt;
Open the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, and within the &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; function, add events &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt;, with width 16. Show these events in a visualization window with &amp;lt;code&amp;gt;Visualize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your two scripts should now look like this: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs &lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TrialNumber&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetPositionY&amp;quot;, 16);&lt;br /&gt;
	    remote.SetParameter(&amp;quot;ModulateAmplitude&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
	    });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionY&amp;quot;, 16);&lt;br /&gt;
	    });&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionX&amp;quot;);&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionY&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Reading the control signal===&lt;br /&gt;
We will be using the control signal to control the cursor. Open the &amp;lt;code&amp;gt;MCursorControl.cs&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
The commented out section of the &amp;lt;code&amp;gt;GetPos()&amp;lt;/code&amp;gt; method contains the code required to turn the control signal waveform coming from the Signal Source and Signal Processing modules into screen coordinates. &lt;br /&gt;
Uncomment the commented part and delete the line &amp;lt;code&amp;gt;Ray r = camera.ScreenPointToRay(Input.MousePosition);&amp;lt;/code&amp;gt;.&lt;br /&gt;
Change the &amp;lt;code&amp;gt;double signalX = 0;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;double signalY = 0;&amp;lt;/code&amp;gt; to. &lt;br /&gt;
&lt;br /&gt;
Your &amp;lt;code&amp;gt;GetPos()&amp;lt;/code&amp;gt; method should look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    Vector3 GetPos() {&lt;br /&gt;
	double signalX = bci.Control.GetSignal(1, bci.CurrentSampleOffset());&lt;br /&gt;
	double signalY = bci.Control.GetSignal(2, bci.CurrentSampleOffset());&lt;br /&gt;
	signalsX[signalIndex] = signalX;&lt;br /&gt;
	signalsY[signalIndex] = signalY;&lt;br /&gt;
	&lt;br /&gt;
	signalIndex = signalIndex + 1 &amp;gt;= rollingMaximumAmount ? 0 : signalIndex + 1;&lt;br /&gt;
	double max_x = signalsX.Max();&lt;br /&gt;
	double max_y = signalsY.Max();&lt;br /&gt;
	Ray r = camera.ScreenPointToRay(new Vector3((float) max_x * Screen.width, (float) max_y * Screen.height, 0));&lt;br /&gt;
	float p;&lt;br /&gt;
	if (!plane.Raycast(r, out p)) {&lt;br /&gt;
	   throw new Exception(&amp;quot;error casting ray to plane, invalid mouse position?&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	return r.GetPoint(p);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the use of the &amp;lt;code&amp;gt;UnityBCI2000.CurrentSampleOffset()&amp;lt;/code&amp;gt; method. This is a special method which gets the offset into the current block such that the sample is exactly one block length later than when it was collected by the hardware. This is to normalize the latency between when the hardware collects the signal and the software receives the signal, due to how BCI2000 processes data in blocks.&lt;br /&gt;
&lt;br /&gt;
===Sending events back to BCI2000===&lt;br /&gt;
&lt;br /&gt;
The primary way to communicate game state back to BCI2000 is via the use of Events, which are integer values encoded alongside the signal data.&lt;br /&gt;
&lt;br /&gt;
We will send the events that we added in a previous section.&lt;br /&gt;
&lt;br /&gt;
First, we will send back the current position of the cursor. Within the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, within the &amp;lt;code&amp;gt;Update()&amp;lt;/code&amp;gt; method, immediately after &amp;lt;code&amp;gt;Move()&amp;lt;/code&amp;gt; is called, set the &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt; events. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
void Update() {&lt;br /&gt;
    ...&lt;br /&gt;
    if (isTrialRunning) {&lt;br /&gt;
	...&lt;br /&gt;
	Move();&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;CursorPositionX&amp;quot;, (uint) ((transform.position.x + 7) * 1000));&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;CursorPositionY&amp;quot;, (uint) ((transform.position.y + 4.5) * 1000));&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that we transform the value of the cursor&#039;s position. This is because events in BCI2000 are represented as unsigned integers, so, for example, the cursor&#039;s range of movement in the x axis, -7 to 7, would not be directly representable within a BCI2000 event, so we add 7 so it is positive, and multiply by 1000 so that we have a more precise measure of the cursor&#039;s position. The range of [-7,7] becomes [0,14000].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We will also set the events corresponding to the game state within &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;. First we will set &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt; to represent when the game is in these states. To do this, at the beginning and end of &amp;lt;code&amp;gt;PreTrial()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Trial()&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PostTrial()&amp;lt;/code&amp;gt;, we will set the corresponding event values to 1 and 0, respectively.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator PreTrial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PreFeedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
IEnumerator Trial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
IEnumerator PostTrial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PostFeedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also set the events which happen at the end of each trial. The &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt; event is activated when the subject hits the target, and the &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; event is activated when the subject runs out of time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator Trial() {&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 0);&lt;br /&gt;
    if (lastTrialSucceeded) {&lt;br /&gt;
	bci.Control.PulseEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
    } else {&lt;br /&gt;
	bci.Control.PulseEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Notice that we use &amp;lt;code&amp;gt;BCI2000Remote.PulseEvent()&amp;lt;/code&amp;gt; rather than &amp;lt;code&amp;gt;BCI2000Remote.SetEvent()&amp;lt;/code&amp;gt;. This results in the event being set to the value &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for exactly one sample duration, then returning to zero.&lt;br /&gt;
&lt;br /&gt;
We will also record the position of the target. Similarly to the cursor, we will transform the target&#039;s coordinates to be a positive integer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator PreTrial() {&lt;br /&gt;
    ...&lt;br /&gt;
    target.SetActive(true);&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;TargetPositionX&amp;quot;, (uint) ((target.transform.position.x + 7) * 1000));&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;TargetPositionY&amp;quot;, (uint) ((target.transform.position.y + 4.5) * 1000));&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The last event we need to set is the trial number.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
IEnumerator ControlLoop() {&lt;br /&gt;
    ...&lt;br /&gt;
    while (IsContinue() &amp;amp;&amp;amp; trials &amp;lt; n_trials) {&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;TrialNumber&amp;quot;, trials + 1);&lt;br /&gt;
	...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Unity Player Settings===&lt;br /&gt;
Additionally, due to how Unity detects changes in BCI2000 state, it must be allowed to run in the background.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity menu bar:&lt;br /&gt;
    Edit &amp;gt; Project Settings &amp;gt; Player &amp;gt; Resolution and Presentation&lt;br /&gt;
Check the &amp;quot;Run In Background&amp;quot; box.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Usage===&lt;br /&gt;
&lt;br /&gt;
Now, when the Unity application runs, BCI2000 will open and start collecting data.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000_Barebones&amp;diff=11526</id>
		<title>User Tutorial:UnityBCI2000 Barebones</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000_Barebones&amp;diff=11526"/>
		<updated>2024-08-16T02:30:12Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Created page with &amp;quot;&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt; Red text blocks contain detailed instructions for the higher-level instructions preceding them. &amp;lt;/pre&amp;gt;  This tutorial goes over how to use BCI2000 as a logging service for an existing Unity project. For a more comprehensive tutorial on integrating Unity with BCI2000, see [User Tutorial:UnityBCI2000]. This tutorial will use a sample Unity project, the same as the full tutorial.  ===Download Unity===  Download Unity Hub from [https://unity3d.com Uni...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Red text blocks contain detailed instructions for the higher-level instructions preceding them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This tutorial goes over how to use BCI2000 as a logging service for an existing Unity project. For a more comprehensive tutorial on integrating Unity with BCI2000, see [User Tutorial:UnityBCI2000]. This tutorial will use a sample Unity project, the same as the full tutorial.&lt;br /&gt;
&lt;br /&gt;
===Download Unity===&lt;br /&gt;
&lt;br /&gt;
Download Unity Hub from [https://unity3d.com Unity].&lt;br /&gt;
&lt;br /&gt;
===Setting Up BCI2000===&lt;br /&gt;
&lt;br /&gt;
Follow the instructions starting with [https://www.bci2000.org/mediawiki/index.php/Programming_Howto:Install_Prerequisites] to download BCI2000. &lt;br /&gt;
&lt;br /&gt;
===Setting Up UnityBCI2000===&lt;br /&gt;
Download UnityBCI2000 from its GitHub page, [https://github.com/neurotechcenter/UnityBCI2000]. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the &amp;quot;Releases&amp;quot; section on the right side of the page. This tutorial is intended to be used with UnityBCI2000 version 2.0.0, so scroll to that release and click on the files BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to download them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Download Tutorial Project===&lt;br /&gt;
Download the CursorTask3 repository from [https://github.com/Personator01/CursorTask3 GitHub].&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Either:&lt;br /&gt;
	-Clone the git repository&lt;br /&gt;
	-Download the respository directly from GitHub&lt;br /&gt;
		-&amp;gt; Click the green &amp;quot;Code&amp;quot; button &lt;br /&gt;
		-&amp;gt; Select &amp;quot;Download ZIP&amp;quot;&lt;br /&gt;
		-&amp;gt; Extract the zip file&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The download directory contains two versions of the CursorTask3 project. One, CursorTask3-BCI2K, contains an example implementation of the task with BCI2000 integration. The other, CursorTask3-NoBCI2K, contains the same task without BCI2000 integration. This tutorial is a step by step guide on turning that second project into the first. &lt;br /&gt;
&lt;br /&gt;
===Opening the project===&lt;br /&gt;
Open the project in the Unity Editor, and open the CursorTask scene.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Open Unity Hub.&lt;br /&gt;
Click the &amp;quot;Add&amp;quot; button in the top right corner.&lt;br /&gt;
Navigate to the CursorTask3 directory downloaded previously.&lt;br /&gt;
Select the CursorTask3-NoBCI2K directory to add it to Unity Hub.&lt;br /&gt;
Click the CursorTask3-NoBCI2K project in the Unity Hub.&lt;br /&gt;
If prompted to select a version of Unity to use or install, select Unity 2022.3. The specific release number of Unity 2022.3 should not matter, so select the one labeled &amp;quot;LTS&amp;quot; for consistency.&lt;br /&gt;
The lower panel (the asset browser) should already show the Assets/Scenes directory, which contains a single scene called SampleScene.&lt;br /&gt;
Double-click SampleScene. This should open a scene with a box containing various lights and objects.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you wish to view the completed implementation, repeat these steps, but instead open the CursorTask3-BCI2K-Barebones directory. Note that in order to use the completed implementation, you will still need to set the Operator Path value of the UnityBCI2000 component of the BCI2000 game object.&lt;br /&gt;
&lt;br /&gt;
===Adding UnityBCI2000 to the project===&lt;br /&gt;
Add BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to your project&#039;s assets.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click Assets &amp;gt; Open Containing Folder to open your project directory.&lt;br /&gt;
Place the BCI2000RemoteNETStandard.dll and UnityBCI2000.cs files in the Assets folder.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add an empty GameObject called &#039;BCI2000&#039;. This will hold the scripts for controlling BCI2000. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click GameObject &amp;gt; Create Empty to create an empty GameObject, and name it &#039;BCI2000&#039;. (The object&#039;s specific name does not actually matter, it is only needed in order to reference it within other scripts)&lt;br /&gt;
You will notice that it now appears in the Scene Hierarchy panel, on the left side of the screen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the UnityBCI2000 component to the object.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the object in the Hierarchy panel. This will open it in the Inspector panel (the panel on the right side of the screen)&lt;br /&gt;
In the inspector, below the new object&#039;s Transform component, click the &amp;quot;Add Component&amp;quot; button, which will open up a small window for adding components.&lt;br /&gt;
Within this window, select Scripts &amp;gt; Unity BCI2000 to add the UnityBCI2000 component.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Configuring UnityBCI2000===&lt;br /&gt;
The inspector panel now contains the configuration options for UnityBCI2000. Set the options as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Local Operator&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This will start the operator on your computer when the Unity scene initializes. If we were instead connecting to an already-running instance of BCI2000, or an instance on another computer, this box would be deselected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Path&amp;lt;/code&amp;gt;: The path to the Operator executable. This will look something like this on Windows (C://path/to/bci2000/prog/Operator.exe)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Address&amp;lt;/code&amp;gt;: 127.0.0.1&lt;br /&gt;
&lt;br /&gt;
This is the address of the machine on which BCI2000 is running. Since we are running BCI2000 on the same computer as Unity, we leave it as 127.0.0.1, the loopback address.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Port&amp;lt;/code&amp;gt;: 3999&lt;br /&gt;
&lt;br /&gt;
This is the port on which BCI2000 is listening for commands. By default, it is 3999.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Modules&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to start the requested Signal Source, Signal Processing, and Application modules when the Unity scene initializes. Similarly to Start Local Operator, we would deselect this box if connecting to an already-running instance. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start With Scene&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to start a data collection run when the scene starts. Since we will be using BCI2000 itself to set experiment parameters, we will instead wait for BCI2000 to start from Unity, and thus will leave the box unchecked. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Stop With Scene&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to stop collecting data when the scene stops. Since we will be controlling BCI2000 directly, rather than entirely through Unity, we will leave this unchecked.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Shutdown With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to shut down alongside the Unity scene. Whether or not this value is set ultimately doesn&#039;t matter much, especially if Start Local Operator is checked. The data will be saved whether or not BCI2000 shuts down. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 1&amp;lt;/code&amp;gt;: SignalGenerator&lt;br /&gt;
&lt;br /&gt;
The signal source module to start. We will use SignalGenerator, which generates a signal without any connected hardware.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 2&amp;lt;/code&amp;gt;: DummySignalProcessing&lt;br /&gt;
&lt;br /&gt;
The signal processing module to start. We will use DummySignalProcessing, as there is no processing to do.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Module 3&amp;lt;/code&amp;gt;: DummyApplication&lt;br /&gt;
&lt;br /&gt;
The Application module to start. Since we are using Unity, we will use DummyApplication.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Setting References===&lt;br /&gt;
In order for the game&#039;s scripts to communicate with BCI2000, they need to hold a reference to the UnityBCI2000 component.&lt;br /&gt;
There are three scripts which will need to communicate with BCI2000. They are &amp;lt;code&amp;gt;GameControl.cs, BallControl.cs, and MCursorControl.cs&amp;lt;/code&amp;gt;.&lt;br /&gt;
These scripts are each located within the Assets directory of the Unity project. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
As before, select Assets &amp;gt; Open Containing Folder to open the project directory, then open the Assets folder. &lt;br /&gt;
For each script, open it in a text editor.&lt;br /&gt;
Add a data member of type UnityBCI2000 to the class, like so:&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
Place the member definition above the Awake() method, for readability.&lt;br /&gt;
Within the Awake() method, set this reference to the UnityBCI2000 component.&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Each of the three scripts should contain a section like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
	void Awake() {&lt;br /&gt;
		bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
		...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding Events===&lt;br /&gt;
[https://www.bci2000.org/mediawiki/index.php/Programming_Reference:Events Events] are the primary way that non-signal experiment data is recorded in BCI2000. They are timestamped integer values which are encoded alongside the signal data in BCI2000 output files. Due to BCI2000&#039;s design, events must be added during a very specific part of its startup sequence, which is immediately after the BCI2000 operator starts, and before any of the modules start. As such, we cannot simply call &amp;lt;code&amp;gt;AddEvent()&amp;lt;/code&amp;gt; whenever we want. Furthermore, the order in which Unity objects initialize is undefined, so it cannot even be guaranteed that calling &amp;lt;code&amp;gt;AddEvent&amp;lt;/code&amp;gt; at a specific time will be consistent across multiple projects. As such, UnityBCI2000 provides a couple of methods for sending commands at well-defined points within the startup sequence. These two methods, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; allow BCI2000 commands to be sent while the operator is in the state Idle (immediately before starting its modules) and when the operator is in the state Connected (after starting and connecting to the modules. Below is an example of using those methods to add and show an event in BCI2000.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Script : MonoBehaviour {&lt;br /&gt;
    UnityBCI2000 bci;&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000Object&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;AnEvent&amp;quot;, 32);&lt;br /&gt;
	});&lt;br /&gt;
    }&lt;br /&gt;
    void Start() {&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;AnEvent&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As seen above, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; take a delegate (C#&#039;s term for a callback/closure/functor/etc.) with a single parameter of type &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt; (in this case called &amp;quot;remote&amp;quot;). The lambda expression given to the call to &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; uses the method &amp;lt;code&amp;gt;BCI2000Remote.AddEvent()&amp;lt;/code&amp;gt; to add an event called &amp;quot;AnEvent&amp;quot; with a bit width of 32 bits. The call to &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; tells BCI2000 to show the event&#039;s value in a graphical window. A description of the BCI2000Remote class can be found [https://www.bci2000.org/mediawiki/index.php/Contributions:BCI2000RemoteNET here], and API documentation can be found [https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html here].&lt;br /&gt;
&lt;br /&gt;
We will now add the events relevant to the Cursor Task. Open the &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt; script, and modify its &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; to add the events &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; with bit width 1. Additionally, add the events &amp;lt;code&amp;gt;TrialNumber&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetPositionX&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;TargetPositionY&amp;lt;/code&amp;gt; with width 16. These will encode the task state and number of trials.&lt;br /&gt;
We also need to set a parameter value so that the signal will be set to the mouse position. Using &amp;lt;code&amp;gt;BCI2000Remote.SetParameter()&amp;lt;/code&amp;gt;, we will set the &amp;lt;code&amp;gt;ModulateAmplitude&amp;lt;/code&amp;gt; parameter to 1.&lt;br /&gt;
&lt;br /&gt;
Open the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, and within the &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; function, add events &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt;, with width 16. Show these events in a visualization window with &amp;lt;code&amp;gt;Visualize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your two scripts should now look like this: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs &lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TrialNumber&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetPositionY&amp;quot;, 16);&lt;br /&gt;
	    remote.SetParameter(&amp;quot;ModulateAmplitude&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
	    });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionY&amp;quot;, 16);&lt;br /&gt;
	    });&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionX&amp;quot;);&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionY&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Reading the control signal===&lt;br /&gt;
We will be using the control signal to control the cursor. Open the &amp;lt;code&amp;gt;MCursorControl.cs&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
The commented out section of the &amp;lt;code&amp;gt;GetPos()&amp;lt;/code&amp;gt; method contains the code required to turn the control signal waveform coming from the Signal Source and Signal Processing modules into screen coordinates. &lt;br /&gt;
Uncomment the commented part and delete the line &amp;lt;code&amp;gt;Ray r = camera.ScreenPointToRay(Input.MousePosition);&amp;lt;/code&amp;gt;.&lt;br /&gt;
Change the &amp;lt;code&amp;gt;double signalX = 0;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;double signalY = 0;&amp;lt;/code&amp;gt; to. &lt;br /&gt;
&lt;br /&gt;
Your &amp;lt;code&amp;gt;GetPos()&amp;lt;/code&amp;gt; method should look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    Vector3 GetPos() {&lt;br /&gt;
	double signalX = bci.Control.GetSignal(1, bci.CurrentSampleOffset());&lt;br /&gt;
	double signalY = bci.Control.GetSignal(2, bci.CurrentSampleOffset());&lt;br /&gt;
	signalsX[signalIndex] = signalX;&lt;br /&gt;
	signalsY[signalIndex] = signalY;&lt;br /&gt;
	&lt;br /&gt;
	signalIndex = signalIndex + 1 &amp;gt;= rollingMaximumAmount ? 0 : signalIndex + 1;&lt;br /&gt;
	double max_x = signalsX.Max();&lt;br /&gt;
	double max_y = signalsY.Max();&lt;br /&gt;
	Ray r = camera.ScreenPointToRay(new Vector3((float) max_x * Screen.width, (float) max_y * Screen.height, 0));&lt;br /&gt;
	float p;&lt;br /&gt;
	if (!plane.Raycast(r, out p)) {&lt;br /&gt;
	   throw new Exception(&amp;quot;error casting ray to plane, invalid mouse position?&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	return r.GetPoint(p);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the use of the &amp;lt;code&amp;gt;UnityBCI2000.CurrentSampleOffset()&amp;lt;/code&amp;gt; method. This is a special method which gets the offset into the current block such that the sample is exactly one block length later than when it was collected by the hardware. This is to normalize the latency between when the hardware collects the signal and the software receives the signal, due to how BCI2000 processes data in blocks.&lt;br /&gt;
&lt;br /&gt;
===Sending events back to BCI2000===&lt;br /&gt;
&lt;br /&gt;
The primary way to communicate game state back to BCI2000 is via the use of Events, which are integer values encoded alongside the signal data.&lt;br /&gt;
&lt;br /&gt;
We will send the events that we added in a previous section.&lt;br /&gt;
&lt;br /&gt;
First, we will send back the current position of the cursor. Within the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, within the &amp;lt;code&amp;gt;Update()&amp;lt;/code&amp;gt; method, immediately after &amp;lt;code&amp;gt;Move()&amp;lt;/code&amp;gt; is called, set the &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt; events. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
void Update() {&lt;br /&gt;
    ...&lt;br /&gt;
    if (isTrialRunning) {&lt;br /&gt;
	...&lt;br /&gt;
	Move();&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;CursorPositionX&amp;quot;, (uint) ((transform.position.x + 7) * 1000));&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;CursorPositionY&amp;quot;, (uint) ((transform.position.y + 4.5) * 1000));&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that we transform the value of the cursor&#039;s position. This is because events in BCI2000 are represented as unsigned integers, so, for example, the cursor&#039;s range of movement in the x axis, -7 to 7, would not be directly representable within a BCI2000 event, so we add 7 so it is positive, and multiply by 1000 so that we have a more precise measure of the cursor&#039;s position. The range of [-7,7] becomes [0,14000].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We will also set the events corresponding to the game state within &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;. First we will set &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt; to represent when the game is in these states. To do this, at the beginning and end of &amp;lt;code&amp;gt;PreTrial()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Trial()&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PostTrial()&amp;lt;/code&amp;gt;, we will set the corresponding event values to 1 and 0, respectively.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator PreTrial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PreFeedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
IEnumerator Trial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
IEnumerator PostTrial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PostFeedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also set the events which happen at the end of each trial. The &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt; event is activated when the subject hits the target, and the &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; event is activated when the subject runs out of time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator Trial() {&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 0);&lt;br /&gt;
    if (lastTrialSucceeded) {&lt;br /&gt;
	bci.Control.PulseEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
    } else {&lt;br /&gt;
	bci.Control.PulseEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Notice that we use &amp;lt;code&amp;gt;BCI2000Remote.PulseEvent()&amp;lt;/code&amp;gt; rather than &amp;lt;code&amp;gt;BCI2000Remote.SetEvent()&amp;lt;/code&amp;gt;. This results in the event being set to the value &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for exactly one sample duration, then returning to zero.&lt;br /&gt;
&lt;br /&gt;
We will also record the position of the target. Similarly to the cursor, we will transform the target&#039;s coordinates to be a positive integer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator PreTrial() {&lt;br /&gt;
    ...&lt;br /&gt;
    target.SetActive(true);&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;TargetPositionX&amp;quot;, (uint) ((target.transform.position.x + 7) * 1000));&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;TargetPositionY&amp;quot;, (uint) ((target.transform.position.y + 4.5) * 1000));&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The last event we need to set is the trial number.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
IEnumerator ControlLoop() {&lt;br /&gt;
    ...&lt;br /&gt;
    while (IsContinue() &amp;amp;&amp;amp; trials &amp;lt; n_trials) {&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;TrialNumber&amp;quot;, trials + 1);&lt;br /&gt;
	...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Unity Player Settings===&lt;br /&gt;
Additionally, due to how Unity detects changes in BCI2000 state, it must be allowed to run in the background.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity menu bar:&lt;br /&gt;
    Edit &amp;gt; Project Settings &amp;gt; Player &amp;gt; Resolution and Presentation&lt;br /&gt;
Check the &amp;quot;Run In Background&amp;quot; box.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Usage===&lt;br /&gt;
&lt;br /&gt;
Now, when the Unity application runs, BCI2000 will open and start collecting data.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000&amp;diff=11520</id>
		<title>User Tutorial:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000&amp;diff=11520"/>
		<updated>2024-08-15T16:02:06Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Red text blocks contain detailed instructions for the higher-level instructions preceding them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example comprehensively demonstrates many of the capabilities of UnityBCI2000, and as such, is more than what is necessary for many usecases. If you just want to use BCI2000 as a logging backend for an existing Unity application, see the Barebones UnityBCI2000 tutorial.&lt;br /&gt;
&lt;br /&gt;
===Download Unity===&lt;br /&gt;
&lt;br /&gt;
Download Unity Hub from [https://unity3d.com Unity].&lt;br /&gt;
&lt;br /&gt;
===Setting Up BCI2000===&lt;br /&gt;
&lt;br /&gt;
Follow the instructions starting with [https://www.bci2000.org/mediawiki/index.php/Programming_Howto:Install_Prerequisites] to download BCI2000. &lt;br /&gt;
&lt;br /&gt;
===Setting Up UnityBCI2000===&lt;br /&gt;
Download UnityBCI2000 from its GitHub page, [https://github.com/neurotechcenter/UnityBCI2000]. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the &amp;quot;Releases&amp;quot; section on the right side of the page. This tutorial is intended to be used with UnityBCI2000 version 2.0.0, so scroll to that release and click on the files BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to download them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Download Tutorial Project===&lt;br /&gt;
Download the CursorTask3 repository from [https://github.com/Personator01/CursorTask3 GitHub].&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Either:&lt;br /&gt;
	-Clone the git repository&lt;br /&gt;
	-Download the respository directly from GitHub&lt;br /&gt;
		-&amp;gt; Click the green &amp;quot;Code&amp;quot; button &lt;br /&gt;
		-&amp;gt; Select &amp;quot;Download ZIP&amp;quot;&lt;br /&gt;
		-&amp;gt; Extract the zip file&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The download directory contains two versions of the CursorTask3 project. One, CursorTask3-BCI2K, contains an example implementation of the task with BCI2000 integration. The other, CursorTask3-NoBCI2K, contains the same task without BCI2000 integration. This tutorial is a step by step guide on turning that second project into the first. &lt;br /&gt;
&lt;br /&gt;
===Opening the project===&lt;br /&gt;
Open the project in the Unity Editor, and open the CursorTask scene.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Open Unity Hub.&lt;br /&gt;
Click the &amp;quot;Add&amp;quot; button in the top right corner.&lt;br /&gt;
Navigate to the CursorTask3 directory downloaded previously.&lt;br /&gt;
Select the CursorTask3-NoBCI2K directory to add it to Unity Hub.&lt;br /&gt;
Click the CursorTask3-NoBCI2K project in the Unity Hub.&lt;br /&gt;
If prompted to select a version of Unity to use or install, select Unity 2022.3. The specific release number of Unity 2022.3 should not matter, so select the one labeled &amp;quot;LTS&amp;quot; for consistency.&lt;br /&gt;
The lower panel (the asset browser) should already show the Assets/Scenes directory, which contains a single scene called SampleScene.&lt;br /&gt;
Double-click SampleScene. This should open a scene with a box containing various lights and objects.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you wish to view the completed implementation, repeat these steps, but instead open the CursorTask3-BCI2K directory. Note that in order to use the completed implementation, you will still need to set the Operator Path value of the UnityBCI2000 component of the BCI2000 game object.&lt;br /&gt;
&lt;br /&gt;
===Adding UnityBCI2000 to the project===&lt;br /&gt;
Add BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to your project&#039;s assets.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click Assets &amp;gt; Open Containing Folder to open your project directory.&lt;br /&gt;
Place the BCI2000RemoteNETStandard.dll and UnityBCI2000.cs files in the Assets folder.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add an empty GameObject called &#039;BCI2000&#039;. This will hold the scripts for controlling BCI2000. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click GameObject &amp;gt; Create Empty to create an empty GameObject, and name it &#039;BCI2000&#039;. (The object&#039;s specific name does not actually matter, it is only needed in order to reference it within other scripts)&lt;br /&gt;
You will notice that it now appears in the Scene Hierarchy panel, on the left side of the screen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the UnityBCI2000 component to the object.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the object in the Hierarchy panel. This will open it in the Inspector panel (the panel on the right side of the screen)&lt;br /&gt;
In the inspector, below the new object&#039;s Transform component, click the &amp;quot;Add Component&amp;quot; button, which will open up a small window for adding components.&lt;br /&gt;
Within this window, select Scripts &amp;gt; Unity BCI2000 to add the UnityBCI2000 component.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Configuring UnityBCI2000===&lt;br /&gt;
The inspector panel now contains the configuration options for UnityBCI2000. Set the options as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Local Operator&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This will start the operator on your computer when the Unity scene initializes. If we were instead connecting to an already-running instance of BCI2000, or an instance on another computer, this box would be deselected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Path&amp;lt;/code&amp;gt;: The path to the Operator executable. This will look something like this on Windows (C://path/to/bci2000/prog/Operator.exe)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Address&amp;lt;/code&amp;gt;: 127.0.0.1&lt;br /&gt;
&lt;br /&gt;
This is the address of the machine on which BCI2000 is running. Since we are running BCI2000 on the same computer as Unity, we leave it as 127.0.0.1, the loopback address.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Port&amp;lt;/code&amp;gt;: 3999&lt;br /&gt;
&lt;br /&gt;
This is the port on which BCI2000 is listening for commands. By default, it is 3999.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Modules&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to start the requested Signal Source, Signal Processing, and Application modules when the Unity scene initializes. Similarly to Start Local Operator, we would deselect this box if connecting to an already-running instance. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to start a data collection run when the scene starts. Since we will be using BCI2000 itself to set experiment parameters, we will instead wait for BCI2000 to start from Unity, and thus will leave the box unchecked. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Stop With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to stop collecting data when the scene stops. Since we will be controlling BCI2000 directly, rather than entirely through Unity, we will leave this unchecked.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Shutdown With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
&lt;br /&gt;
This tells BCI2000 to shut down alongside the Unity scene. Whether or not this value is set ultimately doesn&#039;t matter much, especially if Start Local Operator is checked. The data will be saved whether or not BCI2000 shuts down. &lt;br /&gt;
&lt;br /&gt;
===Setting References===&lt;br /&gt;
In order for the game&#039;s scripts to communicate with BCI2000, they need to hold a reference to the UnityBCI2000 component.&lt;br /&gt;
There are three scripts which will need to communicate with BCI2000. They are &amp;lt;code&amp;gt;GameControl.cs, BallControl.cs, and MCursorControl.cs&amp;lt;/code&amp;gt;.&lt;br /&gt;
These scripts are each located within the Assets directory of the Unity project. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
As before, select Assets &amp;gt; Open Containing Folder to open the project directory, then open the Assets folder. &lt;br /&gt;
For each script, open it in a text editor.&lt;br /&gt;
Add a data member of type UnityBCI2000 to the class, like so:&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
Place the member definition above the Awake() method, for readability.&lt;br /&gt;
Within the Awake() method, set this reference to the UnityBCI2000 component.&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Each of the three scripts should contain a section like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
	void Awake() {&lt;br /&gt;
		bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
		...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding Events===&lt;br /&gt;
[https://www.bci2000.org/mediawiki/index.php/Programming_Reference:Events Events] are the primary way that non-signal experiment data is recorded in BCI2000. They are timestamped integer values which are encoded alongside the signal data in BCI2000 output files. Due to BCI2000&#039;s design, events must be added during a very specific part of its startup sequence, which is immediately after the BCI2000 operator starts, and before any of the modules start. As such, we cannot simply call &amp;lt;code&amp;gt;AddEvent()&amp;lt;/code&amp;gt; whenever we want. Furthermore, the order in which Unity objects initialize is undefined, so it cannot even be guaranteed that calling &amp;lt;code&amp;gt;AddEvent&amp;lt;/code&amp;gt; at a specific time will be consistent across multiple projects. As such, UnityBCI2000 provides a couple of methods for sending commands at well-defined points within the startup sequence. These two methods, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; allow BCI2000 commands to be sent while the operator is in the state Idle (immediately before starting its modules) and when the operator is in the state Connected (after starting and connecting to the modules. Below is an example of using those methods to add and show an event in BCI2000.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Script : MonoBehaviour {&lt;br /&gt;
    UnityBCI2000 bci;&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000Object&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;AnEvent&amp;quot;, 32);&lt;br /&gt;
	});&lt;br /&gt;
    }&lt;br /&gt;
    void Start() {&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;AnEvent&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As seen above, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; take a delegate (C#&#039;s term for a callback/closure/functor/etc.) with a single parameter of type &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt; (in this case called &amp;quot;remote&amp;quot;). The lambda expression given to the call to &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; uses the method &amp;lt;code&amp;gt;BCI2000Remote.AddEvent()&amp;lt;/code&amp;gt; to add an event called &amp;quot;AnEvent&amp;quot; with a bit width of 32 bits. The call to &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; tells BCI2000 to show the event&#039;s value in a graphical window. A description of the BCI2000Remote class can be found [https://www.bci2000.org/mediawiki/index.php/Contributions:BCI2000RemoteNET here], and API documentation can be found [https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html here].&lt;br /&gt;
&lt;br /&gt;
We will now add the events relevant to the Cursor Task. Open the &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt; script, and modify its &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; to add the events &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; with bit width 1. Additionally, add the events &amp;lt;code&amp;gt;TrialNumber&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetPositionX&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;TargetPositionY&amp;lt;/code&amp;gt; with width 16. These will encode the task state and number of trials.&lt;br /&gt;
&lt;br /&gt;
Open the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, and within the &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; function, add events &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt;, with width 16. Show these events in a visualization window with &amp;lt;code&amp;gt;Visualize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your two scripts should now look like this: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs &lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TrialNumber&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetPositionY&amp;quot;, 16);&lt;br /&gt;
	    });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionY&amp;quot;, 16);&lt;br /&gt;
	    });&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionX&amp;quot;);&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionY&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using BCI2000 Parameters===&lt;br /&gt;
====Adding Parameters====&lt;br /&gt;
BCI2000&#039;s operator contains an interface for changing experiment parameters before running a task. By making use of this interface we can change the behavior of the task dynamically, without needing to rebuild the Unity project each time. In order to do this we need to define the parameters and add them to BCI2000, and later read their values after the operator has a chance to change them. &amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;This section is not strictly necessary. The project will function the same whether this is done or not, just without the option to change parameters at runtime. &amp;lt;/span&amp;gt; &lt;br /&gt;
&lt;br /&gt;
First, we define add parameters to BCI2000. Similarly to events, parameters must be added while the Operator is in the &amp;lt;code&amp;gt;Idle&amp;lt;/code&amp;gt; state, so we add them inside of &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt;, like below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public int someParameter = 5;&lt;br /&gt;
void Awake() {&lt;br /&gt;
    bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	remote.AddParameter(&amp;quot;Application:ParameterPlace&amp;quot;, &amp;quot;SomeParameter&amp;quot;, someParameter.ToString()); &lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
The first argument to the method is the section into which the parameter is placed, that is, on which tab and under which heading the parameter will appear within the Operator&#039;s parameter editor window (note that the section is not a scope, all parameter names must be unique). The second argument is the parameter name itself. The third argument is the default value of the parameter. We pass in the value of the parameter, so when it appears in the Operator, its default value is 5 (or another value if it has been changed in the Unity Editor). Note that all parameters are handled as strings, so we need to convert its value to a string when sending it.&lt;br /&gt;
&lt;br /&gt;
For &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;, we will add parameters corresponding to the Pre-Feedback, Feedback, and Post-Feedback durations, Target Radius, and Number of Trials.&lt;br /&gt;
For &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt;, we will add parameters corresponding to the Acceleration Scale, Coefficient of Restitution, Coefficient of Drag, and Attraction Curve Coefficient (how quickly the Ball moves to follow the Mouse Cursor).&lt;br /&gt;
For &amp;lt;code&amp;gt;MCursorControl.cs&amp;lt;/code&amp;gt;, we will add a parameter corresponding to the Rolling Maximum Amount.&lt;br /&gt;
&lt;br /&gt;
Your scripts should look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		remote.AddEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
		...&lt;br /&gt;
&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;PreFeedbackDuration&amp;quot;, preFeedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;FeedbackDuration&amp;quot;, feedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;PostFeedbackDuration&amp;quot;, postFeedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;TargetRadius&amp;quot;, targetRadius.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;Trials&amp;quot;, n_trials.ToString());&lt;br /&gt;
		});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;AccelerationScale&amp;quot;, accelerationScale.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;CoeffOfRestitution&amp;quot;, coefficientOfRestitution.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;CoeffOfDrag&amp;quot;, coefficientOfDrag.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;AccelerationCurve&amp;quot;, attractionCurveCoefficient.ToString());&lt;br /&gt;
		})}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; MCursorControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;RollingMaximumAmount&amp;quot;, rollingMaximumAmount.ToString());&lt;br /&gt;
		});&lt;br /&gt;
}&lt;br /&gt;
		&lt;br /&gt;
&lt;br /&gt;
====Reading and Validating Parameters====&lt;br /&gt;
Since we set the parameters within the BCI2000 operator, we need some way to read them back into Unity after they have been set. Specifically, we need to read them after the operator clicks the &amp;quot;Set Config&amp;quot; button within the BCI2000 Operator. How this timing synchronization is covered in the section [[Reacting to BCI2000 state changes]]. In this section we will cover reading and validating parameters.&lt;br /&gt;
&lt;br /&gt;
A method called &amp;lt;code&amp;gt;SetConfig&amp;lt;/code&amp;gt; is provided in each of the scripts in which we added parameters previously. This method will be called after the operator changes parameters. In this method we will read in parameters and parse them into valid values. Using the same example parameter as before:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void SetConfig() {&lt;br /&gt;
    try {&lt;br /&gt;
	someParameter = int.Parse(bci.Control.GetParameter(&amp;quot;SomeParameter&amp;quot;));&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
	bci.Error(&amp;quot;Could not parse parameter SomeParameter as int&amp;quot;);&lt;br /&gt;
	throw e;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that since we are now working outside the BCI2000 startup sequence, we use &amp;lt;code&amp;gt;UnityBCI2000.Control&amp;lt;/code&amp;gt; to call &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt; methods directly, rather than using &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt;. We also wrap the call within a try/catch block so that we can report erroneous parameters back to the operator. This is optional, but it keeps your project from failing silently and is otherwise useful for doing things like distributing your Unity project as a standalone executable, where logging errors can only be done through the BCI2000 operator. You can also write a helper function which handles parsing and error reporting for you:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int GetParseParameterInt(string paramName) {&lt;br /&gt;
    int p_val = bci.Control.GetParameter(&amp;quot;SomeParameter&amp;quot;);&lt;br /&gt;
    try {&lt;br /&gt;
	someParameter = int.Parse(p_val);&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
	bci.Error($&amp;quot;Could not parse parameter {paramName} (value {p_val}) as int&amp;quot;);&lt;br /&gt;
	throw e;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Unfortunately, since the version of C# used by Unity does not support type-parameterized parsing, you must write one of these helper functions for each type of data you want to store in a parameter (int, float, double, etc.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Read back the parameters added in the previous step. Your scripts should look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs &lt;br /&gt;
void SetConfig() {&lt;br /&gt;
	try {&lt;br /&gt;
	   preFeedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;PreFeedbackDuration&amp;quot;));&lt;br /&gt;
	   feedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;FeedbackDuration&amp;quot;));&lt;br /&gt;
	   postFeedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;PostFeedbackDuration&amp;quot;));&lt;br /&gt;
	   targetRadius = float.Parse(bci.Control.GetParameter(&amp;quot;TargetRadius&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse one of PreFeedbackDuration, FeedbackDuration, PostFeedbackDuration, or TargetRadius as a float&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
	try {&lt;br /&gt;
	   n_trials = int.Parse(bci.Control.GetParameter(&amp;quot;Trials&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse Trials as an int&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if (preFeedbackDuration &amp;lt; COUNTDOWN_DURATION) {&lt;br /&gt;
	   bci.Error(&amp;quot;preFeedbackDuration must be greater than or equal to 2.25&amp;quot;);&lt;br /&gt;
	   throw new Exception(&amp;quot;preFeedbackDuration must be greater than or equal to 2.25&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
    public void SetConfig() {&lt;br /&gt;
	try {&lt;br /&gt;
	   accelerationScale = float.Parse(bci.Control.GetParameter(&amp;quot;AccelerationScale&amp;quot;));&lt;br /&gt;
	   coefficientOfRestitution = float.Parse(bci.Control.GetParameter(&amp;quot;CoeffOfRestitution&amp;quot;));&lt;br /&gt;
	   coefficientOfDrag = float.Parse(bci.Control.GetParameter(&amp;quot;CoeffOfDrag&amp;quot;));&lt;br /&gt;
	   attractionCurveCoefficient = float.Parse(bci.Control.GetParameter(&amp;quot;AccelerationCurve&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse one of AccelerationScale, CoeffOfRestitution, CoeffOfDrag, AccelerationCurve as float&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; MCursorControl.cs&lt;br /&gt;
public void SetConfig() {&lt;br /&gt;
    try {&lt;br /&gt;
       rollingMaximumAmount = int.Parse(bci.Control.GetParameter(&amp;quot;RollingMaximumAmount&amp;quot;));&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
       bci.Error(&amp;quot;Could not parse parameter RollingMaximumAmount as int&amp;quot;);&lt;br /&gt;
       throw e;&lt;br /&gt;
    }&lt;br /&gt;
    signalsX = new int[rollingMaximumAmount];&lt;br /&gt;
    signalsY = new int[rollingMaximumAmount];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;, we also verify that the Pre-Feedback Duration is longer than the duration of the countdown that happens before each trial, and report errors to BCI2000 accordingly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Reacting to BCI2000 state changes===&lt;br /&gt;
Since we will be controlling the Unity task from BCI2000, we need some way to wait for BCI2000 to be in a specific state, for example, waiting for the operator to click Start and put the Operator Module into the Running state. UnityBCI2000 provides a method for this, the &amp;lt;code&amp;gt;UnityBCI2000.PollSystemState&amp;lt;/code&amp;gt; method. In order to wait for the Operator Module to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Running));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will check once per frame whether or not the Operator is in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state, and only continue once BCI2000 is in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state. Note that since &amp;lt;code&amp;gt;SystemState&amp;lt;/code&amp;gt; is a member of &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt;, we also need to add a &amp;lt;code&amp;gt;using BCI2000RemoteNET&amp;lt;/code&amp;gt; statement to our script.&lt;br /&gt;
&lt;br /&gt;
In our case, we need to react to the operator setting the parameters, starting the data collection, and stopping the data collection. These correspond to the Operator Module entering the &amp;lt;code&amp;gt;Resting&amp;lt;/code&amp;gt; state, entering the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state, and exiting the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt; script, we will wait for the system to be in the &amp;lt;code&amp;gt;Resting&amp;lt;/code&amp;gt; state at the start of the &amp;lt;code&amp;gt;ControLoop&amp;lt;/code&amp;gt; method, and wait for the system to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state immediately before the entering the trial loop. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
&lt;br /&gt;
    IEnumerator ControlLoop() {&lt;br /&gt;
	while (True) {&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: red&amp;quot;&amp;gt;&lt;br /&gt;
	   StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Resting));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	   try {&lt;br /&gt;
		...&lt;br /&gt;
	   } catch (Exception e) {&lt;br /&gt;
		continue;&lt;br /&gt;
	   }&lt;br /&gt;
	&lt;br /&gt;
	   int trials = 0;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: red&amp;quot;&amp;gt;&lt;br /&gt;
	   StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Running));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	   yield return new WaitForSeconds(preRunDuration);&lt;br /&gt;
	   while (IsContinue() &amp;amp;&amp;amp; trials &amp;lt; n_trials) {&lt;br /&gt;
		...&lt;br /&gt;
	   }&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need to check for the operator stopping data collection, so we modify the &amp;lt;code&amp;gt;IsContinue()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bool IsContinue () {&lt;br /&gt;
	return bci.Control.GetSystemState() == BCI2000Remote.SystemState.Running;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remember to add &amp;lt;code&amp;gt;using BCI2000RemoteNET;&amp;lt;/code&amp;gt; to the top of the script, so you can access the &amp;lt;code&amp;gt;SystemState&amp;lt;/code&amp;gt; enum.&lt;br /&gt;
&lt;br /&gt;
===Reading the control signal===&lt;br /&gt;
We will be using the control signal to control the cursor. Open the &amp;lt;code&amp;gt;MCursorControl.cs&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
The commented out section of the &amp;lt;code&amp;gt;GetPos()&amp;lt;/code&amp;gt; method contains the code required to turn the control signal waveform coming from the Signal Source and Signal Processing modules into screen coordinates. &lt;br /&gt;
Uncomment the commented part and delete the line &amp;lt;code&amp;gt;Ray r = camera.ScreenPointToRay(Input.MousePosition);&amp;lt;/code&amp;gt;.&lt;br /&gt;
Change the &amp;lt;code&amp;gt;double signalX = 0;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;double signalY = 0;&amp;lt;/code&amp;gt; to. &lt;br /&gt;
&lt;br /&gt;
Your &amp;lt;code&amp;gt;GetPos()&amp;lt;/code&amp;gt; method should look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    Vector3 GetPos() {&lt;br /&gt;
	double signalX = bci.Control.GetSignal(1, bci.CurrentSampleOffset());&lt;br /&gt;
	double signalY = bci.Control.GetSignal(2, bci.CurrentSampleOffset());&lt;br /&gt;
	signalsX[signalIndex] = signalX;&lt;br /&gt;
	signalsY[signalIndex] = signalY;&lt;br /&gt;
	&lt;br /&gt;
	signalIndex = signalIndex + 1 &amp;gt;= rollingMaximumAmount ? 0 : signalIndex + 1;&lt;br /&gt;
	double max_x = signalsX.Max();&lt;br /&gt;
	double max_y = signalsY.Max();&lt;br /&gt;
	Ray r = camera.ScreenPointToRay(new Vector3((float) max_x * Screen.width, (float) max_y * Screen.height, 0));&lt;br /&gt;
	float p;&lt;br /&gt;
	if (!plane.Raycast(r, out p)) {&lt;br /&gt;
	   throw new Exception(&amp;quot;error casting ray to plane, invalid mouse position?&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	return r.GetPoint(p);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the use of the &amp;lt;code&amp;gt;UnityBCI2000.CurrentSampleOffset()&amp;lt;/code&amp;gt; method. This is a special method which gets the offset into the current block such that the sample is exactly one block length later than when it was collected by the hardware. This is to normalize the latency between when the hardware collects the signal and the software receives the signal, due to how BCI2000 processes data in blocks.&lt;br /&gt;
&lt;br /&gt;
===Sending events back to BCI2000===&lt;br /&gt;
&lt;br /&gt;
The primary way to communicate game state back to BCI2000 is via the use of Events, which are integer values encoded alongside the signal data.&lt;br /&gt;
&lt;br /&gt;
We will send the events that we added in a previous section.&lt;br /&gt;
&lt;br /&gt;
First, we will send back the current position of the cursor. Within the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, within the &amp;lt;code&amp;gt;Update()&amp;lt;/code&amp;gt; method, immediately after &amp;lt;code&amp;gt;Move()&amp;lt;/code&amp;gt; is called, set the &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt; events. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
void Update() {&lt;br /&gt;
    ...&lt;br /&gt;
    if (isTrialRunning) {&lt;br /&gt;
	...&lt;br /&gt;
	Move();&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;CursorPositionX&amp;quot;, (uint) ((transform.position.x + 7) * 1000));&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;CursorPositionY&amp;quot;, (uint) ((transform.position.y + 4.5) * 1000));&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that we transform the value of the cursor&#039;s position. This is because events in BCI2000 are represented as unsigned integers, so, for example, the cursor&#039;s range of movement in the x axis, -7 to 7, would not be directly representable within a BCI2000 event, so we add 7 so it is positive, and multiply by 1000 so that we have a more precise measure of the cursor&#039;s position. The range of [-7,7] becomes [0,14000].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We will also set the events corresponding to the game state within &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;. First we will set &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt; to represent when the game is in these states. To do this, at the beginning and end of &amp;lt;code&amp;gt;PreTrial()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Trial()&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PostTrial()&amp;lt;/code&amp;gt;, we will set the corresponding event values to 1 and 0, respectively.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator PreTrial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PreFeedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
IEnumerator Trial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
IEnumerator PostTrial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PostFeedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also set the events which happen at the end of each trial. The &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt; event is activated when the subject hits the target, and the &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; event is activated when the subject runs out of time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator Trial() {&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 0);&lt;br /&gt;
    if (lastTrialSucceeded) {&lt;br /&gt;
	bci.Control.PulseEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
    } else {&lt;br /&gt;
	bci.Control.PulseEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Notice that we use &amp;lt;code&amp;gt;BCI2000Remote.PulseEvent()&amp;lt;/code&amp;gt; rather than &amp;lt;code&amp;gt;BCI2000Remote.SetEvent()&amp;lt;/code&amp;gt;. This results in the event being set to the value &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for exactly one sample duration, then returning to zero.&lt;br /&gt;
&lt;br /&gt;
We will also record the position of the target. Similarly to the cursor, we will transform the target&#039;s coordinates to be a positive integer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator PreTrial() {&lt;br /&gt;
    ...&lt;br /&gt;
    target.SetActive(true);&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;TargetPositionX&amp;quot;, (uint) ((target.transform.position.x + 7) * 1000));&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;TargetPositionY&amp;quot;, (uint) ((target.transform.position.y + 4.5) * 1000));&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The last event we need to set is the trial number.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
IEnumerator ControlLoop() {&lt;br /&gt;
    ...&lt;br /&gt;
    while (IsContinue() &amp;amp;&amp;amp; trials &amp;lt; n_trials) {&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;TrialNumber&amp;quot;, trials + 1);&lt;br /&gt;
	...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
===Unity Player Settings===&lt;br /&gt;
Additionally, due to how Unity detects changes in BCI2000 state, it must be allowed to run in the background.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity menu bar:&lt;br /&gt;
    Edit &amp;gt; Project Settings &amp;gt; Player &amp;gt; Resolution and Presentation&lt;br /&gt;
Check the &amp;quot;Run In Background&amp;quot; box.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Usage===&lt;br /&gt;
&lt;br /&gt;
Now, when the Unity application runs, BCI2000 will open. From here, parameters can be set via the Config window, then clicking Set Config and Start will start data collection.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000&amp;diff=11519</id>
		<title>User Tutorial:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000&amp;diff=11519"/>
		<updated>2024-08-15T01:34:18Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Added last parts&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Red text blocks contain detailed instructions for the higher-level instructions preceding them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example comprehensively demonstrates many of the capabilities of UnityBCI2000, and as such, is more than what is necessary for many usecases. If you just want to use BCI2000 as a logging backend for an existing Unity application, see the Barebones UnityBCI2000 tutorial.&lt;br /&gt;
&lt;br /&gt;
===Download Unity===&lt;br /&gt;
&lt;br /&gt;
Download Unity Hub from [https://unity3d.com Unity].&lt;br /&gt;
&lt;br /&gt;
===Setting Up BCI2000===&lt;br /&gt;
&lt;br /&gt;
Follow the instructions starting with [https://www.bci2000.org/mediawiki/index.php/Programming_Howto:Install_Prerequisites] to download BCI2000. &lt;br /&gt;
&lt;br /&gt;
===Setting Up UnityBCI2000===&lt;br /&gt;
Download UnityBCI2000 from its GitHub page, [https://github.com/neurotechcenter/UnityBCI2000]. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the &amp;quot;Releases&amp;quot; section on the right side of the page. This tutorial is intended to be used with UnityBCI2000 version 2.0.0, so scroll to that release and click on the files BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to download them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Download Tutorial Project===&lt;br /&gt;
Download the CursorTask3 repository from [https://github.com/Personator01/CursorTask3 GitHub].&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Either:&lt;br /&gt;
	-Clone the git repository&lt;br /&gt;
	-Download the respository directly from GitHub&lt;br /&gt;
		-&amp;gt; Click the green &amp;quot;Code&amp;quot; button &lt;br /&gt;
		-&amp;gt; Select &amp;quot;Download ZIP&amp;quot;&lt;br /&gt;
		-&amp;gt; Extract the zip file&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The download directory contains two versions of the CursorTask3 project. One, CursorTask3-BCI2K, contains an example implementation of the task with BCI2000 integration. The other, CursorTask3-NoBCI2K, contains the same task without BCI2000 integration. This tutorial is a step by step guide on turning that second project into the first. &lt;br /&gt;
&lt;br /&gt;
===Opening the project===&lt;br /&gt;
Open the project in the Unity Editor, and open the CursorTask scene.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Open Unity Hub.&lt;br /&gt;
Click the &amp;quot;Add&amp;quot; button in the top right corner.&lt;br /&gt;
Navigate to the CursorTask3 directory downloaded previously.&lt;br /&gt;
Select the CursorTask3-NoBCI2K directory to add it to Unity Hub.&lt;br /&gt;
Click the CursorTask3-NoBCI2K project in the Unity Hub.&lt;br /&gt;
If prompted to select a version of Unity to use or install, select Unity 2022.3. The specific release number of Unity 2022.3 should not matter, so select the one labeled &amp;quot;LTS&amp;quot; for consistency.&lt;br /&gt;
The lower panel (the asset browser) should already show the Assets/Scenes directory, which contains a single scene called SampleScene.&lt;br /&gt;
Double-click SampleScene. This should open a scene with a box containing various lights and objects.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you wish to view the completed implementation, repeat these steps, but instead open the CursorTask3-BCI2K directory. Note that in order to use the completed implementation, you will still need to set the Operator Path value of the UnityBCI2000 component of the BCI2000 game object.&lt;br /&gt;
&lt;br /&gt;
===Adding UnityBCI2000 to the project===&lt;br /&gt;
Add BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to your project&#039;s assets.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click Assets &amp;gt; Open Containing Folder to open your project directory.&lt;br /&gt;
Place the BCI2000RemoteNETStandard.dll and UnityBCI2000.cs files in the Assets folder.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add an empty GameObject called &#039;BCI2000&#039;. This will hold the scripts for controlling BCI2000. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click GameObject &amp;gt; Create Empty to create an empty GameObject, and name it &#039;BCI2000&#039;. (The object&#039;s specific name does not actually matter, it is only needed in order to reference it within other scripts)&lt;br /&gt;
You will notice that it now appears in the Scene Hierarchy panel, on the left side of the screen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the UnityBCI2000 component to the object.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the object in the Hierarchy panel. This will open it in the Inspector panel (the panel on the right side of the screen)&lt;br /&gt;
In the inspector, below the new object&#039;s Transform component, click the &amp;quot;Add Component&amp;quot; button, which will open up a small window for adding components.&lt;br /&gt;
Within this window, select Scripts &amp;gt; Unity BCI2000 to add the UnityBCI2000 component.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Configuring UnityBCI2000===&lt;br /&gt;
The inspector panel now contains the configuration options for UnityBCI2000. Set the options as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Local Operator&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
This will start the operator on your computer when the Unity scene initializes. If we were instead connecting to an already-running instance of BCI2000, or an instance on another computer, this box would be deselected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Path&amp;lt;/code&amp;gt;: The path to the Operator executable. This will look something like this on Windows (C://path/to/bci2000/prog/Operator.exe)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Address&amp;lt;/code&amp;gt;: 127.0.0.1&lt;br /&gt;
This is the address of the machine on which BCI2000 is running. Since we are running BCI2000 on the same computer as Unity, we leave it as 127.0.0.1, the loopback address.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Port&amp;lt;/code&amp;gt;: 3999&lt;br /&gt;
This is the port on which BCI2000 is listening for commands. By default, it is 3999.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Modules&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
This tells BCI2000 to start the requested Signal Source, Signal Processing, and Application modules when the Unity scene initializes. Similarly to Start Local Operator, we would deselect this box if connecting to an already-running instance. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
This tells BCI2000 to start a data collection run when the scene starts. Since we will be using BCI2000 itself to set experiment parameters, we will instead wait for BCI2000 to start from Unity, and thus will leave the box unchecked. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Stop With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
This tells BCI2000 to stop collecting data when the scene stops. Since we will be controlling BCI2000 directly, rather than entirely through Unity, we will leave this unchecked.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Shutdown With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
This tells BCI2000 to shut down alongside the Unity scene. Whether or not this value is set ultimately doesn&#039;t matter much, especially if Start Local Operator is checked. The data will be saved whether or not BCI2000 shuts down. &lt;br /&gt;
&lt;br /&gt;
===Setting References===&lt;br /&gt;
In order for the game&#039;s scripts to communicate with BCI2000, they need to hold a reference to the UnityBCI2000 component.&lt;br /&gt;
There are three scripts which will need to communicate with BCI2000. They are &amp;lt;code&amp;gt;GameControl.cs, BallControl.cs, and MCursorControl.cs&amp;lt;/code&amp;gt;.&lt;br /&gt;
These scripts are each located within the Assets directory of the Unity project. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
As before, select Assets &amp;gt; Open Containing Folder to open the project directory, then open the Assets folder. &lt;br /&gt;
For each script, open it in a text editor.&lt;br /&gt;
Add a data member of type UnityBCI2000 to the class, like so:&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
Place the member definition above the Awake() method, for readability.&lt;br /&gt;
Within the Awake() method, set this reference to the UnityBCI2000 component.&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Each of the three scripts should contain a section like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
	void Awake() {&lt;br /&gt;
		bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
		...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding Events===&lt;br /&gt;
[https://www.bci2000.org/mediawiki/index.php/Programming_Reference:Events Events] are the primary way that non-signal experiment data is recorded in BCI2000. They are timestamped integer values which are encoded alongside the signal data in BCI2000 output files. Due to BCI2000&#039;s design, events must be added during a very specific part of its startup sequence, which is immediately after the BCI2000 operator starts, and before any of the modules start. As such, we cannot simply call &amp;lt;code&amp;gt;AddEvent()&amp;lt;/code&amp;gt; whenever we want. Furthermore, the order in which Unity objects initialize is undefined, so it cannot even be guaranteed that calling &amp;lt;code&amp;gt;AddEvent&amp;lt;/code&amp;gt; at a specific time will be consistent across multiple projects. As such, UnityBCI2000 provides a couple of methods for sending commands at well-defined points within the startup sequence. These two methods, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; allow BCI2000 commands to be sent while the operator is in the state Idle (immediately before starting its modules) and when the operator is in the state Connected (after starting and connecting to the modules. Below is an example of using those methods to add and show an event in BCI2000.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Script : MonoBehaviour {&lt;br /&gt;
    UnityBCI2000 bci;&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000Object&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;AnEvent&amp;quot;, 32);&lt;br /&gt;
	});&lt;br /&gt;
    }&lt;br /&gt;
    void Start() {&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;AnEvent&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As seen above, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; take a delegate (C#&#039;s term for a callback/closure/functor/etc.) with a single parameter of type &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt; (in this case called &amp;quot;remote&amp;quot;). The lambda expression given to the call to &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; uses the method &amp;lt;code&amp;gt;BCI2000Remote.AddEvent()&amp;lt;/code&amp;gt; to add an event called &amp;quot;AnEvent&amp;quot; with a bit width of 32 bits. The call to &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; tells BCI2000 to show the event&#039;s value in a graphical window. A description of the BCI2000Remote class can be found [https://www.bci2000.org/mediawiki/index.php/Contributions:BCI2000RemoteNET here], and API documentation can be found [https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html here].&lt;br /&gt;
&lt;br /&gt;
We will now add the events relevant to the Cursor Task. Open the &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt; script, and modify its &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; to add the events &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; with bit width 1. Additionally, add the events &amp;lt;code&amp;gt;TrialNumber&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetPositionX&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;TargetPositionY&amp;lt;/code&amp;gt; with width 16. These will encode the task state and number of trials.&lt;br /&gt;
&lt;br /&gt;
Open the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, and within the &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; function, add events &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt;, with width 16. Show these events in a visualization window with &amp;lt;code&amp;gt;Visualize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your two scripts should now look like this: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs &lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TrialNumber&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetPositionY&amp;quot;, 16);&lt;br /&gt;
	    });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionY&amp;quot;, 16);&lt;br /&gt;
	    });&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionX&amp;quot;);&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionY&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using BCI2000 Parameters===&lt;br /&gt;
====Adding Parameters====&lt;br /&gt;
BCI2000&#039;s operator contains an interface for changing experiment parameters before running a task. By making use of this interface we can change the behavior of the task dynamically, without needing to rebuild the Unity project each time. In order to do this we need to define the parameters and add them to BCI2000, and later read their values after the operator has a chance to change them. &amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;This section is not strictly necessary. The project will function the same whether this is done or not, just without the option to change parameters at runtime. &amp;lt;/span&amp;gt; &lt;br /&gt;
&lt;br /&gt;
First, we define add parameters to BCI2000. Similarly to events, parameters must be added while the Operator is in the &amp;lt;code&amp;gt;Idle&amp;lt;/code&amp;gt; state, so we add them inside of &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt;, like below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public int someParameter = 5;&lt;br /&gt;
void Awake() {&lt;br /&gt;
    bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	remote.AddParameter(&amp;quot;Application:ParameterPlace&amp;quot;, &amp;quot;SomeParameter&amp;quot;, someParameter.ToString()); &lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
The first argument to the method is the section into which the parameter is placed, that is, on which tab and under which heading the parameter will appear within the Operator&#039;s parameter editor window (note that the section is not a scope, all parameter names must be unique). The second argument is the parameter name itself. The third argument is the default value of the parameter. We pass in the value of the parameter, so when it appears in the Operator, its default value is 5 (or another value if it has been changed in the Unity Editor). Note that all parameters are handled as strings, so we need to convert its value to a string when sending it.&lt;br /&gt;
&lt;br /&gt;
For &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;, we will add parameters corresponding to the Pre-Feedback, Feedback, and Post-Feedback durations, Target Radius, and Number of Trials.&lt;br /&gt;
For &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt;, we will add parameters corresponding to the Acceleration Scale, Coefficient of Restitution, Coefficient of Drag, and Attraction Curve Coefficient (how quickly the Ball moves to follow the Mouse Cursor).&lt;br /&gt;
For &amp;lt;code&amp;gt;MCursorControl.cs&amp;lt;/code&amp;gt;, we will add a parameter corresponding to the Rolling Maximum Amount.&lt;br /&gt;
&lt;br /&gt;
Your scripts should look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		remote.AddEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
		...&lt;br /&gt;
&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;PreFeedbackDuration&amp;quot;, preFeedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;FeedbackDuration&amp;quot;, feedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;PostFeedbackDuration&amp;quot;, postFeedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;TargetRadius&amp;quot;, targetRadius.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;Trials&amp;quot;, n_trials.ToString());&lt;br /&gt;
		});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;AccelerationScale&amp;quot;, accelerationScale.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;CoeffOfRestitution&amp;quot;, coefficientOfRestitution.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;CoeffOfDrag&amp;quot;, coefficientOfDrag.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;AccelerationCurve&amp;quot;, attractionCurveCoefficient.ToString());&lt;br /&gt;
		})}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; MCursorControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;RollingMaximumAmount&amp;quot;, rollingMaximumAmount.ToString());&lt;br /&gt;
		});&lt;br /&gt;
}&lt;br /&gt;
		&lt;br /&gt;
&lt;br /&gt;
====Reading and Validating Parameters====&lt;br /&gt;
Since we set the parameters within the BCI2000 operator, we need some way to read them back into Unity after they have been set. Specifically, we need to read them after the operator clicks the &amp;quot;Set Config&amp;quot; button within the BCI2000 Operator. How this timing synchronization is covered in the section [[Reacting to BCI2000 state changes]]. In this section we will cover reading and validating parameters.&lt;br /&gt;
&lt;br /&gt;
A method called &amp;lt;code&amp;gt;SetConfig&amp;lt;/code&amp;gt; is provided in each of the scripts in which we added parameters previously. This method will be called after the operator changes parameters. In this method we will read in parameters and parse them into valid values. Using the same example parameter as before:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void SetConfig() {&lt;br /&gt;
    try {&lt;br /&gt;
	someParameter = int.Parse(bci.Control.GetParameter(&amp;quot;SomeParameter&amp;quot;));&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
	bci.Error(&amp;quot;Could not parse parameter SomeParameter as int&amp;quot;);&lt;br /&gt;
	throw e;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that since we are now working outside the BCI2000 startup sequence, we use &amp;lt;code&amp;gt;UnityBCI2000.Control&amp;lt;/code&amp;gt; to call &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt; methods directly, rather than using &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt;. We also wrap the call within a try/catch block so that we can report erroneous parameters back to the operator. This is optional, but it keeps your project from failing silently and is otherwise useful for doing things like distributing your Unity project as a standalone executable, where logging errors can only be done through the BCI2000 operator. You can also write a helper function which handles parsing and error reporting for you:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int GetParseParameterInt(string paramName) {&lt;br /&gt;
    int p_val = bci.Control.GetParameter(&amp;quot;SomeParameter&amp;quot;);&lt;br /&gt;
    try {&lt;br /&gt;
	someParameter = int.Parse(p_val);&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
	bci.Error($&amp;quot;Could not parse parameter {paramName} (value {p_val}) as int&amp;quot;);&lt;br /&gt;
	throw e;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Unfortunately, since the version of C# used by Unity does not support type-parameterized parsing, you must write one of these helper functions for each type of data you want to store in a parameter (int, float, double, etc.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Read back the parameters added in the previous step. Your scripts should look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs &lt;br /&gt;
void SetConfig() {&lt;br /&gt;
	try {&lt;br /&gt;
	   preFeedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;PreFeedbackDuration&amp;quot;));&lt;br /&gt;
	   feedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;FeedbackDuration&amp;quot;));&lt;br /&gt;
	   postFeedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;PostFeedbackDuration&amp;quot;));&lt;br /&gt;
	   targetRadius = float.Parse(bci.Control.GetParameter(&amp;quot;TargetRadius&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse one of PreFeedbackDuration, FeedbackDuration, PostFeedbackDuration, or TargetRadius as a float&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
	try {&lt;br /&gt;
	   n_trials = int.Parse(bci.Control.GetParameter(&amp;quot;Trials&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse Trials as an int&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if (preFeedbackDuration &amp;lt; COUNTDOWN_DURATION) {&lt;br /&gt;
	   bci.Error(&amp;quot;preFeedbackDuration must be greater than or equal to 2.25&amp;quot;);&lt;br /&gt;
	   throw new Exception(&amp;quot;preFeedbackDuration must be greater than or equal to 2.25&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
    public void SetConfig() {&lt;br /&gt;
	try {&lt;br /&gt;
	   accelerationScale = float.Parse(bci.Control.GetParameter(&amp;quot;AccelerationScale&amp;quot;));&lt;br /&gt;
	   coefficientOfRestitution = float.Parse(bci.Control.GetParameter(&amp;quot;CoeffOfRestitution&amp;quot;));&lt;br /&gt;
	   coefficientOfDrag = float.Parse(bci.Control.GetParameter(&amp;quot;CoeffOfDrag&amp;quot;));&lt;br /&gt;
	   attractionCurveCoefficient = float.Parse(bci.Control.GetParameter(&amp;quot;AccelerationCurve&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse one of AccelerationScale, CoeffOfRestitution, CoeffOfDrag, AccelerationCurve as float&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; MCursorControl.cs&lt;br /&gt;
public void SetConfig() {&lt;br /&gt;
    try {&lt;br /&gt;
       rollingMaximumAmount = int.Parse(bci.Control.GetParameter(&amp;quot;RollingMaximumAmount&amp;quot;));&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
       bci.Error(&amp;quot;Could not parse parameter RollingMaximumAmount as int&amp;quot;);&lt;br /&gt;
       throw e;&lt;br /&gt;
    }&lt;br /&gt;
    signalsX = new int[rollingMaximumAmount];&lt;br /&gt;
    signalsY = new int[rollingMaximumAmount];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;, we also verify that the Pre-Feedback Duration is longer than the duration of the countdown that happens before each trial, and report errors to BCI2000 accordingly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Reacting to BCI2000 state changes===&lt;br /&gt;
Since we will be controlling the Unity task from BCI2000, we need some way to wait for BCI2000 to be in a specific state, for example, waiting for the operator to click Start and put the Operator Module into the Running state. UnityBCI2000 provides a method for this, the &amp;lt;code&amp;gt;UnityBCI2000.PollSystemState&amp;lt;/code&amp;gt; method. In order to wait for the Operator Module to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Running));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will check once per frame whether or not the Operator is in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state, and only continue once BCI2000 is in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state. Note that since &amp;lt;code&amp;gt;SystemState&amp;lt;/code&amp;gt; is a member of &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt;, we also need to add a &amp;lt;code&amp;gt;using BCI2000RemoteNET&amp;lt;/code&amp;gt; statement to our script.&lt;br /&gt;
&lt;br /&gt;
In our case, we need to react to the operator setting the parameters, starting the data collection, and stopping the data collection. These correspond to the Operator Module entering the &amp;lt;code&amp;gt;Resting&amp;lt;/code&amp;gt; state, entering the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state, and exiting the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt; script, we will wait for the system to be in the &amp;lt;code&amp;gt;Resting&amp;lt;/code&amp;gt; state at the start of the &amp;lt;code&amp;gt;ControLoop&amp;lt;/code&amp;gt; method, and wait for the system to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state immediately before the entering the trial loop. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
&lt;br /&gt;
    IEnumerator ControlLoop() {&lt;br /&gt;
	while (True) {&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: red&amp;quot;&amp;gt;&lt;br /&gt;
	   StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Resting));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	   try {&lt;br /&gt;
		...&lt;br /&gt;
	   } catch (Exception e) {&lt;br /&gt;
		continue;&lt;br /&gt;
	   }&lt;br /&gt;
	&lt;br /&gt;
	   int trials = 0;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: red&amp;quot;&amp;gt;&lt;br /&gt;
	   StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Running));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	   yield return new WaitForSeconds(preRunDuration);&lt;br /&gt;
	   while (IsContinue() &amp;amp;&amp;amp; trials &amp;lt; n_trials) {&lt;br /&gt;
		...&lt;br /&gt;
	   }&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need to check for the operator stopping data collection, so we modify the &amp;lt;code&amp;gt;IsContinue()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bool IsContinue () {&lt;br /&gt;
	return bci.Control.GetSystemState() == BCI2000Remote.SystemState.Running;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remember to add &amp;lt;code&amp;gt;using BCI2000RemoteNET;&amp;lt;/code&amp;gt; to the top of the script, so you can access the &amp;lt;code&amp;gt;SystemState&amp;lt;/code&amp;gt; enum.&lt;br /&gt;
&lt;br /&gt;
===Reading the control signal===&lt;br /&gt;
We will be using the control signal to control the cursor. Open the &amp;lt;code&amp;gt;MCursorControl.cs&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
The commented out section of the &amp;lt;code&amp;gt;GetPos()&amp;lt;/code&amp;gt; method contains the code required to turn the control signal waveform coming from the Signal Source and Signal Processing modules into screen coordinates. &lt;br /&gt;
Uncomment the commented part and delete the line &amp;lt;code&amp;gt;Ray r = camera.ScreenPointToRay(Input.MousePosition);&amp;lt;/code&amp;gt;.&lt;br /&gt;
Change the &amp;lt;code&amp;gt;double signalX = 0;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;double signalY = 0;&amp;lt;/code&amp;gt; to. &lt;br /&gt;
&lt;br /&gt;
Your &amp;lt;code&amp;gt;GetPos()&amp;lt;/code&amp;gt; method should look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    Vector3 GetPos() {&lt;br /&gt;
	double signalX = bci.Control.GetSignal(1, bci.CurrentSampleOffset());&lt;br /&gt;
	double signalY = bci.Control.GetSignal(2, bci.CurrentSampleOffset());&lt;br /&gt;
	signalsX[signalIndex] = signalX;&lt;br /&gt;
	signalsY[signalIndex] = signalY;&lt;br /&gt;
	&lt;br /&gt;
	signalIndex = signalIndex + 1 &amp;gt;= rollingMaximumAmount ? 0 : signalIndex + 1;&lt;br /&gt;
	double max_x = signalsX.Max();&lt;br /&gt;
	double max_y = signalsY.Max();&lt;br /&gt;
	Ray r = camera.ScreenPointToRay(new Vector3((float) max_x * Screen.width, (float) max_y * Screen.height, 0));&lt;br /&gt;
	float p;&lt;br /&gt;
	if (!plane.Raycast(r, out p)) {&lt;br /&gt;
	   throw new Exception(&amp;quot;error casting ray to plane, invalid mouse position?&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	return r.GetPoint(p);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the use of the &amp;lt;code&amp;gt;UnityBCI2000.CurrentSampleOffset()&amp;lt;/code&amp;gt; method. This is a special method which gets the offset into the current block such that the sample is exactly one block length later than when it was collected by the hardware. This is to normalize the latency between when the hardware collects the signal and the software receives the signal, due to how BCI2000 processes data in blocks.&lt;br /&gt;
&lt;br /&gt;
===Sending events back to BCI2000===&lt;br /&gt;
&lt;br /&gt;
The primary way to communicate game state back to BCI2000 is via the use of Events, which are integer values encoded alongside the signal data.&lt;br /&gt;
&lt;br /&gt;
We will send the events that we added in a previous section.&lt;br /&gt;
&lt;br /&gt;
First, we will send back the current position of the cursor. Within the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, within the &amp;lt;code&amp;gt;Update()&amp;lt;/code&amp;gt; method, immediately after &amp;lt;code&amp;gt;Move()&amp;lt;/code&amp;gt; is called, set the &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt; events. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
void Update() {&lt;br /&gt;
    ...&lt;br /&gt;
    if (isTrialRunning) {&lt;br /&gt;
	...&lt;br /&gt;
	Move();&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;CursorPositionX&amp;quot;, (uint) ((transform.position.x + 7) * 1000));&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;CursorPositionY&amp;quot;, (uint) ((transform.position.y + 4.5) * 1000));&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that we transform the value of the cursor&#039;s position. This is because events in BCI2000 are represented as unsigned integers, so, for example, the cursor&#039;s range of movement in the x axis, -7 to 7, would not be directly representable within a BCI2000 event, so we add 7 so it is positive, and multiply by 1000 so that we have a more precise measure of the cursor&#039;s position. The range of [-7,7] becomes [0,14000].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We will also set the events corresponding to the game state within &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;. First we will set &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt; to represent when the game is in these states. To do this, at the beginning and end of &amp;lt;code&amp;gt;PreTrial()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Trial()&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;PostTrial()&amp;lt;/code&amp;gt;, we will set the corresponding event values to 1 and 0, respectively.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator PreTrial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PreFeedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
IEnumerator Trial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
IEnumerator PostTrial() {&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;PostFeedback&amp;quot;, 0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also set the events which happen at the end of each trial. The &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt; event is activated when the subject hits the target, and the &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; event is activated when the subject runs out of time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator Trial() {&lt;br /&gt;
    ...&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;Feedback&amp;quot;, 0);&lt;br /&gt;
    if (lastTrialSucceeded) {&lt;br /&gt;
	bci.Control.PulseEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
    } else {&lt;br /&gt;
	bci.Control.PulseEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Notice that we use &amp;lt;code&amp;gt;BCI2000Remote.PulseEvent()&amp;lt;/code&amp;gt; rather than &amp;lt;code&amp;gt;BCI2000Remote.SetEvent()&amp;lt;/code&amp;gt;. This results in the event being set to the value &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for exactly one sample duration, then returning to zero.&lt;br /&gt;
&lt;br /&gt;
We will also record the position of the target. Similarly to the cursor, we will transform the target&#039;s coordinates to be a positive integer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
IEnumerator PreTrial() {&lt;br /&gt;
    ...&lt;br /&gt;
    target.SetActive(true);&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;TargetPositionX&amp;quot;, (uint) ((target.transform.position.x + 7) * 1000));&lt;br /&gt;
    bci.Control.SetEvent(&amp;quot;TargetPositionY&amp;quot;, (uint) ((target.transform.position.y + 4.5) * 1000));&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The last event we need to set is the trial number.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
IEnumerator ControlLoop() {&lt;br /&gt;
    ...&lt;br /&gt;
    while (IsContinue() &amp;amp;&amp;amp; trials &amp;lt; n_trials) {&lt;br /&gt;
	bci.Control.SetEvent(&amp;quot;TrialNumber&amp;quot;, trials + 1);&lt;br /&gt;
	...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
===Unity Player Settings===&lt;br /&gt;
Additionally, due to how Unity detects changes in BCI2000 state, it must be allowed to run in the background.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity menu bar:&lt;br /&gt;
    Edit &amp;gt; Project Settings &amp;gt; Player &amp;gt; Resolution and Presentation&lt;br /&gt;
Check the &amp;quot;Run In Background&amp;quot; box.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Usage===&lt;br /&gt;
&lt;br /&gt;
Now, when the Unity application runs, BCI2000 will open. From here, parameters can be set via the Config window, then clicking Set Config and Start will start data collection.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000&amp;diff=11492</id>
		<title>User Tutorial:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:UnityBCI2000&amp;diff=11492"/>
		<updated>2024-08-06T16:10:27Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Added unity tutorial&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Red text blocks contain detailed instructions for the higher-level instructions preceding them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example demonstrates many of the capabilities of UnityBCI2000, and as such,&lt;br /&gt;
&lt;br /&gt;
===Download Unity===&lt;br /&gt;
&lt;br /&gt;
Download Unity Hub from [https://unity3d.com Unity].&lt;br /&gt;
&lt;br /&gt;
===Setting Up BCI2000===&lt;br /&gt;
&lt;br /&gt;
Follow the instructions starting with [https://www.bci2000.org/mediawiki/index.php/Programming_Howto:Install_Prerequisites] to download BCI2000. &lt;br /&gt;
&lt;br /&gt;
===Setting Up UnityBCI2000===&lt;br /&gt;
Download UnityBCI2000 from its GitHub page, [https://github.com/neurotechcenter/UnityBCI2000]. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the &amp;quot;Releases&amp;quot; section on the right side of the page. This tutorial is intended to be used with UnityBCI2000 version 2.0.0, so scroll to that release and click on the files BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to download them.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Download Tutorial Project===&lt;br /&gt;
Download the CursorTask3 repository from [https://github.com/Personator01/CursorTask3 GitHub].&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Either:&lt;br /&gt;
	-Clone the git repository&lt;br /&gt;
	-Download the respository directly from GitHub&lt;br /&gt;
		-&amp;gt; Click the green &amp;quot;Code&amp;quot; button &lt;br /&gt;
		-&amp;gt; Select &amp;quot;Download ZIP&amp;quot;&lt;br /&gt;
		-&amp;gt; Extract the zip file&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The downloade directory contains two versions of the CursorTask3 project. One, CursorTask3-BCI2K, contains an example implementation of the task with BCI2000 integration. The other, CursorTask3-NoBCI2K, contains the same task without BCI2000 integration. This tutorial is a step by step guide on turning that second project into the first. &lt;br /&gt;
&lt;br /&gt;
===Opening the project===&lt;br /&gt;
Open the project in the Unity Editor, and open the CursorTask scene.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Open Unity Hub.&lt;br /&gt;
Click the &amp;quot;Add&amp;quot; button in the top right corner.&lt;br /&gt;
Navigate to the CursorTask3 directory downloaded previously.&lt;br /&gt;
Select the CursorTask3-NoBCI2K directory to add it to Unity Hub.&lt;br /&gt;
Click the CursorTask3-NoBCI2K project in the Unity Hub.&lt;br /&gt;
If prompted to select a version of Unity to use or install, select Unity 2022.3. The specific release number of Unity 2022.3 should not matter, so select the one labeled &amp;quot;LTS&amp;quot; for consistency.&lt;br /&gt;
The lower panel (the asset browser) should already show the Assets/Scenes directory, which contains a single scene called SampleScene.&lt;br /&gt;
Double-click SampleScene. This should open a scene with a box containing various lights and objects.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you wish to view the completed implementation, repeat these steps, but instead open the CursorTask3-BCI2K directory. Note that in order to use the completed implementation, you will still need to set the Operator Path value of the UnityBCI2000 component of the BCI2000 game object.&lt;br /&gt;
&lt;br /&gt;
===Adding UnityBCI2000 to the project===&lt;br /&gt;
Add BCI2000RemoteNETStandard.dll and UnityBCI2000.cs to your project&#039;s assets.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click Assets &amp;gt; Open Containing Folder to open your project directory.&lt;br /&gt;
Place the BCI2000RemoteNETStandard.dll and UnityBCI2000.cs files in the Assets folder.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add an empty GameObject called &#039;BCI2000&#039;. This will hold the scripts for controlling BCI2000. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
In the Unity Editor&#039;s menu bar, click GameObject &amp;gt; Create Empty to create an empty GameObject, and name it &#039;BCI2000&#039;. (The object&#039;s specific name does not actually matter, it is only needed in order to reference it within other scripts)&lt;br /&gt;
You will notice that it now appears in the Scene Hierarchy panel, on the left side of the screen.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the UnityBCI2000 component to the object.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Click on the object in the Hierarchy panel. This will open it in the Inspector panel (the panel on the right side of the screen)&lt;br /&gt;
In the inspector, below the new object&#039;s Transform component, click the &amp;quot;Add Component&amp;quot; button, which will open up a small window for adding components.&lt;br /&gt;
Within this window, select Scripts &amp;gt; Unity BCI2000 to add the UnityBCI2000 component.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Configuring UnityBCI2000===&lt;br /&gt;
The inspector panel now contains the configuration options for UnityBCI2000. Set the options as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Local Operator&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
This will start the operator on your computer when the Unity scene initializes. If we were instead connecting to an already-running instance of BCI2000, or an instance on another computer, this box would be deselected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Path&amp;lt;/code&amp;gt;: The path to the Operator executable. This will look something like this on Windows (C://path/to/bci2000/prog/Operator.exe)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Address&amp;lt;/code&amp;gt;: 127.0.0.1&lt;br /&gt;
This is the address of the machine on which BCI2000 is running. Since we are running BCI2000 on the same computer as Unity, we leave it as 127.0.0.1, the loopback address.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Operator Port&amp;lt;/code&amp;gt;: 3999&lt;br /&gt;
This is the port on which BCI2000 is listening for commands. By default, it is 3999.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start Modules&amp;lt;/code&amp;gt;: Checked&lt;br /&gt;
This tells BCI2000 to start the requested Signal Source, Signal Processing, and Application modules when the Unity scene initializes. Similarly to Start Local Operator, we would deselect this box if connecting to an already-running instance. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Start With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
This tells BCI2000 to start a data collection run when the scene starts. Since we will be using BCI2000 itself to set experiment parameters, we will instead wait for BCI2000 to start from Unity, and thus will leave the box unchecked. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Stop With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
This tells BCI2000 to stop collecting data when the scene stops. Since we will be controlling BCI2000 directly, rather than entirely through Unity, we will leave this unchecked.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Shutdown With Scene&amp;lt;/code&amp;gt;: Unchecked&lt;br /&gt;
This tells BCI2000 to shut down alongside the Unity scene. Whether or not this value is set ultimately doesn&#039;t matter much, especially if Start Local Operator is checked. The data will be saved whether or not BCI2000 shuts down. &lt;br /&gt;
&lt;br /&gt;
===Setting References===&lt;br /&gt;
In order for the game&#039;s scripts to communicate with BCI2000, they need to hold a reference to the UnityBCI2000 component.&lt;br /&gt;
There are three scripts which will need to communicate with BCI2000. They are &amp;lt;code&amp;gt;GameControl.cs, BallControl.cs, and MCursorControl.cs&amp;lt;/code&amp;gt;.&lt;br /&gt;
These scripts are each located within the Assets directory of the Unity project. &lt;br /&gt;
&amp;lt;pre style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
As before, select Assets &amp;gt; Open Containing Folder to open the project directory, then open the Assets folder. &lt;br /&gt;
For each script, open it in a text editor.&lt;br /&gt;
Add a data member of type UnityBCI2000 to the class, like so:&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
Place the member definition above the Awake() method, for readability.&lt;br /&gt;
Within the Awake() method, set this reference to the UnityBCI2000 component.&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Each of the three scripts should contain a section like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
	UnityBCI2000 bci;&lt;br /&gt;
	void Awake() {&lt;br /&gt;
		bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
		...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding Events===&lt;br /&gt;
[https://www.bci2000.org/mediawiki/index.php/Programming_Reference:Events Events] are the primary way that non-signal experiment data is recorded in BCI2000. They are timestamped integer values which are encoded alongside the signal data in BCI2000 output files. Due to BCI2000&#039;s design, events must be added during a very specific part of its startup sequence, which is immediately after the BCI2000 operator starts, and before any of the modules start. As such, we cannot simply call &amp;lt;code&amp;gt;AddEvent()&amp;lt;/code&amp;gt; whenever we want. Furthermore, the order in which Unity objects initialize is undefined, so it cannot even be guaranteed that calling &amp;lt;code&amp;gt;AddEvent&amp;lt;/code&amp;gt; at a specific time will be consistent across multiple projects. As such, UnityBCI2000 provides a couple of methods for sending commands at well-defined points within the startup sequence. These two methods, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; allow BCI2000 commands to be sent while the operator is in the state Idle (immediately before starting its modules) and when the operator is in the state Connected (after starting and connecting to the modules. Below is an example of using those methods to add and show an event in BCI2000.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Script : MonoBehaviour {&lt;br /&gt;
    UnityBCI2000 bci;&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000Object&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;AnEvent&amp;quot;, 32);&lt;br /&gt;
	});&lt;br /&gt;
    }&lt;br /&gt;
    void Start() {&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;AnEvent&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As seen above, &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; take a delegate (C#&#039;s term for a callback/closure/functor/etc.) with a single parameter of type &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt; (in this case called &amp;quot;remote&amp;quot;). The lambda expression given to the call to &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; uses the method &amp;lt;code&amp;gt;BCI2000Remote.AddEvent()&amp;lt;/code&amp;gt; to add an event called &amp;quot;AnEvent&amp;quot; with a bit width of 32 bits. The call to &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt; tells BCI2000 to show the event&#039;s value in a graphical window. A description of the BCI2000Remote class can be found [https://www.bci2000.org/mediawiki/index.php/Contributions:BCI2000RemoteNET here], and API documentation can be found [https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html here].&lt;br /&gt;
&lt;br /&gt;
We will now add the events relevant to the Cursor Task. Open the &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt; script, and modify its &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; to add the events &amp;lt;code&amp;gt;PreFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PostFeedback&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TargetHit&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt; with bit width 1. Additionally, add the event &amp;lt;code&amp;gt;TrialNumber&amp;lt;/code&amp;gt; with width 16. These will encode the task state and number of trials.&lt;br /&gt;
&lt;br /&gt;
Open the &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt; script, and within the &amp;lt;code&amp;gt;Awake()&amp;lt;/code&amp;gt; function, add events &amp;lt;code&amp;gt;CursorPositionX&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CursorPositionY&amp;lt;/code&amp;gt;, with width 16. Show these events in a visualization window with &amp;lt;code&amp;gt;Visualize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your two scripts should now look like this: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs &lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Feedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;PostFeedback&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TargetHit&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;Timeout&amp;quot;, 1);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;TrialNumber&amp;quot;, 16);&lt;br /&gt;
	    });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
    ...&lt;br /&gt;
    void Awake() {&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionX&amp;quot;, 16);&lt;br /&gt;
	    remote.AddEvent(&amp;quot;CursorPositionY&amp;quot;, 16);&lt;br /&gt;
	    });&lt;br /&gt;
	bci.OnConnected(remote =&amp;gt; {&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionX&amp;quot;);&lt;br /&gt;
	    remote.Visualize(&amp;quot;CursorPositionY&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using BCI2000 Parameters===&lt;br /&gt;
====Adding Parameters====&lt;br /&gt;
BCI2000&#039;s operator contains an interface for changing experiment parameters before running a task. By making use of this interface we can change the behavior of the task dynamically, without needing to rebuild the Unity project each time. In order to do this we need to define the parameters and add them to BCI2000, and later read their values after the operator has a chance to change them. &amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;This section is not strictly necessary. The project will function the same whether this is done or not, just without the option to change parameters at runtime. &amp;lt;/span&amp;gt; &lt;br /&gt;
&lt;br /&gt;
First, we define add parameters to BCI2000. Similarly to events, parameters must be added while the Operator is in the &amp;lt;code&amp;gt;Idle&amp;lt;/code&amp;gt; state, so we add them inside of &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt;, like below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public int someParameter = 5;&lt;br /&gt;
void Awake() {&lt;br /&gt;
    bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
	remote.AddParameter(&amp;quot;Application:ParameterPlace&amp;quot;, &amp;quot;SomeParameter&amp;quot;, someParameter.ToString()); &lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
The first argument to the method is the section into which the parameter is placed, that is, on which tab and under which heading the parameter will appear within the Operator&#039;s parameter editor window (note that the section is not a scope, all parameter names must be unique). The second argument is the parameter name itself. The third argument is the default value of the parameter. We pass in the value of the parameter, so when it appears in the Operator, its default value is 5 (or another value if it has been changed in the Unity Editor). Note that all parameters are handled as strings, so we need to convert its value to a string when sending it.&lt;br /&gt;
&lt;br /&gt;
For &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;, we will add parameters corresponding to the Pre-Feedback, Feedback, and Post-Feedback durations, Target Radius, and Number of Trials.&lt;br /&gt;
For &amp;lt;code&amp;gt;BallControl.cs&amp;lt;/code&amp;gt;, we will add parameters corresponding to the Acceleration Scale, Coefficient of Restitution, Coefficient of Drag, and Attraction Curve Coefficient (how quickly the Ball moves to follow the Mouse Cursor).&lt;br /&gt;
For &amp;lt;code&amp;gt;MCursorControl.cs&amp;lt;/code&amp;gt;, we will add a parameter corresponding to the Rolling Maximum Amount.&lt;br /&gt;
&lt;br /&gt;
Your scripts should look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		remote.AddEvent(&amp;quot;PreFeedback&amp;quot;, 1);&lt;br /&gt;
		...&lt;br /&gt;
&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;PreFeedbackDuration&amp;quot;, preFeedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;FeedbackDuration&amp;quot;, feedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;PostFeedbackDuration&amp;quot;, postFeedbackDuration.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;TargetRadius&amp;quot;, targetRadius.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Task&amp;quot;, &amp;quot;Trials&amp;quot;, n_trials.ToString());&lt;br /&gt;
		});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;AccelerationScale&amp;quot;, accelerationScale.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;CoeffOfRestitution&amp;quot;, coefficientOfRestitution.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;CoeffOfDrag&amp;quot;, coefficientOfDrag.ToString());&lt;br /&gt;
		remote.AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;AccelerationCurve&amp;quot;, attractionCurveCoefficient.ToString());&lt;br /&gt;
		})}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; MCursorControl.cs&lt;br /&gt;
void Awake() {&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	bci.OnIdle(remote =&amp;gt; {&lt;br /&gt;
		AddParameter(&amp;quot;Application:Physics&amp;quot;, &amp;quot;RollingMaximumAmount&amp;quot;, rollingMaximumAmount.ToString());&lt;br /&gt;
		});&lt;br /&gt;
}&lt;br /&gt;
		&lt;br /&gt;
&lt;br /&gt;
====Reading and Validating Parameters====&lt;br /&gt;
Since we set the parameters within the BCI2000 operator, we need some way to read them back into Unity after they have been set. Specifically, we need to read them after the operator clicks the &amp;quot;Set Config&amp;quot; button within the BCI2000 Operator. How this timing synchronization is covered in the section [[Reacting to BCI2000 state changes]]. In this section we will cover reading and validating parameters.&lt;br /&gt;
&lt;br /&gt;
A method called &amp;lt;code&amp;gt;SetConfig&amp;lt;/code&amp;gt; is provided in each of the scripts in which we added parameters previously. This method will be called after the operator changes parameters. In this method we will read in parameters and parse them into valid values. Using the same example parameter as before:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void SetConfig() {&lt;br /&gt;
    try {&lt;br /&gt;
	someParameter = int.Parse(bci.Control.GetParameter(&amp;quot;SomeParameter&amp;quot;));&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
	bci.Error(&amp;quot;Could not parse parameter SomeParameter as int&amp;quot;);&lt;br /&gt;
	throw e;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that since we are now working outside the BCI2000 startup sequence, we use &amp;lt;code&amp;gt;UnityBCI2000.Control&amp;lt;/code&amp;gt; to call &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt; methods directly, rather than using &amp;lt;code&amp;gt;OnIdle&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;OnConnected&amp;lt;/code&amp;gt;. We also wrap the call within a try/catch block so that we can report erroneous parameters back to the operator. This is optional, but it keeps your project from failing silently and is otherwise useful for doing things like distributing your Unity project as a standalone executable, where logging errors can only be done through the BCI2000 operator. You can also write a helper function which handles parsing and error reporting for you:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int GetParseParameterInt(string paramName) {&lt;br /&gt;
    int p_val = bci.Control.GetParameter(&amp;quot;SomeParameter&amp;quot;);&lt;br /&gt;
    try {&lt;br /&gt;
	someParameter = int.Parse(p_val);&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
	bci.Error($&amp;quot;Could not parse parameter {paramName} (value {p_val}) as int&amp;quot;);&lt;br /&gt;
	throw e;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Unfortunately, since the version of C# used by Unity does not support type-parameterized parsing, you must write one of these helper functions for each type of data you want to store in a parameter (int, float, double, etc.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Read back the parameters added in the previous step. Your scripts should look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs &lt;br /&gt;
void SetConfig() {&lt;br /&gt;
	try {&lt;br /&gt;
	   preFeedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;PreFeedbackDuration&amp;quot;));&lt;br /&gt;
	   feedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;FeedbackDuration&amp;quot;));&lt;br /&gt;
	   postFeedbackDuration = float.Parse(bci.Control.GetParameter(&amp;quot;PostFeedbackDuration&amp;quot;));&lt;br /&gt;
	   targetRadius = float.Parse(bci.Control.GetParameter(&amp;quot;TargetRadius&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse one of PreFeedbackDuration, FeedbackDuration, PostFeedbackDuration, or TargetRadius as a float&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
	try {&lt;br /&gt;
	   n_trials = int.Parse(bci.Control.GetParameter(&amp;quot;Trials&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse Trials as an int&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if (preFeedbackDuration &amp;lt; COUNTDOWN_DURATION) {&lt;br /&gt;
	   bci.Error(&amp;quot;preFeedbackDuration must be greater than or equal to 2.25&amp;quot;);&lt;br /&gt;
	   throw new Exception(&amp;quot;preFeedbackDuration must be greater than or equal to 2.25&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; BallControl.cs&lt;br /&gt;
    public void SetConfig() {&lt;br /&gt;
	try {&lt;br /&gt;
	   accelerationScale = float.Parse(bci.Control.GetParameter(&amp;quot;AccelerationScale&amp;quot;));&lt;br /&gt;
	   coefficientOfRestitution = float.Parse(bci.Control.GetParameter(&amp;quot;CoeffOfRestitution&amp;quot;));&lt;br /&gt;
	   coefficientOfDrag = float.Parse(bci.Control.GetParameter(&amp;quot;CoeffOfDrag&amp;quot;));&lt;br /&gt;
	   attractionCurveCoefficient = float.Parse(bci.Control.GetParameter(&amp;quot;AccelerationCurve&amp;quot;));&lt;br /&gt;
	} catch (FormatException e) {&lt;br /&gt;
	   bci.Error(&amp;quot;Could not parse one of AccelerationScale, CoeffOfRestitution, CoeffOfDrag, AccelerationCurve as float&amp;quot;);&lt;br /&gt;
	   throw e;&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; MCursorControl.cs&lt;br /&gt;
public void SetConfig() {&lt;br /&gt;
    try {&lt;br /&gt;
       rollingMaximumAmount = int.Parse(bci.Control.GetParameter(&amp;quot;RollingMaximumAmount&amp;quot;));&lt;br /&gt;
    } catch (FormatException e) {&lt;br /&gt;
       bci.Error(&amp;quot;Could not parse parameter RollingMaximumAmount as int&amp;quot;);&lt;br /&gt;
       throw e;&lt;br /&gt;
    }&lt;br /&gt;
    signalsX = new int[rollingMaximumAmount];&lt;br /&gt;
    signalsY = new int[rollingMaximumAmount];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt;, we also verify that the Pre-Feedback Duration is longer than the duration of the countdown that happens before each trial, and report errors to BCI2000 accordingly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Reacting to BCI2000 state changes===&lt;br /&gt;
Since we will be controlling the Unity task from BCI2000, we need some way to wait for BCI2000 to be in a specific state, for example, waiting for the operator to click Start and put the Operator Module into the Running state. UnityBCI2000 provides a method for this, the &amp;lt;code&amp;gt;UnityBCI2000.PollSystemState&amp;lt;/code&amp;gt; method. In order to wait for the Operator Module to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Running));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will check once per frame whether or not the Operator is in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state, and only continue once BCI2000 is in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state. Note that since &amp;lt;code&amp;gt;SystemState&amp;lt;/code&amp;gt; is a member of &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt;, we also need to add a &amp;lt;code&amp;gt;using BCI2000RemoteNET&amp;lt;/code&amp;gt; statement to our script.&lt;br /&gt;
&lt;br /&gt;
In our case, we need to react to the operator setting the parameters, starting the data collection, and stopping the data collection. These correspond to the Operator Module entering the &amp;lt;code&amp;gt;Resting&amp;lt;/code&amp;gt; state, entering the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state, and exiting the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;code&amp;gt;GameControl.cs&amp;lt;/code&amp;gt; script, we will wait for the system to be in the &amp;lt;code&amp;gt;Resting&amp;lt;/code&amp;gt; state at the start of the &amp;lt;code&amp;gt;ControLoop&amp;lt;/code&amp;gt; method, and wait for the system to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state immediately before the entering the trial loop. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; GameControl.cs&lt;br /&gt;
&lt;br /&gt;
    IEnumerator ControlLoop() {&lt;br /&gt;
	while (True) {&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: red&amp;quot;&amp;gt;&lt;br /&gt;
	   StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Resting));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	   try {&lt;br /&gt;
		...&lt;br /&gt;
	   } catch (Exception e) {&lt;br /&gt;
		continue;&lt;br /&gt;
	   }&lt;br /&gt;
	&lt;br /&gt;
	   int trials = 0;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: red&amp;quot;&amp;gt;&lt;br /&gt;
	   StartCoroutine(bci.PollSystemState(BCI2000Remote.SystemState.Running));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	   yield return new WaitForSeconds(preRunDuration);&lt;br /&gt;
	   while (IsContinue() &amp;amp;&amp;amp; trials &amp;lt; n_trials) {&lt;br /&gt;
		...&lt;br /&gt;
	   }&lt;br /&gt;
	}&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need to check for the operator stopping data collection, so we modify the &amp;lt;code&amp;gt;IsContinue()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bool IsContinue () {&lt;br /&gt;
	return bci.Control.GetSystemState() == BCI2000Remote.SystemState.Running;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remember to add &amp;lt;code&amp;gt;using BCI2000RemoteNET;&amp;lt;/code&amp;gt; to the top of the script, so you can access the &amp;lt;code&amp;gt;SystemState&amp;lt;/code&amp;gt; enum.&lt;br /&gt;
&lt;br /&gt;
===Reading the control signal===&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Supported_Frameworks&amp;diff=11419</id>
		<title>Supported Frameworks</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Supported_Frameworks&amp;diff=11419"/>
		<updated>2024-07-09T13:28:17Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Moved BCI2000RemoteNET out of &amp;#039;in development&amp;#039; state&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Purpose==&lt;br /&gt;
BCI2000 supports many frameworks outside of its native implementation. This page gives a list of each of these frameworks and how they interact with one another.&lt;br /&gt;
&lt;br /&gt;
==Schematic==&lt;br /&gt;
[[Image:ExternalInterfaces.png|center]]&lt;br /&gt;
A visual schematic for how the varying interfaces of BCI2000 interact. Encapsulated items mean they are built on top of the larger, overarching framework. For example, BCI2000Remote is an extension of BCI2000 Operator Module Scripting. Each interface has a descriptor of the language/method/application you would use for the framework. &lt;br /&gt;
==Documentation==&lt;br /&gt;
===[[Contributions:External Interfaces|External Interfaces]]===&lt;br /&gt;
*[[Contributions:BCPy2000]]&lt;br /&gt;
*[[Contributions:BCI2000SimulinkConnector]]&lt;br /&gt;
*[[Programming Reference:MatlabFilter]]&lt;br /&gt;
*[[User Reference:EEGLabImport]]&lt;br /&gt;
*[[Contributions:FieldTripBuffer]]&lt;br /&gt;
====BCI2000 Operator Module Scripting====&lt;br /&gt;
Documentation: [[User Reference:Module Command Line Options]], [[User Reference:Operator Module Scripting]]&lt;br /&gt;
*[[User Reference:BCI2000Shell]]&lt;br /&gt;
*[[User Reference:BCI2000Launcher]]&lt;br /&gt;
*[[Contributions:BCI2000Command]]&lt;br /&gt;
*[[Technical Reference:Operator Library]]&lt;br /&gt;
=====BCI2000Remote=====&lt;br /&gt;
Documentation: [[User Tutorial:BCI2000Remote]], [[Programming Reference:BCI2000Remote Class]], [[Contributions:BCI2000PythonBindings]]&lt;br /&gt;
*[[PsychoPy]]&lt;br /&gt;
* [[Python Visualizations]]&lt;br /&gt;
======[[Technical Reference:BCI2000Remote Library|BCI2000RemoteLib]]======&lt;br /&gt;
*[[Contributions:BCI2000Automation]]&lt;br /&gt;
*[[Contributions:BCI2000PresentationLink]]&lt;br /&gt;
&lt;br /&gt;
==Frameworks organized by languages==&lt;br /&gt;
&#039;&#039;&#039;User Interface (no coding)&#039;&#039;&#039;: [[User Reference:BCI2000Launcher|BCI2000Launcher]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Python&#039;&#039;&#039;: [[PsychoPy]], [[Contributions:BCPy2000|BCPy2000]], [[User Tutorial:BCI2000Remote#Python_Tutorial|BCI2000Remote]], [[Python Visualizations]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Matlab&#039;&#039;&#039;: [[Programming Reference:MatlabFilter|MatlabFilter]], [[User Tutorial:BCI2000Remote#MatlabTutorial|BCI2000Remote]], [[Contributions:BCI2000SimulinkConnector|Simulink]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Command-line shell&#039;&#039;&#039;: [[User Reference:Operator Module Scripting|Operator Module Scripting]], [[User Reference:BCI2000Shell|BCI2000Shell]], [[Contributions:BCI2000Command|BCI2000Command]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;.NET (Visual Basic, C#)&#039;&#039;&#039;: [[Contributions:BCI2000Automation|BCI2000Automation]], [[Contributions:BCI2000RemoteNET|BCI2000RemoteNET]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;C++&#039;&#039;&#039;: [[User Reference:Filters|Create a native BCI2000 filter]], [[User Tutorial:BCI2000Remote#C++_Tutorial|BCI2000Remote]]&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:BCI2000Unity&amp;diff=11370</id>
		<title>User Tutorial:BCI2000Unity</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:BCI2000Unity&amp;diff=11370"/>
		<updated>2024-05-29T19:43:03Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Tytbutler moved page User Tutorial:BCI2000Unity to User Tutorial:BCI2000Unity OUTDATED&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[User Tutorial:BCI2000Unity OUTDATED]]&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:BCI2000Unity_OUTDATED&amp;diff=11369</id>
		<title>User Tutorial:BCI2000Unity OUTDATED</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=User_Tutorial:BCI2000Unity_OUTDATED&amp;diff=11369"/>
		<updated>2024-05-29T19:43:03Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Tytbutler moved page User Tutorial:BCI2000Unity to User Tutorial:BCI2000Unity OUTDATED&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
Unity is a cross-platform game engine with support for desktop, mobile, console, and virtual reality platforms. It is both easy for beginners to use and is popular for low-cost game development. This is a Unity package which integrates BCI2000. This tutorial assumes that you have already compiled BCI2000. &lt;br /&gt;
&lt;br /&gt;
==Video==&lt;br /&gt;
This video is currently out of date. An updated video is coming soon!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;youtube alignment=&amp;quot;center&amp;quot;&amp;gt;https://www.youtube.com/watch?v=nZG70HSR8v8&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tutorial==&lt;br /&gt;
For information on how to use Unity itself, see the Unity [https://docs.unity3d.com/Manual/index.html manual]. This tutorial assumes knowledge of how to use Unity. It is recommended to know how GameObjects and Components work.&lt;br /&gt;
More in-depth detail on how UnityBCI2000 works is provided in the README.md file, and on this [https://bci2000.org/BCI2000Unity/classUnityBCI2000.html page].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This tutorial will walk through an example cursor control task, making use of the mouse position recorded from BCI2000 to control the cursor position in Unity. First, download UnityBCI2000 from this [https://github.com/neurotechcenter/UnityBCI2000 GitHub] page and download the MWE_UnityBCI2000CursorDemo tutorial project from this [https://github.com/neurotechcenter/ExperimentalDesignDemos GitHub] page. Copy the UnityBCI2000.cs and BCI2000RemoteNET.dll files into the Assets folder of your Unity project.&lt;br /&gt;
&lt;br /&gt;
[[File:UnityMoveAssets.png|500px|alt=&amp;quot;Unity Move Assets&amp;quot;|Unity Move Assets]]&lt;br /&gt;
&lt;br /&gt;
===Connect to an Instance of BCI2000===&lt;br /&gt;
&lt;br /&gt;
To connect to an instance of BCI2000 in Unity, you will need to create an empty GameObject and add the script UnityBCI2000 as a Component. This will serve as the central connection to the BCI2000 Operator. As of now, it is not possible to use multiple scenes with one BCI2000 connection.&lt;br /&gt;
&lt;br /&gt;
1. Create a BCI2000 GameObject.&lt;br /&gt;
&lt;br /&gt;
[[File:UnityBCI2000GameObject.png|600px|alt=&amp;quot;Unity BCI2000 Game Object&amp;quot;|Unity BCI2000 Game Object]]&lt;br /&gt;
&lt;br /&gt;
2. Add UnityBCI2000.cs to the GameObject as a Script Component. &lt;br /&gt;
&lt;br /&gt;
[[File:UnityBCI2000ScriptComponent.png|600px|alt=&amp;quot;Unity BCI2000 Script Component&amp;quot;|Unity BCI2000 Script Component]]&lt;br /&gt;
&lt;br /&gt;
3. Use the Operator Path field to specify the path to the BCI2000 Operator.exe (usually in the C:/bci2000/prog/ directory). If you already have an instance of the operator running, use the Telnet IP and Telnet Port fields to specify the IP and port it is listening on instead.&lt;br /&gt;
&lt;br /&gt;
4. Specify the names of the modules to start up alongside it. Extensions can be added by expanding the Module Args field and adding an element with the appropriate extension flag. For the example that will follow, we will log the mouse extension with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
--LogMouse=1&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. Specify the name of the log file to store the BCI2000 system log. &#039;&#039;&#039;NOTE: There is a known issue with writing to the log file; this is remedied by changing the name of the file to which to write. This is an issue with BCI2000RemoteNET and will be fixed in upcoming updates.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:UnityBCI2000Modules.png|400px|alt=&amp;quot;Unity BCI2000 Modules&amp;quot;|Unity BCI2000 Modules]]&lt;br /&gt;
&lt;br /&gt;
===Save Unity Events in BCI2000===&lt;br /&gt;
&lt;br /&gt;
Next, we will modify a script to create new BCI2000 events and send event change information to BCI2000.&lt;br /&gt;
&lt;br /&gt;
1. Open the TargetControl script (or any script from which you would like to send information to BCI2000).&lt;br /&gt;
&lt;br /&gt;
2. In the class definition, instantiate BCI2000 with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
UnityBCI2000 bci;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. In the Awake() function, set the BCI2000 reference with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. In the Awake() function, create new BCI2000 events with the bci.AddEvent() function. The second input specifies the number of bits assigned to the new event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
bci.AddEvent(&amp;quot;t1hit&amp;quot;, 32);&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. It can be helpful to add watches for the events you have created so you can see their behavior in real time during the experiment. In the Awake() function, use the generic bci.ExecuteCommand() function (this function can be used to execute any BCI2000 operator scripting commands)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
bci.ExecuteCommand(&amp;quot;visualize watch t1hit&amp;quot;);&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
6. It can be useful to reduce the verbosity of event logging, as event logs are written to the log file with every frame&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
bci.ExecuteCommand(&amp;quot;Set variable LogLevel 0&amp;quot;);&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:UnityTargetControlScript.png|500px|alt=&amp;quot;Unity Target Control Script&amp;quot;|Unity Target Control Script]]&lt;br /&gt;
&lt;br /&gt;
7. Update the event value according to some change in the experiment using the bci.SetEvent() function in the Update() function. For example, change a target hit event &amp;quot;t1hit&amp;quot; to 1 every time a target is hit by a cursor. Note that events must be set as unsigned integers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
bci.SetEvent(&amp;quot;t1hit&amp;quot;,(int)(1));&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:UnitySetEvent.png|400px|alt=&amp;quot;Unity Set Event&amp;quot;|Unity Set Event]]&lt;br /&gt;
&lt;br /&gt;
===Access BCI2000 Events for Control===&lt;br /&gt;
&lt;br /&gt;
We can also get event information from BCI2000 for Unity use. For example, you may want to control the Unity cursor position with a BCI2000 event, such as the mouse position. This example makes use of a BallMouseControl.cs script.&lt;br /&gt;
&lt;br /&gt;
First you will need to instantiate BCI2000 and set the BCI2000 reference as in the TargetControl.cs script&lt;br /&gt;
&lt;br /&gt;
1. Open the BallMouseControl.cs script.&lt;br /&gt;
&lt;br /&gt;
2. In the class definition, instantiate BCI2000 with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
UnityBCI2000 bci;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. In the Awake() function, set the BCI2000 reference with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
bci = GameObject.Find(&amp;quot;BCI2000&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:UnityBallMouseControlScript.png|400px|alt=&amp;quot;Unity Ball Mouse Control Script&amp;quot;|Unity Ball Mouse Control Script]]&lt;br /&gt;
&lt;br /&gt;
4. Get the value of the BCI2000 event using the bci.GetEvent() function and store the result in some variable&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
Mpx = bci.GetEvent(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
Mpy = bci.GetEvent(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This value can then be used in Unity to influence the game activity.&lt;br /&gt;
&lt;br /&gt;
[[File:UnityGetEvent.png|400px|alt=&amp;quot;Unity Get Event&amp;quot;|Unity Get Event]]&lt;br /&gt;
&lt;br /&gt;
===Compile===&lt;br /&gt;
&lt;br /&gt;
Compile the project by navigating to file &amp;gt; Build and Run. This should launch the experiment and start up BCI2000!&lt;br /&gt;
&lt;br /&gt;
==Using BCI2000 Control Signal==&lt;br /&gt;
&lt;br /&gt;
The above example makes use of the BCI2000 Mouse Position events to control the Unity cursor position. However, the BCI2000 control signal can also be used in Unity. This is particularly useful for online experiments (for example, a neurofeedback task to move a cursor on the screen based on the decoded alpha power). In the demo script, navigate to the CursorTaskSignal Scene to see how the BCI2000 control signal can be utilized in Unity. Note that this only seems to work when the scene has been compiled!&lt;br /&gt;
&lt;br /&gt;
Access the control signal using the function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
bci.GetSignal(&amp;quot;ChannelNumber&amp;quot;,1);&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:UnityGetSignal.png|500px|alt=&amp;quot;Unity Get Signal&amp;quot;|Unity Get Signal]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000Unity&amp;diff=11368</id>
		<title>Contributions:BCI2000Unity</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000Unity&amp;diff=11368"/>
		<updated>2024-05-29T19:42:19Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Tytbutler moved page Contributions:BCI2000Unity to Contributions:BCI2000Unity OUTDATED&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Contributions:BCI2000Unity OUTDATED]]&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000Unity_OUTDATED&amp;diff=11367</id>
		<title>Contributions:BCI2000Unity OUTDATED</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000Unity_OUTDATED&amp;diff=11367"/>
		<updated>2024-05-29T19:42:19Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Tytbutler moved page Contributions:BCI2000Unity to Contributions:BCI2000Unity OUTDATED&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOINDEX__&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
Unity is a cross-platform game engine with support for desktop, mobile, console, and virtual reality platforms. It is both easy for beginners to use and is popular for low-cost game development. This is a Unity package which integrates BCI2000.&lt;br /&gt;
&lt;br /&gt;
==Prerequisites==&lt;br /&gt;
&lt;br /&gt;
UnityBCI2000 depends on the BCI2000RemoteNET library, located at&lt;br /&gt;
[https://github.com/neurotechcenter/BCI2000RemoteNET Github] or [https://www.nuget.org/packages/BCI2000RemoteNET NuGet]).&lt;br /&gt;
Keep in mind that at the moment both BCI2000RemoteNET and BCI2000Unity are not fully released, and are still in development, so features and API structure are subject to change at any time, and bugs are to be expected.&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
&lt;br /&gt;
Add the `UnityBCI2000.cs` script to one `GameObject`. This is the central script which communicates with BCI2000.  &lt;br /&gt;
Add the `BCI2000StateSender` to any object which you want to monitor with BCI2000.  &lt;br /&gt;
Before starting, you must set the operator and modules to start up, by specifying the fields&lt;br /&gt;
`OperatorPath` and `Module[1-3]`. All other properties have default settings and will function without change.  &lt;br /&gt;
Alternatively, if you leave `OperatorPath` blank, `BCI2000Remote` will attempt to connect to an operator at&lt;br /&gt;
`TelnetIp:TelnetPort`. This is useful for if you already have an operator open that you want to use.  &lt;br /&gt;
If you also have modules started within a running BCI2000 instance, set `DontStartModules` to `true`, this will preserve&lt;br /&gt;
your running modules.&lt;br /&gt;
&lt;br /&gt;
===Using built-in variables===&lt;br /&gt;
&lt;br /&gt;
`BCI2000StateSender` has some variables built in. To use these, just select their check boxes in the inspector.&lt;br /&gt;
&lt;br /&gt;
===Adding custom variables===&lt;br /&gt;
&lt;br /&gt;
To add custom variables,  add a script to the same object as a `BCI2000StateSender`, which inherits from `CustomVariableBase`.  &lt;br /&gt;
Then, add the `CustomVariableBase` to the &amp;quot;Custom Variable Supplier&amp;quot; field of the `BCI2000StateSender`.&lt;br /&gt;
Then, add `CustomVariable`s to the list `customVariables` within the `CustomVariableBase`. There are some included&lt;br /&gt;
templates and snippets which show the syntax for adding custom variables.&lt;br /&gt;
&lt;br /&gt;
===Custom Variables===&lt;br /&gt;
&lt;br /&gt;
A custom variable has four fields. These are its name, value, scale, and type.  &lt;br /&gt;
Its name is a string which holds its name.  &lt;br /&gt;
Its value is a `Func&amp;lt;float&amp;gt;` delegate which returns a float, which will be sent to BCI2000, after being multiplied by its scale.  &lt;br /&gt;
Its type is a member of the enum `UnityBCI2000.StateType`, which represents the format of the number being sent to BCI2000.&lt;br /&gt;
&lt;br /&gt;
===Custom Variable Class Example===&lt;br /&gt;
&lt;br /&gt;
Template&lt;br /&gt;
&lt;br /&gt;
    public class &amp;lt;ClassName&amp;gt; : CustomVariableBase&lt;br /&gt;
    {&lt;br /&gt;
        public override void AddCustomVariables()&lt;br /&gt;
        {&lt;br /&gt;
            customVariables.Add(new CustomSetVariable(  //Copy this for more set variables&lt;br /&gt;
                &amp;quot;[Name]&amp;quot;,&lt;br /&gt;
                new Func&amp;lt;float&amp;gt;(() =&amp;gt; [Code which returns variable to send]),&lt;br /&gt;
                [Scale],&lt;br /&gt;
                UnityBCI2000.StateType.[Type]&lt;br /&gt;
                ));&lt;br /&gt;
                &lt;br /&gt;
            customVariables.Add(new CustomGetVariable(  //Copy this for more get variables&lt;br /&gt;
                &amp;quot;[Name]&amp;quot;,  &lt;br /&gt;
                new Action&amp;lt;int&amp;gt; ((int i) =&amp;gt; [Code which uses i])&lt;br /&gt;
            ));&lt;br /&gt;
&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Example&lt;br /&gt;
&lt;br /&gt;
    public class CustomVariableSupplier1 : CustomVariableBase&lt;br /&gt;
    {&lt;br /&gt;
        public override void AddCustomVariables() &lt;br /&gt;
        {&lt;br /&gt;
            customVariables.Add(new CustomSetVariable(&lt;br /&gt;
                &amp;quot;Custom variable 1&amp;quot;,&lt;br /&gt;
                new Func&amp;lt;float&amp;gt;(() =&amp;gt; {return 65 / 5;}),&lt;br /&gt;
                100,&lt;br /&gt;
                UnityBCI2000.StateType.SignedInt16&lt;br /&gt;
                ));&lt;br /&gt;
            customVariables.Add(new CustomSetVariable(&lt;br /&gt;
                &amp;quot;Custom variable 2: Frame count&amp;quot;,&lt;br /&gt;
                new Func&amp;lt;float&amp;gt;(() =&amp;gt; Time.frameCount),&lt;br /&gt;
                1,&lt;br /&gt;
                UnityBCI2000.StateType.UnsignedInt32&lt;br /&gt;
                ));&lt;br /&gt;
            customVariables.Add(new CustomGetVariable(  &lt;br /&gt;
                &amp;quot;StateName&amp;quot;,  &lt;br /&gt;
                new Action&amp;lt;int&amp;gt; ((int i) =&amp;gt; {score = i})&lt;br /&gt;
            ));&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
===Number Formats===&lt;br /&gt;
&lt;br /&gt;
The available formats are found in the enum `UnityBCI2000.StateType`. As they are being accessed outside of `UnityBCI2000`, &lt;br /&gt;
they will always be preceded by &amp;quot;UnityBCI2000.&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The formats are `Boolean`, `UnsignedInt16`, `UnsignedInt32`, `SignedInt16`, and `SignedInt32`.  &lt;br /&gt;
These are available formats because BCI2000 takes state values in the form of unsigned integers with a bit width of powers of 2 between 1 and 32.  &lt;br /&gt;
Boolean is the same as an unsigned int of bit width 1.  &lt;br /&gt;
Signed numbers will generate a second state within BCI2000 of bit width 1, which holds their sign. If they are negative, their sign will be 1,&lt;br /&gt;
and if they are positive, their sign will be 0. Use signed numbers if your value will ever be negative.&lt;br /&gt;
&lt;br /&gt;
===Other scripting===&lt;br /&gt;
&lt;br /&gt;
Try to avoid calling any of the methods directly. UnityBCI2000 should ideally be able to run and control BCI2000 without any intervention.&lt;br /&gt;
&lt;br /&gt;
==Properties==&lt;br /&gt;
&lt;br /&gt;
===UnityBCI2000===&lt;br /&gt;
&lt;br /&gt;
`Timeout`&lt;br /&gt;
The timeout, in milliseconds, for sending and receiving commands, default 1000.&lt;br /&gt;
&lt;br /&gt;
`TelnetIP`&lt;br /&gt;
The IP at which to connect to the Operator, default 127.0.0.1&lt;br /&gt;
Note: Don&#039;t use &amp;quot;localhost&amp;quot; when setting this, as this causes errors due to ambiguity in name resolution.&lt;br /&gt;
&lt;br /&gt;
`TelnetPort`&lt;br /&gt;
The port to connect to the Operator, default 3999.&lt;br /&gt;
&lt;br /&gt;
`OperatorPath`&lt;br /&gt;
The path to the Operator module to start up when there is no running operator at the IP and port specified, will always connect on localhost, at the previously given port.&lt;br /&gt;
&lt;br /&gt;
`LogFile`&lt;br /&gt;
The path to the file to write the log. This is overwritten on `Connect()`, default &amp;quot;logFile.txt&amp;quot;, in the application&#039;s working directory.&lt;br /&gt;
&lt;br /&gt;
`LogStates`&lt;br /&gt;
Whether or not to log commands to set a state, as well as the received Prompt if the command produces no errors, default false.&lt;br /&gt;
&lt;br /&gt;
`LogPrompts`&lt;br /&gt;
Whether or not to log any Prompt, in which case only received output and errors will be logged, default false.&lt;br /&gt;
&lt;br /&gt;
===BCI2000StateSender===&lt;br /&gt;
&lt;br /&gt;
`UnityBCI2000 object`&lt;br /&gt;
The object which has the attached `UnityBCI2000` script.&lt;br /&gt;
&lt;br /&gt;
`Custom Variable Supplier`&lt;br /&gt;
The component which inherits from `CustomVariableBase` which supplies custom variables.&lt;br /&gt;
&lt;br /&gt;
Global and screen coordinates and their scales.&lt;br /&gt;
&lt;br /&gt;
`Camera`&lt;br /&gt;
The camera to use for finding screen position.&lt;br /&gt;
&lt;br /&gt;
`Is on screen`&lt;br /&gt;
Is the object on screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
`Velocity`&lt;br /&gt;
The velocity of the object in any direction.&lt;br /&gt;
&lt;br /&gt;
`Custom Variables`&lt;br /&gt;
Lists the names of any added custom variables.&lt;br /&gt;
&lt;br /&gt;
==Other Notes==&lt;br /&gt;
&lt;br /&gt;
`StateVariable` is a class which holds values necessary for sending states to BCI2000.  &lt;br /&gt;
They are stored in two places, a central list within `UnityBCI2000` which is only used for checking if a state already exists,&lt;br /&gt;
and within the `BCI2000StateSender` which &#039;owns&#039; the state, where they are stored within objects called `SendStateVariable`,&lt;br /&gt;
which update the state with a new value every frame. This is done so that one state can be changed by mutiple `BCI2000StateSender`s,&lt;br /&gt;
through the use of multiple `SendStateVariables` created using the `AddSendExistingState()` method. &lt;br /&gt;
&lt;br /&gt;
BCI2000Remote will write its output to a log file that is, by default, located at logFile.txt in the working directory of your Unity application.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11354</id>
		<title>Contributions:BCI2000RemoteNET</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11354"/>
		<updated>2024-05-24T23:01:41Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Added info about the Execute method&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
BCI2000RemoteNET is a library for controlling BCI2000 from .NET programs such as Unity. With C# top-level declarations, it can also be used as a replacement for [[User Reference:BCI2000Shell]] with the added step of compilation via [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/ &amp;lt;code&amp;gt;csc&amp;lt;/code&amp;gt;]. &lt;br /&gt;
&lt;br /&gt;
==Operation==&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET communicates with the BCI2000 Operator via [[User Reference:Operator Module Scripting|operator module scripting commands]], which are sent as text over TCP to a running Operator. It also provides functionality for starting the Operator directly, so it can control the Operator entirely from startup to shutdown. &lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET consists of two classes, &amp;lt;code&amp;gt;BCI2000Connection&amp;lt;/code&amp;gt;, which provides the basic functionality necessary for starting and communicating with BCI2000, and &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt;, which provides a set of methods for controlling a BCI2000 experiment, such as interacting with parameters and events, as well as starting modules and experiments.&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET comes in two versions, targeting .NET 8.0 and .NET Standard 2.1. This is due to compatibility with programs such as Unity, which require .NET Standard binaries. There is little difference in functionality between the two versions, other than the behavior of the &amp;lt;code&amp;gt;Execute()&amp;lt;/code&amp;gt; method, whose differences are described below.&lt;br /&gt;
&lt;br /&gt;
==Documentation==&lt;br /&gt;
Documentation for the classes can be found here:&lt;br /&gt;
&lt;br /&gt;
====.NET 8.0====&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
====.NET Standard 2.1====&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Acquire the latest binary from [https://github.com/neurotechcenter/BCI2000RemoteNET GitHub], or build from source from the source code on GitHub or in the main BCI2000 Subversion repository (Keep in mind that the version in the Subversion repository will likely be behind the version on GitHub.)&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
====Starting the operator====&lt;br /&gt;
If you plan on starting the operator separately, skip this step, but make sure to start the operator with its &amp;lt;code&amp;gt;--Telnet&amp;lt;/code&amp;gt; option set.&lt;br /&gt;
&lt;br /&gt;
In order to start the operator, call the &amp;lt;code&amp;gt;BCI2000Connection.StartOperator&amp;lt;/code&amp;gt; method with the path to your BCI2000 Operator executable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
conn.StartOperator(&amp;quot;Path/To/BCI2000/prog/Operator.exe&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, this will start an operator listening on &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. You can also set the Operator to listen on another port:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, port: 51101);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you wish to accept connections from other computers you can set BCI2000 to listen on all addresses:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;0.0.0.0&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or listen on a specific network interface:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;10.11.198.2&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Connecting to the operator====&lt;br /&gt;
Connect to the operator with the &amp;lt;code&amp;gt;BCI2000Connection.Connect()&amp;lt;/code&amp;gt; method. If you started a local operator with default settings, then you can call &amp;lt;code&amp;gt;Connect&amp;lt;/code&amp;gt; with its default parameters, which will connect to the operator at &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. If you are connecting to an operator on another machine, say at IP address &amp;lt;code&amp;gt;11.11.11.11&amp;lt;/code&amp;gt;,or one listening on a port other than 3999, call &amp;lt;code&amp;gt;Connect()&amp;lt;/code&amp;gt; with its optional parameters.&lt;br /&gt;
Please see the [[#Note On Security]] for an important caveat of setting a non-default parameter here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator on the same machine on the default port.&lt;br /&gt;
conn.Connect();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator at address 11.11.11.11:3999&lt;br /&gt;
conn.Connect(address: &amp;quot;11.11.11.11&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
BCI2000Remote bci = new(conn);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Adding parameters and events====&lt;br /&gt;
At this point you can add parameters and events to BCI2000. &lt;br /&gt;
Parameters are values which can be changed in the BCI2000 GUI and can be used to change how experiments behave.&lt;br /&gt;
Parameters can either be loaded from a file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //path is relative to the Operator&#039;s working directory, that is, the /prog directory of the BCI2000 installation&lt;br /&gt;
  bci.LoadParameters(&amp;quot;path/to/parameterfile.prm&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
or added individually:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value 0 &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value &amp;quot;Green&amp;quot; &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param2&amp;quot;, &amp;quot;Green&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea2 section within the Application tab, with default value 0 and range 0-10&lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param3&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;10&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Events are values logged by BCI2000 alongside the signal data. They have a temporal resolution equivalent to the sample rate, and can be set and read throughout data collection.&lt;br /&gt;
Events are unsigned integers with a bit width between 1 and 32:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //An event called &amp;quot;condition&amp;quot; representing a boolean value with possible values 0 and 1. Will be zero by default.&lt;br /&gt;
  bci.AddEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
  //An 32-bit event with default value 100, and range 0 to 2^32 - 1.&lt;br /&gt;
  bci.AddEvent(&amp;quot;value1&amp;quot;, 32, 100);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Starting BCI2000 Modules====&lt;br /&gt;
BCI2000 modules are started using the &amp;lt;code&amp;gt;StartModules()&amp;lt;/code&amp;gt; method, given a dictionary of module names and argument lists. For example, to open SignalGenerator, DummySignalProcessing, and DummyApplication with keyboard and mouse logging:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bci.StartupModules(new Dictionary&amp;lt;string, IEnumerable&amp;lt;string&amp;gt;?&amp;gt;()&lt;br /&gt;
  {&lt;br /&gt;
    {&amp;quot;SignalGenerator&amp;quot;, new List&amp;lt;string&amp;gt;() {&amp;quot;LogKeyboard=1&amp;quot;, &amp;quot;LogMouse=1&amp;quot;}},&lt;br /&gt;
    {&amp;quot;DummySignalProcessing&amp;quot;, null},&lt;br /&gt;
    {&amp;quot;DummyApplication&amp;quot;, null}&lt;br /&gt;
  });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Setting Parameters and Visualizing Values====&lt;br /&gt;
If using BCI2000RemoteNET as a substitute for BCI2000Shell for setting up the basic environment, this would usually be where you continue using BCI2000 through its own GUI.&lt;br /&gt;
&lt;br /&gt;
At this point parameters can be set via &amp;lt;code&amp;gt;SetParameter&amp;lt;/code&amp;gt;, for example, setting up experiment parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.SetParameter(&amp;quot;DataDirectory&amp;quot;, &amp;quot;../data/theDirectory&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectName&amp;quot;, &amp;quot;APatient&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectSession&amp;quot;, &amp;quot;004&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also set values such as events to be shown in a graph view. &lt;br /&gt;
For example, since we set the source module to start with mouse logging enabled, we can view the values of the mouse position events.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We can also visualize the events we added earlier.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;condition&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;value1&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Collecting Data====&lt;br /&gt;
Start collecting data with the &amp;lt;code&amp;gt;Start()&amp;lt;/code&amp;gt; method. This will implicitly call &amp;lt;code&amp;gt;SetConfig()&amp;lt;/code&amp;gt;, but it can be called separately as well.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Start();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you instead want to start BCI2000 through the GUI, and wait for it in this program, you can instead wait for BCI2000 to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Running);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
During a run you can interact with BCI2000 by setting event variables:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.SetEvent(&amp;quot;value1&amp;quot;, 400);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also pulse events, setting their value for one sample duration before setting them back.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.PulseEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also get values from BCI2000. As we set the source module to log the mouse position earlier, we can retrieve its value via &amp;lt;code&amp;gt;GetEvent()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  uint mousePositionX = bci.GetEvent(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  uint mousePositionY = bci.GetEvent(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also retrieve the value of the hardware signal. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //Get value of element 2 of channel 1 of signal&lt;br /&gt;
  double signal11 = bci.GetSignal(1, 2);X&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Stopping BCI2000====&lt;br /&gt;
When you are finished collecting data, stop BCI2000 with the &amp;lt;code&amp;gt;BCI2000Connection.Stop()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.connection.Stop();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also shut down BCI2000.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.connection.Quit();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you instead want to stop BCI2000 via the GUI, you can wait for the system to be in the &amp;lt;code&amp;gt;Suspended&amp;lt;/code&amp;gt; state. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Connected);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you want to poll the system state repeatedly (in a loop, for example);&lt;br /&gt;
&amp;lt;pre&amp;gt;  &lt;br /&gt;
 bool loop = true;&lt;br /&gt;
  while (loop) {&lt;br /&gt;
    ...&lt;br /&gt;
    if (bci.GetSystemState() == BCI2000Remote.SystemState.Suspended) {&lt;br /&gt;
      loop = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Using other BCI2000 Commands====&lt;br /&gt;
&lt;br /&gt;
An arbitrary operator command can be sent using the &amp;lt;code&amp;gt;BCI2000Connection.Execute&amp;lt;/code&amp;gt; method. In the .NET 8.0 version, &amp;lt;code&amp;gt;Execute()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Execute&amp;lt;T&amp;gt;()&amp;lt;/code&amp;gt; are used. &amp;lt;code&amp;gt;Execute()&amp;lt;/code&amp;gt; executes the command and throws an exception if it receives anything other than an empty response, whereas &amp;lt;code&amp;gt;Execute&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt; is a type that implements &amp;lt;code&amp;gt;IParsable&amp;lt;/code&amp;gt;, executes the command and attempts to parse the response as type &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
For example, setting the BCI2000 log level:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bci.Execute(&amp;quot;set LogLevel 0&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Checking if an event exists:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bool eventExists = bci.Execute&amp;lt;bool&amp;gt;(&amp;quot;exists event EventName&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Receiving the BCI2000 system version info:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Console.WriteLine(bci.Execute&amp;lt;string&amp;gt;(&amp;quot;get system version&amp;quot;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the .NET Standard 2.1 version, there is no generic &amp;lt;code&amp;gt;Execute&amp;lt;T&amp;gt;()&amp;lt;/code&amp;gt;, because the version of C# used by .NET Standard 2.1 does not include the &amp;lt;code&amp;gt;IParsable&amp;lt;/code&amp;gt; interface. Instead, &amp;lt;code&amp;gt;ExecuteString, ExecuteBool, ExecuteUInt32, and ExecuteDouble&amp;lt;/code&amp;gt; provide the functionality of parsing responses as basic types. If you need to interpret the response as a different type, use &amp;lt;code&amp;gt;ExecuteString&amp;lt;/code&amp;gt; and parse the result. &lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
Embedding BCI2000RemoteNET within another program is largely covered above, so this section focuses on alternative usecases.&lt;br /&gt;
&lt;br /&gt;
====Using BCI2000RemoteNET as a substitute for BCI2000Shell====&lt;br /&gt;
BCI2000RemoteNET can be used as a replacement for BCI2000Shell when starting up BCI2000, if you need more advanced language capabilities than what the operator scripting language can provide.&lt;br /&gt;
&lt;br /&gt;
This is the existing startup script for the Stimulus Presentation task with the software Signal Generator.&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.bat&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#! ../prog/BCI2000Shell&lt;br /&gt;
@cls &amp;amp; ..\prog\BCI2000Shell %0 %* #! &amp;amp;&amp;amp; exit /b 0 || exit /b 1\n&lt;br /&gt;
Change directory $BCI2000LAUNCHDIR&lt;br /&gt;
Show window; Set title ${Extract file base $0}&lt;br /&gt;
Reset system&lt;br /&gt;
Startup system localhost&lt;br /&gt;
Start executable SignalGenerator --local --LogKeyboard=1 --SpinningWheel=1 --ShowDisplayStatistics=1&lt;br /&gt;
Start executable P3SignalProcessing --local&lt;br /&gt;
Start executable StimulusPresentation --local&lt;br /&gt;
Wait for Connected&lt;br /&gt;
Load parameterfile &amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the equivalent C# code using BCI2000RemoteNET:&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.cs&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
using BCI2000RemoteNET;&lt;br /&gt;
using System.RuntimeInformation.InteropServices;&lt;br /&gt;
BCI2000Remote bci = new(new BCI2000Connection());&lt;br /&gt;
bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);&lt;br /&gt;
bci.connection.StartOperator(&amp;quot;../prog/Operator&amp;quot; + isWindows ? &amp;quot;.exe&amp;quot; : &amp;quot;&amp;quot;); //Add file extension if on windows &lt;br /&gt;
bci.connection.Connect();&lt;br /&gt;
bci.LoadParameters(&amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;);&lt;br /&gt;
bci.StartupModules(new Dictionary&amp;lt;string, IEnumerable&amp;lt;string&amp;gt;?&amp;gt; {&lt;br /&gt;
	{&amp;quot;SignalGenerator&amp;quot;, new() {&amp;quot;LogKeyboard=1&amp;quot;, &amp;quot;SpinningWheel=1&amp;quot;, &amp;quot;ShowDisplayStatistics=1&amp;quot;}},&lt;br /&gt;
	{&amp;quot;P3SignalProcessing&amp;quot;, null},&lt;br /&gt;
	{&amp;quot;StimulusPresentation&amp;quot;, null}&lt;br /&gt;
	});&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
C# startup scripts have access to all of the constructs of the C# language, so different actions can be taken depending on conditions such as the operating system, as seen in the above script, or take other input such as command line options.&lt;br /&gt;
Note that this will need to be part of a C# project, created via &amp;lt;code&amp;gt;dotnet new console&amp;lt;/code&amp;gt; with its accompanied &amp;lt;code&amp;gt;.csproj&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
An alternative would be to instead use a PowerShell or F# script, which can then be run via &amp;lt;code&amp;gt;pwsh&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;dotnet fsi&amp;lt;/code&amp;gt;. This is the equivalent F# code:&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.fsx&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#r &amp;quot;../BCI2000RemoteNET.dll&amp;quot;&lt;br /&gt;
open BCI2000RemoteNET&lt;br /&gt;
open System.Runtime.InteropServices&lt;br /&gt;
let bci = new BCI2000Remote(new BCI2000Connection()) in&lt;br /&gt;
let isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) in&lt;br /&gt;
let operatorPath = &amp;quot;../../bci2000/prog/Operator&amp;quot; + if isWindows then &amp;quot;.exe&amp;quot; else &amp;quot;&amp;quot; in&lt;br /&gt;
bci.connection.StartOperator operatorPath;&lt;br /&gt;
bci.connection.Connect ();&lt;br /&gt;
bci.LoadParameters &amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;;&lt;br /&gt;
bci.StartupModules &amp;lt;| Map [&lt;br /&gt;
  (&amp;quot;SignalGenerator&amp;quot;, [&amp;quot;LogKeyboard=1&amp;quot;; &amp;quot;SpinningWheel=1&amp;quot;; &amp;quot;ShowDisplayStatistics=1&amp;quot;]);&lt;br /&gt;
  (&amp;quot;P3SignalProcessing&amp;quot;, null);&lt;br /&gt;
  (&amp;quot;StimulusPresentation&amp;quot;, null);&lt;br /&gt;
  ]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This can be run directly:&lt;br /&gt;
&amp;lt;code&amp;gt;dotnet fsi StimulusPresentation_SignalGenerator.fsx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Note On Security==&lt;br /&gt;
The BCI2000 command line interface can be used to run arbitrary system shell commands. It is also entirely unsecured and unencrypted. Anyone who has access to it effectively has full access to the computer on which it runs. This is not a problem if running locally, and is generally not a problem if running on a firewalled local network. However, due to the unsecured nature of the interface, running BCI2000 across the internet is highly discouraged. That is, if you set BCI2000 to listen at an address of an external network interface, or to listen at all connections by passing the address &amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt;, make sure that port 3999 (or whichever port BCI2000 is listening on), is not forwarded beyond the local network by your router. Support for securely connecting to BCI2000 is planned for the future.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11353</id>
		<title>Contributions:BCI2000RemoteNET</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11353"/>
		<updated>2024-05-24T20:54:34Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
BCI2000RemoteNET is a library for controlling BCI2000 from .NET programs such as Unity. With C# top-level declarations, it can also be used as a replacement for [[User Reference:BCI2000Shell]] with the added step of compilation via [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/ &amp;lt;code&amp;gt;csc&amp;lt;/code&amp;gt;]. &lt;br /&gt;
&lt;br /&gt;
==Operation==&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET communicates with the BCI2000 Operator via [[User Reference:Operator Module Scripting|operator module scripting commands]], which are sent as text over TCP to a running Operator. It also provides functionality for starting the Operator directly, so it can control the Operator entirely from startup to shutdown. &lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET consists of two classes, &amp;lt;code&amp;gt;BCI2000Connection&amp;lt;/code&amp;gt;, which provides the basic functionality necessary for starting and communicating with BCI2000, and &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt;, which provides a set of methods for controlling a BCI2000 experiment, such as interacting with parameters and events, as well as starting modules and experiments.&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET comes in two versions, targeting .NET 8.0 and .NET Standard 2.1. This is due to compatibility with programs such as Unity, which require .NET Standard binaries. There is little difference in functionality between the two versions, other than the behavior of the &amp;lt;code&amp;gt;Execute()&amp;lt;/code&amp;gt; method, whose differences are described below.&lt;br /&gt;
&lt;br /&gt;
==Documentation==&lt;br /&gt;
Documentation for the classes can be found here:&lt;br /&gt;
&lt;br /&gt;
====.NET 8.0====&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
====.NET Standard 2.1====&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Acquire the latest binary from [https://github.com/neurotechcenter/BCI2000RemoteNET GitHub], or build from source from the source code on GitHub or in the main BCI2000 Subversion repository (Keep in mind that the version in the Subversion repository will likely be behind the version on GitHub.)&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
====Starting the operator====&lt;br /&gt;
If you plan on starting the operator separately, skip this step, but make sure to start the operator with its &amp;lt;code&amp;gt;--Telnet&amp;lt;/code&amp;gt; option set.&lt;br /&gt;
&lt;br /&gt;
In order to start the operator, call the &amp;lt;code&amp;gt;BCI2000Connection.StartOperator&amp;lt;/code&amp;gt; method with the path to your BCI2000 Operator executable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
conn.StartOperator(&amp;quot;Path/To/BCI2000/prog/Operator.exe&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, this will start an operator listening on &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. You can also set the Operator to listen on another port:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, port: 51101);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you wish to accept connections from other computers you can set BCI2000 to listen on all addresses:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;0.0.0.0&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or listen on a specific network interface:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;10.11.198.2&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Connecting to the operator====&lt;br /&gt;
Connect to the operator with the &amp;lt;code&amp;gt;BCI2000Connection.Connect()&amp;lt;/code&amp;gt; method. If you started a local operator with default settings, then you can call &amp;lt;code&amp;gt;Connect&amp;lt;/code&amp;gt; with its default parameters, which will connect to the operator at &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. If you are connecting to an operator on another machine, say at IP address &amp;lt;code&amp;gt;11.11.11.11&amp;lt;/code&amp;gt;,or one listening on a port other than 3999, call &amp;lt;code&amp;gt;Connect()&amp;lt;/code&amp;gt; with its optional parameters.&lt;br /&gt;
Please see the [[#Note On Security]] for an important caveat of setting a non-default parameter here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator on the same machine on the default port.&lt;br /&gt;
conn.Connect();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator at address 11.11.11.11:3999&lt;br /&gt;
conn.Connect(address: &amp;quot;11.11.11.11&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
BCI2000Remote bci = new(conn);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Adding parameters and events====&lt;br /&gt;
At this point you can add parameters and events to BCI2000. &lt;br /&gt;
Parameters are values which can be changed in the BCI2000 GUI and can be used to change how experiments behave.&lt;br /&gt;
Parameters can either be loaded from a file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //path is relative to the Operator&#039;s working directory, that is, the /prog directory of the BCI2000 installation&lt;br /&gt;
  bci.LoadParameters(&amp;quot;path/to/parameterfile.prm&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
or added individually:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value 0 &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value &amp;quot;Green&amp;quot; &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param2&amp;quot;, &amp;quot;Green&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea2 section within the Application tab, with default value 0 and range 0-10&lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param3&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;10&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Events are values logged by BCI2000 alongside the signal data. They have a temporal resolution equivalent to the sample rate, and can be set and read throughout data collection.&lt;br /&gt;
Events are unsigned integers with a bit width between 1 and 32:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //An event called &amp;quot;condition&amp;quot; representing a boolean value with possible values 0 and 1. Will be zero by default.&lt;br /&gt;
  bci.AddEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
  //An 32-bit event with default value 100, and range 0 to 2^32 - 1.&lt;br /&gt;
  bci.AddEvent(&amp;quot;value1&amp;quot;, 32, 100);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Starting BCI2000 Modules====&lt;br /&gt;
BCI2000 modules are started using the &amp;lt;code&amp;gt;StartModules()&amp;lt;/code&amp;gt; method, given a dictionary of module names and argument lists. For example, to open SignalGenerator, DummySignalProcessing, and DummyApplication with keyboard and mouse logging:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bci.StartupModules(new Dictionary&amp;lt;string, IEnumerable&amp;lt;string&amp;gt;?&amp;gt;()&lt;br /&gt;
  {&lt;br /&gt;
    {&amp;quot;SignalGenerator&amp;quot;, new List&amp;lt;string&amp;gt;() {&amp;quot;LogKeyboard=1&amp;quot;, &amp;quot;LogMouse=1&amp;quot;}},&lt;br /&gt;
    {&amp;quot;DummySignalProcessing&amp;quot;, null},&lt;br /&gt;
    {&amp;quot;DummyApplication&amp;quot;, null}&lt;br /&gt;
  });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Setting Parameters and Visualizing Values====&lt;br /&gt;
If using BCI2000RemoteNET as a substitute for BCI2000Shell for setting up the basic environment, this would usually be where you continue using BCI2000 through its own GUI.&lt;br /&gt;
&lt;br /&gt;
At this point parameters can be set via &amp;lt;code&amp;gt;SetParameter&amp;lt;/code&amp;gt;, for example, setting up experiment parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.SetParameter(&amp;quot;DataDirectory&amp;quot;, &amp;quot;../data/theDirectory&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectName&amp;quot;, &amp;quot;APatient&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectSession&amp;quot;, &amp;quot;004&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also set values such as events to be shown in a graph view. &lt;br /&gt;
For example, since we set the source module to start with mouse logging enabled, we can view the values of the mouse position events.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We can also visualize the events we added earlier.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;condition&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;value1&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Collecting Data====&lt;br /&gt;
Start collecting data with the &amp;lt;code&amp;gt;Start()&amp;lt;/code&amp;gt; method. This will implicitly call &amp;lt;code&amp;gt;SetConfig()&amp;lt;/code&amp;gt;, but it can be called separately as well.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Start();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you instead want to start BCI2000 through the GUI, and wait for it in this program, you can instead wait for BCI2000 to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Running);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
During a run you can interact with BCI2000 by setting event variables:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.SetEvent(&amp;quot;value1&amp;quot;, 400);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also pulse events, setting their value for one sample duration before setting them back.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.PulseEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also get values from BCI2000. As we set the source module to log the mouse position earlier, we can retrieve its value via &amp;lt;code&amp;gt;GetEvent()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  uint mousePositionX = bci.GetEvent(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  uint mousePositionY = bci.GetEvent(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also retrieve the value of the hardware signal. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //Get value of element 2 of channel 1 of signal&lt;br /&gt;
  double signal11 = bci.GetSignal(1, 2);X&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Stopping BCI2000====&lt;br /&gt;
When you are finished collecting data, stop BCI2000 with the &amp;lt;code&amp;gt;BCI2000Connection.Stop()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.connection.Stop();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also shut down BCI2000.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.connection.Quit();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you instead want to stop BCI2000 via the GUI, you can wait for the system to be in the &amp;lt;code&amp;gt;Suspended&amp;lt;/code&amp;gt; state. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Connected);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you want to poll the system state repeatedly (in a loop, for example);&lt;br /&gt;
&amp;lt;pre&amp;gt;  &lt;br /&gt;
 bool loop = true;&lt;br /&gt;
  while (loop) {&lt;br /&gt;
    ...&lt;br /&gt;
    if (bci.GetSystemState() == BCI2000Remote.SystemState.Suspended) {&lt;br /&gt;
      loop = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
Embedding BCI2000RemoteNET within another program is largely covered above, so this section focuses on alternative usecases.&lt;br /&gt;
&lt;br /&gt;
====Using BCI2000RemoteNET as a substitute for BCI2000Shell====&lt;br /&gt;
BCI2000RemoteNET can be used as a replacement for BCI2000Shell when starting up BCI2000, if you need more advanced language capabilities than what the operator scripting language can provide.&lt;br /&gt;
&lt;br /&gt;
This is the existing startup script for the Stimulus Presentation task with the software Signal Generator.&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.bat&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#! ../prog/BCI2000Shell&lt;br /&gt;
@cls &amp;amp; ..\prog\BCI2000Shell %0 %* #! &amp;amp;&amp;amp; exit /b 0 || exit /b 1\n&lt;br /&gt;
Change directory $BCI2000LAUNCHDIR&lt;br /&gt;
Show window; Set title ${Extract file base $0}&lt;br /&gt;
Reset system&lt;br /&gt;
Startup system localhost&lt;br /&gt;
Start executable SignalGenerator --local --LogKeyboard=1 --SpinningWheel=1 --ShowDisplayStatistics=1&lt;br /&gt;
Start executable P3SignalProcessing --local&lt;br /&gt;
Start executable StimulusPresentation --local&lt;br /&gt;
Wait for Connected&lt;br /&gt;
Load parameterfile &amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the equivalent C# code using BCI2000RemoteNET:&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.cs&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
using BCI2000RemoteNET;&lt;br /&gt;
using System.RuntimeInformation.InteropServices;&lt;br /&gt;
BCI2000Remote bci = new(new BCI2000Connection());&lt;br /&gt;
bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);&lt;br /&gt;
bci.connection.StartOperator(&amp;quot;../prog/Operator&amp;quot; + isWindows ? &amp;quot;.exe&amp;quot; : &amp;quot;&amp;quot;); //Add file extension if on windows &lt;br /&gt;
bci.connection.Connect();&lt;br /&gt;
bci.LoadParameters(&amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;);&lt;br /&gt;
bci.StartupModules(new Dictionary&amp;lt;string, IEnumerable&amp;lt;string&amp;gt;?&amp;gt; {&lt;br /&gt;
	{&amp;quot;SignalGenerator&amp;quot;, new() {&amp;quot;LogKeyboard=1&amp;quot;, &amp;quot;SpinningWheel=1&amp;quot;, &amp;quot;ShowDisplayStatistics=1&amp;quot;}},&lt;br /&gt;
	{&amp;quot;P3SignalProcessing&amp;quot;, null},&lt;br /&gt;
	{&amp;quot;StimulusPresentation&amp;quot;, null}&lt;br /&gt;
	});&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
C# startup scripts have access to all of the constructs of the C# language, so different actions can be taken depending on conditions such as the operating system, as seen in the above script, or take other input such as command line options.&lt;br /&gt;
Note that this will need to be part of a C# project, created via &amp;lt;code&amp;gt;dotnet new console&amp;lt;/code&amp;gt; with its accompanied &amp;lt;code&amp;gt;.csproj&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
An alternative would be to instead use a PowerShell or F# script, which can then be run via &amp;lt;code&amp;gt;pwsh&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;dotnet fsi&amp;lt;/code&amp;gt;. This is the equivalent F# code:&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.fsx&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#r &amp;quot;../BCI2000RemoteNET.dll&amp;quot;&lt;br /&gt;
open BCI2000RemoteNET&lt;br /&gt;
open System.Runtime.InteropServices&lt;br /&gt;
let bci = new BCI2000Remote(new BCI2000Connection()) in&lt;br /&gt;
let isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) in&lt;br /&gt;
let operatorPath = &amp;quot;../../bci2000/prog/Operator&amp;quot; + if isWindows then &amp;quot;.exe&amp;quot; else &amp;quot;&amp;quot; in&lt;br /&gt;
bci.connection.StartOperator operatorPath;&lt;br /&gt;
bci.connection.Connect ();&lt;br /&gt;
bci.LoadParameters &amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;;&lt;br /&gt;
bci.StartupModules &amp;lt;| Map [&lt;br /&gt;
  (&amp;quot;SignalGenerator&amp;quot;, [&amp;quot;LogKeyboard=1&amp;quot;; &amp;quot;SpinningWheel=1&amp;quot;; &amp;quot;ShowDisplayStatistics=1&amp;quot;]);&lt;br /&gt;
  (&amp;quot;P3SignalProcessing&amp;quot;, null);&lt;br /&gt;
  (&amp;quot;StimulusPresentation&amp;quot;, null);&lt;br /&gt;
  ]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This can be run directly:&lt;br /&gt;
&amp;lt;code&amp;gt;dotnet fsi StimulusPresentation_SignalGenerator.fsx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Note On Security==&lt;br /&gt;
The BCI2000 command line interface can be used to run arbitrary system shell commands. It is also entirely unsecured and unencrypted. Anyone who has access to it effectively has full access to the computer on which it runs. This is not a problem if running locally, and is generally not a problem if running on a firewalled local network. However, due to the unsecured nature of the interface, running BCI2000 across the internet is highly discouraged. That is, if you set BCI2000 to listen at an address of an external network interface, or to listen at all connections by passing the address &amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt;, make sure that port 3999 (or whichever port BCI2000 is listening on), is not forwarded beyond the local network by your router. Support for securely connecting to BCI2000 is planned for the future.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11352</id>
		<title>Contributions:BCI2000RemoteNET</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11352"/>
		<updated>2024-05-24T20:53:34Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Fixed start up modules documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
BCI2000RemoteNET is a library for controlling BCI2000 from .NET programs such as Unity. With C# top-level declarations, it can also be used as a replacement for [[User Reference:BCI2000Shell]] with the added step of compilation via [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/ &amp;lt;code&amp;gt;csc&amp;lt;/code&amp;gt;]. &lt;br /&gt;
&lt;br /&gt;
==Operation==&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET communicates with the BCI2000 Operator via [[User Reference:Operator Module Scripting|operator module scripting commands]], which are sent as text over TCP to a running Operator. It also provides functionality for starting the Operator directly, so it can control the Operator entirely from startup to shutdown. &lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET consists of two classes, &amp;lt;code&amp;gt;BCI2000Connection&amp;lt;/code&amp;gt;, which provides the basic functionality necessary for starting and communicating with BCI2000, and &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt;, which provides a set of methods for controlling a BCI2000 experiment, such as interacting with parameters and events, as well as starting modules and experiments.&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET comes in two versions, targeting .NET 8.0 and .NET Standard 2.1. This is due to compatibility with programs such as Unity, which require .NET Standard binaries. There is little difference in functionality between the two versions, other than the behavior of the &amp;lt;code&amp;gt;Execute()&amp;lt;/code&amp;gt; method, whose differences are described below.&lt;br /&gt;
&lt;br /&gt;
==Documentation==&lt;br /&gt;
Documentation for the classes can be found here:&lt;br /&gt;
&lt;br /&gt;
====.NET 8.0====&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
====.NET Standard 2.1====&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Acquire the latest binary from [https://github.com/neurotechcenter/BCI2000RemoteNET GitHub], or build from source from the source code on GitHub or in the main BCI2000 Subversion repository (Keep in mind that the version in the Subversion repository will likely be behind the version on GitHub.)&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
====Starting the operator====&lt;br /&gt;
If you plan on starting the operator separately, skip this step, but make sure to start the operator with its &amp;lt;code&amp;gt;--Telnet&amp;lt;/code&amp;gt; option set.&lt;br /&gt;
&lt;br /&gt;
In order to start the operator, call the &amp;lt;code&amp;gt;BCI2000Connection.StartOperator&amp;lt;/code&amp;gt; method with the path to your BCI2000 Operator executable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
conn.StartOperator(&amp;quot;Path/To/BCI2000/prog/Operator.exe&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, this will start an operator listening on &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. You can also set the Operator to listen on another port:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, port: 51101);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you wish to accept connections from other computers you can set BCI2000 to listen on all addresses:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;0.0.0.0&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or listen on a specific network interface:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;10.11.198.2&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Connecting to the operator====&lt;br /&gt;
Connect to the operator with the &amp;lt;code&amp;gt;BCI2000Connection.Connect()&amp;lt;/code&amp;gt; method. If you started a local operator with default settings, then you can call &amp;lt;code&amp;gt;Connect&amp;lt;/code&amp;gt; with its default parameters, which will connect to the operator at &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. If you are connecting to an operator on another machine, say at IP address &amp;lt;code&amp;gt;11.11.11.11&amp;lt;/code&amp;gt;,or one listening on a port other than 3999, call &amp;lt;code&amp;gt;Connect()&amp;lt;/code&amp;gt; with its optional parameters.&lt;br /&gt;
Please see the [[#Note On Security]] for an important caveat of setting a non-default parameter here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator on the same machine on the default port.&lt;br /&gt;
conn.Connect();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator at address 11.11.11.11:3999&lt;br /&gt;
conn.Connect(address: &amp;quot;11.11.11.11&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Adding parameters and events====&lt;br /&gt;
At this point you can add parameters and events to BCI2000. &lt;br /&gt;
Parameters are values which can be changed in the BCI2000 GUI and can be used to change how experiments behave.&lt;br /&gt;
Parameters can either be loaded from a file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //path is relative to the Operator&#039;s working directory, that is, the /prog directory of the BCI2000 installation&lt;br /&gt;
  bci.LoadParameters(&amp;quot;path/to/parameterfile.prm&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
or added individually:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value 0 &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value &amp;quot;Green&amp;quot; &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param2&amp;quot;, &amp;quot;Green&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea2 section within the Application tab, with default value 0 and range 0-10&lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param3&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;10&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Events are values logged by BCI2000 alongside the signal data. They have a temporal resolution equivalent to the sample rate, and can be set and read throughout data collection.&lt;br /&gt;
Events are unsigned integers with a bit width between 1 and 32:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //An event called &amp;quot;condition&amp;quot; representing a boolean value with possible values 0 and 1. Will be zero by default.&lt;br /&gt;
  bci.AddEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
  //An 32-bit event with default value 100, and range 0 to 2^32 - 1.&lt;br /&gt;
  bci.AddEvent(&amp;quot;value1&amp;quot;, 32, 100);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Starting BCI2000 Modules====&lt;br /&gt;
BCI2000 modules are started using the &amp;lt;code&amp;gt;StartModules()&amp;lt;/code&amp;gt; method, given a dictionary of module names and argument lists. For example, to open SignalGenerator, DummySignalProcessing, and DummyApplication with keyboard and mouse logging:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bci.StartupModules(new Dictionary&amp;lt;string, IEnumerable&amp;lt;string&amp;gt;?&amp;gt;()&lt;br /&gt;
  {&lt;br /&gt;
    {&amp;quot;SignalGenerator&amp;quot;, new List&amp;lt;string&amp;gt;() {&amp;quot;LogKeyboard=1&amp;quot;, &amp;quot;LogMouse=1&amp;quot;}},&lt;br /&gt;
    {&amp;quot;DummySignalProcessing&amp;quot;, null},&lt;br /&gt;
    {&amp;quot;DummyApplication&amp;quot;, null}&lt;br /&gt;
  });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Setting Parameters and Visualizing Values====&lt;br /&gt;
If using BCI2000RemoteNET as a substitute for BCI2000Shell for setting up the basic environment, this would usually be where you continue using BCI2000 through its own GUI.&lt;br /&gt;
&lt;br /&gt;
At this point parameters can be set via &amp;lt;code&amp;gt;SetParameter&amp;lt;/code&amp;gt;, for example, setting up experiment parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.SetParameter(&amp;quot;DataDirectory&amp;quot;, &amp;quot;../data/theDirectory&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectName&amp;quot;, &amp;quot;APatient&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectSession&amp;quot;, &amp;quot;004&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also set values such as events to be shown in a graph view. &lt;br /&gt;
For example, since we set the source module to start with mouse logging enabled, we can view the values of the mouse position events.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We can also visualize the events we added earlier.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;condition&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;value1&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Collecting Data====&lt;br /&gt;
Start collecting data with the &amp;lt;code&amp;gt;Start()&amp;lt;/code&amp;gt; method. This will implicitly call &amp;lt;code&amp;gt;SetConfig()&amp;lt;/code&amp;gt;, but it can be called separately as well.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Start();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you instead want to start BCI2000 through the GUI, and wait for it in this program, you can instead wait for BCI2000 to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Running);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
During a run you can interact with BCI2000 by setting event variables:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.SetEvent(&amp;quot;value1&amp;quot;, 400);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also pulse events, setting their value for one sample duration before setting them back.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.PulseEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also get values from BCI2000. As we set the source module to log the mouse position earlier, we can retrieve its value via &amp;lt;code&amp;gt;GetEvent()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  uint mousePositionX = bci.GetEvent(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  uint mousePositionY = bci.GetEvent(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also retrieve the value of the hardware signal. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //Get value of element 2 of channel 1 of signal&lt;br /&gt;
  double signal11 = bci.GetSignal(1, 2);X&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Stopping BCI2000====&lt;br /&gt;
When you are finished collecting data, stop BCI2000 with the &amp;lt;code&amp;gt;BCI2000Connection.Stop()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.connection.Stop();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also shut down BCI2000.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.connection.Quit();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you instead want to stop BCI2000 via the GUI, you can wait for the system to be in the &amp;lt;code&amp;gt;Suspended&amp;lt;/code&amp;gt; state. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Connected);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you want to poll the system state repeatedly (in a loop, for example);&lt;br /&gt;
&amp;lt;pre&amp;gt;  &lt;br /&gt;
 bool loop = true;&lt;br /&gt;
  while (loop) {&lt;br /&gt;
    ...&lt;br /&gt;
    if (bci.GetSystemState() == BCI2000Remote.SystemState.Suspended) {&lt;br /&gt;
      loop = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
Embedding BCI2000RemoteNET within another program is largely covered above, so this section focuses on alternative usecases.&lt;br /&gt;
&lt;br /&gt;
====Using BCI2000RemoteNET as a substitute for BCI2000Shell====&lt;br /&gt;
BCI2000RemoteNET can be used as a replacement for BCI2000Shell when starting up BCI2000, if you need more advanced language capabilities than what the operator scripting language can provide.&lt;br /&gt;
&lt;br /&gt;
This is the existing startup script for the Stimulus Presentation task with the software Signal Generator.&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.bat&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#! ../prog/BCI2000Shell&lt;br /&gt;
@cls &amp;amp; ..\prog\BCI2000Shell %0 %* #! &amp;amp;&amp;amp; exit /b 0 || exit /b 1\n&lt;br /&gt;
Change directory $BCI2000LAUNCHDIR&lt;br /&gt;
Show window; Set title ${Extract file base $0}&lt;br /&gt;
Reset system&lt;br /&gt;
Startup system localhost&lt;br /&gt;
Start executable SignalGenerator --local --LogKeyboard=1 --SpinningWheel=1 --ShowDisplayStatistics=1&lt;br /&gt;
Start executable P3SignalProcessing --local&lt;br /&gt;
Start executable StimulusPresentation --local&lt;br /&gt;
Wait for Connected&lt;br /&gt;
Load parameterfile &amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the equivalent C# code using BCI2000RemoteNET:&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.cs&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
using BCI2000RemoteNET;&lt;br /&gt;
using System.RuntimeInformation.InteropServices;&lt;br /&gt;
BCI2000Remote bci = new(new BCI2000Connection());&lt;br /&gt;
bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);&lt;br /&gt;
bci.connection.StartOperator(&amp;quot;../prog/Operator&amp;quot; + isWindows ? &amp;quot;.exe&amp;quot; : &amp;quot;&amp;quot;); //Add file extension if on windows &lt;br /&gt;
bci.connection.Connect();&lt;br /&gt;
bci.LoadParameters(&amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;);&lt;br /&gt;
bci.StartupModules(new Dictionary&amp;lt;string, IEnumerable&amp;lt;string&amp;gt;?&amp;gt; {&lt;br /&gt;
	{&amp;quot;SignalGenerator&amp;quot;, new() {&amp;quot;LogKeyboard=1&amp;quot;, &amp;quot;SpinningWheel=1&amp;quot;, &amp;quot;ShowDisplayStatistics=1&amp;quot;}},&lt;br /&gt;
	{&amp;quot;P3SignalProcessing&amp;quot;, null},&lt;br /&gt;
	{&amp;quot;StimulusPresentation&amp;quot;, null}&lt;br /&gt;
	});&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
C# startup scripts have access to all of the constructs of the C# language, so different actions can be taken depending on conditions such as the operating system, as seen in the above script, or take other input such as command line options.&lt;br /&gt;
Note that this will need to be part of a C# project, created via &amp;lt;code&amp;gt;dotnet new console&amp;lt;/code&amp;gt; with its accompanied &amp;lt;code&amp;gt;.csproj&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
An alternative would be to instead use a PowerShell or F# script, which can then be run via &amp;lt;code&amp;gt;pwsh&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;dotnet fsi&amp;lt;/code&amp;gt;. This is the equivalent F# code:&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.fsx&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#r &amp;quot;../BCI2000RemoteNET.dll&amp;quot;&lt;br /&gt;
open BCI2000RemoteNET&lt;br /&gt;
open System.Runtime.InteropServices&lt;br /&gt;
let bci = new BCI2000Remote(new BCI2000Connection()) in&lt;br /&gt;
let isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) in&lt;br /&gt;
let operatorPath = &amp;quot;../../bci2000/prog/Operator&amp;quot; + if isWindows then &amp;quot;.exe&amp;quot; else &amp;quot;&amp;quot; in&lt;br /&gt;
bci.connection.StartOperator operatorPath;&lt;br /&gt;
bci.connection.Connect ();&lt;br /&gt;
bci.LoadParameters &amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;;&lt;br /&gt;
bci.StartupModules &amp;lt;| Map [&lt;br /&gt;
  (&amp;quot;SignalGenerator&amp;quot;, [&amp;quot;LogKeyboard=1&amp;quot;; &amp;quot;SpinningWheel=1&amp;quot;; &amp;quot;ShowDisplayStatistics=1&amp;quot;]);&lt;br /&gt;
  (&amp;quot;P3SignalProcessing&amp;quot;, null);&lt;br /&gt;
  (&amp;quot;StimulusPresentation&amp;quot;, null);&lt;br /&gt;
  ]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This can be run directly:&lt;br /&gt;
&amp;lt;code&amp;gt;dotnet fsi StimulusPresentation_SignalGenerator.fsx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Note On Security==&lt;br /&gt;
The BCI2000 command line interface can be used to run arbitrary system shell commands. It is also entirely unsecured and unencrypted. Anyone who has access to it effectively has full access to the computer on which it runs. This is not a problem if running locally, and is generally not a problem if running on a firewalled local network. However, due to the unsecured nature of the interface, running BCI2000 across the internet is highly discouraged. That is, if you set BCI2000 to listen at an address of an external network interface, or to listen at all connections by passing the address &amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt;, make sure that port 3999 (or whichever port BCI2000 is listening on), is not forwarded beyond the local network by your router. Support for securely connecting to BCI2000 is planned for the future.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11337</id>
		<title>Contributions:BCI2000RemoteNET</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11337"/>
		<updated>2024-05-21T14:31:16Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Change wording of future plans&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
BCI2000RemoteNET is a library for controlling BCI2000 from .NET programs such as Unity. With C# top-level declarations, it can also be used as a replacement for [[User Reference:BCI2000Shell]] with the added step of compilation via [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/ &amp;lt;code&amp;gt;csc&amp;lt;/code&amp;gt;]. &lt;br /&gt;
&lt;br /&gt;
==Operation==&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET communicates with the BCI2000 Operator via [[User Reference:Operator Module Scripting|operator module scripting commands]], which are sent as text over TCP to a running Operator. It also provides functionality for starting the Operator directly, so it can control the Operator entirely from startup to shutdown. &lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET consists of two classes, &amp;lt;code&amp;gt;BCI2000Connection&amp;lt;/code&amp;gt;, which provides the basic functionality necessary for starting and communicating with BCI2000, and &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt;, which provides a set of methods for controlling a BCI2000 experiment, such as interacting with parameters and events, as well as starting modules and experiments.&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET comes in two versions, targeting .NET 8.0 and .NET Standard 2.1. This is due to compatibility with programs such as Unity, which require .NET Standard binaries. There is little difference in functionality between the two versions, other than the behavior of the &amp;lt;code&amp;gt;Execute()&amp;lt;/code&amp;gt; method, whose differences are described below.&lt;br /&gt;
&lt;br /&gt;
==Documentation==&lt;br /&gt;
Documentation for the classes can be found here:&lt;br /&gt;
&lt;br /&gt;
====.NET 8.0====&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
====.NET Standard 2.1====&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Acquire the latest binary from [https://github.com/neurotechcenter/BCI2000RemoteNET GitHub], or build from source from the source code on GitHub or in the main BCI2000 Subversion repository (Keep in mind that the version in the Subversion repository will likely be behind the version on GitHub.)&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
====Starting the operator====&lt;br /&gt;
If you plan on starting the operator separately, skip this step, but make sure to start the operator with its &amp;lt;code&amp;gt;--Telnet&amp;lt;/code&amp;gt; option set.&lt;br /&gt;
&lt;br /&gt;
In order to start the operator, call the &amp;lt;code&amp;gt;BCI2000Connection.StartOperator&amp;lt;/code&amp;gt; method with the path to your BCI2000 Operator executable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
conn.StartOperator(&amp;quot;Path/To/BCI2000/prog/Operator.exe&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, this will start an operator listening on &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. You can also set the Operator to listen on another port:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, port: 51101);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you wish to accept connections from other computers you can set BCI2000 to listen on all addresses:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;0.0.0.0&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or listen on a specific network interface:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;10.11.198.2&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Connecting to the operator====&lt;br /&gt;
Connect to the operator with the &amp;lt;code&amp;gt;BCI2000Connection.Connect()&amp;lt;/code&amp;gt; method. If you started a local operator with default settings, then you can call &amp;lt;code&amp;gt;Connect&amp;lt;/code&amp;gt; with its default parameters, which will connect to the operator at &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. If you are connecting to an operator on another machine, say at IP address &amp;lt;code&amp;gt;11.11.11.11&amp;lt;/code&amp;gt;,or one listening on a port other than 3999, call &amp;lt;code&amp;gt;Connect()&amp;lt;/code&amp;gt; with its optional parameters.&lt;br /&gt;
Please see the [[#Note On Security]] for an important caveat of setting a non-default parameter here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator on the same machine on the default port.&lt;br /&gt;
conn.Connect();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator at address 11.11.11.11:3999&lt;br /&gt;
conn.Connect(address: &amp;quot;11.11.11.11&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Adding parameters and events====&lt;br /&gt;
At this point you can add parameters and events to BCI2000. &lt;br /&gt;
Parameters are values which can be changed in the BCI2000 GUI and can be used to change how experiments behave.&lt;br /&gt;
Parameters can either be loaded from a file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //path is relative to the Operator&#039;s working directory, that is, the /prog directory of the BCI2000 installation&lt;br /&gt;
  bci.LoadParameters(&amp;quot;path/to/parameterfile.prm&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
or added individually:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value 0 &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value &amp;quot;Green&amp;quot; &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param2&amp;quot;, &amp;quot;Green&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea2 section within the Application tab, with default value 0 and range 0-10&lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param3&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;10&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Events are values logged by BCI2000 alongside the signal data. They have a temporal resolution equivalent to the sample rate, and can be set and read throughout data collection.&lt;br /&gt;
Events are unsigned integers with a bit width between 1 and 32:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //An event called &amp;quot;condition&amp;quot; representing a boolean value with possible values 0 and 1. Will be zero by default.&lt;br /&gt;
  bci.AddEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
  //An 32-bit event with default value 100, and range 0 to 2^32 - 1.&lt;br /&gt;
  bci.AddEvent(&amp;quot;value1&amp;quot;, 32, 100);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Starting BCI2000 Modules====&lt;br /&gt;
BCI2000 modules are started using the &amp;lt;code&amp;gt;StartModules()&amp;lt;/code&amp;gt; method, given a dictionary of module names and argument lists. For example, to open SignalGenerator, DummySignalProcessing, and DummyApplication with keyboard and mouse logging:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bci.StartupModules(new Dictionary&amp;lt;string, List&amp;lt;string&amp;gt;?&amp;gt;()&lt;br /&gt;
  {&lt;br /&gt;
    {&amp;quot;SignalGenerator&amp;quot;, new List&amp;lt;string&amp;gt;() {&amp;quot;LogKeyboard=1&amp;quot;, &amp;quot;LogMouse=1&amp;quot;}},&lt;br /&gt;
    {&amp;quot;DummySignalProcessing&amp;quot;, null},&lt;br /&gt;
    {&amp;quot;DummyApplication&amp;quot;, null}&lt;br /&gt;
  });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Setting Parameters and Visualizing Values====&lt;br /&gt;
If using BCI2000RemoteNET as a substitute for BCI2000Shell for setting up the basic environment, this would usually be where you continue using BCI2000 through its own GUI.&lt;br /&gt;
&lt;br /&gt;
At this point parameters can be set via &amp;lt;code&amp;gt;SetParameter&amp;lt;/code&amp;gt;, for example, setting up experiment parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.SetParameter(&amp;quot;DataDirectory&amp;quot;, &amp;quot;../data/theDirectory&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectName&amp;quot;, &amp;quot;APatient&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectSession&amp;quot;, &amp;quot;004&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also set values such as events to be shown in a graph view. &lt;br /&gt;
For example, since we set the source module to start with mouse logging enabled, we can view the values of the mouse position events.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We can also visualize the events we added earlier.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;condition&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;value1&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Collecting Data====&lt;br /&gt;
Start collecting data with the &amp;lt;code&amp;gt;Start()&amp;lt;/code&amp;gt; method. This will implicitly call &amp;lt;code&amp;gt;SetConfig()&amp;lt;/code&amp;gt;, but it can be called separately as well.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Start();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you instead want to start BCI2000 through the GUI, and wait for it in this program, you can instead wait for BCI2000 to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Running);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
During a run you can interact with BCI2000 by setting event variables:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.SetEvent(&amp;quot;value1&amp;quot;, 400);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also pulse events, setting their value for one sample duration before setting them back.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.PulseEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also get values from BCI2000. As we set the source module to log the mouse position earlier, we can retrieve its value via &amp;lt;code&amp;gt;GetEvent()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  uint mousePositionX = bci.GetEvent(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  uint mousePositionY = bci.GetEvent(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also retrieve the value of the hardware signal. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //Get value of element 2 of channel 1 of signal&lt;br /&gt;
  double signal11 = bci.GetSignal(1, 2);X&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Stopping BCI2000====&lt;br /&gt;
When you are finished collecting data, stop BCI2000 with the &amp;lt;code&amp;gt;BCI2000Connection.Stop()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.connection.Stop();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also shut down BCI2000.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.connection.Quit();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you instead want to stop BCI2000 via the GUI, you can wait for the system to be in the &amp;lt;code&amp;gt;Suspended&amp;lt;/code&amp;gt; state. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Connected);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you want to poll the system state repeatedly (in a loop, for example);&lt;br /&gt;
&amp;lt;pre&amp;gt;  &lt;br /&gt;
 bool loop = true;&lt;br /&gt;
  while (loop) {&lt;br /&gt;
    ...&lt;br /&gt;
    if (bci.GetSystemState() == BCI2000Remote.SystemState.Suspended) {&lt;br /&gt;
      loop = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
Embedding BCI2000RemoteNET within another program is largely covered above, so this section focuses on alternative usecases.&lt;br /&gt;
&lt;br /&gt;
====Using BCI2000RemoteNET as a substitute for BCI2000Shell====&lt;br /&gt;
BCI2000RemoteNET can be used as a replacement for BCI2000Shell when starting up BCI2000, if you need more advanced language capabilities than what the operator scripting language can provide.&lt;br /&gt;
&lt;br /&gt;
This is the existing startup script for the Stimulus Presentation task with the software Signal Generator.&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.bat&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#! ../prog/BCI2000Shell&lt;br /&gt;
@cls &amp;amp; ..\prog\BCI2000Shell %0 %* #! &amp;amp;&amp;amp; exit /b 0 || exit /b 1\n&lt;br /&gt;
Change directory $BCI2000LAUNCHDIR&lt;br /&gt;
Show window; Set title ${Extract file base $0}&lt;br /&gt;
Reset system&lt;br /&gt;
Startup system localhost&lt;br /&gt;
Start executable SignalGenerator --local --LogKeyboard=1 --SpinningWheel=1 --ShowDisplayStatistics=1&lt;br /&gt;
Start executable P3SignalProcessing --local&lt;br /&gt;
Start executable StimulusPresentation --local&lt;br /&gt;
Wait for Connected&lt;br /&gt;
Load parameterfile &amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the equivalent C# code using BCI2000RemoteNET:&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.cs&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
using BCI2000RemoteNET;&lt;br /&gt;
using System.RuntimeInformation.InteropServices;&lt;br /&gt;
BCI2000Remote bci = new(new BCI2000Connection());&lt;br /&gt;
bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);&lt;br /&gt;
bci.connection.StartOperator(&amp;quot;../prog/Operator&amp;quot; + isWindows ? &amp;quot;.exe&amp;quot; : &amp;quot;&amp;quot;); //Add file extension if on windows &lt;br /&gt;
bci.connection.Connect();&lt;br /&gt;
bci.LoadParameters(&amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;);&lt;br /&gt;
bci.StartupModules(new() {&lt;br /&gt;
	{&amp;quot;SignalGenerator&amp;quot;, new() {&amp;quot;LogKeyboard=1&amp;quot;, &amp;quot;SpinningWheel=1&amp;quot;, &amp;quot;ShowDisplayStatistics=1&amp;quot;}},&lt;br /&gt;
	{&amp;quot;P3SignalProcessing&amp;quot;, null},&lt;br /&gt;
	{&amp;quot;StimulusPresentation&amp;quot;, null}&lt;br /&gt;
	});&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
C# startup scripts have access to all of the constructs of the C# language, so different actions can be taken depending on conditions such as the operating system, as seen in the above script, or take other input such as command line options.&lt;br /&gt;
Note that this will need to be part of a C# project, created via &amp;lt;code&amp;gt;dotnet new console&amp;lt;/code&amp;gt; with its accompanied &amp;lt;code&amp;gt;.csproj&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
An alternative would be to instead use a PowerShell or F# script, which can then be run via &amp;lt;code&amp;gt;pwsh&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;dotnet fsi&amp;lt;/code&amp;gt;. This is the equivalent F# code:&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.fsx&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#r &amp;quot;../BCI2000RemoteNET.dll&amp;quot;&lt;br /&gt;
open BCI2000RemoteNET&lt;br /&gt;
open System.Runtime.InteropServices&lt;br /&gt;
let bci = new BCI2000Remote(new BCI2000Connection()) in&lt;br /&gt;
let isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) in&lt;br /&gt;
let operatorPath = &amp;quot;../../bci2000/prog/Operator&amp;quot; + if isWindows then &amp;quot;.exe&amp;quot; else &amp;quot;&amp;quot; in&lt;br /&gt;
bci.connection.StartOperator operatorPath;&lt;br /&gt;
bci.connection.Connect ();&lt;br /&gt;
bci.LoadParameters &amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;;&lt;br /&gt;
bci.StartupModules &amp;lt;| Map [&lt;br /&gt;
  (&amp;quot;SignalGenerator&amp;quot;, [&amp;quot;LogKeyboard=1&amp;quot;; &amp;quot;SpinningWheel=1&amp;quot;; &amp;quot;ShowDisplayStatistics=1&amp;quot;]);&lt;br /&gt;
  (&amp;quot;P3SignalProcessing&amp;quot;, null);&lt;br /&gt;
  (&amp;quot;StimulusPresentation&amp;quot;, null);&lt;br /&gt;
  ]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This can be run directly:&lt;br /&gt;
&amp;lt;code&amp;gt;dotnet fsi StimulusPresentation_SignalGenerator.fsx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Note On Security==&lt;br /&gt;
The BCI2000 command line interface can be used to run arbitrary system shell commands. It is also entirely unsecured and unencrypted. Anyone who has access to it effectively has full access to the computer on which it runs. This is not a problem if running locally, and is generally not a problem if running on a firewalled local network. However, due to the unsecured nature of the interface, running BCI2000 across the internet is highly discouraged. That is, if you set BCI2000 to listen at an address of an external network interface, or to listen at all connections by passing the address &amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt;, make sure that port 3999 (or whichever port BCI2000 is listening on), is not forwarded beyond the local network by your router. Support for securely connecting to BCI2000 is planned for the future.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11336</id>
		<title>Contributions:BCI2000RemoteNET</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11336"/>
		<updated>2024-05-17T21:21:53Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: added F# example&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
BCI2000RemoteNET is a library for controlling BCI2000 from .NET programs such as Unity. With C# top-level declarations, it can also be used as a replacement for [[User Reference:BCI2000Shell]] with the added step of compilation via [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/ &amp;lt;code&amp;gt;csc&amp;lt;/code&amp;gt;]. &lt;br /&gt;
&lt;br /&gt;
==Operation==&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET communicates with the BCI2000 Operator via [[User Reference:Operator Module Scripting|operator module scripting commands]], which are sent as text over TCP to a running Operator. It also provides functionality for starting the Operator directly, so it can control the Operator entirely from startup to shutdown. &lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET consists of two classes, &amp;lt;code&amp;gt;BCI2000Connection&amp;lt;/code&amp;gt;, which provides the basic functionality necessary for starting and communicating with BCI2000, and &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt;, which provides a set of methods for controlling a BCI2000 experiment, such as interacting with parameters and events, as well as starting modules and experiments.&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET comes in two versions, targeting .NET 8.0 and .NET Standard 2.1. This is due to compatibility with programs such as Unity, which require .NET Standard binaries. There is little difference in functionality between the two versions, other than the behavior of the &amp;lt;code&amp;gt;Execute()&amp;lt;/code&amp;gt; method, whose differences are described below.&lt;br /&gt;
&lt;br /&gt;
==Documentation==&lt;br /&gt;
Documentation for the classes can be found here:&lt;br /&gt;
&lt;br /&gt;
====.NET 8.0====&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
====.NET Standard 2.1====&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Acquire the latest binary from [https://github.com/neurotechcenter/BCI2000RemoteNET GitHub], or build from source from the source code on GitHub or in the main BCI2000 Subversion repository (Keep in mind that the version in the Subversion repository will likely be behind the version on GitHub.)&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
====Starting the operator====&lt;br /&gt;
If you plan on starting the operator separately, skip this step, but make sure to start the operator with its &amp;lt;code&amp;gt;--Telnet&amp;lt;/code&amp;gt; option set.&lt;br /&gt;
&lt;br /&gt;
In order to start the operator, call the &amp;lt;code&amp;gt;BCI2000Connection.StartOperator&amp;lt;/code&amp;gt; method with the path to your BCI2000 Operator executable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
conn.StartOperator(&amp;quot;Path/To/BCI2000/prog/Operator.exe&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, this will start an operator listening on &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. You can also set the Operator to listen on another port:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, port: 51101);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you wish to accept connections from other computers you can set BCI2000 to listen on all addresses:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;0.0.0.0&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or listen on a specific network interface:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;10.11.198.2&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Connecting to the operator====&lt;br /&gt;
Connect to the operator with the &amp;lt;code&amp;gt;BCI2000Connection.Connect()&amp;lt;/code&amp;gt; method. If you started a local operator with default settings, then you can call &amp;lt;code&amp;gt;Connect&amp;lt;/code&amp;gt; with its default parameters, which will connect to the operator at &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. If you are connecting to an operator on another machine, say at IP address &amp;lt;code&amp;gt;11.11.11.11&amp;lt;/code&amp;gt;,or one listening on a port other than 3999, call &amp;lt;code&amp;gt;Connect()&amp;lt;/code&amp;gt; with its optional parameters.&lt;br /&gt;
Please see the [[#Note On Security]] for an important caveat of setting a non-default parameter here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator on the same machine on the default port.&lt;br /&gt;
conn.Connect();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator at address 11.11.11.11:3999&lt;br /&gt;
conn.Connect(address: &amp;quot;11.11.11.11&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Adding parameters and events====&lt;br /&gt;
At this point you can add parameters and events to BCI2000. &lt;br /&gt;
Parameters are values which can be changed in the BCI2000 GUI and can be used to change how experiments behave.&lt;br /&gt;
Parameters can either be loaded from a file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //path is relative to the Operator&#039;s working directory, that is, the /prog directory of the BCI2000 installation&lt;br /&gt;
  bci.LoadParameters(&amp;quot;path/to/parameterfile.prm&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
or added individually:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value 0 &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value &amp;quot;Green&amp;quot; &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param2&amp;quot;, &amp;quot;Green&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea2 section within the Application tab, with default value 0 and range 0-10&lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param3&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;10&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Events are values logged by BCI2000 alongside the signal data. They have a temporal resolution equivalent to the sample rate, and can be set and read throughout data collection.&lt;br /&gt;
Events are unsigned integers with a bit width between 1 and 32:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //An event called &amp;quot;condition&amp;quot; representing a boolean value with possible values 0 and 1. Will be zero by default.&lt;br /&gt;
  bci.AddEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
  //An 32-bit event with default value 100, and range 0 to 2^32 - 1.&lt;br /&gt;
  bci.AddEvent(&amp;quot;value1&amp;quot;, 32, 100);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Starting BCI2000 Modules====&lt;br /&gt;
BCI2000 modules are started using the &amp;lt;code&amp;gt;StartModules()&amp;lt;/code&amp;gt; method, given a dictionary of module names and argument lists. For example, to open SignalGenerator, DummySignalProcessing, and DummyApplication with keyboard and mouse logging:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bci.StartupModules(new Dictionary&amp;lt;string, List&amp;lt;string&amp;gt;?&amp;gt;()&lt;br /&gt;
  {&lt;br /&gt;
    {&amp;quot;SignalGenerator&amp;quot;, new List&amp;lt;string&amp;gt;() {&amp;quot;LogKeyboard=1&amp;quot;, &amp;quot;LogMouse=1&amp;quot;}},&lt;br /&gt;
    {&amp;quot;DummySignalProcessing&amp;quot;, null},&lt;br /&gt;
    {&amp;quot;DummyApplication&amp;quot;, null}&lt;br /&gt;
  });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Setting Parameters and Visualizing Values====&lt;br /&gt;
If using BCI2000RemoteNET as a substitute for BCI2000Shell for setting up the basic environment, this would usually be where you continue using BCI2000 through its own GUI.&lt;br /&gt;
&lt;br /&gt;
At this point parameters can be set via &amp;lt;code&amp;gt;SetParameter&amp;lt;/code&amp;gt;, for example, setting up experiment parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.SetParameter(&amp;quot;DataDirectory&amp;quot;, &amp;quot;../data/theDirectory&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectName&amp;quot;, &amp;quot;APatient&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectSession&amp;quot;, &amp;quot;004&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also set values such as events to be shown in a graph view. &lt;br /&gt;
For example, since we set the source module to start with mouse logging enabled, we can view the values of the mouse position events.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We can also visualize the events we added earlier.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;condition&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;value1&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Collecting Data====&lt;br /&gt;
Start collecting data with the &amp;lt;code&amp;gt;Start()&amp;lt;/code&amp;gt; method. This will implicitly call &amp;lt;code&amp;gt;SetConfig()&amp;lt;/code&amp;gt;, but it can be called separately as well.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Start();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you instead want to start BCI2000 through the GUI, and wait for it in this program, you can instead wait for BCI2000 to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Running);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
During a run you can interact with BCI2000 by setting event variables:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.SetEvent(&amp;quot;value1&amp;quot;, 400);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also pulse events, setting their value for one sample duration before setting them back.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.PulseEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also get values from BCI2000. As we set the source module to log the mouse position earlier, we can retrieve its value via &amp;lt;code&amp;gt;GetEvent()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  uint mousePositionX = bci.GetEvent(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  uint mousePositionY = bci.GetEvent(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also retrieve the value of the hardware signal. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //Get value of element 2 of channel 1 of signal&lt;br /&gt;
  double signal11 = bci.GetSignal(1, 2);X&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Stopping BCI2000====&lt;br /&gt;
When you are finished collecting data, stop BCI2000 with the &amp;lt;code&amp;gt;BCI2000Connection.Stop()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.connection.Stop();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also shut down BCI2000.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.connection.Quit();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you instead want to stop BCI2000 via the GUI, you can wait for the system to be in the &amp;lt;code&amp;gt;Suspended&amp;lt;/code&amp;gt; state. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Connected);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you want to poll the system state repeatedly (in a loop, for example);&lt;br /&gt;
&amp;lt;pre&amp;gt;  &lt;br /&gt;
 bool loop = true;&lt;br /&gt;
  while (loop) {&lt;br /&gt;
    ...&lt;br /&gt;
    if (bci.GetSystemState() == BCI2000Remote.SystemState.Suspended) {&lt;br /&gt;
      loop = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
Embedding BCI2000RemoteNET within another program is largely covered above, so this section focuses on alternative usecases.&lt;br /&gt;
&lt;br /&gt;
====Using BCI2000RemoteNET as a substitute for BCI2000Shell====&lt;br /&gt;
BCI2000RemoteNET can be used as a replacement for BCI2000Shell when starting up BCI2000, if you need more advanced language capabilities than what the operator scripting language can provide.&lt;br /&gt;
&lt;br /&gt;
This is the existing startup script for the Stimulus Presentation task with the software Signal Generator.&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.bat&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#! ../prog/BCI2000Shell&lt;br /&gt;
@cls &amp;amp; ..\prog\BCI2000Shell %0 %* #! &amp;amp;&amp;amp; exit /b 0 || exit /b 1\n&lt;br /&gt;
Change directory $BCI2000LAUNCHDIR&lt;br /&gt;
Show window; Set title ${Extract file base $0}&lt;br /&gt;
Reset system&lt;br /&gt;
Startup system localhost&lt;br /&gt;
Start executable SignalGenerator --local --LogKeyboard=1 --SpinningWheel=1 --ShowDisplayStatistics=1&lt;br /&gt;
Start executable P3SignalProcessing --local&lt;br /&gt;
Start executable StimulusPresentation --local&lt;br /&gt;
Wait for Connected&lt;br /&gt;
Load parameterfile &amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the equivalent C# code using BCI2000RemoteNET:&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.cs&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
using BCI2000RemoteNET;&lt;br /&gt;
using System.RuntimeInformation.InteropServices;&lt;br /&gt;
BCI2000Remote bci = new(new BCI2000Connection());&lt;br /&gt;
bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);&lt;br /&gt;
bci.connection.StartOperator(&amp;quot;../prog/Operator&amp;quot; + isWindows ? &amp;quot;.exe&amp;quot; : &amp;quot;&amp;quot;); //Add file extension if on windows &lt;br /&gt;
bci.connection.Connect();&lt;br /&gt;
bci.LoadParameters(&amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;);&lt;br /&gt;
bci.StartupModules(new() {&lt;br /&gt;
	{&amp;quot;SignalGenerator&amp;quot;, new() {&amp;quot;LogKeyboard=1&amp;quot;, &amp;quot;SpinningWheel=1&amp;quot;, &amp;quot;ShowDisplayStatistics=1&amp;quot;}},&lt;br /&gt;
	{&amp;quot;P3SignalProcessing&amp;quot;, null},&lt;br /&gt;
	{&amp;quot;StimulusPresentation&amp;quot;, null}&lt;br /&gt;
	});&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
C# startup scripts have access to all of the constructs of the C# language, so different actions can be taken depending on conditions such as the operating system, as seen in the above script, or take other input such as command line options.&lt;br /&gt;
Note that this will need to be part of a C# project, created via &amp;lt;code&amp;gt;dotnet new console&amp;lt;/code&amp;gt; with its accompanied &amp;lt;code&amp;gt;.csproj&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
An alternative would be to instead use a PowerShell or F# script, which can then be run via &amp;lt;code&amp;gt;pwsh&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;dotnet fsi&amp;lt;/code&amp;gt;. This is the equivalent F# code:&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.fsx&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#r &amp;quot;../BCI2000RemoteNET.dll&amp;quot;&lt;br /&gt;
open BCI2000RemoteNET&lt;br /&gt;
open System.Runtime.InteropServices&lt;br /&gt;
let bci = new BCI2000Remote(new BCI2000Connection()) in&lt;br /&gt;
let isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) in&lt;br /&gt;
let operatorPath = &amp;quot;../../bci2000/prog/Operator&amp;quot; + if isWindows then &amp;quot;.exe&amp;quot; else &amp;quot;&amp;quot; in&lt;br /&gt;
bci.connection.StartOperator operatorPath;&lt;br /&gt;
bci.connection.Connect ();&lt;br /&gt;
bci.LoadParameters &amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;;&lt;br /&gt;
bci.StartupModules &amp;lt;| Map [&lt;br /&gt;
  (&amp;quot;SignalGenerator&amp;quot;, [&amp;quot;LogKeyboard=1&amp;quot;; &amp;quot;SpinningWheel=1&amp;quot;; &amp;quot;ShowDisplayStatistics=1&amp;quot;]);&lt;br /&gt;
  (&amp;quot;P3SignalProcessing&amp;quot;, null);&lt;br /&gt;
  (&amp;quot;StimulusPresentation&amp;quot;, null);&lt;br /&gt;
  ]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This can be run directly:&lt;br /&gt;
&amp;lt;code&amp;gt;dotnet fsi StimulusPresentation_SignalGenerator.fsx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Note On Security==&lt;br /&gt;
The BCI2000 command line interface can be used to run arbitrary system shell commands. It is also entirely unsecured and unencrypted. Anyone who has access to it effectively has full access to the computer on which it runs. This is not a problem if running locally, and is generally not a problem if running on a firewalled local network. However, due to the unsecured nature of the interface, running BCI2000 across the internet is highly discouraged. That is, if you set BCI2000 to listen at an address of an external network interface, or to listen at all connections by passing the address &amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt;, make sure that port 3999 (or whichever port BCI2000 is listening on), is not forwarded beyond the local network by your router. Support for interfacing with BCI2000 over TLS is planned, so that safe connection can be made over the internet.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11335</id>
		<title>Contributions:BCI2000RemoteNET</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11335"/>
		<updated>2024-05-17T19:47:29Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Fixed spacing&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
BCI2000RemoteNET is a library for controlling BCI2000 from .NET programs such as Unity. With C# top-level declarations, it can also be used as a replacement for [[User Reference:BCI2000Shell]] with the added step of compilation via [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/ &amp;lt;code&amp;gt;csc&amp;lt;/code&amp;gt;]. &lt;br /&gt;
&lt;br /&gt;
==Operation==&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET communicates with the BCI2000 Operator via [[User Reference:Operator Module Scripting|operator module scripting commands]], which are sent as text over TCP to a running Operator. It also provides functionality for starting the Operator directly, so it can control the Operator entirely from startup to shutdown. &lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET consists of two classes, &amp;lt;code&amp;gt;BCI2000Connection&amp;lt;/code&amp;gt;, which provides the basic functionality necessary for starting and communicating with BCI2000, and &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt;, which provides a set of methods for controlling a BCI2000 experiment, such as interacting with parameters and events, as well as starting modules and experiments.&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET comes in two versions, targeting .NET 8.0 and .NET Standard 2.1. This is due to compatibility with programs such as Unity, which require .NET Standard binaries. There is little difference in functionality between the two versions, other than the behavior of the &amp;lt;code&amp;gt;Execute()&amp;lt;/code&amp;gt; method, whose differences are described below.&lt;br /&gt;
&lt;br /&gt;
==Documentation==&lt;br /&gt;
Documentation for the classes can be found here:&lt;br /&gt;
&lt;br /&gt;
====.NET 8.0====&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
====.NET Standard 2.1====&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Acquire the latest binary from [https://github.com/neurotechcenter/BCI2000RemoteNET GitHub], or build from source from the source code on GitHub or in the main BCI2000 Subversion repository (Keep in mind that the version in the Subversion repository will likely be behind the version on GitHub.)&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
====Starting the operator====&lt;br /&gt;
If you plan on starting the operator separately, skip this step, but make sure to start the operator with its &amp;lt;code&amp;gt;--Telnet&amp;lt;/code&amp;gt; option set.&lt;br /&gt;
&lt;br /&gt;
In order to start the operator, call the &amp;lt;code&amp;gt;BCI2000Connection.StartOperator&amp;lt;/code&amp;gt; method with the path to your BCI2000 Operator executable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
conn.StartOperator(&amp;quot;Path/To/BCI2000/prog/Operator.exe&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, this will start an operator listening on &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. You can also set the Operator to listen on another port:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, port: 51101);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you wish to accept connections from other computers you can set BCI2000 to listen on all addresses:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;0.0.0.0&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or listen on a specific network interface:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;10.11.198.2&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Connecting to the operator====&lt;br /&gt;
Connect to the operator with the &amp;lt;code&amp;gt;BCI2000Connection.Connect()&amp;lt;/code&amp;gt; method. If you started a local operator with default settings, then you can call &amp;lt;code&amp;gt;Connect&amp;lt;/code&amp;gt; with its default parameters, which will connect to the operator at &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. If you are connecting to an operator on another machine, say at IP address &amp;lt;code&amp;gt;11.11.11.11&amp;lt;/code&amp;gt;,or one listening on a port other than 3999, call &amp;lt;code&amp;gt;Connect()&amp;lt;/code&amp;gt; with its optional parameters.&lt;br /&gt;
Please see the [[#Note On Security]] for an important caveat of setting a non-default parameter here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator on the same machine on the default port.&lt;br /&gt;
conn.Connect();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator at address 11.11.11.11:3999&lt;br /&gt;
conn.Connect(address: &amp;quot;11.11.11.11&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Adding parameters and events====&lt;br /&gt;
At this point you can add parameters and events to BCI2000. &lt;br /&gt;
Parameters are values which can be changed in the BCI2000 GUI and can be used to change how experiments behave.&lt;br /&gt;
Parameters can either be loaded from a file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //path is relative to the Operator&#039;s working directory, that is, the /prog directory of the BCI2000 installation&lt;br /&gt;
  bci.LoadParameters(&amp;quot;path/to/parameterfile.prm&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
or added individually:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value 0 &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value &amp;quot;Green&amp;quot; &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param2&amp;quot;, &amp;quot;Green&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea2 section within the Application tab, with default value 0 and range 0-10&lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param3&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;10&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Events are values logged by BCI2000 alongside the signal data. They have a temporal resolution equivalent to the sample rate, and can be set and read throughout data collection.&lt;br /&gt;
Events are unsigned integers with a bit width between 1 and 32:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //An event called &amp;quot;condition&amp;quot; representing a boolean value with possible values 0 and 1. Will be zero by default.&lt;br /&gt;
  bci.AddEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
  //An 32-bit event with default value 100, and range 0 to 2^32 - 1.&lt;br /&gt;
  bci.AddEvent(&amp;quot;value1&amp;quot;, 32, 100);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Starting BCI2000 Modules====&lt;br /&gt;
BCI2000 modules are started using the &amp;lt;code&amp;gt;StartModules()&amp;lt;/code&amp;gt; method, given a dictionary of module names and argument lists. For example, to open SignalGenerator, DummySignalProcessing, and DummyApplication with keyboard and mouse logging:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bci.StartupModules(new Dictionary&amp;lt;string, List&amp;lt;string&amp;gt;?&amp;gt;()&lt;br /&gt;
  {&lt;br /&gt;
    {&amp;quot;SignalGenerator&amp;quot;, new List&amp;lt;string&amp;gt;() {&amp;quot;LogKeyboard=1&amp;quot;, &amp;quot;LogMouse=1&amp;quot;}},&lt;br /&gt;
    {&amp;quot;DummySignalProcessing&amp;quot;, null},&lt;br /&gt;
    {&amp;quot;DummyApplication&amp;quot;, null}&lt;br /&gt;
  });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Setting Parameters and Visualizing Values====&lt;br /&gt;
If using BCI2000RemoteNET as a substitute for BCI2000Shell for setting up the basic environment, this would usually be where you continue using BCI2000 through its own GUI.&lt;br /&gt;
&lt;br /&gt;
At this point parameters can be set via &amp;lt;code&amp;gt;SetParameter&amp;lt;/code&amp;gt;, for example, setting up experiment parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.SetParameter(&amp;quot;DataDirectory&amp;quot;, &amp;quot;../data/theDirectory&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectName&amp;quot;, &amp;quot;APatient&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectSession&amp;quot;, &amp;quot;004&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also set values such as events to be shown in a graph view. &lt;br /&gt;
For example, since we set the source module to start with mouse logging enabled, we can view the values of the mouse position events.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We can also visualize the events we added earlier.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;condition&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;value1&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Collecting Data====&lt;br /&gt;
Start collecting data with the &amp;lt;code&amp;gt;Start()&amp;lt;/code&amp;gt; method. This will implicitly call &amp;lt;code&amp;gt;SetConfig()&amp;lt;/code&amp;gt;, but it can be called separately as well.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Start();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you instead want to start BCI2000 through the GUI, and wait for it in this program, you can instead wait for BCI2000 to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Running);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
During a run you can interact with BCI2000 by setting event variables:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.SetEvent(&amp;quot;value1&amp;quot;, 400);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also pulse events, setting their value for one sample duration before setting them back.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.PulseEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also get values from BCI2000. As we set the source module to log the mouse position earlier, we can retrieve its value via &amp;lt;code&amp;gt;GetEvent()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  uint mousePositionX = bci.GetEvent(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  uint mousePositionY = bci.GetEvent(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also retrieve the value of the hardware signal. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //Get value of element 2 of channel 1 of signal&lt;br /&gt;
  double signal11 = bci.GetSignal(1, 2);X&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Stopping BCI2000====&lt;br /&gt;
When you are finished collecting data, stop BCI2000 with the &amp;lt;code&amp;gt;BCI2000Connection.Stop()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.connection.Stop();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also shut down BCI2000.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.connection.Quit();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you instead want to stop BCI2000 via the GUI, you can wait for the system to be in the &amp;lt;code&amp;gt;Suspended&amp;lt;/code&amp;gt; state. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Connected);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you want to poll the system state repeatedly (in a loop, for example);&lt;br /&gt;
&amp;lt;pre&amp;gt;  &lt;br /&gt;
 bool loop = true;&lt;br /&gt;
  while (loop) {&lt;br /&gt;
    ...&lt;br /&gt;
    if (bci.GetSystemState() == BCI2000Remote.SystemState.Suspended) {&lt;br /&gt;
      loop = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
Embedding BCI2000RemoteNET within another program is largely covered above, so this section focuses on alternative usecases.&lt;br /&gt;
&lt;br /&gt;
====Using BCI2000RemoteNET as a substitute for BCI2000Shell====&lt;br /&gt;
BCI2000RemoteNET can be used as a replacement for BCI2000Shell when starting up BCI2000, if you need more advanced language capabilities than what the operator scripting language can provide.&lt;br /&gt;
&lt;br /&gt;
This is the existing startup script for the Stimulus Presentation task with the software Signal Generator.&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.bat&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#! ../prog/BCI2000Shell&lt;br /&gt;
@cls &amp;amp; ..\prog\BCI2000Shell %0 %* #! &amp;amp;&amp;amp; exit /b 0 || exit /b 1\n&lt;br /&gt;
Change directory $BCI2000LAUNCHDIR&lt;br /&gt;
Show window; Set title ${Extract file base $0}&lt;br /&gt;
Reset system&lt;br /&gt;
Startup system localhost&lt;br /&gt;
Start executable SignalGenerator --local --LogKeyboard=1 --SpinningWheel=1 --ShowDisplayStatistics=1&lt;br /&gt;
Start executable P3SignalProcessing --local&lt;br /&gt;
Start executable StimulusPresentation --local&lt;br /&gt;
Wait for Connected&lt;br /&gt;
Load parameterfile &amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the equivalent C# code using BCI2000RemoteNET:&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.cs&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
using BCI2000RemoteNET;&lt;br /&gt;
using System.RuntimeInformation.InteropServices;&lt;br /&gt;
BCI2000Remote bci = new(new BCI2000Connection());&lt;br /&gt;
bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);&lt;br /&gt;
bci.connection.StartOperator(&amp;quot;../prog/Operator&amp;quot; + isWindows ? &amp;quot;.exe&amp;quot; : &amp;quot;&amp;quot;); //Add file extension if on windows &lt;br /&gt;
bci.connection.Connect();&lt;br /&gt;
bci.LoadParameters(&amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;);&lt;br /&gt;
bci.StartupModules(new() {&lt;br /&gt;
	{&amp;quot;SignalGenerator&amp;quot;, new() {&amp;quot;LogKeyboard=1&amp;quot;, &amp;quot;SpinningWheel=1&amp;quot;, &amp;quot;ShowDisplayStatistics=1&amp;quot;}},&lt;br /&gt;
	{&amp;quot;P3SignalProcessing&amp;quot;, null}&lt;br /&gt;
	{&amp;quot;StimulusPresentation&amp;quot;, null}&lt;br /&gt;
	});&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
C# startup scripts have access to all of the constructs of the C# language, so different actions can be taken depending on conditions such as the operating system, as seen in the above script, or take other input such as command line options.&lt;br /&gt;
&lt;br /&gt;
This startup script can then be compiled to a .NET executable:&lt;br /&gt;
Windows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;csc.exe /r:&amp;quot;path/to/BCI2000RemoteNET.dll&amp;quot; StimulusPresentation_SignalGenerator.cs&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Non-Windows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;csc /r:&amp;quot;path/to/BCI2000RemoteNET.dll&amp;quot; StimulusPresentation_SignalGenerator.cs&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting executable can be run directly on Windows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;./StimulusPresentation_SignalGenerator.exe&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or via Mono on other platforms:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;mono ./StimulusPresentation_SignalGenerator.exe&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Note On Security==&lt;br /&gt;
The BCI2000 command line interface can be used to run arbitrary system shell commands. It is also entirely unsecured and unencrypted. Anyone who has access to it effectively has full access to the computer on which it runs. This is not a problem if running locally, and is generally not a problem if running on a firewalled local network. However, due to the unsecured nature of the interface, running BCI2000 across the internet is highly discouraged. That is, if you set BCI2000 to listen at an address of an external network interface, or to listen at all connections by passing the address &amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt;, make sure that port 3999 (or whichever port BCI2000 is listening on), is not forwarded beyond the local network by your router. Support for interfacing with BCI2000 over TLS is planned, so that safe connection can be made over the internet.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11334</id>
		<title>Contributions:BCI2000RemoteNET</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11334"/>
		<updated>2024-05-17T19:46:59Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Added example&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
BCI2000RemoteNET is a library for controlling BCI2000 from .NET programs such as Unity. With C# top-level declarations, it can also be used as a replacement for [[User Reference:BCI2000Shell]] with the added step of compilation via [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/ &amp;lt;code&amp;gt;csc&amp;lt;/code&amp;gt;]. &lt;br /&gt;
&lt;br /&gt;
==Operation==&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET communicates with the BCI2000 Operator via [[User Reference:Operator Module Scripting|operator module scripting commands]], which are sent as text over TCP to a running Operator. It also provides functionality for starting the Operator directly, so it can control the Operator entirely from startup to shutdown. &lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET consists of two classes, &amp;lt;code&amp;gt;BCI2000Connection&amp;lt;/code&amp;gt;, which provides the basic functionality necessary for starting and communicating with BCI2000, and &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt;, which provides a set of methods for controlling a BCI2000 experiment, such as interacting with parameters and events, as well as starting modules and experiments.&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET comes in two versions, targeting .NET 8.0 and .NET Standard 2.1. This is due to compatibility with programs such as Unity, which require .NET Standard binaries. There is little difference in functionality between the two versions, other than the behavior of the &amp;lt;code&amp;gt;Execute()&amp;lt;/code&amp;gt; method, whose differences are described below.&lt;br /&gt;
&lt;br /&gt;
==Documentation==&lt;br /&gt;
Documentation for the classes can be found here:&lt;br /&gt;
&lt;br /&gt;
====.NET 8.0====&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
====.NET Standard 2.1====&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Acquire the latest binary from [https://github.com/neurotechcenter/BCI2000RemoteNET GitHub], or build from source from the source code on GitHub or in the main BCI2000 Subversion repository (Keep in mind that the version in the Subversion repository will likely be behind the version on GitHub.)&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
====Starting the operator====&lt;br /&gt;
If you plan on starting the operator separately, skip this step, but make sure to start the operator with its &amp;lt;code&amp;gt;--Telnet&amp;lt;/code&amp;gt; option set.&lt;br /&gt;
&lt;br /&gt;
In order to start the operator, call the &amp;lt;code&amp;gt;BCI2000Connection.StartOperator&amp;lt;/code&amp;gt; method with the path to your BCI2000 Operator executable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
conn.StartOperator(&amp;quot;Path/To/BCI2000/prog/Operator.exe&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, this will start an operator listening on &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. You can also set the Operator to listen on another port:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, port: 51101);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you wish to accept connections from other computers you can set BCI2000 to listen on all addresses:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;0.0.0.0&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or listen on a specific network interface:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;10.11.198.2&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Connecting to the operator====&lt;br /&gt;
Connect to the operator with the &amp;lt;code&amp;gt;BCI2000Connection.Connect()&amp;lt;/code&amp;gt; method. If you started a local operator with default settings, then you can call &amp;lt;code&amp;gt;Connect&amp;lt;/code&amp;gt; with its default parameters, which will connect to the operator at &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. If you are connecting to an operator on another machine, say at IP address &amp;lt;code&amp;gt;11.11.11.11&amp;lt;/code&amp;gt;,or one listening on a port other than 3999, call &amp;lt;code&amp;gt;Connect()&amp;lt;/code&amp;gt; with its optional parameters.&lt;br /&gt;
Please see the [[#Note On Security]] for an important caveat of setting a non-default parameter here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator on the same machine on the default port.&lt;br /&gt;
conn.Connect();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator at address 11.11.11.11:3999&lt;br /&gt;
conn.Connect(address: &amp;quot;11.11.11.11&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Adding parameters and events====&lt;br /&gt;
At this point you can add parameters and events to BCI2000. &lt;br /&gt;
Parameters are values which can be changed in the BCI2000 GUI and can be used to change how experiments behave.&lt;br /&gt;
Parameters can either be loaded from a file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //path is relative to the Operator&#039;s working directory, that is, the /prog directory of the BCI2000 installation&lt;br /&gt;
  bci.LoadParameters(&amp;quot;path/to/parameterfile.prm&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
or added individually:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value 0 &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value &amp;quot;Green&amp;quot; &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param2&amp;quot;, &amp;quot;Green&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea2 section within the Application tab, with default value 0 and range 0-10&lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param3&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;10&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Events are values logged by BCI2000 alongside the signal data. They have a temporal resolution equivalent to the sample rate, and can be set and read throughout data collection.&lt;br /&gt;
Events are unsigned integers with a bit width between 1 and 32:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //An event called &amp;quot;condition&amp;quot; representing a boolean value with possible values 0 and 1. Will be zero by default.&lt;br /&gt;
  bci.AddEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
  //An 32-bit event with default value 100, and range 0 to 2^32 - 1.&lt;br /&gt;
  bci.AddEvent(&amp;quot;value1&amp;quot;, 32, 100);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Starting BCI2000 Modules====&lt;br /&gt;
BCI2000 modules are started using the &amp;lt;code&amp;gt;StartModules()&amp;lt;/code&amp;gt; method, given a dictionary of module names and argument lists. For example, to open SignalGenerator, DummySignalProcessing, and DummyApplication with keyboard and mouse logging:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bci.StartupModules(new Dictionary&amp;lt;string, List&amp;lt;string&amp;gt;?&amp;gt;()&lt;br /&gt;
  {&lt;br /&gt;
    {&amp;quot;SignalGenerator&amp;quot;, new List&amp;lt;string&amp;gt;() {&amp;quot;LogKeyboard=1&amp;quot;, &amp;quot;LogMouse=1&amp;quot;}},&lt;br /&gt;
    {&amp;quot;DummySignalProcessing&amp;quot;, null},&lt;br /&gt;
    {&amp;quot;DummyApplication&amp;quot;, null}&lt;br /&gt;
  });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Setting Parameters and Visualizing Values====&lt;br /&gt;
If using BCI2000RemoteNET as a substitute for BCI2000Shell for setting up the basic environment, this would usually be where you continue using BCI2000 through its own GUI.&lt;br /&gt;
&lt;br /&gt;
At this point parameters can be set via &amp;lt;code&amp;gt;SetParameter&amp;lt;/code&amp;gt;, for example, setting up experiment parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.SetParameter(&amp;quot;DataDirectory&amp;quot;, &amp;quot;../data/theDirectory&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectName&amp;quot;, &amp;quot;APatient&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectSession&amp;quot;, &amp;quot;004&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also set values such as events to be shown in a graph view. &lt;br /&gt;
For example, since we set the source module to start with mouse logging enabled, we can view the values of the mouse position events.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We can also visualize the events we added earlier.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;condition&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;value1&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Collecting Data====&lt;br /&gt;
Start collecting data with the &amp;lt;code&amp;gt;Start()&amp;lt;/code&amp;gt; method. This will implicitly call &amp;lt;code&amp;gt;SetConfig()&amp;lt;/code&amp;gt;, but it can be called separately as well.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Start();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you instead want to start BCI2000 through the GUI, and wait for it in this program, you can instead wait for BCI2000 to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Running);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
During a run you can interact with BCI2000 by setting event variables:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.SetEvent(&amp;quot;value1&amp;quot;, 400);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also pulse events, setting their value for one sample duration before setting them back.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.PulseEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also get values from BCI2000. As we set the source module to log the mouse position earlier, we can retrieve its value via &amp;lt;code&amp;gt;GetEvent()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  uint mousePositionX = bci.GetEvent(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  uint mousePositionY = bci.GetEvent(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also retrieve the value of the hardware signal. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //Get value of element 2 of channel 1 of signal&lt;br /&gt;
  double signal11 = bci.GetSignal(1, 2);X&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Stopping BCI2000====&lt;br /&gt;
When you are finished collecting data, stop BCI2000 with the &amp;lt;code&amp;gt;BCI2000Connection.Stop()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.connection.Stop();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also shut down BCI2000.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.connection.Quit();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you instead want to stop BCI2000 via the GUI, you can wait for the system to be in the &amp;lt;code&amp;gt;Suspended&amp;lt;/code&amp;gt; state. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Connected);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you want to poll the system state repeatedly (in a loop, for example);&lt;br /&gt;
&amp;lt;pre&amp;gt;  &lt;br /&gt;
 bool loop = true;&lt;br /&gt;
  while (loop) {&lt;br /&gt;
    ...&lt;br /&gt;
    if (bci.GetSystemState() == BCI2000Remote.SystemState.Suspended) {&lt;br /&gt;
      loop = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
Embedding BCI2000RemoteNET within another program is largely covered above, so this section focuses on alternative usecases.&lt;br /&gt;
&lt;br /&gt;
====Using BCI2000RemoteNET as a substitute for BCI2000Shell====&lt;br /&gt;
BCI2000RemoteNET can be used as a replacement for BCI2000Shell when starting up BCI2000, if you need more advanced language capabilities than what the operator scripting language can provide.&lt;br /&gt;
&lt;br /&gt;
This is the existing startup script for the Stimulus Presentation task with the software Signal Generator.&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.bat&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#! ../prog/BCI2000Shell&lt;br /&gt;
@cls &amp;amp; ..\prog\BCI2000Shell %0 %* #! &amp;amp;&amp;amp; exit /b 0 || exit /b 1\n&lt;br /&gt;
Change directory $BCI2000LAUNCHDIR&lt;br /&gt;
Show window; Set title ${Extract file base $0}&lt;br /&gt;
Reset system&lt;br /&gt;
Startup system localhost&lt;br /&gt;
Start executable SignalGenerator --local --LogKeyboard=1 --SpinningWheel=1 --ShowDisplayStatistics=1&lt;br /&gt;
Start executable P3SignalProcessing --local&lt;br /&gt;
Start executable StimulusPresentation --local&lt;br /&gt;
Wait for Connected&lt;br /&gt;
Load parameterfile &amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the equivalent C# code using BCI2000RemoteNET:&lt;br /&gt;
&amp;lt;pre&amp;gt;/batch/StimulusPresentation_SignalGenerator.cs&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
using BCI2000RemoteNET;&lt;br /&gt;
using System.RuntimeInformation.InteropServices;&lt;br /&gt;
BCI2000Remote bci = new(new BCI2000Connection());&lt;br /&gt;
bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);&lt;br /&gt;
bci.connection.StartOperator(&amp;quot;../prog/Operator&amp;quot; + isWindows ? &amp;quot;.exe&amp;quot; : &amp;quot;&amp;quot;); //Add file extension if on windows &lt;br /&gt;
bci.connection.Connect();&lt;br /&gt;
bci.LoadParameters(&amp;quot;../parms/examples/StimulusPresentation_SignalGenerator.prm&amp;quot;);&lt;br /&gt;
bci.StartupModules(new() {&lt;br /&gt;
	{&amp;quot;SignalGenerator&amp;quot;, new() {&amp;quot;LogKeyboard=1&amp;quot;, &amp;quot;SpinningWheel=1&amp;quot;, &amp;quot;ShowDisplayStatistics=1&amp;quot;}},&lt;br /&gt;
	{&amp;quot;P3SignalProcessing&amp;quot;, null}&lt;br /&gt;
	{&amp;quot;StimulusPresentation&amp;quot;, null}&lt;br /&gt;
	});&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
C# startup scripts have access to all of the constructs of the C# language, so different actions can be taken depending on conditions such as the operating system, as seen in the above script, or take other input such as command line options.&lt;br /&gt;
&lt;br /&gt;
This startup script can then be compiled to a .NET executable:&lt;br /&gt;
Windows:&lt;br /&gt;
&amp;lt;code&amp;gt;csc.exe /r:&amp;quot;path/to/BCI2000RemoteNET.dll&amp;quot; StimulusPresentation_SignalGenerator.cs&amp;lt;/code&amp;gt;&lt;br /&gt;
Non-Windows:&lt;br /&gt;
&amp;lt;/code&amp;gt;csc /r:&amp;quot;path/to/BCI2000RemoteNET.dll&amp;quot; StimulusPresentation_SignalGenerator.cs&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting executable can be run directly on Windows:&lt;br /&gt;
&amp;lt;code&amp;gt;./StimulusPresentation_SignalGenerator.exe&amp;lt;/code&amp;gt;&lt;br /&gt;
or via Mono on other platforms:&lt;br /&gt;
&amp;lt;code&amp;gt;mono ./StimulusPresentation_SignalGenerator.exe&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Note On Security==&lt;br /&gt;
The BCI2000 command line interface can be used to run arbitrary system shell commands. It is also entirely unsecured and unencrypted. Anyone who has access to it effectively has full access to the computer on which it runs. This is not a problem if running locally, and is generally not a problem if running on a firewalled local network. However, due to the unsecured nature of the interface, running BCI2000 across the internet is highly discouraged. That is, if you set BCI2000 to listen at an address of an external network interface, or to listen at all connections by passing the address &amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt;, make sure that port 3999 (or whichever port BCI2000 is listening on), is not forwarded beyond the local network by your router. Support for interfacing with BCI2000 over TLS is planned, so that safe connection can be made over the internet.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11333</id>
		<title>Contributions:BCI2000RemoteNET</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11333"/>
		<updated>2024-05-17T19:13:09Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Fixed formatting&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
BCI2000RemoteNET is a library for controlling BCI2000 from .NET programs such as Unity. With C# top-level declarations, it can also be used as a replacement for [[User Reference:BCI2000Shell]] with the added step of compilation via [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/ &amp;lt;code&amp;gt;csc&amp;lt;/code&amp;gt;]. &lt;br /&gt;
&lt;br /&gt;
==Operation==&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET communicates with the BCI2000 Operator via [[User Reference:Operator Module Scripting|operator module scripting commands]], which are sent as text over TCP to a running Operator. It also provides functionality for starting the Operator directly, so it can control the Operator entirely from startup to shutdown. &lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET consists of two classes, &amp;lt;code&amp;gt;BCI2000Connection&amp;lt;/code&amp;gt;, which provides the basic functionality necessary for starting and communicating with BCI2000, and &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt;, which provides a set of methods for controlling a BCI2000 experiment, such as interacting with parameters and events, as well as starting modules and experiments.&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET comes in two versions, targeting .NET 8.0 and .NET Standard 2.1. This is due to compatibility with programs such as Unity, which require .NET Standard binaries. There is little difference in functionality between the two versions, other than the behavior of the &amp;lt;code&amp;gt;Execute()&amp;lt;/code&amp;gt; method, whose differences are described below.&lt;br /&gt;
&lt;br /&gt;
==Documentation==&lt;br /&gt;
Documentation for the classes can be found here:&lt;br /&gt;
&lt;br /&gt;
====.NET 8.0====&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
====.NET Standard 2.1====&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
&lt;br /&gt;
[https://bci2000.org/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Acquire the latest binary from [https://github.com/neurotechcenter/BCI2000RemoteNET GitHub], or build from source from the source code on GitHub or in the main BCI2000 Subversion repository (Keep in mind that the version in the Subversion repository will likely be behind the version on GitHub.)&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
====Starting the operator====&lt;br /&gt;
If you plan on starting the operator separately, skip this step, but make sure to start the operator with its &amp;lt;code&amp;gt;--Telnet&amp;lt;/code&amp;gt; option set.&lt;br /&gt;
&lt;br /&gt;
In order to start the operator, call the &amp;lt;code&amp;gt;BCI2000Connection.StartOperator&amp;lt;/code&amp;gt; method with the path to your BCI2000 Operator executable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
conn.StartOperator(&amp;quot;Path/To/BCI2000/prog/Operator.exe&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, this will start an operator listening on &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. You can also set the Operator to listen on another port:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, port: 51101);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you wish to accept connections from other computers you can set BCI2000 to listen on all addresses:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;0.0.0.0&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or listen on a specific network interface:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;10.11.198.2&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Connecting to the operator====&lt;br /&gt;
Connect to the operator with the &amp;lt;code&amp;gt;BCI2000Connection.Connect()&amp;lt;/code&amp;gt; method. If you started a local operator with default settings, then you can call &amp;lt;code&amp;gt;Connect&amp;lt;/code&amp;gt; with its default parameters, which will connect to the operator at &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. If you are connecting to an operator on another machine, say at IP address &amp;lt;code&amp;gt;11.11.11.11&amp;lt;/code&amp;gt;,or one listening on a port other than 3999, call &amp;lt;code&amp;gt;Connect()&amp;lt;/code&amp;gt; with its optional parameters.&lt;br /&gt;
Please see the [[#Note On Security]] for an important caveat of setting a non-default parameter here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator on the same machine on the default port.&lt;br /&gt;
conn.Connect();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator at address 11.11.11.11:3999&lt;br /&gt;
conn.Connect(address: &amp;quot;11.11.11.11&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Adding parameters and events====&lt;br /&gt;
At this point you can add parameters and events to BCI2000. &lt;br /&gt;
Parameters are values which can be changed in the BCI2000 GUI and can be used to change how experiments behave.&lt;br /&gt;
Parameters can either be loaded from a file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //path is relative to the Operator&#039;s working directory, that is, the /prog directory of the BCI2000 installation&lt;br /&gt;
  bci.LoadParameters(&amp;quot;path/to/parameterfile.prm&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
or added individually:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value 0 &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value &amp;quot;Green&amp;quot; &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param2&amp;quot;, &amp;quot;Green&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea2 section within the Application tab, with default value 0 and range 0-10&lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param3&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;10&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Events are values logged by BCI2000 alongside the signal data. They have a temporal resolution equivalent to the sample rate, and can be set and read throughout data collection.&lt;br /&gt;
Events are unsigned integers with a bit width between 1 and 32:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //An event called &amp;quot;condition&amp;quot; representing a boolean value with possible values 0 and 1. Will be zero by default.&lt;br /&gt;
  bci.AddEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
  //An 32-bit event with default value 100, and range 0 to 2^32 - 1.&lt;br /&gt;
  bci.AddEvent(&amp;quot;value1&amp;quot;, 32, 100);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Starting BCI2000 Modules====&lt;br /&gt;
BCI2000 modules are started using the &amp;lt;code&amp;gt;StartModules()&amp;lt;/code&amp;gt; method, given a dictionary of module names and argument lists. For example, to open SignalGenerator, DummySignalProcessing, and DummyApplication with keyboard and mouse logging:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bci.StartupModules(new Dictionary&amp;lt;string, List&amp;lt;string&amp;gt;?&amp;gt;()&lt;br /&gt;
  {&lt;br /&gt;
    {&amp;quot;SignalGenerator&amp;quot;, new List&amp;lt;string&amp;gt;() {&amp;quot;LogKeyboard=1&amp;quot;, &amp;quot;LogMouse=1&amp;quot;}},&lt;br /&gt;
    {&amp;quot;DummySignalProcessing&amp;quot;, null},&lt;br /&gt;
    {&amp;quot;DummyApplication&amp;quot;, null}&lt;br /&gt;
  });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Setting Parameters and Visualizing Values====&lt;br /&gt;
If using BCI2000RemoteNET as a substitute for BCI2000Shell for setting up the basic environment, this would usually be where you continue using BCI2000 through its own GUI.&lt;br /&gt;
&lt;br /&gt;
At this point parameters can be set via &amp;lt;code&amp;gt;SetParameter&amp;lt;/code&amp;gt;, for example, setting up experiment parameters:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.SetParameter(&amp;quot;DataDirectory&amp;quot;, &amp;quot;../data/theDirectory&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectName&amp;quot;, &amp;quot;APatient&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectSession&amp;quot;, &amp;quot;004&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also set values such as events to be shown in a graph view. &lt;br /&gt;
For example, since we set the source module to start with mouse logging enabled, we can view the values of the mouse position events.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We can also visualize the events we added earlier.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;condition&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;value1&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Collecting Data====&lt;br /&gt;
Start collecting data with the &amp;lt;code&amp;gt;Start()&amp;lt;/code&amp;gt; method. This will implicitly call &amp;lt;code&amp;gt;SetConfig()&amp;lt;/code&amp;gt;, but it can be called separately as well.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.Start();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you instead want to start BCI2000 through the GUI, and wait for it in this program, you can instead wait for BCI2000 to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Running);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
During a run you can interact with BCI2000 by setting event variables:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.SetEvent(&amp;quot;value1&amp;quot;, 400);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also pulse events, setting their value for one sample duration before setting them back.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.PulseEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also get values from BCI2000. As we set the source module to log the mouse position earlier, we can retrieve its value via &amp;lt;code&amp;gt;GetEvent()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  uint mousePositionX = bci.GetEvent(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  uint mousePositionY = bci.GetEvent(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also retrieve the value of the hardware signal. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  //Get value of element 2 of channel 1 of signal&lt;br /&gt;
  double signal11 = bci.GetSignal(1, 2);X&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Stopping BCI2000====&lt;br /&gt;
When you are finished collecting data, stop BCI2000 with the &amp;lt;code&amp;gt;BCI2000Connection.Stop()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.connection.Stop();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also shut down BCI2000.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.connection.Quit();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you instead want to stop BCI2000 via the GUI, you can wait for the system to be in the &amp;lt;code&amp;gt;Suspended&amp;lt;/code&amp;gt; state. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Connected);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you want to poll the system state repeatedly (in a loop, for example);&lt;br /&gt;
&amp;lt;pre&amp;gt;  &lt;br /&gt;
 bool loop = true;&lt;br /&gt;
  while (loop) {&lt;br /&gt;
    ...&lt;br /&gt;
    if (bci.GetSystemState() == BCI2000Remote.SystemState.Suspended) {&lt;br /&gt;
      loop = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Note On Security==&lt;br /&gt;
The BCI2000 command line interface can be used to run arbitrary system shell commands. It is also entirely unsecured and unencrypted. Anyone who has access to it effectively has full access to the computer on which it runs. This is not a problem if running locally, and is generally not a problem if running on a firewalled local network. However, due to the unsecured nature of the interface, running BCI2000 across the internet is highly discouraged. That is, if you set BCI2000 to listen at an address of an external network interface, or to listen at all connections by passing the address &amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt;, make sure that port 3999 (or whichever port BCI2000 is listening on), is not forwarded beyond the local network by your router. Support for interfacing with BCI2000 over TLS is planned, so that safe connection can be made over the internet.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11332</id>
		<title>Contributions:BCI2000RemoteNET</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=11332"/>
		<updated>2024-05-17T19:03:17Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: New version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
BCI2000RemoteNET is a library for controlling BCI2000 from .NET programs such as Unity. With C# top-level declarations, it can also be used as a replacement for [[User Reference:BCI2000Shell]] with the added step of compilation via [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/ &amp;lt;code&amp;gt;csc&amp;lt;/code&amp;gt;]. &lt;br /&gt;
&lt;br /&gt;
==Operation==&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET communicates with the BCI2000 Operator via [[User Reference:Operator Module Scripting|operator module scripting commands]], which are sent as text over TCP to a running Operator. It also provides functionality for starting the Operator directly, so it can control the Operator entirely from startup to shutdown. &lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET consists of two classes, &amp;lt;code&amp;gt;BCI2000Connection&amp;lt;/code&amp;gt;, which provides the basic functionality necessary for starting and communicating with BCI2000, and &amp;lt;code&amp;gt;BCI2000Remote&amp;lt;/code&amp;gt;, which provides a set of methods for controlling a BCI2000 experiment, such as interacting with parameters and events, as well as starting modules and experiments.&lt;br /&gt;
&lt;br /&gt;
BCI2000RemoteNET comes in two versions, targeting .NET 8.0 and .NET Standard 2.1. This is due to compatibility with programs such as Unity, which require .NET Standard binaries. There is little difference in functionality between the two versions, other than the behavior of the &amp;lt;code&amp;gt;Execute()&amp;lt;/code&amp;gt; method, whose differences are described below.&lt;br /&gt;
&lt;br /&gt;
==Documentation==&lt;br /&gt;
Documentation for the classes can be found here:&lt;br /&gt;
&lt;br /&gt;
====.NET 8.0====&lt;br /&gt;
[{{hostname}}/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
[{{hostname}}/BCI2000RemoteNET/net8/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
====.NET Standard 2.1====&lt;br /&gt;
[{{hostname}}/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Connection.html BCI2000Connection]&lt;br /&gt;
[{{hostname}}/BCI2000RemoteNET/netstandard2/classBCI2000RemoteNET_1_1BCI2000Remote.html BCI2000Remote]&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Acquire the latest binary from [https://github.com/neurotechcenter/BCI2000RemoteNET GitHub], or build from source from the source code on GitHub or in the main BCI2000 Subversion repository (Keep in mind that the version in the Subversion repository will likely be behind the version on GitHub.)&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
====Starting the operator====&lt;br /&gt;
If you plan on starting the operator separately, skip this step, but make sure to start the operator with its &amp;lt;code&amp;gt;--Telnet&amp;lt;/code&amp;gt; option set.&lt;br /&gt;
&lt;br /&gt;
In order to start the operator, call the &amp;lt;code&amp;gt;BCI2000Connection.StartOperator&amp;lt;/code&amp;gt; method with the path to your BCI2000 Operator executable.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
conn.StartOperator(&amp;quot;Path/To/BCI2000/prog/Operator.exe&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default, this will start an operator listening on &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. You can also set the Operator to listen on another port:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, port: 51101);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you wish to accept connections from other computers you can set BCI2000 to listen on all addresses:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;0.0.0.0&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or listen on a specific network interface:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
conn.StartOperator(&amp;quot;path&amp;quot;, address: &amp;quot;10.11.198.2&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Connecting to the operator====&lt;br /&gt;
Connect to the operator with the &amp;lt;code&amp;gt;BCI2000Connection.Connect()&amp;lt;/code&amp;gt; method. If you started a local operator with default settings, then you can call &amp;lt;code&amp;gt;Connect&amp;lt;/code&amp;gt; with its default parameters, which will connect to the operator at &amp;lt;code&amp;gt;127.0.0.1:3999&amp;lt;/code&amp;gt;. If you are connecting to an operator on another machine, say at IP address &amp;lt;code&amp;gt;11.11.11.11&amp;lt;/code&amp;gt;,or one listening on a port other than 3999, call &amp;lt;code&amp;gt;Connect()&amp;lt;/code&amp;gt; with its optional parameters.&lt;br /&gt;
Please see the [[#Note On Security]] for an important caveat of setting a non-default parameter here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
BCI2000Connection conn = new BCI2000Connection();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator on the same machine on the default port.&lt;br /&gt;
conn.Connect();&lt;br /&gt;
&lt;br /&gt;
//Connect to operator at address 11.11.11.11:3999&lt;br /&gt;
conn.Connect(address: &amp;quot;11.11.11.11&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Adding parameters and events====&lt;br /&gt;
At this point you can add parameters and events to BCI2000. &lt;br /&gt;
Parameters are values which can be changed in the BCI2000 GUI and can be used to change how experiments behave.&lt;br /&gt;
Parameters can either be loaded from a file:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  //path is relative to the Operator&#039;s working directory, that is, the /prog directory of the BCI2000 installation&lt;br /&gt;
  bci.LoadParameters(&amp;quot;path/to/parameterfile.prm&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
or added individually:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value 0 &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea section within the Application tab, with default value &amp;quot;Green&amp;quot; &lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param2&amp;quot;, &amp;quot;Green&amp;quot;);&lt;br /&gt;
  //Parameter in the ParamArea2 section within the Application tab, with default value 0 and range 0-10&lt;br /&gt;
  bci.AddParameter(&amp;quot;Application:ParamArea&amp;quot;, &amp;quot;Param3&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;10&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Events are values logged by BCI2000 alongside the signal data. They have a temporal resolution equivalent to the sample rate, and can be set and read throughout data collection.&lt;br /&gt;
Events are unsigned integers with a bit width between 1 and 32:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  //An event called &amp;quot;condition&amp;quot; representing a boolean value with possible values 0 and 1. Will be zero by default.&lt;br /&gt;
  bci.AddEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
  //An 32-bit event with default value 100, and range 0 to 2^32 - 1.&lt;br /&gt;
  bci.AddEvent(&amp;quot;value1&amp;quot;, 32, 100);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Starting BCI2000 Modules====&lt;br /&gt;
BCI2000 modules are started using the &amp;lt;code&amp;gt;StartModules()&amp;lt;/code&amp;gt; method, given a dictionary of module names and argument lists. For example, to open SignalGenerator, DummySignalProcessing, and DummyApplication with keyboard and mouse logging:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
bci.StartupModules(new Dictionary&amp;lt;string, List&amp;lt;string&amp;gt;?&amp;gt;()&lt;br /&gt;
  {&lt;br /&gt;
    {&amp;quot;SignalGenerator&amp;quot;, new List&amp;lt;string&amp;gt;() {&amp;quot;LogKeyboard=1&amp;quot;, &amp;quot;LogMouse=1&amp;quot;}},&lt;br /&gt;
    {&amp;quot;DummySignalProcessing&amp;quot;, null},&lt;br /&gt;
    {&amp;quot;DummyApplication&amp;quot;, null}&lt;br /&gt;
  });&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Setting Parameters and Visualizing Values====&lt;br /&gt;
If using BCI2000RemoteNET as a substitute for BCI2000Shell for setting up the basic environment, this would usually be where you continue using BCI2000 through its own GUI.&lt;br /&gt;
&lt;br /&gt;
At this point parameters can be set via &amp;lt;code&amp;gt;SetParameter&amp;lt;/code&amp;gt;, for example, setting up experiment parameters:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  bci.SetParameter(&amp;quot;DataDirectory&amp;quot;, &amp;quot;../data/theDirectory&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectName&amp;quot;, &amp;quot;APatient&amp;quot;);&lt;br /&gt;
  bci.SetParameter(&amp;quot;SubjectSession&amp;quot;, &amp;quot;004&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also set values such as events to be shown in a graph view. &lt;br /&gt;
For example, since we set the source module to start with mouse logging enabled, we can view the values of the mouse position events.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We can also visualize the events we added earlier.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  bci.Visualize(&amp;quot;condition&amp;quot;);&lt;br /&gt;
  bci.Visualize(&amp;quot;value1&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Collecting Data====&lt;br /&gt;
Start collecting data with the &amp;lt;code&amp;gt;Start()&amp;lt;/code&amp;gt; method. This will implicitly call &amp;lt;code&amp;gt;SetConfig()&amp;lt;/code&amp;gt;, but it can be called separately as well.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  bci.Start();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If you instead want to start BCI2000 through the GUI, and wait for it in this program, you can instead wait for BCI2000 to be in the &amp;lt;code&amp;gt;Running&amp;lt;/code&amp;gt; state.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Running);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
During a run you can interact with BCI2000 by setting event variables:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  bci.SetEvent(&amp;quot;value1&amp;quot;, 400);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also pulse events, setting their value for one sample duration before setting them back.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  bci.PulseEvent(&amp;quot;condition&amp;quot;, 1);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also get values from BCI2000. As we set the source module to log the mouse position earlier, we can retrieve its value via &amp;lt;code&amp;gt;GetEvent()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  uint mousePositionX = bci.GetEvent(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
  uint mousePositionY = bci.GetEvent(&amp;quot;MousePosY&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also retrieve the value of the hardware signal. &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  //Get value of element 2 of channel 1 of signal&lt;br /&gt;
  double signal11 = bci.GetSignal(1, 2);X&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Stopping BCI2000====&lt;br /&gt;
When you are finished collecting data, stop BCI2000 with the &amp;lt;code&amp;gt;BCI2000Connection.Stop()&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  bci.connection.Stop();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also shut down BCI2000.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  bci.connection.Quit();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you instead want to stop BCI2000 via the GUI, you can wait for the system to be in the &amp;lt;code&amp;gt;Suspended&amp;lt;/code&amp;gt; state. &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  bci.WaitForSystemState(BCI2000Remote.SystemState.Connected);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you want to poll the system state repeatedly (in a loop, for example);&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
bool loop = true;&lt;br /&gt;
while (loop) {&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if (bci.GetSystemState() == BCI2000Remote.SystemState.Suspended) {&lt;br /&gt;
    loop = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Note On Security==&lt;br /&gt;
The BCI2000 command line interface can be used to run arbitrary system shell commands. It is also entirely unsecured and unencrypted. Anyone who has access to it effectively has full access to the computer on which it runs. This is not a problem if running locally, and is generally not a problem if running on a firewalled local network. However, due to the unsecured nature of the interface, running BCI2000 across the internet is highly discouraged. That is, if you set BCI2000 to listen at an address of an external network interface, or to listen at all connections by passing the address &amp;lt;code&amp;gt;0.0.0.0&amp;lt;/code&amp;gt;, make sure that port 3999 (or whichever port BCI2000 is listening on), is not forwarded beyond the local network by your router. Support for interfacing with BCI2000 over TLS is planned, so that safe connection can be made over the internet.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=11256</id>
		<title>Contributions:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=11256"/>
		<updated>2024-04-16T17:34:23Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Initial writing of the new UnityBCI2000 page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
UnityBCI2000 is an extension for the Unity game/3D application development platform that enables control of and communication with the BCI2000 brain-computer interface research platform. It consists of a .NET library for communication with the BCI2000 operator and a Unity package which provides integration with Unity itself.&lt;br /&gt;
&lt;br /&gt;
==Prerequisites==&lt;br /&gt;
Alongside UnityBCI2000, install Unity per the instructions at [https://unity.com/download the Unity website], and the [BCI2000 setup tutorial https://www.bci2000.org/mediawiki/index.php/Programming_Howto:Install_Prerequisites].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Documentation==&lt;br /&gt;
[https://bci2000.org/BCI2000Unity/classUnityBCI2000.html Interface documentation]&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000Unity_OUTDATED&amp;diff=11255</id>
		<title>Contributions:BCI2000Unity OUTDATED</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000Unity_OUTDATED&amp;diff=11255"/>
		<updated>2024-04-16T17:14:43Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Delisted old version of the UnityBCI2000 page. New version located at Contributions:UnityBCI2000&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOINDEX__&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
Unity is a cross-platform game engine with support for desktop, mobile, console, and virtual reality platforms. It is both easy for beginners to use and is popular for low-cost game development. This is a Unity package which integrates BCI2000.&lt;br /&gt;
&lt;br /&gt;
==Prerequisites==&lt;br /&gt;
&lt;br /&gt;
UnityBCI2000 depends on the BCI2000RemoteNET library, located at&lt;br /&gt;
[https://github.com/neurotechcenter/BCI2000RemoteNET Github] or [https://www.nuget.org/packages/BCI2000RemoteNET NuGet]).&lt;br /&gt;
Keep in mind that at the moment both BCI2000RemoteNET and BCI2000Unity are not fully released, and are still in development, so features and API structure are subject to change at any time, and bugs are to be expected.&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
&lt;br /&gt;
Add the `UnityBCI2000.cs` script to one `GameObject`. This is the central script which communicates with BCI2000.  &lt;br /&gt;
Add the `BCI2000StateSender` to any object which you want to monitor with BCI2000.  &lt;br /&gt;
Before starting, you must set the operator and modules to start up, by specifying the fields&lt;br /&gt;
`OperatorPath` and `Module[1-3]`. All other properties have default settings and will function without change.  &lt;br /&gt;
Alternatively, if you leave `OperatorPath` blank, `BCI2000Remote` will attempt to connect to an operator at&lt;br /&gt;
`TelnetIp:TelnetPort`. This is useful for if you already have an operator open that you want to use.  &lt;br /&gt;
If you also have modules started within a running BCI2000 instance, set `DontStartModules` to `true`, this will preserve&lt;br /&gt;
your running modules.&lt;br /&gt;
&lt;br /&gt;
===Using built-in variables===&lt;br /&gt;
&lt;br /&gt;
`BCI2000StateSender` has some variables built in. To use these, just select their check boxes in the inspector.&lt;br /&gt;
&lt;br /&gt;
===Adding custom variables===&lt;br /&gt;
&lt;br /&gt;
To add custom variables,  add a script to the same object as a `BCI2000StateSender`, which inherits from `CustomVariableBase`.  &lt;br /&gt;
Then, add the `CustomVariableBase` to the &amp;quot;Custom Variable Supplier&amp;quot; field of the `BCI2000StateSender`.&lt;br /&gt;
Then, add `CustomVariable`s to the list `customVariables` within the `CustomVariableBase`. There are some included&lt;br /&gt;
templates and snippets which show the syntax for adding custom variables.&lt;br /&gt;
&lt;br /&gt;
===Custom Variables===&lt;br /&gt;
&lt;br /&gt;
A custom variable has four fields. These are its name, value, scale, and type.  &lt;br /&gt;
Its name is a string which holds its name.  &lt;br /&gt;
Its value is a `Func&amp;lt;float&amp;gt;` delegate which returns a float, which will be sent to BCI2000, after being multiplied by its scale.  &lt;br /&gt;
Its type is a member of the enum `UnityBCI2000.StateType`, which represents the format of the number being sent to BCI2000.&lt;br /&gt;
&lt;br /&gt;
===Custom Variable Class Example===&lt;br /&gt;
&lt;br /&gt;
Template&lt;br /&gt;
&lt;br /&gt;
    public class &amp;lt;ClassName&amp;gt; : CustomVariableBase&lt;br /&gt;
    {&lt;br /&gt;
        public override void AddCustomVariables()&lt;br /&gt;
        {&lt;br /&gt;
            customVariables.Add(new CustomSetVariable(  //Copy this for more set variables&lt;br /&gt;
                &amp;quot;[Name]&amp;quot;,&lt;br /&gt;
                new Func&amp;lt;float&amp;gt;(() =&amp;gt; [Code which returns variable to send]),&lt;br /&gt;
                [Scale],&lt;br /&gt;
                UnityBCI2000.StateType.[Type]&lt;br /&gt;
                ));&lt;br /&gt;
                &lt;br /&gt;
            customVariables.Add(new CustomGetVariable(  //Copy this for more get variables&lt;br /&gt;
                &amp;quot;[Name]&amp;quot;,  &lt;br /&gt;
                new Action&amp;lt;int&amp;gt; ((int i) =&amp;gt; [Code which uses i])&lt;br /&gt;
            ));&lt;br /&gt;
&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Example&lt;br /&gt;
&lt;br /&gt;
    public class CustomVariableSupplier1 : CustomVariableBase&lt;br /&gt;
    {&lt;br /&gt;
        public override void AddCustomVariables() &lt;br /&gt;
        {&lt;br /&gt;
            customVariables.Add(new CustomSetVariable(&lt;br /&gt;
                &amp;quot;Custom variable 1&amp;quot;,&lt;br /&gt;
                new Func&amp;lt;float&amp;gt;(() =&amp;gt; {return 65 / 5;}),&lt;br /&gt;
                100,&lt;br /&gt;
                UnityBCI2000.StateType.SignedInt16&lt;br /&gt;
                ));&lt;br /&gt;
            customVariables.Add(new CustomSetVariable(&lt;br /&gt;
                &amp;quot;Custom variable 2: Frame count&amp;quot;,&lt;br /&gt;
                new Func&amp;lt;float&amp;gt;(() =&amp;gt; Time.frameCount),&lt;br /&gt;
                1,&lt;br /&gt;
                UnityBCI2000.StateType.UnsignedInt32&lt;br /&gt;
                ));&lt;br /&gt;
            customVariables.Add(new CustomGetVariable(  &lt;br /&gt;
                &amp;quot;StateName&amp;quot;,  &lt;br /&gt;
                new Action&amp;lt;int&amp;gt; ((int i) =&amp;gt; {score = i})&lt;br /&gt;
            ));&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
===Number Formats===&lt;br /&gt;
&lt;br /&gt;
The available formats are found in the enum `UnityBCI2000.StateType`. As they are being accessed outside of `UnityBCI2000`, &lt;br /&gt;
they will always be preceded by &amp;quot;UnityBCI2000.&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The formats are `Boolean`, `UnsignedInt16`, `UnsignedInt32`, `SignedInt16`, and `SignedInt32`.  &lt;br /&gt;
These are available formats because BCI2000 takes state values in the form of unsigned integers with a bit width of powers of 2 between 1 and 32.  &lt;br /&gt;
Boolean is the same as an unsigned int of bit width 1.  &lt;br /&gt;
Signed numbers will generate a second state within BCI2000 of bit width 1, which holds their sign. If they are negative, their sign will be 1,&lt;br /&gt;
and if they are positive, their sign will be 0. Use signed numbers if your value will ever be negative.&lt;br /&gt;
&lt;br /&gt;
===Other scripting===&lt;br /&gt;
&lt;br /&gt;
Try to avoid calling any of the methods directly. UnityBCI2000 should ideally be able to run and control BCI2000 without any intervention.&lt;br /&gt;
&lt;br /&gt;
==Properties==&lt;br /&gt;
&lt;br /&gt;
===UnityBCI2000===&lt;br /&gt;
&lt;br /&gt;
`Timeout`&lt;br /&gt;
The timeout, in milliseconds, for sending and receiving commands, default 1000.&lt;br /&gt;
&lt;br /&gt;
`TelnetIP`&lt;br /&gt;
The IP at which to connect to the Operator, default 127.0.0.1&lt;br /&gt;
Note: Don&#039;t use &amp;quot;localhost&amp;quot; when setting this, as this causes errors due to ambiguity in name resolution.&lt;br /&gt;
&lt;br /&gt;
`TelnetPort`&lt;br /&gt;
The port to connect to the Operator, default 3999.&lt;br /&gt;
&lt;br /&gt;
`OperatorPath`&lt;br /&gt;
The path to the Operator module to start up when there is no running operator at the IP and port specified, will always connect on localhost, at the previously given port.&lt;br /&gt;
&lt;br /&gt;
`LogFile`&lt;br /&gt;
The path to the file to write the log. This is overwritten on `Connect()`, default &amp;quot;logFile.txt&amp;quot;, in the application&#039;s working directory.&lt;br /&gt;
&lt;br /&gt;
`LogStates`&lt;br /&gt;
Whether or not to log commands to set a state, as well as the received Prompt if the command produces no errors, default false.&lt;br /&gt;
&lt;br /&gt;
`LogPrompts`&lt;br /&gt;
Whether or not to log any Prompt, in which case only received output and errors will be logged, default false.&lt;br /&gt;
&lt;br /&gt;
===BCI2000StateSender===&lt;br /&gt;
&lt;br /&gt;
`UnityBCI2000 object`&lt;br /&gt;
The object which has the attached `UnityBCI2000` script.&lt;br /&gt;
&lt;br /&gt;
`Custom Variable Supplier`&lt;br /&gt;
The component which inherits from `CustomVariableBase` which supplies custom variables.&lt;br /&gt;
&lt;br /&gt;
Global and screen coordinates and their scales.&lt;br /&gt;
&lt;br /&gt;
`Camera`&lt;br /&gt;
The camera to use for finding screen position.&lt;br /&gt;
&lt;br /&gt;
`Is on screen`&lt;br /&gt;
Is the object on screen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
`Velocity`&lt;br /&gt;
The velocity of the object in any direction.&lt;br /&gt;
&lt;br /&gt;
`Custom Variables`&lt;br /&gt;
Lists the names of any added custom variables.&lt;br /&gt;
&lt;br /&gt;
==Other Notes==&lt;br /&gt;
&lt;br /&gt;
`StateVariable` is a class which holds values necessary for sending states to BCI2000.  &lt;br /&gt;
They are stored in two places, a central list within `UnityBCI2000` which is only used for checking if a state already exists,&lt;br /&gt;
and within the `BCI2000StateSender` which &#039;owns&#039; the state, where they are stored within objects called `SendStateVariable`,&lt;br /&gt;
which update the state with a new value every frame. This is done so that one state can be changed by mutiple `BCI2000StateSender`s,&lt;br /&gt;
through the use of multiple `SendStateVariables` created using the `AddSendExistingState()` method. &lt;br /&gt;
&lt;br /&gt;
BCI2000Remote will write its output to a log file that is, by default, located at logFile.txt in the working directory of your Unity application.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=11112</id>
		<title>Contributions:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=11112"/>
		<updated>2024-02-19T22:12:50Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Full tutorial soon, added class documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
UnityBCI2000 is a tool for integration of Unity applications with BCI2000.&lt;br /&gt;
&lt;br /&gt;
==Tutorial==&lt;br /&gt;
[https://bci2000.org/BCI2000Unity/classUnityBCI2000.html Class documentation]&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=10582</id>
		<title>Contributions:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=10582"/>
		<updated>2023-08-02T15:37:16Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
UnityBCI2000 is a tool for integration of Unity applications with BCI2000.&lt;br /&gt;
&lt;br /&gt;
==Tutorial==&lt;br /&gt;
For information on how to use Unity itself, see the Unity [https://docs.unity3d.com/Manual/index.html manual]. This tutorial assumes knowledge of how to use Unity.&lt;br /&gt;
More in-depth detail on how UnityBCI2000 works is provided in the README.md file, as well as HTML documentation in the docs directory.&lt;br /&gt;
&lt;br /&gt;
First, download UnityBCI2000 from [https://github.com/neurotechcenter/UnityBCI2000 GitHub]. As of now, UnityBCI2000 is not a full Unity package, but it works the same. Place the files UnityBCI2000.cs and BCI2000RemoteNET.dll within the Assets folder of your Unity project.&lt;br /&gt;
&lt;br /&gt;
Add the UnityBCI2000 script as a component to an empty GameObject. This will serve as the connection to BCI2000 within your project.&lt;br /&gt;
&lt;br /&gt;
Specify the location of the BCI2000 executable, the BCI2000 modules you want to start along with their startup arguments, and any parameter files you want to load.&lt;br /&gt;
&lt;br /&gt;
Connection to BCI2000 is done by calling UnityBCI2000&#039;s methods from other scripts. Within the script object from which you want to control BCI2000, add the UnityBCI2000 component as a member variable using Unity&#039;s GameObject.Find and GameObject.GetComponent methods.&lt;br /&gt;
For example, if you have UnityBCI2000 attached to a GameObject called &amp;quot;BCI2K&amp;quot;, your script would look like this:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
class ObjScript : MonoBehaviour {&lt;br /&gt;
  private UnityBCI2000 bci = GameObject.Find(&amp;quot;BCI2K&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
  public void Start(){}&lt;br /&gt;
  public void Update(){}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Events and States can be added to BCI2000 within the Start() methods of your scripts. If you wanted to add an Event called &amp;quot;X&amp;quot; and a State called &amp;quot;Y&amp;quot;, your script would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
class ObjScript : MonoBehaviour {&lt;br /&gt;
  private UnityBCI2000 bci = GameObject.Find(&amp;quot;BCI2K&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
  public void Start(){&lt;br /&gt;
    bci.AddEvent(&amp;quot;M&amp;quot;);&lt;br /&gt;
    bci.AddState(&amp;quot;N&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  public void Update(){}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Events and States are accessed through a few methods of UnityBCI2000 called from the Update() method. In order to access their values, use the GetEvent and GetState methods.&lt;br /&gt;
&lt;br /&gt;
In order to set their values, call SetEvent, PulseEvent, or SetState. For events, SetEvent sets the value of an Event like a state, and PulseEvent sets the value of an Event for a single sample before returning it to its previous value, for use if you want to record an instantaneous event happening. &lt;br /&gt;
A script which interacts with events:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
class ObjScript : MonoBehaviour {&lt;br /&gt;
  private UnityBCI2000 bci = GameObject.Find(&amp;quot;BCI2K&amp;quot;).GetComponent&amp;lt;UnityBCI2000&amp;gt;();&lt;br /&gt;
  public void Start(){&lt;br /&gt;
    bci.AddEvent(&amp;quot;M&amp;quot;);&lt;br /&gt;
    bci.AddState(&amp;quot;N&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  public void Update(){&lt;br /&gt;
    int x = bci.GetEvent(&amp;quot;MousePosX&amp;quot;);&lt;br /&gt;
    if (condition) {&lt;br /&gt;
      bci.PulseEvent(&amp;quot;thingHappened&amp;quot;, 1);&lt;br /&gt;
    }&lt;br /&gt;
    bci.SetEvent(&amp;quot;Y&amp;quot;, (int) transform.position.y);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=9207</id>
		<title>Contributions:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=9207"/>
		<updated>2021-10-06T03:49:03Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
UnityBCI2000 is a tool for integration of Unity applications with BCI2000.&lt;br /&gt;
&lt;br /&gt;
==Tutorial==&lt;br /&gt;
For information on how to use Unity itself, see the Unity [https://docs.unity3d.com/Manual/index.html manual]. This tutorial assumes knowledge of how to use Unity. It is recommended to know how GameObjects and Components work.&lt;br /&gt;
More in-depth detail on how UnityBCI2000 works is provided in the README.md file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
First, download UnityBCI2000 from [https://github.com/neurotechcenter/UnityBCI2000 GitHub]. As of now, UnityBCI2000 is not a full Unity package, but it works the same. Place the C# files from the Runtime folder, as well as BCI2000RemoteNET.dll, within the Assets directory of your Unity project.&lt;br /&gt;
&lt;br /&gt;
Create an empty GameObject and add the script UnityBCI2000 as a Component. This will serve as the central connection to the BCI2000 Operator. As of now, it is not possible to use multiple scenes with one BCI2000 connection.&lt;br /&gt;
&lt;br /&gt;
1. Add a UnityBCI2000.cs to the GameObject as a Script Component. &lt;br /&gt;
&lt;br /&gt;
2.Specify the path to the operator using the Operator Path field, as well as the names of the modules to start up alongside it. &lt;br /&gt;
&lt;br /&gt;
If you have an instance of the operator already running, specify the IP and port it is listening on using the Telnet Ip and Telnet Port fields instead.&lt;br /&gt;
&lt;br /&gt;
You can also set a custom log file location, as well as tell the program to log sent states and received prompts. &#039;&#039;&#039;NOTE: There is a known issue with writing to the log file, this is remedied by changing the name of the file to write to. This is an issue with BCI2000RemoteNET, and will be fixed in upcoming updates.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
3. Now, add a Script component of the script BCI2000StateSender to the object which you want to take data from. &lt;br /&gt;
&lt;br /&gt;
4. Drag the BCI2000 GameObject from step 1 into the UnityBCI2000Object field of the BCI2000StateSender.&lt;br /&gt;
&lt;br /&gt;
BCI2000StateSender comes with some predefined states to send, as well as values to scale them by. These are the global and screen coordinates, as well as whether the object is on screen.&lt;br /&gt;
&lt;br /&gt;
===Adding Custom Variables===&lt;br /&gt;
Due to the way Unity works, adding custom variables must be done from a custom script, unique to each GameObject, if the GameObjects are not identical. Unfortunately, this means that some knowledge of C# programming is required, but templates for a CustomVariableSupplier script are provided within the README.md file.&lt;br /&gt;
&lt;br /&gt;
There are two types of custom variables: custom set variables, which set a state in BCI2000 to some value, and custom get variables, which retrieve the value of a state variable from BCI2000.&lt;br /&gt;
&lt;br /&gt;
Custom set variables contain the name of the state to write to, a Func&amp;lt;int&amp;gt; delegate(a piece of code represented by a method or lambda expression which returns the value to send to BCI2000), a scale factor to scale the variable by, in order to avoid truncation due to the fact that BCI2000 state variables are only unsigned integers, and a type.&lt;br /&gt;
Types are defined by the enum UnityBCI2000.StateType, which currently holds 5 values, which are signed integers of bit widths 16 and 32, as well as boolean, which is an unsigned integer of bit width 1. Signed numbers will be represented in BCI2000 by two state variables: The magnitude of the number and its sign, which is 0 for positive and 1 for negative.&lt;br /&gt;
&lt;br /&gt;
Custom get variables contain the name of the state to read from, as well as an Action&amp;lt;int&amp;gt; delegate(a piece of code which takes an int as a parameter), which will receive the value from BCI2000.&lt;br /&gt;
For reference on delegates see the [https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/ C# Programming Guide].&lt;br /&gt;
Note: UnityBCI2000 uses reflection in order to reduce the amount of boilerplate code needed to implement a custom state variable, as well as simplify the process of adding and indexing of custom state variables.&lt;br /&gt;
&lt;br /&gt;
Template for adding custom variables:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
public class &amp;lt;ClassName&amp;gt; : CustomVariableBase&lt;br /&gt;
{&lt;br /&gt;
    public override void AddCustomVariables()&lt;br /&gt;
    {&lt;br /&gt;
        customVariables.Add(new CustomSetVariable(  //Copy this for more set variables&lt;br /&gt;
            &amp;quot;[Name]&amp;quot;,&lt;br /&gt;
            new Func&amp;lt;float&amp;gt;(() =&amp;gt; [Code which returns variable to send]),&lt;br /&gt;
            [Scale],&lt;br /&gt;
            UnityBCI2000.StateType.[Type]&lt;br /&gt;
            ));&lt;br /&gt;
            &lt;br /&gt;
        customVariables.Add(new CustomGetVariable(  //Copy this for more get variables&lt;br /&gt;
            &amp;quot;[Name]&amp;quot;,  &lt;br /&gt;
            new Action&amp;lt;int&amp;gt; ((int i) =&amp;gt; [Code which uses i])&lt;br /&gt;
        ));&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of a custom variable provider script:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
public class CustomVariableSupplier1 : CustomVariableBase&lt;br /&gt;
{&lt;br /&gt;
    public override void AddCustomVariables() &lt;br /&gt;
    {&lt;br /&gt;
        customVariables.Add(new CustomSetVariable( &lt;br /&gt;
            &amp;quot;Custom variable 1&amp;quot;,&lt;br /&gt;
            new Func&amp;lt;float&amp;gt;(() =&amp;gt; {return 65 / 5;}),&lt;br /&gt;
            100,&lt;br /&gt;
            UnityBCI2000.StateType.SignedInt16&lt;br /&gt;
            ));&lt;br /&gt;
&lt;br /&gt;
        customVariables.Add(new CustomSetVariable(&lt;br /&gt;
            &amp;quot;Custom variable 2: Frame count&amp;quot;,&lt;br /&gt;
            new Func&amp;lt;float&amp;gt;(() =&amp;gt; Time.frameCount),&lt;br /&gt;
            1,&lt;br /&gt;
            UnityBCI2000.StateType.UnsignedInt32&lt;br /&gt;
            ));&lt;br /&gt;
&lt;br /&gt;
        customVariables.Add(new CustomGetVariable(  &lt;br /&gt;
            &amp;quot;StateName&amp;quot;,  &lt;br /&gt;
            new Action&amp;lt;int&amp;gt; ((int i) =&amp;gt; {score = i})&lt;br /&gt;
        ));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1. Add a new C# script to the object which you want to take data from.&lt;br /&gt;
&lt;br /&gt;
2. Edit the script to change the inherited class to be CustomVariableBase instead of MonoBehavior.&lt;br /&gt;
&lt;br /&gt;
3. Implement the AddCustomVariables method, and have it add Custom Variables to the customVariables List, by calling customVariables.Add.  &lt;br /&gt;
&lt;br /&gt;
4. Drag this new script into the Custom Variable Supplier field of the BCI2000StateSender Component.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=9206</id>
		<title>Contributions:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=9206"/>
		<updated>2021-10-06T03:47:55Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
UnityBCI2000 is a tool for integration of Unity applications with BCI2000.&lt;br /&gt;
&lt;br /&gt;
==Tutorial==&lt;br /&gt;
For information on how to use Unity itself, see the Unity [https://docs.unity3d.com/Manual/index.html manual]. This tutorial assumes knowledge of how to use Unity. It is recommended to know how GameObjects and Components work.&lt;br /&gt;
More in-depth detail on how UnityBCI2000 works is provided in the README.md file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
First, download UnityBCI2000 from [https://github.com/neurotechcenter/UnityBCI2000 GitHub]. As of now, UnityBCI2000 is not a full Unity package, but it works the same. Place the C# files from the Runtime folder, as well as BCI2000RemoteNET.dll, within the Assets directory of your Unity project.&lt;br /&gt;
&lt;br /&gt;
Create an empty GameObject and add the script UnityBCI2000 as a Component. This will serve as the central connection to the BCI2000 Operator. As of now, it is not possible to use multiple scenes with one BCI2000 connection.&lt;br /&gt;
&lt;br /&gt;
1. Add a UnityBCI2000.cs to the GameObject as a Script Component. &lt;br /&gt;
2.Specify the path to the operator using the Operator Path field, as well as the names of the modules to start up alongside it. &lt;br /&gt;
    -If you have an instance of the operator already running, specify the IP and port it is listening on using the Telnet Ip and Telnet Port fields instead.&lt;br /&gt;
&lt;br /&gt;
    -You can also set a custom log file location, as well as tell the program to log sent states and received prompts. &#039;&#039;&#039;NOTE: There is a known issue with writing to the log file, this is remedied by changing the name of the file to write to. This is an issue with BCI2000RemoteNET, and will be fixed in upcoming updates.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
3. Now, add a Script component of the script BCI2000StateSender to the object which you want to take data from. &lt;br /&gt;
4. Drag the BCI2000 GameObject from step 1 into the UnityBCI2000Object field of the BCI2000StateSender.&lt;br /&gt;
    -BCI2000StateSender comes with some predefined states to send, as well as values to scale them by. These are the global and screen coordinates, as well as whether the object is on screen.&lt;br /&gt;
&lt;br /&gt;
===Adding Custom Variables===&lt;br /&gt;
Due to the way Unity works, adding custom variables must be done from a custom script, unique to each GameObject, if the GameObjects are not identical. Unfortunately, this means that some knowledge of C# programming is required, but templates for a CustomVariableSupplier script are provided within the README.md file.&lt;br /&gt;
&lt;br /&gt;
There are two types of custom variables: custom set variables, which set a state in BCI2000 to some value, and custom get variables, which retrieve the value of a state variable from BCI2000.&lt;br /&gt;
&lt;br /&gt;
Custom set variables contain the name of the state to write to, a Func&amp;lt;int&amp;gt; delegate(a piece of code represented by a method or lambda expression which returns the value to send to BCI2000), a scale factor to scale the variable by, in order to avoid truncation due to the fact that BCI2000 state variables are only unsigned integers, and a type.&lt;br /&gt;
Types are defined by the enum UnityBCI2000.StateType, which currently holds 5 values, which are signed integers of bit widths 16 and 32, as well as boolean, which is an unsigned integer of bit width 1. Signed numbers will be represented in BCI2000 by two state variables: The magnitude of the number and its sign, which is 0 for positive and 1 for negative.&lt;br /&gt;
&lt;br /&gt;
Custom get variables contain the name of the state to read from, as well as an Action&amp;lt;int&amp;gt; delegate(a piece of code which takes an int as a parameter), which will receive the value from BCI2000.&lt;br /&gt;
For reference on delegates see the [https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/ C# Programming Guide].&lt;br /&gt;
Note: UnityBCI2000 uses reflection in order to reduce the amount of boilerplate code needed to implement a custom state variable, as well as simplify the process of adding and indexing of custom state variables.&lt;br /&gt;
&lt;br /&gt;
Template for adding custom variables:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
public class &amp;lt;ClassName&amp;gt; : CustomVariableBase&lt;br /&gt;
{&lt;br /&gt;
    public override void AddCustomVariables()&lt;br /&gt;
    {&lt;br /&gt;
        customVariables.Add(new CustomSetVariable(  //Copy this for more set variables&lt;br /&gt;
            &amp;quot;[Name]&amp;quot;,&lt;br /&gt;
            new Func&amp;lt;float&amp;gt;(() =&amp;gt; [Code which returns variable to send]),&lt;br /&gt;
            [Scale],&lt;br /&gt;
            UnityBCI2000.StateType.[Type]&lt;br /&gt;
            ));&lt;br /&gt;
            &lt;br /&gt;
        customVariables.Add(new CustomGetVariable(  //Copy this for more get variables&lt;br /&gt;
            &amp;quot;[Name]&amp;quot;,  &lt;br /&gt;
            new Action&amp;lt;int&amp;gt; ((int i) =&amp;gt; [Code which uses i])&lt;br /&gt;
        ));&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of a custom variable provider script:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
public class CustomVariableSupplier1 : CustomVariableBase&lt;br /&gt;
{&lt;br /&gt;
    public override void AddCustomVariables() &lt;br /&gt;
    {&lt;br /&gt;
        customVariables.Add(new CustomSetVariable( &lt;br /&gt;
            &amp;quot;Custom variable 1&amp;quot;,&lt;br /&gt;
            new Func&amp;lt;float&amp;gt;(() =&amp;gt; {return 65 / 5;}),&lt;br /&gt;
            100,&lt;br /&gt;
            UnityBCI2000.StateType.SignedInt16&lt;br /&gt;
            ));&lt;br /&gt;
&lt;br /&gt;
        customVariables.Add(new CustomSetVariable(&lt;br /&gt;
            &amp;quot;Custom variable 2: Frame count&amp;quot;,&lt;br /&gt;
            new Func&amp;lt;float&amp;gt;(() =&amp;gt; Time.frameCount),&lt;br /&gt;
            1,&lt;br /&gt;
            UnityBCI2000.StateType.UnsignedInt32&lt;br /&gt;
            ));&lt;br /&gt;
&lt;br /&gt;
        customVariables.Add(new CustomGetVariable(  &lt;br /&gt;
            &amp;quot;StateName&amp;quot;,  &lt;br /&gt;
            new Action&amp;lt;int&amp;gt; ((int i) =&amp;gt; {score = i})&lt;br /&gt;
        ));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1. Add a new C# script to the object which you want to take data from.&lt;br /&gt;
&lt;br /&gt;
2. Edit the script to change the inherited class to be CustomVariableBase instead of MonoBehavior.&lt;br /&gt;
&lt;br /&gt;
3. Implement the AddCustomVariables method, and have it add Custom Variables to the customVariables List, by calling customVariables.Add.  &lt;br /&gt;
&lt;br /&gt;
4. Drag this new script into the Custom Variable Supplier field of the BCI2000StateSender Component.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=9205</id>
		<title>Contributions:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=9205"/>
		<updated>2021-10-06T03:46:49Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
UnityBCI2000 is a tool for integration of Unity applications with BCI2000.&lt;br /&gt;
&lt;br /&gt;
==Tutorial==&lt;br /&gt;
For information on how to use Unity itself, see the Unity [https://docs.unity3d.com/Manual/index.html manual]. This tutorial assumes knowledge of how to use Unity. It is recommended to know how GameObjects and Components work.&lt;br /&gt;
More in-depth detail on how UnityBCI2000 works is provided in the README.md file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
First, download UnityBCI2000 from [https://github.com/neurotechcenter/UnityBCI2000 GitHub]. As of now, UnityBCI2000 is not a full Unity package, but it works the same. Place the C# files from the Runtime folder, as well as BCI2000RemoteNET.dll, within the Assets directory of your Unity project.&lt;br /&gt;
&lt;br /&gt;
Create an empty GameObject and add the script UnityBCI2000 as a Component. This will serve as the central connection to the BCI2000 Operator. As of now, it is not possible to use multiple scenes with one BCI2000 connection.&lt;br /&gt;
&lt;br /&gt;
1. Add a UnityBCI2000.cs to the GameObject as a Script Component. &lt;br /&gt;
2.Specify the path to the operator using the Operator Path field, as well as the names of the modules to start up alongside it. &lt;br /&gt;
    -If you have an instance of the operator already running, specify the IP and port it is listening on using the Telnet Ip and Telnet Port fields instead.&lt;br /&gt;
&lt;br /&gt;
    -You can also set a custom log file location, as well as tell the program to log sent states and received prompts. &#039;&#039;&#039;NOTE: There is a known issue with writing to the log file, this is remedied by changing the name of the file to write to. This is an issue with BCI2000RemoteNET, and will be fixed in upcoming updates.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
3. Now, add a Script component of the script BCI2000StateSender to the object which you want to take data from. &lt;br /&gt;
4. Drag the BCI2000 GameObject from step 1 into the UnityBCI2000Object field of the BCI2000StateSender.&lt;br /&gt;
    -BCI2000StateSender comes with some predefined states to send, as well as values to scale them by. These are the global and screen coordinates, as well as whether the object is on screen.&lt;br /&gt;
&lt;br /&gt;
===Adding Custom Variables===&lt;br /&gt;
Due to the way Unity works, adding custom variables must be done from a custom script, unique to each GameObject, if the GameObjects are not identical. Unfortunately, this means that some knowledge of C# programming is required, but templates for a CustomVariableSupplier script are provided within the README.md file.&lt;br /&gt;
&lt;br /&gt;
There are two types of custom variables: custom set variables, which set a state in BCI2000 to some value, and custom get variables, which retrieve the value of a state variable from BCI2000.&lt;br /&gt;
&lt;br /&gt;
Custom set variables contain the name of the state to write to, a Func&amp;lt;int&amp;gt; delegate(a piece of code represented by a method or lambda expression which returns the value to send to BCI2000), a scale factor to scale the variable by, in order to avoid truncation due to the fact that BCI2000 state variables are only unsigned integers, and a type.&lt;br /&gt;
Types are defined by the enum UnityBCI2000.StateType, which currently holds 5 values, which are signed integers of bit widths 16 and 32, as well as boolean, which is an unsigned integer of bit width 1. Signed numbers will be represented in BCI2000 by two state variables: The magnitude of the number and its sign, which is 0 for positive and 1 for negative.&lt;br /&gt;
&lt;br /&gt;
Custom get variables contain the name of the state to read from, as well as an Action&amp;lt;int&amp;gt; delegate(a piece of code which takes an int as a parameter), which will receive the value from BCI2000.&lt;br /&gt;
For reference on delegates see the [https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/ C# Programming Guide].&lt;br /&gt;
Note: UnityBCI2000 uses reflection in order to reduce the amount of boilerplate code needed to implement a custom state variable, as well as simplify the process of adding and indexing of custom state variables.&lt;br /&gt;
&lt;br /&gt;
Template for adding custom variables:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
public class &amp;lt;ClassName&amp;gt; : CustomVariableBase&lt;br /&gt;
{&lt;br /&gt;
    public override void AddCustomVariables()&lt;br /&gt;
    {&lt;br /&gt;
        customVariables.Add(new CustomSetVariable(  //Copy this for more set variables&lt;br /&gt;
            &amp;quot;[Name]&amp;quot;,&lt;br /&gt;
            new Func&amp;lt;float&amp;gt;(() =&amp;gt; [Code which returns variable to send]),&lt;br /&gt;
            [Scale],&lt;br /&gt;
            UnityBCI2000.StateType.[Type]&lt;br /&gt;
            ));&lt;br /&gt;
            &lt;br /&gt;
        customVariables.Add(new CustomGetVariable(  //Copy this for more get variables&lt;br /&gt;
            &amp;quot;[Name]&amp;quot;,  &lt;br /&gt;
            new Action&amp;lt;int&amp;gt; ((int i) =&amp;gt; [Code which uses i])&lt;br /&gt;
        ));&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of a custom variable provider script:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
public class CustomVariableSupplier1 : CustomVariableBase&lt;br /&gt;
{&lt;br /&gt;
    public override void AddCustomVariables() &lt;br /&gt;
    {&lt;br /&gt;
        customVariables.Add(new CustomSetVariable( &lt;br /&gt;
            &amp;quot;Custom variable 1&amp;quot;,&lt;br /&gt;
            new Func&amp;lt;float&amp;gt;(() =&amp;gt; {return 65 / 5;}),&lt;br /&gt;
            100,&lt;br /&gt;
            UnityBCI2000.StateType.SignedInt16&lt;br /&gt;
            ));&lt;br /&gt;
&lt;br /&gt;
        customVariables.Add(new CustomSetVariable(&lt;br /&gt;
            &amp;quot;Custom variable 2: Frame count&amp;quot;,&lt;br /&gt;
            new Func&amp;lt;float&amp;gt;(() =&amp;gt; Time.frameCount),&lt;br /&gt;
            1,&lt;br /&gt;
            UnityBCI2000.StateType.UnsignedInt32&lt;br /&gt;
            ));&lt;br /&gt;
&lt;br /&gt;
        customVariables.Add(new CustomGetVariable(  &lt;br /&gt;
            &amp;quot;StateName&amp;quot;,  &lt;br /&gt;
            new Action&amp;lt;int&amp;gt; ((int i) =&amp;gt; {score = i})&lt;br /&gt;
        ));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1. Add a new C# script to the object which you want to take data from.&lt;br /&gt;
2. Edit the script to change the inherited class to be CustomVariableBase instead of MonoBehavior.&lt;br /&gt;
3. Implement the AddCustomVariables method, and have it add Custom Variables to the customVariables List, by calling customVariables.Add.&lt;br /&gt;
4. Drag this new script into the Custom Variable Supplier field of the BCI2000StateSender Component.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=9204</id>
		<title>Contributions:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=9204"/>
		<updated>2021-10-06T02:46:24Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
UnityBCI2000 is a tool for integration of Unity applications with BCI2000.&lt;br /&gt;
&lt;br /&gt;
==Tutorial==&lt;br /&gt;
For information on how to use Unity itself, see the Unity [https://docs.unity3d.com/Manual/index.html manual]. This tutorial assumes knowledge of how to use Unity. It is recommended to know how GameObjects and Components work.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
First, download UnityBCI2000 from [https://github.com/neurotechcenter/UnityBCI2000 GitHub]. As of now, UnityBCI2000 is not a full Unity package, but it works the same. Place the C# files from the Runtime folder, as well as BCI2000RemoteNET.dll, within the Assets directory of your Unity project.&lt;br /&gt;
&lt;br /&gt;
Create an empty GameObject and add the script UnityBCI2000 as a Component. This will serve as the central connection to the BCI2000 Operator. As of now, it is not possible to use multiple scenes with one BCI2000 connection.&lt;br /&gt;
&lt;br /&gt;
Add a UnityBCI2000.cs to the GameObject as a Script Component. Specify the path to the operator using the Operator Path field, as well as the names of the modules to start up alongside it. If you have an instance of the operator already running, specify the IP and port it is listening on using the Telnet Ip and Telnet Port fields instead.&lt;br /&gt;
&lt;br /&gt;
You can also set a custom log file location, as well as tell the program to log sent states and received prompts.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=9197</id>
		<title>Contributions:BCI2000RemoteNET</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=9197"/>
		<updated>2021-09-28T01:33:18Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
BCI2000RemoteNET is an implementation of [[Programming_Reference:BCI2000Remote_Class|BCI2000Remote]] as a .NET Standard assembly, for use within .NET languages such as C#, as well as associated applications such as Unity (See [[Contributions:UnityBCI2000|UnityBCI2000]]). Similarly to BCI2000Remote, it sends [[User_Reference:Operator_Module_Scripting|Operator Scripting Commands]] over TCP to a running [[User_Reference:Operator_Module|Operator Module]], or starts up BCI2000 on its own. It does not depends on the BCI2000 Framework, but requires a .NET environment (.NET Framework, .NET Core, Mono) to run.&lt;br /&gt;
&lt;br /&gt;
==Description==&lt;br /&gt;
BCI2000RemoteNET contains a class, BCI2000Remote, which handles connection and communication with the Operator.&lt;br /&gt;
To start, instantiate a BCI2000Remote object, set the operator path if starting a new Operator, and call the Connect() method.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=9196</id>
		<title>Contributions:BCI2000RemoteNET</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:BCI2000RemoteNET&amp;diff=9196"/>
		<updated>2021-09-28T01:23:01Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Created page with &amp;quot;==Synopsis== BCI2000RemoteNET is an implementation of BCI2000Remote as a .NET Standard assembly, for use within .NET languages su...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
BCI2000RemoteNET is an implementation of [[Programming_Reference:BCI2000Remote_Class|BCI2000Remote]] as a .NET Standard assembly, for use within .NET languages such as C#, as well as associated applications such as Unity (See [[Contributions:UnityBCI2000|UnityBCI2000]]). Similarly to BCI2000Remote, it sends [[User_Reference:Operator_Module_Scripting|Operator Scripting Commands]] over TCP to a running [[User_Reference:Operator_Module|Operator Module]], or starts up BCI2000 on its own.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
	<entry>
		<id>https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=9195</id>
		<title>Contributions:UnityBCI2000</title>
		<link rel="alternate" type="text/html" href="https://www.bci2000.org/mediawiki/index.php?title=Contributions:UnityBCI2000&amp;diff=9195"/>
		<updated>2021-09-28T01:19:50Z</updated>

		<summary type="html">&lt;p&gt;Tytbutler: Created page with &amp;quot;==Synopsis== UnityBCI2000 is a tool for integration of Unity applications with BCI2000.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Synopsis==&lt;br /&gt;
UnityBCI2000 is a tool for integration of Unity applications with BCI2000.&lt;/div&gt;</summary>
		<author><name>Tytbutler</name></author>
	</entry>
</feed>