Skip to content

Commit

Permalink
add set_index_percentage for playback board and fix synthetic board (#…
Browse files Browse the repository at this point in the history
…570)

* add set_index_percentage for playback board and fix synthetic board

Signed-off-by: Andrey Parfenov <a1994ndrey@gmail.com>
  • Loading branch information
Andrey1994 committed Oct 23, 2022
1 parent 9f19e73 commit b3b1896
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 40 deletions.
4 changes: 3 additions & 1 deletion python_package/examples/tests/playback_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ def main():
board = BoardShim(board_id, params)
board.prepare_session()
board.start_stream()
time.sleep(10)
time.sleep(5)
board.config_board('set_index_percentage:10')
time.sleep(5)
data_default = board.get_board_data(preset=BrainFlowPresets.DEFAULT_PRESET)
data_aux = board.get_board_data(preset=BrainFlowPresets.AUXILIARY_PRESET)
board.stop_stream()
Expand Down
7 changes: 4 additions & 3 deletions src/board_controller/inc/playback_file_board.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <condition_variable>
#include <mutex>
#include <thread>
#include <vector>

#include "board.h"
#include "board_controller.h"
Expand All @@ -15,13 +16,13 @@ class PlaybackFileBoard : public Board
volatile bool keep_alive;
volatile bool loopback;
volatile bool use_new_timestamps;
std::vector<double> pos_percentage;
std::vector<std::thread> streaming_threads;
bool initialized;
std::mutex m;
std::condition_variable cv;
volatile int state;
std::vector<std::vector<long int>> file_offsets;

void read_thread (int preset, std::string filename);
int get_file_offsets (std::string filename, std::vector<long int> &offsets);

public:
PlaybackFileBoard (struct BrainFlowInputParams params);
Expand Down
162 changes: 136 additions & 26 deletions src/board_controller/playback_file_board.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <algorithm>
#include <chrono>
#include <sstream>
#include <stdio.h>
Expand All @@ -17,6 +18,8 @@
#define SET_LOOPBACK_FALSE "loopback_false"
#define NEW_TIMESTAMPS "new_timestamps"
#define OLD_TIMESTAMPS "old_timestamps"
#define SET_INDEX_PREFIX "set_index_percentage:"
#define MAX_LINE_LENGTH 8192


PlaybackFileBoard::PlaybackFileBoard (struct BrainFlowInputParams params)
Expand All @@ -29,7 +32,8 @@ PlaybackFileBoard::PlaybackFileBoard (struct BrainFlowInputParams params)
loopback = false;
initialized = false;
use_new_timestamps = true;
this->state = (int)BrainFlowExitCodes::SYNC_TIMEOUT_ERROR;
pos_percentage.resize (3);
std::fill (pos_percentage.begin (), pos_percentage.end (), -1);
}

PlaybackFileBoard::~PlaybackFileBoard ()
Expand All @@ -45,6 +49,7 @@ int PlaybackFileBoard::prepare_session ()
safe_logger (spdlog::level::info, "Session is already prepared");
return (int)BrainFlowExitCodes::STATUS_OK;
}

if (params.master_board == (int)BoardIds::NO_BOARD)
{
safe_logger (spdlog::level::err, "master board id is not provided");
Expand All @@ -69,6 +74,46 @@ int PlaybackFileBoard::prepare_session ()
return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR;
}

if (!params.file.empty ())
{
std::vector<long int> offsets;
int res = get_file_offsets (params.file, offsets);
if (res != (int)BrainFlowExitCodes::STATUS_OK)
{
return res;
}
else
{
file_offsets.push_back (offsets);
}
}
if (!params.file_aux.empty ())
{
std::vector<long int> offsets;
int res = get_file_offsets (params.file_aux, offsets);
if (res != (int)BrainFlowExitCodes::STATUS_OK)
{
return res;
}
else
{
file_offsets.push_back (offsets);
}
}
if (!params.file_anc.empty ())
{
std::vector<long int> offsets;
int res = get_file_offsets (params.file_anc, offsets);
if (res != (int)BrainFlowExitCodes::STATUS_OK)
{
return res;
}
else
{
file_offsets.push_back (offsets);
}
}

initialized = true;
return (int)BrainFlowExitCodes::STATUS_OK;
}
Expand Down Expand Up @@ -104,20 +149,8 @@ int PlaybackFileBoard::start_stream (int buffer_size, const char *streamer_param
streaming_threads.push_back (std::thread ([this]
{ this->read_thread ((int)BrainFlowPresets::ANCILLARY_PRESET, params.file_anc); }));
}
// wait for data to ensure that everything is okay
std::unique_lock<std::mutex> lk (this->m);
auto sec = std::chrono::seconds (1);
if (cv.wait_for (lk, 2 * sec,
[this] { return this->state != (int)BrainFlowExitCodes::SYNC_TIMEOUT_ERROR; }))
{
return this->state;
}
else
{
safe_logger (spdlog::level::err, "no data received in 2sec, stopping thread");
this->stop_stream ();
return (int)BrainFlowExitCodes::SYNC_TIMEOUT_ERROR;
}

return (int)BrainFlowExitCodes::STATUS_OK;
}

int PlaybackFileBoard::stop_stream ()
Expand All @@ -130,7 +163,6 @@ int PlaybackFileBoard::stop_stream ()
streaming_thread.join ();
}
streaming_threads.clear ();
this->state = (int)BrainFlowExitCodes::SYNC_TIMEOUT_ERROR;
return (int)BrainFlowExitCodes::STATUS_OK;
}
else
Expand All @@ -147,6 +179,7 @@ int PlaybackFileBoard::release_session ()
free_packages ();
initialized = false;
}
file_offsets.clear ();
return (int)BrainFlowExitCodes::STATUS_OK;
}

Expand All @@ -160,7 +193,7 @@ void PlaybackFileBoard::read_thread (int preset, std::string file)
}

FILE *fp;
fp = fopen (file.c_str (), "r");
fp = fopen (file.c_str (), "rb");
if (fp == NULL)
{
safe_logger (spdlog::level::err, "failed to open file in thread");
Expand All @@ -174,7 +207,7 @@ void PlaybackFileBoard::read_thread (int preset, std::string file)
{
package[i] = 0.0;
}
char buf[4096];
char buf[MAX_LINE_LENGTH];
double last_timestamp = -1.0;
bool new_timestamps = use_new_timestamps; // to prevent changing during streaming
int timestamp_channel = board_preset["timestamp_channel"];
Expand All @@ -183,6 +216,26 @@ void PlaybackFileBoard::read_thread (int preset, std::string file)
while (keep_alive)
{
auto start = std::chrono::high_resolution_clock::now ();
// prevent race condition with another config_board method call
lock.lock ();
double cur_index = pos_percentage[preset];
if ((int)cur_index >= 0)
{
int new_pos = (int)(cur_index * (file_offsets[preset].size () / 100.0));
try
{
fseek (fp, file_offsets[preset][new_pos], SEEK_SET);
safe_logger (spdlog::level::trace, "set position in a file to {}", new_pos);
}
catch (...)
{
// should never happen since input is already validated
safe_logger (spdlog::level::warn, "invalid position in a file");
}
last_timestamp = -1;
pos_percentage[preset] = -1;
}
lock.unlock ();
char *res = fgets (buf, sizeof (buf), fp);
if ((loopback) && (res == NULL))
{
Expand Down Expand Up @@ -226,16 +279,14 @@ void PlaybackFileBoard::read_thread (int preset, std::string file)
}
for (int i = 0; i < num_rows; i++)
{
package[i] = std::stod (splitted[i]);
}
// notify main thread
if (this->state != (int)BrainFlowExitCodes::STATUS_OK)
{
try
{
package[i] = std::stod (splitted[i]);
}
catch (...)
{
std::lock_guard<std::mutex> lk (this->m);
this->state = (int)BrainFlowExitCodes::STATUS_OK;
safe_logger (spdlog::level::err, "failed to parse value: {}", splitted[i].c_str ());
}
this->cv.notify_one ();
}
if (last_timestamp > 0)
{
Expand Down Expand Up @@ -284,10 +335,69 @@ int PlaybackFileBoard::config_board (std::string config, std::string &response)
{
use_new_timestamps = false;
}
else if (strncmp (config.c_str (), SET_INDEX_PREFIX, strlen (SET_INDEX_PREFIX)) == 0)
{
try
{
double new_index = std::stod (config.substr (strlen (SET_INDEX_PREFIX)));
if (((int)new_index >= 0) && ((int)new_index < 100))
{
lock.lock ();
std::fill (pos_percentage.begin (), pos_percentage.end (), new_index);
lock.unlock ();
}
else
{
safe_logger (
spdlog::level::err, "invalid index value, should be between 0 and 100");
return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR;
}
}
catch (const std::exception &e)
{
safe_logger (spdlog::level::err, "need to write a number after {}, exception is: {}",
SET_INDEX_PREFIX, e.what ());
return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR;
}
}
else
{
safe_logger (spdlog::level::warn, "invalid config string {}", config);
}

return (int)BrainFlowExitCodes::STATUS_OK;
}

int PlaybackFileBoard::get_file_offsets (std::string filename, std::vector<long int> &offsets)
{
offsets.clear ();

FILE *fp = fopen (filename.c_str (), "rb");
if (fp == NULL)
{
safe_logger (spdlog::level::err, "failed to open file: {}", filename.c_str ());
return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR;
}

char buf[MAX_LINE_LENGTH];
long int bytes_read = 0;
while (true)
{
offsets.push_back (bytes_read);
char *res = fgets (buf, sizeof (buf), fp);
bytes_read += (long int)strlen (buf);
if (res == NULL)
{
break;
}
}

fclose (fp);
if (offsets.size () < 2)
{
safe_logger (spdlog::level::err, "empty file: {}", filename);
return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR;
}

return (int)BrainFlowExitCodes::STATUS_OK;
}
18 changes: 9 additions & 9 deletions src/board_controller/synthetic_board.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,41 +194,41 @@ void SyntheticBoard::read_thread ()
aux_package[channel] = (double)channel;
}
aux_package[board_descr["auxiliary"]["timestamp_channel"].get<int> ()] = get_timestamp ();
package[board_descr["auxiliary"]["package_num_channel"].get<int> ()] = (double)counter;
package[board_descr["auxiliary"]["battery_channel"].get<int> ()] =
aux_package[board_descr["auxiliary"]["package_num_channel"].get<int> ()] = (double)counter;
aux_package[board_descr["auxiliary"]["battery_channel"].get<int> ()] =
(dist_around_one (mt) - 0.1) * 100;
for (int channel : board_descr["auxiliary"]["accel_channels"])
{
package[channel] = dist_around_one (mt) - 0.1;
aux_package[channel] = dist_around_one (mt) - 0.1;
}
for (int channel : board_descr["auxiliary"]["gyro_channels"])
{
package[channel] = dist_around_one (mt) - 0.1;
aux_package[channel] = dist_around_one (mt) - 0.1;
}
for (int channel : board_descr["auxiliary"]["eda_channels"])
{
package[channel] = dist_around_one (mt);
aux_package[channel] = dist_around_one (mt);
}
for (int chan_num = 0; chan_num < (int)board_descr["auxiliary"]["ppg_channels"].size ();
chan_num++)
{
int channel = board_descr["auxiliary"]["ppg_channels"][chan_num];
if (chan_num == 0)
{
package[channel] = 500.0 * dist_around_one (mt);
aux_package[channel] = 500.0 * dist_around_one (mt);
}
else
{
package[channel] = 253500.0 * dist_around_one (mt);
aux_package[channel] = 253500.0 * dist_around_one (mt);
}
}
for (int channel : board_descr["auxiliary"]["temperature_channels"])
{
package[channel] = dist_around_one (mt) / 10.0 + 36.5;
aux_package[channel] = dist_around_one (mt) / 10.0 + 36.5;
}
for (int channel : board_descr["auxiliary"]["resistance_channels"])
{
package[channel] = 1000.0 * dist_around_one (mt);
aux_package[channel] = 1000.0 * dist_around_one (mt);
}

push_package (aux_package, (int)BrainFlowPresets::AUXILIARY_PRESET);
Expand Down
1 change: 0 additions & 1 deletion src/ml/train/train_classifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import numpy as np
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
from sklearn.gaussian_process import GaussianProcessClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import StackingClassifier
from sklearn.neighbors import KNeighborsClassifier
Expand Down

0 comments on commit b3b1896

Please sign in to comment.