Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Read bytes in both py2 and py3 #62

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 29 additions & 76 deletions sunspec/core/modbus/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ def remove_device(self, slave_id):
modbus_rtu_client_remove(self.name)

def _read(self, slave_id, addr, count, op=FUNC_READ_HOLDING, trace_func=None):
resp = ''
resp = bytearray()
len_remaining = 5
len_found = False
except_code = None
Expand All @@ -232,7 +232,7 @@ def _read(self, slave_id, addr, count, op=FUNC_READ_HOLDING, trace_func=None):
if trace_func:
s = '%s:%s[addr=%s] ->' % (self.name, str(slave_id), addr)
for c in req:
s += '%02X' % (ord(c))
s += '%02X' % (c)
trace_func(s)

self.serial.flushInput()
Expand All @@ -243,32 +243,27 @@ def _read(self, slave_id, addr, count, op=FUNC_READ_HOLDING, trace_func=None):

while len_remaining > 0:
c = self.serial.read(len_remaining)
if type(c) == bytes and sys.version_info > (3,):
temp = ""
for i in c:
temp += chr(i)
c = temp

len_read = len(c);
if len_read > 0:
resp += c
len_remaining -= len_read
if len_found is False and len(resp) >= 5:
if not (ord(resp[1]) & 0x80):
len_remaining = (ord(resp[2]) + 5) - len(resp)
if not (resp[1] & 0x80):
len_remaining = (resp[2] + 5) - len(resp)
len_found = True
else:
except_code = ord(resp[2])
except_code = resp[2]
else:
raise ModbusClientTimeout('Response timeout')

if trace_func:
s = '%s:%s[addr=%s] <--' % (self.name, str(slave_id), addr)
for c in resp:
s += '%02X' % (ord(c))
s += '%02X' % (c)
trace_func(s)

crc = (ord(resp[-2]) << 8) | ord(resp[-1])
crc = (resp[-2] << 8) | resp[-1]
if not checkCRC(resp[:-2], crc):
raise ModbusClientError('CRC error')

Expand Down Expand Up @@ -306,7 +301,7 @@ def read(self, slave_id, addr, count, op=FUNC_READ_HOLDING, trace_func=None, max
Byte string containing register contents.
"""

resp = ''
resp = bytearray()
read_count = 0
read_offset = 0

Expand All @@ -329,7 +324,7 @@ def read(self, slave_id, addr, count, op=FUNC_READ_HOLDING, trace_func=None, max
return resp

def _write(self, slave_id, addr, data, trace_func=None):
resp = ''
resp = bytearray()
len_remaining = 5
len_found = False
except_code = None
Expand All @@ -338,66 +333,50 @@ def _write(self, slave_id, addr, data, trace_func=None):
count = int(len_data/2)

req = struct.pack('>BBHHB', int(slave_id), func, int(addr), count, len_data)
if sys.version_info > (3,):
data = bytes(data, "latin-1")
req += data
req += struct.pack('>H', computeCRC(req))
if sys.version_info > (3,):
temp = ""
for i in req:
temp += chr(i)
req = temp

if trace_func:
s = '%s:%s[addr=%s] ->' % (self.name, str(slave_id), addr)
for c in req:
s += '%02X' % (ord(c))
s += '%02X' % (c)
trace_func(s)

self.serial.flushInput()
try:
if sys.version_info > (3,):
req = bytes(req, "latin-1")
self.serial.write(req)
except Exception as e:
raise ModbusClientError('Serial write error: %s' % str(e))

while len_remaining > 0:
c = self.serial.read(len_remaining)
if type(c) == bytes and sys.version_info > (3,):
temp = ""
for i in c:
temp += chr(i)
c = temp
len_read = len(c);
if len_read > 0:
resp += c
len_remaining -= len_read
if len_found is False and len(resp) >= 5:
if not (ord(resp[1]) & 0x80):
if not (resp[1] & 0x80):
len_remaining = 8 - len(resp)
len_found = True
else:
except_code = ord(resp[2])
except_code = resp[2]
else:
raise ModbusClientTimeout('Response timeout')

if trace_func:
s = '%s:%s[addr=%s] <--' % (self.name, str(slave_id), addr)
for c in resp:
s += '%02X' % (ord(c))
s += '%02X' % (c)
trace_func(s)


crc = (ord(resp[-2]) << 8) | ord(resp[-1])
crc = (resp[-2] << 8) | resp[-1]
if not checkCRC(resp[:-2], crc):
raise ModbusClientError('CRC error')

if except_code:
raise ModbusClientException('Modbus exception: %d' % (except_code))
else:
if sys.version_info > (3,):
resp = bytes(resp, 'latin-1')
resp_slave_id, resp_func, resp_addr, resp_count, resp_crc = struct.unpack('>BBHHH', resp)
if resp_slave_id != slave_id or resp_func != func or resp_addr != addr or resp_count != count:
raise ModbusClientError('Mobus response format error')
Expand Down Expand Up @@ -686,7 +665,7 @@ def disconnect(self):

def _read(self, addr, count, op=FUNC_READ_HOLDING):

resp = b''
resp = bytearray()
len_remaining = TCP_HDR_LEN + TCP_RESP_MIN_LEN
len_found = False
except_code = None
Expand All @@ -696,7 +675,7 @@ def _read(self, addr, count, op=FUNC_READ_HOLDING):
if self.trace_func:
s = '%s:%s:%s[addr=%s] ->' % (self.ipaddr, str(self.ipport), str(self.slave_id), addr)
for c in req:
s += '%02X' % (ord(c))
s += '%02X' % (c)
self.trace_func(s)

try:
Expand All @@ -717,22 +696,16 @@ def _read(self, addr, count, op=FUNC_READ_HOLDING):
else:
raise ModbusClientError('Response timeout')

if sys.version_info > (3,):
temp = ""
for i in resp:
temp += chr(i)
resp = temp

if not (ord(resp[TCP_HDR_LEN + 1]) & 0x80):
len_remaining = (ord(resp[TCP_HDR_LEN + 2]) + TCP_HDR_LEN) - len(resp)
if not (resp[TCP_HDR_LEN + 1] & 0x80):
len_remaining = (resp[TCP_HDR_LEN + 2] + TCP_HDR_LEN) - len(resp)
len_found = True
else:
except_code = ord(resp[TCP_HDR_LEN + 2])
except_code = resp[TCP_HDR_LEN + 2]

if self.trace_func:
s = '%s:%s:%s[addr=%s] <--' % (self.ipaddr, str(self.ipport), str(self.slave_id), addr)
for c in resp:
s += '%02X' % (ord(c))
s += '%02X' % (c)
self.trace_func(s)

if except_code:
Expand Down Expand Up @@ -760,7 +733,7 @@ def read(self, addr, count, op=FUNC_READ_HOLDING):
Byte string containing register contents.
"""

resp = ''
resp = bytearray()
read_count = 0
read_offset = 0
local_connect = False
Expand All @@ -787,14 +760,11 @@ def read(self, addr, count, op=FUNC_READ_HOLDING):
if local_connect:
self.disconnect()

if sys.version_info > (3,):
resp = bytes(resp, 'latin-1')

return resp

def _write(self, addr, data):

resp = ''
resp = bytearray()
len_remaining = TCP_HDR_LEN + TCP_RESP_MIN_LEN
len_found = False
except_code = None
Expand All @@ -811,7 +781,7 @@ def _write(self, addr, data):
if self.trace_func:
s = '%s:%s:%s[addr=%s] ->' % (self.ipaddr, str(self.ipport), str(self.slave_id), addr)
for c in req:
s += '%02X' % (ord(c))
s += '%02X' % (c)
self.trace_func(s)

try:
Expand All @@ -824,36 +794,24 @@ def _write(self, addr, data):
# print('c = {0}'.format(c))
len_read = len(c);
if len_read > 0:
if type(c) == bytes and sys.version_info > (3,):
temp = ""
for i in c:
temp += chr(i)
c = temp
resp += c
len_remaining -= len_read
if len_found is False and len(resp) >= TCP_HDR_LEN + TCP_RESP_MIN_LEN:
if sys.version_info > (3,):
resp = bytes(resp, "latin-1")
data_len = struct.unpack('>H', resp[TCP_HDR_O_LEN:TCP_HDR_O_LEN + 2])
len_remaining = data_len[0] - (len(resp) - TCP_HDR_LEN)
if type(resp) == bytes and sys.version_info > (3,):
temp = ""
for i in resp:
temp += chr(i)
resp = temp
else:
raise ModbusClientTimeout('Response timeout')

if not (ord(resp[TCP_HDR_LEN + 1]) & 0x80):
len_remaining = (ord(resp[TCP_HDR_LEN + 2]) + TCP_HDR_LEN) - len(resp)
if not (resp[TCP_HDR_LEN + 1] & 0x80):
len_remaining = (resp[TCP_HDR_LEN + 2] + TCP_HDR_LEN) - len(resp)
len_found = True
else:
except_code = ord(resp[TCP_HDR_LEN + 2])
except_code = resp[TCP_HDR_LEN + 2]

if self.trace_func:
s = '%s:%s:%s[addr=%s] <--' % (self.ipaddr, str(self.ipport), str(self.slave_id), addr)
for c in resp:
s += '%02X' % (ord(c))
s += '%02X' % (c)
self.trace_func(s)

if except_code:
Expand Down Expand Up @@ -1033,13 +991,8 @@ def computeCRC(data):
:returns: The calculated CRC
'''
crc = 0xffff
if type(data) == bytes and sys.version_info > (3,):
temp = ""
for i in data:
temp += chr(i)
data = temp
for a in data:
idx = __crc16_table[(crc ^ ord(a)) & 0xff];
for a in bytearray(data):
idx = __crc16_table[(crc ^ a) & 0xff];
crc = ((crc >> 8) & 0xff) ^ idx
swapped = ((crc << 8) & 0xff00) | ((crc >> 8) & 0x00ff)
return swapped
Expand Down
7 changes: 4 additions & 3 deletions sunspec/core/test/test_modbus_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ def test_modbus_client_device_rtu_read(self):
if d.client.serial.out_buf != b'\x01\x03\x9C\x40\x00\x02\xEB\x8F':
raise Exception("Modbus request mismatch")

if data != 'SunS':
raise Exception("Read data mismatch - expected: 'SunS' received: %s") % (data)
expected = b'SunS'
if data != expected:
raise Exception("Read data mismatch - expected: {expected} received: {data}".format(expected=repr(expected), data=repr(data)))

d.close()

Expand All @@ -63,7 +64,7 @@ def test_modbus_client_device_rtu_write(self):
d.client.serial.in_buf = b'\x01\x10\x9C\x40\x00\x02\x6E\x4C'
d.client.serial.out_buf = b''

d.write(40000, 'ABCD')
d.write(40000, b'ABCD')

if d.client.serial.out_buf != b'\x01\x10\x9C\x40\x00\x02\x04\x41\x42\x43\x44\x8B\xB2':
raise Exception("Modbus request mismatch")
Expand Down
2 changes: 1 addition & 1 deletion sunspec/core/test/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def test_data_to_double(self):
self.assertEqual(util.data_to_double(b'\xc0\x8f\x40\x00\x00\x00\x00\x00'), float(-1000))

def test_data_to_str(self):
self.assertEqual(util.data_to_str(b'\x53\x75\x6e\x53\x70\x65\x63\x20\x54\x65\x73\x74\x00'), 'SunSpec Test')
self.assertEqual(util.data_to_str(b'\x53\x75\x6e\x53\x70\x65\x63\x20\x54\x65\x73\x74\x00'), b'SunSpec Test')


def test_s16_to_data(self):
Expand Down
10 changes: 3 additions & 7 deletions sunspec/core/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,10 @@ def data_to_double(data):
return d[0]

def data_to_str(data):
data = data.rstrip(b'\0')
if len(data) == 0:
data = b'\0'

# Change the data from bytes string to regular string for python 3
# compatibility
if sys.version_info > (3,):
data = str(data, 'latin-1')

if len(data) > 1:
data = data[0] + data[1:].rstrip('\0')
return data

def s16_to_data(s16, len=None):
Expand Down