Как записать сразу несколько узлов с OP C -UA, используя open62541? - PullRequest
0 голосов
/ 08 мая 2020

Я пытаюсь записать несколько узлов в одном запросе, однако я не нашел никакой документации или примеров того, как это сделать, каждый раз, когда я нахожу что-либо, касающееся проблемы, записывается один узел. Основываясь на моем понимании библиотеки open62541 (что немного), я попытался сделать это так:

void Write_from_3_to_5_piece_queue() {
        char NodeID[128];
        char NodeID_backup[128];
        char aux[3];
        bool bool_to_write = false;
        strcpy(NodeID_backup, _BaseNodeID);
        strcat(NodeID_backup, "POU.AT2.piece_queue["); // this is where I want to write, I need only to append the array index in which to write


        UA_WriteRequest wReq;
        UA_WriteValue my_nodes[3]; // this is where I start to make things up, I'm not sure this is the correct way to do it
        my_nodes[0] = *UA_WriteValue_new();
        my_nodes[1] = *UA_WriteValue_new();
        my_nodes[2] = *UA_WriteValue_new();
        strcpy(NodeID, NodeID_backup);
        strcat(NodeID, "3]"); //append third index of array (will write to piece_queue[3])
        my_nodes[0].nodeId = UA_NODEID_STRING_ALLOC(_nodeIndex, NodeID);
        my_nodes[0].attributeId = UA_ATTRIBUTEID_VALUE;
        my_nodes[0].value.hasValue = true;
        my_nodes[0].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
        my_nodes[0].value.value.storageType = UA_VARIANT_DATA_NODELETE;
        my_nodes[0].value.value.data = &bool_to_write;

        strcpy(NodeID, NodeID_backup);
        strcat(NodeID, "4]");
        my_nodes[1].nodeId = UA_NODEID_STRING_ALLOC(_nodeIndex, NodeID);
        my_nodes[1].attributeId = UA_ATTRIBUTEID_VALUE;
        my_nodes[1].value.hasValue = true;
        my_nodes[1].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
        my_nodes[1].value.value.storageType = UA_VARIANT_DATA_NODELETE;
        my_nodes[1].value.value.data = &bool_to_write;

        strcpy(NodeID, NodeID_backup);
        strcat(NodeID, "5]");
        my_nodes[2].nodeId = UA_NODEID_STRING_ALLOC(_nodeIndex, NodeID);
        my_nodes[2].attributeId = UA_ATTRIBUTEID_VALUE;
        my_nodes[2].value.hasValue = true;
        my_nodes[2].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
        my_nodes[2].value.value.storageType = UA_VARIANT_DATA_NODELETE;
        my_nodes[2].value.value.data = &bool_to_write;


        UA_WriteRequest_init(&wReq);
        wReq.nodesToWrite = my_nodes;
        wReq.nodesToWriteSize = 3;
        UA_WriteResponse wResp = UA_Client_Service_write(_client, wReq);
        UA_WriteResponse_clear(&wResp);
        UA_WriteRequest_clear(&wReq);

        return;
    }

Сначала у меня не было большой надежды, что это сработает, но это оказывается, это на самом деле записывает значения, которые я sh. Проблема в том, что на UA_WriteRequest_clear(&wReq); я вызываю исключение в библиотеке open62541: enter image description here

Кроме того, я знаю, что могу записывать несколько значений в массивы, даже если в этом конкретном пример, который решит мою проблему, это не то, что я хочу сделать, этот пример просто упрощает мою проблему. Просто предположим, что у меня есть структура с несколькими типами, и я хочу писать в нее одним запросом. Я ценю любую помощь!

1 Ответ

1 голос
/ 08 мая 2020

Во-первых, это плохо:


UA_WriteValue my_nodes[3];
        my_nodes[0] = *UA_WriteValue_new();
        my_nodes[1] = *UA_WriteValue_new();
        my_nodes[2] = *UA_WriteValue_new();

my_nodes уже создан в стеке, а затем вы копируете в него содержимое нового объекта путем разыменования. Это однозначно приводит к утечкам памяти. Вероятно, вы захотите использовать вместо него UA_WriteValue_init(). Никогда не разыменовывайте возвращаемое значение функции new().

Давайте go снизу вверх:

UA_WriteRequest_clear(&wReq) рекурсивно освобождает все содержимое структуры wReq. Это означает, что он также будет вызывать: UA_Array_delete(wReq.nodesToWrite, wReq.nodesToWriteSize, ...), который, в свою очередь, вызывает UA_free(wReq.nodesToWrite)

И у вас есть: wReq.nodesToWrite = my_nodes; с UA_WriteValue my_nodes[3];

Это означает, что вы назначаете переменную, который находится в стеке на указатель, а позже этот указатель освобождается. free может удалять только то, что находится в куче, а не стек, и поэтому он терпит неудачу.

Теперь у вас есть два варианта:

  1. Если вы все еще хотите использовать стек обмануть UA_clear, думая, что переменная пуста:
wReq.nodesToWrite = NULL;
wReq.nodesToWriteSize = 0;
UA_clear(&wReq);
Поместите узлы в кучу: вместо UA_WriteValue my_nodes[3]; используйте что-то вроде UA_WriteValue *my_nodes = (UA_WriteValue*)UA_malloc(sizeof(UA_WriteValue)*3);

Также я настоятельно рекомендую вам использовать valgrind или clang очиститель памяти, чтобы избежать всех этих проблем с памятью.

...