dmroeder / pylogix

Read/Write data from Allen Bradley Compact/Control Logix PLC's

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Can not write more than 32 bits in a BOOL[512] array tag

curtislehmann opened this issue · comments

Preflight checks

Before you post an issue, ensure you have tried the minimal examples within the repo, or tried the pylogix-tester.

Type of issue

  • [x ] Bug
  • Feature Request
  • Question
  • Other

Description of issue

Can not write more than 32 bits in a BOOL[512] array tag.
(Reading the whole array works fine.)
(My deepest apologies for bringing up your nemesis!)

Expected behavior

Write all 512 elements in BOOL[512] array tag using a list.

Actual behavior

Can only write up to 32 elements by list. Can write any block of 32 bits within the array.
(Setting tag to 'Use_Node[480]' writes bits 480-511.)
2 different results depending on the number of elements in the list:
Trying to write 33 to 96 elements throws argument out of range error and subsequent code fails.
From 97 to 512 elements, response object is returned and prints as expected but with Status as "Unknown error 255".

Code

from pylogix import PLC

with PLC() as comm:
comm = PLC()
comm.IPAddress = '192.168.0.16'

# make a list
writeVal = []
for iNodeIdx in range(0, 33):
    writeVal.append(True)

# Show the list
print("Value list: " + str(len(writeVal)) + " elements.")
print(writeVal)

# *** Fails if more than 32 elements in list
plcResponse = comm.Write('Use_Node[0]', writeVal)

# Write just one value. Good on any bit 0-511.
#plcResponse = comm.Write('Use_Node[511]', False)     

# Using 33 to 96 element list, these prints fail, but using 98 to 512 elements, they work.
print("Response to Boolean Write: ")
print(plcResponse.TagName, plcResponse.Value, plcResponse.Status)

Stacktrace

Trying to write 33 to 96 elements causes subsequent lines of code to fail. Error output:
Windows:
Traceback (most recent call last):
File "D:\Documents\Python_Progs\Test\PyLogix\PLCtest-Bool.py", line 47, in
plcResponse = comm.Write('Use_Node[0]', writeVal)
File "C:\Python39\lib\site-packages\pylogix\eip.py", line 125, in Write
return self._writeTag(tag, value, datatype)
File "C:\Python39\lib\site-packages\pylogix\eip.py", line 364, in _writeTag
request = self._add_mod_write_service(tag_name, ioi, write_data[0], data_type)
File "C:\Python39\lib\site-packages\pylogix\eip.py", line 1154, in _add_mod_write_service
write_request += pack(fmt, val)
struct.error: argument out of range

Ubuntu:
Traceback (most recent call last):
File "/usr/lib/python3.8/idlelib/run.py", line 559, in runcode
exec(code, self.locals)
File "/home/curtis/pyprogs/PLCtest-Bool.py", line 51, in
plcResponse = comm.Write('Use_Node[0]', writeVal)
File "/home/curtis/.local/lib/python3.8/site-packages/pylogix/eip.py", line 128, in Write
return self._writeTag(tag, value, datatype)
File "/home/curtis/.local/lib/python3.8/site-packages/pylogix/eip.py", line 367, in _writeTag
request = self._add_mod_write_service(tag_name, ioi, write_data[0], data_type)
File "/home/curtis/.local/lib/python3.8/site-packages/pylogix/eip.py", line 1166, in _add_mod_write_service
write_request += pack(fmt, val)
struct.error: 'i' format requires -2147483648 <= number <= 2147483647

Include versions to

  • pylogix: 0.7.14, 0.7.16
  • python: 3.9.1 (win), 3.8.10 (Ubuntu)
  • OS: Windows 10 Ent. 20H2 build 19042.1237, Ubuntu 20.04

I hate boolean arrays so bad. It's not your fault :)
I'll check this out when I have a few. I appreciate the details.

@dmroeder, any words of wisdom from your fight against the forces of evil BOOL arrays? I started to develop "support" for these and found that there was a large challenge when you want to write a single bit. You have to set up a RMW operation. Those, in CIP, are annoying. They do not have an offset field and you can only mask up to 12 bytes IIRC. So you have to treat the array differently depending on whether you are write a single bit or not. It was a mess.

@kyle-github, it's been a bit since I've thought about BOOL arrays, I'll share what I remember when I work through this.

Dang it I think this is a unittest deficiency, we have a test fixture to read bool_array[128] but not to write, if I am not mistaken. I'll add that to the todo for unittests. And also probably up the 128 to a few more multiples of that.

https://github.com/dmroeder/pylogix/blob/master/tests/PylogixTests.py#L329

BOOLS are evil!

Well, I made a typo referencing this issue. It should be fixed in 0.8.1 @curtislehmann. Apologies for taking so long.

@TheFern2, I also added a unittest. The main issue was spanning multiple words, so more BOOL's isn't necessary for the unittest, only making sure that we write more than 4 bytes worth, or more accurately, write to 2 different 4 byte "chunks". For example:

values = [1, 1]
tag = nemesis[31]
comm.Write(tag, value)

The above would test this because the first bool is the last bit of a word, the 2nd is the first bit of the next word.

@dmroeder Thanks so much.
Using 0.8.1 I can now write up to 96 bits to any block within the 512 bit tag. The data does not have to match any 32 bit boundary either, as it did before. However, it still gives the "Unknown error 255" if I try to write more than 96 bits. @kyle-github mentioned a 12 byte (96 bit) limitation, perhaps that is related to this problem. Again, Thanks.

You are not trying to write beyond the 512 bits are you? I tested it with all 512.

Edit: I'm guessing not, that returns a different error

This works:

import pylogix

with pylogix.PLC("192.168.1.10") as comm:

    values = [1 for i in range(512)]
    ret = comm.Write("Nemesis[0]", values)
    print(ret)

Not going past 512. If I write to bits 0-95 it's ok, 0-96 it throws error 255. 512 element BOOL tag.
Same results with your code and mine.
I wonder if it's processor dependent. Tested on an L32E with FW 20.12 and an L71 with FW 30.13.

Weird. I solved this in kind of a hacky way. I find the boundaries and make multiple writes, so only a maximum of 32 bits ware written at a time. I did all of my testing on my L30ER with v30 and v34. The 5370 and 5570 are really the same in this regard.

That code I pasted in there is exactly what I used. I retested with it moments before I pasted it here.

Can you capture it via wireshark and email it to me?

Will do.

Hmm, I don't think I got the wireshark file.

Try my email in the setup.py file, if you don't mind.

Okay, I see what is going on. Fragmented write is being triggered because pylogix was thinking that your write wasn't going to fit in a single packet. Fix coming soon.