upm icon indicating copy to clipboard operation
upm copied to clipboard

add a new driver with python bindings for upm/mraa

Open mgiaco opened this issue 7 years ago • 11 comments

Hi,

For a project I have to add a custom driver. So the C code is already available. There is also a interface file for the spi_init, spi_read, and so on available. Is there a good sample driver where I can get a good recipe of porting?

thx

mgiaco avatar Jun 22 '17 19:06 mgiaco

Hi @mgiaco, the best examples for porting are other drivers that already exist in the UPM library. Since you already have the implementation, sounds like all you have to do is plug the MRAA SPI API function calls to the interface.

You can learn more about MRAA's SPI C API here. We also have a document on porting here.

Example UPM SPI drivers: apa102, adis16448, max31855, st7735, rf22, rsc, lpd8806.

Propanu avatar Jun 30 '17 23:06 Propanu

@Propanu Many thanks. My problem is let´s say I have a driver in C which works very well. So there I have extracted the spi stuf so the driver is plain ansi C now. I would be nice if I can use this C driver add some mraa specifiy spi stuf and add the python wrapper files for that. But I always find examples with cpp therfore I taught it is for C++ only. I am wrong here?

mgiaco avatar Jul 02 '17 13:07 mgiaco

You're right, SWIG will need a C++ class to generate bindings for the other languages.

In UPM, only about half of the drivers have both C/C++ implementations, the others are C++ only, and none are C only, because we want the bindings generated too. Thus use one of the examples that has both (e.g. rsc).

The way this usually works, if you want to provide a C implementation and have UPM generate python/node/Java bindings for you, you'll also have to wrap a C++ class around that C implementation. In certain cases, the C++ class can be header only since all functions map to corresponding C calls.

Propanu avatar Jul 07 '17 19:07 Propanu

@Propanu many thanks that was what i found out. For developing it is really bad that building took so much time. So therefore I delete almost every driver in the src on my fork. Do you know a better way?

mgiaco avatar Jul 11 '17 20:07 mgiaco

Yes, after you run cmake you can run make and make install from the folder of the one library you are trying to build (e.g. src/sensortemplate, there's a short paragraph on this in the build documentation towards the end). This will not install dependencies though. Alternatively, you can list only the directories you want to build with a variable while running cmake: -DMODULE_LIST=dirname and then proceed as usual with make.

Propanu avatar Jul 11 '17 22:07 Propanu

Hi,

I tried to work on my driver for a ad7124 here https://github.com/mgiaco/upm/tree/only_ad7124/src/ad7124 So it works now as expected but I have a question concerning the C defines i use in ad7124.hpp I would like to get access to some defines from the header like this one

#define AD7124_ADC_CTRL_REG_REF_EN         (1 << 8)

Do I really need to move all the defines in the public section or outside the Class definition?

mgiaco avatar Jul 28 '17 13:07 mgiaco

This is really up to you, but the way it usually works:

  • When you have #define constants only used internally and don't want users to have access to the values, define them in the source (.c/.cxx).
  • To allow access from all languages to a #define constant, place it in the header (.h/.hpp). Or even better, in a separate header file that gets included by the main library header.
  • If you go with an enum instead of #define then you'll have to place it into the public/private section of your class based on what I described above.

Propanu avatar Aug 08 '17 22:08 Propanu

@Propanu many thanks. I have moved the defines. Is there a way how I can tell swig to generate functions for the Function-like Macros?

Example C:

#define AD7124_CFG_REG_BURNOUT(x)  (((x) & 0x3) << 9)

To python:

AD7124_CFG_REG_BURNOUT = lambda x: ((x & 0x3) << 9)

or

def AD7124_CFG_REG_BURNOUT(x):
    return (x & 0x3) << 9

mgiaco avatar Aug 28 '17 18:08 mgiaco

Also some other problem is how can I map this pointer to something python is able to handle?

	/*! Reads the conversion result from the device. */
	int32_t ReadData(int32_t* pData);

I tried this but dose not work:

// Include doxygen-generated documentation
%include "pyupm_doxy2swig.i"
%module pyupm_ad7124
%include "../upm.i"
%include "cpointer.i"

%pointer_functions(int, intPointer);

%{
    #include "ad7124.hpp"
%}

%include "ad7124.hpp"

many thanks

mgiaco avatar Aug 28 '17 21:08 mgiaco

Hi @mgiaco, try using array classes instead:

%include "stdint.i"
%include "carrays.i"
%array_class(int32_t, int32Array);

We have some decent examples on how to use them under upm/src, see the carrays_<type>.i files.

For function macros I believe you can just declare them as normal functions in the swig interface. E.g:

  • C/C++ header:
    #define add_fun(x, y)     ((x) + (y))
    
  • Swig interface:
    %{
    #include "my_header.h"
    %}
    
    void add_fun(int, int);
    

Propanu avatar Sep 22 '17 19:09 Propanu

@Propanu okay many thanks - i will try this later.

mgiaco avatar Sep 25 '17 07:09 mgiaco