mirror of
https://gitlab.alpinelinux.org/alpine/aports.git
synced 2025-09-21 13:41:20 +02:00
2299 lines
70 KiB
Diff
2299 lines
70 KiB
Diff
From 0d727b3ef8ea56132fd538c9aa54b671950e1297 Mon Sep 17 00:00:00 2001
|
|
From: Matt Mills <mmills@2bn.net>
|
|
Date: Thu, 29 Oct 2020 18:28:13 -0600
|
|
Subject: Replace swig with pybind11 for gr3.9 master compat
|
|
|
|
Signed-off-by: Eric Wild <ewild@sysmocom.de>
|
|
---
|
|
CMakeLists.txt | 16 +-
|
|
docs/doxygen/pydoc_macros.h | 19 ++
|
|
docs/doxygen/swig_doc.py | 332 --------------------
|
|
docs/doxygen/update_pydoc.py | 346 +++++++++++++++++++++
|
|
python/CMakeLists.txt | 20 +-
|
|
python/__init__.py | 29 +-
|
|
python/bindings/CMakeLists.txt | 30 ++
|
|
python/bindings/README.md | 0
|
|
python/bindings/bind_oot_file.py | 53 ++++
|
|
python/bindings/docstrings/README.md | 1 +
|
|
python/bindings/docstrings/sink_pydoc_template.h | 153 +++++++++
|
|
python/bindings/docstrings/source_pydoc_template.h | 162 ++++++++++
|
|
python/bindings/header_utils.py | 78 +++++
|
|
python/bindings/python_bindings.cc | 57 ++++
|
|
python/bindings/sink_python.cc | 320 +++++++++++++++++++
|
|
python/bindings/source_python.cc | 342 ++++++++++++++++++++
|
|
swig/CMakeLists.txt | 57 ----
|
|
swig/osmosdr_swig.i | 82 -----
|
|
18 files changed, 1583 insertions(+), 514 deletions(-)
|
|
create mode 100644 docs/doxygen/pydoc_macros.h
|
|
delete mode 100644 docs/doxygen/swig_doc.py
|
|
create mode 100644 docs/doxygen/update_pydoc.py
|
|
create mode 100644 python/bindings/CMakeLists.txt
|
|
create mode 100644 python/bindings/README.md
|
|
create mode 100644 python/bindings/bind_oot_file.py
|
|
create mode 100644 python/bindings/docstrings/README.md
|
|
create mode 100644 python/bindings/docstrings/sink_pydoc_template.h
|
|
create mode 100644 python/bindings/docstrings/source_pydoc_template.h
|
|
create mode 100644 python/bindings/header_utils.py
|
|
create mode 100644 python/bindings/python_bindings.cc
|
|
create mode 100644 python/bindings/sink_python.cc
|
|
create mode 100644 python/bindings/source_python.cc
|
|
delete mode 100644 swig/CMakeLists.txt
|
|
delete mode 100644 swig/osmosdr_swig.i
|
|
|
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
|
index 74c54f5..b4bb535 100644
|
|
--- a/CMakeLists.txt
|
|
+++ b/CMakeLists.txt
|
|
@@ -41,7 +41,7 @@ set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "")
|
|
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules)
|
|
|
|
# Find GNURadio (pmt and runtime are core, always included)
|
|
-find_package(Gnuradio "3.8" REQUIRED COMPONENTS blocks fft filter)
|
|
+find_package(Gnuradio "3.9" REQUIRED COMPONENTS blocks fft filter)
|
|
|
|
# Set the version information here
|
|
set(VERSION_MAJOR 0)
|
|
@@ -188,20 +188,11 @@ find_package(Doxygen)
|
|
##########
|
|
|
|
find_package(PythonLibs 3)
|
|
-find_package(SWIG)
|
|
-
|
|
-if(SWIG_FOUND)
|
|
- message(STATUS "Minimum SWIG version required is 1.3.31")
|
|
- set(SWIG_VERSION_CHECK FALSE)
|
|
- if("${SWIG_VERSION}" VERSION_GREATER "1.3.30")
|
|
- set(SWIG_VERSION_CHECK TRUE)
|
|
- endif()
|
|
-endif(SWIG_FOUND)
|
|
+find_package(pybind11)
|
|
|
|
GR_REGISTER_COMPONENT("Python support" ENABLE_PYTHON
|
|
PYTHONLIBS_FOUND
|
|
- SWIG_FOUND
|
|
- SWIG_VERSION_CHECK
|
|
+ pybind11_FOUND
|
|
)
|
|
|
|
########################################################################
|
|
@@ -269,7 +260,6 @@ add_custom_target(uninstall
|
|
add_subdirectory(include/osmosdr)
|
|
add_subdirectory(lib)
|
|
if(ENABLE_PYTHON)
|
|
- add_subdirectory(swig)
|
|
add_subdirectory(python)
|
|
add_subdirectory(grc)
|
|
add_subdirectory(apps)
|
|
diff --git a/docs/doxygen/pydoc_macros.h b/docs/doxygen/pydoc_macros.h
|
|
new file mode 100644
|
|
index 0000000..98bf7cd
|
|
--- /dev/null
|
|
+++ b/docs/doxygen/pydoc_macros.h
|
|
@@ -0,0 +1,19 @@
|
|
+#ifndef PYDOC_MACROS_H
|
|
+#define PYDOC_MACROS_H
|
|
+
|
|
+#define __EXPAND(x) x
|
|
+#define __COUNT(_1, _2, _3, _4, _5, _6, _7, COUNT, ...) COUNT
|
|
+#define __VA_SIZE(...) __EXPAND(__COUNT(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1))
|
|
+#define __CAT1(a, b) a##b
|
|
+#define __CAT2(a, b) __CAT1(a, b)
|
|
+#define __DOC1(n1) __doc_##n1
|
|
+#define __DOC2(n1, n2) __doc_##n1##_##n2
|
|
+#define __DOC3(n1, n2, n3) __doc_##n1##_##n2##_##n3
|
|
+#define __DOC4(n1, n2, n3, n4) __doc_##n1##_##n2##_##n3##_##n4
|
|
+#define __DOC5(n1, n2, n3, n4, n5) __doc_##n1##_##n2##_##n3##_##n4##_##n5
|
|
+#define __DOC6(n1, n2, n3, n4, n5, n6) __doc_##n1##_##n2##_##n3##_##n4##_##n5##_##n6
|
|
+#define __DOC7(n1, n2, n3, n4, n5, n6, n7) \
|
|
+ __doc_##n1##_##n2##_##n3##_##n4##_##n5##_##n6##_##n7
|
|
+#define DOC(...) __EXPAND(__EXPAND(__CAT2(__DOC, __VA_SIZE(__VA_ARGS__)))(__VA_ARGS__))
|
|
+
|
|
+#endif // PYDOC_MACROS_H
|
|
\ No newline at end of file
|
|
diff --git a/docs/doxygen/swig_doc.py b/docs/doxygen/swig_doc.py
|
|
deleted file mode 100644
|
|
index e3b308e..0000000
|
|
--- a/docs/doxygen/swig_doc.py
|
|
+++ /dev/null
|
|
@@ -1,332 +0,0 @@
|
|
-#
|
|
-# Copyright 2010-2012 Free Software Foundation, Inc.
|
|
-#
|
|
-# This file was generated by gr_modtool, a tool from the GNU Radio framework
|
|
-# This file is a part of gr-osmosdr
|
|
-#
|
|
-# GNU Radio is free software; you can redistribute it and/or modify
|
|
-# it under the terms of the GNU General Public License as published by
|
|
-# the Free Software Foundation; either version 3, or (at your option)
|
|
-# any later version.
|
|
-#
|
|
-# GNU Radio is distributed in the hope that it will be useful,
|
|
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
-# GNU General Public License for more details.
|
|
-#
|
|
-# You should have received a copy of the GNU General Public License
|
|
-# along with GNU Radio; see the file COPYING. If not, write to
|
|
-# the Free Software Foundation, Inc., 51 Franklin Street,
|
|
-# Boston, MA 02110-1301, USA.
|
|
-#
|
|
-"""
|
|
-Creates the swig_doc.i SWIG interface file.
|
|
-Execute using: python swig_doc.py xml_path outputfilename
|
|
-
|
|
-The file instructs SWIG to transfer the doxygen comments into the
|
|
-python docstrings.
|
|
-
|
|
-"""
|
|
-from __future__ import unicode_literals
|
|
-
|
|
-import sys, time
|
|
-
|
|
-from doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile
|
|
-from doxyxml import DoxyOther, base
|
|
-
|
|
-def py_name(name):
|
|
- bits = name.split('_')
|
|
- return '_'.join(bits[1:])
|
|
-
|
|
-def make_name(name):
|
|
- bits = name.split('_')
|
|
- return bits[0] + '_make_' + '_'.join(bits[1:])
|
|
-
|
|
-
|
|
-class Block(object):
|
|
- """
|
|
- Checks if doxyxml produced objects correspond to a gnuradio block.
|
|
- """
|
|
-
|
|
- @classmethod
|
|
- def includes(cls, item):
|
|
- if not isinstance(item, DoxyClass):
|
|
- return False
|
|
- # Check for a parsing error.
|
|
- if item.error():
|
|
- return False
|
|
- friendname = make_name(item.name())
|
|
- is_a_block = item.has_member(friendname, DoxyFriend)
|
|
- # But now sometimes the make function isn't a friend so check again.
|
|
- if not is_a_block:
|
|
- is_a_block = di.has_member(friendname, DoxyFunction)
|
|
- return is_a_block
|
|
-
|
|
-class Block2(object):
|
|
- """
|
|
- Checks if doxyxml produced objects correspond to a new style
|
|
- gnuradio block.
|
|
- """
|
|
-
|
|
- @classmethod
|
|
- def includes(cls, item):
|
|
- if not isinstance(item, DoxyClass):
|
|
- return False
|
|
- # Check for a parsing error.
|
|
- if item.error():
|
|
- return False
|
|
- is_a_block2 = item.has_member('make', DoxyFunction) and item.has_member('sptr', DoxyOther)
|
|
- return is_a_block2
|
|
-
|
|
-
|
|
-def utoascii(text):
|
|
- """
|
|
- Convert unicode text into ascii and escape quotes and backslashes.
|
|
- """
|
|
- if text is None:
|
|
- return ''
|
|
- out = text.encode('ascii', 'replace')
|
|
- # swig will require us to replace blackslash with 4 backslashes
|
|
- out = out.replace(b'\\', b'\\\\\\\\')
|
|
- out = out.replace(b'"', b'\\"').decode('ascii')
|
|
- return str(out)
|
|
-
|
|
-
|
|
-def combine_descriptions(obj):
|
|
- """
|
|
- Combines the brief and detailed descriptions of an object together.
|
|
- """
|
|
- description = []
|
|
- bd = obj.brief_description.strip()
|
|
- dd = obj.detailed_description.strip()
|
|
- if bd:
|
|
- description.append(bd)
|
|
- if dd:
|
|
- description.append(dd)
|
|
- return utoascii('\n\n'.join(description)).strip()
|
|
-
|
|
-def format_params(parameteritems):
|
|
- output = ['Args:']
|
|
- template = ' {0} : {1}'
|
|
- for pi in parameteritems:
|
|
- output.append(template.format(pi.name, pi.description))
|
|
- return '\n'.join(output)
|
|
-
|
|
-entry_templ = '%feature("docstring") {name} "{docstring}"'
|
|
-def make_entry(obj, name=None, templ="{description}", description=None, params=[]):
|
|
- """
|
|
- Create a docstring entry for a swig interface file.
|
|
-
|
|
- obj - a doxyxml object from which documentation will be extracted.
|
|
- name - the name of the C object (defaults to obj.name())
|
|
- templ - an optional template for the docstring containing only one
|
|
- variable named 'description'.
|
|
- description - if this optional variable is set then it's value is
|
|
- used as the description instead of extracting it from obj.
|
|
- """
|
|
- if name is None:
|
|
- name=obj.name()
|
|
- if "operator " in name:
|
|
- return ''
|
|
- if description is None:
|
|
- description = combine_descriptions(obj)
|
|
- if params:
|
|
- description += '\n\n'
|
|
- description += utoascii(format_params(params))
|
|
- docstring = templ.format(description=description)
|
|
- if not docstring:
|
|
- return ''
|
|
- return entry_templ.format(
|
|
- name=name,
|
|
- docstring=docstring,
|
|
- )
|
|
-
|
|
-
|
|
-def make_func_entry(func, name=None, description=None, params=None):
|
|
- """
|
|
- Create a function docstring entry for a swig interface file.
|
|
-
|
|
- func - a doxyxml object from which documentation will be extracted.
|
|
- name - the name of the C object (defaults to func.name())
|
|
- description - if this optional variable is set then it's value is
|
|
- used as the description instead of extracting it from func.
|
|
- params - a parameter list that overrides using func.params.
|
|
- """
|
|
- #if params is None:
|
|
- # params = func.params
|
|
- #params = [prm.declname for prm in params]
|
|
- #if params:
|
|
- # sig = "Params: (%s)" % ", ".join(params)
|
|
- #else:
|
|
- # sig = "Params: (NONE)"
|
|
- #templ = "{description}\n\n" + sig
|
|
- #return make_entry(func, name=name, templ=utoascii(templ),
|
|
- # description=description)
|
|
- return make_entry(func, name=name, description=description, params=params)
|
|
-
|
|
-
|
|
-def make_class_entry(klass, description=None, ignored_methods=[], params=None):
|
|
- """
|
|
- Create a class docstring for a swig interface file.
|
|
- """
|
|
- if params is None:
|
|
- params = klass.params
|
|
- output = []
|
|
- output.append(make_entry(klass, description=description, params=params))
|
|
- for func in klass.in_category(DoxyFunction):
|
|
- if func.name() not in ignored_methods:
|
|
- name = klass.name() + '::' + func.name()
|
|
- output.append(make_func_entry(func, name=name))
|
|
- return "\n\n".join(output)
|
|
-
|
|
-
|
|
-def make_block_entry(di, block):
|
|
- """
|
|
- Create class and function docstrings of a gnuradio block for a
|
|
- swig interface file.
|
|
- """
|
|
- descriptions = []
|
|
- # Get the documentation associated with the class.
|
|
- class_desc = combine_descriptions(block)
|
|
- if class_desc:
|
|
- descriptions.append(class_desc)
|
|
- # Get the documentation associated with the make function
|
|
- make_func = di.get_member(make_name(block.name()), DoxyFunction)
|
|
- make_func_desc = combine_descriptions(make_func)
|
|
- if make_func_desc:
|
|
- descriptions.append(make_func_desc)
|
|
- # Get the documentation associated with the file
|
|
- try:
|
|
- block_file = di.get_member(block.name() + ".h", DoxyFile)
|
|
- file_desc = combine_descriptions(block_file)
|
|
- if file_desc:
|
|
- descriptions.append(file_desc)
|
|
- except base.Base.NoSuchMember:
|
|
- # Don't worry if we can't find a matching file.
|
|
- pass
|
|
- # And join them all together to make a super duper description.
|
|
- super_description = "\n\n".join(descriptions)
|
|
- # Associate the combined description with the class and
|
|
- # the make function.
|
|
- output = []
|
|
- output.append(make_class_entry(block, description=super_description))
|
|
- output.append(make_func_entry(make_func, description=super_description,
|
|
- params=block.params))
|
|
- return "\n\n".join(output)
|
|
-
|
|
-def make_block2_entry(di, block):
|
|
- """
|
|
- Create class and function docstrings of a new style gnuradio block for a
|
|
- swig interface file.
|
|
- """
|
|
- descriptions = []
|
|
- # For new style blocks all the relevant documentation should be
|
|
- # associated with the 'make' method.
|
|
- class_description = combine_descriptions(block)
|
|
- make_func = block.get_member('make', DoxyFunction)
|
|
- make_description = combine_descriptions(make_func)
|
|
- description = class_description + "\n\nConstructor Specific Documentation:\n\n" + make_description
|
|
- # Associate the combined description with the class and
|
|
- # the make function.
|
|
- output = []
|
|
- output.append(make_class_entry(
|
|
- block, description=description,
|
|
- ignored_methods=['make'], params=make_func.params))
|
|
- makename = block.name() + '::make'
|
|
- output.append(make_func_entry(
|
|
- make_func, name=makename, description=description,
|
|
- params=make_func.params))
|
|
- return "\n\n".join(output)
|
|
-
|
|
-def make_swig_interface_file(di, swigdocfilename, custom_output=None):
|
|
-
|
|
- output = ["""
|
|
-/*
|
|
- * This file was automatically generated using swig_doc.py.
|
|
- *
|
|
- * Any changes to it will be lost next time it is regenerated.
|
|
- */
|
|
-"""]
|
|
-
|
|
- if custom_output is not None:
|
|
- output.append(custom_output)
|
|
-
|
|
- # Create docstrings for the blocks.
|
|
- blocks = di.in_category(Block)
|
|
- blocks2 = di.in_category(Block2)
|
|
-
|
|
- make_funcs = set([])
|
|
- for block in blocks:
|
|
- try:
|
|
- make_func = di.get_member(make_name(block.name()), DoxyFunction)
|
|
- # Don't want to risk writing to output twice.
|
|
- if make_func.name() not in make_funcs:
|
|
- make_funcs.add(make_func.name())
|
|
- output.append(make_block_entry(di, block))
|
|
- except block.ParsingError:
|
|
- sys.stderr.write('Parsing error for block {0}\n'.format(block.name()))
|
|
- raise
|
|
-
|
|
- for block in blocks2:
|
|
- try:
|
|
- make_func = block.get_member('make', DoxyFunction)
|
|
- make_func_name = block.name() +'::make'
|
|
- # Don't want to risk writing to output twice.
|
|
- if make_func_name not in make_funcs:
|
|
- make_funcs.add(make_func_name)
|
|
- output.append(make_block2_entry(di, block))
|
|
- except block.ParsingError:
|
|
- sys.stderr.write('Parsing error for block {0}\n'.format(block.name()))
|
|
- raise
|
|
-
|
|
- # Create docstrings for functions
|
|
- # Don't include the make functions since they have already been dealt with.
|
|
- funcs = [f for f in di.in_category(DoxyFunction)
|
|
- if f.name() not in make_funcs and not f.name().startswith('std::')]
|
|
- for f in funcs:
|
|
- try:
|
|
- output.append(make_func_entry(f))
|
|
- except f.ParsingError:
|
|
- sys.stderr.write('Parsing error for function {0}\n'.format(f.name()))
|
|
-
|
|
- # Create docstrings for classes
|
|
- block_names = [block.name() for block in blocks]
|
|
- block_names += [block.name() for block in blocks2]
|
|
- klasses = [k for k in di.in_category(DoxyClass)
|
|
- if k.name() not in block_names and not k.name().startswith('std::')]
|
|
- for k in klasses:
|
|
- try:
|
|
- output.append(make_class_entry(k))
|
|
- except k.ParsingError:
|
|
- sys.stderr.write('Parsing error for class {0}\n'.format(k.name()))
|
|
-
|
|
- # Docstrings are not created for anything that is not a function or a class.
|
|
- # If this excludes anything important please add it here.
|
|
-
|
|
- output = "\n\n".join(output)
|
|
-
|
|
- swig_doc = open(swigdocfilename, 'w')
|
|
- swig_doc.write(output)
|
|
- swig_doc.close()
|
|
-
|
|
-if __name__ == "__main__":
|
|
- # Parse command line options and set up doxyxml.
|
|
- err_msg = "Execute using: python swig_doc.py xml_path outputfilename"
|
|
- if len(sys.argv) != 3:
|
|
- raise Exception(err_msg)
|
|
- xml_path = sys.argv[1]
|
|
- swigdocfilename = sys.argv[2]
|
|
- di = DoxyIndex(xml_path)
|
|
-
|
|
- # gnuradio.gr.msq_queue.insert_tail and delete_head create errors unless docstrings are defined!
|
|
- # This is presumably a bug in SWIG.
|
|
- #msg_q = di.get_member(u'gr_msg_queue', DoxyClass)
|
|
- #insert_tail = msg_q.get_member(u'insert_tail', DoxyFunction)
|
|
- #delete_head = msg_q.get_member(u'delete_head', DoxyFunction)
|
|
- output = []
|
|
- #output.append(make_func_entry(insert_tail, name='gr_py_msg_queue__insert_tail'))
|
|
- #output.append(make_func_entry(delete_head, name='gr_py_msg_queue__delete_head'))
|
|
- custom_output = "\n\n".join(output)
|
|
-
|
|
- # Generate the docstrings interface file.
|
|
- make_swig_interface_file(di, swigdocfilename, custom_output=custom_output)
|
|
diff --git a/docs/doxygen/update_pydoc.py b/docs/doxygen/update_pydoc.py
|
|
new file mode 100644
|
|
index 0000000..e6b4544
|
|
--- /dev/null
|
|
+++ b/docs/doxygen/update_pydoc.py
|
|
@@ -0,0 +1,346 @@
|
|
+#
|
|
+# Copyright 2010-2012 Free Software Foundation, Inc.
|
|
+#
|
|
+# This file was generated by gr_modtool, a tool from the GNU Radio framework
|
|
+# This file is a part of gnuradio
|
|
+#
|
|
+# SPDX-License-Identifier: GPL-3.0-or-later
|
|
+#
|
|
+#
|
|
+"""
|
|
+Updates the *pydoc_h files for a module
|
|
+Execute using: python update_pydoc.py xml_path outputfilename
|
|
+
|
|
+The file instructs Pybind11 to transfer the doxygen comments into the
|
|
+python docstrings.
|
|
+
|
|
+"""
|
|
+
|
|
+import os, sys, time, glob, re, json
|
|
+from argparse import ArgumentParser
|
|
+
|
|
+from doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile
|
|
+from doxyxml import DoxyOther, base
|
|
+
|
|
+def py_name(name):
|
|
+ bits = name.split('_')
|
|
+ return '_'.join(bits[1:])
|
|
+
|
|
+def make_name(name):
|
|
+ bits = name.split('_')
|
|
+ return bits[0] + '_make_' + '_'.join(bits[1:])
|
|
+
|
|
+
|
|
+class Block(object):
|
|
+ """
|
|
+ Checks if doxyxml produced objects correspond to a gnuradio block.
|
|
+ """
|
|
+
|
|
+ @classmethod
|
|
+ def includes(cls, item):
|
|
+ if not isinstance(item, DoxyClass):
|
|
+ return False
|
|
+ # Check for a parsing error.
|
|
+ if item.error():
|
|
+ return False
|
|
+ friendname = make_name(item.name())
|
|
+ is_a_block = item.has_member(friendname, DoxyFriend)
|
|
+ # But now sometimes the make function isn't a friend so check again.
|
|
+ if not is_a_block:
|
|
+ is_a_block = di.has_member(friendname, DoxyFunction)
|
|
+ return is_a_block
|
|
+
|
|
+class Block2(object):
|
|
+ """
|
|
+ Checks if doxyxml produced objects correspond to a new style
|
|
+ gnuradio block.
|
|
+ """
|
|
+
|
|
+ @classmethod
|
|
+ def includes(cls, item):
|
|
+ if not isinstance(item, DoxyClass):
|
|
+ return False
|
|
+ # Check for a parsing error.
|
|
+ if item.error():
|
|
+ return False
|
|
+ is_a_block2 = item.has_member('make', DoxyFunction) and item.has_member('sptr', DoxyOther)
|
|
+ return is_a_block2
|
|
+
|
|
+
|
|
+def utoascii(text):
|
|
+ """
|
|
+ Convert unicode text into ascii and escape quotes and backslashes.
|
|
+ """
|
|
+ if text is None:
|
|
+ return ''
|
|
+ out = text.encode('ascii', 'replace')
|
|
+ # swig will require us to replace blackslash with 4 backslashes
|
|
+ # TODO: evaluate what this should be for pybind11
|
|
+ out = out.replace(b'\\', b'\\\\\\\\')
|
|
+ out = out.replace(b'"', b'\\"').decode('ascii')
|
|
+ return str(out)
|
|
+
|
|
+
|
|
+def combine_descriptions(obj):
|
|
+ """
|
|
+ Combines the brief and detailed descriptions of an object together.
|
|
+ """
|
|
+ description = []
|
|
+ bd = obj.brief_description.strip()
|
|
+ dd = obj.detailed_description.strip()
|
|
+ if bd:
|
|
+ description.append(bd)
|
|
+ if dd:
|
|
+ description.append(dd)
|
|
+ return utoascii('\n\n'.join(description)).strip()
|
|
+
|
|
+def format_params(parameteritems):
|
|
+ output = ['Args:']
|
|
+ template = ' {0} : {1}'
|
|
+ for pi in parameteritems:
|
|
+ output.append(template.format(pi.name, pi.description))
|
|
+ return '\n'.join(output)
|
|
+
|
|
+entry_templ = '%feature("docstring") {name} "{docstring}"'
|
|
+def make_entry(obj, name=None, templ="{description}", description=None, params=[]):
|
|
+ """
|
|
+ Create a docstring key/value pair, where the key is the object name.
|
|
+
|
|
+ obj - a doxyxml object from which documentation will be extracted.
|
|
+ name - the name of the C object (defaults to obj.name())
|
|
+ templ - an optional template for the docstring containing only one
|
|
+ variable named 'description'.
|
|
+ description - if this optional variable is set then it's value is
|
|
+ used as the description instead of extracting it from obj.
|
|
+ """
|
|
+ if name is None:
|
|
+ name=obj.name()
|
|
+ if hasattr(obj,'_parse_data') and hasattr(obj._parse_data,'definition'):
|
|
+ name=obj._parse_data.definition.split(' ')[-1]
|
|
+ if "operator " in name:
|
|
+ return ''
|
|
+ if description is None:
|
|
+ description = combine_descriptions(obj)
|
|
+ if params:
|
|
+ description += '\n\n'
|
|
+ description += utoascii(format_params(params))
|
|
+ docstring = templ.format(description=description)
|
|
+
|
|
+ return {name: docstring}
|
|
+
|
|
+
|
|
+def make_class_entry(klass, description=None, ignored_methods=[], params=None):
|
|
+ """
|
|
+ Create a class docstring key/value pair.
|
|
+ """
|
|
+ if params is None:
|
|
+ params = klass.params
|
|
+ output = {}
|
|
+ output.update(make_entry(klass, description=description, params=params))
|
|
+ for func in klass.in_category(DoxyFunction):
|
|
+ if func.name() not in ignored_methods:
|
|
+ name = klass.name() + '::' + func.name()
|
|
+ output.update(make_entry(func, name=name))
|
|
+ return output
|
|
+
|
|
+
|
|
+def make_block_entry(di, block):
|
|
+ """
|
|
+ Create class and function docstrings of a gnuradio block
|
|
+ """
|
|
+ descriptions = []
|
|
+ # Get the documentation associated with the class.
|
|
+ class_desc = combine_descriptions(block)
|
|
+ if class_desc:
|
|
+ descriptions.append(class_desc)
|
|
+ # Get the documentation associated with the make function
|
|
+ make_func = di.get_member(make_name(block.name()), DoxyFunction)
|
|
+ make_func_desc = combine_descriptions(make_func)
|
|
+ if make_func_desc:
|
|
+ descriptions.append(make_func_desc)
|
|
+ # Get the documentation associated with the file
|
|
+ try:
|
|
+ block_file = di.get_member(block.name() + ".h", DoxyFile)
|
|
+ file_desc = combine_descriptions(block_file)
|
|
+ if file_desc:
|
|
+ descriptions.append(file_desc)
|
|
+ except base.Base.NoSuchMember:
|
|
+ # Don't worry if we can't find a matching file.
|
|
+ pass
|
|
+ # And join them all together to make a super duper description.
|
|
+ super_description = "\n\n".join(descriptions)
|
|
+ # Associate the combined description with the class and
|
|
+ # the make function.
|
|
+ output = {}
|
|
+ output.update(make_class_entry(block, description=super_description))
|
|
+ output.update(make_entry(make_func, description=super_description,
|
|
+ params=block.params))
|
|
+ return output
|
|
+
|
|
+def make_block2_entry(di, block):
|
|
+ """
|
|
+ Create class and function docstrings of a new style gnuradio block
|
|
+ """
|
|
+ # For new style blocks all the relevant documentation should be
|
|
+ # associated with the 'make' method.
|
|
+ class_description = combine_descriptions(block)
|
|
+ make_func = block.get_member('make', DoxyFunction)
|
|
+ make_description = combine_descriptions(make_func)
|
|
+ description = class_description + "\n\nConstructor Specific Documentation:\n\n" + make_description
|
|
+ # Associate the combined description with the class and
|
|
+ # the make function.
|
|
+ output = {}
|
|
+ output.update(make_class_entry(
|
|
+ block, description=description,
|
|
+ ignored_methods=['make'], params=make_func.params))
|
|
+ makename = block.name() + '::make'
|
|
+ output.update(make_entry(
|
|
+ make_func, name=makename, description=description,
|
|
+ params=make_func.params))
|
|
+ return output
|
|
+
|
|
+def get_docstrings_dict(di, custom_output=None):
|
|
+
|
|
+ output = {}
|
|
+ if custom_output:
|
|
+ output.update(custom_output)
|
|
+
|
|
+ # Create docstrings for the blocks.
|
|
+ blocks = di.in_category(Block)
|
|
+ blocks2 = di.in_category(Block2)
|
|
+
|
|
+ make_funcs = set([])
|
|
+ for block in blocks:
|
|
+ try:
|
|
+ make_func = di.get_member(make_name(block.name()), DoxyFunction)
|
|
+ # Don't want to risk writing to output twice.
|
|
+ if make_func.name() not in make_funcs:
|
|
+ make_funcs.add(make_func.name())
|
|
+ output.update(make_block_entry(di, block))
|
|
+ except block.ParsingError:
|
|
+ sys.stderr.write('Parsing error for block {0}\n'.format(block.name()))
|
|
+ raise
|
|
+
|
|
+ for block in blocks2:
|
|
+ try:
|
|
+ make_func = block.get_member('make', DoxyFunction)
|
|
+ make_func_name = block.name() +'::make'
|
|
+ # Don't want to risk writing to output twice.
|
|
+ if make_func_name not in make_funcs:
|
|
+ make_funcs.add(make_func_name)
|
|
+ output.update(make_block2_entry(di, block))
|
|
+ except block.ParsingError:
|
|
+ sys.stderr.write('Parsing error for block {0}\n'.format(block.name()))
|
|
+ raise
|
|
+
|
|
+ # Create docstrings for functions
|
|
+ # Don't include the make functions since they have already been dealt with.
|
|
+ funcs = [f for f in di.in_category(DoxyFunction)
|
|
+ if f.name() not in make_funcs and not f.name().startswith('std::')]
|
|
+ for f in funcs:
|
|
+ try:
|
|
+ output.update(make_entry(f))
|
|
+ except f.ParsingError:
|
|
+ sys.stderr.write('Parsing error for function {0}\n'.format(f.name()))
|
|
+
|
|
+ # Create docstrings for classes
|
|
+ block_names = [block.name() for block in blocks]
|
|
+ block_names += [block.name() for block in blocks2]
|
|
+ klasses = [k for k in di.in_category(DoxyClass)
|
|
+ if k.name() not in block_names and not k.name().startswith('std::')]
|
|
+ for k in klasses:
|
|
+ try:
|
|
+ output.update(make_class_entry(k))
|
|
+ except k.ParsingError:
|
|
+ sys.stderr.write('Parsing error for class {0}\n'.format(k.name()))
|
|
+
|
|
+ # Docstrings are not created for anything that is not a function or a class.
|
|
+ # If this excludes anything important please add it here.
|
|
+
|
|
+ return output
|
|
+
|
|
+def sub_docstring_in_pydoc_h(pydoc_files, docstrings_dict, output_dir, filter_str=None):
|
|
+ if filter_str:
|
|
+ docstrings_dict = {k: v for k, v in docstrings_dict.items() if k.startswith(filter_str)}
|
|
+
|
|
+ with open(os.path.join(output_dir,'docstring_status'),'w') as status_file:
|
|
+
|
|
+ for pydoc_file in pydoc_files:
|
|
+ if filter_str:
|
|
+ filter_str2 = "::".join((filter_str,os.path.split(pydoc_file)[-1].split('_pydoc_template.h')[0]))
|
|
+ docstrings_dict2 = {k: v for k, v in docstrings_dict.items() if k.startswith(filter_str2)}
|
|
+ else:
|
|
+ docstrings_dict2 = docstrings_dict
|
|
+
|
|
+
|
|
+
|
|
+ file_in = open(pydoc_file,'r').read()
|
|
+ for key, value in docstrings_dict2.items():
|
|
+ file_in_tmp = file_in
|
|
+ try:
|
|
+ doc_key = key.split("::")
|
|
+ # if 'gr' in doc_key:
|
|
+ # doc_key.remove('gr')
|
|
+ doc_key = '_'.join(doc_key)
|
|
+ regexp = r'(__doc_{} =\sR\"doc\()[^)]*(\)doc\")'.format(doc_key)
|
|
+ regexp = re.compile(regexp, re.MULTILINE)
|
|
+
|
|
+ (file_in, nsubs) = regexp.subn(r'\1'+value+r'\2', file_in, count=1)
|
|
+ if nsubs == 1:
|
|
+ status_file.write("PASS: " + pydoc_file + "\n")
|
|
+ except KeyboardInterrupt:
|
|
+ raise KeyboardInterrupt
|
|
+ except: # be permissive, TODO log, but just leave the docstring blank
|
|
+ status_file.write("FAIL: " + pydoc_file + "\n")
|
|
+ file_in = file_in_tmp
|
|
+
|
|
+ output_pathname = os.path.join(output_dir, os.path.basename(pydoc_file).replace('_template.h','.h'))
|
|
+ # FIXME: Remove this debug print
|
|
+ print('output docstrings to {}'.format(output_pathname))
|
|
+ with open(output_pathname,'w') as file_out:
|
|
+ file_out.write(file_in)
|
|
+
|
|
+def copy_docstring_templates(pydoc_files, output_dir):
|
|
+ with open(os.path.join(output_dir,'docstring_status'),'w') as status_file:
|
|
+ for pydoc_file in pydoc_files:
|
|
+ file_in = open(pydoc_file,'r').read()
|
|
+ output_pathname = os.path.join(output_dir, os.path.basename(pydoc_file).replace('_template.h','.h'))
|
|
+ # FIXME: Remove this debug print
|
|
+ print('copy docstrings to {}'.format(output_pathname))
|
|
+ with open(output_pathname,'w') as file_out:
|
|
+ file_out.write(file_in)
|
|
+ status_file.write("DONE")
|
|
+
|
|
+def argParse():
|
|
+ """Parses commandline args."""
|
|
+ desc='Scrape the doxygen generated xml for docstrings to insert into python bindings'
|
|
+ parser = ArgumentParser(description=desc)
|
|
+
|
|
+ parser.add_argument("function", help="Operation to perform on docstrings", choices=["scrape","sub","copy"])
|
|
+
|
|
+ parser.add_argument("--xml_path")
|
|
+ parser.add_argument("--bindings_dir")
|
|
+ parser.add_argument("--output_dir")
|
|
+ parser.add_argument("--json_path")
|
|
+ parser.add_argument("--filter", default=None)
|
|
+
|
|
+ return parser.parse_args()
|
|
+
|
|
+if __name__ == "__main__":
|
|
+ # Parse command line options and set up doxyxml.
|
|
+ args = argParse()
|
|
+ if args.function.lower() == 'scrape':
|
|
+ di = DoxyIndex(args.xml_path)
|
|
+ docstrings_dict = get_docstrings_dict(di)
|
|
+ with open(args.json_path, 'w') as fp:
|
|
+ json.dump(docstrings_dict, fp)
|
|
+ elif args.function.lower() == 'sub':
|
|
+ with open(args.json_path, 'r') as fp:
|
|
+ docstrings_dict = json.load(fp)
|
|
+ pydoc_files = glob.glob(os.path.join(args.bindings_dir,'*_pydoc_template.h'))
|
|
+ sub_docstring_in_pydoc_h(pydoc_files, docstrings_dict, args.output_dir, args.filter)
|
|
+ elif args.function.lower() == 'copy':
|
|
+ pydoc_files = glob.glob(os.path.join(args.bindings_dir,'*_pydoc_template.h'))
|
|
+ copy_docstring_templates(pydoc_files, args.output_dir)
|
|
+
|
|
+
|
|
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
|
|
index 53cb61e..dcae02a 100644
|
|
--- a/python/CMakeLists.txt
|
|
+++ b/python/CMakeLists.txt
|
|
@@ -1,21 +1,10 @@
|
|
# Copyright 2011 Free Software Foundation, Inc.
|
|
#
|
|
-# This file is part of gr-osmosdr
|
|
+# This file was generated by gr_modtool, a tool from the GNU Radio framework
|
|
+# This file is a part of gr-osmosdr
|
|
#
|
|
-# gr-osmosdr is free software; you can redistribute it and/or modify
|
|
-# it under the terms of the GNU General Public License as published by
|
|
-# the Free Software Foundation; either version 3, or (at your option)
|
|
-# any later version.
|
|
+# SPDX-License-Identifier: GPL-3.0-or-later
|
|
#
|
|
-# gr-osmosdr is distributed in the hope that it will be useful,
|
|
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
-# GNU General Public License for more details.
|
|
-#
|
|
-# You should have received a copy of the GNU General Public License
|
|
-# along with gr-osmosdr; see the file COPYING. If not, write to
|
|
-# the Free Software Foundation, Inc., 51 Franklin Street,
|
|
-# Boston, MA 02110-1301, USA.
|
|
|
|
########################################################################
|
|
# Include python install macros
|
|
@@ -25,6 +14,8 @@ if(NOT PYTHONINTERP_FOUND)
|
|
return()
|
|
endif()
|
|
|
|
+add_subdirectory(bindings)
|
|
+
|
|
########################################################################
|
|
# Install python sources
|
|
########################################################################
|
|
@@ -40,4 +31,3 @@ GR_PYTHON_INSTALL(
|
|
include(GrTest)
|
|
|
|
set(GR_TEST_TARGET_DEPS gnuradio-osmosdr)
|
|
-set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig)
|
|
diff --git a/python/__init__.py b/python/__init__.py
|
|
index 1cb090f..e619f4f 100644
|
|
--- a/python/__init__.py
|
|
+++ b/python/__init__.py
|
|
@@ -1,25 +1,24 @@
|
|
#
|
|
# Copyright 2008,2009 Free Software Foundation, Inc.
|
|
#
|
|
-# This application is free software; you can redistribute it and/or modify
|
|
-# it under the terms of the GNU General Public License as published by
|
|
-# the Free Software Foundation; either version 3, or (at your option)
|
|
-# any later version.
|
|
-#
|
|
-# This application is distributed in the hope that it will be useful,
|
|
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
-# GNU General Public License for more details.
|
|
-#
|
|
-# You should have received a copy of the GNU General Public License along
|
|
-# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
+# SPDX-License-Identifier: GPL-3.0-or-later
|
|
#
|
|
|
|
# The presence of this file turns this directory into a Python package
|
|
|
|
'''
|
|
-This is the GNU Radio OsmoSDR module.
|
|
+This is the GNU Radio OSMOSDR module. Place your Python package
|
|
+description here (python/__init__.py).
|
|
'''
|
|
+import os
|
|
|
|
-from .osmosdr_swig import *
|
|
+# import pybind11 generated symbols into the osmosdr namespace
|
|
+try:
|
|
+ from .osmosdr_python import *
|
|
+except ImportError:
|
|
+ dirname, filename = os.path.split(os.path.abspath(__file__))
|
|
+ __path__.append(os.path.join(dirname, "bindings"))
|
|
+ from .osmosdr_python import *
|
|
+
|
|
+# import any pure python here
|
|
+#
|
|
diff --git a/python/bindings/CMakeLists.txt b/python/bindings/CMakeLists.txt
|
|
new file mode 100644
|
|
index 0000000..ed50d7e
|
|
--- /dev/null
|
|
+++ b/python/bindings/CMakeLists.txt
|
|
@@ -0,0 +1,30 @@
|
|
+# Copyright 2020 Free Software Foundation, Inc.
|
|
+#
|
|
+# This file is part of GNU Radio
|
|
+#
|
|
+# SPDX-License-Identifier: GPL-3.0-or-later
|
|
+#
|
|
+
|
|
+GR_PYTHON_CHECK_MODULE_RAW(
|
|
+ "pygccxml"
|
|
+ "import pygccxml"
|
|
+ PYGCCXML_FOUND
|
|
+ )
|
|
+
|
|
+include(GrPybind)
|
|
+
|
|
+########################################################################
|
|
+# Python Bindings
|
|
+########################################################################
|
|
+
|
|
+list(APPEND osmosdr_python_files
|
|
+ sink_python.cc
|
|
+ source_python.cc
|
|
+ python_bindings.cc)
|
|
+
|
|
+GR_PYBIND_MAKE_OOT(osmosdr
|
|
+ ../..
|
|
+ gr::osmosdr
|
|
+ "${osmosdr_python_files}")
|
|
+
|
|
+install(TARGETS osmosdr_python DESTINATION ${GR_PYTHON_DIR}/osmosdr COMPONENT pythonapi)
|
|
diff --git a/python/bindings/README.md b/python/bindings/README.md
|
|
new file mode 100644
|
|
index 0000000..e69de29
|
|
diff --git a/python/bindings/bind_oot_file.py b/python/bindings/bind_oot_file.py
|
|
new file mode 100644
|
|
index 0000000..55de795
|
|
--- /dev/null
|
|
+++ b/python/bindings/bind_oot_file.py
|
|
@@ -0,0 +1,53 @@
|
|
+import warnings
|
|
+import argparse
|
|
+import os
|
|
+from gnuradio.bindtool import BindingGenerator
|
|
+import pathlib
|
|
+import sys
|
|
+
|
|
+parser = argparse.ArgumentParser(description='Bind a GR Out of Tree Block')
|
|
+parser.add_argument('--module', type=str,
|
|
+ help='Name of gr module containing file to bind (e.g. fft digital analog)')
|
|
+
|
|
+parser.add_argument('--output_dir', default='/tmp',
|
|
+ help='Output directory of generated bindings')
|
|
+parser.add_argument('--prefix', help='Prefix of Installed GNU Radio')
|
|
+parser.add_argument('--src', help='Directory of gnuradio source tree',
|
|
+ default=os.path.dirname(os.path.abspath(__file__))+'/../../..')
|
|
+
|
|
+parser.add_argument(
|
|
+ '--filename', help="File to be parsed")
|
|
+
|
|
+parser.add_argument(
|
|
+ '--include', help='Additional Include Dirs, separated', default=(), nargs='+')
|
|
+
|
|
+parser.add_argument(
|
|
+ '--status', help='Location of output file for general status (used during cmake)', default=None
|
|
+)
|
|
+parser.add_argument(
|
|
+ '--flag_automatic', default='0'
|
|
+)
|
|
+parser.add_argument(
|
|
+ '--flag_pygccxml', default='0'
|
|
+)
|
|
+
|
|
+args = parser.parse_args()
|
|
+
|
|
+prefix = args.prefix
|
|
+output_dir = args.output_dir
|
|
+includes = args.include
|
|
+name = args.module
|
|
+
|
|
+namespace = [name]
|
|
+prefix_include_root = name
|
|
+
|
|
+
|
|
+with warnings.catch_warnings():
|
|
+ warnings.filterwarnings("ignore", category=DeprecationWarning)
|
|
+
|
|
+ bg = BindingGenerator(prefix, namespace,
|
|
+ prefix_include_root, output_dir, addl_includes=','.join(args.include), catch_exceptions=False, write_json_output=False, status_output=args.status,
|
|
+ flag_automatic=True if args.flag_automatic.lower() in [
|
|
+ '1', 'true'] else False,
|
|
+ flag_pygccxml=True if args.flag_pygccxml.lower() in ['1', 'true'] else False)
|
|
+ bg.gen_file_binding(args.filename)
|
|
diff --git a/python/bindings/docstrings/README.md b/python/bindings/docstrings/README.md
|
|
new file mode 100644
|
|
index 0000000..295455a
|
|
--- /dev/null
|
|
+++ b/python/bindings/docstrings/README.md
|
|
@@ -0,0 +1 @@
|
|
+This directory stores templates for docstrings that are scraped from the include header files for each block
|
|
\ No newline at end of file
|
|
diff --git a/python/bindings/docstrings/sink_pydoc_template.h b/python/bindings/docstrings/sink_pydoc_template.h
|
|
new file mode 100644
|
|
index 0000000..dad47cf
|
|
--- /dev/null
|
|
+++ b/python/bindings/docstrings/sink_pydoc_template.h
|
|
@@ -0,0 +1,153 @@
|
|
+/*
|
|
+ * Copyright 2020 Free Software Foundation, Inc.
|
|
+ *
|
|
+ * This file is part of GNU Radio
|
|
+ *
|
|
+ * SPDX-License-Identifier: GPL-3.0-or-later
|
|
+ *
|
|
+ */
|
|
+#include "pydoc_macros.h"
|
|
+#define D(...) DOC(gr,osmosdr, __VA_ARGS__ )
|
|
+/*
|
|
+ This file contains placeholders for docstrings for the Python bindings.
|
|
+ Do not edit! These were automatically extracted during the binding process
|
|
+ and will be overwritten during the build process
|
|
+ */
|
|
+
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_sink_0 = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_sink_1 = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_make = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_num_channels = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_sample_rates = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_sample_rate = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_sample_rate = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_freq_range = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_center_freq = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_center_freq = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_freq_corr = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_freq_corr = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_gain_names = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_gain_range_0 = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_gain_range_1 = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_gain_mode = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_gain_mode = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_gain_0 = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_gain_1 = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_gain_0 = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_gain_1 = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_if_gain = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_bb_gain = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_antennas = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_antenna = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_antenna = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_dc_offset = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_iq_balance = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_bandwidth = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_bandwidth = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_bandwidth_range = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_time_source = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_time_source = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_time_sources = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_clock_source = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_clock_source = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_clock_sources = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_clock_rate = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_clock_rate = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_time_now = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_get_time_last_pps = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_time_now = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_time_next_pps = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_sink_set_time_unknown_pps = R"doc()doc";
|
|
+
|
|
+
|
|
diff --git a/python/bindings/docstrings/source_pydoc_template.h b/python/bindings/docstrings/source_pydoc_template.h
|
|
new file mode 100644
|
|
index 0000000..f2c3ca4
|
|
--- /dev/null
|
|
+++ b/python/bindings/docstrings/source_pydoc_template.h
|
|
@@ -0,0 +1,162 @@
|
|
+/*
|
|
+ * Copyright 2020 Free Software Foundation, Inc.
|
|
+ *
|
|
+ * This file is part of GNU Radio
|
|
+ *
|
|
+ * SPDX-License-Identifier: GPL-3.0-or-later
|
|
+ *
|
|
+ */
|
|
+#include "pydoc_macros.h"
|
|
+#define D(...) DOC(gr,osmosdr, __VA_ARGS__ )
|
|
+/*
|
|
+ This file contains placeholders for docstrings for the Python bindings.
|
|
+ Do not edit! These were automatically extracted during the binding process
|
|
+ and will be overwritten during the build process
|
|
+ */
|
|
+
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_source_0 = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_source_1 = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_make = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_num_channels = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_seek = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_sample_rates = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_sample_rate = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_sample_rate = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_freq_range = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_center_freq = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_center_freq = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_freq_corr = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_freq_corr = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_gain_names = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_gain_range_0 = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_gain_range_1 = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_gain_mode = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_gain_mode = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_gain_0 = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_gain_1 = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_gain_0 = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_gain_1 = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_if_gain = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_bb_gain = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_antennas = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_antenna = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_antenna = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_dc_offset_mode = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_dc_offset = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_iq_balance_mode = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_iq_balance = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_bandwidth = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_bandwidth = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_bandwidth_range = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_time_source = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_time_source = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_time_sources = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_clock_source = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_clock_source = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_clock_sources = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_clock_rate = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_clock_rate = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_time_now = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_get_time_last_pps = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_time_now = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_time_next_pps = R"doc()doc";
|
|
+
|
|
+
|
|
+ static const char *__doc_osmosdr_source_set_time_unknown_pps = R"doc()doc";
|
|
+
|
|
+
|
|
diff --git a/python/bindings/header_utils.py b/python/bindings/header_utils.py
|
|
new file mode 100644
|
|
index 0000000..165124e
|
|
--- /dev/null
|
|
+++ b/python/bindings/header_utils.py
|
|
@@ -0,0 +1,78 @@
|
|
+# Utilities for reading values in header files
|
|
+
|
|
+from argparse import ArgumentParser
|
|
+import re
|
|
+
|
|
+
|
|
+class PybindHeaderParser:
|
|
+ def __init__(self, pathname):
|
|
+ with open(pathname,'r') as f:
|
|
+ self.file_txt = f.read()
|
|
+
|
|
+ def get_flag_automatic(self):
|
|
+ # p = re.compile(r'BINDTOOL_GEN_AUTOMATIC\(([^\s])\)')
|
|
+ # m = p.search(self.file_txt)
|
|
+ m = re.search(r'BINDTOOL_GEN_AUTOMATIC\(([^\s])\)', self.file_txt)
|
|
+ if (m and m.group(1) == '1'):
|
|
+ return True
|
|
+ else:
|
|
+ return False
|
|
+
|
|
+ def get_flag_pygccxml(self):
|
|
+ # p = re.compile(r'BINDTOOL_USE_PYGCCXML\(([^\s])\)')
|
|
+ # m = p.search(self.file_txt)
|
|
+ m = re.search(r'BINDTOOL_USE_PYGCCXML\(([^\s])\)', self.file_txt)
|
|
+ if (m and m.group(1) == '1'):
|
|
+ return True
|
|
+ else:
|
|
+ return False
|
|
+
|
|
+ def get_header_filename(self):
|
|
+ # p = re.compile(r'BINDTOOL_HEADER_FILE\(([^\s]*)\)')
|
|
+ # m = p.search(self.file_txt)
|
|
+ m = re.search(r'BINDTOOL_HEADER_FILE\(([^\s]*)\)', self.file_txt)
|
|
+ if (m):
|
|
+ return m.group(1)
|
|
+ else:
|
|
+ return None
|
|
+
|
|
+ def get_header_file_hash(self):
|
|
+ # p = re.compile(r'BINDTOOL_HEADER_FILE_HASH\(([^\s]*)\)')
|
|
+ # m = p.search(self.file_txt)
|
|
+ m = re.search(r'BINDTOOL_HEADER_FILE_HASH\(([^\s]*)\)', self.file_txt)
|
|
+ if (m):
|
|
+ return m.group(1)
|
|
+ else:
|
|
+ return None
|
|
+
|
|
+ def get_flags(self):
|
|
+ return f'{self.get_flag_automatic()};{self.get_flag_pygccxml()};{self.get_header_filename()};{self.get_header_file_hash()};'
|
|
+
|
|
+
|
|
+
|
|
+def argParse():
|
|
+ """Parses commandline args."""
|
|
+ desc='Reads the parameters from the comment block in the pybind files'
|
|
+ parser = ArgumentParser(description=desc)
|
|
+
|
|
+ parser.add_argument("function", help="Operation to perform on comment block of pybind file", choices=["flag_auto","flag_pygccxml","header_filename","header_file_hash","all"])
|
|
+ parser.add_argument("pathname", help="Pathname of pybind c++ file to read, e.g. blockname_python.cc")
|
|
+
|
|
+ return parser.parse_args()
|
|
+
|
|
+if __name__ == "__main__":
|
|
+ # Parse command line options and set up doxyxml.
|
|
+ args = argParse()
|
|
+
|
|
+ pbhp = PybindHeaderParser(args.pathname)
|
|
+
|
|
+ if args.function == "flag_auto":
|
|
+ print(pbhp.get_flag_automatic())
|
|
+ elif args.function == "flag_pygccxml":
|
|
+ print(pbhp.get_flag_pygccxml())
|
|
+ elif args.function == "header_filename":
|
|
+ print(pbhp.get_header_filename())
|
|
+ elif args.function == "header_file_hash":
|
|
+ print(pbhp.get_header_file_hash())
|
|
+ elif args.function == "all":
|
|
+ print(pbhp.get_flags())
|
|
\ No newline at end of file
|
|
diff --git a/python/bindings/python_bindings.cc b/python/bindings/python_bindings.cc
|
|
new file mode 100644
|
|
index 0000000..fc11ee0
|
|
--- /dev/null
|
|
+++ b/python/bindings/python_bindings.cc
|
|
@@ -0,0 +1,57 @@
|
|
+/*
|
|
+ * Copyright 2020 Free Software Foundation, Inc.
|
|
+ *
|
|
+ * This file is part of GNU Radio
|
|
+ *
|
|
+ * SPDX-License-Identifier: GPL-3.0-or-later
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <pybind11/pybind11.h>
|
|
+
|
|
+#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
|
|
+#include <numpy/arrayobject.h>
|
|
+
|
|
+namespace py = pybind11;
|
|
+
|
|
+// Headers for binding functions
|
|
+/**************************************/
|
|
+/* The following comment block is used for
|
|
+/* gr_modtool to insert function prototypes
|
|
+/* Please do not delete
|
|
+/**************************************/
|
|
+// BINDING_FUNCTION_PROTOTYPES(
|
|
+ void bind_sink(py::module& m);
|
|
+ void bind_source(py::module& m);
|
|
+// ) END BINDING_FUNCTION_PROTOTYPES
|
|
+
|
|
+
|
|
+// 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.
|
|
+void* init_numpy()
|
|
+{
|
|
+ import_array();
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+PYBIND11_MODULE(osmosdr_python, m)
|
|
+{
|
|
+ // Initialize the numpy C API
|
|
+ // (otherwise we will see segmentation faults)
|
|
+ init_numpy();
|
|
+
|
|
+ // Allow access to base block methods
|
|
+ py::module::import("gnuradio.gr");
|
|
+
|
|
+ /**************************************/
|
|
+ /* The following comment block is used for
|
|
+ /* gr_modtool to insert binding function calls
|
|
+ /* Please do not delete
|
|
+ /**************************************/
|
|
+ // BINDING_FUNCTION_CALLS(
|
|
+ bind_sink(m);
|
|
+ bind_source(m);
|
|
+ // ) END BINDING_FUNCTION_CALLS
|
|
+}
|
|
diff --git a/python/bindings/sink_python.cc b/python/bindings/sink_python.cc
|
|
new file mode 100644
|
|
index 0000000..1c6711d
|
|
--- /dev/null
|
|
+++ b/python/bindings/sink_python.cc
|
|
@@ -0,0 +1,320 @@
|
|
+/*
|
|
+ * Copyright 2020 Free Software Foundation, Inc.
|
|
+ *
|
|
+ * This file is part of GNU Radio
|
|
+ *
|
|
+ * SPDX-License-Identifier: GPL-3.0-or-later
|
|
+ *
|
|
+ */
|
|
+
|
|
+/***********************************************************************************/
|
|
+/* This file is automatically generated using bindtool and can be manually edited */
|
|
+/* The following lines can be configured to regenerate this file during cmake */
|
|
+/* If manual edits are made, the following tags should be modified accordingly. */
|
|
+/* BINDTOOL_GEN_AUTOMATIC(1) */
|
|
+/* BINDTOOL_USE_PYGCCXML(0) */
|
|
+/* BINDTOOL_HEADER_FILE(sink.h) */
|
|
+/* BINDTOOL_HEADER_FILE_HASH(d4331eb8a19b7a2aa4ed0100039f7a0e) */
|
|
+/***********************************************************************************/
|
|
+
|
|
+#include <pybind11/complex.h>
|
|
+#include <pybind11/pybind11.h>
|
|
+#include <pybind11/stl.h>
|
|
+
|
|
+namespace py = pybind11;
|
|
+
|
|
+#include <osmosdr/sink.h>
|
|
+// pydoc.h is automatically generated in the build directory
|
|
+#include <sink_pydoc.h>
|
|
+
|
|
+void bind_sink(py::module& m)
|
|
+{
|
|
+
|
|
+ using sink = ::osmosdr::sink;
|
|
+
|
|
+
|
|
+ py::class_<sink, gr::hier_block2,
|
|
+ std::shared_ptr<sink>>(m, "sink", D(sink))
|
|
+
|
|
+ .def(py::init(&sink::make),
|
|
+ py::arg("args") = "",
|
|
+ D(sink,make)
|
|
+ )
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+ .def("get_num_channels",&sink::get_num_channels,
|
|
+ D(sink,get_num_channels)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_sample_rates",&sink::get_sample_rates,
|
|
+ D(sink,get_sample_rates)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_sample_rate",&sink::set_sample_rate,
|
|
+ py::arg("rate"),
|
|
+ D(sink,set_sample_rate)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_sample_rate",&sink::get_sample_rate,
|
|
+ D(sink,get_sample_rate)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_freq_range",&sink::get_freq_range,
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,get_freq_range)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_center_freq",&sink::set_center_freq,
|
|
+ py::arg("freq"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,set_center_freq)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_center_freq",&sink::get_center_freq,
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,get_center_freq)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_freq_corr",&sink::set_freq_corr,
|
|
+ py::arg("ppm"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,set_freq_corr)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_freq_corr",&sink::get_freq_corr,
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,get_freq_corr)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_gain_names",&sink::get_gain_names,
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,get_gain_names)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_gain_range",(osmosdr::gain_range_t (sink::*)(size_t))&sink::get_gain_range,
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,get_gain_range,0)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_gain_range",(osmosdr::gain_range_t (sink::*)(std::string const &, size_t))&sink::get_gain_range,
|
|
+ py::arg("name"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,get_gain_range,1)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_gain_mode",&sink::set_gain_mode,
|
|
+ py::arg("automatic"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,set_gain_mode)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_gain_mode",&sink::get_gain_mode,
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,get_gain_mode)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_gain",(double (sink::*)(double, size_t))&sink::set_gain,
|
|
+ py::arg("gain"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,set_gain,0)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_gain",(double (sink::*)(double, std::string const &, size_t))&sink::set_gain,
|
|
+ py::arg("gain"),
|
|
+ py::arg("name"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,set_gain,1)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_gain",(double (sink::*)(size_t))&sink::get_gain,
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,get_gain,0)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_gain",(double (sink::*)(std::string const &, size_t))&sink::get_gain,
|
|
+ py::arg("name"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,get_gain,1)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_if_gain",&sink::set_if_gain,
|
|
+ py::arg("gain"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,set_if_gain)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_bb_gain",&sink::set_bb_gain,
|
|
+ py::arg("gain"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,set_bb_gain)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_antennas",&sink::get_antennas,
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,get_antennas)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_antenna",&sink::set_antenna,
|
|
+ py::arg("antenna"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,set_antenna)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_antenna",&sink::get_antenna,
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,get_antenna)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_dc_offset",&sink::set_dc_offset,
|
|
+ py::arg("offset"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,set_dc_offset)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_iq_balance",&sink::set_iq_balance,
|
|
+ py::arg("balance"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,set_iq_balance)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_bandwidth",&sink::set_bandwidth,
|
|
+ py::arg("bandwidth"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,set_bandwidth)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_bandwidth",&sink::get_bandwidth,
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,get_bandwidth)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_bandwidth_range",&sink::get_bandwidth_range,
|
|
+ py::arg("chan") = 0,
|
|
+ D(sink,get_bandwidth_range)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_time_source",&sink::set_time_source,
|
|
+ py::arg("source"),
|
|
+ py::arg("mboard") = 0,
|
|
+ D(sink,set_time_source)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_time_source",&sink::get_time_source,
|
|
+ py::arg("mboard"),
|
|
+ D(sink,get_time_source)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_time_sources",&sink::get_time_sources,
|
|
+ py::arg("mboard"),
|
|
+ D(sink,get_time_sources)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_clock_source",&sink::set_clock_source,
|
|
+ py::arg("source"),
|
|
+ py::arg("mboard") = 0,
|
|
+ D(sink,set_clock_source)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_clock_source",&sink::get_clock_source,
|
|
+ py::arg("mboard"),
|
|
+ D(sink,get_clock_source)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_clock_sources",&sink::get_clock_sources,
|
|
+ py::arg("mboard"),
|
|
+ D(sink,get_clock_sources)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_clock_rate",&sink::get_clock_rate,
|
|
+ py::arg("mboard") = 0,
|
|
+ D(sink,get_clock_rate)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_clock_rate",&sink::set_clock_rate,
|
|
+ py::arg("rate"),
|
|
+ py::arg("mboard") = 0,
|
|
+ D(sink,set_clock_rate)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_time_now",&sink::get_time_now,
|
|
+ py::arg("mboard") = 0,
|
|
+ D(sink,get_time_now)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_time_last_pps",&sink::get_time_last_pps,
|
|
+ py::arg("mboard") = 0,
|
|
+ D(sink,get_time_last_pps)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_time_now",&sink::set_time_now,
|
|
+ py::arg("time_spec"),
|
|
+ py::arg("mboard") = 0,
|
|
+ D(sink,set_time_now)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_time_next_pps",&sink::set_time_next_pps,
|
|
+ py::arg("time_spec"),
|
|
+ D(sink,set_time_next_pps)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_time_unknown_pps",&sink::set_time_unknown_pps,
|
|
+ py::arg("time_spec"),
|
|
+ D(sink,set_time_unknown_pps)
|
|
+ )
|
|
+
|
|
+ ;
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+
|
|
diff --git a/python/bindings/source_python.cc b/python/bindings/source_python.cc
|
|
new file mode 100644
|
|
index 0000000..48bf10c
|
|
--- /dev/null
|
|
+++ b/python/bindings/source_python.cc
|
|
@@ -0,0 +1,342 @@
|
|
+/*
|
|
+ * Copyright 2020 Free Software Foundation, Inc.
|
|
+ *
|
|
+ * This file is part of GNU Radio
|
|
+ *
|
|
+ * SPDX-License-Identifier: GPL-3.0-or-later
|
|
+ *
|
|
+ */
|
|
+
|
|
+/***********************************************************************************/
|
|
+/* This file is automatically generated using bindtool and can be manually edited */
|
|
+/* The following lines can be configured to regenerate this file during cmake */
|
|
+/* If manual edits are made, the following tags should be modified accordingly. */
|
|
+/* BINDTOOL_GEN_AUTOMATIC(1) */
|
|
+/* BINDTOOL_USE_PYGCCXML(0) */
|
|
+/* BINDTOOL_HEADER_FILE(source.h) */
|
|
+/* BINDTOOL_HEADER_FILE_HASH(574373c3c7682569b0fd7eea577739da) */
|
|
+/***********************************************************************************/
|
|
+
|
|
+#include <pybind11/complex.h>
|
|
+#include <pybind11/pybind11.h>
|
|
+#include <pybind11/stl.h>
|
|
+
|
|
+namespace py = pybind11;
|
|
+
|
|
+#include <osmosdr/source.h>
|
|
+// pydoc.h is automatically generated in the build directory
|
|
+#include <source_pydoc.h>
|
|
+
|
|
+void bind_source(py::module& m)
|
|
+{
|
|
+
|
|
+ using source = ::osmosdr::source;
|
|
+
|
|
+
|
|
+ py::class_<source, gr::hier_block2,
|
|
+ std::shared_ptr<source>>(m, "source", D(source))
|
|
+
|
|
+ .def(py::init(&source::make),
|
|
+ py::arg("args") = "",
|
|
+ D(source,make)
|
|
+ )
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+ .def("get_num_channels",&source::get_num_channels,
|
|
+ D(source,get_num_channels)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("seek",&source::seek,
|
|
+ py::arg("seek_point"),
|
|
+ py::arg("whence"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,seek)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_sample_rates",&source::get_sample_rates,
|
|
+ D(source,get_sample_rates)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_sample_rate",&source::set_sample_rate,
|
|
+ py::arg("rate"),
|
|
+ D(source,set_sample_rate)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_sample_rate",&source::get_sample_rate,
|
|
+ D(source,get_sample_rate)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_freq_range",&source::get_freq_range,
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,get_freq_range)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_center_freq",&source::set_center_freq,
|
|
+ py::arg("freq"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,set_center_freq)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_center_freq",&source::get_center_freq,
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,get_center_freq)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_freq_corr",&source::set_freq_corr,
|
|
+ py::arg("ppm"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,set_freq_corr)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_freq_corr",&source::get_freq_corr,
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,get_freq_corr)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_gain_names",&source::get_gain_names,
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,get_gain_names)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_gain_range",(osmosdr::gain_range_t (source::*)(size_t))&source::get_gain_range,
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,get_gain_range,0)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_gain_range",(osmosdr::gain_range_t (source::*)(std::string const &, size_t))&source::get_gain_range,
|
|
+ py::arg("name"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,get_gain_range,1)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_gain_mode",&source::set_gain_mode,
|
|
+ py::arg("automatic"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,set_gain_mode)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_gain_mode",&source::get_gain_mode,
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,get_gain_mode)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_gain",(double (source::*)(double, size_t))&source::set_gain,
|
|
+ py::arg("gain"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,set_gain,0)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_gain",(double (source::*)(double, std::string const &, size_t))&source::set_gain,
|
|
+ py::arg("gain"),
|
|
+ py::arg("name"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,set_gain,1)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_gain",(double (source::*)(size_t))&source::get_gain,
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,get_gain,0)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_gain",(double (source::*)(std::string const &, size_t))&source::get_gain,
|
|
+ py::arg("name"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,get_gain,1)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_if_gain",&source::set_if_gain,
|
|
+ py::arg("gain"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,set_if_gain)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_bb_gain",&source::set_bb_gain,
|
|
+ py::arg("gain"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,set_bb_gain)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_antennas",&source::get_antennas,
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,get_antennas)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_antenna",&source::set_antenna,
|
|
+ py::arg("antenna"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,set_antenna)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_antenna",&source::get_antenna,
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,get_antenna)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_dc_offset_mode",&source::set_dc_offset_mode,
|
|
+ py::arg("mode"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,set_dc_offset_mode)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_dc_offset",&source::set_dc_offset,
|
|
+ py::arg("offset"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,set_dc_offset)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_iq_balance_mode",&source::set_iq_balance_mode,
|
|
+ py::arg("mode"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,set_iq_balance_mode)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_iq_balance",&source::set_iq_balance,
|
|
+ py::arg("balance"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,set_iq_balance)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_bandwidth",&source::set_bandwidth,
|
|
+ py::arg("bandwidth"),
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,set_bandwidth)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_bandwidth",&source::get_bandwidth,
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,get_bandwidth)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_bandwidth_range",&source::get_bandwidth_range,
|
|
+ py::arg("chan") = 0,
|
|
+ D(source,get_bandwidth_range)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_time_source",&source::set_time_source,
|
|
+ py::arg("source"),
|
|
+ py::arg("mboard") = 0,
|
|
+ D(source,set_time_source)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_time_source",&source::get_time_source,
|
|
+ py::arg("mboard"),
|
|
+ D(source,get_time_source)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_time_sources",&source::get_time_sources,
|
|
+ py::arg("mboard"),
|
|
+ D(source,get_time_sources)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_clock_source",&source::set_clock_source,
|
|
+ py::arg("source"),
|
|
+ py::arg("mboard") = 0,
|
|
+ D(source,set_clock_source)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_clock_source",&source::get_clock_source,
|
|
+ py::arg("mboard"),
|
|
+ D(source,get_clock_source)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_clock_sources",&source::get_clock_sources,
|
|
+ py::arg("mboard"),
|
|
+ D(source,get_clock_sources)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_clock_rate",&source::get_clock_rate,
|
|
+ py::arg("mboard") = 0,
|
|
+ D(source,get_clock_rate)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_clock_rate",&source::set_clock_rate,
|
|
+ py::arg("rate"),
|
|
+ py::arg("mboard") = 0,
|
|
+ D(source,set_clock_rate)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_time_now",&source::get_time_now,
|
|
+ py::arg("mboard") = 0,
|
|
+ D(source,get_time_now)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("get_time_last_pps",&source::get_time_last_pps,
|
|
+ py::arg("mboard") = 0,
|
|
+ D(source,get_time_last_pps)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_time_now",&source::set_time_now,
|
|
+ py::arg("time_spec"),
|
|
+ py::arg("mboard") = 0,
|
|
+ D(source,set_time_now)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_time_next_pps",&source::set_time_next_pps,
|
|
+ py::arg("time_spec"),
|
|
+ D(source,set_time_next_pps)
|
|
+ )
|
|
+
|
|
+
|
|
+ .def("set_time_unknown_pps",&source::set_time_unknown_pps,
|
|
+ py::arg("time_spec"),
|
|
+ D(source,set_time_unknown_pps)
|
|
+ )
|
|
+
|
|
+ ;
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+
|
|
diff --git a/swig/CMakeLists.txt b/swig/CMakeLists.txt
|
|
deleted file mode 100644
|
|
index 159f212..0000000
|
|
--- a/swig/CMakeLists.txt
|
|
+++ /dev/null
|
|
@@ -1,57 +0,0 @@
|
|
-# Copyright 2011 Free Software Foundation, Inc.
|
|
-#
|
|
-# This file is part of gr-osmosdr
|
|
-#
|
|
-# gr-osmosdr is free software; you can redistribute it and/or modify
|
|
-# it under the terms of the GNU General Public License as published by
|
|
-# the Free Software Foundation; either version 3, or (at your option)
|
|
-# any later version.
|
|
-#
|
|
-# gr-osmosdr is distributed in the hope that it will be useful,
|
|
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
-# GNU General Public License for more details.
|
|
-#
|
|
-# You should have received a copy of the GNU General Public License
|
|
-# along with gr-osmosdr; see the file COPYING. If not, write to
|
|
-# the Free Software Foundation, Inc., 51 Franklin Street,
|
|
-# Boston, MA 02110-1301, USA.
|
|
-
|
|
-########################################################################
|
|
-# Include swig generation macros
|
|
-########################################################################
|
|
-find_package(SWIG)
|
|
-find_package(PythonLibs 3)
|
|
-if(NOT SWIG_FOUND OR NOT PYTHONLIBS_FOUND)
|
|
- return()
|
|
-endif()
|
|
-include(GrSwig)
|
|
-include(GrPython)
|
|
-
|
|
-########################################################################
|
|
-# Setup swig generation
|
|
-########################################################################
|
|
-set(GR_SWIG_INCLUDE_DIRS $<TARGET_PROPERTY:gnuradio::runtime_swig,INTERFACE_INCLUDE_DIRECTORIES>)
|
|
-set(GR_SWIG_TARGET_DEPS gnuradio::runtime_swig)
|
|
-
|
|
-set(GR_SWIG_LIBRARIES gnuradio-osmosdr)
|
|
-
|
|
-set(GR_SWIG_DOC_FILE ${CMAKE_CURRENT_BINARY_DIR}/osmosdr_swig_doc.i)
|
|
-set(GR_SWIG_DOC_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../include/osmosdr)
|
|
-
|
|
-GR_SWIG_MAKE(osmosdr_swig osmosdr_swig.i)
|
|
-
|
|
-########################################################################
|
|
-# Install the build swig module
|
|
-########################################################################
|
|
-GR_SWIG_INSTALL(TARGETS osmosdr_swig DESTINATION ${GR_PYTHON_DIR}/osmosdr)
|
|
-
|
|
-########################################################################
|
|
-# Install swig .i files for development
|
|
-########################################################################
|
|
-install(
|
|
- FILES
|
|
- osmosdr_swig.i
|
|
- ${CMAKE_CURRENT_BINARY_DIR}/osmosdr_swig_doc.i
|
|
- DESTINATION ${GR_INCLUDE_DIR}/osmosdr/swig
|
|
-)
|
|
diff --git a/swig/osmosdr_swig.i b/swig/osmosdr_swig.i
|
|
deleted file mode 100644
|
|
index da42e6e..0000000
|
|
--- a/swig/osmosdr_swig.i
|
|
+++ /dev/null
|
|
@@ -1,82 +0,0 @@
|
|
-/* -*- c++ -*- */
|
|
-
|
|
-#define OSMOSDR_API
|
|
-
|
|
-// suppress Warning 319: No access specifier given for base class 'boost::noncopyable' (ignored).
|
|
-#pragma SWIG nowarn=319
|
|
-
|
|
-%include "gnuradio.i" // the common stuff
|
|
-
|
|
-//load generated python docstrings
|
|
-%include "osmosdr_swig_doc.i"
|
|
-
|
|
-%{
|
|
-#include "osmosdr/device.h"
|
|
-#include "osmosdr/source.h"
|
|
-#include "osmosdr/sink.h"
|
|
-%}
|
|
-
|
|
-// Workaround for a SWIG 2.0.4 bug with templates. Probably needs to be looked in to.
|
|
-%{
|
|
-#if PY_VERSION_HEX >= 0x03020000
|
|
-# define SWIGPY_SLICE_ARG(obj) ((PyObject*) (obj))
|
|
-#else
|
|
-# define SWIGPY_SLICE_ARG(obj) ((PySliceObject*) (obj))
|
|
-#endif
|
|
-%}
|
|
-
|
|
-%template(string_vector_t) std::vector<std::string>;
|
|
-
|
|
-//%template(size_vector_t) std::vector<size_t>;
|
|
-
|
|
-%include <osmosdr/pimpl.h>
|
|
-
|
|
-%ignore osmosdr::device_t::operator[]; //ignore warnings about %extend
|
|
-
|
|
-%template(string_string_dict_t) std::map<std::string, std::string>; //define before device
|
|
-%template(devices_t) std::vector<osmosdr::device_t>;
|
|
-%include <osmosdr/device.h>
|
|
-
|
|
-//%extend std::map<std::string, std::string>{
|
|
-// std::string __getitem__(std::string key) {return (*self)[key];}
|
|
-// void __setitem__(std::string key, std::string val) {(*self)[key] = val;}
|
|
-//};
|
|
-
|
|
-%template(range_vector_t) std::vector<osmosdr::range_t>; //define before range
|
|
-%include <osmosdr/ranges.h>
|
|
-
|
|
-%include <osmosdr/time_spec.h>
|
|
-
|
|
-%extend osmosdr::time_spec_t{
|
|
- osmosdr::time_spec_t __add__(const osmosdr::time_spec_t &what)
|
|
- {
|
|
- osmosdr::time_spec_t temp = *self;
|
|
- temp += what;
|
|
- return temp;
|
|
- }
|
|
- osmosdr::time_spec_t __sub__(const osmosdr::time_spec_t &what)
|
|
- {
|
|
- osmosdr::time_spec_t temp = *self;
|
|
- temp -= what;
|
|
- return temp;
|
|
- }
|
|
-};
|
|
-
|
|
-%define OSMOSDR_SWIG_BLOCK_MAGIC2(PKG, BASE_NAME)
|
|
-%template(BASE_NAME ## _sptr) std::shared_ptr<PKG ## :: ## BASE_NAME>;
|
|
-%pythoncode %{
|
|
-BASE_NAME ## _sptr.__repr__ = lambda self: "<gr_block %s (%d)>" % (self.name(), self.unique_id())
|
|
-BASE_NAME = BASE_NAME.make;
|
|
-%}
|
|
-%enddef
|
|
-
|
|
-%include "osmosdr/source.h"
|
|
-%include "osmosdr/sink.h"
|
|
-
|
|
-OSMOSDR_SWIG_BLOCK_MAGIC2(osmosdr,source);
|
|
-OSMOSDR_SWIG_BLOCK_MAGIC2(osmosdr,sink);
|
|
-
|
|
-%{
|
|
-static const size_t ALL_MBOARDS = osmosdr::ALL_MBOARDS;
|
|
-%}
|
|
-//static const size_t ALL_MBOARDS;
|
|
--
|
|
cgit v1.2.3
|
|
|