Strings and Floats C++

164 views
Skip to first unread message

PirithiumX

unread,
Oct 26, 2020, 1:46:21 PM10/26/20
to libplctag
Greetings,
I am Having great success gathering Integers. But Now I need to read Strings from a serialized process for storage into a database.
To better explain I am trying to read ST11:0 from an SLC 505.
I am struggling a bit with C++ and C since I have not coded with that in 15 years.
So I am progressing slowly but productively.
Is it possible for someone to give me an example of just simply reading ST11:0 and parsing it into a string example "J12345" =  Serial code from actual production assembly. The code is put into the PLC using a barcode scanner / laser etcher etc.

Once I tackle this issue Its just a matter of programming error handling in my database insertion and making the program a service in my linux server.

P.S. Is there also an example for Doubles or Floats?

Thank You,
John Wurm   

Kyle Hayes

unread,
Oct 26, 2020, 8:18:29 PM10/26/20
to PirithiumX, libplctag
Hi John,

Thanks for using the library and reaching out!   I have some low level support API additions that I may add in the future to make strings slightly less painful to deal with.   If you do not want to use one of the fine C#/.Net or Julia wrappers, and really want to use C, then keep reading...

Here is a quick and dirty example in C for a PLC5.   Should be the same for an SLC (you should change the PLC type to SLC in the tag string).


#include <stdio.h>
#include <stdlib.h>
#include "../lib/libplctag.h"
#include "utils.h"

/*
* Read a STRING from a PCCC-based PLC. Note that the actual data size of a string is 84 bytes.
*
* STRING types are an INT (2 bytes) followed by 82 bytes of characters. The character data is
* byteswapped! Character 0 is at offset 1, character 1 is at offset 0, character 2 is at offset 3,
* character 4 is at offset 2...
*/

#define REQUIRED_VERSION 2,1,16

#define TAG_PATH "protocol=ab_eip&gateway=10.206.1.38&plc=plc5&elem_size=84&elem_count=2&name=ST18:0"
#define DATA_TIMEOUT 5000

int main()
{
int32_t tag = 0;
int elem_size = 0;
int elem_count = 0;
int tag_size = 0;
int rc;
int i;

/* check the library version. */
if(plc_tag_check_lib_version(REQUIRED_VERSION) != PLCTAG_STATUS_OK) {
fprintf(stderr, "Required compatible library version %d.%d.%d not available!", REQUIRED_VERSION);
}

/* turn off debugging */
plc_tag_set_debug_level(PLCTAG_DEBUG_NONE);

/* open the tag handle to the PLC tag */
tag = plc_tag_create(TAG_PATH, DATA_TIMEOUT);

/* everything OK? */
if((rc = plc_tag_status(tag)) != PLCTAG_STATUS_OK) {
fprintf(stderr,"Error setting up tag internal state. Error %s\n", plc_tag_decode_error(rc));
plc_tag_destroy(tag);
return 0;
}

/* read the data from the PLC */
rc = plc_tag_read(tag, DATA_TIMEOUT);
if(rc != PLCTAG_STATUS_OK) {
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 0;
}

/*
* determine how much data we got and how big each element is.
*
* This allows us to change the tag string without changing the code.
* It is extra boilerplate if you already know this and it will not change.
*/

tag_size = plc_tag_get_size(tag);
elem_count = plc_tag_get_int_attribute(tag, "elem_count", 1);
elem_size = tag_size / elem_count;

/* print out the data */
for(i=0; i < elem_count; i++) {
/* get the string character count, as a INT */
int str_size = plc_tag_get_int16(tag,(i*elem_size));
char str[elem_size];
int j = 0;

for(j=0; j<str_size; j++) {
int char_index = (i*elem_size) /* each string has a full buffer. */
+ 2 /* skip the string length INT */
+ (j ^ 0x01); /* byteswap the index. */
str[j] = (char)plc_tag_get_uint8(tag,char_index);
}
str[j] = (char)0; /* null terminate since we are using a stack-based buffer! */

printf("string %d (%d chars) = '%s'\n",i, str_size, str);
}

/* we are done */
plc_tag_destroy(tag);

return 0;
}

Note that you can only retrieve 2 strings at a time due to the limitations of the PLC.   It can only send/receive about 240 bytes per request/response.   So overhead + 2x84 bytes...

My strings were at a data file 18, so you may need to tweak that too.

I hope this helps!

Best,
Kyle



--
You received this message because you are subscribed to the Google Groups "libplctag" group.
To unsubscribe from this group and stop receiving emails from it, send an email to libplctag+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/libplctag/ff66b9cc-a9e4-4e2f-9ece-a3a2627b3838n%40googlegroups.com.

Kyle Hayes

unread,
Oct 29, 2020, 9:23:02 PM10/29/20
to PirithiumX, libplctag
Glad to hear that it worked.  Did you have any luck with floats?

Note that you will need to multiple any offsets by 4-byte increments if you need to read an array of floats.

You can experiment with the tag_rw tool to get working tag strings and also to see how the data prints out.

We'd love to have you help with the project!   There is a very active wrapper project for C# .Net as well as .Net Framework (did I get that right, Jody?) here: https://github.com/libplctag/libplctag.NET

Even if programming in C is not your strength, there are plenty of areas to help.   Just helping test releases and determining how different PLCs respond to queries by using tools like tag_rw can help very much.

If you know Java, I could really use some help there, particularly about how to package it for uploading to JCenter!

Best,
Kyle

On Tue, Oct 27, 2020 at 6:13 AM PirithiumX <pirit...@gmail.com> wrote:
Thank you very much this Example worked perfectly. 

pirithiumx@pxdc:~/Dropbox/Filez/pxDC$ ./stringx
string 0 (6 chars) = 'J19205'
string 1 (1 chars) = '0'
pirithiumx@pxdc:~/Dropbox/File

This is a wonderful project you have going. This allows me to get out of windows and needing Rockwell Software for data collection.
When I am complete with this project I very much would like to contribute in some way. I am not strong C C++ programming and am interested in linux
for data collection.  We run assembly process and since 2000 I have been using custom made DDE (ActiveX) interface using RSLINX and at the time MFC of VB applications
that 1. Connect to PLC 2. Connect to database. Using a cycle complete trigger we store every part cycle and its corresponding data into SQL databases. I then Created Web pages (Apache) with pre made queries to display the data
to the manufacturing floor etc. with libplctag I plan on creating Linux Service that will hopefully be fault tolerant and collect data with little to no intervention. I mean 90% of my failures come from RSLINX.
So once again thank you and keep up the great work!

Sincerly,
John Wurm
LPIC


P.S. Is there an example of a float in the examples. I think I just need to see it.
I am assuming it is in plc_tag_get_float32 will try to work it out again today.
--
Thank You,
John Wurm

tim...@gmail.com

unread,
Oct 29, 2020, 10:29:31 PM10/29/20
to libplctag
libplctag.NET is built for .NET Standard 2.0 - which both .NET Core >=2.0 and .NET Framework >=4.6.1 can run.
C#, VB.NET, F#, IronPython, etc that target these runtimes should all be able to make use of the package - we only have demos and have tested for C# and VB.NET though.

Tim

Reply all
Reply to author
Forward
0 new messages