Open CagtayFabry opened 1 year ago
I am sorry that noone replied to you on this. I think this is because noone knows the solution. Sorry! This is a pretty advanced case though and not something I have come across people wanting to do. As this is more of a question that a bug, could you please kindly close this issue to help us manage the issue tracker.
Thanks for looking into it @chrisbeardy
I agree that this is more of a feature request than a bug report (and a pretty advanced one probably) If you don't mind I would like to keep this open, maybe someone scrolls past here at some point who knows how to implement this.
As for the feature itself, I think it would be a great addition if pyads
would be able to handle receive the corrected timestamp information. 🚀
Looking into this in more detail, it looks like None should be used as a null pointer in python when using ctypes.
https://docs.python.org/3/library/ctypes.html#calling-functions
The issue here i think is the pyads function adsSyncWriteReqEx
does not account for this being passed in and is throwing the error before it even calls the C DLL.
It actually calls the C DLL here
error_code = sync_write_request(
port,
ams_address_pointer,
index_group_c,
index_offset_c,
data_length,
data_pointer,
)
You could experiment with editing the pyads code to account for the None type being passed in.
e.g.
elif type(value) is plc_data_type:
data = value
elif plc_data_type is None:
data = None
else:
data = plc_data_type(value)
This may not work due to the lines:
data_pointer = ctypes.pointer(data)
data_length = ctypes.sizeof(data)
You could also try calling the C DLL manually yourself by accessing the "private" variable in the library, or just adding it yourself by cribbing the following:
if platform_is_windows(): # pragma: no cover, skip Windows test
dlldir_handle = None
if sys.version_info >= (3, 8) and "TWINCAT3DIR" in os.environ:
# Starting with version 3.8, CPython does not consider the PATH environment
# variable any more when resolving DLL paths. The following works with the default
# installation of the Beckhoff TwinCAT ADS DLL.
dll_path = os.environ["TWINCAT3DIR"] + "\\..\\AdsApi\\TcAdsDll"
if platform.architecture()[0] == "64bit":
dll_path += "\\x64"
dlldir_handle = os.add_dll_directory(dll_path)
try:
_adsDLL = ctypes.WinDLL("TcAdsDll.dll") # type: ignore
finally:
if dlldir_handle:
# Do not clobber the load path for other modules
dlldir_handle.close()
NOTEFUNC = ctypes.WINFUNCTYPE( # type: ignore
ctypes.c_void_p,
ctypes.POINTER(SAmsAddr),
ctypes.POINTER(SAdsNotificationHeader),
ctypes.c_ulong,
)
sync_write_request = pyads._adsDLL.AdsSyncWriteReqEx # something like that, can't remember exact path, you'll be able to fudge the path
ams_address_pointer = ctypes.pointer(address.amsAddrStruct())
index_group_c = ctypes.c_ulong(index_group)
index_offset_c = ctypes.c_ulong(index_offset)
error_code = sync_write_request(
plc._port,
ctypes.pointer(plc._adr.amsAddrStruct())
ctypes.c_ulong(0xF088),
ctypes.c_ulong(0x00000000 | (3 & 0x000000FF)),
None,
None,
)
This is some great insight, thank you! I will try to get it to work.
I agree, pyads
has all the tools in place to make this work, might just need a few tweaks.
Let us know how you get on and if you can make pyads work, feel free to make a PR
I am trying to send an
AdsSyncWriteReqEx
command without any data usingpyads
The equivalent C API command I am trying to send is using a
nullptr
as data (with length 0)and is taken from the TwinCAT 3 | Corrected timestamps - ADS consumer example.
I initially tried
plc.write()
which didn't work and also tried using the ADS bindings inpyads
more directly after opening the ADS connection withplc.open()
but I run into the following error which I think indicates that
None
is not a valid replacement fornullptr
.Is there any way I could send this command using
pyads
? How to work withnullptr
in python? I am thankful for any suggestions