Skip to content

Sending SINT write request using client results in error #109

@mgomez12

Description

@mgomez12

I'm attempting to use the client to send EIP requests, but I had an issue pop up when the data type is an SINT. Essentially, I send the operation @0x64/1/0x05 = (SINT)-1, which fails with the following trace:

/usr/local/lib/python3.8/dist-packages/cpppo/server/enip/get_attribute.py:431: in read
    for val,(sts,(att,typ,uni)) in reader:
/usr/local/lib/python3.8/dist-packages/cpppo/server/enip/get_attribute.py:618: in read_details
    for i,(idx,dsc,req,rpy,sts,val) in enumerate( connection.operate(
/usr/local/lib/python3.8/dist-packages/cpppo/server/enip/client.py:1749: in operate
    for idx,dsc,req,rpy,sts,val in harvested:
/usr/local/lib/python3.8/dist-packages/cpppo/server/enip/client.py:1599: in pipeline
    iss         = next( issuer )
/usr/local/lib/python3.8/dist-packages/cpppo/server/enip/client.py:1348: in issue
    req         = self.set_attribute_single( timeout=timeout, send=not multiple, **op )
/usr/local/lib/python3.8/dist-packages/cpppo/server/enip/client.py:903: in set_attribute_sing
e
    self.req_send(
/usr/local/lib/python3.8/dist-packages/cpppo/server/enip/client.py:1188: in req_send
    return self.unconnected_send( request, **kwds )
/usr/local/lib/python3.8/dist-packages/cpppo/server/enip/client.py:1074: in unconnected_send
    us.request.input= bytearray( dialect.produce( us.request )) # eg. logix.Logix
/usr/local/lib/python3.8/dist-packages/cpppo/server/enip/logix.py:539: in produce
    result              = super( Logix, cls ).produce( data )
/usr/local/lib/python3.8/dist-packages/cpppo/server/enip/device.py:1797: in produce
    result              = super( Message_Router, cls ).produce( data )
/usr/local/lib/python3.8/dist-packages/cpppo/server/enip/device.py:1235: in produce
    result             += typed_data.produce(   data.set_attribute_single,
/usr/local/lib/python3.8/dist-packages/cpppo/server/enip/parser.py:2103: in produce
    result             += b''.join( map( producer, data.get( 'data' )))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

cls = <class 'cpppo.server.enip.parser.USINT'>, value = -1

    @classmethod
    def produce( cls, value ):
>       return struct.pack( cls.struct_format, value )
E       struct.error: ubyte format requires 0 <= number <= 255

/usr/local/lib/python3.8/dist-packages/cpppo/server/enip/parser.py:175: error

This is was unexpected because if the data was not valid for the specific type to begin with, it would have been caught with in the earlier int_validate step, however it doesn't fail until the produce function is called.

After digging a little more, I came across the following:

if tag_type not in (None,parser.SINT.tag_type,parser.USINT.tag_type):

What I'm understanding is that if the data type is more than a byte long (aka USINT or SINT), it converts it to a byte array of USINTs that it can later send. However, since the data isn't getting formatted, the SINT retains its negative value, which then causes the issue down the line when it tries to pack the data as a USINT. This seems like a quick fix (just removing the SINT check from the quoted line), but I was wondering if there was an intended reason for this behavior since i don't think it's been mentioned before.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions