Crash when reading 'CPU Program File Name' from P2000 simulator
Closed this issue · 4 comments
File "/usr/local/lib/python3.9/site-packages/productivity/driver.py", line 85, in get
result.update(await self._read_registers(type))
File "/usr/local/lib/python3.9/site-packages/productivity/driver.py", line 254, in _read_registers
result[tag] = decoder.decode_string(chars).decode('ascii')
UnicodeDecodeError: 'ascii' codec can't decode byte 0x9c in position 29: ordinal not in range(128)
The problem is the register CPU Program File Name
which should be a 50-byte string. In the built-in ProductivitySuite Simulator it's showing as "TIC_Sourcing_Rev03_WIP.adpro" (presumably with padding at the end)
But over MODBUS it returns TIC_sourcing_Rev03_WIP.adpro\x00\x9c<\x9c\x00\
and the \x9c
character breaks both ASCII and UTF-8 decoders. There's also a strange >
for some reason.
Try decoding to iso Latin and let me know how it goes.
Also I've never seen the decoder library imported like that. Any reason to use that pattern instead of b"foo".decode()?
TIL there's a lot of overlap between ascii, Latin-1 and UTF-8 https://stackoverflow.com/questions/7048745/what-is-the-difference-between-utf-8-and-iso-8859-1
Obligatory recommendation of one of my favorite non-Hettinger pycon talks: Pragmatic Unicode, or, How do I stop the pain?. ISO Latin replaces most of the control characters in ASCII/UTF-8 with common non-ascii characters. If ASCII chokes on a one-byte char, then UTF-8 will too because UTF-8 is ASCII (outside of interpreting \xc2 and \xc3 differently). ISO Latin will likely succeed because it has far less control characters (probably encoding a TM, (c), etc).
I'll add in my heuristic: if you can see people using it with Office 2003 on Windows XP, it's probably ISO Latin.
Try decoding to iso Latin and let me know how it goes.
"TIC_sourcing_Rev03_WIP.adpro\u0000\u009c<\u009cy\u00bdC\u0003\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
"TIC_sourcing_Rev03_WIP.adpro�<�y½C�"
Not bad, but not really an improvement either. I'm going to call AutomationDirect and ask, especially because it's different from hardware PLCs.
Also I've never seen the decoder library imported like that. Any reason to use that pattern instead of b"foo".decode()?
I believe you wrote it based on upstream examples :P