結構體示例:
這里是 C 代碼的部分,主要是結構體的聲明和回調函數定義。
// 新版本定義
typedef enum {
DevCard,
DevLocator,
DevReader
} DevType;
typedef enum {
MsgLocate, // 定位信號
MsgCut, // 剪斷信號
MsgHeartBeat, // 心跳信號
MsgCall, // 呼叫信號
MsgShake, // 震動信號
MsgLeave, // 離開信號
MsgOffAlarm, // 報警燈關閉信號
MsgCheckPower, // 電量檢測信號
MsgHeartRate, // 心率信號
MsgExtra, // 補發信號
MsgNoPower, // 沒電信號
MsgReset, // 重置信號
MsgBoundary, // 跨界信號
// 此消息會跟隨着MsgLocate消息出現
MsgPower,
// 當checkOffline設置為1時有效。如果在offlineTime時間內沒有收到此設備的信號,則發出離線信號
MsgOffline,
MsgLast
} MsgType;
// 由於消息類型的不同,不是所有的值都有意義
typedef struct {
MsgType type;
DevType device; // 硬件類型
int32_t cardID; // 標簽/腕帶ID,當DevType為DevCard時有意義
int32_t readerID; // 閱讀器ID,總是有意義
int32_t locatorID; // 大於0時有意義,表示定位器ID
int32_t readerRSSI; // 閱讀器信號強度,由於硬件版本的差異,此值要么全有意義,要么全沒意義(總是0)
int32_t locatorRssiX; // 當MsgType為[MsgLocate, MsgExtra]時,此值有意義,表示定位器的信號強度
int32_t locatorRssiY; // 定位器的信號強度
uint8_t isCut; // 如果此值為1,表示硬件被破壞。因為有專門的MsgCut消息,可以忽視此值
uint8_t isShake; // 如果此值為1,表示硬件處於震動狀態。僅當MsgType為MsgShake是有意義,1表示震動,0表示靜止
uint8_t isLowpower; // 硬件是否低電。硬件為標簽時有意義,因為有追加的MsgPower消息,可以在MsgType為MsgPower時使用此值
int32_t heartRate; // 心率,當MsgType為[MsgHeartBeat, MsgHeartRate]之一時有意義
int32_t power; // 電量,當MsgType為[MsgHeartBeat, MsgReset, MsgCheckPower]之一時有意義
int64_t time; // 消息時間戳
int version; // 硬件版本號,DevType為DevCard時有意義
} DevMsg;
typedef void(*MsgCallback)(DevMsg msg, void *ctx);
extern "C" {
DEVSDK_API int ccrfidDevSdkStartWork(MsgCallback fun, void *ctx);
}
# coding=UTF-8
from ctypes import *
import time
import _ctypes
# 定義回調函數參數的結構體
class DevMsg(Structure):
_fields_ = [("type", c_long),
("device", c_long),
("cardID", c_long),
("readerID", c_long),
("locatorID", c_long),
("readerRSSI", c_long),
("locatorRssiX", c_long),
("locatorRssiY", c_long),
("isCut", c_char),
("isShake", c_char),
("isLowpower", c_char),
("heartRate", c_long),
("power", c_long),
("time", c_longlong),
("version", c_long)]
注意一下 _fields_
的內容:這里就是對 C 數據類型的轉換。左邊是 C 的結構成員名稱,右邊則是在 python 中聲明一下各個成員的類型。其他的一些類型請參見官方文檔。
此外還需要注意一下類似於 c_int
, c_void_p
等等的定義是在 ctypes
中的,如果是用import ctypes
的方式包含 ctypes 模塊,則應該寫成 ctypes.c_long
, ctypes.c_longlong
,ctypes.c_char
。
第三個要注意的是:這個類必須定義為 ctypes.Structure 的子類,否則在進行后續的函數傳遞時,ctypes
由於不知道如何進行數據類型的對應,會拋出異常
回調函數示例:
# 定義功能類與方法
class DemoDll:
def __init__(self):
self.dll = cdll.LoadLibrary('ccrfidDevSDK.dll')
return
def ccrfidDevSdkStartWork(self, callback, p):
return self.dll.ccrfidDevSdkStartWork(callback, p)
# ctypes通過 CFUNCTYPE 支持回調函數,定義返回值與參數,第一個參數表示返回值,void為None
CALLBACK = CFUNCTYPE(None, POINTER(DevMsg))
最后的 CALLBACK
通過 ctypes
定義了一個回調函數類型,這個在后面的調用中需要使用
在 CFUNCTYPE
后面的第一個參數為 None
,這表示回調函數的返回值類型為 void
完整功能示例:
# coding=UTF-8
from ctypes import *
import time
import _ctypes
# 定義回調函數參數的結構體
class DevMsg(Structure):
_fields_ = [("type", c_long),
("device", c_long),
("cardID", c_long),
("readerID", c_long),
("locatorID", c_long),
("readerRSSI", c_long),
("locatorRssiX", c_long),
("locatorRssiY", c_long),
("isCut", c_char),
("isShake", c_char),
("isLowpower", c_char),
("heartRate", c_long),
("power", c_long),
("time", c_longlong),
("version", c_long)]
# 定義功能類與方法
class DemoDll:
def __init__(self):
self.dll = cdll.LoadLibrary('ccrfidDevSDK.dll')
return
def ccrfidDevSdkStartWork(self, callback, p):
return self.dll.ccrfidDevSdkStartWork(callback, p)
# ctypes通過 CFUNCTYPE 支持回調函數,定義返回值與參數,第一個參數表示返回值,void為None,第二參數為回調函數的參數為結構體指針
CALLBACK = CFUNCTYPE(None, POINTER(DevMsg))
# 回調函數距離功能實現
def _callback(para):
# print(dir(para))
obj = para.__getitem__(0)
print(obj.type, obj.cardID, obj.readerID, obj.locatorID, obj.heartRate, obj.power, obj.time, obj.version)
# 定義回調函數
callBackFunc = CALLBACK(_callback)
# 實例化功能類
dll = DemoDll()
# 定義一個空的指針
null_ptr = POINTER(c_int)()
# 具體功能調用
c = dll.ccrfidDevSdkStartWork(callBackFunc, null_ptr)
print(c)
time.sleep(100000)
運行結果