Set_raw_data_byes

43 views
Skip to first unread message

Richard Reeves

unread,
Aug 16, 2026, 9:30:28 PMAug 16
to libplctag
I am trying to write a program that will allow me to read and write to a UDT.  I started with the simple.c example and modified the commands to allow me to read and write to a UDT.  Reading from the UDT works well, but I cannot write to the tag of my UDT type.  

My path to the tag is: 
    #define TAG_PATH "protocol=ab-eip&gateway=192.168.3.68&path=1,0&cpu=LGX&name=DataBlock"

For test purposes, I created a UDT of 10 DINT.

The code to write to tag:

     tag = plc_tag_create(TAG_PATH, DATA_TIMEOUT);
if (tag < 0) {
// NOLINTNEXTLINE
fprintf(stderr, "ERROR %s: Could not create tag!\n", plc_tag_decode_error(tag));
return 1;
}

iS7BufferOffset = 0;
iItem1 = 10;
memcpy(byPLCWriteData + iS7BufferOffset, &iItem1, sizeof(int));
iS7BufferOffset += sizeof(int);
iItem2 = 10;
memcpy(byPLCWriteData + iS7BufferOffset, &iItem2, sizeof(int));
iS7BufferOffset += sizeof(int);
iItem3 = 10;
memcpy(byPLCWriteData + iS7BufferOffset, &iItem3, sizeof(int));
iS7BufferOffset += sizeof(int);
iItem4 = 10;
memcpy(byPLCWriteData + iS7BufferOffset, &iItem4, sizeof(int));
iS7BufferOffset += sizeof(int);
iItem5 = 10;
memcpy(byPLCWriteData + iS7BufferOffset, &iItem5, sizeof(int));
iS7BufferOffset += sizeof(int);
iItem6 = 10;
memcpy(byPLCWriteData + iS7BufferOffset, &iItem6, sizeof(int));
iS7BufferOffset += sizeof(int);
iItem7 = 10;
memcpy(byPLCWriteData + iS7BufferOffset, &iItem7, sizeof(int));
iS7BufferOffset += sizeof(int);
iItem8 = 10;
memcpy(byPLCWriteData + iS7BufferOffset, &iItem8, sizeof(int));
iS7BufferOffset += sizeof(int);
iItem9 = 10;
memcpy(byPLCWriteData + iS7BufferOffset, &iItem9, sizeof(int));
iS7BufferOffset += sizeof(int);
iItem10 = 10;
memcpy(byPLCWriteData + iS7BufferOffset, &iItem10, sizeof(int));
iS7BufferOffset += sizeof(int);

rc = plc_tag_set_raw_bytes(tag, 0, byPLCWriteData, 40);
    if(rc != PLCTAG_STATUS_OK) {
        // NOLINTNEXTLINE
        fprintf(stderr, "ERROR: Unable to write the data! Got error code %d: %s\n", rc, plc_tag_decode_error(rc));
        plc_tag_destroy(tag);
        return 1;
    }
plc_tag_destroy(tag);

When I execute the code, the plc_tag_set_raw_bytes returns a 0, but the values in the PLC never change.  I do not get any messages in the debug window until I exit the program.  Then I get the following:

2026-08-16 13:20:28.077359 thread(2) tag(0) [AB_SESSION] INFO session_destroy:1148 Session sent 3 packets.
2026-08-16 13:20:28.077355 thread(4) tag(0) [AB_SESSION] INFO send_eip_request:2503 00032 00 00 00 00 b2 00 18 00 4e 02 20 06 24 01 0a 0e
2026-08-16 13:20:28.078448 thread(4) tag(0) [AB_SESSION] INFO send_eip_request:2503 00048 72 f9 3d f3 45 43 50 21 03 00 01 00 20 02 24 01
2026-08-16 13:20:28.078523 thread(4) tag(0) [PLATFORM] WARN socket_write:1937 socket write error rc=-1, errno=10054
2026-08-16 13:20:28.078548 thread(4) tag(0) [AB_SESSION] WARN send_eip_request:2530 Session is terminating.
2026-08-16 13:20:28.078612 thread(4) tag(0) [AB_SESSION] INFO send_forward_close_req:3067 Done
2026-08-16 13:20:28.078637 thread(4) tag(0) [AB_SESSION] WARN perform_forward_close:2668 Sending forward close failed, PLCTAG_ERR_ABORT!
2026-08-16 13:20:28.078668 thread(4) tag(0) [AB_SESSION] INFO perform_forward_close:2679 Done.
2026-08-16 13:20:28.078699 thread(4) tag(0) [AB_SESSION] WARN session_handler:1597 Forward close failed PLCTAG_ERR_ABORT!

I could not find any examples for reading/writing raw bytes.  

I am using Visual Studio 2017 with the x86 dev library.  I have tried both versions 2.7.1 and 2.6.16.  The plc that I am communicating with is a CompactLogix 1769--L18ER-BB1B.  

The simple.c software works, and the get_raw_bytes work, but the set_raw_bytes makes no change in the PLC.

One other thing was I had to destroy the tag, and create a new tag each time I read from the UDT.

Any help would be appreciated.  Thanks.

Kyle

unread,
Sep 9, 2026, 6:52:28 AMSep 9
to libplctag
Hi, sorry for the long delay.

There are some possible problems with the above code:

- no call to plc_tag_write().  Changing the data with set_raw_bytes will only change the local buffer and not the PLC unless you set up auto sync.

- you make the assumption that the PLC and the PC have the same endianess (little endian).  While true for all x86 and most ARM CPUs, that is not universally true.

- you also make the assumption that sizeof(int) == 4 on your platform.  As with the above assumption, it is probably true for PC platforms but it is not true for some platforms.

Is there a reason that you do not want to use the regular data accessor functions?

You can configure the library to automatically send changed data using the `auto_sync_write_ms` attribute.  Set that to some reasonable number like 20ms.  Then, when you change the data, the library will automatically write it out after 20ms.  The delay is to help consolidate multiple writes.

I hope this helps.

Best,
Kyle

Richard Reeves

unread,
Sep 17, 2026, 10:17:20 AMSep 17
to libplctag
Thanks for the response.  I was able to find the problem with my code.  Everything is working now.

The code I am using is:

#define WRITE_TAG_PATH "protocol=ab-eip&gateway=192.168.3.68&path=1,0&cpu=LGX&name=WriteDataBlock"

// get the data //
tag = plc_tag_create(WRITE_TAG_PATH, DATA_TIMEOUT);
    if(tag < 0) {

        // NOLINTNEXTLINE
        fprintf(stderr, "ERROR %s: Could not create tag!\n", plc_tag_decode_error(tag));
        return 1;
    }

rc = plc_tag_read(tag, DATA_TIMEOUT);
if (rc != PLCTAG_STATUS_OK) {
// NOLINTNEXTLINE
fprintf(stderr, "ERROR: Unable to read the data! Got error code %d: %s\n", rc, plc_tag_decode_error(rc));
plc_tag_destroy(tag);
return 1;
}

/* get the tag size and element size. Do this _AFTER_ reading the tag otherwise we may not know how big the tag is! */
elem_size = plc_tag_get_int_attribute(tag, "elem_size", 0);
elem_count = plc_tag_get_int_attribute(tag, "elem_count", 0);

iS7BufferOffset = 0;
iItem1 = plc_tag_get_int32(tag, iS7BufferOffset);
iS7BufferOffset += sizeof(int);
iItem2 = plc_tag_get_int32(tag, iS7BufferOffset);
iS7BufferOffset += sizeof(int);
iItem3 = plc_tag_get_int32(tag, iS7BufferOffset);
iS7BufferOffset += sizeof(int);
iItem4 = plc_tag_get_int32(tag, iS7BufferOffset);
iS7BufferOffset += sizeof(int);
iItem5 = plc_tag_get_int32(tag, iS7BufferOffset);
iS7BufferOffset += sizeof(int);
iItem6 = plc_tag_get_int32(tag, iS7BufferOffset);
iS7BufferOffset += sizeof(int);
iItem7 = plc_tag_get_int32(tag, iS7BufferOffset);
iS7BufferOffset += sizeof(int);
iItem8 = plc_tag_get_int32(tag, iS7BufferOffset);
iS7BufferOffset += sizeof(int);
iItem9 = plc_tag_get_int32(tag, iS7BufferOffset);
iS7BufferOffset += sizeof(int);
iItem10 = plc_tag_get_int32(tag, iS7BufferOffset);
iS7BufferOffset += sizeof(int);

My UDT is 10 DINT.  Elem_size is 40, and count is 1, like you would expect.

All my PC work is on Windows computers with either C or C#.  Almost all the information is passed through UDT.  

When you get a chance, can you look at this to see if this seems like a good way to code my application.

Thanks.

Reply all
Reply to author
Forward
0 new messages