mirror of
https://github.com/nasa/trick.git
synced 2024-12-20 05:37:55 +00:00
Parser and test for var_binary (#1425)
This commit is contained in:
parent
a8daf4514c
commit
97cf685b6a
3
.gitignore
vendored
3
.gitignore
vendored
@ -38,3 +38,6 @@ server.pem
|
|||||||
archive/
|
archive/
|
||||||
.venv
|
.venv
|
||||||
trickops_logs/
|
trickops_logs/
|
||||||
|
*.gcda
|
||||||
|
*.gcno
|
||||||
|
coverage.info
|
22
Makefile
22
Makefile
@ -96,13 +96,16 @@ UTILS_DIRS := \
|
|||||||
${TRICK_HOME}/trick_source/trick_utils/shm \
|
${TRICK_HOME}/trick_source/trick_utils/shm \
|
||||||
${TRICK_HOME}/trick_source/trick_utils/math \
|
${TRICK_HOME}/trick_source/trick_utils/math \
|
||||||
${TRICK_HOME}/trick_source/trick_utils/units \
|
${TRICK_HOME}/trick_source/trick_utils/units \
|
||||||
${TRICK_HOME}/trick_source/trick_utils/unicode
|
${TRICK_HOME}/trick_source/trick_utils/unicode \
|
||||||
|
${TRICK_HOME}/trick_source/trick_utils/var_binary_parser
|
||||||
|
|
||||||
UTILS_OBJS := $(addsuffix /object_$(TRICK_HOST_CPU)/*.o ,$(UTILS_DIRS))
|
UTILS_OBJS := $(addsuffix /object_$(TRICK_HOST_CPU)/*.o ,$(UTILS_DIRS))
|
||||||
|
|
||||||
# filter out the directories that make their own libraries
|
# filter out the directories that make their own libraries
|
||||||
UTILS_OBJS := $(filter-out ${TRICK_HOME}/trick_source/trick_utils/comm/%, $(UTILS_OBJS))
|
UTILS_OBJS := $(filter-out ${TRICK_HOME}/trick_source/trick_utils/comm/%, $(UTILS_OBJS))
|
||||||
UTILS_OBJS := $(filter-out ${TRICK_HOME}/trick_source/trick_utils/math/%, $(UTILS_OBJS))
|
UTILS_OBJS := $(filter-out ${TRICK_HOME}/trick_source/trick_utils/math/%, $(UTILS_OBJS))
|
||||||
UTILS_OBJS := $(filter-out ${TRICK_HOME}/trick_source/trick_utils/units/%, $(UTILS_OBJS))
|
UTILS_OBJS := $(filter-out ${TRICK_HOME}/trick_source/trick_utils/units/%, $(UTILS_OBJS))
|
||||||
|
UTILS_OBJS := $(filter-out ${TRICK_HOME}/trick_source/trick_utils/var_binary_parser/%, $(UTILS_OBJS))
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
# Specify the contents of: libtrick_pyip.a
|
# Specify the contents of: libtrick_pyip.a
|
||||||
@ -306,9 +309,20 @@ sim_test:
|
|||||||
pytest:
|
pytest:
|
||||||
make -C share/trick/pymods/trick
|
make -C share/trick/pymods/trick
|
||||||
|
|
||||||
code-coverage: test
|
COVERAGE_DIRS = trick_source/sim_services \
|
||||||
lcov --capture --directory trick_source/sim_services --output-file coverage_large.info
|
trick_source/trick_utils/var_binary_parser \
|
||||||
lcov --remove coverage_large.info '/Library/*' '/usr/*' '*/io_src/*' '*/test/*' -o coverage.info
|
trick_source/trick_utils/unicode \
|
||||||
|
trick_source/trick_utils/units \
|
||||||
|
trick_source/trick_utils/interpolator \
|
||||||
|
trick_source/trick_utils/comm \
|
||||||
|
trick_source/trick_utils/SAIntegrator
|
||||||
|
|
||||||
|
extra-coverage-builds:
|
||||||
|
@ $(MAKE) test -C trick_source/trick_utils/SAIntegrator
|
||||||
|
|
||||||
|
code-coverage: test extra-coverage-builds
|
||||||
|
lcov --capture $(addprefix --directory , $(COVERAGE_DIRS)) --output-file coverage_large.info
|
||||||
|
lcov --remove coverage_large.info '/Library/*' '/usr/*' '*/io_src/*' '*/test/*' '*/unittest/*' -o coverage.info
|
||||||
rm coverage_large.info
|
rm coverage_large.info
|
||||||
lcov --list coverage.info
|
lcov --list coverage.info
|
||||||
|
|
||||||
|
120
include/trick/var_binary_parser.hh
Normal file
120
include/trick/var_binary_parser.hh
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
#include "trick/parameter_types.h"
|
||||||
|
|
||||||
|
class IncorrectUsageException : public std::exception
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::string _message;
|
||||||
|
public:
|
||||||
|
IncorrectUsageException(std::string msg) : _message(msg) {}
|
||||||
|
const char * what() const noexcept override { return _message.c_str(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ParseTypeException : public IncorrectUsageException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ParseTypeException() : IncorrectUsageException("Mismatched trick type and template call") {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class MalformedMessageException : public std::exception
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::string _message;
|
||||||
|
public:
|
||||||
|
MalformedMessageException() : _message("Attempted to parse an incorrectly formed message") {}
|
||||||
|
MalformedMessageException(std::string msg) : _message(msg) {}
|
||||||
|
const char * what() const noexcept override { return _message.c_str(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef union Number {
|
||||||
|
unsigned char raw_bytes[sizeof(long long)]; // Raw bytes
|
||||||
|
|
||||||
|
uint8_t unsigned_char_val;
|
||||||
|
int8_t char_val;
|
||||||
|
bool bool_val;
|
||||||
|
|
||||||
|
wchar_t wchar_val;
|
||||||
|
uint16_t unsigned_short_val;
|
||||||
|
int16_t short_val;
|
||||||
|
|
||||||
|
uint32_t unsigned_int_val;
|
||||||
|
int32_t int_val;
|
||||||
|
|
||||||
|
uint64_t unsigned_long_val;
|
||||||
|
int64_t long_val;
|
||||||
|
|
||||||
|
unsigned long long unsigned_long_long_val;
|
||||||
|
long long long_long_val;
|
||||||
|
|
||||||
|
float float_val;
|
||||||
|
double double_val;
|
||||||
|
} Number;
|
||||||
|
|
||||||
|
|
||||||
|
class Var {
|
||||||
|
public:
|
||||||
|
Var () : _has_name(false) {};
|
||||||
|
void setValue(const std::vector<unsigned char>& bytes, size_t size, TRICK_TYPE type, bool byteswap = false);
|
||||||
|
void setName(size_t name_size, const std::vector<unsigned char>& name_data);
|
||||||
|
|
||||||
|
// The closest to runtime return type polymorphism that I can think of
|
||||||
|
// There won't be a general case
|
||||||
|
template <typename T>
|
||||||
|
T getValue() const;
|
||||||
|
|
||||||
|
std::string getName() const;
|
||||||
|
TRICK_TYPE getType() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<unsigned char> value_bytes;
|
||||||
|
Number getInterpreter () const;
|
||||||
|
|
||||||
|
bool _has_name;
|
||||||
|
unsigned int _name_length;
|
||||||
|
std::string _name;
|
||||||
|
|
||||||
|
bool _byteswap;
|
||||||
|
|
||||||
|
TRICK_TYPE _trick_type;
|
||||||
|
unsigned int _var_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ParsedBinaryMessage {
|
||||||
|
public:
|
||||||
|
ParsedBinaryMessage() : _byteswap(false), _nonames(false) {}
|
||||||
|
ParsedBinaryMessage (bool byteswap, bool nonames) : _byteswap(byteswap), _nonames(nonames) {}
|
||||||
|
|
||||||
|
void combine (const ParsedBinaryMessage& message);
|
||||||
|
|
||||||
|
int parse (const std::vector<unsigned char>& bytes);
|
||||||
|
|
||||||
|
int getMessageType() const;
|
||||||
|
unsigned int getMessageSize() const;
|
||||||
|
unsigned int getNumVars() const;
|
||||||
|
Var getVariable(const std::string& name);
|
||||||
|
Var getVariable(unsigned int index);
|
||||||
|
|
||||||
|
std::vector<Var> variables;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool validateMessageType(int message_type);
|
||||||
|
|
||||||
|
int _message_type;
|
||||||
|
unsigned int _message_size;
|
||||||
|
unsigned int _num_vars;
|
||||||
|
|
||||||
|
bool _byteswap;
|
||||||
|
bool _nonames;
|
||||||
|
|
||||||
|
const static size_t header_size;
|
||||||
|
const static size_t message_indicator_size;
|
||||||
|
const static size_t variable_num_size;
|
||||||
|
const static size_t message_size_size;
|
||||||
|
const static size_t variable_name_length_size;
|
||||||
|
const static size_t variable_type_size;
|
||||||
|
const static size_t variable_size_size;
|
||||||
|
};
|
@ -13,7 +13,9 @@ typedef enum {
|
|||||||
VS_SIE_RESOURCE = 2,
|
VS_SIE_RESOURCE = 2,
|
||||||
VS_LIST_SIZE = 3 ,
|
VS_LIST_SIZE = 3 ,
|
||||||
VS_STDIO = 4,
|
VS_STDIO = 4,
|
||||||
VS_SEND_ONCE = 5
|
VS_SEND_ONCE = 5,
|
||||||
|
VS_MIN_CODE = VS_IP_ERROR,
|
||||||
|
VS_MAX_CODE = VS_SEND_ONCE
|
||||||
} VS_MESSAGE_TYPE ;
|
} VS_MESSAGE_TYPE ;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
|
|
||||||
TRICK_CFLAGS += -I./models
|
TRICK_CFLAGS += -I./models
|
||||||
TRICK_CXXFLAGS += -I./models -I$(GTEST_HOME)/include -std=c++11
|
TRICK_CXXFLAGS += -I./models
|
||||||
|
|
||||||
all: test_client
|
all: test_client
|
||||||
clean: clean_test_client
|
clean: clean_test_client
|
||||||
|
|
||||||
TEST_CLIENT_LIBS += -L${GTEST_HOME}lib64 -L${GTEST_HOME}lib -lgtest -lgtest_main -lpthread
|
TEST_CLIENT_LIBS += -L${GTEST_HOME}/lib64 -L${GTEST_HOME}/lib -lgtest -lgtest_main -lpthread -L${TRICK_LIB_DIR} -ltrick_var_binary_parser
|
||||||
|
|
||||||
test_client: models/test_client/test_client.cpp
|
test_client: models/test_client/test_client.cpp
|
||||||
cd models/test_client; $(TRICK_CXX) test_client.cpp $(TRICK_SYSTEM_LDFLAGS) $(TRICK_CXXFLAGS) -o test_client $(TEST_CLIENT_LIBS) -std=c++11
|
cd models/test_client; $(TRICK_CXX) test_client.cpp -o test_client $(TRICK_CXXFLAGS) -I$(TRICK_HOME)/include $(TEST_CLIENT_LIBS) -std=c++11
|
||||||
|
|
||||||
clean_test_client:
|
clean_test_client:
|
||||||
rm -f models/test_client/test_client
|
rm -f models/test_client/test_client
|
@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "trick/var_binary_parser.hh"
|
||||||
|
|
||||||
#define SOCKET_BUF_SIZE 20480
|
#define SOCKET_BUF_SIZE 20480
|
||||||
|
|
||||||
#define DOUBLE_TOL 1e-5
|
#define DOUBLE_TOL 1e-5
|
||||||
@ -92,6 +94,21 @@ class Socket {
|
|||||||
ret = receive();
|
ret = receive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> receive_bytes() {
|
||||||
|
unsigned char buffer[SOCKET_BUF_SIZE];
|
||||||
|
int numBytes = recv(_socket_fd, buffer, SOCKET_BUF_SIZE, 0);
|
||||||
|
if (numBytes < 0) {
|
||||||
|
std::cout << "Failed to read from socket" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> bytes;
|
||||||
|
for (int i = 0; i < numBytes; i++) {
|
||||||
|
bytes.push_back(buffer[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
bool check_for_message_availible(long timeout_sec = 2) {
|
bool check_for_message_availible(long timeout_sec = 2) {
|
||||||
fd_set read_fd_set;
|
fd_set read_fd_set;
|
||||||
struct timeval timeout = { .tv_sec = timeout_sec, .tv_usec = 0 };
|
struct timeval timeout = { .tv_sec = timeout_sec, .tv_usec = 0 };
|
||||||
@ -581,9 +598,6 @@ TEST_F (VariableServerTest, CopyAndWriteModes) {
|
|||||||
// Is this what we want? Maybe we should have more strict communication on whether the data has been staged so the first message isn't incorrect
|
// Is this what we want? Maybe we should have more strict communication on whether the data has been staged so the first message isn't incorrect
|
||||||
spin();
|
spin();
|
||||||
|
|
||||||
// expected = "0 -1234 1234";
|
|
||||||
// EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0);
|
|
||||||
// std::cout << "\tExpected: " << expected << "\n\tActual: " << reply << std::endl;
|
|
||||||
expected = "-1234 1234";
|
expected = "-1234 1234";
|
||||||
parse_message(socket.receive());
|
parse_message(socket.receive());
|
||||||
EXPECT_EQ(strcmp_IgnoringWhiteSpace(vars, expected), 0) << "Received: " << vars << " Expected: " << expected;
|
EXPECT_EQ(strcmp_IgnoringWhiteSpace(vars, expected), 0) << "Received: " << vars << " Expected: " << expected;
|
||||||
@ -683,6 +697,163 @@ TEST_F (VariableServerTest, CopyAndWriteModes) {
|
|||||||
socket.clear_buffered_data();
|
socket.clear_buffered_data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getCompleteBinaryMessage(ParsedBinaryMessage& message, Socket& socket) {
|
||||||
|
static const int max_retries = 5;
|
||||||
|
|
||||||
|
int tries = 0;
|
||||||
|
bool parse_success = false;
|
||||||
|
std::vector<unsigned char> reply;
|
||||||
|
|
||||||
|
// Try parsing until message received is correct
|
||||||
|
// May take a cycle or 2 to update properly
|
||||||
|
while (!parse_success && tries++ < max_retries) {
|
||||||
|
try {
|
||||||
|
reply = socket.receive_bytes();
|
||||||
|
message.parse(reply);
|
||||||
|
parse_success = true;
|
||||||
|
} catch (const MalformedMessageException& ex) {
|
||||||
|
std::cout << "Attempt " << tries << " failed with exception " << ex.what() << std::endl;;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F (VariableServerTest, Binary) {
|
||||||
|
if (socket_status != 0) {
|
||||||
|
FAIL();
|
||||||
|
}
|
||||||
|
std::vector<unsigned char> reply;
|
||||||
|
socket << "trick.var_binary()\ntrick.var_add(\"vsx.vst.c\")\ntrick.var_add(\"vsx.vst.k\")\ntrick.var_add(\"vsx.vst.o\")\ntrick.var_add(\"vsx.vst.m\")\n";
|
||||||
|
|
||||||
|
ParsedBinaryMessage message;
|
||||||
|
|
||||||
|
if (!getCompleteBinaryMessage(message, socket)) {
|
||||||
|
FAIL() << "Parser was not able to interpret the message.";
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(message.getMessageType(), 0);
|
||||||
|
ASSERT_EQ(message.getNumVars(), 4);
|
||||||
|
|
||||||
|
EXPECT_EQ(strcmp(message.variables[0].getName().c_str(), "vsx.vst.c"), 0);
|
||||||
|
EXPECT_EQ(message.variables[0].getType(), TRICK_SHORT);
|
||||||
|
EXPECT_EQ(message.variables[0].getValue<short>(), -1234);
|
||||||
|
|
||||||
|
|
||||||
|
EXPECT_EQ(strcmp(message.variables[1].getName().c_str(), "vsx.vst.k"), 0);
|
||||||
|
EXPECT_EQ(message.variables[1].getType(), TRICK_LONG_LONG);
|
||||||
|
EXPECT_EQ(message.variables[1].getValue<long long>(), -12345678912345);
|
||||||
|
|
||||||
|
EXPECT_EQ(strcmp(message.variables[2].getName().c_str(), "vsx.vst.o"), 0);
|
||||||
|
EXPECT_EQ(message.variables[2].getType(), TRICK_STRING);
|
||||||
|
std::string actual = message.variables[2].getValue<std::string>();
|
||||||
|
std::string expected = "You will rejoice to hear that no disaster has accompanied the commencement of an enterprise which you have regarded with such evil forebodings. I arrived here yesterday, and my first task is to assure my dear sister of my welfare and increasing confidence in the success of my undertaking.\0";
|
||||||
|
EXPECT_EQ(actual.substr(0, actual.size()-1), expected);
|
||||||
|
|
||||||
|
Var variable = message.getVariable("vsx.vst.m");
|
||||||
|
EXPECT_EQ(strcmp(variable.getName().c_str(), "vsx.vst.m"), 0);
|
||||||
|
EXPECT_EQ(variable.getType(), TRICK_BOOLEAN);
|
||||||
|
EXPECT_EQ(variable.getValue<bool>(), true);
|
||||||
|
|
||||||
|
// Switch to nonames
|
||||||
|
socket << "trick.var_binary_nonames()\n";
|
||||||
|
|
||||||
|
ParsedBinaryMessage noname_message(false, true);
|
||||||
|
if (!getCompleteBinaryMessage(noname_message, socket)) {
|
||||||
|
FAIL() << "Parser was not able to interpret the message.";
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(noname_message.getMessageType(), 0);
|
||||||
|
ASSERT_EQ(noname_message.getNumVars(), 4);
|
||||||
|
|
||||||
|
EXPECT_EQ(strcmp(noname_message.variables[0].getName().c_str(), "<no name>"), 0);
|
||||||
|
EXPECT_EQ(noname_message.variables[0].getType(), TRICK_SHORT);
|
||||||
|
EXPECT_EQ(noname_message.variables[0].getValue<short>(), -1234);
|
||||||
|
|
||||||
|
EXPECT_EQ(strcmp(noname_message.variables[1].getName().c_str(), "<no name>"), 0);
|
||||||
|
EXPECT_EQ(noname_message.variables[1].getType(), TRICK_LONG_LONG);
|
||||||
|
EXPECT_EQ(noname_message.variables[1].getValue<long long>(), -12345678912345);
|
||||||
|
|
||||||
|
EXPECT_EQ(strcmp(noname_message.variables[2].getName().c_str(), "<no name>"), 0);
|
||||||
|
EXPECT_EQ(noname_message.variables[2].getType(), TRICK_STRING);
|
||||||
|
actual = noname_message.variables[2].getValue<std::string>();
|
||||||
|
EXPECT_EQ(actual.substr(0, actual.size()-1), expected);
|
||||||
|
|
||||||
|
Var variable_noname = noname_message.getVariable(3);
|
||||||
|
EXPECT_EQ(strcmp(variable_noname.getName().c_str(), "<no name>"), 0);
|
||||||
|
EXPECT_EQ(variable_noname.getType(), TRICK_BOOLEAN);
|
||||||
|
EXPECT_EQ(variable_noname.getValue<bool>(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F (VariableServerTest, DISABLED_BinaryByteswap) {
|
||||||
|
// TODO: VAR_BYTESWAP DOES NOT APPEAR TO WORK CORRECTLY
|
||||||
|
|
||||||
|
std::vector<unsigned char> reply;
|
||||||
|
socket << "trick.var_binary()\ntrick.var_byteswap(False)\ntrick.var_add(\"vsx.vst.f\")\ntrick.var_add(\"vsx.vst.j\")\n";
|
||||||
|
|
||||||
|
socket.receive_bytes();
|
||||||
|
reply = socket.receive_bytes();
|
||||||
|
|
||||||
|
// Test byteswap
|
||||||
|
|
||||||
|
std::cout << "Message: ";
|
||||||
|
for (unsigned char byte : reply) {
|
||||||
|
std::cout << "0x" << std::setw(2) << std::setfill('0') << std::hex << (int)byte << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
ParsedBinaryMessage message;
|
||||||
|
|
||||||
|
try {
|
||||||
|
message.parse(reply);
|
||||||
|
} catch (const MalformedMessageException& ex) {
|
||||||
|
FAIL() << "Parser threw an exception: " << ex.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(message.getMessageType(), 0);
|
||||||
|
ASSERT_EQ(message.getNumVars(), 2);
|
||||||
|
|
||||||
|
EXPECT_EQ(strcmp(message.variables[0].getName().c_str(), "vsx.vst.f"), 0);
|
||||||
|
EXPECT_EQ(message.variables[0].getType(), TRICK_UNSIGNED_INTEGER);
|
||||||
|
EXPECT_EQ(message.variables[0].getValue<unsigned int>(), 123456);
|
||||||
|
|
||||||
|
EXPECT_EQ(strcmp(message.variables[1].getName().c_str(), "vsx.vst.j"), 0);
|
||||||
|
EXPECT_EQ(message.variables[1].getType(), TRICK_DOUBLE);
|
||||||
|
EXPECT_EQ(message.variables[1].getValue<double>(), -1234.567890);
|
||||||
|
|
||||||
|
socket << "trick.var_byteswap(True)\n";
|
||||||
|
|
||||||
|
socket.receive_bytes();
|
||||||
|
reply = socket.receive_bytes();
|
||||||
|
|
||||||
|
std::cout << "Message: ";
|
||||||
|
for (unsigned char byte : reply) {
|
||||||
|
std::cout << "0x" << std::setw(2) << std::setfill('0') << std::hex << (int)byte << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
ParsedBinaryMessage byteswap_message(true, false);
|
||||||
|
|
||||||
|
try {
|
||||||
|
byteswap_message.parse(reply);
|
||||||
|
} catch (const MalformedMessageException& ex) {
|
||||||
|
FAIL() << "Parser threw an exception: " << ex.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(byteswap_message.getMessageType(), 0);
|
||||||
|
ASSERT_EQ(byteswap_message.getNumVars(), 2);
|
||||||
|
|
||||||
|
EXPECT_EQ(strcmp(byteswap_message.variables[0].getName().c_str(), "vsx.vst.f"), 0);
|
||||||
|
EXPECT_EQ(byteswap_message.variables[0].getType(), TRICK_UNSIGNED_INTEGER);
|
||||||
|
EXPECT_EQ(byteswap_message.variables[0].getValue<unsigned int>(), 123456);
|
||||||
|
std::cout << "Byteswap value: " << byteswap_message.variables[0].getValue<unsigned int>() << std::endl;
|
||||||
|
|
||||||
|
EXPECT_EQ(strcmp(byteswap_message.variables[1].getName().c_str(), "vsx.vst.j"), 0);
|
||||||
|
EXPECT_EQ(byteswap_message.variables[1].getType(), TRICK_DOUBLE);
|
||||||
|
EXPECT_EQ(byteswap_message.variables[1].getValue<double>(), -1234.567890);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
int result = RUN_ALL_TESTS();
|
int result = RUN_ALL_TESTS();
|
||||||
|
@ -3,7 +3,7 @@ RM = rm -rf
|
|||||||
CC = cc
|
CC = cc
|
||||||
CPP = c++
|
CPP = c++
|
||||||
|
|
||||||
CFLAGS = -g -Wall -std=c++11
|
CFLAGS = -g -Wall -std=c++11 ${TRICK_CXXFLAGS}
|
||||||
INCLUDE_DIRS = -Iinclude
|
INCLUDE_DIRS = -Iinclude
|
||||||
OBJDIR = obj
|
OBJDIR = obj
|
||||||
LIBDIR = lib
|
LIBDIR = lib
|
||||||
|
@ -3,7 +3,7 @@ include ${TRICK_HOME}/share/trick/makefiles/Makefile.common
|
|||||||
|
|
||||||
RM = rm -rf
|
RM = rm -rf
|
||||||
|
|
||||||
TRICK_CPPFLAGS += -I$(GTEST_HOME)/include -I$(TRICK_HOME)/include -g -Wall -Wextra -std=c++11 ${TRICK_SYSTEM_CXXFLAGS}
|
TRICK_CPPFLAGS += -I$(GTEST_HOME)/include -I$(TRICK_HOME)/include -g -Wall -Wextra -std=c++11 ${TRICK_CXXFLAGS}
|
||||||
INCLUDE_DIRS = -I../include -I$(GTEST_HOME)/include
|
INCLUDE_DIRS = -I../include -I$(GTEST_HOME)/include
|
||||||
|
|
||||||
SAI_OBJDIR = obj
|
SAI_OBJDIR = obj
|
||||||
|
2
trick_source/trick_utils/var_binary_parser/.gitignore
vendored
Normal file
2
trick_source/trick_utils/var_binary_parser/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*.o
|
||||||
|
TEST_var_binary_parser
|
52
trick_source/trick_utils/var_binary_parser/Makefile
Normal file
52
trick_source/trick_utils/var_binary_parser/Makefile
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
RM = rm -rf
|
||||||
|
CC = cc
|
||||||
|
CPP = c++
|
||||||
|
include ${TRICK_HOME}/share/trick/makefiles/Makefile.common
|
||||||
|
|
||||||
|
|
||||||
|
#include ${TRICK_HOME}/share/trick/makefiles/Makefile.tricklib
|
||||||
|
|
||||||
|
CFLAGS = -g -Wall -Wextra -std=c++11 $(TRICK_CXXFLAGS)
|
||||||
|
INCLUDE_DIRS = -I${TRICK_HOME}/include
|
||||||
|
OBJDIR = obj
|
||||||
|
LIBDIR = lib
|
||||||
|
LIBNAME = libtrick_var_binary_parser.a
|
||||||
|
LIBOBJS = ${OBJDIR}/var_binary_parser.o
|
||||||
|
|
||||||
|
TRICK_LIB := $(TRICK_LIB_DIR)/$(LIBNAME)
|
||||||
|
# TRICK_LIB := $(TRICK_HOME)/lib/$(LIBNAME)
|
||||||
|
|
||||||
|
|
||||||
|
trick: ${TRICK_LIB}
|
||||||
|
|
||||||
|
install: ${TRICK_LIB}
|
||||||
|
|
||||||
|
all: test
|
||||||
|
|
||||||
|
test: ${LIBDIR}/${LIBNAME}
|
||||||
|
${MAKE} -C test
|
||||||
|
|
||||||
|
$(LIBOBJS): $(OBJDIR)/%.o : src/%.cc | $(OBJDIR)
|
||||||
|
$(CPP) $(CFLAGS) ${INCLUDE_DIRS} -c $< -o $@
|
||||||
|
|
||||||
|
${LIBDIR}/${LIBNAME}: ${LIBOBJS} | ${LIBDIR}
|
||||||
|
ar crs $@ ${LIBOBJS}
|
||||||
|
|
||||||
|
${OBJDIR}:
|
||||||
|
mkdir -p ${OBJDIR}
|
||||||
|
|
||||||
|
${LIBDIR}:
|
||||||
|
mkdir -p ${LIBDIR}
|
||||||
|
|
||||||
|
${TRICK_LIB}: ${LIBDIR}/${LIBNAME}
|
||||||
|
cp ${LIBDIR}/${LIBNAME} $(TRICK_LIB)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
${RM} -r ${OBJDIR}
|
||||||
|
${MAKE} -C test clean
|
||||||
|
|
||||||
|
spotless:
|
||||||
|
${RM} ${OBJDIR}
|
||||||
|
${RM} ${LIBDIR}
|
||||||
|
${MAKE} -C unittest spotless
|
||||||
|
${MAKE} -C examples spotless
|
@ -0,0 +1,364 @@
|
|||||||
|
#include "trick/var_binary_parser.hh"
|
||||||
|
#include "trick/variable_server_message_types.h"
|
||||||
|
#include <climits>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
|
// Utility method
|
||||||
|
uint64_t bytesToInt(const std::vector<unsigned char>& bytes, bool byteswap) {
|
||||||
|
uint64_t result = 0;
|
||||||
|
|
||||||
|
if (byteswap) {
|
||||||
|
for (unsigned int i = 0; i < bytes.size(); i++) {
|
||||||
|
result |= bytes[bytes.size() - 1 - i] << i*8;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (unsigned int i = 0; i < bytes.size(); i++) {
|
||||||
|
result |= bytes[i] << i*8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MessageIterator {
|
||||||
|
public:
|
||||||
|
MessageIterator(const std::vector<unsigned char>& container) : _container(container), _index(0) {}
|
||||||
|
|
||||||
|
std::vector<unsigned char> slice(unsigned int length) {
|
||||||
|
unsigned int slice_end = _index + length;
|
||||||
|
if (_index > _container.size() || slice_end > _container.size()) {
|
||||||
|
throw MalformedMessageException("Message ends unexpectedly");
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::vector<unsigned char>(_container.begin() + _index, _container.begin() + slice_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator+= (int n) {
|
||||||
|
_index += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<unsigned char> _container;
|
||||||
|
unsigned int _index;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Var implementation
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
const size_t ParsedBinaryMessage::header_size = 12;
|
||||||
|
const size_t ParsedBinaryMessage::message_indicator_size = 4;
|
||||||
|
const size_t ParsedBinaryMessage::variable_num_size = 4;
|
||||||
|
const size_t ParsedBinaryMessage::message_size_size = 4;
|
||||||
|
const size_t ParsedBinaryMessage::variable_name_length_size = 4;
|
||||||
|
const size_t ParsedBinaryMessage::variable_type_size = 4;
|
||||||
|
const size_t ParsedBinaryMessage::variable_size_size = 4;
|
||||||
|
|
||||||
|
int ParsedBinaryMessage::parse (const std::vector<unsigned char>& bytes){
|
||||||
|
if (bytes.size() < header_size) {
|
||||||
|
throw MalformedMessageException(std::string("Not enough bytes in message to contain header: expected at least 12, got " + std::to_string(bytes.size())));
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageIterator messageIterator (bytes);
|
||||||
|
|
||||||
|
// First 4 bytes is message type
|
||||||
|
_message_type = bytesToInt(messageIterator.slice(message_indicator_size), _byteswap);
|
||||||
|
if (!validateMessageType(_message_type)) {
|
||||||
|
throw MalformedMessageException(std::string("Received unknown message type: " + std::to_string(_message_type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
messageIterator += message_indicator_size;
|
||||||
|
|
||||||
|
// Next 4 bytes is message size
|
||||||
|
_message_size = bytesToInt(messageIterator.slice(message_size_size), _byteswap);
|
||||||
|
if (bytes.size() - message_indicator_size != _message_size) {
|
||||||
|
std::string error_message = "Message size in header (" + std::to_string(_message_size) + ") does not match size of message received (" + std::to_string(bytes.size() - message_indicator_size) + ")";
|
||||||
|
throw MalformedMessageException(error_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
messageIterator += message_size_size;
|
||||||
|
|
||||||
|
// Next 4 bytes is number of variables
|
||||||
|
_num_vars = bytesToInt(messageIterator.slice(variable_num_size), _byteswap);
|
||||||
|
messageIterator += variable_num_size;
|
||||||
|
|
||||||
|
// Pull out all of the variables
|
||||||
|
for (unsigned int i = 0; i < _num_vars; i++) {
|
||||||
|
Var variable;
|
||||||
|
|
||||||
|
if (!_nonames) {
|
||||||
|
// Get the name
|
||||||
|
size_t name_length = bytesToInt(messageIterator.slice(variable_name_length_size), _byteswap);
|
||||||
|
messageIterator += variable_name_length_size;
|
||||||
|
|
||||||
|
variable.setName(name_length, messageIterator.slice(name_length));
|
||||||
|
messageIterator += name_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the type first
|
||||||
|
int var_type = bytesToInt(messageIterator.slice(variable_type_size), _byteswap);
|
||||||
|
messageIterator += variable_type_size;
|
||||||
|
|
||||||
|
size_t var_size = bytesToInt(messageIterator.slice(variable_size_size), _byteswap);
|
||||||
|
messageIterator += variable_size_size;
|
||||||
|
|
||||||
|
variable.setValue(messageIterator.slice(var_size), var_size, static_cast<TRICK_TYPE>(var_type), _byteswap);
|
||||||
|
messageIterator += var_size;
|
||||||
|
|
||||||
|
variables.emplace_back(variable);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParsedBinaryMessage::combine (const ParsedBinaryMessage& other) {
|
||||||
|
if (_message_type != other._message_type) {
|
||||||
|
std::string error_message = "Trying to combine two messages with different message indicators (" + std::to_string(_message_type) + " and " + std::to_string(other._message_type) + ")";
|
||||||
|
throw MalformedMessageException(error_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combined size - subtract the header size from other message size
|
||||||
|
_message_size += other._message_size - message_size_size - variable_num_size;
|
||||||
|
|
||||||
|
// Combine variables
|
||||||
|
_num_vars += other._num_vars;
|
||||||
|
variables.insert(variables.end(), other.variables.begin(), other.variables.end());
|
||||||
|
|
||||||
|
// Other error checking - duplicate variables?
|
||||||
|
}
|
||||||
|
|
||||||
|
Var ParsedBinaryMessage::getVariable(const std::string& name) {
|
||||||
|
if (_nonames)
|
||||||
|
throw IncorrectUsageException("Cannot fetch variables by name in noname message");
|
||||||
|
|
||||||
|
for (auto variable : variables) {
|
||||||
|
if (variable.getName() == name)
|
||||||
|
return variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw IncorrectUsageException("Variable " + name + " does not exist in this message.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Var ParsedBinaryMessage::getVariable(unsigned int index) {
|
||||||
|
if (index >= variables.size()) {
|
||||||
|
throw IncorrectUsageException("Variable index " + std::to_string(index) + " does not exist in this message.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return variables[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
int ParsedBinaryMessage::getMessageType() const {
|
||||||
|
return _message_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ParsedBinaryMessage::getMessageSize() const {
|
||||||
|
return _message_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ParsedBinaryMessage::getNumVars() const {
|
||||||
|
return _num_vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static methods
|
||||||
|
|
||||||
|
bool ParsedBinaryMessage::validateMessageType(int message_type) {
|
||||||
|
return message_type >= VS_MIN_CODE && message_type <= VS_MAX_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Var implementation
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
void Var::setName(size_t name_size, const std::vector<unsigned char>& name_data) {
|
||||||
|
_has_name = true;
|
||||||
|
_name_length = name_size;
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
for (unsigned char character : name_data) {
|
||||||
|
ss << static_cast<char>(character);
|
||||||
|
}
|
||||||
|
|
||||||
|
_name = ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Var::setValue(const std::vector<unsigned char>& bytes, size_t size, TRICK_TYPE type, bool byteswap) {
|
||||||
|
_trick_type = type;
|
||||||
|
_var_size = size;
|
||||||
|
_byteswap = byteswap;
|
||||||
|
|
||||||
|
value_bytes = std::vector<unsigned char> (bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
Number Var::getInterpreter() const {
|
||||||
|
Number interpreted_val;
|
||||||
|
|
||||||
|
if (_byteswap) {
|
||||||
|
for (unsigned int i = 0; i < _var_size; i++) {
|
||||||
|
interpreted_val.raw_bytes[i] = value_bytes[_var_size - 1 - i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (unsigned int i = 0; i < _var_size; i++) {
|
||||||
|
interpreted_val.raw_bytes[i] = value_bytes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return interpreted_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Var::getName() const {
|
||||||
|
if (_has_name) {
|
||||||
|
return _name;
|
||||||
|
} else {
|
||||||
|
return std::string ("<no name>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TRICK_TYPE Var::getType() const {
|
||||||
|
return _trick_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Template specialization for each supported type
|
||||||
|
template<>
|
||||||
|
char Var::getValue<char> () const {
|
||||||
|
if (_trick_type != TRICK_CHARACTER) {
|
||||||
|
throw ParseTypeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getInterpreter().char_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
unsigned char Var::getValue<unsigned char> () const {
|
||||||
|
if (_trick_type != TRICK_UNSIGNED_CHARACTER) {
|
||||||
|
throw ParseTypeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getInterpreter().unsigned_char_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
bool Var::getValue<bool> () const {
|
||||||
|
if (_trick_type != TRICK_BOOLEAN) {
|
||||||
|
throw ParseTypeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getInterpreter().bool_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
short Var::getValue<short> () const {
|
||||||
|
if (_trick_type != TRICK_SHORT) {
|
||||||
|
throw ParseTypeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getInterpreter().short_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
unsigned short Var::getValue<unsigned short> () const {
|
||||||
|
if (_trick_type != TRICK_UNSIGNED_SHORT) {
|
||||||
|
throw ParseTypeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getInterpreter().unsigned_short_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
unsigned int Var::getValue<unsigned int> () const {
|
||||||
|
if (_trick_type != TRICK_UNSIGNED_INTEGER) {
|
||||||
|
throw ParseTypeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getInterpreter().unsigned_int_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
int Var::getValue<int> () const {
|
||||||
|
if (_trick_type != TRICK_INTEGER) {
|
||||||
|
throw ParseTypeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getInterpreter().int_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
long Var::getValue<long> () const {
|
||||||
|
if (_trick_type != TRICK_LONG) {
|
||||||
|
throw ParseTypeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getInterpreter().long_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
unsigned long Var::getValue<unsigned long> () const {
|
||||||
|
if (_trick_type != TRICK_UNSIGNED_LONG) {
|
||||||
|
throw ParseTypeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getInterpreter().unsigned_long_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
long long Var::getValue<long long> () const {
|
||||||
|
if (_trick_type != TRICK_LONG_LONG) {
|
||||||
|
throw ParseTypeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getInterpreter().long_long_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
unsigned long long Var::getValue<unsigned long long> () const {
|
||||||
|
if (_trick_type != TRICK_UNSIGNED_LONG_LONG) {
|
||||||
|
throw ParseTypeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getInterpreter().unsigned_long_long_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
float Var::getValue<float> () const {
|
||||||
|
if (_trick_type != TRICK_FLOAT) {
|
||||||
|
throw ParseTypeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getInterpreter().float_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
double Var::getValue<double> () const {
|
||||||
|
if (_trick_type != TRICK_DOUBLE) {
|
||||||
|
throw ParseTypeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getInterpreter().double_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
std::string Var::getValue<std::string> () const {
|
||||||
|
if (_trick_type != TRICK_STRING) {
|
||||||
|
throw ParseTypeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream stream;
|
||||||
|
for (unsigned char character : value_bytes) {
|
||||||
|
stream << static_cast<char>(character);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
wchar_t Var::getValue<wchar_t> () const {
|
||||||
|
if (_trick_type != TRICK_WCHAR) {
|
||||||
|
throw ParseTypeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getInterpreter().wchar_val;
|
||||||
|
}
|
37
trick_source/trick_utils/var_binary_parser/test/Makefile
Normal file
37
trick_source/trick_utils/var_binary_parser/test/Makefile
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#SYNOPSIS:
|
||||||
|
#
|
||||||
|
## make [all] - makes everything.
|
||||||
|
# make TARGET - makes the given target.
|
||||||
|
# # make clean - removes all files generated by make.
|
||||||
|
|
||||||
|
# Flags passed to the preprocessor.
|
||||||
|
CPPFLAGS += -g -Wall -Wextra -std=c++11 ${TRICK_SYSTEM_CXXFLAGS} -I../include -I${TRICK_HOME}/include
|
||||||
|
|
||||||
|
# TRICK_LIBS = ${TRICK_LIB_DIR}/libtrick_units.a
|
||||||
|
EXEC_LINK_LIBS += -L${GTEST_HOME}/lib64 -L${GTEST_HOME}/lib -lgtest -lgtest_main
|
||||||
|
|
||||||
|
#Added pthreads for Ubuntu
|
||||||
|
EXEC_LINK_LIBS += -lpthread
|
||||||
|
|
||||||
|
OTHER_OBJECTS = ../obj/*.o
|
||||||
|
|
||||||
|
TESTS = TEST_var_binary_parser
|
||||||
|
|
||||||
|
GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \
|
||||||
|
$(GTEST_DIR)/include/gtest/internal/*.h
|
||||||
|
|
||||||
|
all : $(TESTS) test
|
||||||
|
|
||||||
|
test: $(TESTS)
|
||||||
|
./TEST_var_binary_parser --gtest_output=xml:${TRICK_HOME}/trick_test/TEST_var_binary_parser.xml
|
||||||
|
|
||||||
|
clean :
|
||||||
|
rm -f $(TESTS)
|
||||||
|
rm -f *.o
|
||||||
|
|
||||||
|
TEST_var_binary_parser.o : TEST_var_binary_parser.cc $(OTHER_OBJECTS)
|
||||||
|
$(CXX) $(CPPFLAGS) -c $<
|
||||||
|
|
||||||
|
TEST_var_binary_parser : TEST_var_binary_parser.o $(OTHER_OBJECTS)
|
||||||
|
@echo 'Building TEST_var_binary_parser'
|
||||||
|
$(CXX) $(TRICK_SYSTEM_LDFLAGS) -o $@ $^ -L${TRICK_HOME}/lib_${TRICK_HOST_CPU} $(LIBS) $(EXEC_LINK_LIBS)
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user