Commit 5440e07d authored by nickolay.kovalev's avatar nickolay.kovalev
Browse files

read node interface and typesation of response

parent d549b70c
......@@ -11,11 +11,15 @@
#define BUFFER_LEN 1024
void error_logger(void *context, UA_LogLevel level, UA_LogCategory category,
void parseIdentity(const char *identity, int32_t *nmSpace, uint32_t *nodeId);
void parseType(UA_Variant *value, char *destination, uint32_t *len);
const char * const boolToString(bool b);
void errorLogger(void *context, UA_LogLevel level, UA_LogCategory category,
const char *msg, va_list args);
void error_clear(void *logContext);
void errorClear(void *logContext);
int is_big_endian(void)
int isBigEndian(void)
{
union {
uint32_t i;
......@@ -34,23 +38,23 @@ uint32_t swapByteOrder(uint32_t ui)
return ui;
}
uint32_t read_packet_length(std::istream& s)
uint32_t readPacketLength(std::istream& s)
{
uint32_t len;
s.read(reinterpret_cast<char*>(&len), sizeof(len));
if (!is_big_endian())
if (!isBigEndian())
len = swapByteOrder(len);
//std::cerr << 'r' << len << ' ';
//std::cerr.flush();
return len;
}
std::ostream& write_packet_length(std::ostream& s, uint32_t len)
std::ostream& writePacketLength(std::ostream& s, uint32_t len)
{
//std::cerr << 'w' << len << ' ';
//std::cerr.flush();
if (!is_big_endian())
if (!isBigEndian())
len = swapByteOrder(len);
s.write(reinterpret_cast<char*>(&len), sizeof(len));
return s;
......@@ -58,19 +62,21 @@ std::ostream& write_packet_length(std::ostream& s, uint32_t len)
int main(void)
{
char output;
char *output = new char[BUFFER_LEN];
UA_StatusCode retval;
UA_Variant value;
UA_NodeId nodeId;
int node_int;
uint32_t nodeid;
int32_t nmSpace;
UA_Client *client = UA_Client_new();
UA_ClientConfig *conf = UA_Client_getConfig(client);
/* Default logger is using stdout which is used by port, thus redefined */
conf->logger.log = error_logger;
conf->logger.log = errorLogger;
conf->logger.context = NULL;
conf->logger.clear = error_clear;
conf->logger.clear = errorClear;
/* Prosys OPC UA simulator crashes if not set */
conf->clientDescription.applicationName = UA_LOCALIZEDTEXT_ALLOC("en", "erlopen62541");
......@@ -83,7 +89,7 @@ int main(void)
while(true)
{
/* read len, 4 bytes */
uint32_t len = read_packet_length(std::cin);
uint32_t len = readPacketLength(std::cin);
/* read data, len bytes */
char* input = new char[len];
......@@ -96,50 +102,65 @@ int main(void)
std::cerr.flush();
retval = UA_Client_connect(client, input+1); /* Connects to server */
output = (retval != UA_STATUSCODE_GOOD) ? NOT_OK : OK;
*output = (retval != UA_STATUSCODE_GOOD) ? NOT_OK : OK;
//std::cerr << "CONNECTed "<< output << std::endl;
//std::cerr.flush();
write_packet_length(std::cout, 1);
std::cout.write(&output, 1);
writePacketLength(std::cout, 1);
std::cout.write(output, 1);
std::cout.flush();
break;
case DISCONNECT:
std::cerr << "DISCONNECT clause " << std::endl;
std::cerr.flush();
UA_Client_delete(client); /* Disconnects the client internally */
output = OK;
write_packet_length(std::cout, 1);
std::cout.write(&output, 1);
*output = OK;
writePacketLength(std::cout, 1);
std::cout.write(output, 1);
std::cout.flush();
break;
case READ_NODE:
UA_Variant_init(&value);
node_int = std::stoi(input+1);
std::cerr << "READ_NODE clause " << node_int << std::endl;
case READ_NODE:
parseIdentity(input+1, &nmSpace, &nodeid);
std::cerr << "input: " << input << std::endl;
std::cerr << "READ_NODE: " << nmSpace << ":" << nodeid << std::endl;
std::cerr.flush();
if(nmSpace >= 0){
nodeId = UA_NODEID_NUMERIC(nmSpace, nodeid);
UA_Variant_init(&value);
/* Read value from server */
retval = UA_Client_readValueAttribute(client, nodeId, &value);
/* Parse value and populate output */
if(retval == UA_STATUSCODE_GOOD){
parseType(&value, output, &len);
}
else{
std::string error_resp = "error|Client failed to read server data";
error_resp.copy(output, error_resp.size(), 0);
len = error_resp.size();
}
/* Clean up */
UA_Variant_clear(&value);
}
else
{
std::string error_resp = "error|Wrong identifier requested";
error_resp.copy(output, error_resp.size(), 0);
len = error_resp.size();
}
std::cerr << "read_response: " << output << std::endl;
std::cerr << "read_response_len: " << len << std::endl;
std::cerr.flush();
nodeId = UA_NODEID_NUMERIC(0, node_int);
retval = UA_Client_readValueAttribute(client, nodeId, &value);
std::cerr.flush();
if(retval == UA_STATUSCODE_GOOD &&
UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DATETIME])) {
UA_DateTime raw_date = *(UA_DateTime *) value.data;
UA_DateTimeStruct dts = UA_DateTime_toStruct(raw_date);
std::cerr
<< dts.day << "/" << dts.month << "/" << dts.year << " "
<< dts.hour << ":" << dts.min << ":" << dts.sec << "." << dts.milliSec << std::endl;
std::cerr.flush();
output = OK;
}
else{
output = NOT_OK;
}
UA_Variant_clear(&value); /* Clean up */
write_packet_length(std::cout, 1);
std::cout.write(&output, 1);
writePacketLength(std::cout, len);
std::cout.write(output, len);
std::cout.flush();
break;
default:
......@@ -153,11 +174,148 @@ int main(void)
return 0;
}
void error_logger(void *context, UA_LogLevel level, UA_LogCategory category,
void errorLogger(void *context, UA_LogLevel level, UA_LogCategory category,
const char *msg, va_list args) {
}
void error_clear(void *logContext) {
void errorClear(void *logContext) {
}
void parseType(UA_Variant *value, char *destination, uint32_t *len){
/* datetime type */
if(UA_Variant_hasScalarType(value, &UA_TYPES[UA_TYPES_DATETIME])){
UA_DateTime raw_date = *(UA_DateTime *) value->data;
UA_DateTimeStruct dts = UA_DateTime_toStruct(raw_date);
std::string d = std::to_string(dts.day);
std::string mo = std::to_string(dts.month);
std::string y = std::to_string(dts.year);
std::string h = std::to_string(dts.hour);
std::string mi = std::to_string(dts.min);
std::string s = std::to_string(dts.sec);
std::string ms = std::to_string(dts.milliSec);
std::string dt_resp = "datetime|" + d + "/" + mo + "/" + y + " " + h + ":" + mi + ":" + s + "." + ms;
if(dt_resp.size() < BUFFER_LEN){
dt_resp.copy(destination, dt_resp.size(), 0);
*len = dt_resp.size();
}
else{
std::string error_resp = "error|Buffer too small for datetime type";
error_resp.copy(destination, error_resp.size(), 0);
*len = error_resp.size();
}
}
/* boolean type */
else if(UA_Variant_hasScalarType(value, &UA_TYPES[UA_TYPES_BOOLEAN])) {
UA_Boolean bool_value = *(UA_Boolean *) value->data;
std::string bool_string(boolToString(bool_value));
std::string bool_resp = "bool|" + bool_string;
bool_resp.copy(destination, bool_resp.size(), 0);
*len = bool_resp.size();
}
/* Signed integer types */
else if(UA_Variant_hasScalarType(value, &UA_TYPES[UA_TYPES_SBYTE])) {
UA_SByte int_val = *(UA_SByte *) value->data;
std::string int_resp = "int|" + std::to_string(int_val);
int_resp.copy(destination, int_resp.size(), 0);
*len = int_resp.size();
}
else if(UA_Variant_hasScalarType(value, &UA_TYPES[UA_TYPES_BYTE])) {
UA_Byte int_val = *(UA_Byte *) value->data;
std::string int_resp = "int|" + std::to_string(int_val);
int_resp.copy(destination, int_resp.size(), 0);
*len = int_resp.size();
}
else if(UA_Variant_hasScalarType(value, &UA_TYPES[UA_TYPES_INT16])) {
UA_Int16 int_val = *(UA_Int16 *) value->data;
std::string int_resp = "int|" + std::to_string(int_val);
int_resp.copy(destination, int_resp.size(), 0);
*len = int_resp.size();
}
else if(UA_Variant_hasScalarType(value, &UA_TYPES[UA_TYPES_INT32])) {
UA_Int32 int_val = *(UA_Int32 *) value->data;
std::string int_resp = "int|" + std::to_string(int_val);
int_resp.copy(destination, int_resp.size(), 0);
*len = int_resp.size();
}
else if(UA_Variant_hasScalarType(value, &UA_TYPES[UA_TYPES_INT64])) {
UA_Int64 int_val = *(UA_Int64 *) value->data;
std::string int_resp = "int|" + std::to_string(int_val);
int_resp.copy(destination, int_resp.size(), 0);
*len = int_resp.size();
}
/* Unsigned integer types */
else if(UA_Variant_hasScalarType(value, &UA_TYPES[UA_TYPES_UINT16])) {
UA_UInt16 int_val = *(UA_UInt16 *) value->data;
std::string int_resp = "uint|" + std::to_string(int_val);
int_resp.copy(destination, int_resp.size(), 0);
*len = int_resp.size();
}
else if(UA_Variant_hasScalarType(value, &UA_TYPES[UA_TYPES_UINT32])) {
UA_UInt32 int_val = *(UA_UInt32 *) value->data;
std::string int_resp = "uint|" + std::to_string(int_val);
int_resp.copy(destination, int_resp.size(), 0);
*len = int_resp.size();
}
else if(UA_Variant_hasScalarType(value, &UA_TYPES[UA_TYPES_UINT64])) {
UA_UInt64 int_val = *(UA_UInt64 *) value->data;
std::string int_resp = "uint|" + std::to_string(int_val);
int_resp.copy(destination, int_resp.size(), 0);
*len = int_resp.size();
}
/* Float and double types*/
else if(UA_Variant_hasScalarType(value, &UA_TYPES[UA_TYPES_FLOAT])) {
UA_Float float_val = *(UA_Float *) value->data;
std::string float_resp = "float|" + std::to_string(float_val);
float_resp.copy(destination, float_resp.size(), 0);
*len = float_resp.size();
}
else if(UA_Variant_hasScalarType(value, &UA_TYPES[UA_TYPES_DOUBLE])) {
UA_UInt64 float_val = *(UA_UInt64 *) value->data;
std::string float_resp = "float|" + std::to_string(float_val);
float_resp.copy(destination, float_resp.size(), 0);
*len = float_resp.size();
}
/* String type */
/*
else if(UA_Variant_hasScalarType(value, &UA_TYPES[UA_TYPES_STRING])) {
UA_String string = *(UA_String *) value->data;
char *
std::string str(*(char *) string.data, string.data + string.length());
std::string string_resp = "string|" + str;
string_resp.copy(destination, string_resp.size(), 0);
*len = string_resp.size();
}
*/
//TODO more datatypes if needed
else {
std::string error_resp = "error|Unknown value type";
error_resp.copy(destination, error_resp.size(), 0);
*len = error_resp.size();
}
}
void parseIdentity(const char *input, int32_t *nmSpace, uint32_t *nodeId){
std::string identity(input);
std::string delimiter("|");
std::size_t found = identity.find(delimiter);
if (found != std::string::npos)
{
std::string name_string(identity, 0, found-1);
std::string node_string(identity, found+1, identity.size()-found-1);
//std::cerr << "parseIdentity.name_string: " << name_string.c_str() << std::endl;
//std::cerr << "parseIdentity.node_string: " << node_string.c_str() << std::endl;
//std::cerr.flush();
*nmSpace = std::atoi(name_string.c_str());
*nodeId = std::atoi(node_string.c_str());
}
else{
*nmSpace = -1;
}
}
inline const char * const boolToString(bool b)
{
return b ? "true" : "false";
}
\ No newline at end of file
......@@ -13,7 +13,7 @@
start_link/0,
connect/2,
disconnect/1,
get_value/2,
get_value/3,
stop/1
]).
......@@ -48,8 +48,8 @@ connect(Pid, ServerName) when is_binary(ServerName) ->
disconnect(Pid) ->
gen_server:call(Pid, disconnect).
get_value(Pid, Id) ->
gen_server:call(Pid, {get_value, Id}).
get_value(Pid, Namespace, NodeId) ->
gen_server:call(Pid, {get_value, Namespace, NodeId}).
init([]) ->
Port = erlang:open_port({spawn_executable, "/home/nick/erlopen62541/priv/" ++ ?PORT_NAME}, ?PORT_OPTS),
......@@ -63,8 +63,10 @@ handle_call(disconnect, _, #{port := Port} = State) ->
handle_call({connect, ServerName}, _, #{port := Port} = State) ->
ConnectCmd = <<(?CONNECT)/binary, ServerName/binary>>,
{reply, sync_read(Port, ConnectCmd), State};
handle_call({get_value, Id}, _, #{port := Port} = State) ->
GetValue = <<(?READ_NODE)/binary, Id/binary>>,
handle_call({get_value, Namespace, NodeId}, _, #{port := Port} = State) ->
NamespaceBin = erlang:integer_to_binary(Namespace),
NodeIdBin = erlang:integer_to_binary(NodeId),
GetValue = <<(?READ_NODE)/binary, NamespaceBin/binary, $|, NodeIdBin/binary>>,
{reply, sync_read(Port, GetValue), State};
handle_call(Msg, From, State) ->
io:format(?MODULE_STRING ++ ": What a call heck ~p in state: ~p from ~p", [Msg, From]),
......@@ -91,6 +93,17 @@ sync_read(Port, Data) when is_binary(Data) ->
nok;
{Port, {data, ?OK}} ->
ok;
{Port, {data, <<"error|", Reason/binary>>}} ->
{error, Reason};
{Port, {data, <<"datetime|", Value/binary>>}} ->
{datetime, Value};
{Port, {data, <<"int|", Value/binary>>}} ->
{integer, erlang:binary_to_integer(Value)};
{Port, {data, <<"float|", Value/binary>>}} ->
Float = string:to_float(erlang:binary_to_list(Value)),
{float, Float};
{Port, {data, <<"string|", Value/binary>>}} ->
{string, Value};
{Port, {exit_status, Status}} ->
{exit, Status};
Anything ->
......@@ -98,4 +111,3 @@ sync_read(Port, Data) when is_binary(Data) ->
after ?PORT_SYNC_MS ->
{error, timeout}
end.
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