PR-766 Fix several issues with bool group
This commit is contained in:
parent
ce1143f84c
commit
5481a31b04
|
@ -45,7 +45,9 @@ int config_handler(void* user_data, const char* section,
|
|||
auto config = reinterpret_cast<PlcConfig*>(user_data);
|
||||
|
||||
if (ini_matches("logging", "level", section, name)) {
|
||||
if (strcmp(value, "debug") == 0) {
|
||||
if (strcmp(value, "trace") == 0) {
|
||||
spdlog::set_level(spdlog::level::trace);
|
||||
} else if (strcmp(value, "debug") == 0) {
|
||||
spdlog::set_level(spdlog::level::debug);
|
||||
} else if (strcmp(value, "info") == 0) {
|
||||
spdlog::set_level(spdlog::level::info);
|
||||
|
|
|
@ -329,6 +329,8 @@ int dnp3s_cfg_handler(void* user_data, const char* section,
|
|||
} else if (strcmp(name, "unsol_retry_timeout") == 0) {
|
||||
config->outstation.params.unsolRetryTimeout =
|
||||
openpal::TimeDuration::Milliseconds(atoi(value));
|
||||
} else if (strcmp(name, "enabled") == 0) {
|
||||
// Nothing to do here - we already know this is enabled
|
||||
} else {
|
||||
spdlog::warn("Unknown configuration item {}", name);
|
||||
return -1;
|
||||
|
|
|
@ -282,11 +282,11 @@ void Dnp3Receiver::ExchangeGlue() {
|
|||
}
|
||||
|
||||
void Dnp3Receiver::Start() {
|
||||
spdlog::info("DNP3 receiver started");
|
||||
spdlog::trace("DNP3 receiver started");
|
||||
}
|
||||
|
||||
void Dnp3Receiver::End() {
|
||||
spdlog::info("DNP3 receiver stopped");
|
||||
spdlog::trace("DNP3 receiver stopped");
|
||||
}
|
||||
|
||||
#endif // OPLC_DNP3_OUTSTATION
|
||||
|
|
|
@ -68,8 +68,8 @@ class Dnp3Receiver : public opendnp3::ICommandHandler {
|
|||
|
||||
template <typename T>
|
||||
struct CacheItem {
|
||||
bool has_value;
|
||||
T value;
|
||||
volatile bool has_value;
|
||||
volatile T value;
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "glue.h"
|
||||
#include "ini_util.h"
|
||||
#include "ladder.h"
|
||||
#include "lib/iec_types_all.h"
|
||||
|
||||
/** \addtogroup openplc_runtime
|
||||
* @{
|
||||
|
@ -97,6 +98,20 @@ size_t get_size_bytes(const GlueVariablesBinding& bindings) {
|
|||
return size;
|
||||
}
|
||||
|
||||
inline uint8_t mask_index(GlueBoolGroup* group, uint8_t i) {
|
||||
if (!group->values[i]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (*group->values) ? (1 << i) : 0;
|
||||
}
|
||||
|
||||
inline void set_index(GlueBoolGroup* group, uint8_t i, uint8_t v) {
|
||||
if (group->values[i]) {
|
||||
(*group->values[i]) = ((1 << i) & v) ? TRUE: FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy the glue values into the buffer.
|
||||
/// @param bindings The bindings that we want to copy from.
|
||||
/// @param buffer The buffer that we are copying into.
|
||||
|
@ -115,8 +130,21 @@ size_t pstorage_copy_glue(const GlueVariablesBinding& bindings, char* buffer) {
|
|||
|
||||
uint8_t num_bytes = get_size_bytes(glue.size);
|
||||
|
||||
// Write the number of bytes to the buffer
|
||||
memcpy(buffer, glue.value, num_bytes);
|
||||
if (glue.size == IECLST_BIT) {
|
||||
GlueBoolGroup* group = reinterpret_cast<GlueBoolGroup*>(glue.value);
|
||||
uint8_t bools_as_byte = mask_index(group, 0)
|
||||
| mask_index(group, 1)
|
||||
| mask_index(group, 2)
|
||||
| mask_index(group, 3)
|
||||
| mask_index(group, 4)
|
||||
| mask_index(group, 5)
|
||||
| mask_index(group, 6)
|
||||
| mask_index(group, 7);
|
||||
memcpy(buffer, &bools_as_byte, 1);
|
||||
} else {
|
||||
// Write the number of bytes to the buffer
|
||||
memcpy(buffer, glue.value, num_bytes);
|
||||
}
|
||||
|
||||
// Advance the pointer to the next starting position
|
||||
num_written += num_bytes;
|
||||
|
@ -147,6 +175,8 @@ int pstorage_cfg_handler(void* user_data, const char* section,
|
|||
// We do not allow a poll period of less than 1 second as that
|
||||
// might cause lock contention problems.
|
||||
config->poll_interval = std::chrono::seconds(max(1, atoi(value)));
|
||||
} else if (strcmp(name, "enabled") == 0) {
|
||||
// Nothing to do here - we already know this is enabled
|
||||
} else {
|
||||
spdlog::warn("Unknown configuration item {}", name);
|
||||
return -1;
|
||||
|
@ -315,7 +345,20 @@ int8_t pstorage_read(istream& input_stream,
|
|||
// value or a group of booleans.
|
||||
// We don't actually care what the contents are - we just populate as
|
||||
// though they are raw bytes
|
||||
memcpy(glue.value, buffer, num_bytes);
|
||||
if (glue.size == IECLST_BIT) {
|
||||
GlueBoolGroup* group = reinterpret_cast<GlueBoolGroup*>(glue.value);
|
||||
uint8_t value = static_cast<uint8_t>(buffer[0]);
|
||||
set_index(group, 0, value);
|
||||
set_index(group, 1, value);
|
||||
set_index(group, 2, value);
|
||||
set_index(group, 3, value);
|
||||
set_index(group, 4, value);
|
||||
set_index(group, 5, value);
|
||||
set_index(group, 6, value);
|
||||
set_index(group, 7, value);
|
||||
} else {
|
||||
memcpy(glue.value, buffer, num_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
spdlog::info("Initialized from persistent storage");
|
||||
|
|
|
@ -43,10 +43,11 @@ SCENARIO("pstorage_read", "") {
|
|||
IEC_LWORD lword_var = 0;
|
||||
IEC_SINT usint_var = 0;
|
||||
IEC_BOOL bool_var = 0;
|
||||
GlueBoolGroup grp { .index=0, .values = { &bool_var, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr} };
|
||||
const GlueVariable glue_vars[] = {
|
||||
{ IECLDT_MEM, IECLST_DOUBLEWORD, 0, 0, IECVT_LWORD, &lword_var },
|
||||
{ IECLDT_MEM, IECLST_BYTE, 0, 0, IECVT_USINT, &usint_var },
|
||||
{ IECLDT_MEM, IECLST_BIT, 0, 0, IECVT_BOOL, &bool_var },
|
||||
{ IECLDT_MEM, IECLST_BIT, 0, 0, IECVT_BOOL, &grp },
|
||||
};
|
||||
GlueVariablesBinding bindings(&glue_mutex, 3, glue_vars, CHECKSUM_HEADER);
|
||||
|
||||
|
@ -90,6 +91,32 @@ SCENARIO("pstorage_read", "") {
|
|||
REQUIRE(bool_var == 1);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("one bool group") {
|
||||
IEC_BOOL bool_var0 = 0;
|
||||
IEC_BOOL bool_var1 = 0;
|
||||
IEC_BOOL bool_var7 = 0;
|
||||
GlueBoolGroup grp { .index=0, .values = { &bool_var0, &bool_var1, nullptr, nullptr, nullptr, nullptr, nullptr, &bool_var7} };
|
||||
const GlueVariable glue_vars[] = {
|
||||
{ IECLDT_MEM, IECLST_BIT, 0, 0, IECVT_BOOL, &grp },
|
||||
};
|
||||
GlueVariablesBinding bindings(&glue_mutex, 1, glue_vars, CHECKSUM_HEADER);
|
||||
|
||||
WHEN("data is valid and mixture of bits set") {
|
||||
// We don't (in general) know the endianness to know
|
||||
// the byte order, so we initialize the buffer based on
|
||||
// the actual memory layout
|
||||
char one_char = 0x81;
|
||||
|
||||
input_stream.write(&one_char, 1);
|
||||
input_stream.seekg(0);
|
||||
REQUIRE(pstorage_read(input_stream, bindings) == 0);
|
||||
|
||||
REQUIRE(bool_var0 == 1);
|
||||
REQUIRE(bool_var1 == 0);
|
||||
REQUIRE(bool_var7 == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("pstorage_run") {
|
||||
|
@ -105,10 +132,11 @@ SCENARIO("pstorage_run") {
|
|||
IEC_LWORD lword_var = 1;
|
||||
IEC_SINT usint_var = 2;
|
||||
IEC_BOOL bool_var = 1;
|
||||
GlueBoolGroup grp { .index=0, .values = { &bool_var, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr} };
|
||||
const GlueVariable glue_vars[] = {
|
||||
{ IECLDT_MEM, IECLST_DOUBLEWORD, 0, 0, IECVT_LWORD, &lword_var },
|
||||
{ IECLDT_MEM, IECLST_BYTE, 0, 0, IECVT_USINT, &usint_var },
|
||||
{ IECLDT_MEM, IECLST_BIT, 0, 0, IECVT_BOOL, &bool_var },
|
||||
{ IECLDT_MEM, IECLST_BIT, 0, 0, IECVT_BOOL, &grp },
|
||||
};
|
||||
GlueVariablesBinding bindings(&glue_mutex, 3, glue_vars, CHECKSUM_HEADER);
|
||||
|
||||
|
|
|
@ -15,9 +15,13 @@
|
|||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "md5.h"
|
||||
|
@ -331,6 +335,8 @@ const char* fromDirectionFlag(const char flag) {
|
|||
|
||||
const char* fromSizeFlag(const char flag) {
|
||||
switch (flag) {
|
||||
// G is a special flag we use to represent a boolean group
|
||||
case 'G':
|
||||
case 'X':
|
||||
return "BIT";
|
||||
case 'B':
|
||||
|
@ -345,6 +351,93 @@ const char* fromSizeFlag(const char flag) {
|
|||
}
|
||||
}
|
||||
|
||||
void generateBoolGroups(ostream& glueVars, char direction, map<uint16_t, array<string, 8>>& items) {
|
||||
if (items.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto it_group = items.begin(); it_group != items.end(); ++it_group) {
|
||||
string name;
|
||||
name += direction;
|
||||
name += 'G';
|
||||
name += to_string(it_group->first);
|
||||
glueVars << "GlueBoolGroup ___" << name;
|
||||
glueVars << " { .index=" << it_group->first << ", .values={ ";
|
||||
for (auto it_var = it_group->second.begin(); it_var != it_group->second.end(); ++it_var) {
|
||||
if (it_var->empty()) {
|
||||
glueVars << "nullptr, ";
|
||||
} else {
|
||||
glueVars << (*it_var) << ", ";
|
||||
}
|
||||
}
|
||||
glueVars << "} };\n";
|
||||
glueVars << "GlueBoolGroup* __" << name << "(&___" << name << ");\n";
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate the boolean groups structures. These structures contain
|
||||
/// boolean values that are grouped together. For example, %IX0.0 and %IX0.1
|
||||
/// are generated as a group and then that group is referred to from
|
||||
/// the integrated glue. This function generates the definitions
|
||||
/// of the bool groups.
|
||||
void generateBoolGroups(ostream& glueVars, list<IecVar>& all_vars) {
|
||||
map<uint16_t, array<string, 8>> inputs;
|
||||
map<uint16_t, array<string, 8>> outputs;
|
||||
map<uint16_t, array<string, 8>> memory;
|
||||
for (auto it_var = all_vars.begin(); it_var != all_vars.end(); ) {
|
||||
const char sizeFlag = it_var->name[3];
|
||||
if (sizeFlag != 'X') {
|
||||
// We only care about the boolen locations here.
|
||||
++it_var;
|
||||
continue;
|
||||
}
|
||||
const char directionFlag = it_var->name[2];
|
||||
|
||||
map<uint16_t, array<string, 8>>* container;
|
||||
switch (directionFlag) {
|
||||
case 'I':
|
||||
container = &inputs;
|
||||
break;
|
||||
case 'Q':
|
||||
container = &outputs;
|
||||
break;
|
||||
default:
|
||||
container = &memory;
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t pos1 = it_var->pos1;
|
||||
uint16_t pos2 = it_var->pos2;
|
||||
string name = it_var->name;
|
||||
|
||||
auto it_group = container->find(pos1);
|
||||
if (it_group == container->end()) {
|
||||
(*container)[pos1] = array<string, 8>();
|
||||
// Replace the name with our special name
|
||||
it_var->name = "__";
|
||||
it_var->name += directionFlag;
|
||||
it_var->name += 'G';
|
||||
it_var->name += to_string(pos1);
|
||||
it_var->pos2 = 0;
|
||||
++it_var;
|
||||
} else {
|
||||
// Since we have seen this before, remove it from the
|
||||
// list of variables so that when we generate the
|
||||
// integrated glue, we only see the first item in
|
||||
// the group, not each item
|
||||
it_var = all_vars.erase(it_var);
|
||||
}
|
||||
|
||||
(*container)[pos1][pos2] = name;
|
||||
}
|
||||
|
||||
// Now that we have them grouped into the groups that we care about
|
||||
// generate the intermediate glue bindings for the items
|
||||
generateBoolGroups(glueVars, 'I', inputs);
|
||||
generateBoolGroups(glueVars, 'Q', outputs);
|
||||
generateBoolGroups(glueVars, 'M', memory);
|
||||
}
|
||||
|
||||
void generateIntegratedGlue(ostream& glueVars, const list<IecVar>& all_vars) {
|
||||
glueVars << "/// The size of the array of glue variables.\n";
|
||||
glueVars << "extern std::uint16_t const OPLCGLUE_GLUE_SIZE(";
|
||||
|
@ -353,16 +446,17 @@ void generateIntegratedGlue(ostream& glueVars, const list<IecVar>& all_vars) {
|
|||
glueVars << "/// The packed glue variables.\n";
|
||||
glueVars << "extern const GlueVariable oplc_glue_vars[] = {\n";
|
||||
for (auto it = all_vars.begin(); it != all_vars.end(); ++it) {
|
||||
const char directionFlag = (*it).name[2];
|
||||
const char sizeFlag = (*it).name[3];
|
||||
string name = it->name;
|
||||
const char directionFlag = it->name[2];
|
||||
const char sizeFlag = it->name[3];
|
||||
|
||||
glueVars << " {";
|
||||
glueVars << " IECLDT_" << fromDirectionFlag(directionFlag) << ",";
|
||||
glueVars << " IECLST_" << fromSizeFlag(sizeFlag) << ",";
|
||||
glueVars << " " << (*it).pos1 << ",";
|
||||
glueVars << " " << (*it).pos2 << ",";
|
||||
glueVars << " IECVT_" << (*it).type << ", ";
|
||||
glueVars << " " << (*it).name << " },\n";
|
||||
glueVars << " " << it->pos1 << ",";
|
||||
glueVars << " " << it->pos2 << ",";
|
||||
glueVars << " IECVT_" << it->type << ", ";
|
||||
glueVars << " " << name << " },\n";
|
||||
}
|
||||
glueVars << "};\n\n";
|
||||
}
|
||||
|
@ -421,6 +515,7 @@ void generateBody(istream& locatedVars, ostream& glueVars, md5_byte_t digest[16]
|
|||
glueVars << "}\n\n";
|
||||
|
||||
// Generate the unified glue variables
|
||||
generateBoolGroups(glueVars, all_vars);
|
||||
generateIntegratedGlue(glueVars, all_vars);
|
||||
|
||||
// Finish the checksum value
|
||||
|
|
|
@ -69,109 +69,132 @@ SCENARIO("", "") {
|
|||
WHEN("Contains single BOOL at %IX0") {
|
||||
std::stringstream input_stream("__LOCATED_VAR(BOOL,__IX0,I,X,0)");
|
||||
generateBody(input_stream, output_stream, digest);
|
||||
|
||||
const char* expected = PREFIX "\tbool_input[0][0] = __IX0;\n" POSTFIX GLUE_PREFIX\
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n\
|
||||
/// The packed glue variables.\n\
|
||||
extern const GlueVariable oplc_glue_vars[] = {\n\
|
||||
{ IECLDT_IN, IECLST_BIT, 0, 0, IECVT_BOOL, __IX0 },\n\
|
||||
};\n\n";
|
||||
const char* expected = PREFIX "\tbool_input[0][0] = __IX0;\n" POSTFIX
|
||||
"GlueBoolGroup ___IG0 { .index=0, .values={ __IX0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, } };\n"
|
||||
"GlueBoolGroup* __IG0(&___IG0);\n"
|
||||
GLUE_PREFIX
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n"
|
||||
"/// The packed glue variables.\n"
|
||||
"extern const GlueVariable oplc_glue_vars[] = {\n"
|
||||
" { IECLDT_IN, IECLST_BIT, 0, 0, IECVT_BOOL, __IG0 },\n"
|
||||
"};\n\n";
|
||||
REQUIRE(output_stream.str() == expected);
|
||||
}
|
||||
|
||||
WHEN("Contains single BOOL at %QX0") {
|
||||
std::stringstream input_stream("__LOCATED_VAR(BOOL,__QX0,Q,X,0)");
|
||||
generateBody(input_stream, output_stream, digest);
|
||||
const char* expected = PREFIX "\tbool_output[0][0] = __QX0;\n" POSTFIX GLUE_PREFIX\
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n\
|
||||
/// The packed glue variables.\n\
|
||||
extern const GlueVariable oplc_glue_vars[] = {\n\
|
||||
{ IECLDT_OUT, IECLST_BIT, 0, 0, IECVT_BOOL, __QX0 },\n\
|
||||
};\n\n";
|
||||
const char* expected = PREFIX "\tbool_output[0][0] = __QX0;\n" POSTFIX
|
||||
"GlueBoolGroup ___QG0 { .index=0, .values={ __QX0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, } };\n"
|
||||
"GlueBoolGroup* __QG0(&___QG0);\n"
|
||||
GLUE_PREFIX
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n"
|
||||
"/// The packed glue variables.\n"
|
||||
"extern const GlueVariable oplc_glue_vars[] = {\n"
|
||||
" { IECLDT_OUT, IECLST_BIT, 0, 0, IECVT_BOOL, __QG0 },\n"
|
||||
"};\n\n";
|
||||
REQUIRE(output_stream.str() == expected);
|
||||
}
|
||||
|
||||
WHEN("Contains multiple BOOL at %QX0") {
|
||||
std::stringstream input_stream("__LOCATED_VAR(BOOL,__QX0_0,Q,X,0,0)\n__LOCATED_VAR(BOOL,__QX0_2,Q,X,0,2)\n__LOCATED_VAR(BOOL,__QX1_3,Q,X,1,3)");
|
||||
generateBody(input_stream, output_stream, digest);
|
||||
const char* expected = PREFIX "\tbool_output[0][0] = __QX0_0;\n\tbool_output[0][2] = __QX0_2;\n\tbool_output[1][3] = __QX1_3;\n" POSTFIX
|
||||
"GlueBoolGroup ___QG0 { .index=0, .values={ __QX0_0, nullptr, __QX0_2, nullptr, nullptr, nullptr, nullptr, nullptr, } };\n"
|
||||
"GlueBoolGroup* __QG0(&___QG0);\n"
|
||||
"GlueBoolGroup ___QG1 { .index=1, .values={ nullptr, nullptr, nullptr, __QX1_3, nullptr, nullptr, nullptr, nullptr, } };\n"
|
||||
"GlueBoolGroup* __QG1(&___QG1);\n"
|
||||
GLUE_PREFIX
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(2);\n"
|
||||
"/// The packed glue variables.\n"
|
||||
"extern const GlueVariable oplc_glue_vars[] = {\n"
|
||||
" { IECLDT_OUT, IECLST_BIT, 0, 0, IECVT_BOOL, __QG0 },\n"
|
||||
" { IECLDT_OUT, IECLST_BIT, 1, 0, IECVT_BOOL, __QG1 },\n"
|
||||
"};\n\n";
|
||||
REQUIRE(output_stream.str() == expected);
|
||||
}
|
||||
|
||||
WHEN("Contains single BYTE at %IB0") {
|
||||
std::stringstream input_stream("__LOCATED_VAR(BYTE,__IB0,I,B,0)");
|
||||
generateBody(input_stream, output_stream, digest);
|
||||
const char* expected = PREFIX"\tbyte_input[0] = __IB0;\n" POSTFIX GLUE_PREFIX\
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n\
|
||||
/// The packed glue variables.\n\
|
||||
extern const GlueVariable oplc_glue_vars[] = {\n\
|
||||
{ IECLDT_IN, IECLST_BYTE, 0, 0, IECVT_BYTE, __IB0 },\n\
|
||||
};\n\n";
|
||||
const char* expected = PREFIX"\tbyte_input[0] = __IB0;\n" POSTFIX GLUE_PREFIX
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n"
|
||||
"/// The packed glue variables.\n"
|
||||
"extern const GlueVariable oplc_glue_vars[] = {\n"
|
||||
" { IECLDT_IN, IECLST_BYTE, 0, 0, IECVT_BYTE, __IB0 },\n"
|
||||
"};\n\n";
|
||||
REQUIRE(output_stream.str() == expected);
|
||||
}
|
||||
|
||||
WHEN("Contains single SINT at %IB1") {
|
||||
std::stringstream input_stream("__LOCATED_VAR(SINT,__IB1,I,B,1)");
|
||||
generateBody(input_stream, output_stream, digest);
|
||||
const char* expected = PREFIX "\tbyte_input[1] = __IB1;\n" POSTFIX GLUE_PREFIX\
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n\
|
||||
/// The packed glue variables.\n\
|
||||
extern const GlueVariable oplc_glue_vars[] = {\n\
|
||||
{ IECLDT_IN, IECLST_BYTE, 1, 0, IECVT_SINT, __IB1 },\n\
|
||||
};\n\n";
|
||||
const char* expected = PREFIX "\tbyte_input[1] = __IB1;\n" POSTFIX GLUE_PREFIX
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n"
|
||||
"/// The packed glue variables.\n"
|
||||
"extern const GlueVariable oplc_glue_vars[] = {\n"
|
||||
" { IECLDT_IN, IECLST_BYTE, 1, 0, IECVT_SINT, __IB1 },\n"
|
||||
"};\n\n";
|
||||
REQUIRE(output_stream.str() == expected);
|
||||
}
|
||||
|
||||
WHEN("Contains single SINT at %QB1") {
|
||||
std::stringstream input_stream("__LOCATED_VAR(SINT,__QB1,Q,B,1)");
|
||||
generateBody(input_stream, output_stream, digest);
|
||||
const char* expected = PREFIX "\tbyte_output[1] = __QB1;\n" POSTFIX GLUE_PREFIX\
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n\
|
||||
/// The packed glue variables.\n\
|
||||
extern const GlueVariable oplc_glue_vars[] = {\n\
|
||||
{ IECLDT_OUT, IECLST_BYTE, 1, 0, IECVT_SINT, __QB1 },\n\
|
||||
};\n\n";
|
||||
const char* expected = PREFIX "\tbyte_output[1] = __QB1;\n" POSTFIX GLUE_PREFIX
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n"
|
||||
"/// The packed glue variables.\n"
|
||||
"extern const GlueVariable oplc_glue_vars[] = {\n"
|
||||
" { IECLDT_OUT, IECLST_BYTE, 1, 0, IECVT_SINT, __QB1 },\n"
|
||||
"};\n\n";
|
||||
REQUIRE(output_stream.str() == expected);
|
||||
}
|
||||
|
||||
WHEN("Contains single USINT at %IB2") {
|
||||
std::stringstream input_stream("__LOCATED_VAR(USINT,__IB2,I,B,2)");
|
||||
generateBody(input_stream, output_stream, digest);
|
||||
const char* expected = PREFIX "\tbyte_input[2] = __IB2;\n" POSTFIX GLUE_PREFIX\
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n\
|
||||
/// The packed glue variables.\n\
|
||||
extern const GlueVariable oplc_glue_vars[] = {\n\
|
||||
{ IECLDT_IN, IECLST_BYTE, 2, 0, IECVT_USINT, __IB2 },\n\
|
||||
};\n\n";
|
||||
const char* expected = PREFIX "\tbyte_input[2] = __IB2;\n" POSTFIX GLUE_PREFIX
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n"
|
||||
"/// The packed glue variables.\n"
|
||||
"extern const GlueVariable oplc_glue_vars[] = {\n"
|
||||
" { IECLDT_IN, IECLST_BYTE, 2, 0, IECVT_USINT, __IB2 },\n"
|
||||
"};\n\n";
|
||||
REQUIRE(output_stream.str() == expected);
|
||||
}
|
||||
|
||||
WHEN("Contains single WORD at %IW0") {
|
||||
std::stringstream input_stream("__LOCATED_VAR(WORD,__IW0,I,W,0)");
|
||||
generateBody(input_stream, output_stream, digest);
|
||||
const char* expected = PREFIX "\tint_input[0] = __IW0;\n" POSTFIX GLUE_PREFIX\
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n\
|
||||
/// The packed glue variables.\n\
|
||||
extern const GlueVariable oplc_glue_vars[] = {\n\
|
||||
{ IECLDT_IN, IECLST_WORD, 0, 0, IECVT_WORD, __IW0 },\n\
|
||||
};\n\n";
|
||||
const char* expected = PREFIX "\tint_input[0] = __IW0;\n" POSTFIX GLUE_PREFIX
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n"
|
||||
"/// The packed glue variables.\n"
|
||||
"extern const GlueVariable oplc_glue_vars[] = {\n"
|
||||
" { IECLDT_IN, IECLST_WORD, 0, 0, IECVT_WORD, __IW0 },\n"
|
||||
"};\n\n";
|
||||
REQUIRE(output_stream.str() == expected);
|
||||
}
|
||||
|
||||
WHEN("Contains single WORD at %QW0") {
|
||||
std::stringstream input_stream("__LOCATED_VAR(WORD,__QW0,Q,W,0)");
|
||||
generateBody(input_stream, output_stream, digest);
|
||||
const char* expected = PREFIX "\tint_output[0] = __QW0;\n" POSTFIX GLUE_PREFIX\
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n\
|
||||
/// The packed glue variables.\n\
|
||||
extern const GlueVariable oplc_glue_vars[] = {\n\
|
||||
{ IECLDT_OUT, IECLST_WORD, 0, 0, IECVT_WORD, __QW0 },\n\
|
||||
};\n\n";
|
||||
const char* expected = PREFIX "\tint_output[0] = __QW0;\n" POSTFIX GLUE_PREFIX
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n"
|
||||
"/// The packed glue variables.\n"
|
||||
"extern const GlueVariable oplc_glue_vars[] = {\n"
|
||||
" { IECLDT_OUT, IECLST_WORD, 0, 0, IECVT_WORD, __QW0 },\n"
|
||||
"};\n\n";
|
||||
REQUIRE(output_stream.str() == expected);
|
||||
}
|
||||
|
||||
WHEN("Contains single INT at %IW1") {
|
||||
std::stringstream input_stream("__LOCATED_VAR(INT,__IW1,I,W,1)");
|
||||
generateBody(input_stream, output_stream, digest);
|
||||
const char* expected = PREFIX "\tint_input[1] = __IW1;\n" POSTFIX GLUE_PREFIX\
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n\
|
||||
/// The packed glue variables.\n\
|
||||
extern const GlueVariable oplc_glue_vars[] = {\n\
|
||||
{ IECLDT_IN, IECLST_WORD, 1, 0, IECVT_INT, __IW1 },\n\
|
||||
};\n\n";
|
||||
const char* expected = PREFIX "\tint_input[1] = __IW1;\n" POSTFIX GLUE_PREFIX
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n"
|
||||
"/// The packed glue variables.\n"
|
||||
"extern const GlueVariable oplc_glue_vars[] = {\n"
|
||||
" { IECLDT_IN, IECLST_WORD, 1, 0, IECVT_INT, __IW1 },\n"
|
||||
"};\n\n";
|
||||
REQUIRE(output_stream.str() == expected);
|
||||
}
|
||||
|
||||
|
@ -179,12 +202,12 @@ extern const GlueVariable oplc_glue_vars[] = {\n\
|
|||
std::stringstream input_stream("__LOCATED_VAR(UINT,__IW2,I,W,2)");
|
||||
generateBody(input_stream, output_stream, digest);
|
||||
|
||||
const char* expected = PREFIX "\tint_input[2] = __IW2;\n" POSTFIX GLUE_PREFIX\
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n\
|
||||
/// The packed glue variables.\n\
|
||||
extern const GlueVariable oplc_glue_vars[] = {\n\
|
||||
{ IECLDT_IN, IECLST_WORD, 2, 0, IECVT_UINT, __IW2 },\n\
|
||||
};\n\n";
|
||||
const char* expected = PREFIX "\tint_input[2] = __IW2;\n" POSTFIX GLUE_PREFIX
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n"
|
||||
"/// The packed glue variables.\n"
|
||||
"extern const GlueVariable oplc_glue_vars[] = {\n"
|
||||
" { IECLDT_IN, IECLST_WORD, 2, 0, IECVT_UINT, __IW2 },\n"
|
||||
"};\n\n";
|
||||
REQUIRE(output_stream.str() == expected);
|
||||
}
|
||||
|
||||
|
@ -193,61 +216,61 @@ extern const GlueVariable oplc_glue_vars[] = {\n\
|
|||
generateBody(input_stream, output_stream, digest);
|
||||
|
||||
// Note that the type-separate glue does not support REAL types
|
||||
const char* expected = PREFIX POSTFIX GLUE_PREFIX\
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(2);\n\
|
||||
/// The packed glue variables.\n\
|
||||
extern const GlueVariable oplc_glue_vars[] = {\n\
|
||||
{ IECLDT_IN, IECLST_DOUBLEWORD, 0, 0, IECVT_REAL, __ID0 },\n\
|
||||
{ IECLDT_IN, IECLST_DOUBLEWORD, 10, 0, IECVT_REAL, __ID10 },\n\
|
||||
};\n\n";
|
||||
const char* expected = PREFIX POSTFIX GLUE_PREFIX
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(2);\n"
|
||||
"/// The packed glue variables.\n"
|
||||
"extern const GlueVariable oplc_glue_vars[] = {\n"
|
||||
" { IECLDT_IN, IECLST_DOUBLEWORD, 0, 0, IECVT_REAL, __ID0 },\n"
|
||||
" { IECLDT_IN, IECLST_DOUBLEWORD, 10, 0, IECVT_REAL, __ID10 },\n"
|
||||
"};\n\n";
|
||||
REQUIRE(output_stream.str() == expected);
|
||||
}
|
||||
|
||||
WHEN("Contains single INT at %MW2") {
|
||||
std::stringstream input_stream("__LOCATED_VAR(INT,__MW2,M,W,2)");
|
||||
generateBody(input_stream, output_stream, digest);
|
||||
const char* expected = PREFIX "\tint_memory[2] = __MW2;\n" POSTFIX GLUE_PREFIX\
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n\
|
||||
/// The packed glue variables.\n\
|
||||
extern const GlueVariable oplc_glue_vars[] = {\n\
|
||||
{ IECLDT_MEM, IECLST_WORD, 2, 0, IECVT_INT, __MW2 },\n\
|
||||
};\n\n";
|
||||
const char* expected = PREFIX "\tint_memory[2] = __MW2;\n" POSTFIX GLUE_PREFIX
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n"
|
||||
"/// The packed glue variables.\n"
|
||||
"extern const GlueVariable oplc_glue_vars[] = {\n"
|
||||
" { IECLDT_MEM, IECLST_WORD, 2, 0, IECVT_INT, __MW2 },\n"
|
||||
"};\n\n";
|
||||
REQUIRE(output_stream.str() == expected);
|
||||
}
|
||||
|
||||
WHEN("Contains single DWORD at %MD0") {
|
||||
std::stringstream input_stream("__LOCATED_VAR(DWORD,__MD2,M,D,2)");
|
||||
generateBody(input_stream, output_stream, digest);
|
||||
const char* expected = PREFIX "\tdint_memory[2] = (IEC_DINT *)__MD2;\n" POSTFIX GLUE_PREFIX\
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n\
|
||||
/// The packed glue variables.\n\
|
||||
extern const GlueVariable oplc_glue_vars[] = {\n\
|
||||
{ IECLDT_MEM, IECLST_DOUBLEWORD, 2, 0, IECVT_DWORD, __MD2 },\n\
|
||||
};\n\n";
|
||||
const char* expected = PREFIX "\tdint_memory[2] = (IEC_DINT *)__MD2;\n" POSTFIX GLUE_PREFIX
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n"
|
||||
"/// The packed glue variables.\n"
|
||||
"extern const GlueVariable oplc_glue_vars[] = {\n"
|
||||
" { IECLDT_MEM, IECLST_DOUBLEWORD, 2, 0, IECVT_DWORD, __MD2 },\n"
|
||||
"};\n\n";
|
||||
REQUIRE(output_stream.str() == expected);
|
||||
}
|
||||
|
||||
WHEN("Contains single LINT at %ML1") {
|
||||
std::stringstream input_stream("__LOCATED_VAR(LINT,__ML1,M,L,1)");
|
||||
generateBody(input_stream, output_stream, digest);
|
||||
const char* expected = PREFIX "\tlint_memory[1] = (IEC_LINT *)__ML1;\n" POSTFIX GLUE_PREFIX\
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n\
|
||||
/// The packed glue variables.\n\
|
||||
extern const GlueVariable oplc_glue_vars[] = {\n\
|
||||
{ IECLDT_MEM, IECLST_LONGWORD, 1, 0, IECVT_LINT, __ML1 },\n\
|
||||
};\n\n";
|
||||
const char* expected = PREFIX "\tlint_memory[1] = (IEC_LINT *)__ML1;\n" POSTFIX GLUE_PREFIX
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n"
|
||||
"/// The packed glue variables.\n"
|
||||
"extern const GlueVariable oplc_glue_vars[] = {\n"
|
||||
" { IECLDT_MEM, IECLST_LONGWORD, 1, 0, IECVT_LINT, __ML1 },\n"
|
||||
"};\n\n";
|
||||
REQUIRE(output_stream.str() == expected);
|
||||
}
|
||||
|
||||
WHEN("Contains single LINT at %ML1024") {
|
||||
std::stringstream input_stream("__LOCATED_VAR(LINT,__ML1024,M,L,1024)");
|
||||
generateBody(input_stream, output_stream, digest);
|
||||
const char* expected = PREFIX "\tspecial_functions[0] = (IEC_LINT *)__ML1024;\n" POSTFIX GLUE_PREFIX\
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n\
|
||||
/// The packed glue variables.\n\
|
||||
extern const GlueVariable oplc_glue_vars[] = {\n\
|
||||
{ IECLDT_MEM, IECLST_LONGWORD, 1024, 0, IECVT_LINT, __ML1024 },\n\
|
||||
};\n\n";
|
||||
const char* expected = PREFIX "\tspecial_functions[0] = (IEC_LINT *)__ML1024;\n" POSTFIX GLUE_PREFIX
|
||||
"extern std::uint16_t const OPLCGLUE_GLUE_SIZE(1);\n"
|
||||
"/// The packed glue variables.\n"
|
||||
"extern const GlueVariable oplc_glue_vars[] = {\n"
|
||||
" { IECLDT_MEM, IECLST_LONGWORD, 1024, 0, IECVT_LINT, __ML1024 },\n"
|
||||
"};\n\n";
|
||||
REQUIRE(output_stream.str() == expected);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue