SAAT-500 Series Active RFID in Python using C code PROJECT - python

We are building a project using active RFID, and this RFID needs to be coded on Python to use it on Raspberry PI3
SAAT RFID already has DLL file, RFIDAPI.lib and RFIDAPIEXPORT.h and various API calling function
For instance and the basic code I need to execute
bool SAAT_TCPInit (void** pHandle,char *pHostName,int nsocketPort)
HANDLE hp; if(!SAAT_TCPInit(&hp,”192.168.0.238”,7086) )
{
printf("reader initialization failed!\n"); return false;
}
How can I convert this code into Python to get into RFID?

Untested, but illustrates what you need to do. I assumed Python 3, but Python 2 is similar.
#!python3
import ctypes
# import the DLL
dll = ctypes.CDLL('RFIDAPI')
# declare the argument and return value types
dll.SAAT_TCPInit.argtypes = ctypes.POINTER(ctypes.c_void_p),ctypes.c_char_p,ctypes.c_int)
dll.SAAT_TCPInit.restype = ctypes.c_bool
# For the output parameter, create an instance to be passed by reference.
hp = ctypes.c_void_p()
if not dll.SAAT_TCPInit(ctypes.byref(hp),b'192.168.0.238',7086):
print('reader initialization failed!')
Note the byte string for the IP. In Python 3 byte strings are the correct input for c_char_p.

Related

Getting the instance handle of a window in python (ctypes)

I've been trying to create a simple window using win32api but in python using the ctypes lib.
Now the first thing i need is the programs console windows instance handle.
For getting that i need to get a handle to the console window which is doable by using Kernel.dll GetConsoleWindow() Function. Then i pass that to the GetWindowLongA() Function of the User32.dll library which should return the python equivalent of HINSTANCE in windows.h header of C which should be an int. but all i get is 0 which means it has failed.
The code i currently have is:
windows = windll.LoadLibrary("User32.dll")
kernel = windll.LoadLibrary("Kernel32.dll")
consoleHandle = kernel.GetConsoleWindow()
print(f"Console HWND : {consoleHandle}")
instanceHandle: ctypes.wintypes.HINSTANCE = windows.GetWindowLongA(consoleHandle, c_int(-6))
print(f"Console HINSTANCE : {instanceHandle}")
print(f"LAST FUNCTION ERROR : {kernel.GetLastError()}")
OUTPUT :
Console HWND : 198610
Console HINSTANCE : 0
LAST FUNCTION ERROR : 1413
now error 1413 is ERROR_INVALID_INDEX (based on System error codes) which is probably caused cause i passed c_int(-6) as the int nIndex argument which must represent the GWL_HINSTANCE macro defined in windows.h (based on this windows doc) but it doesnt work.
What should i do to fix it and why doesnt it work?
Console Windows are not the same as GUI Windows. GetActiveWindow() is what you want, and needs to be run for a GUI Python IDE, not a console window.
Assuming 64-bit Windows and Python, you also need GetWindowLongPtrA() (or W) to retrieve handles.
To ensure you retrieve the last error cause by a Windows API failure using ctypes, use the use_last_error=True parameter and call ctypes.get_last_error() to retrieve it. The error code is only valid after the specific Windows call that failed, ctypes will capture that with this method. Otherwise, you don't know what Windows APIs might be called by the Python implementation between the ctypes API call to the function that failed and the ctypes GetLastError() API call. I got 1400 (invalid window handle) when calling GetWindowLongPtrA() with a console handle.
It's also good practice to fully specify .argtypes and .restype, esp. for 64-bit Windows as the default return type is c_int (32-bit) and handles are 64-bit in that architecture.
Below works for a 64-bit Python IDE:
import ctypes as ct
from ctypes import wintypes as w
GWLP_HINSTANCE = -6
# LONG_PTR isn't defined by wintypes.
# LPARAM is long on 32-bit, longlong on 64-bit,
# which matches LONG_PTR type.
LONG_PTR = w.LPARAM
u32 = ct.WinDLL('user32', use_last_error=True)
GetWindowLongPtrA = u32.GetWindowLongPtrA
GetWindowLongPtrA.argtypes = w.HWND, ct.c_int
GetWindowLongPtrA.restype = LONG_PTR
GetActiveWindow = u32.GetActiveWindow
GetActiveWindow.argtypes = ()
GetActiveWindow.restype = w.HWND
hwnd = GetActiveWindow()
print(f'hwnd = {hwnd:#x}')
instanceHandle = GetWindowLongPtrA(hwnd, GWLP_HINSTANCE)
print(f'instanceHandle = {instanceHandle:#x}')
Output:
hwnd = 0xd044c
instanceHandle = 0x7ff700250000

Interacting with AURA_SDK.dll through python using ctypes

I'm trying to control my ASUS ROG Flare keyboard LED colors using python.
I downloaded the Aura Software Developer Kit from the ASUS website.
link here: https://www.asus.com/campaign/aura/us/SDK.php
inside the kit there is a menu guide and a dll file called AURA_SDK.dll. The guide says that with the mentioned dll the keyboard can be controlled.
I'm using the ctypes python package and succeeded in loading the package, but when I'm calling the first function to obtain control on the keyboard the program fails because I don't fully understand the argument the function needs to run.
Documentation from the guide:
Code I am trying:
import ctypes
path_dll = 'AURA_SDK.dll'
dll = ctypes.cdll.LoadLibrary(path_dll)
res = dll.CreateClaymoreKeyboard() # fails here
Any ideas on how to create this argument?
Thanks in advance.
This should do it. A good habit to get into is always define .argtypes and .restype for the functions you call. This will make sure parameters are converted correctly between Python and C types, and provide better error checking to help catch doing something incorrectly.
There are also many pre-defined Windows types in wintypes so you don't have to guess what ctype-type to use for a parameter.
Also note that WINAPI is defined as __stdcall calling convention and should use WinDLL instead of CDLL for loading the DLL. On 64-bit systems there is no difference between standard C calling convention (__cdecl) and __stdcall, but it will matter if you are using 32-bit Python or desire portability to 32-bit Python.
import ctypes as ct
from ctypes import wintypes as w
dll = ct.WinDLL('./AURA_SDK') # Use WinDLL for WINAPI calls.
dll.CreateClaymoreKeyboard.argtypes = ct.POINTER(ct.c_void_p), # tuple of arguments
dll.CreateClaymoreKeyboard.restype = w.DWORD
handle = ct.c_void_p() # Make an instance to pass by reference and receive the handle.
res = dll.CreateClaymoreKeyboard(ct.byref(handle))
# res is non-zero on success

Calling C# DLL from Python with "out" parameter

I have a C# piece that generates a DLL which I'm trying to invoke from Python. The C# prototype is as follow:
public Main(NationalInstruments.TestStand.Interop.API.SequenceContext sequenceContext){
public void ShowFullOptions(out bool errorOccurred, out int errorCode, out String errorMsg) {
[...]
}
}
I followed this post which explains how to achieve to pass "out" parameters from python, without success since clr.Reference does not exist and throw me the error:
AttributeError: module 'clr' has no attribute 'Reference'
I have pythonnet installed, version 2.3.
My python code:
import clr
dll_path = R"thatDllPath.dll"
clr.AddReference(dll_path)
from Flamenco_Calibration_Interface import Main
import System
my_instance = Main(None)
v1 = clr.Reference[System.Boolean](False)
v2 = clr.Reference[System.Int64](1)
v3 = clr.Reference[System.String]("")
a = my_instance.ShowFullOptions(v1,v2,v3)
I have checked that the DLL path is good and I am able to successfully call the C# method if I overload "ShowFullOptions" with a version without any arguments.
The main problem resides in that I have the "out" keyword in the C# method prototype.
How do you properly generate argument in python so they are accepted as "out" within C# ?
Any help much appreciated.

Error in using C SDK in python

I'm trying to use a SDK with python.
I have multiple dll files in the SPK.
My script:
import ctypes
import os
malib = ctypes.WinDLL(os.path.join('D:\Downloads\Aura API\sdk\AURA_SDK.dll'))
print(malib.GetClaymoreKeyboardLedCount(1)) #function in the dll
I get the error :
WindowsError: exception: access violation reading 0x00000005
I can use some of the functions normaly but for others I get this issue. Also there are different dll's in the SDK and I think the problem could come from the communication between these dll (I only open one of these dll in the script) also because function not working seem to be using the other dll or/and communication with the computer.
Thanks if you got advices
You haven't set the argtypes and restype for the functions you're calling.
This means that, instead of knowing what C types to convert your arguments to, ctypes has to guess based on the Python types you pass it. If it guesses wrong, you will either pass garbage, or, worse, corrupt the stack, leading to an access violation.
For example, imagine this C function:
void func(int64_t n, char *s);
If you do this:
lib = # however you load the library
lib.func(2, 'abc')
… then ctypes, it will convert that 2 to a 32-bit int, not a 64-bit one. If you're using a 32-bit Python and DLL, that means n will get the 2 and the pointer to 'abc' crammed into one meaningless number, and s will be an uninitialized pointer to some arbitrary location in memory that, if your lucky, won't be mapped to anything and will raise an access violation.
But if you first do this:
lib = # however you load the library
lib.func.argtypes = [ctypes.c_int64, ctypes.c_char_p]
lib.func.restype = None
lib.func(2, 'abc')
… then ctypes will convert the 2 to a 64-bit int, so n will get 2 and s will get 'abc' and everyone will be happy.

Using NI-VISA with Python: error code -1073807343 in viFindRsrc

I'm working in Python and have installed the lastest version of NI-VISA. I'm using the ctypes package in order to load the visa32.dll installed with NI-VISA.
I used both the NI-VISA documentation, as well as the following page as a base for my code.
I already know of the pyVisa wrapper and using their find_resources function does return the instruments connected. However, I do not wish to use this wrapper and would rather use the VISA DLL file directly.
I've also been browsing the pyVisa code to see how they do it, and tried to learn from it, but it seems I still don't get it.
Here is my current unfinished code:
import sys
from ctypes import *
visa = windll.LoadLibrary("visa32.dll")
resourceManagerHandle = c_int(0)
visa.viOpenDefaultRM(byref(resourceManagerHandle))
instr_list = c_ulong(0)
nb = c_ulong(0)
desc = create_string_buffer(128)
print(visa.viFindRsrc(resourceManagerHandle,
"?*INSTR",
byref(instr_list),
byref(nb),
byref(desc)))
# The previous line prints: -1073807343
print(instr_list)
# The previous line prints: c_ulong(0)
I've been trying to find the meaning of the error code -1073807343 (4000FFEF in hex) on the Internet and though I have found some forum threads about it on the National Instruments forums, I still don't quite understand what it means.
I would welcome any advice, guidance or link towards relevant information.
The literal "?*INSTR" creates an str object, which is Unicode in Python 3. ctypes converts a unicode string to a wchar_t *. On Windows, wchar_t is 2 bytes, so ctypes passes a pointer to the UTF-16 encoded buffer "?\x00*\x00I\x00N\x00S\x00T\x00R\x00". Bear in mind that the function expects a null-terminated string.
To pass a byte string instead, prefix the literal with b to create a bytes object, i.e. use b"?*INSTR".
To prevent a mistake like this from passing unnoticed, define the function pointer's argtypes. ctypes will raise an ArgumentError if a unicode str argument is passed for a parameter that's defined to be c_char_p.
from ctypes import *
visa = WinDLL("visa32.dll") # or windll.visa32
def vi_status_check(vi_status, func, args):
if vi_status < 0:
raise RuntimeError(hex(vi_status + 2**32))
return args
visa.viOpenDefaultRM.errcheck = vi_status_check
visa.viOpenDefaultRM.argtypes = [POINTER(c_uint32)]
visa.viFindRsrc.errcheck = vi_status_check
visa.viFindRsrc.argtypes = [c_uint32, # sesn
c_char_p, # expr
POINTER(c_uint32), # findList
POINTER(c_uint32), # retcnt
c_char_p] # desc
rm_session = c_uint32()
visa.viOpenDefaultRM(byref(rm_session))
expr = b"?*INSTR"
instr_list = c_uint32()
nb = c_uint32()
desc = create_string_buffer(256)
visa.viFindRsrc(rm_session,
expr,
byref(instr_list),
byref(nb),
desc)
The NI-VISA Programmer Reference Manual says on page 5-30 that instrDesc should be at least 256 bytes.

Categories