我正在使用别人编写的代码来读取和编码来自数字/模拟转换器的数据。我尝试通过使其与python 3一起使用来改进此代码,因为它是在python 2中编码的。
我已经减少了很多代码以了解为什么它在Python 3上不起作用,并发现了“ map”函数行为的问题,因为它说“在Python 3中发生了错误,但在python 2中没有发生。
我不知道我在哪里做错了,因为我自己没有编写此代码,因此有些地方我无法理解。 我应该进行哪些更改才能使其与python 3兼容?
from DTOL import DTOL
io = DTOL(name='DT9818(00)')
io.Initialize('DT9818(00)')
io.setupGetSingleValue()
DTOL
import ctypes
from time import sleep
from DTOL_defs import *
from DTOL_prototypes import *
class DTOL:
""" Data Translation DtOLWrapper Class """
def __init__(self, name='DT9818(00)'):
self.name = name
self.data = []
self.sshandle = []
self.hdev = []
self.range = (-10,10)
self.rmin = ctypes.c_double(-10)
self.rmax = ctypes.c_double(10)
self.gain = ctypes.c_double(1)
self.res = ctypes.c_uint(16)
self.enc = ctypes.c_uint(OL_ENC_BINARY)
self.val = 0
def Initialize(self, name):
print('Available Boards:')
olDaEnumBoards(listboardscallback, 1)
print('-----')
print('Initializing: ' + str(name))
name = name.encode('utf-8')
hdev = olDaInitialize(name)
self.hdev = hdev
return hdev
def GetSubsystem(self, subsystem_code, elemNum):
print(subsystem_code)
print(elemNum)
sshandle = olDaGetDASS(self.hdev, subsystem_code, elemNum)
self.sshandle = sshandle
return sshandle
def setupGetSingleValue(self):
self.Initialize(self.name)
self.GetSubsystem(OLSS_AD, ctypes.c_ulong(0))
if __name__ == "__main__":
print("Usage: io=DTOL('DT9818(00)')")
print("io.setupSingleValue()")
print("io.getSingleValue()")
io = DTOL()
io.setupGetSingleValue()
DTOL_prototypes
import ctypes
from ctypes.util import find_library
dll = ctypes.CDLL(find_library('oldaapi64'))
dll2 = ctypes.CDLL(find_library('OLMEM64'))
def errcheck_all(ret, func, args):
if ret:
print("Error occured in"+ str(func))
return
return args
def errcheck_none(ret, func, args):
if ret:
print("Error occured in"+ str(func))
print(ret)
return
# ----------- Initialize ---------------------------------
prototype = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_char_p, ctypes.POINTER(ctypes.c_ulong))
paramflags = (1, "name"), (2,"hDev")
olDaInitialize = prototype(('olDaInitialize', dll), paramflags)
olDaInitialize.errcheck = errcheck_all
# -----------END Initialize ---------------------------------
# ----------- olDaGetDASS ---------------------------------
prototype = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_ulong, ctypes.c_long, ctypes.c_uint, ctypes.POINTER(ctypes.c_ulong))
paramflags = (1, "hDev"), (1,"SubsystemType"), (1,"uiElementNr"), (2,"adhandle")
olDaGetDASS = prototype(('olDaGetDASS',dll), paramflags)
olDaGetDASS.errcheck = errcheck_all
# ----------- olDaGetDASS ---------------------------------
DTOL_defs
import ctypes
(OLSS_AD,
OLSS_DA,
OLSS_DIN,
OLSS_DOUT,
OLSS_SRL,
OLSS_CT) = list(map(ctypes.c_int, (range(6))))
OL_ENC_BINARY = 200
结果,我发现了python 3和2之间的区别: Python 3:
c_long(0)
<class 'ctypes.c_long'>
Available Boards:
Name = b'DT9818(00)'
Drivername = b'Dt9818'
1
-----
Initializing: DT9818(00)
Available Boards:
Name = b'DT9818(00)'
Drivername = b'Dt9818'
1
-----
Initializing: DT9818(00)
c_long(0)
c_ulong(0)
Error occured in<WinFunctionType object at 0x00000235269DC528>
Python 2:
c_long(0)
<class 'ctypes.c_long'>
Available Boards:
Name = DT9818(00)
Drivername = Dt9818
1
-----
Initializing: DT9818(00)
Available Boards:
Name = DT9818(00)
Drivername = Dt9818
1
-----
Initializing: DT9818(00)
c_long(0)
c_ulong(0L)
最后两个参数分别对应于“ print(subsystem_code)”和“ print(elemNum)”。
答案 0 :(得分:1)
我不知道您为什么认为 map 是问题。在两个 Python 版本中,它的调用方式(从中构造 list )均相同。
发布[Python 3]: ctypes - A foreign function library for Python。
如果没有函数文档,就无法确定 100%,但是从声明它们的方式来看:
olDaInitialize :
prototype = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_char_p, ctypes.POINTER(ctypes.c_ulong))
paramflags = (1, "name"), (2, "hDev")
olDaGetDASS :
prototype = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_ulong, ctypes.c_long, ctypes.c_uint, ctypes.POINTER(ctypes.c_ulong))
paramflags = (1, "hDev"), (1, "SubsystemType"), (1, "uiElementNr"), (2, "adhandle")
我可以得出结论,返回值代表函数的执行状态,通常是:
但是,在 Initialize 中,设置 hDev (这是 olDaInitialize 的输出,是 olDaGetDASS 的输入)像这样(也有类型不匹配,但被自动强制转换隐藏了):
hdev = olDaInitialize(name)
self.hdev = hdev
因此您将 olDaInitialize 的状态分配给 hdev ,这毫无意义。正确的方法是:
在 __ init __ 中:
self.hdev = ctypes.c_ulong(0)
在初始化中:
hdev = ctypes.c_ulong(0)
status = olDaInitialize(name, ctypes.byref(hdev))
if status == 0: # Or whichever value means SUCCESS
self.hdev = hdev
完全相同的内容也适用于 adhandle ( olDaGetDASS 的最后一个参数),您在 GetSubsystem中引用(如 shangdle ),并且可能在代码中使用其他地方。
我们处于改进部分:
同时传递给 __ init __ 和 Initialize 的名称似乎是多余的。我建议将其保留在初始化程序中,并放在正文中:
self.name = name.encode("utf-8")
,然后从 Initialize 中删除参数,并在其中使用self.name
您正在使用 errcheck 功能,但是现在它根本没有帮助。您可以对此进行改进(例如,通过显示错误代码)。有关[SO]: How to use ctypes' errcheck? (@CristiFati's answer)
Initialize 被调用两次:在主脚本和 setupGetSingleValue 中。您应该从一个地方删除呼叫(我想说是后者)
olDaEnumBoards (和 listboardscallback )丢失。另外, 1 st 2行是从哪里打印的?
尝试使标识符名称保持一致([Python]: PEP 8 -- Style Guide for Python Code)
@ EDIT0 :
添加一些简化的代码,以检查问题是否重现。
code.py :
#!/usr/bin/env python3
import sys
import ctypes
def main():
oldaapi64 = ctypes.CDLL(find_library("oldaapi64"))
olmem64 = ctypes.CDLL(find_library("olmem64"))
oldainitialize = oldaapi64.olDaInitialize
oldainitialize.argtypes = [
ctypes.c_char_p, ctypes.POINTER(ctypes.c_ulong),
]
oldainitialize.restype = ctypes.c_int
oldagetdass = olmem64.olDaGetDASS
oldagetdass.argtypes = [
ctypes.c_ulong, ctypes.c_long, ctypes.c_uint, ctypes.POINTER(ctypes.c_ulong),
]
oldagetdass.restype = ctypes.c_int
dev = ctypes.c_ulong(0)
res = oldainitialize(b"DT9818(00)", ctypes.byref(dev))
print("{:s} returned {:d}. Dev: {:d}".format(oldainitialize.name, res, dev.value))
OLSS_AD = 0
element_num = 0
handle = ctypes.c_ulong(0)
res = oldagetdass(dev, OLSS_AD, element_num, ctypes.byref(handle))
print("{:s} returned {:d}. Handle: {:d}".format(oldagetdass.name, res, handle.value))
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
main()
print("Done.")
答案 1 :(得分:0)
我还尝试使用类似的ADC与python 3.x一起使用。和您一样,我遇到了与python 2.7一起运行的pyDTOL模块。不幸的是,我陷入了同样的问题。 我试图了解pyDTOL中到底发生了什么,最终得到了与CristiFati类似的方法。我添加了发布ADC的功能。 这是我的代码(适用于python 2.7,但对于3.x有问题):
import ctypes
from ctypes.util import find_library
def main():
ctypes.cdll.LoadLibrary(find_library('oldaapi64'))
oldaapi = ctypes.CDLL("oldaapi64")
name= b'DT9836S(00)'
olDaInitialize = oldaapi.olDaInitialize
olDaInitialize.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_ulong)]
olDaInitialize.retype = ctypes.c_ulong
hdev = ctypes.c_ulong()
ret_init = olDaInitialize(name, ctypes.byref(hdev))
print('hdev: ' + str(hdev))
print('return from olDaInitialize: ' + str(ret_init))
olDaGetDASS = oldaapi.olDaGetDASS
olDaGetDASS.argtypes = [ctypes.c_ulong, ctypes.c_long, ctypes.c_uint,
ctypes.POINTER(ctypes.c_ulong)]
olDaGetDASS.restype = ctypes.c_ulong
OLSS_AD = ctypes.c_long(0)
sshandle = ctypes.c_ulong()
ret_dass = olDaGetDASS(hdev.value, OLSS_AD, ctypes.c_uint(0),
ctypes.byref(sshandle))
print('sshandle: ' + str(sshandle))
print('return from olDaGetDASS: ' + str(ret_dass))
olDaReleaseDASS = oldaapi.olDaReleaseDASS
olDaReleaseDASS.argtype = ctypes.c_ulong
olDaReleaseDASS.restype = ctypes.c_ulong
ret_rdass = olDaReleaseDASS(sshandle.value)
olDaTerminate = oldaapi.olDaTerminate
olDaTerminate.argtype = ctypes.c_ulong
olDaTerminate.restype = ctypes.c_ulong
ret_term = olDaTerminate(hdev.value)
if __name__ == "__main__":
main()
Python 2.7中的输出:
hdev: c_ulong(11836704L)
return from olDaInitialize: 0
sshandle: c_ulong(11843088L)
return from olDaGetDASS: 0
Python 3.6中的输出:
hdev: c_ulong(3420637248)
return from olDaInitialize: 0
sshandle: c_ulong(0)
return from olDaGetDASS: 39
根据“ oldaapi64-手册”,返回值“ 0”表示“操作已完成;没有错误。 ” olDaGetDass的重新运行值为39表示:“指定了非法的设备句柄。 “
在我看来,有两种可能性: hdev指针(来自“ olDaInitialize”)在python 3中有不同的解释,或者将hdev传递给“ olDaGetDASS”会出现问题。
如果我们能找到解决方法,那就太好了!
修改: @来自CrisiFati的答复:DLL olmem64没有功能 olDaGetDASS
oldagetdass = olmem64.olDaGetDASS
您必须使用oldaapi64
oldagetdass = oldaapi64.olDaGetDASS
用户手册可以在这里找到:
https://www.mccdaq.com/PDFs/Manuals/UMDataAcq.pdf 附录A显示了一个示例。 在 Calling Conventions 中,声明返回值是无符号长且使用Microsoft Pascal调用约定。
最好的问候