Difference between revisions of "Device (C++)"

From Neurotech Software Development Kit
Jump to: navigation, search
(Non-member functions)
 
(11 intermediate revisions by the same user not shown)
Line 3: Line 3:
 
Defined in header [https://github.com/NeurotechLtd/neuro-sdk/blob/master/core/include/device/device.h <span style="color:#0033CC;"><device/device.h></span>]
 
Defined in header [https://github.com/NeurotechLtd/neuro-sdk/blob/master/core/include/device/device.h <span style="color:#0033CC;"><device/device.h></span>]
  
'''<span style="color:#0033CC;">class</span> Device <span style="color:#0033CC;">final</span>''';
+
'''<span style="font-size:1.3em; line-height:130%"><span style="color:#0033CC;">class</span> Device <span style="color:#0033CC;">final</span></span>''';
  
The Device class is an abstraction for NeuroMD BLE devices. This abstraction provides functions for changing of device state by executing commands and setting parameters. Each device have different sets of supported commands and parameters, Device class has functions designed to get information about these sets.
+
The Device class is an abstraction for NeuroMD BLE devices. This abstraction provides functions for changing of device state by executing commands and setting parameters. Each device have different sets of supported commands and parameters, Device class has functions designed to get information about these sets. Callibri and Braibit devices has different parameters sets and provides different ways to access them. Device class hides all differences behind its interface and provides universal way to read and write parameters, execute commands and receive biopotential signals.  
  
 
==Member functions==
 
==Member functions==
Line 48: Line 48:
 
|}
 
|}
  
<tbody><tr class="t-dsc">
+
==Notes==
<td>  <div class="t-dsc-member-div t-dsc-member-nobold-div"><div><a href="/w/cpp/thread/mutex/mutex" title="cpp/thread/mutex/mutex"> <span class="t-lines"><span>(constructor)</span></span></a></div></div>
+
In general all parameter read/write operations, command executions and data read operations through channels must be done on connected devices. Only Name, State and Address parameters could be read on a disconnected device. Performing another operations on a disconnected device cause device-dependent behavior. For Callibri device most of operations on disconnected device will cause exception throwing, for Brainbit some read operations may be performed but it is not guaranteed to be stable for all versions of SDK.
</td>
 
<td>  constructs the mutex <br> <span class="t-mark">(public member function)</span> <span class="editsection noprint plainlinks" title="Edit this template"><a rel="nofollow" class="external text" href="http://en.cppreference.com/mwiki/index.php?title=Template:cpp/thread/mutex/dsc_constructor&amp;action=edit">[edit]</a></span>
 
</td></tr>
 
  
<tr class="t-dsc">
+
==Example==
<td>  <div class="t-dsc-member-div t-dsc-member-nobold-div"><div><a href="/w/cpp/thread/mutex/%7Emutex" title="cpp/thread/mutex/~mutex"> <span class="t-lines"><span>(destructor)</span></span></a></div></div>
+
This example shows how a to find device, establish connection with it and to list device features
</td>
+
<syntaxhighlight lang="c++">
<td>  destroys the mutex <br> <span class="t-mark">(public member function)</span> <span class="editsection noprint plainlinks" title="Edit this template"><a rel="nofollow" class="external text" href="http://en.cppreference.com/mwiki/index.php?title=Template:cpp/thread/mutex/dsc_destructor&amp;action=edit">[edit]</a></span>
+
#include <iostream>
</td></tr>
+
#include <vector>
 +
#include "device_scanner.h"
 +
#include "device/param_values.h"
  
<tr class="t-dsc">
+
std::vector<std::shared_ptr<Neuro::Device>> FoundDevices;
<td>  <div class="t-dsc-member-div"><div><span class="t-lines"><span>operator=</span></span></div><div><span class="t-lines"><span><span class="t-cmark">[deleted]</span></span></span></div></div>
 
</td>
 
<td>  not copy-assignable <br> <span class="t-mark">(public member function)</span> <span class="editsection noprint plainlinks" title="Edit this template"><a rel="nofollow" class="external text" href="http://en.cppreference.com/mwiki/index.php?title=Template:cpp/thread/mutex/dsc_operator%3D&amp;action=edit">[edit]</a></span>
 
</td></tr>
 
  
 +
template <typename T>
 +
void displayDeviceFeatures(T&& device_ptr){
 +
    using Neuro::to_string;
  
<tr>
+
    std::cout << "Device can execute:" << std::endl;
<td colspan="2"> <h5> <span class="mw-headline" id="Locking">  Locking </span></h5>
+
    auto commands = device_ptr->commands();
</td></tr>
+
    for (auto& cmd : commands){
 +
        std::cout << "-" << to_string(cmd) << std::endl;
 +
    }
 +
std::cout << std::endl;
  
<tr class="t-dsc">
+
    std::cout << "Device has parameters:" << std::endl;
<td>  <div class="t-dsc-member-div"><div><a href="/w/cpp/thread/mutex/lock" title="cpp/thread/mutex/lock"> <span class="t-lines"><span>lock</span></span></a></div></div>
+
    auto params = device_ptr->parameters();
</td>
+
    for (auto& paramPair : params){
<td>  locks the mutex, blocks if the mutex is not available <br> <span class="t-mark">(public member function)</span> <span class="editsection noprint plainlinks" title="Edit this template"><a rel="nofollow" class="external text" href="http://en.cppreference.com/mwiki/index.php?title=Template:cpp/thread/mutex/dsc_lock&amp;action=edit">[edit]</a></span>
+
        std::cout << "-" << to_string(paramPair.first) << " {" << to_string(paramPair.second) << "}" <<std::endl;
</td></tr>
+
    }
 +
std::cout << std::endl;
  
<tr class="t-dsc">
+
    std::cout << "Device has channels:" << std::endl;
<td>  <div class="t-dsc-member-div"><div><a href="/w/cpp/thread/mutex/try_lock" title="cpp/thread/mutex/try lock"> <span class="t-lines"><span>try_lock</span></span></a></div></div>
+
    auto channels = device_ptr->channels();
</td>
+
    for (auto& channel : channels){
<td>  tries to lock the mutex, returns if the mutex is not available <br> <span class="t-mark">(public member function)</span> <span class="editsection noprint plainlinks" title="Edit this template"><a rel="nofollow" class="external text" href="http://en.cppreference.com/mwiki/index.php?title=Template:cpp/thread/mutex/dsc_try_lock&amp;action=edit">[edit]</a></span>
+
        std::cout << "-" << channel.getName() << std::endl;
</td></tr>
+
    }
 +
std::cout << std::endl;
 +
}
  
<tr class="t-dsc">
 
<td>  <div class="t-dsc-member-div"><div><a href="/w/cpp/thread/mutex/unlock" title="cpp/thread/mutex/unlock"> <span class="t-lines"><span>unlock</span></span></a></div></div>
 
</td>
 
<td>  unlocks the mutex <br> <span class="t-mark">(public member function)</span> <span class="editsection noprint plainlinks" title="Edit this template"><a rel="nofollow" class="external text" href="http://en.cppreference.com/mwiki/index.php?title=Template:cpp/thread/mutex/dsc_unlock&amp;action=edit">[edit]</a></span>
 
</td></tr>
 
  
 +
template <typename T>
 +
void connectDevice(T&& device_ptr){
 +
    using Neuro::Parameter;
 +
std::cout << "Connecting device ["
 +
  << device_ptr->readParam<Parameter::Address>()
 +
  << "]" << std::endl;
  
<tr>
+
using device_t = typename std::remove_reference_t<decltype(device_ptr)>::element_type;
<td colspan="2"> <h5> <span class="mw-headline" id="Native_handle">  Native handle </span></h5>
+
auto weakDevice = std::weak_ptr<device_t>(device_ptr);
</td></tr>
+
    device_ptr->setParamChangedCallback([weakDevice](auto param){
 +
        if (param == Parameter::State){
 +
auto device = weakDevice.lock();
 +
if (device != nullptr) {
 +
auto state = device->readParam<Parameter::State>();
 +
if (state == Neuro::DeviceState::Connected) {
 +
std::cout << "Device ["
 +
<< device->readParam<Parameter::Address>()
 +
<< "] connected" << std::endl;
 +
displayDeviceFeatures(device);
 +
}
 +
}
 +
        }
 +
    });
 +
device_ptr->connect();
 +
FoundDevices.push_back(device_ptr);
 +
}
  
<tr class="t-dsc">
+
template <typename T>
<td>  <div class="t-dsc-member-div"><div><a href="/w/cpp/thread/mutex/native_handle" title="cpp/thread/mutex/native handle"> <span class="t-lines"><span>native_handle</span></span></a></div></div>
+
void onDeviceFound(T&& device_ptr){
</td>
+
    using Neuro::Parameter;
<td>  returns the underlying implementation-defined native handle object <br> <span class="t-mark">(public member function)</span> <span class="editsection noprint plainlinks" title="Edit this template"><a rel="nofollow" class="external text" href="http://en.cppreference.com/mwiki/index.php?title=Template:cpp/thread/mutex/dsc_native_handle&amp;action=edit">[edit]</a></span>
+
    using Neuro::DeviceState;
</td></tr>
+
    using Neuro::to_string;
</tbody></table>
+
 
|}
+
    auto deviceName = device_ptr->readParam<Parameter::Name>();
<h3><span class="editsection">[<a href="/mwiki/index.php?title=cpp/thread/mutex&amp;action=edit&amp;section=3" title="Edit section: Notes">edit</a>]</span> <span class="mw-headline" id="Notes">Notes</span></h3>
+
    auto deviceAddress = device_ptr->readParam<Parameter::Address>();
<p><code>std::mutex</code> is usually not accessed directly: <span class="t-lc"><a href="/w/cpp/thread/unique_lock" title="cpp/thread/unique lock">std::unique_lock</a></span>, <span class="t-lc"><a href="/w/cpp/thread/lock_guard" title="cpp/thread/lock guard">std::lock_guard</a></span>, <span class="t-rev-inl t-since-cxx17"><span> or <span class="t-lc">std::scoped_lock</span> </span> <span><span class="t-mark-rev t-since-cxx17">(since C++17)</span></span></span> manage locking in a more exception-safe manner.
+
    auto deviceState = device_ptr->readParam<Parameter::State>();
</p>
+
    std::cout << deviceName
<h3><span class="editsection">[<a href="/mwiki/index.php?title=cpp/thread/mutex&amp;action=edit&amp;section=4" title="Edit section: Example">edit</a>]</span> <span class="mw-headline" id="Example">Example</span></h3>
+
              << " [" << deviceAddress << "] "
<div class="t-example"><p> This example shows how a <code>mutex</code> can be used to protect a <span class="t-lc"><a href="/w/cpp/container/map" title="cpp/container/map">std::map</a></span> shared between two threads.
+
              << to_string(deviceState)
</p><div class="t-example-live-link"><div class="coliru-btn coliru-btn-run-init">Run this code</div></div>
+
              << std::endl;
<div dir="ltr" class="mw-geshi t-example-code" style="text-align: left;"><div class="cpp source-cpp"><pre class="de1"><span class="co2">#include &lt;iostream&gt;</span>
+
 
<span class="co2">#include &lt;map&gt;</span>
+
using device_t = typename std::remove_reference_t<decltype(device_ptr)>::element_type;
<span class="co2">#include &lt;string&gt;</span>
+
auto sharedDevice = std::shared_ptr<device_t>(std::forward<T>(device_ptr));
<span class="co2">#include &lt;chrono&gt;</span>
+
if (deviceState != DeviceState::Connected) {
<span class="co2">#include &lt;thread&gt;</span>
+
connectDevice(sharedDevice);
<span class="co2">#include &lt;mutex&gt;</span>
+
}
&nbsp;
+
else{
<a href="http://en.cppreference.com/w/cpp/container/map"><span class="kw1281">std::<span class="me2">map</span></span></a><span class="sy1">&lt;</span><a href="http://en.cppreference.com/w/cpp/string/basic_string"><span class="kw1230">std::<span class="me2">string</span></span></a>, <a href="http://en.cppreference.com/w/cpp/string/basic_string"><span class="kw1230">std::<span class="me2">string</span></span></a><span class="sy1">&gt;</span> g_pages<span class="sy4">;</span>
+
displayDeviceFeatures(sharedDevice);
std<span class="sy4">::</span><span class="me2">mutex</span> g_pages_mutex<span class="sy4">;</span>
+
}
&nbsp;
+
}
<span class="kw4">void</span> save_page<span class="br0">(</span><span class="kw4">const</span> <a href="http://en.cppreference.com/w/cpp/string/basic_string"><span class="kw1230">std::<span class="me2">string</span></span></a> <span class="sy3">&amp;</span>url<span class="br0">)</span>
+
 
<span class="br0">{</span>
+
int main(int argc, char *argv[]){
    <span class="co1">// simulate a long page fetch</span>
+
     auto scanner = Neuro::createDeviceScanner();
    <a href="http://en.cppreference.com/w/cpp/thread/sleep_for"><span class="kw2149">std::<span class="me2">this_thread</span><span class="sy4">::</span><span class="me2">sleep_for</span></span></a><span class="br0">(</span><a href="http://en.cppreference.com/w/cpp/chrono/duration"><span class="kw997">std::<span class="me2">chrono</span><span class="sy4">::</span><span class="me2">seconds</span></span></a><span class="br0">(</span><span class="nu0">2</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>
+
     scanner->subscribeDeviceFound([](auto&& device_ptr){
    <a href="http://en.cppreference.com/w/cpp/string/basic_string"><span class="kw1230">std::<span class="me2">string</span></span></a> result <span class="sy1">=</span> <span class="st0">"fake content"</span><span class="sy4">;</span>
+
        onDeviceFound(std::forward<decltype(device_ptr)>(device_ptr));
&nbsp;
+
     });
    <a href="http://en.cppreference.com/w/cpp/thread/lock_guard"><span class="kw2165">std::<span class="me2">lock_guard</span></span></a><span class="sy1">&lt;</span>std<span class="sy4">::</span><span class="me2">mutex</span><span class="sy1">&gt;</span> guard<span class="br0">(</span>g_pages_mutex<span class="br0">)</span><span class="sy4">;</span>
+
     scanner->startScan(0);//zero timeout for infinity
    g_pages<span class="br0">[</span>url<span class="br0">]</span> <span class="sy1">=</span> result<span class="sy4">;</span>
+
     while (std::cin.get() != '\n');
<span class="br0">}</span>
+
}
&nbsp;
+
 
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
+
</syntaxhighlight>
<span class="br0">{</span>
+
 
     <a href="http://en.cppreference.com/w/cpp/thread/thread"><span class="kw2146">std::<span class="me2">thread</span></span></a> t1<span class="br0">(</span>save_page, <span class="st0">"http://foo"</span><span class="br0">)</span><span class="sy4">;</span>
+
Possible output:
     <a href="http://en.cppreference.com/w/cpp/thread/thread"><span class="kw2146">std::<span class="me2">thread</span></span></a> t2<span class="br0">(</span>save_page, <span class="st0">"http://bar"</span><span class="br0">)</span><span class="sy4">;</span>
+
<syntaxhighlight lang="bash">
     t1.<span class="me1">join</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
+
Neurotech_Callibri_R [2a:90:37:c0:ec:d4] Disconnected
     t2.<span class="me1">join</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
+
Connecting device [2a:90:37:c0:ec:d4]
&nbsp;
+
Device [2a:90:37:c0:ec:d4] connected
    <span class="co1">// safe to access g_pages without lock now, as the threads are joined</span>
+
Device can execute:
     <span class="kw1">for</span> <span class="br0">(</span><span class="kw4">const</span> <span class="kw4">auto</span> <span class="sy3">&amp;</span>pair <span class="sy4">:</span> g_pages<span class="br0">)</span> <span class="br0">{</span>
+
-FindMe
        <a href="http://en.cppreference.com/w/cpp/io/cout"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1">&lt;&lt;</span> pair.<span class="me1">first</span> <span class="sy1">&lt;&lt;</span> <span class="st0">" =&gt; "</span> <span class="sy1">&lt;&lt;</span> pair.<span class="me1">second</span> <span class="sy1">&lt;&lt;</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
+
-StartSignal
    <span class="br0">}</span>
+
-StopSignal
<span class="br0">}</span></pre></div></div>
+
 
<p>Output:
+
Device has parameters:
</p>
+
-Name {Read}
<div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="text source-text"><pre class="de1">http://bar =&gt; fake content
+
-State {ReadNotify}
http://foo =&gt; fake content</pre></div></div>
+
-Address {Read}
</div>
+
-SerialNumber {Read}
 +
-FirmwareMode {Read}
 +
-SamplingFrequency {ReadWrite}
 +
-ADCInputState {ReadWrite}
 +
-ExternalSwitchState {ReadWrite}
 +
-HardwareFilterState {ReadWrite}
 +
-Gain {ReadWrite}
 +
-Offset {ReadWrite}
 +
-AccelerometerSens {ReadWrite}
 +
-GyroscopeSens {ReadWrite}
 +
 
 +
Device has channels:
 +
-Signal
 +
-ElectrodesState
 +
-ConnectionStats
 +
-Battery
 +
</syntaxhighlight>
  
<!--
+
==See also==
NewPP limit report
+
[[NeuroMD SDK Manual]]
Preprocessor visited node count: 5285/1000000
 
Preprocessor generated node count: 10355/1000000
 
Post‐expand include size: 159462/2097152 bytes
 
Template argument size: 30567/2097152 bytes
 
Highest expansion depth: 20/40
 
Expensive parser function count: 0/100
 
-->
 
  
<!-- Saved in parser cache with key mwiki1-mwiki_en_:pcache:idhash:2291-0!*!0!!en!*!* and timestamp 20180411183737 -->
+
[[Device (Java)]]
</div>                    <!-- /bodycontent -->
 
                                        <!-- printfooter -->
 
                    <div class="printfooter">
 
                    Retrieved from "<a href="http://en.cppreference.com/mwiki/index.php?title=cpp/thread/mutex&amp;oldid=89024">http://en.cppreference.com/mwiki/index.php?title=cpp/thread/mutex&amp;oldid=89024</a>"                    </div>
 
                    <!-- /printfooter -->
 
                                                            <!-- catlinks -->
 
                    <div id="catlinks" class="catlinks catlinks-allhidden"></div>                    <!-- /catlinks -->
 
                                                            <div class="visualClear"></div>
 
                    <!-- debughtml -->
 
                                        <!-- /debughtml -->
 
                </div>
 

Latest revision as of 02:43, 1 May 2018

Neuro::Device

Defined in header <device/device.h>

class Device final;

The Device class is an abstraction for NeuroMD BLE devices. This abstraction provides functions for changing of device state by executing commands and setting parameters. Each device have different sets of supported commands and parameters, Device class has functions designed to get information about these sets. Callibri and Braibit devices has different parameters sets and provides different ways to access them. Device class hides all differences behind its interface and provides universal way to read and write parameters, execute commands and receive biopotential signals.

Member functions

(constructor)[private] constructs device, inaccessible from user code, new device object could be constructed only by DeviceScanner instance
(destructor) destroys device
operator=[deleted] not copy assignable
Supported features
channels returns information about channels which could be created with this device, contains information about channels types and names
commands returns vector containing supported commands
parameters returns

Non-member functions

checkHasChannel returns true if device has channel with same channel information
checkHasCommand returns true if device supports specified command
checkHasParameter returns true if device has specified parameter
countChannelsWithType returns number of channels with specified type in channel info section
getParameterAccess if device has specified parameter returns access modifier for it, otherwise throws

Notes

In general all parameter read/write operations, command executions and data read operations through channels must be done on connected devices. Only Name, State and Address parameters could be read on a disconnected device. Performing another operations on a disconnected device cause device-dependent behavior. For Callibri device most of operations on disconnected device will cause exception throwing, for Brainbit some read operations may be performed but it is not guaranteed to be stable for all versions of SDK.

Example

This example shows how a to find device, establish connection with it and to list device features

#include <iostream>
#include <vector>
#include "device_scanner.h"
#include "device/param_values.h"

std::vector<std::shared_ptr<Neuro::Device>> FoundDevices;

template <typename T>
void displayDeviceFeatures(T&& device_ptr){
    using Neuro::to_string;

    std::cout << "Device can execute:" << std::endl;
    auto commands = device_ptr->commands();
    for (auto& cmd : commands){
        std::cout << "-" << to_string(cmd) << std::endl;
    }
	std::cout << std::endl;

    std::cout << "Device has parameters:" << std::endl;
    auto params = device_ptr->parameters();
    for (auto& paramPair : params){
        std::cout << "-" << to_string(paramPair.first) << " {" << to_string(paramPair.second) << "}" <<std::endl;
    }
	std::cout << std::endl;

    std::cout << "Device has channels:" << std::endl;
    auto channels = device_ptr->channels();
    for (auto& channel : channels){
        std::cout << "-" << channel.getName() << std::endl;
    }
	std::cout << std::endl;
}


template <typename T>
void connectDevice(T&& device_ptr){
    using Neuro::Parameter;
	std::cout << "Connecting device [" 
			  << device_ptr->readParam<Parameter::Address>() 
			  << "]" << std::endl;

	using device_t = typename std::remove_reference_t<decltype(device_ptr)>::element_type;
	auto weakDevice = std::weak_ptr<device_t>(device_ptr);
    device_ptr->setParamChangedCallback([weakDevice](auto param){
        if (param == Parameter::State){
			auto device = weakDevice.lock();
			if (device != nullptr) {
				auto state = device->readParam<Parameter::State>();
				if (state == Neuro::DeviceState::Connected) {
					std::cout << "Device ["
						<< device->readParam<Parameter::Address>()
						<< "] connected" << std::endl;
					displayDeviceFeatures(device);
				}
			}
        }
    });
	device_ptr->connect();
	FoundDevices.push_back(device_ptr);
}

template <typename T>
void onDeviceFound(T&& device_ptr){
    using Neuro::Parameter;
    using Neuro::DeviceState;
    using Neuro::to_string;

    auto deviceName = device_ptr->readParam<Parameter::Name>();
    auto deviceAddress = device_ptr->readParam<Parameter::Address>();
    auto deviceState = device_ptr->readParam<Parameter::State>();
    std::cout << deviceName
              << " [" << deviceAddress << "] "
              << to_string(deviceState)
              << std::endl;

	using device_t = typename std::remove_reference_t<decltype(device_ptr)>::element_type;
	auto sharedDevice = std::shared_ptr<device_t>(std::forward<T>(device_ptr));
	if (deviceState != DeviceState::Connected) {
		connectDevice(sharedDevice);
	}
	else{
		displayDeviceFeatures(sharedDevice);
	}
}

int main(int argc, char *argv[]){
    auto scanner = Neuro::createDeviceScanner();
    scanner->subscribeDeviceFound([](auto&& device_ptr){
        onDeviceFound(std::forward<decltype(device_ptr)>(device_ptr));
    });
    scanner->startScan(0);//zero timeout for infinity
    while (std::cin.get() != '\n');
}

Possible output:

Neurotech_Callibri_R [2a:90:37:c0:ec:d4] Disconnected
Connecting device [2a:90:37:c0:ec:d4]
Device [2a:90:37:c0:ec:d4] connected
Device can execute:
-FindMe
-StartSignal
-StopSignal

Device has parameters:
-Name {Read}
-State {ReadNotify}
-Address {Read}
-SerialNumber {Read}
-FirmwareMode {Read}
-SamplingFrequency {ReadWrite}
-ADCInputState {ReadWrite}
-ExternalSwitchState {ReadWrite}
-HardwareFilterState {ReadWrite}
-Gain {ReadWrite}
-Offset {ReadWrite}
-AccelerometerSens {ReadWrite}
-GyroscopeSens {ReadWrite}

Device has channels:
-Signal
-ElectrodesState
-ConnectionStats
-Battery

See also

NeuroMD SDK Manual

Device (Java)