Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions include/BetterSerialPlotter/BSP.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class BSP : public mahi::gui::Application
// std::vector<std::string> data_names;
// std::vector<ImVec4> data_colors;

std::unordered_map<char,DataInfo> all_data_info;
std::unordered_map<std::string,DataInfo> all_data_info;

// HANDLE hSerial;

Expand Down Expand Up @@ -76,12 +76,13 @@ class BSP : public mahi::gui::Application
~BSP();
void update();
/// returns an optional reference wrapper to a scrolling data object. This returns the data corresponding to the requested identifier if available, or nullopt otherwise
std::optional<std::reference_wrapper<ScrollingData>> get_data(char identifier);
std::optional<std::reference_wrapper<ScrollingData>> get_data(std::string identifier);
/// appends the vector of current data to the current data set. Need to make sure that this is working for any size of data
void append_all_data(std::vector<float> curr_data);
void append_all_data(std::vector<NamedSerialData> curr_data);

std::string get_name(char identifier);
ImVec4 get_color(char identifier);
std::string get_name(std::string identifier);
ImVec4 get_color(std::string identifier);

void serialize();
void deserialize();
Expand Down
14 changes: 7 additions & 7 deletions include/BetterSerialPlotter/Plot.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@ class Plot
/// actually plots the data that goes on the plot
void plot_data();
/// adds a unique identifier to this plot, adding the variable to the dsiplay
void add_identifier(char identifier, int y_axis_num = 0);
void add_identifier(std::string identifier, int y_axis_num = 0);
/// removes a unique identifier to this plot, removing the variable from the display
void remove_identifier(char identifier);
void remove_identifier(std::string identifier);
/// checks if a unique identifier is used on this plot
bool has_identifier(char identifier) const;
bool has_identifier(std::string identifier) const;
/// sets all_plot_paused_data and paused_x_axis to current data
void update_paused_data();
/// returns the data corresponding to a specific identifier
std::optional<std::reference_wrapper<ScrollingData>> get_data(char identifier);
std::optional<std::reference_wrapper<ScrollingData>> get_data(std::string identifier);
/// vector of all identifiers for this plot
std::vector<char> all_plot_data;
std::vector<std::string> all_plot_data;

/// saved paused data for all variables on this plot
std::vector<ScrollingData> all_plot_paused_data;

bool other_x_axis = false; // indicates that x-axis for this plot is something other than this program time
bool x_axis_realtime = true; // indicates that x-axis for this plot corresponds to something realtime, meaning that we want it to scroll with the
char x_axis = -1;
std::string x_axis = "-1";
ScrollingData paused_x_axis;
std::unordered_map<char,int> y_axis;
std::unordered_map<std::string,int> y_axis;
bool is_resizing = false;
float time_frame = 10.0f;
float paused_x_axis_modifier = 0.1f;
Expand Down
7 changes: 5 additions & 2 deletions include/BetterSerialPlotter/SerialManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <BetterSerialPlotter/Widget.hpp>
#include <Mahi/Com/SerialPort.hpp>
#include <mutex>
#include "Utility.hpp"

namespace bsp{

Expand Down Expand Up @@ -65,8 +66,10 @@ class SerialManager : public Widget
std::string get_port_name(BspPort port_num);
/// parses a buffer received from a serial port read
void parse_buffer(unsigned char* message, size_t buff_len);
/// parses a single line received from the buffer
std::vector<float> parse_line(std::string line);
/// parses a single line with unnamed data received from the buffer
std::vector<float> parse_unnamed_data_line(std::string line);
/// parses a single line with named data received from the buffer
std::vector<NamedSerialData> parse_named_data_line(std::string line);

bool comport_valid();

Expand Down
2 changes: 1 addition & 1 deletion include/BetterSerialPlotter/Serialization.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ struct BSPData{
std::vector<ScrollingData> all_data;
SerialManager serial_manager;
PlotMonitor plot_monitor;
std::unordered_map<char,DataInfo> all_data_info;
std::unordered_map<std::string,DataInfo> all_data_info;
};

// all of these need to be in the bsp namespace because the to_json
Expand Down
9 changes: 7 additions & 2 deletions include/BetterSerialPlotter/Utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace bsp{

// data structure to handle a single variable coming in from serial
struct ScrollingData {
char identifier = 0; // unique identifier that can be used to pull this data
std::string identifier; // unique identifier that can be used to pull this data
int MaxSize = 5000; // maximum amount of data points that will be stored
int Offset = 0; // offset to handle plotting
ImVector<ImVec2> Data; // vector of x and y data. X data always is time
Expand Down Expand Up @@ -58,7 +58,7 @@ struct ScrollingData {
}

/// set the identifier
void set_identifier(char identifier){identifier = identifier;}
void set_identifier(std::string identifier){identifier = identifier;}
};

struct DataInfo {
Expand All @@ -71,6 +71,11 @@ struct DataInfo {
void set_identifier(char identifier){identifier = identifier;}
};

struct NamedSerialData {
std::string name;
float data;
};

// void plot_data(const ScrollingData &data, int i);
#ifdef __APPLE__
std::vector<std::string> get_serial_ports();
Expand Down
82 changes: 63 additions & 19 deletions src/BetterSerialPlotter/BSP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,34 +102,78 @@ void BSP::append_all_data(std::vector<float> curr_data){
// std::cout << "begin append\n";
std::lock_guard<std::mutex> lock(serial_manager.mtx);

auto old_size = mutexed_all_data.size();
if (old_size != curr_data.size()){
if (old_size < curr_data.size()){
for (int i = old_size; i < curr_data.size(); i++){
mutexed_all_data.emplace_back();
mutexed_all_data[i].identifier = old_size+i;
if (all_data_info.find(mutexed_all_data[i].identifier) == all_data_info.end()){
all_data_info[mutexed_all_data[i].identifier].set_name("data " + std::to_string(i));
all_data_info[mutexed_all_data[i].identifier].color = plot_colors[i%plot_colors.size()];
}
}
}
else{
for (auto i = old_size-1; i > old_size - curr_data.size(); i--){
mutexed_all_data.erase(mutexed_all_data.begin()+i);
int old_unnamed_data_count = std::count_if(
mutexed_all_data.begin(),
mutexed_all_data.end(),
[](const ScrollingData& element) {
return element.identifier.rfind("unnamed ", 0) == 0;
});

if (old_unnamed_data_count < curr_data.size()){
for (int i = old_unnamed_data_count; i < curr_data.size(); i++){
ScrollingData new_data;
std::string new_identifier = "unnamed " + std::to_string(i);
new_data.identifier = new_identifier;

mutexed_all_data.emplace_back(new_data);
if (all_data_info.find(new_identifier) == all_data_info.end()){
all_data_info[new_identifier].set_name("data " + std::to_string(i));
all_data_info[new_identifier].color = plot_colors[i%plot_colors.size()];
}
}
}

float curr_time = static_cast<float>(program_clock.get_elapsed_time().as_seconds());

for (auto i = 0; i < curr_data.size(); i++){
mutexed_all_data[i].AddPoint(curr_time, curr_data[i]);
std::string identifier = "unnamed " + std::to_string(i);

auto data_element = std::find_if(
mutexed_all_data.begin(),
mutexed_all_data.end(),
[&identifier](const ScrollingData& element) {
return element.identifier == identifier;
});

data_element->AddPoint(curr_time, curr_data[i]);
}
// std::cout << "end append\n";
}

std::optional<std::reference_wrapper<ScrollingData>> BSP::get_data(char identifier){
void BSP::append_all_data(std::vector<NamedSerialData> curr_data){
// std::cout << "begin append\n";
std::lock_guard<std::mutex> lock(serial_manager.mtx);

float curr_time = static_cast<float>(program_clock.get_elapsed_time().as_seconds());

for (const auto& data : curr_data) {
std::string identifier = "named " + data.name;

auto data_element = std::find_if(
mutexed_all_data.begin(),
mutexed_all_data.end(),
[&identifier](const ScrollingData& element) {
return element.identifier == identifier;
});

if (data_element == mutexed_all_data.end()) {
ScrollingData new_data;
new_data.identifier = identifier;

mutexed_all_data.emplace_back(new_data);
if (all_data_info.find(identifier) == all_data_info.end()){
all_data_info[identifier].set_name(data.name);
all_data_info[identifier].color = plot_colors[mutexed_all_data.size() % plot_colors.size()];
}

new_data.AddPoint(curr_time, data.data);
} else {
data_element->AddPoint(curr_time, data.data);
}
}
}

std::optional<std::reference_wrapper<ScrollingData>> BSP::get_data(std::string identifier){
for (auto &data : all_data){
if (data.identifier == identifier){
return data;
Expand All @@ -139,12 +183,12 @@ std::optional<std::reference_wrapper<ScrollingData>> BSP::get_data(char identifi
return std::nullopt; //ScrollingData();
}

std::string BSP::get_name(char identifier){
std::string BSP::get_name(std::string identifier){
auto found_it = all_data_info.find(identifier);
return (found_it != all_data_info.end()) ? found_it->second.name : "";
}

ImVec4 BSP::get_color(char identifier){
ImVec4 BSP::get_color(std::string identifier){
auto found_it = all_data_info.find(identifier);
return (found_it != all_data_info.end()) ? found_it->second.color : ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
}
Expand Down
8 changes: 4 additions & 4 deletions src/BetterSerialPlotter/Plot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ void Plot::plot_data(){

}

void Plot::add_identifier(char identifier, int y_axis_num){
void Plot::add_identifier(std::string identifier, int y_axis_num){
bool exists = false;
// check if it is already there
for (const auto &i : all_plot_data){
Expand All @@ -282,7 +282,7 @@ void Plot::add_identifier(char identifier, int y_axis_num){
y_axis[identifier] = y_axis_num;
}

void Plot::remove_identifier(char identifier){
void Plot::remove_identifier(std::string identifier){
// look for the identifier in the identifiers vector
for (auto i = all_plot_data.begin(); i != all_plot_data.end(); i++){
if (*i == identifier) {
Expand All @@ -300,14 +300,14 @@ void Plot::remove_identifier(char identifier){
}
}

bool Plot::has_identifier(char identifier) const{
bool Plot::has_identifier(std::string identifier) const{
for (const auto &data : all_plot_data){
if (data == identifier) return true;
}
return false;
}

std::optional<std::reference_wrapper<ScrollingData>> Plot::get_data(char identifier){
std::optional<std::reference_wrapper<ScrollingData>> Plot::get_data(std::string identifier){
return plot_monitor->gui->get_data(identifier);
}

Expand Down
66 changes: 59 additions & 7 deletions src/BetterSerialPlotter/SerialManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,23 +151,43 @@ void SerialManager::read_serial(){
}

void SerialManager::parse_buffer(unsigned char* buff, size_t buff_len){
const std::regex unnamed_data_regex(
"^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?([ \t][-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?)*$"
);

const std::regex named_data_regex(
"^([a-zA-Z_][a-zA-Z0-9_]*:[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?)([ \t,][a-zA-Z_][a-zA-Z0-9_]*:[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?)*$"
);

for (size_t i = 0; i < buff_len; i++){
// if we got a newline character, (0x0a)
if (buff[i] == 0x0a){
// if we haven't run through once, just note that, and
// if we haven't run through once, just note that, and
// then return to make sure we have clean data
if (!read_once){
read_once = true;
curr_line_buff.clear();
}
// if we have run through once, send the full line to be parsed
else{
std::vector<float> curr_data = parse_line(curr_line_buff);
gui->append_all_data(curr_data);
// Parse as unnamed data if regex matches
if (std::regex_match(curr_line_buff, unnamed_data_regex)){
std::vector<float> curr_data = parse_unnamed_data_line(curr_line_buff);
gui->append_all_data(curr_data);

{
std::lock_guard<std::mutex> lock(mtx);
gui->PrintBuffer.push_back(curr_line_buff);
}
}
else if (std::regex_match(curr_line_buff, named_data_regex)){
std::vector<NamedSerialData> curr_data = parse_named_data_line(curr_line_buff);
gui->append_all_data(curr_data);

{
std::lock_guard<std::mutex> lock(mtx);
gui->PrintBuffer.push_back(curr_line_buff);
{
std::lock_guard<std::mutex> lock(mtx);
gui->PrintBuffer.push_back(curr_line_buff);
}
}
curr_line_buff.clear();
if (gui->verbose) std::cout << std::endl;
Expand All @@ -185,7 +205,7 @@ void SerialManager::parse_buffer(unsigned char* buff, size_t buff_len){
}
}

std::vector<float> SerialManager::parse_line(std::string line){
std::vector<float> SerialManager::parse_unnamed_data_line(std::string line){
// std::cout << line << "\n";

std::vector<float> curr_data;
Expand Down Expand Up @@ -222,6 +242,38 @@ std::vector<float> SerialManager::parse_line(std::string line){
return curr_data;
}

std::vector<NamedSerialData> SerialManager::parse_named_data_line(std::string line) {
std::vector<NamedSerialData> curr_data;

// Regex for splitting the line by spaces, tabs, or commas
static const std::regex re_delims("[ \t,]+");
// Regex for matching the name:float pattern
static const std::regex re_named_fp_num("([a-zA-Z_][a-zA-Z0-9_]*):([-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?)");

std::sregex_token_iterator first{line.begin(), line.end(), re_delims, -1}, last;
std::vector<std::string> name_data_pairs{first, last};

for (const auto &name_data_pair : name_data_pairs) {
std::smatch match;
if (std::regex_match(name_data_pair, match, re_named_fp_num)) {
try {
NamedSerialData named_data;
named_data.name = match[1].str();
named_data.data = std::stof(match[2].str());
curr_data.push_back(named_data);
}
catch(const std::exception &e) {
std::cerr << "Error: " << e.what() << "\n";
}
baud_status = true;
} else {
std::cerr << "Invalid pair: " << name_data_pair << "\n";
}
}

return curr_data;
}

std::string SerialManager::get_port_name(BspPort port_num){
#if defined(WIN32)
return "COM" + std::to_string(port_num + 1);
Expand Down
Loading