Skip to content
Merged
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
30 changes: 30 additions & 0 deletions TestConcoreHpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,20 @@ static void test_read_FM_missing_file_uses_initstr() {
check("missing_file fallback val==3.0", approx(v[0], 3.0));
}

static void test_read_result_missing_file_status() {
setup_dirs();
rm("in1/no_port_status");

Concore c;
c.delay = 0;
c.simtime = 0.0;

Concore::ReadResult r = c.read_result(1, "no_port_status", "[9.0,3.0]");
check("read_result missing status FILE_NOT_FOUND",
r.status == Concore::ReadStatus::FILE_NOT_FOUND);
check("read_result missing uses initstr", r.data.size() == 1 && approx(r.data[0], 3.0));
}

// ------------- write_FM --------------------------------------------------

static void test_write_FM_creates_file() {
Expand Down Expand Up @@ -274,6 +288,20 @@ static void test_tryparam_missing_key_uses_default() {
c.tryparam("no_key", "def_val") == "def_val");
}

static void test_load_params_semicolon_format() {
setup_dirs();
write_file("in/1/concore.params", "a=1;b=2");

Concore c;
c.delay = 0;
c.load_params();

check("load_params semicolon parses a", c.tryparam("a", "") == "1");
check("load_params semicolon parses b", c.tryparam("b", "") == "2");

rm("in/1/concore.params");
}

// ------------- main -------------------------------------------------------

int main() {
Expand All @@ -282,6 +310,7 @@ int main() {
// read_FM / write_FM
test_read_FM_file();
test_read_FM_missing_file_uses_initstr();
test_read_result_missing_file_status();
test_write_FM_creates_file();

// unchanged()
Expand All @@ -307,6 +336,7 @@ int main() {
// tryparam()
test_tryparam_found();
test_tryparam_missing_key_uses_default();
test_load_params_semicolon_format();

std::cout << "\n=== Results: " << passed << " passed, " << failed
<< " failed out of " << (passed + failed) << " tests ===\n";
Expand Down
80 changes: 74 additions & 6 deletions concore.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,27 @@ class Concore{
#endif

public:
enum class ReadStatus {
SUCCESS,
TIMEOUT,
PARSE_ERROR,
FILE_NOT_FOUND,
RETRIES_EXCEEDED
};

struct ReadResult {
ReadStatus status;
vector<double> data;
};

double delay = 1;
int retrycount = 0;
double simtime;
int maxtime = 100;
map <string, int> iport;
map <string, int> oport;
map <string, string> params;
ReadStatus last_read_status = ReadStatus::SUCCESS;

/**
* @brief Constructor for Concore class.
Expand Down Expand Up @@ -372,6 +386,14 @@ class Concore{
return read_FM(port, name, initstr);
}

ReadResult read_result(int port, string name, string initstr)
{
ReadResult result;
result.data = read(port, name, initstr);
result.status = last_read_status;
return result;
}

/**
* @brief Reads data from a specified port and name using the FM (File Method) communication protocol.
* @param port The port number.
Expand All @@ -383,6 +405,7 @@ class Concore{
chrono::milliseconds timespan((int)(1000*delay));
this_thread::sleep_for(timespan);
string ins;
ReadStatus status = ReadStatus::SUCCESS;
try {
ifstream infile;
infile.open(inpath+to_string(port)+"/"+name, ios::in);
Expand All @@ -393,10 +416,13 @@ class Concore{
infile.close();
}
else {
status = ReadStatus::FILE_NOT_FOUND;
throw 505;}
}
catch (...) {
ins = initstr;
if (status == ReadStatus::SUCCESS)
status = ReadStatus::FILE_NOT_FOUND;
}

int retry = 0;
Expand Down Expand Up @@ -424,14 +450,24 @@ class Concore{
}
retry++;
}
if ((int)ins.length()==0)
status = ReadStatus::RETRIES_EXCEEDED;
s += ins;

vector<double> inval = parser(ins);
if(inval.empty())
if(inval.empty()) {
if (status == ReadStatus::SUCCESS)
status = ReadStatus::PARSE_ERROR;
inval = parser(initstr);
if(inval.empty())
}
if(inval.empty()) {
if (status == ReadStatus::SUCCESS)
status = ReadStatus::PARSE_ERROR;
last_read_status = status;
return inval;
}
simtime = simtime > inval[0] ? simtime : inval[0];
last_read_status = status;

//returning a string with data excluding simtime
inval.erase(inval.begin());
Expand All @@ -450,6 +486,7 @@ class Concore{
chrono::milliseconds timespan((int)(1000*delay));
this_thread::sleep_for(timespan);
string ins = "";
ReadStatus status = ReadStatus::SUCCESS;
try {
if (shmId_get != -1) {
if (sharedData_get && sharedData_get[0] != '\0') {
Expand All @@ -463,10 +500,13 @@ class Concore{
}
else
{
status = ReadStatus::FILE_NOT_FOUND;
throw 505;
}
} catch (...) {
ins = initstr;
if (status == ReadStatus::SUCCESS)
status = ReadStatus::FILE_NOT_FOUND;
}

int retry = 0;
Expand All @@ -490,14 +530,24 @@ class Concore{
}
retry++;
}
if ((int)ins.length()==0)
status = ReadStatus::RETRIES_EXCEEDED;
s += ins;

vector<double> inval = parser(ins);
if(inval.empty())
if(inval.empty()) {
if (status == ReadStatus::SUCCESS)
status = ReadStatus::PARSE_ERROR;
inval = parser(initstr);
if(inval.empty())
}
if(inval.empty()) {
if (status == ReadStatus::SUCCESS)
status = ReadStatus::PARSE_ERROR;
last_read_status = status;
return inval;
}
simtime = simtime > inval[0] ? simtime : inval[0];
last_read_status = status;

//returning a string with data excluding simtime
inval.erase(inval.begin());
Expand Down Expand Up @@ -674,15 +724,26 @@ class Concore{
* @return a vector of double values
*/
vector<double> read_ZMQ(string port_name, string name, string initstr) {
ReadStatus status = ReadStatus::SUCCESS;
auto it = zmq_ports.find(port_name);
if (it == zmq_ports.end()) {
cerr << "read_ZMQ: port '" << port_name << "' not initialized" << endl;
status = ReadStatus::FILE_NOT_FOUND;
last_read_status = status;
return parser(initstr);
}
vector<double> inval = it->second->recv_with_retry();
if (inval.empty())
if (inval.empty()) {
status = ReadStatus::TIMEOUT;
inval = parser(initstr);
if (inval.empty()) return inval;
}
if (inval.empty()) {
if (status == ReadStatus::SUCCESS)
status = ReadStatus::PARSE_ERROR;
last_read_status = status;
return inval;
}
last_read_status = status;
simtime = simtime > inval[0] ? simtime : inval[0];
s += port_name;
inval.erase(inval.begin());
Expand Down Expand Up @@ -736,6 +797,13 @@ class Concore{
return read_ZMQ(port_name, name, initstr);
}

ReadResult read_result(string port_name, string name, string initstr) {
ReadResult result;
result.data = read(port_name, name, initstr);
result.status = last_read_status;
return result;
}

/**
* @brief deviate the write to ZMQ communication protocol when port identifier is a string key.
* @param port_name The ZMQ port name.
Expand Down
3 changes: 2 additions & 1 deletion concore_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,10 +345,11 @@ inline std::map<std::string, std::string> load_params(const std::string& params_

// Otherwise convert semicolon-separated key=value to dict format
// e.g. "a=1;b=2" -> {"a":"1","b":"2"}
std::string normalized = std::regex_replace(sparams, std::regex(";"), ",");
std::string converted = "{\"" +
std::regex_replace(
std::regex_replace(
std::regex_replace(sparams, std::regex(","), ",\""),
std::regex_replace(normalized, std::regex(","), ",\""),
std::regex("="), "\":"),
std::regex(" "), "") +
"}";
Expand Down
Loading
Loading