我可以使用哪些方法将结构返回到Python Ctypes调用共享对象中的函数?

时间:2014-03-06 10:39:28

标签: python ctypes temperature

我有以下编译为共享对象的C文件。然后我通过python中的ctypes加载.so共享对象。我可以从ctypes调用函数,函数打印正确的温度和湿度,但是我似乎无法从主代码中获取结构。如何从C函数中获取结构,如何在python中从中检索字段。

#!/bin/python

from ctypes import *
class HMTEMP(Structure):
 _fields_ = [ ("temp", c_double) , ("humidity", c_double) ]
dhtlib = 'libdht4py.so'
hlibc = CDLL(dhtlib)
HMTEMP = hlibc.readDHT()
print HMTEMP.temp

#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <bcm2835.h>
#include <unistd.h>

#define MAXTIMINGS 100

struct DHStruct {    
 double temp;
 double humidity;
}  ;


struct DHStruct readDHT();


int bits[250], data[100];
int bitidx = 0;

struct DHStruct readDHT() {
  bcm2835_init() ; 
  int type = 11 ; 
  int pin = 4 ;
  struct DHStruct dhts;
  int counter = 0;
  int laststate = HIGH;
  int j=0;

  // Set GPIO pin to output
  bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);

  bcm2835_gpio_write(pin, HIGH);
  usleep(500000);  // 500 ms
  bcm2835_gpio_write(pin, LOW);
  usleep(20000);

  bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_INPT);

  data[0] = data[1] = data[2] = data[3] = data[4] = 0;

  // wait for pin to drop?
  while (bcm2835_gpio_lev(pin) == 1) {
    usleep(1);
  } //while

  // read data!
  for (int i=0; i< MAXTIMINGS; i++) {
    counter = 0;
    while ( bcm2835_gpio_lev(pin) == laststate) {
    counter++;
    //nanosleep(1);     // overclocking might change this?
        if (counter == 1000)
      break;
    }//while
    laststate = bcm2835_gpio_lev(pin);
    if (counter == 1000) break;
    bits[bitidx++] = counter;

    if ((i>3) && (i%2 == 0)) {
      // shove each bit into the storage bytes
      data[j/8] <<= 1;
      if (counter > 200)
        data[j/8] |= 1;
      j++;
    }//if
  } //for

    dhts.temp = data[2] ;
    dhts.humidity = data[0] ; 
    printf("Temp = %5.2f *C, Hum = %5.2f \%\n", dhts.temp , dhts.humidity );

  return dhts;
}//function

2 个答案:

答案 0 :(得分:1)

好的,我明白了 - 使用ctypes非常快。 python代码:

#!/bin/python
from ctypes import *
# define the struct and it's fields
class DHStruct(Structure):
    _fields_ = [("temp",c_double),("humidity",c_double)]
#reference the library
dhtlib = CDLL("libdht4py.so")
# set the return type as the object above 
dhtlib.readDHT.restype = POINTER(DHStruct)
# dereference the pointer using ctype's -contents and access the struct fields.
print ( dhtlib.readDHT().contents.temp ,   dhtlib.readDHT().contents.humidity  )

C代码:关键是将函数转换为返回指针。

    #define BCM2708_PERI_BASE        0x20000000
    #define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <dirent.h>
    #include <fcntl.h>
    #include <assert.h>
    #include <unistd.h>
    #include <sys/mman.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/time.h>
    #include <bcm2835.h>
    #include <unistd.h>

    #define MAXTIMINGS 100

//define the struct
    struct DHStruct {
     double temp;
     double humidity;
    }  ;


    struct DHStruct *readDHT(); // define the function prototype to return the pointer


    int bits[250], data[100];
    int bitidx = 0;

    //make sure to return a POINTER!!
    struct DHStruct *readDHT() {
      bcm2835_init() ;
      int type = 11 ;
      int pin = 4 ;
      struct DHStruct *dhts; // here is the key - define the pointer to the struct
      int counter = 0;
      int laststate = HIGH;
      int j=0;

      // Set GPIO pin to output
      bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);

      bcm2835_gpio_write(pin, HIGH);
      usleep(500000);  // 500 ms
      bcm2835_gpio_write(pin, LOW);
      usleep(20000);

      bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_INPT);

      data[0] = data[1] = data[2] = data[3] = data[4] = 0;

      // wait for pin to drop?
      while (bcm2835_gpio_lev(pin) == 1) {
        usleep(1);
      } //while

      // read data!
      for (int i=0; i< MAXTIMINGS; i++) {
        counter = 0;
        while ( bcm2835_gpio_lev(pin) == laststate) {
            counter++;
            //nanosleep(1);         // overclocking might change this?
            if (counter == 1000)
              break;
        }//while
        laststate = bcm2835_gpio_lev(pin);
        if (counter == 1000) break;
        bits[bitidx++] = counter;

        if ((i>3) && (i%2 == 0)) {
          // shove each bit into the storage bytes
          data[j/8] <<= 1;
          if (counter > 200)
            data[j/8] |= 1;
          j++;
        }//if
      } //for

            dhts->temp = data[2] ;
            dhts->humidity = data[0] ;
   //for debug  printf("Temp = %5.2f *C, Hum = %5.2f \%\n", dhts->temp , dhts->humidity );

      return dhts;
    }//function

答案 1 :(得分:0)

要结合使用C / C ++和Python,我建议使用Cython。 使用Cython,您可以将对象(例如numpy数组)传递给C / C ++,将其填入数据并将其恢复为python代码。


这是一个简短的例子:

C-skript:(c_example.c)

#include <stdlib.h>
#include <math.h>

void c_claculate(double *x, int N) {
  int i;
  for (i = 0; i<N;i++) {
    x[i]+=i*i;
  }
}

python-skript:(example.py)

from numpy import *
from example import *

data=zeros(10)
calculate(data)
print data

.pyx文件:(example.pyx)

import cython
import numpy
cimport numpy

# declare the interface to the C code
cdef extern void c_claculate(double *x, int N)

# Cython interface to C function
def calculate(numpy.ndarray[double, ndim=1, mode='c'] x not None):
    cdef int N = x.shape[0]
    c_claculate(&x[0],N)
    return x

和安装文件:(setup.py)

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
import numpy

setup(
    cmdclass = {'build_ext': build_ext},
    ext_modules = [
        Extension("example",
                  sources=["example.pyx", "c_example.c"],
                  include_dirs=[numpy.get_include()]
                  )
    ],
)

现在您可以通过运行

来编译skript
python setup.py build_ext -fi

然后执行python skript。


应该通过PI上的pip提供Cython。