Learn open62541 --- [31] Display Chinese characters correctly

This article mainly describes how to correctly display Chinese characters under win10, the development environment is VS2015


A server-side code

// server.cpp

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
* See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */

#include <signal.h>
#include <stdlib.h>

#include "open62541.h"

UA_Boolean running = true;

static void stopHandler(int sign) {
    
    
	UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
	running = false;
}



static void addVariable(UA_Server *server)
{
    
    
	/* Define the attribute of the myInteger variable node */
	UA_VariableAttributes attr = UA_VariableAttributes_default;


	UA_LocalizedText orig = UA_LOCALIZEDTEXT((char*)"zh-CN", "123你456");

	UA_Variant_setScalar(&attr.value, &orig, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
	attr.description = UA_LOCALIZEDTEXT("en-US", "info");
	attr.displayName = UA_LOCALIZEDTEXT("en-US", "info");
	attr.dataType = UA_TYPES[UA_TYPES_LOCALIZEDTEXT].typeId;
	attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;

	/* Add the variable node to the information model */
	UA_NodeId myNodeId = UA_NODEID_STRING(1, "info");
	UA_QualifiedName myName = UA_QUALIFIEDNAME(1, "info");
	UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
	UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
	UA_Server_addVariableNode(server, myNodeId, parentNodeId, parentReferenceNodeId, myName,
			UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), attr, NULL, NULL);
}


static void ctrlCallback(UA_Server *server, void *data)
{
    
    
	UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "ctrl callback");

	UA_Variant val;
	UA_Server_readValue(server, UA_NODEID_STRING(1, "info"), &val);

	UA_LocalizedText *pOrig = (UA_LocalizedText*)(val.data);
	
	for (unsigned int i = 0; i < pOrig->text.length; ++i)
	{
    
    
		printf("0x%x ", pOrig->text.data[i]);
	}
	printf("\n%.*s\n\n", pOrig->text.length, pOrig->text.data);

}


int main(void)
{
    
    
	signal(SIGINT, stopHandler);
	signal(SIGTERM, stopHandler);

	UA_Server *server = UA_Server_new();
	UA_ServerConfig_setDefault(UA_Server_getConfig(server));

	addVariable(server);

	UA_Server_addRepeatedCallback(server, ctrlCallback, NULL, 2000, NULL); // call every 2s

	UA_StatusCode retval = UA_Server_run(server, &running);

	UA_Server_delete(server);

	return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}

The code function is relatively simple, mainly to add a variable, the variable value is "123你456", and then read its value every 2 seconds, and finally print it out.

After running, use UaExpert to connect and display garbled characters,
Insert picture description here
but you can manually modify it to the correct Chinese on UaExpert. After modifying it to the correct "123你456", check the timing printing on the server side. The
Insert picture description here
first red mark is the one before modification. Value, you can see that the hexadecimal value corresponding to "you" is 0xc4 0xe3, the second red mark is the modified value, the hexadecimal value corresponding to "you" is 0xe4 0xbd 0xa0, what's the matter What?


Two solve the problem

After searching for information on the Internet, it is found that the root cause is the different encoding and decoding methods on both sides. The DOS terminal on the server side uses GB18030 encoding (or other), while UaExpert uses UTF-8 encoding.

This is no problem for English, but it is not so friendly to Chinese.

Knowing the reason, the solution is relatively simple, there are two ways:

1. Use wstring (at least C++11 required)

If you are developing in c++, and the c++ version is 11 and above, then you can use wstring, as follows,

#include <string>
#include <locale>
#include <codecvt>

static std::string wstringToUtf8(const std::wstring& str)
{
    
    
	std::wstring_convert<std::codecvt_utf8<wchar_t> > strCnv;
	return strCnv.to_bytes(str);
}

static void addVariable(UA_Server *server)
{
    
    
	/* Define the attribute of the myInteger variable node */
	UA_VariableAttributes attr = UA_VariableAttributes_default;

	std::wstring textStr = L"123你456";
	std::string temp = wstringToUtf8(textStr);

	UA_LocalizedText orig = UA_LOCALIZEDTEXT((char*)"zh-CN", (char*)(temp.c_str()));

	UA_Variant_setScalar(&attr.value, &orig, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
	attr.description = UA_LOCALIZEDTEXT("en-US", "info");
	attr.displayName = UA_LOCALIZEDTEXT("en-US", "info");
	attr.dataType = UA_TYPES[UA_TYPES_LOCALIZEDTEXT].typeId;
	attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;

	/* Add the variable node to the information model */
	UA_NodeId myNodeId = UA_NODEID_STRING(1, "info");
	UA_QualifiedName myName = UA_QUALIFIEDNAME(1, "info");
	UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
	UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
	UA_Server_addVariableNode(server, myNodeId, parentNodeId, parentReferenceNodeId, myName,
			UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), attr, NULL, NULL);
}

Add the corresponding header file and function wstringToUtf8(), and then call wstringToUtf8() in addVariable(), so that Chinese can be displayed correctly on the UaExpert side.

2. Modify the encoding method of the dos terminal

This method is more troublesome. I refer to this article to change the encoding method of the DOS terminal to UTF-8.

Note: After the modification, the Chinese characters in the source code in Visual Studio become garbled. You need to write it again, and finally recompile and run. At this time, use UaExpert to connect and you can correctly display Chinese.

Insert picture description here


Three summary

This article mainly describes how to correctly display Chinese characters under Win, and it is recommended to use UTF-8 encoding.

Guess you like

Origin blog.csdn.net/whahu1989/article/details/106628606