当前位置:网站首页>学习open62541 --- [67] 添加自定义Enum并显示名字

学习open62541 --- [67] 添加自定义Enum并显示名字

2022-07-07 16:49:00 爱就是恒久忍耐

Enum类型的变量有点特殊,在base data type里,可以看到enum不能直接实例化,
在这里插入图片描述
其属性如下,是抽象类型,
在这里插入图片描述

对于自定义enum,需要经过3个步骤来操作,

  1. 先定义对应的DataType
  2. 然后再定义对应的变量类型
  3. 最后使用这个变量类型来创建enum变量

本文讲述如何添加自定义Enum,并创建对应的变量


一 代码

代码如下,

#include "open62541.h"

static bool running = true;

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


UA_UInt16 LocalServerNSIndex = 1;

typedef enum {
    
    AA = 0,
    BB = 1,
    CC = 2,
    DD = 3,
    __MY_ENUM_FORCE32BIT = 0x7fffffff
} MyEnum;

// 定义DataType
static UA_DataType MyEnumDataType = 
{
    
    UA_TYPENAME("MyEnum") /* .typeName */
    {
    LocalServerNSIndex, UA_NODEIDTYPE_NUMERIC, {
    0}}, /* .typeId */
    {
    LocalServerNSIndex, UA_NODEIDTYPE_NUMERIC, {
    0}}, /* .binaryEncodingId */
    sizeof(MyEnum), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    1, /* .overlayable */
    0, /* .membersSize */
    NULL  /* .members */
};

// 把enum的datatype添加到namespace里
UA_StatusCode addMyEnumDataType(UA_Server* server)
{
    
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
    attr.displayName = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"My Enum Data Type");

    ret = UA_Server_addDataTypeNode(
            server, UA_NODEID_NUMERIC(LocalServerNSIndex, 0), 
            UA_NODEID_NUMERIC(0, UA_NS0ID_ENUMERATION),
            UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), 
            UA_QUALIFIEDNAME(LocalServerNSIndex, (char*)"My.Enum"), attr, NULL, &MyEnumDataType.typeId);
    
    return ret;
}

// 把enum对应的变量类型添加到namespace里
UA_StatusCode addMyEnumVariableType(UA_Server *server, UA_NodeId& myEnumVarTypeId) 
{
    
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_VariableTypeAttributes dattr = UA_VariableTypeAttributes_default;
    dattr.description = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"My Enum Var type");
    dattr.displayName = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"My Enum Var type");
    dattr.dataType = MyEnumDataType.typeId;
    dattr.valueRank = UA_VALUERANK_SCALAR;

    MyEnum p = AA;

    UA_Variant_setScalar(&dattr.value, &p, &MyEnumDataType);

    ret = UA_Server_addVariableTypeNode(server, UA_NODEID_NUMERIC(LocalServerNSIndex, 0),
                                  UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
                                  UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                                  UA_QUALIFIEDNAME(LocalServerNSIndex, (char*)"My Enum Var type"),
                                  UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
                                  dattr, NULL, &myEnumVarTypeId);

    return ret;
}

// 创建enum变量,并添加到namespace里
UA_StatusCode addMyEnumVariable(UA_Server *server, UA_NodeId myEnumVarTypeId) 
{
    
    MyEnum p = CC;
    UA_VariableAttributes vattr = UA_VariableAttributes_default;
    vattr.description = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"My Enum Var");
    vattr.displayName = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"My Enum Var");
    vattr.dataType = MyEnumDataType.typeId;
    vattr.valueRank = UA_VALUERANK_SCALAR;
    UA_Variant_setScalar(&vattr.value, &p, &);

    UA_StatusCode ret = UA_STATUSCODE_GOOD;

    ret = UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(LocalServerNSIndex, 0),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                              UA_QUALIFIEDNAME(LocalServerNSIndex, (char*)"My Enum Var"),
                              myEnumVarTypeId, vattr, NULL, NULL);

    return ret;
}



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

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

    UA_StatusCode ret = addMyEnumDataType(server);

    if (UA_StatusCode_isGood(ret))
    {
    
        UA_NodeId myEnumVarTypeId;
        ret = addMyEnumVariableType(server, myEnumVarTypeId);
        if (UA_StatusCode_isGood(ret))
        {
    
            ret = addMyEnumVariable(server, myEnumVarTypeId);
        }
    }


    if (UA_StatusCode_isBad(ret))
    {
    
        printf("Error\n");
        UA_Server_delete(server);
        return 0;
    }


    UA_Server_run(server, &running);

    UA_Server_delete(server);

    return 0;
}



编译成功后运行,可以看到变量添加成功,
在这里插入图片描述
其值为2,因为CC对应的值就是2
在这里插入图片描述
添加的自定义DataType也在namespace里,
在这里插入图片描述


二 添加enum名字

从上面的代码可以看到虽然enum变量添加了,似乎和一个int类型的数据没区别,最好能体现出其名字,这里讲下如何给enum类型添加对应的名称,

这里定义一个函数addEnumString,用于给enum的DataType添加名称,如下,

UA_StatusCode addEnumString(UA_Server *server)
{
    
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_VariableAttributes attr = UA_VariableAttributes_default;
    attr.minimumSamplingInterval = 0.000000;
    attr.userAccessLevel = 1;
    attr.accessLevel = 1;
    attr.valueRank = 1;
    attr.arrayDimensionsSize = 1;
    
    UA_UInt32 arrayDimensions[1];
    arrayDimensions[0] = 0;
    attr.arrayDimensions = &arrayDimensions[0];
    attr.dataType = UA_NODEID_NUMERIC(0, 21LU);
    UA_LocalizedText my_enum_variant_DataContents[4];
    my_enum_variant_DataContents[0] = UA_LOCALIZEDTEXT((char*)"", (char*)"AA");
    my_enum_variant_DataContents[1] = UA_LOCALIZEDTEXT((char*)"", (char*)"BB");
    my_enum_variant_DataContents[2] = UA_LOCALIZEDTEXT((char*)"", (char*)"CC");
    my_enum_variant_DataContents[3] = UA_LOCALIZEDTEXT((char*)"", (char*)"DD");
    UA_Variant_setArray(&attr.value, &my_enum_variant_DataContents, (UA_Int32) 4, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
    attr.displayName = UA_LOCALIZEDTEXT((char*)"", (char*)"EnumStrings");

    UA_NodeId enumStringNodeId;
    ret = UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,
                                    UA_NODEID_NUMERIC(LocalServerNSIndex, 0),
                                    MyEnumDataType.typeId,
                                    UA_NODEID_NUMERIC(0, 46LU),
                                    UA_QUALIFIEDNAME(0, (char*)"EnumStrings"),
                                    UA_NODEID_NUMERIC(0, 68LU),
                                    (const UA_NodeAttributes*)&attr, 
                                    &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], NULL, &enumStringNodeId);

    if (UA_StatusCode_isGood(ret))
    {
    
        ret = UA_Server_addNode_finish(server, enumStringNodeId);
    }

    return ret;
}

有4个元素就添加4个名称,注意enum的值必须从0开始,后面都是顺序加1,否则就无法显示名称。在函数addMyEnumDataType里调用addEnumString,如下,

UA_StatusCode addMyEnumDataType(UA_Server* server)
{
    
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
    attr.displayName = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"My Enum Data Type");

    ret = UA_Server_addDataTypeNode(
            server, UA_NODEID_NUMERIC(LocalServerNSIndex, 0), 
            UA_NODEID_NUMERIC(0, UA_NS0ID_ENUMERATION),
            UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), 
            UA_QUALIFIEDNAME(LocalServerNSIndex, (char*)"My.Enum"), attr, NULL, &MyEnumDataType.typeId);
    
    if (UA_StatusCode_isGood(ret))
    {
    
        ret = addEnumString(server);
    }

    return ret;
}

重新编译运行,可以看到变量值后面加了其对应的名称,
在这里插入图片描述
在DataType里,也可以看到有EnumStrings,
在这里插入图片描述
查看EnumStrings的值,如下,是个数组,
在这里插入图片描述
这样就实现了我们的期望

完整代码如下,

#include "open62541.h"

static bool running = true;

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


const UA_UInt16 LocalServerNSIndex = 1;

typedef enum {
    
    AA = 0,
    BB = 1,
    CC = 2,
    DD = 3,
    __MY_ENUM_FORCE32BIT = 0x7fffffff
} MyEnum;

static UA_DataType MyEnumDataType = 
{
    
    UA_TYPENAME("MyEnum") /* .typeName */
    {
    LocalServerNSIndex, UA_NODEIDTYPE_NUMERIC, {
    0}}, /* .typeId */
    {
    LocalServerNSIndex, UA_NODEIDTYPE_NUMERIC, {
    0}}, /* .binaryEncodingId */
    sizeof(MyEnum), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    1, /* .overlayable */
    0, /* .membersSize */
    NULL  /* .members */
};


UA_StatusCode addEnumString(UA_Server *server)
{
    
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_VariableAttributes attr = UA_VariableAttributes_default;
    attr.minimumSamplingInterval = 0.000000;
    attr.userAccessLevel = 1;
    attr.accessLevel = 1;
    attr.valueRank = 1;
    attr.arrayDimensionsSize = 1;
    
    UA_UInt32 arrayDimensions[1];
    arrayDimensions[0] = 0;
    attr.arrayDimensions = &arrayDimensions[0];
    attr.dataType = UA_NODEID_NUMERIC(0, 21LU);
    UA_LocalizedText my_enum_variant_DataContents[4];
    my_enum_variant_DataContents[0] = UA_LOCALIZEDTEXT((char*)"", (char*)"AA");
    my_enum_variant_DataContents[1] = UA_LOCALIZEDTEXT((char*)"", (char*)"BB");
    my_enum_variant_DataContents[2] = UA_LOCALIZEDTEXT((char*)"", (char*)"CC");
    my_enum_variant_DataContents[3] = UA_LOCALIZEDTEXT((char*)"", (char*)"DD");
    UA_Variant_setArray(&attr.value, &my_enum_variant_DataContents, (UA_Int32) 4, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
    attr.displayName = UA_LOCALIZEDTEXT((char*)"", (char*)"EnumStrings");

    UA_NodeId enumStringNodeId;
    ret = UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,
                                    UA_NODEID_NUMERIC(LocalServerNSIndex, 0),
                                    MyEnumDataType.typeId,
                                    UA_NODEID_NUMERIC(0, 46LU),
                                    UA_QUALIFIEDNAME(0, (char*)"EnumStrings"),
                                    UA_NODEID_NUMERIC(0, 68LU),
                                    (const UA_NodeAttributes*)&attr, 
                                    &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], NULL, &enumStringNodeId);

    if (UA_StatusCode_isGood(ret))
    {
    
        ret = UA_Server_addNode_finish(server, enumStringNodeId);
    }

    return ret;
}


UA_StatusCode addMyEnumDataType(UA_Server* server)
{
    
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
    attr.displayName = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"My Enum Data Type");

    ret = UA_Server_addDataTypeNode(
            server, UA_NODEID_NUMERIC(LocalServerNSIndex, 0), 
            UA_NODEID_NUMERIC(0, UA_NS0ID_ENUMERATION),
            UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), 
            UA_QUALIFIEDNAME(LocalServerNSIndex, (char*)"My.Enum"), attr, NULL, &MyEnumDataType.typeId);
    
    if (UA_StatusCode_isGood(ret))
    {
    
        ret = addEnumString(server);
    }

    return ret;
}

UA_StatusCode addMyEnumVariableType(UA_Server *server, UA_NodeId& myEnumVarTypeId) 
{
    
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_VariableTypeAttributes dattr = UA_VariableTypeAttributes_default;
    dattr.description = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"My Enum Var type");
    dattr.displayName = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"My Enum Var type");
    dattr.dataType = MyEnumDataType.typeId;
    dattr.valueRank = UA_VALUERANK_SCALAR;

    MyEnum p = AA;

    UA_Variant_setScalar(&dattr.value, &p, &MyEnumDataType);

    ret = UA_Server_addVariableTypeNode(server, UA_NODEID_NUMERIC(LocalServerNSIndex, 0),
                                  UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
                                  UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                                  UA_QUALIFIEDNAME(LocalServerNSIndex, (char*)"My Enum Var type"),
                                  UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
                                  dattr, NULL, &myEnumVarTypeId);

    return ret;
}

UA_StatusCode addMyEnumVariable(UA_Server *server, UA_NodeId myEnumVarTypeId) 
{
    
    MyEnum p = CC;
    UA_VariableAttributes vattr = UA_VariableAttributes_default;
    vattr.description = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"My Enum Var");
    vattr.displayName = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"My Enum Var");
    vattr.dataType = MyEnumDataType.typeId;
    vattr.valueRank = UA_VALUERANK_SCALAR;
    UA_Variant_setScalar(&vattr.value, &p, &UA_TYPES[UA_TYPES_INT32]);

    UA_StatusCode ret = UA_STATUSCODE_GOOD;

    ret = UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(LocalServerNSIndex, 0),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                              UA_QUALIFIEDNAME(LocalServerNSIndex, (char*)"My Enum Var"),
                              myEnumVarTypeId, vattr, NULL, NULL);

    return ret;
}



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

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

    UA_StatusCode ret = addMyEnumDataType(server);

    if (UA_StatusCode_isGood(ret))
    {
    
        UA_NodeId myEnumVarTypeId;
        ret = addMyEnumVariableType(server, myEnumVarTypeId);
        if (UA_StatusCode_isGood(ret))
        {
    
            ret = addMyEnumVariable(server, myEnumVarTypeId);
        }
    }


    if (UA_StatusCode_isBad(ret))
    {
    
        printf("Error\n");
        UA_Server_delete(server);
        return 0;
    }


    UA_Server_run(server, &running);

    UA_Server_delete(server);

    return 0;
}


三 小结

本文讲述了如何添加自定义enum,并创建对应的变量,读者可以照葫芦画瓢,添加自己需要的enum。有个点需要注意,最后在创建enum变量时,使用的类型是int32,只需要在变量属性里指定好data type的id就行了。

原网站

版权声明
本文为[爱就是恒久忍耐]所创,转载请带上原文链接,感谢
https://blog.csdn.net/whahu1989/article/details/125609360