Skip to content

Commit

Permalink
Merge pull request #863 from jpreiss/pybindings
Browse files Browse the repository at this point in the history
Python bindings draft
  • Loading branch information
krichardsson authored Nov 17, 2021
2 parents 46780e3 + e3e2ecd commit 3d02a53
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ tools/make/config.mk
cflie.*
version.c
tags
*cffirmware*.so
cffirmware.py

/cf2.*
/tag.*
Expand All @@ -21,6 +23,7 @@ current_platform.mk

/generated/**
**/__pycache__/**
**/*.pyc

docs/.jekyll-metadata
docs/.jekyll-cache
Expand Down
16 changes: 15 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -493,4 +493,18 @@ unit:
# The flag "-DUNITY_INCLUDE_DOUBLE" allows comparison of double values in Unity. See: https://stackoverflow.com/a/37790196
rake unit "DEFINES=$(CFLAGS) -DUNITY_INCLUDE_DOUBLE" "FILES=$(FILES)" "UNIT_TEST_STYLE=$(UNIT_TEST_STYLE)"

.PHONY: all clean build compile unit prep erase flash check_submodules trace openocd gdb halt reset flash_dfu flash_verify cload size print_version clean_version
# Python bindings
MOD_INC = $(CRAZYFLIE_BASE)/src/modules/interface
MOD_SRC = $(CRAZYFLIE_BASE)/src/modules/src

bindings_python: bindings/setup.py bin/cffirmware_wrap.c $(MOD_SRC)/*.c
$(PYTHON) bindings/setup.py build_ext --inplace

bin/cffirmware_wrap.c cffirmware.py: bindings/cffirmware.i $(MOD_INC)/*.h
swig -python -I$(MOD_INC) -o bin/cffirmware_wrap.c bindings/cffirmware.i
mv bin/cffirmware.py cffirmware.py

test_python: bindings_python
$(PYTHON) -m pytest test_python

.PHONY: all clean build compile unit prep erase flash check_submodules trace openocd gdb halt reset flash_dfu flash_verify cload size print_version clean_version bindings_python
70 changes: 70 additions & 0 deletions bindings/cffirmware.i
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
%module cffirmware

// ignore GNU specific compiler attributes
#define __attribute__(x)

%{
#define SWIG_FILE_WITH_INIT
#include "math3d.h"
%}

%include "math3d.h"

%inline %{
%}

%pythoncode %{
import numpy as np
%}

#define COPY_CTOR(structname) \
structname(struct structname const *x) { \
struct structname *y = malloc(sizeof(struct structname)); \
*y = *x; \
return y; \
} \
~structname() { \
free($self); \
} \

%extend vec {
COPY_CTOR(vec)

%pythoncode %{
def __repr__(self):
return "({}, {}, {})".format(self.x, self.y, self.z)

def __array__(self):
return np.array([self.x, self.y, self.z])

def __len__(self):
return 3

def __getitem__(self, i):
if 0 <= i and i < 3:
return _cffirmware.vindex(self, i)
else:
raise IndexError("vec index must be in {0, 1, 2}.")

# Unary operator overloads.
def __neg__(self):
return _cffirmware.vneg(self)

# Vector-scalar binary operator overloads.
def __rmul__(self, s):
return _cffirmware.vscl(s, self)

def __div__(self, s):
return self.__truediv__(s)

def __truediv__(self, s):
return _cffirmware.vdiv(self, s)

# Vector-vector binary operator overloads.
def __add__(self, other):
return _cffirmware.vadd(self, other)

def __sub__(self, other):
return _cffirmware.vsub(self, other)
%}
};
37 changes: 37 additions & 0 deletions bindings/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""Compiles the cffirmware C extension."""

import distutils.command.build
from distutils.core import setup, Extension
import os

fw_dir = "."
include = [
os.path.join(fw_dir, "src/modules/interface"),
]

modules = [
# list firmware c-files here
]
fw_sources = [os.path.join(fw_dir, "src/modules/src", mod) for mod in modules]

cffirmware = Extension(
"_cffirmware",
include_dirs=include,
sources=fw_sources + ["bin/cffirmware_wrap.c"],
extra_compile_args=[
"-O3",
],
)

# Override build command to specify custom "build" directory
class BuildCommand(distutils.command.build.build):
def initialize_options(self):
distutils.command.build.build.initialize_options(self)
self.build_base = "bin"

setup(
name="cffirmware",
version="1.0",
cmdclass={"build": BuildCommand},
ext_modules=[cffirmware]
)
9 changes: 9 additions & 0 deletions test_python/test_math3d.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env python

import numpy as np
import cffirmware

def test_conversion_to_numpy():
v_cf = cffirmware.mkvec(1, 2, 3)
v_np = np.array(v_cf)
assert np.allclose(v_np, np.array([1,2,3]))
1 change: 1 addition & 0 deletions tools/build/build
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ set -e
scriptDir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )

${scriptDir}/test "${@}"
${scriptDir}/test_python "${@}"
${scriptDir}/make "${@}"
${scriptDir}/check_elf
6 changes: 6 additions & 0 deletions tools/build/test_python
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -e

scriptDir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )

make test_python "${@}"
2 changes: 1 addition & 1 deletion tools/make/targets.mk
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ clean_o: clean_version
@$(if $(QUIET), ,echo $(CLEAN_O_COMMAND$(VERBOSE)) )
@$(CLEAN_O_COMMAND)

CLEAN_COMMAND=rm -f cf*.elf cf*.hex cf*.bin cf*.dfu cf*.map $(BIN)/dep/*.d $(BIN)/*.o
CLEAN_COMMAND=rm -f cf*.elf cf*.hex cf*.bin cf*.dfu cf*.map cf*.py _cf*.so $(BIN)/dep/*.d $(BIN)/*.o $(BIN)/*.c
CLEAN_COMMAND_SILENT=" CLEAN"
clean:
@$(if $(QUIET), ,echo $(CLEAN_COMMAND$(VERBOSE)) )
Expand Down

0 comments on commit 3d02a53

Please sign in to comment.