Commit 542db5fd authored by nickolay.kovalev's avatar nickolay.kovalev
Browse files

working port draft

parent 549eb4fb
# Based on from by Loic Hoguin <>
CURDIR := $(shell pwd)
BASEDIR := $(abspath $(CURDIR)/..)
PROJECT ?= $(notdir $(BASEDIR))
PROJECT := $(strip $(PROJECT))
ERTS_INCLUDE_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~ts/erts-~ts/include/\", [code:root_dir(), erlang:system_info(version)]).")
ERL_INTERFACE_INCLUDE_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~ts\", [code:lib_dir(erl_interface, include)]).")
ERL_INTERFACE_LIB_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~ts\", [code:lib_dir(erl_interface, lib)]).")
C_SRC_OUTPUT ?= $(CURDIR)/../priv/$(PROJECT).so
# System type and C compiler/flags.
UNAME_SYS := $(shell uname -s)
ifeq ($(UNAME_SYS), Darwin)
CC ?= cc
CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes
CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall
LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress
else ifeq ($(UNAME_SYS), FreeBSD)
CC ?= cc
CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
CXXFLAGS ?= -O3 -finline-functions -Wall
else ifeq ($(UNAME_SYS), Linux)
CC ?= gcc
CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes -Wno-narrowing
CXXFLAGS ?= -O3 -std=c++11 -finline-functions -Wall -Wno-narrowing
LDLIBS += -L $(ERL_INTERFACE_LIB_DIR) -lerl_interface -lei -lstdc++
LDFLAGS += -shared
# Verbosity.
c_verbose_0 = @echo " C " $(?F);
c_verbose = $(c_verbose_$(V))
cpp_verbose_0 = @echo " CPP " $(?F);
cpp_verbose = $(cpp_verbose_$(V))
link_verbose_0 = @echo " LD " $(@F);
link_verbose = $(link_verbose_$(V))
SOURCES := $(shell find $(C_SRC_DIR) -type f \( -name "*.c" -o -name "*.C" -o -name "*.cc" -o -name "*.cpp" \))
OBJECTS = $(addsuffix .o, $(basename $(SOURCES)))
COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c
COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c
@mkdir -p $(BASEDIR)/priv/
$(link_verbose) $(CC) $(OBJECTS) $(LDFLAGS) $(LDLIBS) -o $(C_SRC_OUTPUT)
%.o: %.c
%.o: %.C
%.o: %.cpp
\ No newline at end of file
#define CONNECT 0x01
#define DISCONNECT 0x02
\ No newline at end of file
#include "open62541Client.h"
#include "erlopen62541.h"
#include "erl_driver.h"
typedef struct {
ErlDrvPort port;
} port_data;
static class open62541Client client;
extern "C" {
static ErlDrvData example_drv_start(ErlDrvPort port, char *buff)
port_data* d = (port_data*)driver_alloc(sizeof(port_data));
d->port = port;
return (ErlDrvData)d;
static void example_drv_stop(ErlDrvData handle)
static void example_drv_output(ErlDrvData handle, char *buff, ErlDrvSizeT bufflen){
port_data* d = (port_data*)handle;
char msg_type = buff[0], res;
client.print_log("client: lib received request");
ErlDrvEntry example_driver_entry = {
NULL, /* F_PTR init, called when driver is loaded */
example_drv_start, /* L_PTR start, called when port is opened */
example_drv_stop, /* F_PTR stop, called when port is closed */
example_drv_output, /* F_PTR output, called when erlang has sent */
NULL, /* F_PTR ready_input, called when input descriptor ready */
NULL, /* F_PTR ready_output, called when output descriptor ready */
"erlopen62541", /* char *driver_name, the argument to open_port */
NULL, /* F_PTR finish, called when unloaded */
NULL, /* void *handle, Reserved by VM */
NULL, /* F_PTR control, port_command callback */
NULL, /* F_PTR timeout, reserved */
NULL, /* F_PTR outputv, reserved */
NULL, /* F_PTR ready_async, only for async drivers */
NULL, /* F_PTR flush, called when port is about
to be closed, but there is data in driver queue */
NULL, /* F_PTR call, much like control, sync call to driver */
NULL, /* F_PTR event, called when an event selected by driver_event() occurs. */
ERL_DRV_EXTENDED_MARKER, /* int extended marker, Should always be set to indicate driver versioning */
ERL_DRV_EXTENDED_MAJOR_VERSION, /* int major_version, should always be set to this value */
ERL_DRV_EXTENDED_MINOR_VERSION, /* int minor_version, should always be set to this value */
0, /* int driver_flags, see documentation */
NULL, /* void *handle2, reserved for VM use */
NULL, /* F_PTR process_exit, called when a monitored process dies */
NULL /* F_PTR stop_select, called to close an event object */
DRIVER_INIT(erlopen62541) /* must match name in driver_entry */
return &example_driver_entry;
#include <ctime>
#include "open62541Client.h"
open62541Client::open62541Client(){, std::ios::out);
print_log("File opened by magic");
print_log("File closed by machine");
if(logFile.is_open()) logFile.close();
void open62541Client::print_log(const char *string){
time_t t = time(0);
struct tm *now = localtime(&t);
char buf[80];
// strftime(buf, sizeof(buf), "%Y-%m-%d.%X", now);
strftime(buf, sizeof(buf), "%s", now);
logFile << buf << " " << string << std::endl;
#include <iostream>
#include <fstream>
#define LOG_NAME "balito.log"
class open62541Client {
std::ofstream logFile;
void print_log(const char *string);
\ No newline at end of file
% Header file for application-driver interface.
% Should be compatible with driver header file (erlopen62541.h)
-define(CONNECT, 16#01).
-define(DISCONNECT, 16#02).
\ No newline at end of file
{erl_opts, [debug_info]}.
{deps, []}.
[{"(linux|darwin|solaris)", compile, "make -C c_src"},
{"(freebsd)", compile, "gmake -C c_src"}]}.
[{"(linux|darwin|solaris)", clean, "make -C c_src clean"},
{"(freebsd)", clean, "gmake -C c_src clean"}]}.
{application, erlopen62541,
[{description, "Erlang port of open62541 client"},
{vsn, "0.0.1"},
{registered, []},
{modules, []},
{maintainers, []},
{links, []}
%% @doc
%% Port wrapper for open62541 client
%% @end
%% Copyright (c) 2020,
%% General API
-define(LIBRARY_NAME, "erlopen62541").
%% General API
start_link() ->
gen_server:start_link(?MODULE, [], []).
stop(Pid) ->
gen_server:call(Pid, stop).
connect(Pid) ->
gen_server:call(Pid, connect).
init([]) ->
case erl_ddll:load_driver("/home/nick/erlopen62541/priv/", ?LIBRARY_NAME) of
ok ->
{error, already_loaded} ->
{error, Reason} ->
exit({error, erl_ddll:format_error(Reason)})
%open port as driver in dll - session initialization occurs upon
Port = erlang:open_port({spawn, ?LIBRARY_NAME}, []),
{ok, #{port => Port}}.
%calls for management
handle_call(stop, _, State) ->
{stop, normal, State};
handle_call(connect, _, #{port := Port} = State) ->
Port ! {self(), {command, [?CONNECT]}},
{reply, ok, State};
handle_call(Msg, From, State) ->
io:format(?MODULE_STRING ++ ": What a call heck ~p in state: ~p from ~p", [Msg, From]),
{reply, ok, State}.
handle_cast(Msg, State) ->
io:format(?MODULE_STRING ++ ": What a cast heck ~p in state: ~p", [Msg]),
{noreply, State}.
handle_info(Msg, State) ->
io:format(?MODULE_STRING ++ ": What a info heck ~p in state: ~p", [Msg]),
{noreply, State}.
terminate(_Reason, _State) ->
code_change(_, State, _) ->
{ok, State}.
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment