Merge pull request #120 from garretfick/feature/ENIP_SERVICE

Make ENIP follow the same service-based approach
This commit is contained in:
Thiago Alves 2019-12-11 11:50:15 -05:00 committed by GitHub
commit 9c925c590d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 1509 additions and 1477 deletions

View File

@ -232,7 +232,7 @@ if(OPLC_MAIN_PROGRAM)
message("Compile main program enabled")
set(OPLC_USER_DIR ${PROJECT_SOURCE_DIR}/etc/src)
file(GLOB oplc_SRC runtime/core/*.cpp runtime/core/dnp3s/*.cpp runtime/core/modbusslave/*.cpp runtime/core/modbusmaster/*.cpp runtime/core/service/*.cpp runtime/vendor/inih-r46/*.c)
file(GLOB oplc_SRC runtime/core/*.cpp runtime/core/dnp3s/*.cpp runtime/core/modbusslave/*.cpp runtime/core/modbusmaster/*.cpp runtime/core/service/*.cpp runtime/core/enip/*.cpp runtime/vendor/inih-r46/*.c)
include_directories(${OPLC_USER_DIR})
include_directories(runtime/core)

View File

@ -26,7 +26,7 @@ endif()
include_directories(lib)
# The primary source is everything in this directory
file(GLOB oplc_SRC *.cpp dnp3s/*.cpp service/*.cpp modbusslave/*.cpp modbusmaster/*.cpp)
file(GLOB oplc_SRC *.cpp dnp3s/*.cpp service/*.cpp modbusslave/*.cpp modbusmaster/*.cpp enip/*.cpp)
message("In runtime")
message(${oplc_SRC})

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,49 @@
//-----------------------------------------------------------------------------
// Copyright 2019 Thiago Alves
// This file is part of the OpenPLC Software Stack.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http ://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissionsand
// limitations under the License.
// This file contains the structured used by enip.cpp to process
// EtherNet/IP requests.
// UAH, Sep 2019
//-----------------------------------------------------------------------------
/** \addtogroup openplc_runtime
* @{
*/
/** @} */
//-----------------------------------------------------------------------------
// Copyright 2019 Thiago Alves
// Copyright 2019 Garret Fick
// This file is part of the OpenPLC Software Stack.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http ://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissionsand
// limitations under the License.
// This file contains the structured used by enip.cpp to process
// EtherNet/IP requests.
// UAH, Sep 2019
//-----------------------------------------------------------------------------
#ifndef RUNTIME_CORE_ENIP_ENIP_H_
#define RUNTIME_CORE_ENIP_ENIP_H_
#include <cstdint>
/** \addtogroup openplc_runtime
* @{
*/
class GlueVariablesBinding;
/// @brief Start the enip server.
///
/// @param glue_variables The glue variables that may be bound into this
/// server.
/// @param run A signal for running this server. This server terminates when
/// this signal is false.
/// @param config The custom configuration for this service.
void enip_service_run(const GlueVariablesBinding& binding,
volatile bool& run, const char* config);
std::int16_t enip_process_message(unsigned char *buffer, std::int16_t buffer_size, void* user_data);
std::uint16_t processPCCCMessage(unsigned char *buffer, int buffer_size);
/** @} */
#endif // RUNTIME_CORE_ENIP_ENIP_H_

File diff suppressed because it is too large Load Diff

View File

@ -52,14 +52,8 @@
const uint16_t BUFFER_MAX_SIZE(1024);
std::mutex command_mutex;
// TODO Globals to move into services
bool run_enip = 0;
uint16_t enip_port = 44818;
time_t start_time;
// Global Threads
pthread_t enip_thread;
// Log Buffer
#define LOG_BUFFER_SIZE 1000000
unsigned char log_buffer[LOG_BUFFER_SIZE];
@ -67,43 +61,6 @@ std::shared_ptr<buffered_sink> log_sink;
using namespace std;
/// @brief Start the Enip Thread
/// @param *arg
void *enipThread(void *arg)
{
startServer(enip_port, run_enip, &processEnipMessage, nullptr);
return nullptr;
}
/// @brief Read the argument from a command function
/// @param *command
int readCommandArgument(const char *command)
{
int i = 0;
int j = 0;
char argument[BUFFER_MAX_SIZE];
while (command[i] != '(' && command[i] != '\0')
{
i++;
}
if (command[i] == '(')
{
i++;
}
while (command[i] != ')' && command[i] != '\0')
{
argument[j] = command[i];
i++;
j++;
argument[j] = '\0';
}
return atoi(reinterpret_cast<char *>(argument));
}
/// Copy the configuration argument from the command into the buffer
/// @param source The source of the command. This should be pointing to the
/// character right after the opening "("
@ -141,6 +98,30 @@ std::int8_t copy_command_config(const char *source, char target[],
return 0;
}
/// @brief Get the name of the service from the command.
/// @param command The command, starting with the character after "_"
/// @return The start of the configuration information.
const char* get_service_name(const char* command, char target[], size_t target_size)
{
size_t end_index = 0;
while (command[end_index] != '(' && command[end_index] != '\0')
{
end_index++;
}
// Now we want to copy everything from the beginning of source
// into target, up to the length of target. This may or many not
// fill our target, but the size ensure we don't go over the buffer
// size.
std::memcpy(target, command, min(end_index, target_size));
// And set the final null terminating character in target. In general
// this is replacing the null terminating character with the right end.
target[end_index] = '\0';
return command + end_index + 1;
}
/// @brief Create the socket and bind it.
/// @param port
/// @return the file descriptor for the socket, or less than 0 if a socket
@ -240,91 +221,55 @@ void interactive_client_command(const char* command, int client_fd)
return;
}
spdlog::trace("Process command received {}", command);
spdlog::trace("Command received {}", command);
if (strncmp(command, "quit()", 6) == 0)
{
spdlog::info("Issued quit() command");
run_openplc = 0;
}
else if (strncmp(command, "start_modbus(", 13) == 0)
else if (strncmp(command, "start_", 6) == 0)
{
ServiceDefinition* def = services_find("modbusslave");
if (def && copy_command_config(command + 13, command_buffer, BUFFER_MAX_SIZE) == 0)
char service_name[MAX_SERVICE_NAME_SIZE];
auto config_start = get_service_name(command + 6, service_name, MAX_SERVICE_NAME_SIZE);
ServiceDefinition* def = services_find(service_name);
if (!def)
{
spdlog::error("Unrecognized service name {}", service_name);
int count_char = sprintf(command_buffer, "Error: unrecognized service name '%s'\n", service_name);
write(client_fd, command_buffer, count_char);
return;
}
if (copy_command_config(config_start, command_buffer, BUFFER_MAX_SIZE) == 0)
{
def->start(command_buffer);
}
}
else if (strncmp(command, "stop_modbus()", 13) == 0)
{
ServiceDefinition* def = services_find("modbusslave");
if (def)
else
{
def->stop();
spdlog::error("Unable to start service due {} to missing config", service_name);
}
}
#ifdef OPLC_DNP3_OUTSTATION
else if (strncmp(command, "start_dnp3(", 11) == 0)
else if (strncmp(command, "stop_", 5) == 0)
{
ServiceDefinition* def = services_find("dnp3s");
if (def && copy_command_config(command + 11, command_buffer, BUFFER_MAX_SIZE) == 0)
char service_name[MAX_SERVICE_NAME_SIZE];
auto config_start = get_service_name(command + 5, service_name, MAX_SERVICE_NAME_SIZE);
ServiceDefinition* def = services_find(service_name);
if (!def)
{
def->start(command_buffer);
}
}
else if (strncmp(command, "stop_dnp3()", 11) == 0)
{
ServiceDefinition* def = services_find("dnp3s");
if (def)
{
def->stop();
}
}
#endif // OPLC_DNP3_OUTSTATION
else if (strncmp(command, "start_enip(", 11) == 0)
{
spdlog::info("Issued start_enip() command to start on port: {}", readCommandArgument(command));
enip_port = readCommandArgument(command);
if (run_enip) {
spdlog::info("EtherNet/IP server already active. Restarting on port: {}", enip_port);
//Stop Enip server
run_enip = 0;
pthread_join(enip_thread, NULL);
spdlog::info("EtherNet/IP server was stopped");
}
//Start Enip server
run_enip = 1;
pthread_create(&enip_thread, NULL, enipThread, NULL);
}
else if (strncmp(command, "stop_enip()", 11) == 0)
{
spdlog::info("Issued stop_enip() command");
if (run_enip)
{
run_enip = 0;
pthread_join(enip_thread, NULL);
spdlog::info("EtherNet/IP server was stopped");
}
}
else if (strncmp(command, "start_pstorage(", 15) == 0)
{
ServiceDefinition* def = services_find("pstorage");
if (def && copy_command_config(command + 15, command_buffer, BUFFER_MAX_SIZE) == 0)
{
def->start(command_buffer);
}
}
else if (strncmp(command, "stop_pstorage()", 15) == 0)
{
ServiceDefinition* def = services_find("pstorage");
if (def)
{
def->stop();
int count_char = sprintf(command_buffer, "Error: unrecognized service name '%s'\n", service_name);
write(client_fd, command_buffer, count_char);
return;
}
def->stop();
}
else if (strncmp(command, "runtime_logs()", 14) == 0)
{
spdlog::debug("Issued runtime_logs() command");
spdlog::trace("Issued runtime_logs() command");
std::string data = log_sink->data();
write(client_fd, data.c_str(), data.size());
return;
@ -339,6 +284,7 @@ void interactive_client_command(const char* command, int client_fd)
}
else
{
spdlog::error("Unrecognized command {}", command_buffer);
int count_char = sprintf(command_buffer, "Error: unrecognized command\n");
write(client_fd, command_buffer, count_char);
return;
@ -401,7 +347,7 @@ void* interactive_client_run(void* arguments)
}
}
closeSocket(client_args->client_fd);
close_socket(client_args->client_fd);
spdlog::trace("Interactive server connection completed");
delete client_args;
pthread_exit(NULL);
@ -436,7 +382,7 @@ void interactive_run(oplc::config_stream& cfg_stream,
auto args = new ClientArgs { .client_fd = client_fd, .run = &run };
spdlog::trace("Interactive Server: Client accepted! Creating thread for the new client ID: {}", client_fd);
int ret = pthread_create(&thread, NULL, interactive_client_run, args);
int ret = pthread_create(&thread, nullptr, interactive_client_run, args);
if (ret == 0)
{
pthread_detach(thread);
@ -447,7 +393,7 @@ void interactive_run(oplc::config_stream& cfg_stream,
}
}
closeSocket(socket_fd);
close_socket(socket_fd);
}
void interactive_service_run(const GlueVariablesBinding& binding,

View File

@ -1,4 +1,5 @@
// Copyright 2015 Thiago Alves
// Copyright 2019 Garret Fick
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -82,11 +83,6 @@ extern unsigned long long common_ticktime__;
struct GlueVariable;
class GlueVariablesBinding;
extern const std::uint16_t OPLCGLUE_GLUE_SIZE;
extern const GlueVariable oplc_glue_vars[];
extern const char OPLCGLUE_MD5_DIGEST[];
//----------------------------------------------------------------------
// FUNCTION PROTOTYPES
//----------------------------------------------------------------------
@ -119,26 +115,17 @@ extern int ignored_int_outputs[];
void sleep_until(struct timespec *ts, int delay);
bool pinNotPresent(int *ignored_vector, int vector_size, int pinNumber);
extern uint8_t run_openplc;
void handleSpecialFunctions();
// server.cpp
typedef std::int16_t (*process_message_fn)(unsigned char *buffer, std::int16_t buffer_size, void* user_data);
void startServer(uint16_t port, volatile bool& run_server, process_message_fn process_message, void* user_data);
int getSO_ERROR(int fd);
void closeSocket(int fd);
void start_server(uint16_t port, volatile bool& run_server, process_message_fn process_message, void* user_data);
void close_socket(int fd);
bool SetSocketBlockingEnabled(int fd, bool blocking);
// interactive_server.cpp
void initialize_logging(int argc, char **argv);
extern bool run_enip;
extern time_t start_time;
// enip.cpp
std::int16_t processEnipMessage(unsigned char *buffer, std::int16_t buffer_size, void* user_data);
// pccc.cpp ADDED Ulmer
uint16_t processPCCCMessage(unsigned char *buffer, int buffer_size);
void bootstrap();
/** @}*/

View File

@ -116,7 +116,7 @@ void disableOutputs()
////////////////////////////////////////////////////////////////////////////////
/// \brief Special Functions
////////////////////////////////////////////////////////////////////////////////
void handleSpecialFunctions()
void handle_special_functions()
{
// Current time [%ML1024]
struct tm *current_time;
@ -191,14 +191,11 @@ int main(int argc, char **argv)
updateBuffersIn();
{
std::lock_guard<std::mutex> guard(bufferLock);
// Make sure the buffer pointers are correct and
// attached to the user variables
glueVars();
updateCustomIn();
// Update input image table with data from slave devices
services_before_cycle();
handleSpecialFunctions();
handle_special_functions();
// Execute plc program logic
config_run__(__tick++);
updateCustomOut();

View File

@ -482,7 +482,7 @@ int8_t modbus_slave_run(oplc::config_stream& cfg_stream,
}
spdlog::info("Starting modbus slave on port {}", config.port);
startServer(config.port, run, &modbus_process_message, &strategy);
start_server(config.port, run, &modbus_process_message, &strategy);
pthread_join(exchange_data_thread, nullptr);

View File

@ -44,7 +44,7 @@ using namespace std;
////////////////////////////////////////////////////////////////////////////////
/// @brief Verify if all errors were cleared on a socket
////////////////////////////////////////////////////////////////////////////////
int getSO_ERROR(int fd)
int get_socket_error(int fd)
{
int err = 1;
socklen_t len = sizeof err;
@ -58,11 +58,11 @@ int getSO_ERROR(int fd)
////////////////////////////////////////////////////////////////////////////////
/// @brief Properly close a socket
////////////////////////////////////////////////////////////////////////////////
void closeSocket(int fd)
void close_socket(int fd)
{
if (fd >= 0)
{
getSO_ERROR(fd); // first clear any errors, which can cause close to fail
get_socket_error(fd); // first clear any errors, which can cause close to fail
if (shutdown(fd, SHUT_RDWR) < 0) // secondly, terminate the 'reliable' delivery
if (errno != ENOTCONN && errno != EINVAL) // SGI causes EINVAL
perror("shutdown");
@ -88,7 +88,7 @@ bool SetSocketBlockingEnabled(int fd, bool blocking)
/// @param port
/// @return the file descriptor for the socket created
////////////////////////////////////////////////////////////////////////////////
int createSocket(uint16_t port)
int create_socket(uint16_t port)
{
int socket_fd;
struct sockaddr_in server_addr;
@ -136,7 +136,7 @@ int createSocket(uint16_t port)
/// @param run_server A flag to terminate this client.
/// @return file descriptor to communicate with the client
////////////////////////////////////////////////////////////////////////////////
int waitForClient(int socket_fd, volatile bool& run_server)
int wait_for_client(int socket_fd, volatile bool& run_server)
{
int client_fd;
struct sockaddr_in client_addr;
@ -167,7 +167,7 @@ int waitForClient(int socket_fd, volatile bool& run_server)
/// @param buffer
/// @return the number of bytes received.
////////////////////////////////////////////////////////////////////////////////
int listenToClient(int client_fd, unsigned char *buffer)
int listen_to_client(int client_fd, unsigned char *buffer)
{
bzero(buffer, NET_BUFFER_SIZE);
int n = read(client_fd, buffer, NET_BUFFER_SIZE);
@ -190,19 +190,18 @@ struct ServerArgs
////////////////////////////////////////////////////////////////////////////////
/// @brief Thread to handle requests for each connected client
////////////////////////////////////////////////////////////////////////////////
void *handleConnections(void *arguments)
void *handle_connections(void *arguments)
{
auto args = reinterpret_cast<ServerArgs*>(arguments);
unsigned char buffer[NET_BUFFER_SIZE];
int message_size;
int client_fd = args->client_fd;
spdlog::debug("Server: Thread created for client ID: {}", client_fd);
while(*args->run)
{
message_size = listenToClient(client_fd, buffer);
auto message_size = listen_to_client(client_fd, buffer);
if (message_size <= 0 || message_size > NET_BUFFER_SIZE)
{
// something has gone wrong or the client has closed connection
@ -230,7 +229,7 @@ void *handleConnections(void *arguments)
spdlog::trace("Closing client socket and calling pthread_exit");
close(args->client_fd);
spdlog::trace("Terminating server connections thread");
pthread_exit(NULL);
pthread_exit(nullptr);
delete args;
return nullptr;
@ -244,15 +243,15 @@ void *handleConnections(void *arguments)
/// @param port The port to listen on.
/// @param process_message A function to run to process socket messages.
/// @param user_data Passed into the process_message function as client data.
void startServer(uint16_t port, volatile bool& run_server, process_message_fn process_message, void* user_data)
void start_server(uint16_t port, volatile bool& run_server, process_message_fn process_message, void* user_data)
{
int socket_fd, client_fd;
socket_fd = createSocket(port);
socket_fd = create_socket(port);
while(run_server)
{
client_fd = waitForClient(socket_fd, run_server); //block until a client connects
client_fd = wait_for_client(socket_fd, run_server); //block until a client connects
if (client_fd < 0)
{
spdlog::error("Server: Error accepting client!");
@ -268,7 +267,7 @@ void startServer(uint16_t port, volatile bool& run_server, process_message_fn pr
.user_data=user_data
};
spdlog::trace("Server: Client accepted on {}! Creating thread for the new client ID: {}...", port, client_fd);
int success = pthread_create(&thread, NULL, handleConnections, args);
int success = pthread_create(&thread, NULL, handle_connections, args);
if (success == 0)
{
pthread_detach(thread);

View File

@ -14,10 +14,19 @@
#include <spdlog/spdlog.h>
#include <algorithm>
#include <mutex>
#include "service_definition.h"
#include "glue.h"
#include "ladder.h"
// These definitions are provided by the glueVars.cpp
// implementation file. They define the information about
// glue variables that we pass to services during a lifecycle
// function.
extern std::mutex bufferLock;
extern const std::uint16_t OPLCGLUE_GLUE_SIZE;
extern const GlueVariable oplc_glue_vars[];
extern const char OPLCGLUE_MD5_DIGEST[];
using namespace std;

View File

@ -19,6 +19,7 @@
#include "service_registry.h"
#include "interactive_server.h"
#include "pstorage.h"
#include "enip/enip.h"
#include "modbusslave/slave.h"
#include "modbusmaster/master_indexed.h"
#include "dnp3s/dnp3.h"
@ -34,6 +35,7 @@ ServiceDefinition* services[] = {
#ifdef OPLC_DNP3_OUTSTATION
new ServiceDefinition("dnp3s", dnp3s_service_run),
#endif
new ServiceDefinition("enip", enip_service_run)
};
ServiceDefinition* services_find(const char* name)

View File

@ -15,12 +15,16 @@
#ifndef RUNTIME_CORE_SERVICE_SERVICE_REGISTRY_H_
#define RUNTIME_CORE_SERVICE_SERVICE_REGISTRY_H_
#include <cstdint>
/** \addtogroup openplc_runtime
* @{
*/
class ServiceDefinition;
const std::size_t MAX_SERVICE_NAME_SIZE = 512;
/// @brief Finds the service in the registry by the name of the service.
/// @param name The identifier for the service.
/// @return The service if found, or nullptr if there is no such service.

View File

@ -442,7 +442,7 @@ void generate_bool_groups(ostream& glueVars, list<IecVar>& all_vars) {
void generate_integrated_glue(ostream& glueVars, const list<IecVar>& all_vars) {
glueVars << "/// The size of the array of glue variables.\n";
glueVars << "extern std::size_t const OPLCGLUE_GLUE_SIZE(";
glueVars << "extern const std::size_t OPLCGLUE_GLUE_SIZE(";
glueVars << all_vars.size() << ");\n";
glueVars << "/// The packed glue variables.\n";

View File

@ -29,19 +29,19 @@ using namespace std;
#define PREFIX "void glueVars()\n{\n"
#define POSTFIX "}\n\n"
#define EMPTY_INPUT "/// The size of the array of input variables.\n\
extern std::size_t const OPLCGLUE_INPUT_SIZE(0);\n\
extern const std::size_t OPLCGLUE_INPUT_SIZE(0);\n\
GlueVariable oplc_input_vars[] = {\n\
};\n\n"
#define EMPTY_OUTPUT "/// The size of the array of output variables.\n\
extern std::size_t const OPLCGLUE_OUTPUT_SIZE(0);\n\
extern const std::size_t OPLCGLUE_OUTPUT_SIZE(0);\n\
GlueVariable oplc_output_vars[] = {\n\
};\n\n"
#define EMPTY_INPUT_BOOL "/// Size of the array of input boolean variables.\n\
extern std::size_t const OPLCGLUE_INPUT_BOOL_SIZE(0);\n\
extern const std::size_t OPLCGLUE_INPUT_BOOL_SIZE(0);\n\
GlueBoolGroup oplc_bool_input_vars[] = {\n\
};\n\n"
#define EMPTY_OUTPUT_BOOL "/// Size of the array of output boolean variables.\n\
extern std::size_t const OPLCGLUE_OUTPUT_BOOL_SIZE(0);\n\
extern const std::size_t OPLCGLUE_OUTPUT_BOOL_SIZE(0);\n\
GlueBoolGroup oplc_bool_output_vars[] = {\n\
};\n\n"
#define GLUE_PREFIX "/// The size of the array of glue variables.\n"
@ -79,7 +79,7 @@ SCENARIO("", "") {
"GlueBoolGroup ___IG0 { .index=0, .values={ __IX0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, } };\n"
"GlueBoolGroup* __IG0(&___IG0);\n"
GLUE_PREFIX
"extern std::size_t const OPLCGLUE_GLUE_SIZE(1);\n"
"extern const std::size_t 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"
@ -94,7 +94,7 @@ SCENARIO("", "") {
"GlueBoolGroup ___QG0 { .index=0, .values={ __QX0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, } };\n"
"GlueBoolGroup* __QG0(&___QG0);\n"
GLUE_PREFIX
"extern std::size_t const OPLCGLUE_GLUE_SIZE(1);\n"
"extern const std::size_t 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"
@ -111,7 +111,7 @@ SCENARIO("", "") {
"GlueBoolGroup ___QG1 { .index=1, .values={ nullptr, nullptr, nullptr, __QX1_3, nullptr, nullptr, nullptr, nullptr, } };\n"
"GlueBoolGroup* __QG1(&___QG1);\n"
GLUE_PREFIX
"extern std::size_t const OPLCGLUE_GLUE_SIZE(2);\n"
"extern const std::size_t 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"
@ -124,7 +124,7 @@ SCENARIO("", "") {
std::stringstream input_stream("__LOCATED_VAR(BYTE,__IB0,I,B,0)");
generate_body(input_stream, output_stream, digest);
const char* expected = PREFIX"\tbyte_input[0] = __IB0;\n" POSTFIX GLUE_PREFIX
"extern std::size_t const OPLCGLUE_GLUE_SIZE(1);\n"
"extern const std::size_t 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"
@ -136,7 +136,7 @@ SCENARIO("", "") {
std::stringstream input_stream("__LOCATED_VAR(SINT,__IB1,I,B,1)");
generate_body(input_stream, output_stream, digest);
const char* expected = PREFIX "\tbyte_input[1] = __IB1;\n" POSTFIX GLUE_PREFIX
"extern std::size_t const OPLCGLUE_GLUE_SIZE(1);\n"
"extern const std::size_t 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"
@ -148,7 +148,7 @@ SCENARIO("", "") {
std::stringstream input_stream("__LOCATED_VAR(SINT,__QB1,Q,B,1)");
generate_body(input_stream, output_stream, digest);
const char* expected = PREFIX "\tbyte_output[1] = __QB1;\n" POSTFIX GLUE_PREFIX
"extern std::size_t const OPLCGLUE_GLUE_SIZE(1);\n"
"extern const std::size_t 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"
@ -160,7 +160,7 @@ SCENARIO("", "") {
std::stringstream input_stream("__LOCATED_VAR(USINT,__IB2,I,B,2)");
generate_body(input_stream, output_stream, digest);
const char* expected = PREFIX "\tbyte_input[2] = __IB2;\n" POSTFIX GLUE_PREFIX
"extern std::size_t const OPLCGLUE_GLUE_SIZE(1);\n"
"extern const std::size_t 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"
@ -172,7 +172,7 @@ SCENARIO("", "") {
std::stringstream input_stream("__LOCATED_VAR(WORD,__IW0,I,W,0)");
generate_body(input_stream, output_stream, digest);
const char* expected = PREFIX "\tint_input[0] = __IW0;\n" POSTFIX GLUE_PREFIX
"extern std::size_t const OPLCGLUE_GLUE_SIZE(1);\n"
"extern const std::size_t 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"
@ -184,7 +184,7 @@ SCENARIO("", "") {
std::stringstream input_stream("__LOCATED_VAR(WORD,__QW0,Q,W,0)");
generate_body(input_stream, output_stream, digest);
const char* expected = PREFIX "\tint_output[0] = __QW0;\n" POSTFIX GLUE_PREFIX
"extern std::size_t const OPLCGLUE_GLUE_SIZE(1);\n"
"extern const std::size_t 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"
@ -196,7 +196,7 @@ SCENARIO("", "") {
std::stringstream input_stream("__LOCATED_VAR(INT,__IW1,I,W,1)");
generate_body(input_stream, output_stream, digest);
const char* expected = PREFIX "\tint_input[1] = __IW1;\n" POSTFIX GLUE_PREFIX
"extern std::size_t const OPLCGLUE_GLUE_SIZE(1);\n"
"extern const std::size_t 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"
@ -209,7 +209,7 @@ SCENARIO("", "") {
generate_body(input_stream, output_stream, digest);
const char* expected = PREFIX "\tint_input[2] = __IW2;\n" POSTFIX GLUE_PREFIX
"extern std::size_t const OPLCGLUE_GLUE_SIZE(1);\n"
"extern const std::size_t 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"
@ -223,7 +223,7 @@ SCENARIO("", "") {
// Note that the type-separate glue does not support REAL types
const char* expected = PREFIX POSTFIX GLUE_PREFIX
"extern std::size_t const OPLCGLUE_GLUE_SIZE(2);\n"
"extern const std::size_t 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"
@ -236,7 +236,7 @@ SCENARIO("", "") {
std::stringstream input_stream("__LOCATED_VAR(INT,__MW2,M,W,2)");
generate_body(input_stream, output_stream, digest);
const char* expected = PREFIX "\tint_memory[2] = __MW2;\n" POSTFIX GLUE_PREFIX
"extern std::size_t const OPLCGLUE_GLUE_SIZE(1);\n"
"extern const std::size_t 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"
@ -248,7 +248,7 @@ SCENARIO("", "") {
std::stringstream input_stream("__LOCATED_VAR(DWORD,__MD2,M,D,2)");
generate_body(input_stream, output_stream, digest);
const char* expected = PREFIX "\tdint_memory[2] = (IEC_DINT *)__MD2;\n" POSTFIX GLUE_PREFIX
"extern std::size_t const OPLCGLUE_GLUE_SIZE(1);\n"
"extern const std::size_t 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"
@ -260,7 +260,7 @@ SCENARIO("", "") {
std::stringstream input_stream("__LOCATED_VAR(LINT,__ML1,M,L,1)");
generate_body(input_stream, output_stream, digest);
const char* expected = PREFIX "\tlint_memory[1] = (IEC_LINT *)__ML1;\n" POSTFIX GLUE_PREFIX
"extern std::size_t const OPLCGLUE_GLUE_SIZE(1);\n"
"extern const std::size_t 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"
@ -272,7 +272,7 @@ SCENARIO("", "") {
std::stringstream input_stream("__LOCATED_VAR(LINT,__ML1024,M,L,1024)");
generate_body(input_stream, output_stream, digest);
const char* expected = PREFIX "\tspecial_functions[0] = (IEC_LINT *)__ML1024;\n" POSTFIX GLUE_PREFIX
"extern std::size_t const OPLCGLUE_GLUE_SIZE(1);\n"
"extern const std::size_t 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"

View File

@ -167,7 +167,7 @@ class runtime:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 43628))
s.send(b'start_modbus(' + str(port_num) + ')\n')
s.send(b'start_modbusslave(' + str(port_num) + ')\n')
data = s.recv(1000)
s.close()
except:
@ -178,7 +178,7 @@ class runtime:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 43628))
s.send(b'stop_modbus()\n')
s.send(b'stop_modbusslave()\n')
data = s.recv(1000)
s.close()
except:
@ -189,7 +189,7 @@ class runtime:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 43628))
s.send(b'start_dnp3(' + str(port_num) + ')\n')
s.send(b'start_dnp3s(' + str(port_num) + ')\n')
data = s.recv(1000)
s.close()
except:
@ -200,7 +200,7 @@ class runtime:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 43628))
s.send(b'stop_dnp3()\n')
s.send(b'stop_dnp3s()\n')
data = s.recv(1000)
s.close()
except: