aboutsummaryrefslogtreecommitdiffstats
path: root/host/python/pyuhd.cpp
blob: e0f35d929befb73baf8ac50c85069a8c934fc0cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
//
// Copyright 2017-2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: GPL-3.0-or-later
//

#include <boost/shared_ptr.hpp>
#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>

/*
This solution was adapted from an Issue posted to the Boost.Python Github.
https://github.com/boostorg/python/pull/159/files
*/
#if (BOOST_VERSION >= 106400) && (BOOST_VERSION < 106600)
#warning overriding broken boost python implementation of BOOST_PYTHON_MODULE_INIT
#  define BOOST_PYTHON_MODULE_INIT(name)                       \
  void BOOST_PP_CAT(init_module_,name)();                      \
extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_INIT(name)
#endif

#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include <numpy/arrayobject.h>

namespace bp = boost::python;

#include "stream_python.hpp"

#include "types/types_python.hpp"
#include "types/serial_python.hpp"
#include "types/time_spec_python.hpp"
#include "types/metadata_python.hpp"
#include "types/sensors_python.hpp"
#include "types/filters_python.hpp"
#include "types/tune_python.hpp"

#include "usrp/fe_connection_python.hpp"
#include "usrp/dboard_iface_python.hpp"
#include "usrp/subdev_spec_python.hpp"
#include "usrp/multi_usrp_python.hpp"

// Converter for std::vector / std::list arguments from python iterables
struct iterable_converter
{
    template <typename Container>
    iterable_converter& from_python()
    {
        bp::converter::registry::push_back(
            &iterable_converter::convertible,
            &iterable_converter::construct<Container>,
            bp::type_id<Container>()
        );
        return *this;
    }

    static void* convertible(PyObject* object)
    {
        return PyObject_GetIter(object) ? object : NULL;
    }

    template <typename Container>
    static void construct(
        PyObject* object,
        bp::converter::rvalue_from_python_stage1_data* data)
    {
        // Object is a borrowed reference, so create a handle indicting it is
        // borrowed for proper reference counting.
        bp::handle<> handle(bp::borrowed(object));

        // Obtain a handle to the memory block that the converter has
        // allocated for the C++ type.
        typedef bp::converter::rvalue_from_python_storage<Container> storage_type;

        void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;
        typedef bp::stl_input_iterator<typename Container::value_type> iterator;

        // Allocate the C++ type into the converter's memory block, and assign
        // its handle to the converter's convertible variable.  The C++
        // container is populated by passing the begin and end iterators of
        // the python object to the container's constructor.
        new (storage) Container(
          iterator(bp::object(handle)), // begin
          iterator()                    // end
        );

        data->convertible = storage;
    }
};

template<typename Dtype1, typename Dtype2>
struct uhd_to_python_dict
{
    static PyObject* convert(uhd::dict<Dtype1, Dtype2> const& input_dict)
    {
        bp::dict py_dict;
        for (const auto& key: input_dict.keys()){
            py_dict[key] = input_dict[key];
        }
        return bp::incref(py_dict.ptr());
    }

};

template<typename Container>
struct iterable_to_python_list
{
    static PyObject* convert(Container const& input)
    {
        bp::list py_list;
        for (const auto& element: input){
            py_list.append(element);
        }
        return bp::incref(py_list.ptr());
    }
};

// We need this hack because import_array() returns NULL
// for newer Python versions.
// This function is also necessary because it ensures access to the C API
// and removes a warning.
#if PY_MAJOR_VERSION >= 3
void* init_numpy()
{
    import_array();
    return NULL;
}
#else
void init_numpy()
{
    import_array();
}
#endif

BOOST_PYTHON_MODULE(libpyuhd)
{
    // Initialize the numpy C API
    // (otherwise we will see segmentation faults)
    init_numpy();

    bp::object package = bp::scope();
    package.attr("__path__") = "libpyuhd";

    // Declare converters
    iterable_converter()
        .from_python<std::vector<double> >()
        .from_python<std::vector<int> >()
        .from_python<std::vector<size_t> >()
        ;

    bp::to_python_converter<
        uhd::dict<std::string, std::string>,
        uhd_to_python_dict<std::string, std::string>, false >();
    bp::to_python_converter<
        std::vector<std::string>,
        iterable_to_python_list<std::vector<std::string> >, false >();

    // Register types submodule
    {
        bp::object types_module(
            bp::handle<>(bp::borrowed(PyImport_AddModule("libpyuhd.types")))
        );
        bp::scope().attr("types") = types_module;
        bp::scope io_scope = types_module;

        bp::implicitly_convertible<std::string, uhd::device_addr_t>();

        export_types();
        export_time_spec();
        export_spi_config();
        export_metadata();
        export_sensors();
        export_tune();

        // Declare some more converters
        iterable_converter()
            .from_python<std::vector<uhd::device_addr_t>>()
            ;

        bp::to_python_converter<
            std::vector<uhd::device_addr_t>,
            iterable_to_python_list<std::vector<uhd::device_addr_t>>, false >();
    }

    // Register usrp submodule
    {
        bp::object usrp_module(
            bp::handle<>(bp::borrowed(PyImport_AddModule("libpyuhd.usrp")))
        );
        bp::scope().attr("usrp") = usrp_module;
        bp::scope io_scope = usrp_module;

        export_multi_usrp();
        export_subdev_spec();
        export_dboard_iface();
        export_fe_connection();
        export_stream();
    }

    // Register filters submodule
    {
        bp::object filters_module(
            bp::handle<>(bp::borrowed(PyImport_AddModule("libpyuhd.filters")))
        );
        bp::scope().attr("filters") = filters_module;
        bp::scope io_scope = filters_module;

        export_filters();
    }
}