plcpeople / nodepccc

Library for node.js to communicate with some Allen-Bradley programmable controllers (PLCs)
MIT License
81 stars 24 forks source link

Can not read string array #29

Closed srebling closed 5 years ago

srebling commented 5 years ago

Trying to read string array and only get first 2 elements. Writes work perfectly. Can always read array of 2. Code below produces following:

Values read: { STRARRAY: [ 'String 00', 'String 01', '', '' ] } [50475,547282909 10.0.0.101] Preparing to WRITE STR0,STR1,STR2,STR3,STR4 [50475,559641594] NST9:0 write completed with quality OK [50475,559721341] NST9:1 write completed with quality OK [50475,559756823] NST9:2 write completed with quality OK [50475,559794130] NST9:3 write completed with quality OK [50475,559815871] NST9:4 write completed with quality OK Done writing.


function connected(err) { if (typeof(err) !== "undefined") { // We have an error. Maybe the PLC is not reachable. console.log(err); // process.exit(); } conn.setTranslationCB(tagLookup);

conn.addItems('STRARRAY');

// conn.addItems(['INT0','INT1','INT2', 'INT2']);

    async.forever(
        function(next) {
            //conn.readAllItems(valuesReady);
            if (doneReading && doneWriting) {
            doneReading = false;
            conn.readAllItems(function (err, values) {
                if (err) {
                  console.log("SOMETHING WENT WRONG READING VALUES!!!!");
                  plc_error = true;
                } else {
                  console.log('Values read: ',values)
                  plc_error = false;
                  ++sheet_length;
                  conn.writeItems(['STR0', 'STR1', 'STR2', 'STR3', 'STR4'],
                                  ['String 00', 'String 01', 'String 02', 'String 03', 'String 04'], valuesWritten);

// conn.writeItems(['INT0', 'INT1', 'INT2'], // [2, sheet_length, 500500], valuesWritten); doneWriting = false; } doneReading = true; setTimeout(function () { next(); }, 1000); // if (doneWriting) { process.exit(); } }); } }, function(err) { console.log('READ LOOP ERROR: ' + err); } ); }

function valuesWritten(anythingBad) { if (anythingBad) { console.log("SOMETHING WENT WRONG WRITING VALUES!!!!"); } console.log("Done writing."); doneWriting = true; }

// This is a very simple "tag lookup" callback function that would eventually be replaced with either a database findOne(), or a large array in memory. // Note that the return value is a controller absolute address and datatype specifier. // If you want to use absolute addresses only, you can do that too. function tagLookup(tag) { switch (tag) { case 'TEST1': return 'Test_Int'; // Integer case 'TEST2': return 'B3:0/0'; // Bit case 'TEST3': return 'B3/17'; // Same as B3:1/1 case 'TEST4': return 'F8:0,20'; // Yes this is an array... 20 real numbers. case 'TEST5': return 'F8:1'; // Single real. case 'TEST6': return 'F8:2'; // Another single real. case 'TEST7': return 'N7:1,2'; // A couple of integers in an array case 'TEST8': return 'NST9:2,4'; // Direct output case 'TEST9': return 'N7:0'; // Direct output case 'STRARRAY': return 'NST9:0,4'; // setup number case 'STR0': return 'NST9:0'; // setup number case 'STR1': return 'NST9:1'; // customer name case 'STR2': return 'NST9:2'; // order number case 'STR3': return 'NST9:3'; // next operation case 'STR4': return 'NST9:4'; // generic comment case 'INT0': return 'L7:0'; // discharge direction (flags?) case 'INT1': return 'L7:1'; // sheet width case 'INT2': return 'L7:2'; // sheet length case 'INT3': return 'L7:3'; // sheets in discharge case 'INT4': return 'L7:4'; // sheets in discharge case 'INT5': return 'L7:5'; // stacks to batch default: return undefined; } }

plcpeople commented 5 years ago

Did you verify the write in Studio 5000?

Because it's an N file, it needs 44 integers for a string, STR1 should be NST9:44, then 88 and so on.

srebling commented 5 years ago

I've never been able to get it work writing with single dimension array. Always writes over first location offset by one. But writing to a 2 dimensional array works great! N9 INT[100,44] (100 strings). STR0 = N9[0,0] STR1 = N9[1,0], STR2 = N9[2,0]... Then this instruction copies to a true STRING array: COP N9[0,0] PC_STRING[0] 100 Can only read back the first two though.

plcpeople commented 5 years ago

That is why it works for me and not for you - I think it will be really difficult to support two-dimensional arrays with nodePCCC because the PCCC protocol is meant for simple data tables.

Reason: When we read an array of NSTRING values, we need to read 88x4 = 352 bytes. The maximum amount of PCCC data we can request varies, but the latest nodePCCC figures it's about 200 in my case, but then shortens this to 176 to keep from "splitting a string" over multiple read requests. So it comes up with two chunks of data - one starting at N9:0, and another one starting at - it calculates N9:88, because this is 176 bytes later, and the "88" number is part of the request for the second half of the data. But in the case of a two dimensional array, how the ControlLogix/CompactLogix maps a two dimensional array to a SLC file internally probably doesn't agree with that calculation. You could fill the array with a bunch of characters to see what you're getting, but then we would need additional syntax in the item definition to support this properly, and that could get complicated when extended to other data types as well. Time would be better spent supporting CIP to get the tag in its native format.

When I tested this on the weekend, I set up a CompactLogix with the following variables: N9 created as INT[484]
ST41 created as STRING[5]

And a single instruction in the program: COP ST41[0] N9[0] 484

I typed in values in Logix for the strings and wanted to read them as NSTRINGS.

I then was able to read strings using either of the following methods: TEST8 - NST9:0,4 to read or write ALL strings as an array. STR0 - NST9:0 STR1 - NST9:44 STR2 - NST9:88 STR3 - NST9:132

Writing the array works too, I tested this as well, with the COP instruction disabled.

I would suggest you try the single-dimension arrays again with the COP done the way I suggest, it works much better with 0.1.11.

Alternatively, edit the code for theItem.plcnpratio = 44; on line 2412 and try different values to find what works for a two-dimensional array.

srebling commented 5 years ago

Ok, I see what I was doing wrong when writing to the single array. All works as advertised now. I might continue using the two dimensional array for writing though. Works so nice. Thanks!

plcpeople commented 5 years ago

Good to hear it's working better now. When I get a chance I will see if I can figure out what the PLC is doing with the 2D array and the PCCC request.

plcpeople commented 5 years ago

I did play around a bit with 2D arrays and at least I understand a little better how that works. If you set the plcnpratio to 1 instead of 44 as in the latest code, it works reading and writing large arrays of strings. If you want to have this as an option that you specify when connecting, I will add it, but I don't want to force it to be that way as I don't want to break any existing applications. Either way I will close the issue, it works now with single-dimension arrays and we can support the 2D ones easily if anyone asks for the option.