• 正文
    • 一、需求描述
    • 二、創(chuàng)建工程及其目錄
    • ?三、創(chuàng)建文件
    • 四、環(huán)境配置
    • 五、運行代碼
    • 六、將原功能改寫成接口,供python調(diào)用
    • ?七、豐富接口
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

C++開發(fā)實戰(zhàn)(四):對提供接口的C/C++進(jìn)行二次開發(fā)

01/08 16:10
1886
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

一、需求描述

我有一個USB5538的庫和頭文件,并通過頭文件提供了接口,我想把它更改一下,編譯成python可調(diào)用的模塊。

二、創(chuàng)建工程及其目錄

1、創(chuàng)建空項目

2、創(chuàng)建目錄

?三、創(chuàng)建文件

1、復(fù)制文件并添加

2、添加新文件并寫入

四、環(huán)境配置

1、環(huán)境異常情況

2、配置環(huán)境以消除異常

五、運行代碼

1、二次封裝代碼

定義一個接口對象,調(diào)用之前的接口,并將方法寫入該接口對象即可。

#include <iostream>
using namespace std;
#include "usbpylib.h"
// usbpylib.cpp : 只包括標(biāo)準(zhǔn)包含文件的源文件
// Sys.pch 將作為預(yù)編譯頭
// usbpylib.obj 將包含預(yù)編譯類型信息

class AutoTest {
    //private:
public:
    //USB5538數(shù)據(jù)采集器
    HANDLE createUSB5538();
    void releaseUSB5538(HANDLE hDevice);
    void resetUSB5538(HANDLE hDevice);  //復(fù)位,相當(dāng)于與PC重連,等同于重新插上USB
    void getUSB5538DI_All(HANDLE hDevice, BYTE bDISts[16]);  //bDISts[16]為output參數(shù)
    void setUSB5538DO_All(HANDLE hDevice, BYTE bDOSts[16]);  //bDOSts[16]為input參數(shù)
    int getUSB5538DI_One(HANDLE hDevice, int iDI);
    void setUSB5538DO_One(HANDLE hDevice, int iDO, int value);
};

// TODO: 在 STDAFX.H 中
// 引用任何所需的附加頭文件,而不是在此文件中引用

HANDLE AutoTest::createUSB5538()
{
    return USB5538_CreateDevice(0);
}

void AutoTest::releaseUSB5538(HANDLE hDevice)
{
    if (hDevice == INVALID_HANDLE_VALUE)
    {
        return;
    }
    USB5538_ReleaseDevice(hDevice);
}

void AutoTest::resetUSB5538(HANDLE hDevice)
{
    if (hDevice == INVALID_HANDLE_VALUE)
    {
        return;
    }
    USB5538_ResetDevice(hDevice);
}

void AutoTest::getUSB5538DI_All(HANDLE hDevice, BYTE bDISts[])
{
    if (hDevice == INVALID_HANDLE_VALUE)
    {
        return;
    }
    USB5538_GetDeviceDI(hDevice, bDISts);
}

void AutoTest::setUSB5538DO_All(HANDLE hDevice, BYTE bDOSts[])
{
    if (hDevice == INVALID_HANDLE_VALUE)
    {
        return;
    }
    USB5538_SetDeviceDO(hDevice, bDOSts);
}

int AutoTest::getUSB5538DI_One(HANDLE hDevice, int iDI)
{
    if (hDevice == INVALID_HANDLE_VALUE)
    {
        return -1;
    }
    BYTE bDISts[16];
    USB5538_GetDeviceDI(hDevice, bDISts);
    return bDISts[iDI];
}

void AutoTest::setUSB5538DO_One(HANDLE hDevice, int iDO, int value)
{
    if (hDevice == INVALID_HANDLE_VALUE)
    {
        return;
    }
    BYTE bDOSts[16];
    USB5538_RetDeviceDO(hDevice, bDOSts);//回讀輸出狀態(tài)
    bDOSts[iDO] = value;
    USB5538_SetDeviceDO(hDevice, bDOSts);
}

int main()
{
    HANDLE obj1;
    BYTE bd[16] = { 0,0,0,0,0,1,1,1, 0,0,0,0,0,1,1,1 };
    AutoTest AutoTest1;
    //cout << "Hello World";
    obj1 = AutoTest1.createUSB5538();
    cout << "句柄是n" << obj1 << "n";
    AutoTest1.getUSB5538DI_All(obj1, bd);
    AutoTest1.resetUSB5538(obj1);
    AutoTest1.releaseUSB5538(obj1);
    //cout << "Hello World";
    HANDLE hDevice = AutoTest1.createUSB5538();
    if (hDevice == INVALID_HANDLE_VALUE)
    {
        cout << "create error...." << "n";
    }
    BYTE bDOSts[16];
    BYTE bDISts[16];
    bDOSts[0] = 0;
    bDOSts[1] = 1;
    bDOSts[2] = 0;
    bDOSts[3] = 1;
    bDOSts[4] = 0;
    bDOSts[5] = 1;
    bDOSts[6] = 0;
    bDOSts[7] = 1;
    bDOSts[8] = 0;
    bDOSts[9] = 1;
    bDOSts[10] = 0;
    bDOSts[11] = 1;
    bDOSts[12] = 0;
    bDOSts[13] = 1;
    bDOSts[14] = 0;
    bDOSts[15] = 1;
    AutoTest1.setUSB5538DO_All(hDevice, bDOSts);
    AutoTest1.getUSB5538DI_All(hDevice, bDISts);
    cout << "bDISts是n" << bDISts << "n";
}

2、如圖,運行正常,說明對原接口的二次封裝是有效的

六、將原功能改寫成接口,供python調(diào)用

1、基于上一篇文章,創(chuàng)建新文件USB5538.cpp編寫如下:

#define PY_SSIZE_T_CLEAN  // 建議在包含Python.h之前總是定義PY_SSIZE_T_CLEAN。
#include <Python.h>  // 打包成python擴(kuò)展所需要的頭文件

#include <iostream>
using namespace std;

//#ifndef _USBPYLIB_H_ // 避免頭文件被多次編譯
//#define _USBPYLIB_H_
#include "../include/usbpylib.h"
//#endif


// 函數(shù)的三種實現(xiàn)方式,C函數(shù)通常是通過將Python模塊和函數(shù)名組合在一起命名的,如模塊是Combinations(也是.cpp名稱),函數(shù)是uniqueCombinations,組成了一個函數(shù)名
static PyObject* 
USB5538_get(PyObject* self)  // 定義功能有三種方式,詳細(xì)文檔(舊文檔)請查閱https://www.tutorialspoint.com/python/python_further_extensions.htm
{   
    //PyLongObject one = USB5538_CreateDevice(0);
    //PyAddrPair one = USB5538_CreateDevice(0);
    //PyAnySet_Check one = USB5538_CreateDevice(0);
    //PyAnySet_CheckExact one = USB5538_CreateDevice(0);
    //PyAPI_DATA one = USB5538_CreateDevice(0);
    //PyAPI_FUNC one = USB5538_CreateDevice(0);
    //PyArena_AddPyObject one = USB5538_CreateDevice(0);
    //PyASCIIObject one = USB5538_CreateDevice(0);
    //PyBaseObject_Type one = USB5538_CreateDevice(0);
    //PyByteArrayObject one = USB5538_CreateDevice(0);
    //PyBytes_FromObject one = USB5538_CreateDevice(0);
    //PyBytesObject one = USB5538_CreateDevice(0);
    //PyObject_AsCharBuffer one = USB5538_CreateDevice(0);
    //PyObject_AsReadBuffer one = USB5538_CreateDevice(0);
    //PyObject_CallObject one = USB5538_CreateDevice(0);
    PyObject_Length one = USB5538_CreateDevice(0);
    //CompareObjectHandles one = USB5538_CreateDevice(0);
    //PyOS_sighandler_t one = USB5538_CreateDevice(0);
    //PyObject one = USB5538_CreateDevice(0);

    HANDLE hDevice = USB5538_CreateDevice(0);  // 獲取句柄

    cout << hDevice;

    BYTE bd[16] = { 0,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1 };

    //if (hDevice == INVALID_HANDLE_VALUE)
    //{
    //    return;
    //}
    BOOL a = USB5538_GetDeviceDI(hDevice, bd);  // 獲取設(shè)備DI狀態(tài)
    USB5538_ReleaseDevice(hDevice);  // 釋放句柄
    return Py_BuildValue("s", "uniqueCombinations() return value (is of type 'string')");
    ;
    //if (a == true)
    //{
    //    return NULL;
    //}
    //else 
    //{ 
    //    return 0;
    //};
};

/*
函數(shù)的三種實現(xiàn)方式例子:
static PyObject *MyFunction( PyObject *self, PyObject *args );  // METH_VARARGS
static PyObject *MyFunctionWithKeywords(PyObject *self,PyObject *args,PyObject *kw);  // METH_KEYWORDS
static PyObject *MyFunctionWithNoArgs( PyObject *self );  // METH_NOARGS
*/

static char get_docs[] = "獲取設(shè)備的相關(guān)信息n";  // 隨意定義的文檔字符串描述

// 方法映射表,方法表是一個簡單的PyMethodDef結(jié)構(gòu)數(shù)組
static PyMethodDef module_methods[] = {
    {"get", (PyCFunction)USB5538_get, METH_NOARGS, get_docs},
    { NULL, NULL, 0, NULL }
    // 格式解釋:{ml_name,ml_meth,ml_flags,ml_doc}
    // ml_name:這是Python解釋器在Python程序中使用的函數(shù)名。
    // ml_meth:這必須是函數(shù)名。
    // ml_flags:函數(shù)的三種實現(xiàn)方式,上述例子中已經(jīng)標(biāo)明對應(yīng)字段選擇
    // ml_doc:可以為空值,四個選項對應(yīng)的空值分別為:{ NULL, NULL, 0, NULL }
};

// 模塊后面加module,比較規(guī)范。這個結(jié)構(gòu)必須在模塊的初始化函數(shù)中傳遞給解釋器。初始化函數(shù)必須命名為PyInit_name(),其中name是模塊的名稱,并且應(yīng)該是模塊文件中定義的唯一非靜態(tài)項
static struct PyModuleDef USB5538module =
{
    PyModuleDef_HEAD_INIT,
    "Combinations",  /* 模塊名稱 */
    "usage: Combinations.uniqueCombinations(lstSortableItems, comboSize)n", /* 模塊文檔*/
    -1, /* 模塊的每個解釋器狀態(tài)的大小,如果模塊在全局變量中保持狀態(tài),則為-1。*/
    module_methods  /* 方法映射表 , 即需要引用定義好的引射表*/
};

// 初始化函數(shù),之前的初始化方法 PyMODINIT_FUNC initModule() 已棄用,新文檔見 https://docs.python.org/3/extending/extending.html
PyMODINIT_FUNC PyInit_USB5538(void)
{
    return PyModule_Create(&USB5538module);  // 它返回一個模塊對象,并根據(jù)模塊定義中的表(PyMethodDef結(jié)構(gòu)的數(shù)組)將內(nèi)置函數(shù)對象插入到新創(chuàng)建的模塊中。
}

2、嘗試進(jìn)行編譯

3、嘗試將該文件打包成python庫

新建setup.py文件寫入以下內(nèi)容

from distutils.core import setup, Extension
setup(name='USB5538', version='0.1', ext_modules=[Extension('USB5538', [r'D:MinGWprojectsUSB5538ForPythonsourceUSB5538.cpp' ])])

打開cmd窗口執(zhí)行setup.py文件(要進(jìn)入該文件目錄下執(zhí)行)

python setup.py build
python setup.py install --record files.txt

以及調(diào)用其接口,均能成功

?七、豐富接口

1、將該接口改為傳參對象

#define PY_SSIZE_T_CLEAN  // 建議在包含Python.h之前總是定義PY_SSIZE_T_CLEAN。
#include <Python.h>  // 打包成python擴(kuò)展所需要的頭文件

#include <stdio.h>

#include <iostream>
using namespace std;

//#ifndef _USBPYLIB_H_ // 避免頭文件被多次編譯
//#define _USBPYLIB_H_
#include "../include/usbpylib.h"
//#endif


// 函數(shù)的三種實現(xiàn)方式,C函數(shù)通常是通過將Python模塊和函數(shù)名組合在一起命名的,如模塊是Combinations(也是.cpp名稱),函數(shù)是uniqueCombinations,組成了一個函數(shù)名
static PyObject* 
USB5538_set(PyObject* self, PyObject* args)  // 定義功能有三種方式,詳細(xì)文檔(舊文檔)請查閱https://www.tutorialspoint.com/python/python_further_extensions.htm
{   
    //PyLongObject one = USB5538_CreateDevice(0);
    //PyAddrPair one = USB5538_CreateDevice(0);
    //PyAnySet_Check one = USB5538_CreateDevice(0);
    //PyAnySet_CheckExact one = USB5538_CreateDevice(0);
    //PyAPI_DATA one = USB5538_CreateDevice(0);
    //PyAPI_FUNC one = USB5538_CreateDevice(0);
    //PyArena_AddPyObject one = USB5538_CreateDevice(0);
    //PyASCIIObject one = USB5538_CreateDevice(0);
    //PyBaseObject_Type one = USB5538_CreateDevice(0);
    //PyByteArrayObject one = USB5538_CreateDevice(0);
    //PyBytes_FromObject one = USB5538_CreateDevice(0);
    //PyBytesObject one = USB5538_CreateDevice(0);
    //PyObject_AsCharBuffer one = USB5538_CreateDevice(0);
    //PyObject_AsReadBuffer one = USB5538_CreateDevice(0);
    //PyObject_CallObject one = USB5538_CreateDevice(0);
    PyObject_Length one = USB5538_CreateDevice(0);
    //CompareObjectHandles one = USB5538_CreateDevice(0);
    //PyOS_sighandler_t one = USB5538_CreateDevice(0);
    //PyObject one = USB5538_CreateDevice(0);

    int a1;
    int a2;
    int a3;
    int a4;
    int a5;
    int a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16;
    if (!PyArg_ParseTuple(args, "iiiiiiiiiiiiiiii", &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16))
    {
        //return Py_BuildValue("s", "參數(shù)輸入有誤,請傳遞全數(shù)字的列表!");
        return Py_BuildValue("s", "error!");
    }
    //return Py_BuildValue("(iiiiiiiiiiiiiiiii)", a1 + a1, a1 - a2, a1+a3);

    HANDLE hDevice = USB5538_CreateDevice(0);  // 獲取句柄

    //cout << hDevice << "n";

    BYTE bd[16] = { a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16 };
    //BYTE bd[16] = { 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1 };  // 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

    USB5538_SetDeviceDO(hDevice, bd);

    //BOOL DIstatus = USB5538_GetDeviceDI(hDevice, bd);  // 獲取設(shè)備DI狀態(tài)

    //cout << DIstatus << "n";

    USB5538_ReleaseDevice(hDevice);  // 釋放句柄
    //return Py_BuildValue("s", "恭喜你,在窗口打印設(shè)備句柄成功!");
    return Py_BuildValue("s", "set success!");
};

/*
函數(shù)的三種實現(xiàn)方式例子:
static PyObject *MyFunction( PyObject *self, PyObject *args );  // METH_VARARGS
static PyObject *MyFunctionWithKeywords(PyObject *self,PyObject *args,PyObject *kw);  // METH_KEYWORDS
static PyObject *MyFunctionWithNoArgs( PyObject *self );  // METH_NOARGS
*/

//static char get_docs[] = "獲取設(shè)備的相關(guān)信息n";  // 隨意定義的文檔字符串描述
static char get_docs[] = "get info of devicen";  // 隨意定義的文檔字符串描述

// 方法映射表,方法表是一個簡單的PyMethodDef結(jié)構(gòu)數(shù)組
static PyMethodDef module_methods[] = {
    {"set", (PyCFunction)USB5538_set, METH_VARARGS, get_docs},
    { NULL, NULL, 0, NULL }
    // 格式解釋:{ml_name,ml_meth,ml_flags,ml_doc}
    // ml_name:這是Python解釋器在Python程序中使用的函數(shù)名。
    // ml_meth:這必須是函數(shù)名。
    // ml_flags:函數(shù)的三種實現(xiàn)方式,上述例子中已經(jīng)標(biāo)明對應(yīng)字段選擇
    // ml_doc:可以為空值,四個選項對應(yīng)的空值分別為:{ NULL, NULL, 0, NULL }
};

// 模塊后面加module,比較規(guī)范。這個結(jié)構(gòu)必須在模塊的初始化函數(shù)中傳遞給解釋器。初始化函數(shù)必須命名為PyInit_name(),其中name是模塊的名稱,并且應(yīng)該是模塊文件中定義的唯一非靜態(tài)項
static struct PyModuleDef USB5538module =
{
    PyModuleDef_HEAD_INIT,
    "USB5538",  /* 模塊名稱 這個只是python調(diào)用__name__時展示,即使寫錯也不會有影響*/
    //"USB5538的python接口對象,提供豐富的接口,用于操作USB5538設(shè)備n", /* 模塊文檔*/
    "USB5538 of python interfacen", /* 模塊文檔*/
    -1, /* 模塊的每個解釋器狀態(tài)的大小,如果模塊在全局變量中保持狀態(tài),則為-1。*/
    module_methods  /* 方法映射表 , 即需要引用定義好的引射表*/
};

// 初始化函數(shù),之前的初始化方法 PyMODINIT_FUNC initModule() 已棄用,新文檔見 https://docs.python.org/3/extending/extending.html
PyMODINIT_FUNC PyInit_USB5538(void)
{
    return PyModule_Create(&USB5538module);  // 它返回一個模塊對象,并根據(jù)模塊定義中的表(PyMethodDef結(jié)構(gòu)的數(shù)組)將內(nèi)置函數(shù)對象插入到新創(chuàng)建的模塊中。
}

2、驗證

如圖,驗證成功!

相關(guān)推薦