Compare commits
3 Commits
master
...
e310-updat
Author | SHA1 | Date | |
---|---|---|---|
|
0c98c44011 | ||
|
2182e5c6b8 | ||
|
77f4245c35 |
156
CMakeLists.txt
156
CMakeLists.txt
@ -1,36 +1,31 @@
|
|||||||
# Copyright 2011,2013 Free Software Foundation, Inc.
|
# Copyright 2011,2012,2014 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is part of GNU Radio
|
# This file is part of GNU Radio
|
||||||
#
|
#
|
||||||
# GNU Radio is free software; you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation; either version 3, or (at your option)
|
# the Free Software Foundation; either version 3, or (at your option)
|
||||||
# any later version.
|
# any later version.
|
||||||
#
|
#
|
||||||
# GNU Radio is distributed in the hope that it will be useful,
|
# GNU Radio is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with GNU Radio; see the file COPYING. If not, write to
|
# along with GNU Radio; see the file COPYING. If not, write to
|
||||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
# Boston, MA 02110-1301, USA.
|
# Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
# Project setup
|
# Project setup
|
||||||
########################################################################
|
########################################################################
|
||||||
cmake_minimum_required(VERSION 3.8)
|
cmake_minimum_required(VERSION 2.6)
|
||||||
project(gr-air-modes CXX C)
|
project(gr-gr-air-modes CXX C)
|
||||||
|
set(gr-gr-air-modes_VERSION_MAJOR 0)
|
||||||
|
set(gr-gr-air-modes_VERSION_MINOR 0)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
#install to PyBOMBS target prefix if defined
|
|
||||||
if(DEFINED ENV{PYBOMBS_PREFIX})
|
|
||||||
set(CMAKE_INSTALL_PREFIX $ENV{PYBOMBS_PREFIX})
|
|
||||||
message(STATUS "PyBOMBS installed GNU Radio. Setting CMAKE_INSTALL_PREFIX to $ENV{PYBOMBS_PREFIX}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
#select the release build type by default to get optimization flags
|
#select the release build type by default to get optimization flags
|
||||||
if(NOT CMAKE_BUILD_TYPE)
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
set(CMAKE_BUILD_TYPE "Release")
|
set(CMAKE_BUILD_TYPE "Release")
|
||||||
@ -41,68 +36,51 @@ set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "")
|
|||||||
#make sure our local CMake Modules path comes first
|
#make sure our local CMake Modules path comes first
|
||||||
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules)
|
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules)
|
||||||
|
|
||||||
# Set the version information here
|
|
||||||
set(VERSION_MAJOR 1)
|
|
||||||
set(VERSION_API 0)
|
|
||||||
set(VERSION_ABI 0)
|
|
||||||
set(VERSION_PATCH git)
|
|
||||||
|
|
||||||
# Set cmake policies.
|
|
||||||
# This will suppress developer warnings during the cmake process that can occur
|
|
||||||
# if a newer cmake version than the minimum is used.
|
|
||||||
cmake_policy(SET CMP0011 NEW)
|
|
||||||
|
|
||||||
# Enable generation of compile_commands.json for code completion engines
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
# Compiler specific setup
|
# Compiler specific setup
|
||||||
########################################################################
|
########################################################################
|
||||||
if((CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR
|
if(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32)
|
||||||
CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
||||||
AND NOT WIN32)
|
|
||||||
#http://gcc.gnu.org/wiki/Visibility
|
#http://gcc.gnu.org/wiki/Visibility
|
||||||
add_definitions(-fvisibility=hidden)
|
add_definitions(-fvisibility=hidden)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
########################################################################
|
||||||
SET(CMAKE_CXX_STANDARD 11)
|
# Find boost
|
||||||
ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
########################################################################
|
||||||
SET(CMAKE_CXX_STANDARD 11)
|
if(UNIX AND EXISTS "/usr/lib64")
|
||||||
ELSEIF(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix
|
||||||
SET(CMAKE_CXX_STANDARD 11)
|
endif(UNIX AND EXISTS "/usr/lib64")
|
||||||
ELSE()
|
set(Boost_ADDITIONAL_VERSIONS
|
||||||
message(WARNING "C++ standard could not be set because compiler is not GNU, Clang or MSVC.")
|
"1.35.0" "1.35" "1.36.0" "1.36" "1.37.0" "1.37" "1.38.0" "1.38" "1.39.0" "1.39"
|
||||||
ENDIF()
|
"1.40.0" "1.40" "1.41.0" "1.41" "1.42.0" "1.42" "1.43.0" "1.43" "1.44.0" "1.44"
|
||||||
|
"1.45.0" "1.45" "1.46.0" "1.46" "1.47.0" "1.47" "1.48.0" "1.48" "1.49.0" "1.49"
|
||||||
|
"1.50.0" "1.50" "1.51.0" "1.51" "1.52.0" "1.52" "1.53.0" "1.53" "1.54.0" "1.54"
|
||||||
|
"1.55.0" "1.55" "1.56.0" "1.56" "1.57.0" "1.57" "1.58.0" "1.58" "1.59.0" "1.59"
|
||||||
|
"1.60.0" "1.60" "1.61.0" "1.61" "1.62.0" "1.62" "1.63.0" "1.63" "1.64.0" "1.64"
|
||||||
|
"1.65.0" "1.65" "1.66.0" "1.66" "1.67.0" "1.67" "1.68.0" "1.68" "1.69.0" "1.69"
|
||||||
|
)
|
||||||
|
find_package(Boost "1.35" COMPONENTS filesystem system)
|
||||||
|
|
||||||
IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
if(NOT Boost_FOUND)
|
||||||
SET(CMAKE_C_STANDARD 11)
|
message(FATAL_ERROR "Boost required to compile air-modes")
|
||||||
ELSEIF(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
endif()
|
||||||
SET(CMAKE_C_STANDARD 11)
|
|
||||||
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
|
|
||||||
SET(CMAKE_C_STANDARD 11)
|
|
||||||
ELSE()
|
|
||||||
message(WARNING "C standard could not be set because compiler is not GNU, Clang or MSVC.")
|
|
||||||
ENDIF()
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
# Find gnuradio build dependencies
|
# Install directories
|
||||||
########################################################################
|
########################################################################
|
||||||
find_package(Gnuradio "3.8" REQUIRED)
|
|
||||||
include(GrVersion)
|
|
||||||
|
|
||||||
include(GrPlatform) #define LIB_SUFFIX
|
include(GrPlatform) #define LIB_SUFFIX
|
||||||
|
set(GR_RUNTIME_DIR bin)
|
||||||
if(NOT CMAKE_MODULES_DIR)
|
set(GR_LIBRARY_DIR lib${LIB_SUFFIX})
|
||||||
set(CMAKE_MODULES_DIR lib${LIB_SUFFIX}/cmake)
|
|
||||||
endif(NOT CMAKE_MODULES_DIR)
|
|
||||||
|
|
||||||
set(GR_INCLUDE_DIR include/gr_air_modes)
|
set(GR_INCLUDE_DIR include/gr_air_modes)
|
||||||
set(GR_CMAKE_DIR ${CMAKE_MODULES_DIR}/${CMAKE_PROJECT_NAME})
|
set(GR_DATA_DIR share)
|
||||||
set(GR_PKG_DATA_DIR ${GR_DATA_DIR}/${CMAKE_PROJECT_NAME})
|
set(GR_PKG_DATA_DIR ${GR_DATA_DIR}/${CMAKE_PROJECT_NAME})
|
||||||
|
set(GR_DOC_DIR ${GR_DATA_DIR}/doc)
|
||||||
set(GR_PKG_DOC_DIR ${GR_DOC_DIR}/${CMAKE_PROJECT_NAME})
|
set(GR_PKG_DOC_DIR ${GR_DOC_DIR}/${CMAKE_PROJECT_NAME})
|
||||||
|
set(GR_CONF_DIR etc)
|
||||||
set(GR_PKG_CONF_DIR ${GR_CONF_DIR}/${CMAKE_PROJECT_NAME}/conf.d)
|
set(GR_PKG_CONF_DIR ${GR_CONF_DIR}/${CMAKE_PROJECT_NAME}/conf.d)
|
||||||
|
set(GR_LIBEXEC_DIR libexec)
|
||||||
set(GR_PKG_LIBEXEC_DIR ${GR_LIBEXEC_DIR}/${CMAKE_PROJECT_NAME})
|
set(GR_PKG_LIBEXEC_DIR ${GR_LIBEXEC_DIR}/${CMAKE_PROJECT_NAME})
|
||||||
|
set(GRC_BLOCKS_DIR ${GR_PKG_DATA_DIR}/grc/blocks)
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
# On Apple only, set install name and use rpath correctly, if not already set
|
# On Apple only, set install name and use rpath correctly, if not already set
|
||||||
@ -124,6 +102,55 @@ if(APPLE)
|
|||||||
endif(NOT CMAKE_BUILD_WITH_INSTALL_RPATH)
|
endif(NOT CMAKE_BUILD_WITH_INSTALL_RPATH)
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Find gnuradio build dependencies
|
||||||
|
########################################################################
|
||||||
|
find_package(CppUnit)
|
||||||
|
find_package(Doxygen)
|
||||||
|
|
||||||
|
# Search for GNU Radio and its components and versions. Add any
|
||||||
|
# components required to the list of GR_REQUIRED_COMPONENTS (in all
|
||||||
|
# caps such as FILTER or FFT) and change the version to the minimum
|
||||||
|
# API compatible version required.
|
||||||
|
set(GR_REQUIRED_COMPONENTS RUNTIME)
|
||||||
|
find_package(Gnuradio "3.7.2" REQUIRED)
|
||||||
|
|
||||||
|
if(NOT CPPUNIT_FOUND)
|
||||||
|
message(FATAL_ERROR "CppUnit required to compile airmodes")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Setup doxygen option
|
||||||
|
########################################################################
|
||||||
|
if(DOXYGEN_FOUND)
|
||||||
|
option(ENABLE_DOXYGEN "Build docs using Doxygen" ON)
|
||||||
|
else(DOXYGEN_FOUND)
|
||||||
|
option(ENABLE_DOXYGEN "Build docs using Doxygen" OFF)
|
||||||
|
endif(DOXYGEN_FOUND)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Setup the include and linker paths
|
||||||
|
########################################################################
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_SOURCE_DIR}/lib
|
||||||
|
${CMAKE_SOURCE_DIR}/include
|
||||||
|
${CMAKE_BINARY_DIR}/lib
|
||||||
|
${CMAKE_BINARY_DIR}/include
|
||||||
|
${Boost_INCLUDE_DIRS}
|
||||||
|
${CPPUNIT_INCLUDE_DIRS}
|
||||||
|
${GNURADIO_ALL_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
link_directories(
|
||||||
|
${Boost_LIBRARY_DIRS}
|
||||||
|
${CPPUNIT_LIBRARY_DIRS}
|
||||||
|
${GNURADIO_RUNTIME_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set component parameters
|
||||||
|
set(GR_GR-AIR-MODES_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "" FORCE)
|
||||||
|
set(GR_GR-AIR-MODES_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/swig CACHE INTERNAL "" FORCE)
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
# Create uninstall target
|
# Create uninstall target
|
||||||
########################################################################
|
########################################################################
|
||||||
@ -147,3 +174,14 @@ add_subdirectory(grc)
|
|||||||
add_subdirectory(apps)
|
add_subdirectory(apps)
|
||||||
add_subdirectory(docs)
|
add_subdirectory(docs)
|
||||||
add_subdirectory(res)
|
add_subdirectory(res)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Install cmake search helper for this library
|
||||||
|
########################################################################
|
||||||
|
if(NOT CMAKE_MODULES_DIR)
|
||||||
|
set(CMAKE_MODULES_DIR lib${LIB_SUFFIX}/cmake)
|
||||||
|
endif(NOT CMAKE_MODULES_DIR)
|
||||||
|
|
||||||
|
install(FILES cmake/Modules/gr_air_modesConfig.cmake
|
||||||
|
DESTINATION ${CMAKE_MODULES_DIR}/gr_air_modes
|
||||||
|
)
|
||||||
|
13
Dockerfile
13
Dockerfile
@ -1,13 +0,0 @@
|
|||||||
FROM bistromath/gnuradio:v3.8
|
|
||||||
|
|
||||||
ENV num_threads 10
|
|
||||||
MAINTAINER bistromath@gmail.com version: 0.1
|
|
||||||
|
|
||||||
WORKDIR /opt
|
|
||||||
|
|
||||||
RUN apt install -y python3-zmq python3-scipy
|
|
||||||
|
|
||||||
RUN mkdir gr-air-modes
|
|
||||||
COPY . gr-air-modes/
|
|
||||||
WORKDIR /opt/gr-air-modes
|
|
||||||
RUN mkdir build && cd build && cmake ../ && make -j${num_threads} && make install && ldconfig
|
|
1
README
1
README
@ -97,7 +97,6 @@ gr-air-modes requires:
|
|||||||
|
|
||||||
* Python >= 2.5 (written for Python 2.7, Python 3.0 might work)
|
* Python >= 2.5 (written for Python 2.7, Python 3.0 might work)
|
||||||
** NumPy and SciPy are required for the FlightGear output plugin.
|
** NumPy and SciPy are required for the FlightGear output plugin.
|
||||||
* PyZMQ
|
|
||||||
* Gnuradio >= 3.5.0
|
* Gnuradio >= 3.5.0
|
||||||
* Ettus UHD >= 3.4.0 for use with USRPs
|
* Ettus UHD >= 3.4.0 for use with USRPs
|
||||||
* osmosdr (any version) for use with RTLSDR dongles
|
* osmosdr (any version) for use with RTLSDR dongles
|
||||||
|
@ -30,7 +30,6 @@ import air_modes
|
|||||||
from air_modes.exceptions import *
|
from air_modes.exceptions import *
|
||||||
from air_modes.modes_rx_ui import Ui_MainWindow
|
from air_modes.modes_rx_ui import Ui_MainWindow
|
||||||
from air_modes.gui_model import *
|
from air_modes.gui_model import *
|
||||||
from air_modes.az_map import *
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import zmq
|
import zmq
|
||||||
|
|
||||||
@ -88,9 +87,7 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
self.ui.line_my_lat.insert(defaults["latitude"])
|
self.ui.line_my_lat.insert(defaults["latitude"])
|
||||||
if defaults["longitude"] is not None:
|
if defaults["longitude"] is not None:
|
||||||
self.ui.line_my_lon.insert(defaults["longitude"])
|
self.ui.line_my_lon.insert(defaults["longitude"])
|
||||||
if defaults["apikey"] is not None:
|
|
||||||
self.ui.line_my_api_key.insert(defaults["apikey"])
|
|
||||||
|
|
||||||
#disable by default
|
#disable by default
|
||||||
self.ui.check_adsbonly.setCheckState(QtCore.Qt.Unchecked)
|
self.ui.check_adsbonly.setCheckState(QtCore.Qt.Unchecked)
|
||||||
|
|
||||||
@ -107,7 +104,7 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
self.ui.list_aircraft.setModel(self.datamodel)
|
self.ui.list_aircraft.setModel(self.datamodel)
|
||||||
self.ui.list_aircraft.setModelColumn(0)
|
self.ui.list_aircraft.setModelColumn(0)
|
||||||
|
|
||||||
self.az_model = air_modes.az_map.az_map_model(None)
|
self.az_model = air_modes.az_map_model(None)
|
||||||
self.ui.azimuth_map.setModel(self.az_model)
|
self.ui.azimuth_map.setModel(self.az_model)
|
||||||
|
|
||||||
#set up dashboard views
|
#set up dashboard views
|
||||||
@ -324,11 +321,6 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
except:
|
except:
|
||||||
my_position = None
|
my_position = None
|
||||||
|
|
||||||
try:
|
|
||||||
my_apikey = str(self.ui.line_my_api_key.text())
|
|
||||||
except:
|
|
||||||
my_apikey = None
|
|
||||||
|
|
||||||
self._cpr_dec = air_modes.cpr_decoder(my_position)
|
self._cpr_dec = air_modes.cpr_decoder(my_position)
|
||||||
|
|
||||||
self.datamodelout = dashboard_output(self._cpr_dec, self.datamodel, self._publisher)
|
self.datamodelout = dashboard_output(self._cpr_dec, self.datamodel, self._publisher)
|
||||||
@ -351,7 +343,7 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
|
|
||||||
#add azimuth map output and hook it up
|
#add azimuth map output and hook it up
|
||||||
if my_position is not None:
|
if my_position is not None:
|
||||||
self.az_map_output = air_modes.az_map.az_map_output(self._cpr_dec, self.az_model, self._publisher)
|
self.az_map_output = air_modes.az_map_output(self._cpr_dec, self.az_model, self._publisher)
|
||||||
#self._relay.subscribe("dl_data", self.az_map_output.output)
|
#self._relay.subscribe("dl_data", self.az_map_output.output)
|
||||||
|
|
||||||
#set up map
|
#set up map
|
||||||
@ -367,12 +359,12 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
#create SQL database for KML and dashboard displays
|
#create SQL database for KML and dashboard displays
|
||||||
self.dbwriter = air_modes.output_sql(self._cpr_dec, self.dbname, self.lock, self._publisher)
|
self.dbwriter = air_modes.output_sql(self._cpr_dec, self.dbname, self.lock, self._publisher)
|
||||||
self.jsonpgen = air_modes.output_jsonp(self._jsonfile.name, self.dbname, my_position, self.lock, timeout=1)
|
self.jsonpgen = air_modes.output_jsonp(self._jsonfile.name, self.dbname, my_position, self.lock, timeout=1)
|
||||||
htmlstring = air_modes.html_template(my_apikey, my_position, self._jsonfile.name)
|
htmlstring = air_modes.html_template(my_position, self._jsonfile.name)
|
||||||
self._htmlfile.write(htmlstring)
|
self._htmlfile.write(htmlstring)
|
||||||
self._htmlfile.flush()
|
self._htmlfile.flush()
|
||||||
class WebPage(QtWebKit.QWebPage):
|
class WebPage(QtWebKit.QWebPage):
|
||||||
def javaScriptConsoleMessage(self, msg, line, source):
|
def javaScriptConsoleMessage(self, msg, line, source):
|
||||||
print('%s line %d: %s' % (source, line, msg))
|
print '%s line %d: %s' % (source, line, msg)
|
||||||
page = WebPage()
|
page = WebPage()
|
||||||
self.ui.mapView.setPage(page)
|
self.ui.mapView.setPage(page)
|
||||||
self.ui.mapView.load( QtCore.QUrl( QtCore.QUrl.fromLocalFile("/tmp/mode_s.html") ) )
|
self.ui.mapView.load( QtCore.QUrl( QtCore.QUrl.fromLocalFile("/tmp/mode_s.html") ) )
|
||||||
@ -412,11 +404,7 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
self.prefs["longitude"] = float(self.ui.line_my_lon.text())
|
self.prefs["longitude"] = float(self.ui.line_my_lon.text())
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
try:
|
|
||||||
self.prefs["apikey"] = self.ui.line_my_api_key.text()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def on_quit(self):
|
def on_quit(self):
|
||||||
if self.running is True:
|
if self.running is True:
|
||||||
self._radio.close()
|
self._radio.close()
|
||||||
@ -475,7 +463,6 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
defaults["threshold"] = "5"
|
defaults["threshold"] = "5"
|
||||||
defaults["latitude"] = None
|
defaults["latitude"] = None
|
||||||
defaults["longitude"] = None
|
defaults["longitude"] = None
|
||||||
defaults["apikey"] = None
|
|
||||||
|
|
||||||
prefs = ConfigParser.ConfigParser(defaults)
|
prefs = ConfigParser.ConfigParser(defaults)
|
||||||
prefs.optionxform = str
|
prefs.optionxform = str
|
||||||
@ -485,7 +472,7 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
for item in prefs.items("GUI"):
|
for item in prefs.items("GUI"):
|
||||||
defaults[item[0]] = item[1]
|
defaults[item[0]] = item[1]
|
||||||
except (IOError, ConfigParser.NoSectionError):
|
except (IOError, ConfigParser.NoSectionError):
|
||||||
print("No preferences file %s found, creating..." % os.path.expanduser(self.opt_file))
|
print "No preferences file %s found, creating..." % os.path.expanduser(self.opt_file)
|
||||||
self.write_defaults(defaults)
|
self.write_defaults(defaults)
|
||||||
|
|
||||||
return defaults
|
return defaults
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python
|
||||||
# Copyright 2010, 2013 Nick Foster
|
# Copyright 2010, 2013 Nick Foster
|
||||||
#
|
#
|
||||||
# This file is part of gr-air-modes
|
# This file is part of gr-air-modes
|
||||||
@ -23,8 +23,9 @@ from gnuradio.eng_option import eng_option
|
|||||||
from gnuradio.gr.pubsub import pubsub
|
from gnuradio.gr.pubsub import pubsub
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
import time, os, sys, threading, math
|
import time, os, sys, threading, math
|
||||||
|
from string import split, join
|
||||||
import air_modes
|
import air_modes
|
||||||
from air_modes.modes_types import *
|
from air_modes.types import *
|
||||||
from air_modes.exceptions import *
|
from air_modes.exceptions import *
|
||||||
import zmq
|
import zmq
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
# the new option.
|
# the new option.
|
||||||
# E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in
|
# E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in
|
||||||
# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would
|
# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would
|
||||||
# be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefore.
|
# be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor.
|
||||||
|
|
||||||
#=============================================================================
|
#=============================================================================
|
||||||
# Copyright 2010 Alexander Neundorf <neundorf@kde.org>
|
# Copyright 2010 Alexander Neundorf <neundorf@kde.org>
|
||||||
|
39
cmake/Modules/FindCppUnit.cmake
Normal file
39
cmake/Modules/FindCppUnit.cmake
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# http://www.cmake.org/pipermail/cmake/2006-October/011446.html
|
||||||
|
# Modified to use pkg config and use standard var names
|
||||||
|
|
||||||
|
#
|
||||||
|
# Find the CppUnit includes and library
|
||||||
|
#
|
||||||
|
# This module defines
|
||||||
|
# CPPUNIT_INCLUDE_DIR, where to find tiff.h, etc.
|
||||||
|
# CPPUNIT_LIBRARIES, the libraries to link against to use CppUnit.
|
||||||
|
# CPPUNIT_FOUND, If false, do not try to use CppUnit.
|
||||||
|
|
||||||
|
INCLUDE(FindPkgConfig)
|
||||||
|
PKG_CHECK_MODULES(PC_CPPUNIT "cppunit")
|
||||||
|
|
||||||
|
FIND_PATH(CPPUNIT_INCLUDE_DIRS
|
||||||
|
NAMES cppunit/TestCase.h
|
||||||
|
HINTS ${PC_CPPUNIT_INCLUDE_DIR}
|
||||||
|
${CMAKE_INSTALL_PREFIX}/include
|
||||||
|
PATHS
|
||||||
|
/usr/local/include
|
||||||
|
/usr/include
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(CPPUNIT_LIBRARIES
|
||||||
|
NAMES cppunit
|
||||||
|
HINTS ${PC_CPPUNIT_LIBDIR}
|
||||||
|
${CMAKE_INSTALL_PREFIX}/lib
|
||||||
|
${CMAKE_INSTALL_PREFIX}/lib64
|
||||||
|
PATHS
|
||||||
|
${CPPUNIT_INCLUDE_DIRS}/../lib
|
||||||
|
/usr/local/lib
|
||||||
|
/usr/lib
|
||||||
|
)
|
||||||
|
|
||||||
|
LIST(APPEND CPPUNIT_LIBRARIES ${CMAKE_DL_LIBS})
|
||||||
|
|
||||||
|
INCLUDE(FindPackageHandleStandardArgs)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(CPPUNIT DEFAULT_MSG CPPUNIT_LIBRARIES CPPUNIT_INCLUDE_DIRS)
|
||||||
|
MARK_AS_ADVANCED(CPPUNIT_LIBRARIES CPPUNIT_INCLUDE_DIRS)
|
36
cmake/Modules/FindGnuradioRuntime.cmake
Normal file
36
cmake/Modules/FindGnuradioRuntime.cmake
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
INCLUDE(FindPkgConfig)
|
||||||
|
PKG_CHECK_MODULES(PC_GNURADIO_RUNTIME gnuradio-runtime)
|
||||||
|
|
||||||
|
if(PC_GNURADIO_RUNTIME_FOUND)
|
||||||
|
# look for include files
|
||||||
|
FIND_PATH(
|
||||||
|
GNURADIO_RUNTIME_INCLUDE_DIRS
|
||||||
|
NAMES gnuradio/top_block.h
|
||||||
|
HINTS $ENV{GNURADIO_RUNTIME_DIR}/include
|
||||||
|
${PC_GNURADIO_RUNTIME_INCLUDE_DIRS}
|
||||||
|
${CMAKE_INSTALL_PREFIX}/include
|
||||||
|
PATHS /usr/local/include
|
||||||
|
/usr/include
|
||||||
|
)
|
||||||
|
|
||||||
|
# look for libs
|
||||||
|
FIND_LIBRARY(
|
||||||
|
GNURADIO_RUNTIME_LIBRARIES
|
||||||
|
NAMES gnuradio-runtime
|
||||||
|
HINTS $ENV{GNURADIO_RUNTIME_DIR}/lib
|
||||||
|
${PC_GNURADIO_RUNTIME_LIBDIR}
|
||||||
|
${CMAKE_INSTALL_PREFIX}/lib/
|
||||||
|
${CMAKE_INSTALL_PREFIX}/lib64/
|
||||||
|
PATHS /usr/local/lib
|
||||||
|
/usr/local/lib64
|
||||||
|
/usr/lib
|
||||||
|
/usr/lib64
|
||||||
|
)
|
||||||
|
|
||||||
|
set(GNURADIO_RUNTIME_FOUND ${PC_GNURADIO_RUNTIME_FOUND})
|
||||||
|
endif(PC_GNURADIO_RUNTIME_FOUND)
|
||||||
|
|
||||||
|
INCLUDE(FindPackageHandleStandardArgs)
|
||||||
|
# do not check GNURADIO_RUNTIME_INCLUDE_DIRS, is not set when default include path us used.
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNURADIO_RUNTIME DEFAULT_MSG GNURADIO_RUNTIME_LIBRARIES)
|
||||||
|
MARK_AS_ADVANCED(GNURADIO_RUNTIME_LIBRARIES GNURADIO_RUNTIME_INCLUDE_DIRS)
|
24
cmake/Modules/FindPyQt.py
Normal file
24
cmake/Modules/FindPyQt.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
|
||||||
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
|
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||||
|
|
||||||
|
import PyQt4.pyqtconfig
|
||||||
|
|
||||||
|
pyqtcfg = PyQt4.pyqtconfig.Configuration()
|
||||||
|
print("pyqt_version:%06.0x" % pyqtcfg.pyqt_version)
|
||||||
|
print("pyqt_version_str:%s" % pyqtcfg.pyqt_version_str)
|
||||||
|
|
||||||
|
pyqt_version_tag = ""
|
||||||
|
in_t = False
|
||||||
|
for item in pyqtcfg.pyqt_sip_flags.split(' '):
|
||||||
|
if item=="-t":
|
||||||
|
in_t = True
|
||||||
|
elif in_t:
|
||||||
|
if item.startswith("Qt_4"):
|
||||||
|
pyqt_version_tag = item
|
||||||
|
else:
|
||||||
|
in_t = False
|
||||||
|
print("pyqt_version_tag:%s" % pyqt_version_tag)
|
||||||
|
|
||||||
|
print("pyqt_sip_dir:%s" % pyqtcfg.pyqt_sip_dir)
|
||||||
|
print("pyqt_sip_flags:%s" % pyqtcfg.pyqt_sip_flags)
|
61
cmake/Modules/FindPyQt4.cmake
Normal file
61
cmake/Modules/FindPyQt4.cmake
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# Find PyQt4
|
||||||
|
# ~~~~~~~~~~
|
||||||
|
# Copyright (c) 2007-2008, Simon Edwards <simon@simonzone.com>
|
||||||
|
# Copyright (c) 2012, Nicholas Corgan <nick.corgan@ettus.com>
|
||||||
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
|
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||||
|
#
|
||||||
|
# PyQt4 website: http://www.riverbankcomputing.co.uk/pyqt/index.php
|
||||||
|
#
|
||||||
|
# Find the installed version of PyQt4. FindPyQt4 should only be called after
|
||||||
|
# Python has been found.
|
||||||
|
#
|
||||||
|
# This file defines the following variables:
|
||||||
|
#
|
||||||
|
# PYQT4_VERSION - The version of PyQt4 found expressed as a 6 digit hex number
|
||||||
|
# suitable for comparision as a string
|
||||||
|
#
|
||||||
|
# PYQT4_VERSION_STR - The version of PyQt4 as a human readable string.
|
||||||
|
#
|
||||||
|
# PYQT4_VERSION_TAG - The PyQt version tag using by PyQt's sip files.
|
||||||
|
#
|
||||||
|
# PYQT4_SIP_DIR - The directory holding the PyQt4 .sip files.
|
||||||
|
#
|
||||||
|
# PYQT4_SIP_FLAGS - The SIP flags used to build PyQt.
|
||||||
|
|
||||||
|
IF(EXISTS PYQT4_VERSION AND EXISTS PYUIC4_EXECUTABLE)
|
||||||
|
# Already in cache, be silent
|
||||||
|
SET(PYQT4_FOUND TRUE)
|
||||||
|
SET(PYUIC4_FOUND TRUE)
|
||||||
|
ELSE(EXISTS PYQT4_VERSION AND EXISTS PYUIC4_EXECUTABLE)
|
||||||
|
|
||||||
|
FIND_FILE(_find_pyqt_py FindPyQt.py PATHS ${CMAKE_MODULE_PATH})
|
||||||
|
|
||||||
|
EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} ${_find_pyqt_py} OUTPUT_VARIABLE pyqt_config)
|
||||||
|
IF(pyqt_config)
|
||||||
|
STRING(REGEX REPLACE "^pyqt_version:([^\n]+).*$" "\\1" PYQT4_VERSION ${pyqt_config})
|
||||||
|
STRING(REGEX REPLACE ".*\npyqt_version_str:([^\n]+).*$" "\\1" PYQT4_VERSION_STR ${pyqt_config})
|
||||||
|
STRING(REGEX REPLACE ".*\npyqt_version_tag:([^\n]+).*$" "\\1" PYQT4_VERSION_TAG ${pyqt_config})
|
||||||
|
STRING(REGEX REPLACE ".*\npyqt_sip_dir:([^\n]+).*$" "\\1" PYQT4_SIP_DIR ${pyqt_config})
|
||||||
|
STRING(REGEX REPLACE ".*\npyqt_sip_flags:([^\n]+).*$" "\\1" PYQT4_SIP_FLAGS ${pyqt_config})
|
||||||
|
|
||||||
|
SET(PYQT4_FOUND TRUE)
|
||||||
|
ENDIF(pyqt_config)
|
||||||
|
|
||||||
|
FIND_PROGRAM(PYUIC4_EXECUTABLE NAMES pyuic4)
|
||||||
|
IF(PYUIC4_EXECUTABLE)
|
||||||
|
SET(PYUIC4_FOUND TRUE)
|
||||||
|
ENDIF(PYUIC4_EXECUTABLE)
|
||||||
|
|
||||||
|
IF(PYQT4_FOUND AND PYUIC4_FOUND)
|
||||||
|
IF(NOT PYQT4_FIND_QUIETLY)
|
||||||
|
MESSAGE(STATUS "Found PyQt4 version: ${PYQT4_VERSION_STR}")
|
||||||
|
MESSAGE(STATUS "Found pyuic4: ${PYUIC4_EXECUTABLE}")
|
||||||
|
ENDIF(NOT PYQT4_FIND_QUIETLY)
|
||||||
|
ELSE(PYQT4_FOUND AND PYUIC4_FOUND)
|
||||||
|
IF(PYQT4_FIND_REQUIRED)
|
||||||
|
MESSAGE(FATAL_ERROR "Could not find Python")
|
||||||
|
ENDIF(PYQT4_FIND_REQUIRED)
|
||||||
|
ENDIF(PYQT4_FOUND AND PYUIC4_FOUND)
|
||||||
|
|
||||||
|
ENDIF(EXISTS PYQT4_VERSION AND EXISTS PYUIC4_EXECUTABLE)
|
525
cmake/Modules/GrMiscUtils.cmake
Normal file
525
cmake/Modules/GrMiscUtils.cmake
Normal file
@ -0,0 +1,525 @@
|
|||||||
|
# Copyright 2010-2011,2014 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of GNU Radio
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
if(DEFINED __INCLUDED_GR_MISC_UTILS_CMAKE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(__INCLUDED_GR_MISC_UTILS_CMAKE TRUE)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Set global variable macro.
|
||||||
|
# Used for subdirectories to export settings.
|
||||||
|
# Example: include and library paths.
|
||||||
|
########################################################################
|
||||||
|
function(GR_SET_GLOBAL var)
|
||||||
|
set(${var} ${ARGN} CACHE INTERNAL "" FORCE)
|
||||||
|
endfunction(GR_SET_GLOBAL)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Set the pre-processor definition if the condition is true.
|
||||||
|
# - def the pre-processor definition to set and condition name
|
||||||
|
########################################################################
|
||||||
|
function(GR_ADD_COND_DEF def)
|
||||||
|
if(${def})
|
||||||
|
add_definitions(-D${def})
|
||||||
|
endif(${def})
|
||||||
|
endfunction(GR_ADD_COND_DEF)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Check for a header and conditionally set a compile define.
|
||||||
|
# - hdr the relative path to the header file
|
||||||
|
# - def the pre-processor definition to set
|
||||||
|
########################################################################
|
||||||
|
function(GR_CHECK_HDR_N_DEF hdr def)
|
||||||
|
include(CheckIncludeFileCXX)
|
||||||
|
CHECK_INCLUDE_FILE_CXX(${hdr} ${def})
|
||||||
|
GR_ADD_COND_DEF(${def})
|
||||||
|
endfunction(GR_CHECK_HDR_N_DEF)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Include subdirectory macro.
|
||||||
|
# Sets the CMake directory variables,
|
||||||
|
# includes the subdirectory CMakeLists.txt,
|
||||||
|
# resets the CMake directory variables.
|
||||||
|
#
|
||||||
|
# This macro includes subdirectories rather than adding them
|
||||||
|
# so that the subdirectory can affect variables in the level above.
|
||||||
|
# This provides a work-around for the lack of convenience libraries.
|
||||||
|
# This way a subdirectory can append to the list of library sources.
|
||||||
|
########################################################################
|
||||||
|
macro(GR_INCLUDE_SUBDIRECTORY subdir)
|
||||||
|
#insert the current directories on the front of the list
|
||||||
|
list(INSERT _cmake_source_dirs 0 ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
list(INSERT _cmake_binary_dirs 0 ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
#set the current directories to the names of the subdirs
|
||||||
|
set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${subdir})
|
||||||
|
set(CMAKE_CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${subdir})
|
||||||
|
|
||||||
|
#include the subdirectory CMakeLists to run it
|
||||||
|
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
include(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt)
|
||||||
|
|
||||||
|
#reset the value of the current directories
|
||||||
|
list(GET _cmake_source_dirs 0 CMAKE_CURRENT_SOURCE_DIR)
|
||||||
|
list(GET _cmake_binary_dirs 0 CMAKE_CURRENT_BINARY_DIR)
|
||||||
|
|
||||||
|
#pop the subdir names of the front of the list
|
||||||
|
list(REMOVE_AT _cmake_source_dirs 0)
|
||||||
|
list(REMOVE_AT _cmake_binary_dirs 0)
|
||||||
|
endmacro(GR_INCLUDE_SUBDIRECTORY)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Check if a compiler flag works and conditionally set a compile define.
|
||||||
|
# - flag the compiler flag to check for
|
||||||
|
# - have the variable to set with result
|
||||||
|
########################################################################
|
||||||
|
macro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE flag have)
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
CHECK_CXX_COMPILER_FLAG(${flag} ${have})
|
||||||
|
if(${have})
|
||||||
|
if(${CMAKE_VERSION} VERSION_GREATER "2.8.4")
|
||||||
|
STRING(FIND "${CMAKE_CXX_FLAGS}" "${flag}" flag_dup)
|
||||||
|
if(${flag_dup} EQUAL -1)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flag}")
|
||||||
|
endif(${flag_dup} EQUAL -1)
|
||||||
|
endif(${CMAKE_VERSION} VERSION_GREATER "2.8.4")
|
||||||
|
endif(${have})
|
||||||
|
endmacro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Generates the .la libtool file
|
||||||
|
# This appears to generate libtool files that cannot be used by auto*.
|
||||||
|
# Usage GR_LIBTOOL(TARGET [target] DESTINATION [dest])
|
||||||
|
# Notice: there is not COMPONENT option, these will not get distributed.
|
||||||
|
########################################################################
|
||||||
|
function(GR_LIBTOOL)
|
||||||
|
if(NOT DEFINED GENERATE_LIBTOOL)
|
||||||
|
set(GENERATE_LIBTOOL OFF) #disabled by default
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(GENERATE_LIBTOOL)
|
||||||
|
include(CMakeParseArgumentsCopy)
|
||||||
|
CMAKE_PARSE_ARGUMENTS(GR_LIBTOOL "" "TARGET;DESTINATION" "" ${ARGN})
|
||||||
|
|
||||||
|
find_program(LIBTOOL libtool)
|
||||||
|
if(LIBTOOL)
|
||||||
|
include(CMakeMacroLibtoolFile)
|
||||||
|
CREATE_LIBTOOL_FILE(${GR_LIBTOOL_TARGET} /${GR_LIBTOOL_DESTINATION})
|
||||||
|
endif(LIBTOOL)
|
||||||
|
endif(GENERATE_LIBTOOL)
|
||||||
|
|
||||||
|
endfunction(GR_LIBTOOL)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Do standard things to the library target
|
||||||
|
# - set target properties
|
||||||
|
# - make install rules
|
||||||
|
# Also handle gnuradio custom naming conventions w/ extras mode.
|
||||||
|
########################################################################
|
||||||
|
function(GR_LIBRARY_FOO target)
|
||||||
|
#parse the arguments for component names
|
||||||
|
include(CMakeParseArgumentsCopy)
|
||||||
|
CMAKE_PARSE_ARGUMENTS(GR_LIBRARY "" "RUNTIME_COMPONENT;DEVEL_COMPONENT" "" ${ARGN})
|
||||||
|
|
||||||
|
#set additional target properties
|
||||||
|
set_target_properties(${target} PROPERTIES SOVERSION ${LIBVER})
|
||||||
|
|
||||||
|
#install the generated files like so...
|
||||||
|
install(TARGETS ${target}
|
||||||
|
LIBRARY DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} # .so/.dylib file
|
||||||
|
ARCHIVE DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_DEVEL_COMPONENT} # .lib file
|
||||||
|
RUNTIME DESTINATION ${GR_RUNTIME_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} # .dll file
|
||||||
|
)
|
||||||
|
|
||||||
|
#extras mode enabled automatically on linux
|
||||||
|
if(NOT DEFINED LIBRARY_EXTRAS)
|
||||||
|
set(LIBRARY_EXTRAS ${LINUX})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#special extras mode to enable alternative naming conventions
|
||||||
|
if(LIBRARY_EXTRAS)
|
||||||
|
|
||||||
|
#create .la file before changing props
|
||||||
|
GR_LIBTOOL(TARGET ${target} DESTINATION ${GR_LIBRARY_DIR})
|
||||||
|
|
||||||
|
#give the library a special name with ultra-zero soversion
|
||||||
|
set_target_properties(${target} PROPERTIES OUTPUT_NAME ${target}-${LIBVER} SOVERSION "0.0.0")
|
||||||
|
set(target_name lib${target}-${LIBVER}.so.0.0.0)
|
||||||
|
|
||||||
|
#custom command to generate symlinks
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${target}
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E create_symlink ${target_name} ${CMAKE_CURRENT_BINARY_DIR}/lib${target}.so
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E create_symlink ${target_name} ${CMAKE_CURRENT_BINARY_DIR}/lib${target}-${LIBVER}.so.0
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E touch ${target_name} #so the symlinks point to something valid so cmake 2.6 will install
|
||||||
|
)
|
||||||
|
|
||||||
|
#and install the extra symlinks
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/lib${target}.so
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/lib${target}-${LIBVER}.so.0
|
||||||
|
DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT}
|
||||||
|
)
|
||||||
|
|
||||||
|
endif(LIBRARY_EXTRAS)
|
||||||
|
endfunction(GR_LIBRARY_FOO)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Create a dummy custom command that depends on other targets.
|
||||||
|
# Usage:
|
||||||
|
# GR_GEN_TARGET_DEPS(unique_name target_deps <target1> <target2> ...)
|
||||||
|
# ADD_CUSTOM_COMMAND(<the usual args> ${target_deps})
|
||||||
|
#
|
||||||
|
# Custom command cant depend on targets, but can depend on executables,
|
||||||
|
# and executables can depend on targets. So this is the process:
|
||||||
|
########################################################################
|
||||||
|
function(GR_GEN_TARGET_DEPS name var)
|
||||||
|
file(
|
||||||
|
WRITE ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp.in
|
||||||
|
"int main(void){return 0;}\n"
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp
|
||||||
|
)
|
||||||
|
add_executable(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp)
|
||||||
|
if(ARGN)
|
||||||
|
add_dependencies(${name} ${ARGN})
|
||||||
|
endif(ARGN)
|
||||||
|
|
||||||
|
if(CMAKE_CROSSCOMPILING)
|
||||||
|
set(${var} "DEPENDS;${name}" PARENT_SCOPE) #cant call command when cross
|
||||||
|
else()
|
||||||
|
set(${var} "DEPENDS;${name};COMMAND;${name}" PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endfunction(GR_GEN_TARGET_DEPS)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Control use of gr_logger
|
||||||
|
# Usage:
|
||||||
|
# GR_LOGGING()
|
||||||
|
#
|
||||||
|
# Will set ENABLE_GR_LOG to 1 by default.
|
||||||
|
# Can manually set with -DENABLE_GR_LOG=0|1
|
||||||
|
########################################################################
|
||||||
|
function(GR_LOGGING)
|
||||||
|
find_package(Log4cpp)
|
||||||
|
|
||||||
|
OPTION(ENABLE_GR_LOG "Use gr_logger" ON)
|
||||||
|
if(ENABLE_GR_LOG)
|
||||||
|
# If gr_logger is enabled, make it usable
|
||||||
|
add_definitions( -DENABLE_GR_LOG )
|
||||||
|
|
||||||
|
# also test LOG4CPP; if we have it, use this version of the logger
|
||||||
|
# otherwise, default to the stdout/stderr model.
|
||||||
|
if(LOG4CPP_FOUND)
|
||||||
|
SET(HAVE_LOG4CPP True CACHE INTERNAL "" FORCE)
|
||||||
|
add_definitions( -DHAVE_LOG4CPP )
|
||||||
|
else(not LOG4CPP_FOUND)
|
||||||
|
SET(HAVE_LOG4CPP False CACHE INTERNAL "" FORCE)
|
||||||
|
SET(LOG4CPP_INCLUDE_DIRS "" CACHE INTERNAL "" FORCE)
|
||||||
|
SET(LOG4CPP_LIBRARY_DIRS "" CACHE INTERNAL "" FORCE)
|
||||||
|
SET(LOG4CPP_LIBRARIES "" CACHE INTERNAL "" FORCE)
|
||||||
|
endif(LOG4CPP_FOUND)
|
||||||
|
|
||||||
|
SET(ENABLE_GR_LOG ${ENABLE_GR_LOG} CACHE INTERNAL "" FORCE)
|
||||||
|
|
||||||
|
else(ENABLE_GR_LOG)
|
||||||
|
SET(HAVE_LOG4CPP False CACHE INTERNAL "" FORCE)
|
||||||
|
SET(LOG4CPP_INCLUDE_DIRS "" CACHE INTERNAL "" FORCE)
|
||||||
|
SET(LOG4CPP_LIBRARY_DIRS "" CACHE INTERNAL "" FORCE)
|
||||||
|
SET(LOG4CPP_LIBRARIES "" CACHE INTERNAL "" FORCE)
|
||||||
|
endif(ENABLE_GR_LOG)
|
||||||
|
|
||||||
|
message(STATUS "ENABLE_GR_LOG set to ${ENABLE_GR_LOG}.")
|
||||||
|
message(STATUS "HAVE_LOG4CPP set to ${HAVE_LOG4CPP}.")
|
||||||
|
message(STATUS "LOG4CPP_LIBRARIES set to ${LOG4CPP_LIBRARIES}.")
|
||||||
|
|
||||||
|
endfunction(GR_LOGGING)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Run GRCC to compile .grc files into .py files.
|
||||||
|
#
|
||||||
|
# Usage: GRCC(filename, directory)
|
||||||
|
# - filenames: List of file name of .grc file
|
||||||
|
# - directory: directory of built .py file - usually in
|
||||||
|
# ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
# - Sets PYFILES: output converted GRC file names to Python files.
|
||||||
|
########################################################################
|
||||||
|
function(GRCC)
|
||||||
|
# Extract directory from list of args, remove it for the list of filenames.
|
||||||
|
list(GET ARGV -1 directory)
|
||||||
|
list(REMOVE_AT ARGV -1)
|
||||||
|
set(filenames ${ARGV})
|
||||||
|
file(MAKE_DIRECTORY ${directory})
|
||||||
|
|
||||||
|
SET(GRCC_COMMAND ${CMAKE_SOURCE_DIR}/gr-utils/python/grcc)
|
||||||
|
|
||||||
|
# GRCC uses some stuff in grc and gnuradio-runtime, so we force
|
||||||
|
# the known paths here
|
||||||
|
list(APPEND PYTHONPATHS
|
||||||
|
${CMAKE_SOURCE_DIR}
|
||||||
|
${CMAKE_SOURCE_DIR}/gnuradio-runtime/python
|
||||||
|
${CMAKE_SOURCE_DIR}/gnuradio-runtime/lib/swig
|
||||||
|
${CMAKE_BINARY_DIR}/gnuradio-runtime/lib/swig
|
||||||
|
)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
#SWIG generates the python library files into a subdirectory.
|
||||||
|
#Therefore, we must append this subdirectory into PYTHONPATH.
|
||||||
|
#Only do this for the python directories matching the following:
|
||||||
|
foreach(pydir ${PYTHONPATHS})
|
||||||
|
get_filename_component(name ${pydir} NAME)
|
||||||
|
if(name MATCHES "^(swig|lib|src)$")
|
||||||
|
list(APPEND PYTHONPATHS ${pydir}/${CMAKE_BUILD_TYPE})
|
||||||
|
endif()
|
||||||
|
endforeach(pydir)
|
||||||
|
endif(WIN32)
|
||||||
|
|
||||||
|
file(TO_NATIVE_PATH "${PYTHONPATHS}" pypath)
|
||||||
|
|
||||||
|
if(UNIX)
|
||||||
|
list(APPEND pypath "$PYTHONPATH")
|
||||||
|
string(REPLACE ";" ":" pypath "${pypath}")
|
||||||
|
set(ENV{PYTHONPATH} ${pypath})
|
||||||
|
endif(UNIX)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
list(APPEND pypath "%PYTHONPATH%")
|
||||||
|
string(REPLACE ";" "\\;" pypath "${pypath}")
|
||||||
|
#list(APPEND environs "PYTHONPATH=${pypath}")
|
||||||
|
set(ENV{PYTHONPATH} ${pypath})
|
||||||
|
endif(WIN32)
|
||||||
|
|
||||||
|
foreach(f ${filenames})
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GRCC_COMMAND} -d ${directory} ${f}
|
||||||
|
)
|
||||||
|
string(REPLACE ".grc" ".py" pyfile "${f}")
|
||||||
|
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" pyfile "${pyfile}")
|
||||||
|
list(APPEND pyfiles ${pyfile})
|
||||||
|
endforeach(f)
|
||||||
|
|
||||||
|
set(PYFILES ${pyfiles} PARENT_SCOPE)
|
||||||
|
endfunction(GRCC)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Check if HAVE_PTHREAD_SETSCHEDPARAM and HAVE_SCHED_SETSCHEDULER
|
||||||
|
# should be defined
|
||||||
|
########################################################################
|
||||||
|
macro(GR_CHECK_LINUX_SCHED_AVAIL)
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES -lpthread)
|
||||||
|
CHECK_CXX_SOURCE_COMPILES("
|
||||||
|
#include <pthread.h>
|
||||||
|
int main(){
|
||||||
|
pthread_t pthread;
|
||||||
|
pthread_setschedparam(pthread, 0, 0);
|
||||||
|
return 0;
|
||||||
|
} " HAVE_PTHREAD_SETSCHEDPARAM
|
||||||
|
)
|
||||||
|
GR_ADD_COND_DEF(HAVE_PTHREAD_SETSCHEDPARAM)
|
||||||
|
|
||||||
|
CHECK_CXX_SOURCE_COMPILES("
|
||||||
|
#include <sched.h>
|
||||||
|
int main(){
|
||||||
|
pid_t pid;
|
||||||
|
sched_setscheduler(pid, 0, 0);
|
||||||
|
return 0;
|
||||||
|
} " HAVE_SCHED_SETSCHEDULER
|
||||||
|
)
|
||||||
|
GR_ADD_COND_DEF(HAVE_SCHED_SETSCHEDULER)
|
||||||
|
endmacro(GR_CHECK_LINUX_SCHED_AVAIL)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Macros to generate source and header files from template
|
||||||
|
########################################################################
|
||||||
|
macro(GR_EXPAND_X_H component root)
|
||||||
|
|
||||||
|
include(GrPython)
|
||||||
|
|
||||||
|
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
|
||||||
|
"#!${PYTHON_EXECUTABLE}
|
||||||
|
|
||||||
|
import sys, os, re
|
||||||
|
sys.path.append('${GR_RUNTIME_PYTHONPATH}')
|
||||||
|
os.environ['srcdir'] = '${CMAKE_CURRENT_SOURCE_DIR}'
|
||||||
|
os.chdir('${CMAKE_CURRENT_BINARY_DIR}')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import build_utils
|
||||||
|
root, inp = sys.argv[1:3]
|
||||||
|
for sig in sys.argv[3:]:
|
||||||
|
name = re.sub ('X+', sig, root)
|
||||||
|
d = build_utils.standard_dict2(name, sig, '${component}')
|
||||||
|
build_utils.expand_template(d, inp)
|
||||||
|
")
|
||||||
|
|
||||||
|
#make a list of all the generated headers
|
||||||
|
unset(expanded_files_h)
|
||||||
|
foreach(sig ${ARGN})
|
||||||
|
string(REGEX REPLACE "X+" ${sig} name ${root})
|
||||||
|
list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/${name}.h)
|
||||||
|
endforeach(sig)
|
||||||
|
unset(name)
|
||||||
|
|
||||||
|
#create a command to generate the headers
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${expanded_files_h}
|
||||||
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}.h.t
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
|
||||||
|
${root} ${root}.h.t ${ARGN}
|
||||||
|
)
|
||||||
|
|
||||||
|
#install rules for the generated headers
|
||||||
|
list(APPEND generated_includes ${expanded_files_h})
|
||||||
|
|
||||||
|
endmacro(GR_EXPAND_X_H)
|
||||||
|
|
||||||
|
macro(GR_EXPAND_X_CC_H component root)
|
||||||
|
|
||||||
|
include(GrPython)
|
||||||
|
|
||||||
|
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
|
||||||
|
"#!${PYTHON_EXECUTABLE}
|
||||||
|
|
||||||
|
import sys, os, re
|
||||||
|
sys.path.append('${GR_RUNTIME_PYTHONPATH}')
|
||||||
|
os.environ['srcdir'] = '${CMAKE_CURRENT_SOURCE_DIR}'
|
||||||
|
os.chdir('${CMAKE_CURRENT_BINARY_DIR}')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import build_utils
|
||||||
|
root, inp = sys.argv[1:3]
|
||||||
|
for sig in sys.argv[3:]:
|
||||||
|
name = re.sub ('X+', sig, root)
|
||||||
|
d = build_utils.standard_impl_dict2(name, sig, '${component}')
|
||||||
|
build_utils.expand_template(d, inp)
|
||||||
|
")
|
||||||
|
|
||||||
|
#make a list of all the generated files
|
||||||
|
unset(expanded_files_cc)
|
||||||
|
unset(expanded_files_h)
|
||||||
|
foreach(sig ${ARGN})
|
||||||
|
string(REGEX REPLACE "X+" ${sig} name ${root})
|
||||||
|
list(APPEND expanded_files_cc ${CMAKE_CURRENT_BINARY_DIR}/${name}.cc)
|
||||||
|
list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/${name}.h)
|
||||||
|
endforeach(sig)
|
||||||
|
unset(name)
|
||||||
|
|
||||||
|
#create a command to generate the source files
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${expanded_files_cc}
|
||||||
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}.cc.t
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
|
||||||
|
${root} ${root}.cc.t ${ARGN}
|
||||||
|
)
|
||||||
|
|
||||||
|
#create a command to generate the header files
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${expanded_files_h}
|
||||||
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}.h.t
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
|
||||||
|
${root} ${root}.h.t ${ARGN}
|
||||||
|
)
|
||||||
|
|
||||||
|
#make source files depends on headers to force generation
|
||||||
|
set_source_files_properties(${expanded_files_cc}
|
||||||
|
PROPERTIES OBJECT_DEPENDS "${expanded_files_h}"
|
||||||
|
)
|
||||||
|
|
||||||
|
#install rules for the generated files
|
||||||
|
list(APPEND generated_sources ${expanded_files_cc})
|
||||||
|
list(APPEND generated_headers ${expanded_files_h})
|
||||||
|
|
||||||
|
endmacro(GR_EXPAND_X_CC_H)
|
||||||
|
|
||||||
|
macro(GR_EXPAND_X_CC_H_IMPL component root)
|
||||||
|
|
||||||
|
include(GrPython)
|
||||||
|
|
||||||
|
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
|
||||||
|
"#!${PYTHON_EXECUTABLE}
|
||||||
|
|
||||||
|
import sys, os, re
|
||||||
|
sys.path.append('${GR_RUNTIME_PYTHONPATH}')
|
||||||
|
os.environ['srcdir'] = '${CMAKE_CURRENT_SOURCE_DIR}'
|
||||||
|
os.chdir('${CMAKE_CURRENT_BINARY_DIR}')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import build_utils
|
||||||
|
root, inp = sys.argv[1:3]
|
||||||
|
for sig in sys.argv[3:]:
|
||||||
|
name = re.sub ('X+', sig, root)
|
||||||
|
d = build_utils.standard_dict(name, sig, '${component}')
|
||||||
|
build_utils.expand_template(d, inp, '_impl')
|
||||||
|
")
|
||||||
|
|
||||||
|
#make a list of all the generated files
|
||||||
|
unset(expanded_files_cc_impl)
|
||||||
|
unset(expanded_files_h_impl)
|
||||||
|
unset(expanded_files_h)
|
||||||
|
foreach(sig ${ARGN})
|
||||||
|
string(REGEX REPLACE "X+" ${sig} name ${root})
|
||||||
|
list(APPEND expanded_files_cc_impl ${CMAKE_CURRENT_BINARY_DIR}/${name}_impl.cc)
|
||||||
|
list(APPEND expanded_files_h_impl ${CMAKE_CURRENT_BINARY_DIR}/${name}_impl.h)
|
||||||
|
list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/../include/gnuradio/${component}/${name}.h)
|
||||||
|
endforeach(sig)
|
||||||
|
unset(name)
|
||||||
|
|
||||||
|
#create a command to generate the _impl.cc files
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${expanded_files_cc_impl}
|
||||||
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}_impl.cc.t
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
|
||||||
|
${root} ${root}_impl.cc.t ${ARGN}
|
||||||
|
)
|
||||||
|
|
||||||
|
#create a command to generate the _impl.h files
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${expanded_files_h_impl}
|
||||||
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}_impl.h.t
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
|
||||||
|
${root} ${root}_impl.h.t ${ARGN}
|
||||||
|
)
|
||||||
|
|
||||||
|
#make _impl.cc source files depend on _impl.h to force generation
|
||||||
|
set_source_files_properties(${expanded_files_cc_impl}
|
||||||
|
PROPERTIES OBJECT_DEPENDS "${expanded_files_h_impl}"
|
||||||
|
)
|
||||||
|
|
||||||
|
#make _impl.h source files depend on headers to force generation
|
||||||
|
set_source_files_properties(${expanded_files_h_impl}
|
||||||
|
PROPERTIES OBJECT_DEPENDS "${expanded_files_h}"
|
||||||
|
)
|
||||||
|
|
||||||
|
#install rules for the generated files
|
||||||
|
list(APPEND generated_sources ${expanded_files_cc_impl})
|
||||||
|
list(APPEND generated_headers ${expanded_files_h_impl})
|
||||||
|
|
||||||
|
endmacro(GR_EXPAND_X_CC_H_IMPL)
|
54
cmake/Modules/GrPlatform.cmake
Normal file
54
cmake/Modules/GrPlatform.cmake
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
# Copyright 2011 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of GNU Radio
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
if(DEFINED __INCLUDED_GR_PLATFORM_CMAKE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(__INCLUDED_GR_PLATFORM_CMAKE TRUE)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Setup additional defines for OS types
|
||||||
|
########################################################################
|
||||||
|
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
set(LINUX TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(LINUX AND EXISTS "/etc/debian_version")
|
||||||
|
set(DEBIAN TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(LINUX AND EXISTS "/etc/redhat-release")
|
||||||
|
set(REDHAT TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(LINUX AND EXISTS "/etc/slackware-version")
|
||||||
|
set(SLACKWARE TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# when the library suffix should be 64 (applies to redhat linux family)
|
||||||
|
########################################################################
|
||||||
|
if (REDHAT OR SLACKWARE)
|
||||||
|
set(LIB64_CONVENTION TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED LIB_SUFFIX AND LIB64_CONVENTION AND CMAKE_SYSTEM_PROCESSOR MATCHES "64$")
|
||||||
|
set(LIB_SUFFIX 64)
|
||||||
|
endif()
|
||||||
|
set(LIB_SUFFIX ${LIB_SUFFIX} CACHE STRING "lib directory suffix")
|
242
cmake/Modules/GrPython.cmake
Normal file
242
cmake/Modules/GrPython.cmake
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
# Copyright 2010-2011 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of GNU Radio
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
if(DEFINED __INCLUDED_GR_PYTHON_CMAKE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(__INCLUDED_GR_PYTHON_CMAKE TRUE)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Setup the python interpreter:
|
||||||
|
# This allows the user to specify a specific interpreter,
|
||||||
|
# or finds the interpreter via the built-in cmake module.
|
||||||
|
########################################################################
|
||||||
|
#this allows the user to override PYTHON_EXECUTABLE
|
||||||
|
if(PYTHON_EXECUTABLE)
|
||||||
|
|
||||||
|
set(PYTHONINTERP_FOUND TRUE)
|
||||||
|
|
||||||
|
#otherwise if not set, try to automatically find it
|
||||||
|
else(PYTHON_EXECUTABLE)
|
||||||
|
|
||||||
|
#use the built-in find script
|
||||||
|
find_package(PythonInterp 2)
|
||||||
|
|
||||||
|
#and if that fails use the find program routine
|
||||||
|
if(NOT PYTHONINTERP_FOUND)
|
||||||
|
find_program(PYTHON_EXECUTABLE NAMES python python2 python2.7 python2.6 python2.5)
|
||||||
|
if(PYTHON_EXECUTABLE)
|
||||||
|
set(PYTHONINTERP_FOUND TRUE)
|
||||||
|
endif(PYTHON_EXECUTABLE)
|
||||||
|
endif(NOT PYTHONINTERP_FOUND)
|
||||||
|
|
||||||
|
endif(PYTHON_EXECUTABLE)
|
||||||
|
|
||||||
|
if (CMAKE_CROSSCOMPILING)
|
||||||
|
set(QA_PYTHON_EXECUTABLE "/usr/bin/python")
|
||||||
|
else (CMAKE_CROSSCOMPILING)
|
||||||
|
set(QA_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE})
|
||||||
|
endif(CMAKE_CROSSCOMPILING)
|
||||||
|
|
||||||
|
#make the path to the executable appear in the cmake gui
|
||||||
|
set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter")
|
||||||
|
set(QA_PYTHON_EXECUTABLE ${QA_PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter for QA tests")
|
||||||
|
|
||||||
|
#make sure we can use -B with python (introduced in 2.6)
|
||||||
|
if(PYTHON_EXECUTABLE)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} -B -c ""
|
||||||
|
OUTPUT_QUIET ERROR_QUIET
|
||||||
|
RESULT_VARIABLE PYTHON_HAS_DASH_B_RESULT
|
||||||
|
)
|
||||||
|
if(PYTHON_HAS_DASH_B_RESULT EQUAL 0)
|
||||||
|
set(PYTHON_DASH_B "-B")
|
||||||
|
endif()
|
||||||
|
endif(PYTHON_EXECUTABLE)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Check for the existence of a python module:
|
||||||
|
# - desc a string description of the check
|
||||||
|
# - mod the name of the module to import
|
||||||
|
# - cmd an additional command to run
|
||||||
|
# - have the result variable to set
|
||||||
|
########################################################################
|
||||||
|
macro(GR_PYTHON_CHECK_MODULE desc mod cmd have)
|
||||||
|
message(STATUS "")
|
||||||
|
message(STATUS "Python checking for ${desc}")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} -c "
|
||||||
|
#########################################
|
||||||
|
try:
|
||||||
|
import ${mod}
|
||||||
|
assert ${cmd}
|
||||||
|
except ImportError, AssertionError: exit(-1)
|
||||||
|
except: pass
|
||||||
|
#########################################"
|
||||||
|
RESULT_VARIABLE ${have}
|
||||||
|
)
|
||||||
|
if(${have} EQUAL 0)
|
||||||
|
message(STATUS "Python checking for ${desc} - found")
|
||||||
|
set(${have} TRUE)
|
||||||
|
else(${have} EQUAL 0)
|
||||||
|
message(STATUS "Python checking for ${desc} - not found")
|
||||||
|
set(${have} FALSE)
|
||||||
|
endif(${have} EQUAL 0)
|
||||||
|
endmacro(GR_PYTHON_CHECK_MODULE)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Sets the python installation directory GR_PYTHON_DIR
|
||||||
|
########################################################################
|
||||||
|
if(NOT DEFINED GR_PYTHON_DIR)
|
||||||
|
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "
|
||||||
|
from distutils import sysconfig
|
||||||
|
print sysconfig.get_python_lib(plat_specific=True, prefix='')
|
||||||
|
" OUTPUT_VARIABLE GR_PYTHON_DIR OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
file(TO_CMAKE_PATH ${GR_PYTHON_DIR} GR_PYTHON_DIR)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Create an always-built target with a unique name
|
||||||
|
# Usage: GR_UNIQUE_TARGET(<description> <dependencies list>)
|
||||||
|
########################################################################
|
||||||
|
function(GR_UNIQUE_TARGET desc)
|
||||||
|
file(RELATIVE_PATH reldir ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import re, hashlib
|
||||||
|
unique = hashlib.md5('${reldir}${ARGN}').hexdigest()[:5]
|
||||||
|
print(re.sub('\\W', '_', '${desc} ${reldir} ' + unique))"
|
||||||
|
OUTPUT_VARIABLE _target OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
add_custom_target(${_target} ALL DEPENDS ${ARGN})
|
||||||
|
endfunction(GR_UNIQUE_TARGET)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Install python sources (also builds and installs byte-compiled python)
|
||||||
|
########################################################################
|
||||||
|
function(GR_PYTHON_INSTALL)
|
||||||
|
include(CMakeParseArgumentsCopy)
|
||||||
|
CMAKE_PARSE_ARGUMENTS(GR_PYTHON_INSTALL "" "DESTINATION;COMPONENT" "FILES;PROGRAMS" ${ARGN})
|
||||||
|
|
||||||
|
####################################################################
|
||||||
|
if(GR_PYTHON_INSTALL_FILES)
|
||||||
|
####################################################################
|
||||||
|
install(${ARGN}) #installs regular python files
|
||||||
|
|
||||||
|
#create a list of all generated files
|
||||||
|
unset(pysrcfiles)
|
||||||
|
unset(pycfiles)
|
||||||
|
unset(pyofiles)
|
||||||
|
foreach(pyfile ${GR_PYTHON_INSTALL_FILES})
|
||||||
|
get_filename_component(pyfile ${pyfile} ABSOLUTE)
|
||||||
|
list(APPEND pysrcfiles ${pyfile})
|
||||||
|
|
||||||
|
#determine if this file is in the source or binary directory
|
||||||
|
file(RELATIVE_PATH source_rel_path ${CMAKE_CURRENT_SOURCE_DIR} ${pyfile})
|
||||||
|
string(LENGTH "${source_rel_path}" source_rel_path_len)
|
||||||
|
file(RELATIVE_PATH binary_rel_path ${CMAKE_CURRENT_BINARY_DIR} ${pyfile})
|
||||||
|
string(LENGTH "${binary_rel_path}" binary_rel_path_len)
|
||||||
|
|
||||||
|
#and set the generated path appropriately
|
||||||
|
if(${source_rel_path_len} GREATER ${binary_rel_path_len})
|
||||||
|
set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${binary_rel_path})
|
||||||
|
else()
|
||||||
|
set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${source_rel_path})
|
||||||
|
endif()
|
||||||
|
list(APPEND pycfiles ${pygenfile}c)
|
||||||
|
list(APPEND pyofiles ${pygenfile}o)
|
||||||
|
|
||||||
|
#ensure generation path exists
|
||||||
|
get_filename_component(pygen_path ${pygenfile} PATH)
|
||||||
|
file(MAKE_DIRECTORY ${pygen_path})
|
||||||
|
|
||||||
|
endforeach(pyfile)
|
||||||
|
|
||||||
|
#the command to generate the pyc files
|
||||||
|
add_custom_command(
|
||||||
|
DEPENDS ${pysrcfiles} OUTPUT ${pycfiles}
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pycfiles}
|
||||||
|
)
|
||||||
|
|
||||||
|
#the command to generate the pyo files
|
||||||
|
add_custom_command(
|
||||||
|
DEPENDS ${pysrcfiles} OUTPUT ${pyofiles}
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} -O ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pyofiles}
|
||||||
|
)
|
||||||
|
|
||||||
|
#create install rule and add generated files to target list
|
||||||
|
set(python_install_gen_targets ${pycfiles} ${pyofiles})
|
||||||
|
install(FILES ${python_install_gen_targets}
|
||||||
|
DESTINATION ${GR_PYTHON_INSTALL_DESTINATION}
|
||||||
|
COMPONENT ${GR_PYTHON_INSTALL_COMPONENT}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
####################################################################
|
||||||
|
elseif(GR_PYTHON_INSTALL_PROGRAMS)
|
||||||
|
####################################################################
|
||||||
|
file(TO_NATIVE_PATH ${PYTHON_EXECUTABLE} pyexe_native)
|
||||||
|
|
||||||
|
if (CMAKE_CROSSCOMPILING)
|
||||||
|
set(pyexe_native "/usr/bin/env python")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(pyfile ${GR_PYTHON_INSTALL_PROGRAMS})
|
||||||
|
get_filename_component(pyfile_name ${pyfile} NAME)
|
||||||
|
get_filename_component(pyfile ${pyfile} ABSOLUTE)
|
||||||
|
string(REPLACE "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" pyexefile "${pyfile}.exe")
|
||||||
|
list(APPEND python_install_gen_targets ${pyexefile})
|
||||||
|
|
||||||
|
get_filename_component(pyexefile_path ${pyexefile} PATH)
|
||||||
|
file(MAKE_DIRECTORY ${pyexefile_path})
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${pyexefile} DEPENDS ${pyfile}
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} -c
|
||||||
|
"open('${pyexefile}','w').write('\#!${pyexe_native}\\n'+open('${pyfile}').read())"
|
||||||
|
COMMENT "Shebangin ${pyfile_name}"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
|
#on windows, python files need an extension to execute
|
||||||
|
get_filename_component(pyfile_ext ${pyfile} EXT)
|
||||||
|
if(WIN32 AND NOT pyfile_ext)
|
||||||
|
set(pyfile_name "${pyfile_name}.py")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(PROGRAMS ${pyexefile} RENAME ${pyfile_name}
|
||||||
|
DESTINATION ${GR_PYTHON_INSTALL_DESTINATION}
|
||||||
|
COMPONENT ${GR_PYTHON_INSTALL_COMPONENT}
|
||||||
|
)
|
||||||
|
endforeach(pyfile)
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
|
GR_UNIQUE_TARGET("pygen" ${python_install_gen_targets})
|
||||||
|
|
||||||
|
endfunction(GR_PYTHON_INSTALL)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Write the python helper script that generates byte code files
|
||||||
|
########################################################################
|
||||||
|
file(WRITE ${CMAKE_BINARY_DIR}/python_compile_helper.py "
|
||||||
|
import sys, py_compile
|
||||||
|
files = sys.argv[1:]
|
||||||
|
srcs, gens = files[:len(files)/2], files[len(files)/2:]
|
||||||
|
for src, gen in zip(srcs, gens):
|
||||||
|
py_compile.compile(file=src, cfile=gen, doraise=True)
|
||||||
|
")
|
251
cmake/Modules/GrSwig.cmake
Normal file
251
cmake/Modules/GrSwig.cmake
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
# Copyright 2010-2011 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of GNU Radio
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
if(DEFINED __INCLUDED_GR_SWIG_CMAKE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(__INCLUDED_GR_SWIG_CMAKE TRUE)
|
||||||
|
|
||||||
|
include(GrPython)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Builds a swig documentation file to be generated into python docstrings
|
||||||
|
# Usage: GR_SWIG_MAKE_DOCS(output_file input_path input_path....)
|
||||||
|
#
|
||||||
|
# Set the following variable to specify extra dependent targets:
|
||||||
|
# - GR_SWIG_DOCS_SOURCE_DEPS
|
||||||
|
# - GR_SWIG_DOCS_TARGET_DEPS
|
||||||
|
########################################################################
|
||||||
|
function(GR_SWIG_MAKE_DOCS output_file)
|
||||||
|
if(ENABLE_DOXYGEN)
|
||||||
|
|
||||||
|
#setup the input files variable list, quote formated
|
||||||
|
set(input_files)
|
||||||
|
unset(INPUT_PATHS)
|
||||||
|
foreach(input_path ${ARGN})
|
||||||
|
if(IS_DIRECTORY ${input_path}) #when input path is a directory
|
||||||
|
file(GLOB input_path_h_files ${input_path}/*.h)
|
||||||
|
else() #otherwise its just a file, no glob
|
||||||
|
set(input_path_h_files ${input_path})
|
||||||
|
endif()
|
||||||
|
list(APPEND input_files ${input_path_h_files})
|
||||||
|
set(INPUT_PATHS "${INPUT_PATHS} \"${input_path}\"")
|
||||||
|
endforeach(input_path)
|
||||||
|
|
||||||
|
#determine the output directory
|
||||||
|
get_filename_component(name ${output_file} NAME_WE)
|
||||||
|
get_filename_component(OUTPUT_DIRECTORY ${output_file} PATH)
|
||||||
|
set(OUTPUT_DIRECTORY ${OUTPUT_DIRECTORY}/${name}_swig_docs)
|
||||||
|
make_directory(${OUTPUT_DIRECTORY})
|
||||||
|
|
||||||
|
#generate the Doxyfile used by doxygen
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_SOURCE_DIR}/docs/doxygen/Doxyfile.swig_doc.in
|
||||||
|
${OUTPUT_DIRECTORY}/Doxyfile
|
||||||
|
@ONLY)
|
||||||
|
|
||||||
|
#Create a dummy custom command that depends on other targets
|
||||||
|
include(GrMiscUtils)
|
||||||
|
GR_GEN_TARGET_DEPS(_${name}_tag tag_deps ${GR_SWIG_DOCS_TARGET_DEPS})
|
||||||
|
|
||||||
|
#call doxygen on the Doxyfile + input headers
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${OUTPUT_DIRECTORY}/xml/index.xml
|
||||||
|
DEPENDS ${input_files} ${GR_SWIG_DOCS_SOURCE_DEPS} ${tag_deps}
|
||||||
|
COMMAND ${DOXYGEN_EXECUTABLE} ${OUTPUT_DIRECTORY}/Doxyfile
|
||||||
|
COMMENT "Generating doxygen xml for ${name} docs"
|
||||||
|
)
|
||||||
|
|
||||||
|
#call the swig_doc script on the xml files
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${output_file}
|
||||||
|
DEPENDS ${input_files} ${stamp-file} ${OUTPUT_DIRECTORY}/xml/index.xml
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
|
||||||
|
${CMAKE_SOURCE_DIR}/docs/doxygen/swig_doc.py
|
||||||
|
${OUTPUT_DIRECTORY}/xml
|
||||||
|
${output_file}
|
||||||
|
COMMENT "Generating python docstrings for ${name}"
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/docs/doxygen
|
||||||
|
)
|
||||||
|
|
||||||
|
else(ENABLE_DOXYGEN)
|
||||||
|
file(WRITE ${output_file} "\n") #no doxygen -> empty file
|
||||||
|
endif(ENABLE_DOXYGEN)
|
||||||
|
endfunction(GR_SWIG_MAKE_DOCS)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Build a swig target for the common gnuradio use case. Usage:
|
||||||
|
# GR_SWIG_MAKE(target ifile ifile ifile...)
|
||||||
|
#
|
||||||
|
# Set the following variables before calling:
|
||||||
|
# - GR_SWIG_FLAGS
|
||||||
|
# - GR_SWIG_INCLUDE_DIRS
|
||||||
|
# - GR_SWIG_LIBRARIES
|
||||||
|
# - GR_SWIG_SOURCE_DEPS
|
||||||
|
# - GR_SWIG_TARGET_DEPS
|
||||||
|
# - GR_SWIG_DOC_FILE
|
||||||
|
# - GR_SWIG_DOC_DIRS
|
||||||
|
########################################################################
|
||||||
|
macro(GR_SWIG_MAKE name)
|
||||||
|
set(ifiles ${ARGN})
|
||||||
|
|
||||||
|
# Shimming this in here to take care of a SWIG bug with handling
|
||||||
|
# vector<size_t> and vector<unsigned int> (on 32-bit machines) and
|
||||||
|
# vector<long unsigned int> (on 64-bit machines). Use this to test
|
||||||
|
# the size of size_t, then set SIZE_T_32 if it's a 32-bit machine
|
||||||
|
# or not if it's 64-bit. The logic in gr_type.i handles the rest.
|
||||||
|
INCLUDE(CheckTypeSize)
|
||||||
|
CHECK_TYPE_SIZE("size_t" SIZEOF_SIZE_T)
|
||||||
|
CHECK_TYPE_SIZE("unsigned int" SIZEOF_UINT)
|
||||||
|
if(${SIZEOF_SIZE_T} EQUAL ${SIZEOF_UINT})
|
||||||
|
list(APPEND GR_SWIG_FLAGS -DSIZE_T_32)
|
||||||
|
endif(${SIZEOF_SIZE_T} EQUAL ${SIZEOF_UINT})
|
||||||
|
|
||||||
|
#do swig doc generation if specified
|
||||||
|
if(GR_SWIG_DOC_FILE)
|
||||||
|
set(GR_SWIG_DOCS_SOURCE_DEPS ${GR_SWIG_SOURCE_DEPS})
|
||||||
|
list(APPEND GR_SWIG_DOCS_TARGET_DEPS ${GR_SWIG_TARGET_DEPS})
|
||||||
|
GR_SWIG_MAKE_DOCS(${GR_SWIG_DOC_FILE} ${GR_SWIG_DOC_DIRS})
|
||||||
|
add_custom_target(${name}_swig_doc DEPENDS ${GR_SWIG_DOC_FILE})
|
||||||
|
list(APPEND GR_SWIG_TARGET_DEPS ${name}_swig_doc ${GR_RUNTIME_SWIG_DOC_FILE})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#append additional include directories
|
||||||
|
find_package(PythonLibs 2)
|
||||||
|
list(APPEND GR_SWIG_INCLUDE_DIRS ${PYTHON_INCLUDE_PATH}) #deprecated name (now dirs)
|
||||||
|
list(APPEND GR_SWIG_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
#prepend local swig directories
|
||||||
|
list(INSERT GR_SWIG_INCLUDE_DIRS 0 ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
list(INSERT GR_SWIG_INCLUDE_DIRS 0 ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
#determine include dependencies for swig file
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE}
|
||||||
|
${CMAKE_BINARY_DIR}/get_swig_deps.py
|
||||||
|
"${ifiles}" "${GR_SWIG_INCLUDE_DIRS}"
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
OUTPUT_VARIABLE SWIG_MODULE_${name}_EXTRA_DEPS
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
#Create a dummy custom command that depends on other targets
|
||||||
|
include(GrMiscUtils)
|
||||||
|
GR_GEN_TARGET_DEPS(_${name}_swig_tag tag_deps ${GR_SWIG_TARGET_DEPS})
|
||||||
|
set(tag_file ${CMAKE_CURRENT_BINARY_DIR}/${name}.tag)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${tag_file}
|
||||||
|
DEPENDS ${GR_SWIG_SOURCE_DEPS} ${tag_deps}
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E touch ${tag_file}
|
||||||
|
)
|
||||||
|
|
||||||
|
#append the specified include directories
|
||||||
|
include_directories(${GR_SWIG_INCLUDE_DIRS})
|
||||||
|
list(APPEND SWIG_MODULE_${name}_EXTRA_DEPS ${tag_file})
|
||||||
|
|
||||||
|
#setup the swig flags with flags and include directories
|
||||||
|
set(CMAKE_SWIG_FLAGS -fvirtual -modern -keyword -w511 -module ${name} ${GR_SWIG_FLAGS})
|
||||||
|
foreach(dir ${GR_SWIG_INCLUDE_DIRS})
|
||||||
|
list(APPEND CMAKE_SWIG_FLAGS "-I${dir}")
|
||||||
|
endforeach(dir)
|
||||||
|
|
||||||
|
#set the C++ property on the swig .i file so it builds
|
||||||
|
set_source_files_properties(${ifiles} PROPERTIES CPLUSPLUS ON)
|
||||||
|
|
||||||
|
#setup the actual swig library target to be built
|
||||||
|
include(UseSWIG)
|
||||||
|
SWIG_ADD_MODULE(${name} python ${ifiles})
|
||||||
|
SWIG_LINK_LIBRARIES(${name} ${PYTHON_LIBRARIES} ${GR_SWIG_LIBRARIES})
|
||||||
|
if(${name} STREQUAL "runtime_swig")
|
||||||
|
SET_TARGET_PROPERTIES(${SWIG_MODULE_runtime_swig_REAL_NAME} PROPERTIES DEFINE_SYMBOL "gnuradio_runtime_EXPORTS")
|
||||||
|
endif(${name} STREQUAL "runtime_swig")
|
||||||
|
|
||||||
|
endmacro(GR_SWIG_MAKE)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Install swig targets generated by GR_SWIG_MAKE. Usage:
|
||||||
|
# GR_SWIG_INSTALL(
|
||||||
|
# TARGETS target target target...
|
||||||
|
# [DESTINATION destination]
|
||||||
|
# [COMPONENT component]
|
||||||
|
# )
|
||||||
|
########################################################################
|
||||||
|
macro(GR_SWIG_INSTALL)
|
||||||
|
|
||||||
|
include(CMakeParseArgumentsCopy)
|
||||||
|
CMAKE_PARSE_ARGUMENTS(GR_SWIG_INSTALL "" "DESTINATION;COMPONENT" "TARGETS" ${ARGN})
|
||||||
|
|
||||||
|
foreach(name ${GR_SWIG_INSTALL_TARGETS})
|
||||||
|
install(TARGETS ${SWIG_MODULE_${name}_REAL_NAME}
|
||||||
|
DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
|
||||||
|
COMPONENT ${GR_SWIG_INSTALL_COMPONENT}
|
||||||
|
)
|
||||||
|
|
||||||
|
include(GrPython)
|
||||||
|
GR_PYTHON_INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}.py
|
||||||
|
DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
|
||||||
|
COMPONENT ${GR_SWIG_INSTALL_COMPONENT}
|
||||||
|
)
|
||||||
|
|
||||||
|
GR_LIBTOOL(
|
||||||
|
TARGET ${SWIG_MODULE_${name}_REAL_NAME}
|
||||||
|
DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
|
||||||
|
)
|
||||||
|
|
||||||
|
endforeach(name)
|
||||||
|
|
||||||
|
endmacro(GR_SWIG_INSTALL)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Generate a python file that can determine swig dependencies.
|
||||||
|
# Used by the make macro above to determine extra dependencies.
|
||||||
|
# When you build C++, CMake figures out the header dependencies.
|
||||||
|
# This code essentially performs that logic for swig includes.
|
||||||
|
########################################################################
|
||||||
|
file(WRITE ${CMAKE_BINARY_DIR}/get_swig_deps.py "
|
||||||
|
|
||||||
|
import os, sys, re
|
||||||
|
|
||||||
|
i_include_matcher = re.compile('%(include|import)\\s*[<|\"](.*)[>|\"]')
|
||||||
|
h_include_matcher = re.compile('#(include)\\s*[<|\"](.*)[>|\"]')
|
||||||
|
include_dirs = sys.argv[2].split(';')
|
||||||
|
|
||||||
|
def get_swig_incs(file_path):
|
||||||
|
if file_path.endswith('.i'): matcher = i_include_matcher
|
||||||
|
else: matcher = h_include_matcher
|
||||||
|
file_contents = open(file_path, 'r').read()
|
||||||
|
return matcher.findall(file_contents, re.MULTILINE)
|
||||||
|
|
||||||
|
def get_swig_deps(file_path, level):
|
||||||
|
deps = [file_path]
|
||||||
|
if level == 0: return deps
|
||||||
|
for keyword, inc_file in get_swig_incs(file_path):
|
||||||
|
for inc_dir in include_dirs:
|
||||||
|
inc_path = os.path.join(inc_dir, inc_file)
|
||||||
|
if not os.path.exists(inc_path): continue
|
||||||
|
deps.extend(get_swig_deps(inc_path, level-1))
|
||||||
|
break #found, we dont search in lower prio inc dirs
|
||||||
|
return deps
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
ifiles = sys.argv[1].split(';')
|
||||||
|
deps = sum([get_swig_deps(ifile, 3) for ifile in ifiles], [])
|
||||||
|
#sys.stderr.write(';'.join(set(deps)) + '\\n\\n')
|
||||||
|
print(';'.join(set(deps)))
|
||||||
|
")
|
143
cmake/Modules/GrTest.cmake
Normal file
143
cmake/Modules/GrTest.cmake
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
# Copyright 2010-2011 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of GNU Radio
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
if(DEFINED __INCLUDED_GR_TEST_CMAKE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(__INCLUDED_GR_TEST_CMAKE TRUE)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Add a unit test and setup the environment for a unit test.
|
||||||
|
# Takes the same arguments as the ADD_TEST function.
|
||||||
|
#
|
||||||
|
# Before calling set the following variables:
|
||||||
|
# GR_TEST_TARGET_DEPS - built targets for the library path
|
||||||
|
# GR_TEST_LIBRARY_DIRS - directories for the library path
|
||||||
|
# GR_TEST_PYTHON_DIRS - directories for the python path
|
||||||
|
# GR_TEST_ENVIRONS - other environment key/value pairs
|
||||||
|
########################################################################
|
||||||
|
function(GR_ADD_TEST test_name)
|
||||||
|
|
||||||
|
#Ensure that the build exe also appears in the PATH.
|
||||||
|
list(APPEND GR_TEST_TARGET_DEPS ${ARGN})
|
||||||
|
|
||||||
|
#In the land of windows, all libraries must be in the PATH.
|
||||||
|
#Since the dependent libraries are not yet installed,
|
||||||
|
#we must manually set them in the PATH to run tests.
|
||||||
|
#The following appends the path of a target dependency.
|
||||||
|
foreach(target ${GR_TEST_TARGET_DEPS})
|
||||||
|
get_target_property(location ${target} LOCATION)
|
||||||
|
if(location)
|
||||||
|
get_filename_component(path ${location} PATH)
|
||||||
|
string(REGEX REPLACE "\\$\\(.*\\)" ${CMAKE_BUILD_TYPE} path ${path})
|
||||||
|
list(APPEND GR_TEST_LIBRARY_DIRS ${path})
|
||||||
|
endif(location)
|
||||||
|
endforeach(target)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
#SWIG generates the python library files into a subdirectory.
|
||||||
|
#Therefore, we must append this subdirectory into PYTHONPATH.
|
||||||
|
#Only do this for the python directories matching the following:
|
||||||
|
foreach(pydir ${GR_TEST_PYTHON_DIRS})
|
||||||
|
get_filename_component(name ${pydir} NAME)
|
||||||
|
if(name MATCHES "^(swig|lib|src)$")
|
||||||
|
list(APPEND GR_TEST_PYTHON_DIRS ${pydir}/${CMAKE_BUILD_TYPE})
|
||||||
|
endif()
|
||||||
|
endforeach(pydir)
|
||||||
|
endif(WIN32)
|
||||||
|
|
||||||
|
file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} srcdir)
|
||||||
|
file(TO_NATIVE_PATH "${GR_TEST_LIBRARY_DIRS}" libpath) #ok to use on dir list?
|
||||||
|
file(TO_NATIVE_PATH "${GR_TEST_PYTHON_DIRS}" pypath) #ok to use on dir list?
|
||||||
|
|
||||||
|
set(environs "VOLK_GENERIC=1" "GR_DONT_LOAD_PREFS=1" "srcdir=${srcdir}")
|
||||||
|
list(APPEND environs ${GR_TEST_ENVIRONS})
|
||||||
|
|
||||||
|
#http://www.cmake.org/pipermail/cmake/2009-May/029464.html
|
||||||
|
#Replaced this add test + set environs code with the shell script generation.
|
||||||
|
#Its nicer to be able to manually run the shell script to diagnose problems.
|
||||||
|
#ADD_TEST(${ARGV})
|
||||||
|
#SET_TESTS_PROPERTIES(${test_name} PROPERTIES ENVIRONMENT "${environs}")
|
||||||
|
|
||||||
|
if(UNIX)
|
||||||
|
set(LD_PATH_VAR "LD_LIBRARY_PATH")
|
||||||
|
if(APPLE)
|
||||||
|
set(LD_PATH_VAR "DYLD_LIBRARY_PATH")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(binpath "${CMAKE_CURRENT_BINARY_DIR}:$PATH")
|
||||||
|
list(APPEND libpath "$${LD_PATH_VAR}")
|
||||||
|
list(APPEND pypath "$PYTHONPATH")
|
||||||
|
|
||||||
|
#replace list separator with the path separator
|
||||||
|
string(REPLACE ";" ":" libpath "${libpath}")
|
||||||
|
string(REPLACE ";" ":" pypath "${pypath}")
|
||||||
|
list(APPEND environs "PATH=${binpath}" "${LD_PATH_VAR}=${libpath}" "PYTHONPATH=${pypath}")
|
||||||
|
|
||||||
|
#generate a bat file that sets the environment and runs the test
|
||||||
|
if (CMAKE_CROSSCOMPILING)
|
||||||
|
set(SHELL "/bin/sh")
|
||||||
|
else(CMAKE_CROSSCOMPILING)
|
||||||
|
find_program(SHELL sh)
|
||||||
|
endif(CMAKE_CROSSCOMPILING)
|
||||||
|
set(sh_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.sh)
|
||||||
|
file(WRITE ${sh_file} "#!${SHELL}\n")
|
||||||
|
#each line sets an environment variable
|
||||||
|
foreach(environ ${environs})
|
||||||
|
file(APPEND ${sh_file} "export ${environ}\n")
|
||||||
|
endforeach(environ)
|
||||||
|
#load the command to run with its arguments
|
||||||
|
foreach(arg ${ARGN})
|
||||||
|
file(APPEND ${sh_file} "${arg} ")
|
||||||
|
endforeach(arg)
|
||||||
|
file(APPEND ${sh_file} "\n")
|
||||||
|
|
||||||
|
#make the shell file executable
|
||||||
|
execute_process(COMMAND chmod +x ${sh_file})
|
||||||
|
|
||||||
|
add_test(${test_name} ${SHELL} ${sh_file})
|
||||||
|
|
||||||
|
endif(UNIX)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
list(APPEND libpath ${DLL_PATHS} "%PATH%")
|
||||||
|
list(APPEND pypath "%PYTHONPATH%")
|
||||||
|
|
||||||
|
#replace list separator with the path separator (escaped)
|
||||||
|
string(REPLACE ";" "\\;" libpath "${libpath}")
|
||||||
|
string(REPLACE ";" "\\;" pypath "${pypath}")
|
||||||
|
list(APPEND environs "PATH=${libpath}" "PYTHONPATH=${pypath}")
|
||||||
|
|
||||||
|
#generate a bat file that sets the environment and runs the test
|
||||||
|
set(bat_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.bat)
|
||||||
|
file(WRITE ${bat_file} "@echo off\n")
|
||||||
|
#each line sets an environment variable
|
||||||
|
foreach(environ ${environs})
|
||||||
|
file(APPEND ${bat_file} "SET ${environ}\n")
|
||||||
|
endforeach(environ)
|
||||||
|
#load the command to run with its arguments
|
||||||
|
foreach(arg ${ARGN})
|
||||||
|
file(APPEND ${bat_file} "${arg} ")
|
||||||
|
endforeach(arg)
|
||||||
|
file(APPEND ${bat_file} "\n")
|
||||||
|
|
||||||
|
add_test(${test_name} ${bat_file})
|
||||||
|
endif(WIN32)
|
||||||
|
|
||||||
|
endfunction(GR_ADD_TEST)
|
304
cmake/Modules/UseSWIG.cmake
Normal file
304
cmake/Modules/UseSWIG.cmake
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
# - SWIG module for CMake
|
||||||
|
# Defines the following macros:
|
||||||
|
# SWIG_ADD_MODULE(name language [ files ])
|
||||||
|
# - Define swig module with given name and specified language
|
||||||
|
# SWIG_LINK_LIBRARIES(name [ libraries ])
|
||||||
|
# - Link libraries to swig module
|
||||||
|
# All other macros are for internal use only.
|
||||||
|
# To get the actual name of the swig module,
|
||||||
|
# use: ${SWIG_MODULE_${name}_REAL_NAME}.
|
||||||
|
# Set Source files properties such as CPLUSPLUS and SWIG_FLAGS to specify
|
||||||
|
# special behavior of SWIG. Also global CMAKE_SWIG_FLAGS can be used to add
|
||||||
|
# special flags to all swig calls.
|
||||||
|
# Another special variable is CMAKE_SWIG_OUTDIR, it allows one to specify
|
||||||
|
# where to write all the swig generated module (swig -outdir option)
|
||||||
|
# The name-specific variable SWIG_MODULE_<name>_EXTRA_DEPS may be used
|
||||||
|
# to specify extra dependencies for the generated modules.
|
||||||
|
# If the source file generated by swig need some special flag you can use
|
||||||
|
# set_source_files_properties( ${swig_generated_file_fullname}
|
||||||
|
# PROPERTIES COMPILE_FLAGS "-bla")
|
||||||
|
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# Copyright 2004-2009 Kitware, Inc.
|
||||||
|
# Copyright 2009 Mathieu Malaterre <mathieu.malaterre@gmail.com>
|
||||||
|
#
|
||||||
|
# Distributed under the OSI-approved BSD License (the "License");
|
||||||
|
# see accompanying file Copyright.txt for details.
|
||||||
|
#
|
||||||
|
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||||
|
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
# See the License for more information.
|
||||||
|
#=============================================================================
|
||||||
|
# (To distribute this file outside of CMake, substitute the full
|
||||||
|
# License text for the above reference.)
|
||||||
|
|
||||||
|
set(SWIG_CXX_EXTENSION "cxx")
|
||||||
|
set(SWIG_EXTRA_LIBRARIES "")
|
||||||
|
|
||||||
|
set(SWIG_PYTHON_EXTRA_FILE_EXTENSION "py")
|
||||||
|
|
||||||
|
#
|
||||||
|
# For given swig module initialize variables associated with it
|
||||||
|
#
|
||||||
|
macro(SWIG_MODULE_INITIALIZE name language)
|
||||||
|
string(TOUPPER "${language}" swig_uppercase_language)
|
||||||
|
string(TOLOWER "${language}" swig_lowercase_language)
|
||||||
|
set(SWIG_MODULE_${name}_LANGUAGE "${swig_uppercase_language}")
|
||||||
|
set(SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG "${swig_lowercase_language}")
|
||||||
|
|
||||||
|
set(SWIG_MODULE_${name}_REAL_NAME "${name}")
|
||||||
|
if("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "UNKNOWN")
|
||||||
|
message(FATAL_ERROR "SWIG Error: Language \"${language}\" not found")
|
||||||
|
elseif("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "PYTHON")
|
||||||
|
# when swig is used without the -interface it will produce in the module.py
|
||||||
|
# a 'import _modulename' statement, which implies having a corresponding
|
||||||
|
# _modulename.so (*NIX), _modulename.pyd (Win32).
|
||||||
|
set(SWIG_MODULE_${name}_REAL_NAME "_${name}")
|
||||||
|
elseif("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "PERL")
|
||||||
|
set(SWIG_MODULE_${name}_EXTRA_FLAGS "-shadow")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#
|
||||||
|
# For a given language, input file, and output file, determine extra files that
|
||||||
|
# will be generated. This is internal swig macro.
|
||||||
|
#
|
||||||
|
|
||||||
|
macro(SWIG_GET_EXTRA_OUTPUT_FILES language outfiles generatedpath infile)
|
||||||
|
set(${outfiles} "")
|
||||||
|
get_source_file_property(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename
|
||||||
|
${infile} SWIG_MODULE_NAME)
|
||||||
|
if(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename STREQUAL "NOTFOUND")
|
||||||
|
get_filename_component(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename "${infile}" NAME_WE)
|
||||||
|
endif()
|
||||||
|
foreach(it ${SWIG_${language}_EXTRA_FILE_EXTENSION})
|
||||||
|
set(${outfiles} ${${outfiles}}
|
||||||
|
"${generatedpath}/${SWIG_GET_EXTRA_OUTPUT_FILES_module_basename}.${it}")
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Take swig (*.i) file and add proper custom commands for it
|
||||||
|
#
|
||||||
|
macro(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
|
||||||
|
set(swig_full_infile ${infile})
|
||||||
|
get_filename_component(swig_source_file_path "${infile}" PATH)
|
||||||
|
get_filename_component(swig_source_file_name_we "${infile}" NAME_WE)
|
||||||
|
get_source_file_property(swig_source_file_generated ${infile} GENERATED)
|
||||||
|
get_source_file_property(swig_source_file_cplusplus ${infile} CPLUSPLUS)
|
||||||
|
get_source_file_property(swig_source_file_flags ${infile} SWIG_FLAGS)
|
||||||
|
if("${swig_source_file_flags}" STREQUAL "NOTFOUND")
|
||||||
|
set(swig_source_file_flags "")
|
||||||
|
endif()
|
||||||
|
set(swig_source_file_fullname "${infile}")
|
||||||
|
if(${swig_source_file_path} MATCHES "^${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
string(REGEX REPLACE
|
||||||
|
"^${CMAKE_CURRENT_SOURCE_DIR}" ""
|
||||||
|
swig_source_file_relative_path
|
||||||
|
"${swig_source_file_path}")
|
||||||
|
else()
|
||||||
|
if(${swig_source_file_path} MATCHES "^${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
|
string(REGEX REPLACE
|
||||||
|
"^${CMAKE_CURRENT_BINARY_DIR}" ""
|
||||||
|
swig_source_file_relative_path
|
||||||
|
"${swig_source_file_path}")
|
||||||
|
set(swig_source_file_generated 1)
|
||||||
|
else()
|
||||||
|
set(swig_source_file_relative_path "${swig_source_file_path}")
|
||||||
|
if(swig_source_file_generated)
|
||||||
|
set(swig_source_file_fullname "${CMAKE_CURRENT_BINARY_DIR}/${infile}")
|
||||||
|
else()
|
||||||
|
set(swig_source_file_fullname "${CMAKE_CURRENT_SOURCE_DIR}/${infile}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(swig_generated_file_fullname
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
|
if(swig_source_file_relative_path)
|
||||||
|
set(swig_generated_file_fullname
|
||||||
|
"${swig_generated_file_fullname}/${swig_source_file_relative_path}")
|
||||||
|
endif()
|
||||||
|
# If CMAKE_SWIG_OUTDIR was specified then pass it to -outdir
|
||||||
|
if(CMAKE_SWIG_OUTDIR)
|
||||||
|
set(swig_outdir ${CMAKE_SWIG_OUTDIR})
|
||||||
|
else()
|
||||||
|
set(swig_outdir ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
endif()
|
||||||
|
SWIG_GET_EXTRA_OUTPUT_FILES(${SWIG_MODULE_${name}_LANGUAGE}
|
||||||
|
swig_extra_generated_files
|
||||||
|
"${swig_outdir}"
|
||||||
|
"${infile}")
|
||||||
|
set(swig_generated_file_fullname
|
||||||
|
"${swig_generated_file_fullname}/${swig_source_file_name_we}")
|
||||||
|
# add the language into the name of the file (i.e. TCL_wrap)
|
||||||
|
# this allows for the same .i file to be wrapped into different languages
|
||||||
|
set(swig_generated_file_fullname
|
||||||
|
"${swig_generated_file_fullname}${SWIG_MODULE_${name}_LANGUAGE}_wrap")
|
||||||
|
|
||||||
|
if(swig_source_file_cplusplus)
|
||||||
|
set(swig_generated_file_fullname
|
||||||
|
"${swig_generated_file_fullname}.${SWIG_CXX_EXTENSION}")
|
||||||
|
else()
|
||||||
|
set(swig_generated_file_fullname
|
||||||
|
"${swig_generated_file_fullname}.c")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Shut up some warnings from poor SWIG code generation that we
|
||||||
|
# can do nothing about, when this flag is available
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
check_cxx_compiler_flag("-Wno-unused-but-set-variable" HAVE_WNO_UNUSED_BUT_SET_VARIABLE)
|
||||||
|
if(HAVE_WNO_UNUSED_BUT_SET_VARIABLE)
|
||||||
|
set_source_files_properties(${swig_generated_file_fullname}
|
||||||
|
PROPERTIES COMPILE_FLAGS "-Wno-unused-but-set-variable")
|
||||||
|
endif(HAVE_WNO_UNUSED_BUT_SET_VARIABLE)
|
||||||
|
|
||||||
|
get_directory_property(cmake_include_directories INCLUDE_DIRECTORIES)
|
||||||
|
set(swig_include_dirs)
|
||||||
|
foreach(it ${cmake_include_directories})
|
||||||
|
set(swig_include_dirs ${swig_include_dirs} "-I${it}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(swig_special_flags)
|
||||||
|
# default is c, so add c++ flag if it is c++
|
||||||
|
if(swig_source_file_cplusplus)
|
||||||
|
set(swig_special_flags ${swig_special_flags} "-c++")
|
||||||
|
endif()
|
||||||
|
set(swig_extra_flags)
|
||||||
|
if(SWIG_MODULE_${name}_EXTRA_FLAGS)
|
||||||
|
set(swig_extra_flags ${swig_extra_flags} ${SWIG_MODULE_${name}_EXTRA_FLAGS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# hack to work around CMake bug in add_custom_command with multiple OUTPUT files
|
||||||
|
|
||||||
|
file(RELATIVE_PATH reldir ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} -c "import re, hashlib
|
||||||
|
unique = hashlib.md5('${reldir}${ARGN}').hexdigest()[:5]
|
||||||
|
print(re.sub('\\W', '_', '${name} ${reldir} ' + unique))"
|
||||||
|
OUTPUT_VARIABLE _target OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
)
|
||||||
|
|
||||||
|
file(
|
||||||
|
WRITE ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp.in
|
||||||
|
"int main(void){return 0;}\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
# create dummy dependencies
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp
|
||||||
|
DEPENDS "${swig_source_file_fullname}" ${SWIG_MODULE_${name}_EXTRA_DEPS}
|
||||||
|
COMMENT ""
|
||||||
|
)
|
||||||
|
|
||||||
|
# create the dummy target
|
||||||
|
add_executable(${_target} ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp)
|
||||||
|
|
||||||
|
# add a custom command to the dummy target
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${_target}
|
||||||
|
# Let's create the ${swig_outdir} at execution time, in case dir contains $(OutDir)
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${swig_outdir}
|
||||||
|
COMMAND "${SWIG_EXECUTABLE}"
|
||||||
|
ARGS "-${SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG}"
|
||||||
|
${swig_source_file_flags}
|
||||||
|
${CMAKE_SWIG_FLAGS}
|
||||||
|
-outdir ${swig_outdir}
|
||||||
|
${swig_special_flags}
|
||||||
|
${swig_extra_flags}
|
||||||
|
${swig_include_dirs}
|
||||||
|
-o "${swig_generated_file_fullname}"
|
||||||
|
"${swig_source_file_fullname}"
|
||||||
|
COMMENT "Swig source"
|
||||||
|
)
|
||||||
|
|
||||||
|
#add dummy independent dependencies from the _target to each file
|
||||||
|
#that will be generated by the SWIG command above
|
||||||
|
|
||||||
|
set(${outfiles} "${swig_generated_file_fullname}" ${swig_extra_generated_files})
|
||||||
|
|
||||||
|
foreach(swig_gen_file ${${outfiles}})
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${swig_gen_file}
|
||||||
|
COMMAND ""
|
||||||
|
DEPENDS ${_target}
|
||||||
|
COMMENT ""
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set_source_files_properties(
|
||||||
|
${outfiles} PROPERTIES GENERATED 1
|
||||||
|
)
|
||||||
|
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create Swig module
|
||||||
|
#
|
||||||
|
macro(SWIG_ADD_MODULE name language)
|
||||||
|
SWIG_MODULE_INITIALIZE(${name} ${language})
|
||||||
|
set(swig_dot_i_sources)
|
||||||
|
set(swig_other_sources)
|
||||||
|
foreach(it ${ARGN})
|
||||||
|
if(${it} MATCHES ".*\\.i$")
|
||||||
|
set(swig_dot_i_sources ${swig_dot_i_sources} "${it}")
|
||||||
|
else()
|
||||||
|
set(swig_other_sources ${swig_other_sources} "${it}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(swig_generated_sources)
|
||||||
|
foreach(it ${swig_dot_i_sources})
|
||||||
|
SWIG_ADD_SOURCE_TO_MODULE(${name} swig_generated_source ${it})
|
||||||
|
set(swig_generated_sources ${swig_generated_sources} "${swig_generated_source}")
|
||||||
|
endforeach()
|
||||||
|
get_directory_property(swig_extra_clean_files ADDITIONAL_MAKE_CLEAN_FILES)
|
||||||
|
set_directory_properties(PROPERTIES
|
||||||
|
ADDITIONAL_MAKE_CLEAN_FILES "${swig_extra_clean_files};${swig_generated_sources}")
|
||||||
|
add_library(${SWIG_MODULE_${name}_REAL_NAME}
|
||||||
|
MODULE
|
||||||
|
${swig_generated_sources}
|
||||||
|
${swig_other_sources})
|
||||||
|
string(TOLOWER "${language}" swig_lowercase_language)
|
||||||
|
if ("${swig_lowercase_language}" STREQUAL "java")
|
||||||
|
if (APPLE)
|
||||||
|
# In java you want:
|
||||||
|
# System.loadLibrary("LIBRARY");
|
||||||
|
# then JNI will look for a library whose name is platform dependent, namely
|
||||||
|
# MacOS : libLIBRARY.jnilib
|
||||||
|
# Windows: LIBRARY.dll
|
||||||
|
# Linux : libLIBRARY.so
|
||||||
|
set_target_properties (${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".jnilib")
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
if ("${swig_lowercase_language}" STREQUAL "python")
|
||||||
|
# this is only needed for the python case where a _modulename.so is generated
|
||||||
|
set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "")
|
||||||
|
# Python extension modules on Windows must have the extension ".pyd"
|
||||||
|
# instead of ".dll" as of Python 2.5. Older python versions do support
|
||||||
|
# this suffix.
|
||||||
|
# http://docs.python.org/whatsnew/ports.html#SECTION0001510000000000000000
|
||||||
|
# <quote>
|
||||||
|
# Windows: .dll is no longer supported as a filename extension for extension modules.
|
||||||
|
# .pyd is now the only filename extension that will be searched for.
|
||||||
|
# </quote>
|
||||||
|
if(WIN32 AND NOT CYGWIN)
|
||||||
|
set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".pyd")
|
||||||
|
endif()
|
||||||
|
endif ()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Like TARGET_LINK_LIBRARIES but for swig modules
|
||||||
|
#
|
||||||
|
macro(SWIG_LINK_LIBRARIES name)
|
||||||
|
if(SWIG_MODULE_${name}_REAL_NAME)
|
||||||
|
target_link_libraries(${SWIG_MODULE_${name}_REAL_NAME} ${ARGN})
|
||||||
|
else()
|
||||||
|
message(SEND_ERROR "Cannot find Swig library \"${name}\".")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
@ -1,31 +0,0 @@
|
|||||||
INCLUDE(FindPkgConfig)
|
|
||||||
PKG_CHECK_MODULES(PC_AIR_MODES air_modes)
|
|
||||||
|
|
||||||
FIND_PATH(
|
|
||||||
AIR_MODES_INCLUDE_DIRS
|
|
||||||
NAMES air_modes/api.h
|
|
||||||
HINTS $ENV{AIR_MODES_DIR}/include
|
|
||||||
${PC_AIR_MODES_INCLUDEDIR}
|
|
||||||
PATHS ${CMAKE_INSTALL_PREFIX}/include
|
|
||||||
/usr/local/include
|
|
||||||
/usr/include
|
|
||||||
)
|
|
||||||
|
|
||||||
FIND_LIBRARY(
|
|
||||||
AIR_MODES_LIBRARIES
|
|
||||||
NAMES gnuradio-air-modes
|
|
||||||
HINTS $ENV{AIR_MODES_DIR}/lib
|
|
||||||
${PC_AIR_MODES_LIBDIR}
|
|
||||||
PATHS ${CMAKE_INSTALL_PREFIX}/lib
|
|
||||||
${CMAKE_INSTALL_PREFIX}/lib64
|
|
||||||
/usr/local/lib
|
|
||||||
/usr/local/lib64
|
|
||||||
/usr/lib
|
|
||||||
/usr/lib64
|
|
||||||
)
|
|
||||||
|
|
||||||
include("${CMAKE_CURRENT_LIST_DIR}/air_modesTarget.cmake")
|
|
||||||
|
|
||||||
INCLUDE(FindPackageHandleStandardArgs)
|
|
||||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(AIR_MODES DEFAULT_MSG AIR_MODES_LIBRARIES AIR_MODES_INCLUDE_DIRS)
|
|
||||||
MARK_AS_ADVANCED(AIR_MODES_LIBRARIES AIR_MODES_INCLUDE_DIRS)
|
|
@ -1,26 +0,0 @@
|
|||||||
# Copyright 2018 Free Software Foundation, Inc.
|
|
||||||
#
|
|
||||||
# This file is part of GNU Radio
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
include(CMakeFindDependencyMacro)
|
|
||||||
|
|
||||||
set(target_deps "@TARGET_DEPENDENCIES@")
|
|
||||||
foreach(dep IN LISTS target_deps)
|
|
||||||
find_dependency(${dep})
|
|
||||||
endforeach()
|
|
||||||
include("${CMAKE_CURRENT_LIST_DIR}/@TARGET@Targets.cmake")
|
|
@ -261,22 +261,6 @@ SUBGROUPING = YES
|
|||||||
|
|
||||||
TYPEDEF_HIDES_STRUCT = NO
|
TYPEDEF_HIDES_STRUCT = NO
|
||||||
|
|
||||||
# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
|
|
||||||
# determine which symbols to keep in memory and which to flush to disk.
|
|
||||||
# When the cache is full, less often used symbols will be written to disk.
|
|
||||||
# For small to medium size projects (<1000 input files) the default value is
|
|
||||||
# probably good enough. For larger projects a too small cache size can cause
|
|
||||||
# doxygen to be busy swapping symbols to and from disk most of the time
|
|
||||||
# causing a significant performance penality.
|
|
||||||
# If the system has enough physical memory increasing the cache will improve the
|
|
||||||
# performance by keeping more symbols in memory. Note that the value works on
|
|
||||||
# a logarithmic scale so increasing the size by one will rougly double the
|
|
||||||
# memory usage. The cache size is given by this formula:
|
|
||||||
# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
|
|
||||||
# corresponding to a cache size of 2^16 = 65536 symbols
|
|
||||||
|
|
||||||
SYMBOL_CACHE_SIZE = 4
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Build related configuration options
|
# Build related configuration options
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
@ -455,12 +439,6 @@ MAX_INITIALIZER_LINES = 30
|
|||||||
|
|
||||||
SHOW_USED_FILES = YES
|
SHOW_USED_FILES = YES
|
||||||
|
|
||||||
# If the sources in your project are distributed over multiple directories
|
|
||||||
# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
|
|
||||||
# in the documentation. The default is NO.
|
|
||||||
|
|
||||||
SHOW_DIRECTORIES = NO
|
|
||||||
|
|
||||||
# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
|
# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
|
||||||
# This will remove the Files entry from the Quick Index and from the
|
# This will remove the Files entry from the Quick Index and from the
|
||||||
# Folder Tree View (if specified). The default is YES.
|
# Folder Tree View (if specified). The default is YES.
|
||||||
@ -807,12 +785,6 @@ HTML_FOOTER =
|
|||||||
|
|
||||||
HTML_STYLESHEET =
|
HTML_STYLESHEET =
|
||||||
|
|
||||||
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
|
|
||||||
# files or namespaces will be aligned in HTML using tables. If set to
|
|
||||||
# NO a bullet list will be used.
|
|
||||||
|
|
||||||
HTML_ALIGN_MEMBERS = YES
|
|
||||||
|
|
||||||
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
|
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
|
||||||
# documentation will contain sections that can be hidden and shown after the
|
# documentation will contain sections that can be hidden and shown after the
|
||||||
# page has loaded. For this to work a browser that supports
|
# page has loaded. For this to work a browser that supports
|
||||||
@ -1127,18 +1099,6 @@ GENERATE_XML = @enable_xml_docs@
|
|||||||
|
|
||||||
XML_OUTPUT = xml
|
XML_OUTPUT = xml
|
||||||
|
|
||||||
# The XML_SCHEMA tag can be used to specify an XML schema,
|
|
||||||
# which can be used by a validating XML parser to check the
|
|
||||||
# syntax of the XML files.
|
|
||||||
|
|
||||||
XML_SCHEMA =
|
|
||||||
|
|
||||||
# The XML_DTD tag can be used to specify an XML DTD,
|
|
||||||
# which can be used by a validating XML parser to check the
|
|
||||||
# syntax of the XML files.
|
|
||||||
|
|
||||||
XML_DTD =
|
|
||||||
|
|
||||||
# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
|
# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
|
||||||
# dump the program listings (including syntax highlighting
|
# dump the program listings (including syntax highlighting
|
||||||
# and cross-referencing information) to the XML output. Note that
|
# and cross-referencing information) to the XML output. Note that
|
||||||
@ -1344,7 +1304,7 @@ HAVE_DOT = @HAVE_DOT@
|
|||||||
# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
|
# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
|
||||||
# containing the font.
|
# containing the font.
|
||||||
|
|
||||||
DOT_FONTNAME = FreeSans
|
#DOT_FONTNAME = FreeSans
|
||||||
|
|
||||||
# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
|
# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
|
||||||
# The default size is 10pt.
|
# The default size is 10pt.
|
||||||
|
@ -37,11 +37,11 @@ class AIR_MODES_API preamble : virtual public gr::block
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef boost::shared_ptr<preamble> sptr;
|
typedef boost::shared_ptr<preamble> sptr;
|
||||||
static sptr make(float channel_rate, float threshold_db);
|
static sptr make(int channel_rate, float threshold_db);
|
||||||
|
|
||||||
virtual void set_rate(float channel_rate) = 0;
|
virtual void set_rate(int channel_rate) = 0;
|
||||||
virtual void set_threshold(float threshold_db) = 0;
|
virtual void set_threshold(float threshold_db) = 0;
|
||||||
virtual float get_rate(void) = 0;
|
virtual int get_rate(void) = 0;
|
||||||
virtual float get_threshold(void) = 0;
|
virtual float get_threshold(void) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,29 +27,34 @@ add_library(air_modes SHARED
|
|||||||
slicer_impl.cc
|
slicer_impl.cc
|
||||||
modes_crc.cc
|
modes_crc.cc
|
||||||
)
|
)
|
||||||
target_link_libraries(air_modes gnuradio::gnuradio-runtime)
|
target_link_libraries(air_modes ${Boost_LIBRARIES} ${GNURADIO_RUNTIME_LIBRARIES})
|
||||||
target_include_directories(air_modes
|
|
||||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
|
|
||||||
PUBLIC $<INSTALL_INTERFACE:include>
|
|
||||||
)
|
|
||||||
set_target_properties(air_modes PROPERTIES DEFINE_SYMBOL "AIR_MODES_EXPORTS")
|
set_target_properties(air_modes PROPERTIES DEFINE_SYMBOL "AIR_MODES_EXPORTS")
|
||||||
set_target_properties(air_modes PROPERTIES SOVERSION "${VERSION_MAJOR}")
|
set_target_properties(air_modes PROPERTIES SOVERSION "${gr-gr-air-modes_VERSION_MAJOR}")
|
||||||
set_target_properties(air_modes PROPERTIES VERSION "${VERSION_MAJOR}.${VERSION_MINOR}")
|
set_target_properties(air_modes PROPERTIES VERSION "${gr-gr-air-modes_VERSION_MAJOR}.${gr-gr-air-modes_VERSION_MINOR}")
|
||||||
|
|
||||||
if(APPLE)
|
|
||||||
set_target_properties(air_modes PROPERTIES
|
|
||||||
INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib"
|
|
||||||
)
|
|
||||||
endif(APPLE)
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
# Install built library files
|
# Install built library files
|
||||||
########################################################################
|
########################################################################
|
||||||
include(GrMiscUtils)
|
install(TARGETS air_modes
|
||||||
GR_LIBRARY_FOO(air_modes)
|
LIBRARY DESTINATION lib${LIB_SUFFIX} # .so/.dylib file
|
||||||
|
ARCHIVE DESTINATION lib${LIB_SUFFIX} # .lib file
|
||||||
|
RUNTIME DESTINATION bin # .dll file
|
||||||
|
)
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
# Print summary
|
# Build and register unit test
|
||||||
########################################################################
|
########################################################################
|
||||||
message(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}")
|
#find_package(Boost COMPONENTS unit_test_framework)
|
||||||
message(STATUS "Building for version: ${VERSION} / ${LIBVER}")
|
|
||||||
|
#include(GrTest)
|
||||||
|
#set(GR_TEST_TARGET_DEPS gnuradio-gr-air-modes)
|
||||||
|
#turn each test cpp file into an executable with an int main() function
|
||||||
|
#add_definitions(-DBOOST_TEST_DYN_LINK -DBOOST_TEST_MAIN)
|
||||||
|
|
||||||
|
#add_executable(qa_gr-air-modes_square_ff qa_gr-air-modes_square_ff.cc)
|
||||||
|
#target_link_libraries(qa_gr-air-modes_square_ff gnuradio-gr-air-modes ${Boost_LIBRARIES})
|
||||||
|
#GR_ADD_TEST(qa_gr-air-modes_square_ff qa_gr-air-modes_square_ff)
|
||||||
|
|
||||||
|
#add_executable(qa_gr-air-modes_square2_ff qa_gr-air-modes_square2_ff.cc)
|
||||||
|
#target_link_libraries(qa_gr-air-modes_square2_ff gnuradio-gr-air-modes ${Boost_LIBRARIES})
|
||||||
|
#GR_ADD_TEST(qa_gr-air-modes_square2_ff qa_gr-air-modes_square2_ff)
|
||||||
|
@ -34,11 +34,11 @@
|
|||||||
|
|
||||||
namespace gr {
|
namespace gr {
|
||||||
|
|
||||||
air_modes::preamble::sptr air_modes::preamble::make(float channel_rate, float threshold_db) {
|
air_modes::preamble::sptr air_modes::preamble::make(int channel_rate, float threshold_db) {
|
||||||
return gnuradio::get_initial_sptr(new air_modes::preamble_impl(channel_rate, threshold_db));
|
return gnuradio::get_initial_sptr(new air_modes::preamble_impl(channel_rate, threshold_db));
|
||||||
}
|
}
|
||||||
|
|
||||||
air_modes::preamble_impl::preamble_impl(float channel_rate, float threshold_db) :
|
air_modes::preamble_impl::preamble_impl(int channel_rate, float threshold_db) :
|
||||||
gr::block ("preamble",
|
gr::block ("preamble",
|
||||||
gr::io_signature::make2 (2, 2, sizeof(float), sizeof(float)), //stream 0 is received data, stream 1 is moving average for reference
|
gr::io_signature::make2 (2, 2, sizeof(float), sizeof(float)), //stream 0 is received data, stream 1 is moving average for reference
|
||||||
gr::io_signature::make (1, 1, sizeof(float))) //the output soft symbols
|
gr::io_signature::make (1, 1, sizeof(float))) //the output soft symbols
|
||||||
@ -53,11 +53,11 @@ air_modes::preamble_impl::preamble_impl(float channel_rate, float threshold_db)
|
|||||||
d_key = pmt::string_to_symbol("preamble_found");
|
d_key = pmt::string_to_symbol("preamble_found");
|
||||||
}
|
}
|
||||||
|
|
||||||
void air_modes::preamble_impl::set_rate(float channel_rate) {
|
void air_modes::preamble_impl::set_rate(int channel_rate) {
|
||||||
d_samples_per_chip = channel_rate / d_chip_rate;
|
d_samples_per_chip = channel_rate / d_chip_rate;
|
||||||
d_samples_per_symbol = d_samples_per_chip * 2;
|
d_samples_per_symbol = d_samples_per_chip * 2;
|
||||||
d_check_width = 120 * d_samples_per_symbol;
|
d_check_width = 120 * d_samples_per_symbol;
|
||||||
d_sample_rate = channel_rate;
|
d_secs_per_sample = 1.0/channel_rate;
|
||||||
set_output_multiple(1+d_check_width*2);
|
set_output_multiple(1+d_check_width*2);
|
||||||
set_history(d_samples_per_symbol);
|
set_history(d_samples_per_symbol);
|
||||||
}
|
}
|
||||||
@ -71,8 +71,8 @@ float air_modes::preamble_impl::get_threshold(void) {
|
|||||||
return d_threshold_db;
|
return d_threshold_db;
|
||||||
}
|
}
|
||||||
|
|
||||||
float air_modes::preamble_impl::get_rate(void) {
|
int air_modes::preamble_impl::get_rate(void) {
|
||||||
return d_sample_rate;
|
return d_samples_per_chip * d_chip_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void integrate_and_dump(float *out, const float *in, int chips, int samps_per_chip) {
|
static void integrate_and_dump(float *out, const float *in, int chips, int samps_per_chip) {
|
||||||
@ -97,42 +97,19 @@ static double correlate_preamble(const float *in, int samples_per_chip) {
|
|||||||
return corr;
|
return corr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pmt::pmt_t tag_to_timestamp(gr::tag_t tstamp, uint64_t abs_sample_cnt, int rate) {
|
//todo: make it return a pair of some kind, otherwise you can lose precision
|
||||||
uint64_t last_whole_stamp;
|
static double tag_to_timestamp(gr::tag_t tstamp, uint64_t abs_sample_cnt, double secs_per_sample) {
|
||||||
|
uint64_t ts_sample, last_whole_stamp;
|
||||||
double last_frac_stamp;
|
double last_frac_stamp;
|
||||||
pmt::pmt_t tstime = pmt::make_tuple(pmt::from_uint64(0), pmt::from_double(0));
|
|
||||||
if(tstamp.key == NULL
|
|
||||||
|| !pmt::is_symbol(tstamp.key)
|
|
||||||
|| pmt::symbol_to_string(tstamp.key) != "rx_time") {
|
|
||||||
last_whole_stamp = 0;
|
|
||||||
last_frac_stamp = 0;
|
|
||||||
} else {
|
|
||||||
last_whole_stamp = pmt::to_uint64(pmt::tuple_ref(tstamp.value, 0));
|
|
||||||
last_frac_stamp = pmt::to_double(pmt::tuple_ref(tstamp.value, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
//the timestamp tag has tstamp.offset, the sample index of the timestamp tag
|
if(tstamp.key == NULL || pmt::symbol_to_string(tstamp.key) != "rx_time") return 0;
|
||||||
//also tstamp.value, a pmt pair with (uint64, double) representing int and
|
|
||||||
//fractional timestamp, respectively.
|
|
||||||
//this function also gets an abs_sample_cnt which represents the sample count to
|
|
||||||
//find a timestamp for. sps is obviously samples per second.
|
|
||||||
//
|
|
||||||
//so (abs_sample_cnt - tstamp.offset) is the delay we apply to the tag
|
|
||||||
// int((abs_sample_cnt - tstamp.offset)/sps) is the integer offset
|
|
||||||
// (abs_sample_cnt - tstamp.offset)/sps is the fractional offset
|
|
||||||
|
|
||||||
uint64_t int_offset = (abs_sample_cnt - tstamp.offset)/rate;
|
last_whole_stamp = pmt::to_uint64(pmt::tuple_ref(tstamp.value, 0));
|
||||||
double frac_offset = ((abs_sample_cnt - tstamp.offset) % rate) / double(rate);
|
last_frac_stamp = pmt::to_double(pmt::tuple_ref(tstamp.value, 1));
|
||||||
|
ts_sample = tstamp.offset;
|
||||||
uint64_t abs_whole = last_whole_stamp + int_offset;
|
|
||||||
double abs_frac = last_frac_stamp + frac_offset;
|
|
||||||
if(abs_frac > 1.0f) {
|
|
||||||
abs_frac -= 1.0f;
|
|
||||||
abs_whole += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
tstime = pmt::make_tuple(pmt::from_uint64(abs_whole), pmt::from_double(abs_frac));
|
|
||||||
|
|
||||||
|
double tstime = double(abs_sample_cnt * secs_per_sample) + last_whole_stamp + last_frac_stamp;
|
||||||
|
if(0) std::cout << "HEY WE GOT A STAMP AT " << tstime << " TICKS AT SAMPLE " << ts_sample << " ABS SAMPLE CNT IS " << abs_sample_cnt << std::endl;
|
||||||
return tstime;
|
return tstime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +124,7 @@ int air_modes::preamble_impl::general_work(int noutput_items,
|
|||||||
int mininputs = std::min(ninput_items[0], ninput_items[1]); //they should be matched but let's be safe
|
int mininputs = std::min(ninput_items[0], ninput_items[1]); //they should be matched but let's be safe
|
||||||
//round number of input samples down to nearest d_samples_per_chip
|
//round number of input samples down to nearest d_samples_per_chip
|
||||||
//we also subtract off d_samples_per_chip to allow the bit center finder some leeway
|
//we also subtract off d_samples_per_chip to allow the bit center finder some leeway
|
||||||
const int ninputs = std::max(mininputs - (mininputs % int(d_samples_per_chip)) - int(d_samples_per_chip), 0);
|
const int ninputs = std::max(mininputs - (mininputs % d_samples_per_chip) - d_samples_per_chip, 0);
|
||||||
if (ninputs <= 0) { consume_each(0); return 0; }
|
if (ninputs <= 0) { consume_each(0); return 0; }
|
||||||
|
|
||||||
float *out = (float *) output_items[0];
|
float *out = (float *) output_items[0];
|
||||||
@ -217,20 +194,22 @@ int air_modes::preamble_impl::general_work(int noutput_items,
|
|||||||
|
|
||||||
//all right i'm prepared to call this a preamble
|
//all right i'm prepared to call this a preamble
|
||||||
for(int j=0; j<240; j++) {
|
for(int j=0; j<240; j++) {
|
||||||
out[j] = in[i+int(j*d_samples_per_chip)] - inavg[i];
|
out[j] = in[i+j*d_samples_per_chip] - inavg[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the timestamp of the preamble
|
//get the timestamp of the preamble
|
||||||
pmt::pmt_t tstamp = tag_to_timestamp(d_timestamp, abs_sample_cnt + i, d_sample_rate);
|
double tstamp = tag_to_timestamp(d_timestamp, abs_sample_cnt + i, d_secs_per_sample);
|
||||||
|
|
||||||
//now tag the preamble
|
//now tag the preamble
|
||||||
add_item_tag(0, //stream ID
|
add_item_tag(0, //stream ID
|
||||||
nitems_written(0), //sample
|
nitems_written(0), //sample
|
||||||
d_key, //frame_info
|
d_key, //frame_info
|
||||||
tstamp,
|
pmt::from_double(tstamp),
|
||||||
d_me //block src id
|
d_me //block src id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//std::cout << "PREAMBLE" << std::endl;
|
||||||
|
|
||||||
//produce only one output per work call -- TODO this should probably change
|
//produce only one output per work call -- TODO this should probably change
|
||||||
if(0) std::cout << "Preamble consumed " << i+240*d_samples_per_chip << "with i=" << i << ", returned 240" << std::endl;
|
if(0) std::cout << "Preamble consumed " << i+240*d_samples_per_chip << "with i=" << i << ", returned 240" << std::endl;
|
||||||
|
|
||||||
|
@ -15,26 +15,26 @@ private:
|
|||||||
int d_check_width;
|
int d_check_width;
|
||||||
int d_chip_rate;
|
int d_chip_rate;
|
||||||
float d_preamble_length_us;
|
float d_preamble_length_us;
|
||||||
float d_samples_per_chip;
|
int d_samples_per_chip;
|
||||||
float d_samples_per_symbol;
|
int d_samples_per_symbol;
|
||||||
float d_threshold_db;
|
float d_threshold_db;
|
||||||
float d_threshold;
|
float d_threshold;
|
||||||
gr::tag_t d_timestamp;
|
|
||||||
pmt::pmt_t d_me, d_key;
|
pmt::pmt_t d_me, d_key;
|
||||||
int d_sample_rate;
|
gr::tag_t d_timestamp;
|
||||||
|
double d_secs_per_sample;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
preamble_impl(float channel_rate, float threshold_db);
|
preamble_impl(int channel_rate, float threshold_db);
|
||||||
|
|
||||||
int general_work (int noutput_items,
|
int general_work (int noutput_items,
|
||||||
gr_vector_int &ninput_items,
|
gr_vector_int &ninput_items,
|
||||||
gr_vector_const_void_star &input_items,
|
gr_vector_const_void_star &input_items,
|
||||||
gr_vector_void_star &output_items);
|
gr_vector_void_star &output_items);
|
||||||
|
|
||||||
void set_rate(float channel_rate);
|
void set_rate(int channel_rate);
|
||||||
void set_threshold(float threshold_db);
|
void set_threshold(float threshold_db);
|
||||||
float get_threshold(void);
|
float get_threshold(void);
|
||||||
float get_rate(void);
|
int get_rate(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
} //namespace air_modes
|
} //namespace air_modes
|
||||||
|
@ -158,6 +158,8 @@ int air_modes::slicer_impl::work(int noutput_items,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rx_packet.timestamp = pmt::to_double(tag_iter->value);
|
||||||
|
|
||||||
//here you might want to traverse the whole packet and if you find all 0's, just toss it. don't know why these packets turn up, but they pass ECC.
|
//here you might want to traverse the whole packet and if you find all 0's, just toss it. don't know why these packets turn up, but they pass ECC.
|
||||||
bool zeroes = 1;
|
bool zeroes = 1;
|
||||||
for(int m = 0; m < 14; m++) {
|
for(int m = 0; m < 14; m++) {
|
||||||
@ -181,15 +183,13 @@ int air_modes::slicer_impl::work(int noutput_items,
|
|||||||
//crc for the other short packets is usually nonzero, so they can't really be trusted that far
|
//crc for the other short packets is usually nonzero, so they can't really be trusted that far
|
||||||
if(rx_packet.crc && (rx_packet.message_type == 11 || rx_packet.message_type == 17)) {continue;}
|
if(rx_packet.crc && (rx_packet.message_type == 11 || rx_packet.message_type == 17)) {continue;}
|
||||||
|
|
||||||
pmt::pmt_t tstamp = tag_iter->value;
|
|
||||||
|
|
||||||
d_payload.str("");
|
d_payload.str("");
|
||||||
for(int m = 0; m < packet_length/8; m++) {
|
for(int m = 0; m < packet_length/8; m++) {
|
||||||
d_payload << std::hex << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]);
|
d_payload << std::hex << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]);
|
||||||
}
|
}
|
||||||
|
|
||||||
d_payload << " " << std::setw(6) << rx_packet.crc << " " << std::dec << rx_packet.reference_level
|
d_payload << " " << std::setw(6) << rx_packet.crc << " " << std::dec << rx_packet.reference_level
|
||||||
<< " " << pmt::to_uint64(pmt::tuple_ref(tstamp, 0)) << " " << std::setprecision(10) << pmt::to_double(pmt::tuple_ref(tstamp, 1));
|
<< " " << std::setprecision(10) << std::setw(10) << rx_packet.timestamp;
|
||||||
gr::message::sptr msg = gr::message::make_from_string(std::string(d_payload.str()));
|
gr::message::sptr msg = gr::message::make_from_string(std::string(d_payload.str()));
|
||||||
d_queue->handle(msg);
|
d_queue->handle(msg);
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,6 @@ private:
|
|||||||
int d_chip_rate;
|
int d_chip_rate;
|
||||||
int d_samples_per_chip;
|
int d_samples_per_chip;
|
||||||
int d_samples_per_symbol;
|
int d_samples_per_symbol;
|
||||||
gr::tag_t d_timestamp;
|
|
||||||
gr::msg_queue::sptr d_queue;
|
gr::msg_queue::sptr d_queue;
|
||||||
std::ostringstream d_payload;
|
std::ostringstream d_payload;
|
||||||
|
|
||||||
|
@ -40,7 +40,6 @@ GR_PYTHON_INSTALL(
|
|||||||
flightgear.py
|
flightgear.py
|
||||||
gui_model.py
|
gui_model.py
|
||||||
kml.py
|
kml.py
|
||||||
modes_types.py
|
|
||||||
parse.py
|
parse.py
|
||||||
msprint.py
|
msprint.py
|
||||||
radio.py
|
radio.py
|
||||||
@ -48,6 +47,7 @@ GR_PYTHON_INSTALL(
|
|||||||
rx_path.py
|
rx_path.py
|
||||||
sbs1.py
|
sbs1.py
|
||||||
sql.py
|
sql.py
|
||||||
|
types.py
|
||||||
zmq_socket.py
|
zmq_socket.py
|
||||||
Quaternion.py
|
Quaternion.py
|
||||||
DESTINATION ${GR_PYTHON_DIR}/air_modes
|
DESTINATION ${GR_PYTHON_DIR}/air_modes
|
||||||
|
@ -28,10 +28,26 @@ KML, and PlanePlotter-compliant SBS-1 emulation output. mlat.py provides
|
|||||||
an experimental implementation of a multilateration solver.
|
an experimental implementation of a multilateration solver.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
# ----------------------------------------------------------------
|
||||||
|
# Temporary workaround for ticket:181 (swig+python problem)
|
||||||
|
import sys
|
||||||
|
_RTLD_GLOBAL = 0
|
||||||
|
try:
|
||||||
|
from dl import RTLD_GLOBAL as _RTLD_GLOBAL
|
||||||
|
except ImportError:
|
||||||
|
try:
|
||||||
|
from DLFCN import RTLD_GLOBAL as _RTLD_GLOBAL
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if _RTLD_GLOBAL != 0:
|
||||||
|
_dlopenflags = sys.getdlopenflags()
|
||||||
|
sys.setdlopenflags(_dlopenflags|_RTLD_GLOBAL)
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
# import swig generated symbols into the gr-air-modes namespace
|
# import swig generated symbols into the gr-air-modes namespace
|
||||||
from .air_modes_swig import *
|
from air_modes_swig import *
|
||||||
|
|
||||||
# import any pure python here
|
# import any pure python here
|
||||||
#
|
#
|
||||||
@ -41,24 +57,31 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
raise RuntimeError("PyZMQ not found! Please install libzmq and PyZMQ to run gr-air-modes")
|
raise RuntimeError("PyZMQ not found! Please install libzmq and PyZMQ to run gr-air-modes")
|
||||||
|
|
||||||
from .rx_path import rx_path
|
from rx_path import rx_path
|
||||||
from .zmq_socket import zmq_pubsub_iface
|
from zmq_socket import zmq_pubsub_iface
|
||||||
from .parse import *
|
from parse import *
|
||||||
from .msprint import output_print
|
from msprint import output_print
|
||||||
from .sql import output_sql
|
from sql import output_sql
|
||||||
from .sbs1 import output_sbs1
|
from sbs1 import output_sbs1
|
||||||
from .kml import output_kml, output_jsonp
|
from kml import output_kml, output_jsonp
|
||||||
from .raw_server import raw_server
|
from raw_server import raw_server
|
||||||
from .radio import modes_radio
|
from radio import modes_radio
|
||||||
from .exceptions import *
|
from exceptions import *
|
||||||
from .modes_types import *
|
from az_map import *
|
||||||
from .altitude import *
|
from types import *
|
||||||
from .cpr import cpr_decoder
|
from altitude import *
|
||||||
from .html_template import html_template
|
from cpr import cpr_decoder
|
||||||
|
from html_template import html_template
|
||||||
#this is try/excepted in case the user doesn't have numpy installed
|
#this is try/excepted in case the user doesn't have numpy installed
|
||||||
try:
|
try:
|
||||||
from .flightgear import output_flightgear
|
from flightgear import output_flightgear
|
||||||
from .Quaternion import *
|
from Quaternion import *
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print("gr-air-modes warning: numpy+scipy not installed, FlightGear interface not supported")
|
print "gr-air-modes warning: numpy+scipy not installed, FlightGear interface not supported"
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# Tail of workaround
|
||||||
|
if _RTLD_GLOBAL != 0:
|
||||||
|
sys.setdlopenflags(_dlopenflags) # Restore original flags
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
@ -26,119 +26,120 @@
|
|||||||
from air_modes.exceptions import *
|
from air_modes.exceptions import *
|
||||||
|
|
||||||
def decode_alt(alt, bit13):
|
def decode_alt(alt, bit13):
|
||||||
mbit = alt & 0x0040
|
mbit = alt & 0x0040
|
||||||
qbit = alt & 0x0010
|
qbit = alt & 0x0010
|
||||||
|
|
||||||
if mbit and bit13:
|
if mbit and bit13:
|
||||||
#nobody uses metric altitude: AFAIK, it's an orphaned part of
|
#nobody uses metric altitude: AFAIK, it's an orphaned part of
|
||||||
#the spec. haven't seen it in three years. as a result, replies
|
#the spec. haven't seen it in three years. as a result, replies
|
||||||
#with mbit set can be considered spurious, and so we discard them here.
|
#with mbit set can be considered spurious, and so we discard them here.
|
||||||
|
|
||||||
#bits 20-25, 27-31 encode alt in meters
|
#bits 20-25, 27-31 encode alt in meters
|
||||||
#remember that bits are LSB (bit 20 is MSB)
|
#remember that bits are LSB (bit 20 is MSB)
|
||||||
#meters_alt = 0
|
#meters_alt = 0
|
||||||
#for (shift, bit) in enumerate(range(31,26,-1)+range(25,19,-1)):
|
#for (shift, bit) in enumerate(range(31,26,-1)+range(25,19,-1)):
|
||||||
# meters_alt += ((alt & (1<<bit)) != 0) << shift
|
# meters_alt += ((alt & (1<<bit)) != 0) << shift
|
||||||
#decoded_alt = meters_alt / 0.3048
|
#decoded_alt = meters_alt / 0.3048
|
||||||
raise MetricAltError
|
raise MetricAltError
|
||||||
|
|
||||||
if qbit: #a mode S-style reply
|
if qbit: #a mode S-style reply
|
||||||
#bit13 is false for BDS0,5 ADS-B squitters, and is true otherwise
|
#bit13 is false for BDS0,5 ADS-B squitters, and is true otherwise
|
||||||
if bit13:
|
if bit13:
|
||||||
#in this representation, the altitude bits are as follows:
|
#in this representation, the altitude bits are as follows:
|
||||||
# 12 11 10 9 8 7 (6) 5 (4) 3 2 1 0
|
# 12 11 10 9 8 7 (6) 5 (4) 3 2 1 0
|
||||||
# so bits 6 and 4 are the M and Q bits, respectively.
|
# so bits 6 and 4 are the M and Q bits, respectively.
|
||||||
tmp1 = (alt & 0x3F80) >> 2
|
tmp1 = (alt & 0x3F80) >> 2
|
||||||
tmp2 = (alt & 0x0020) >> 1
|
tmp2 = (alt & 0x0020) >> 1
|
||||||
else:
|
else:
|
||||||
tmp1 = (alt & 0x1FE0) >> 1
|
tmp1 = (alt & 0x1FE0) >> 1
|
||||||
tmp2 = 0
|
tmp2 = 0
|
||||||
|
|
||||||
decoded_alt = ((alt & 0x0F) | tmp1 | tmp2) * 25 - 1000
|
decoded_alt = ((alt & 0x0F) | tmp1 | tmp2) * 25 - 1000
|
||||||
|
|
||||||
else: #a mode C-style reply
|
else: #a mode C-style reply
|
||||||
#okay, the order they come in is:
|
#okay, the order they come in is:
|
||||||
#C1 A1 C2 A2 C4 A4 X B1 D1 B2 D2 B4 D4
|
#C1 A1 C2 A2 C4 A4 X B1 D1 B2 D2 B4 D4
|
||||||
#the order we want them in is:
|
#the order we want them in is:
|
||||||
#D2 D4 A1 A2 A4 B1 B2 B4
|
#D2 D4 A1 A2 A4 B1 B2 B4
|
||||||
#so we'll reassemble into a Gray-coded representation
|
#so we'll reassemble into a Gray-coded representation
|
||||||
|
|
||||||
if bit13 is False:
|
if bit13 is False:
|
||||||
alt = (alt & 0x003F) | (alt & 0x0FC0 << 1)
|
alt = (alt & 0x003F) | (alt & 0x0FC0 << 1)
|
||||||
|
|
||||||
C1 = 0x1000
|
C1 = 0x1000
|
||||||
A1 = 0x0800
|
A1 = 0x0800
|
||||||
C2 = 0x0400
|
C2 = 0x0400
|
||||||
A2 = 0x0200 #this represents the order in which the bits come
|
A2 = 0x0200 #this represents the order in which the bits come
|
||||||
C4 = 0x0100
|
C4 = 0x0100
|
||||||
A4 = 0x0080
|
A4 = 0x0080
|
||||||
B1 = 0x0020
|
B1 = 0x0020
|
||||||
D1 = 0x0010
|
D1 = 0x0010
|
||||||
B2 = 0x0008
|
B2 = 0x0008
|
||||||
D2 = 0x0004
|
D2 = 0x0004
|
||||||
B4 = 0x0002
|
B4 = 0x0002
|
||||||
D4 = 0x0001
|
D4 = 0x0001
|
||||||
|
|
||||||
bigpart = ((alt & B4) >> 1) \
|
bigpart = ((alt & B4) >> 1) \
|
||||||
+ ((alt & B2) >> 2) \
|
+ ((alt & B2) >> 2) \
|
||||||
+ ((alt & B1) >> 3) \
|
+ ((alt & B1) >> 3) \
|
||||||
+ ((alt & A4) >> 4) \
|
+ ((alt & A4) >> 4) \
|
||||||
+ ((alt & A2) >> 5) \
|
+ ((alt & A2) >> 5) \
|
||||||
+ ((alt & A1) >> 6) \
|
+ ((alt & A1) >> 6) \
|
||||||
+ ((alt & D4) << 6) \
|
+ ((alt & D4) << 6) \
|
||||||
+ ((alt & D2) << 5)
|
+ ((alt & D2) << 5)
|
||||||
|
|
||||||
#bigpart is now the 500-foot-resolution Gray-coded binary part
|
#bigpart is now the 500-foot-resolution Gray-coded binary part
|
||||||
decoded_alt = gray2bin(bigpart)
|
decoded_alt = gray2bin(bigpart)
|
||||||
#real_alt is now the 500-foot-per-tick altitude
|
#real_alt is now the 500-foot-per-tick altitude
|
||||||
|
|
||||||
cbits = ((alt & C4) >> 8) + ((alt & C2) >> 9) + ((alt & C1) >> 10)
|
cbits = ((alt & C4) >> 8) + ((alt & C2) >> 9) + ((alt & C1) >> 10)
|
||||||
cval = gray2bin(cbits) #turn them into a real number
|
cval = gray2bin(cbits) #turn them into a real number
|
||||||
|
|
||||||
if cval == 7:
|
if cval == 7:
|
||||||
cval = 5 #not a real gray code after all
|
cval = 5 #not a real gray code after all
|
||||||
|
|
||||||
if decoded_alt % 2:
|
if decoded_alt % 2:
|
||||||
cval = 6 - cval #since the code is symmetric this unwraps it to see whether to subtract the C bits or add them
|
cval = 6 - cval #since the code is symmetric this unwraps it to see whether to subtract the C bits or add them
|
||||||
|
|
||||||
decoded_alt *= 500 #take care of the A,B,D data
|
decoded_alt *= 500 #take care of the A,B,D data
|
||||||
decoded_alt += cval * 100 #factor in the C data
|
decoded_alt += cval * 100 #factor in the C data
|
||||||
decoded_alt -= 1300 #subtract the offset
|
decoded_alt -= 1300 #subtract the offset
|
||||||
|
|
||||||
return decoded_alt
|
return decoded_alt
|
||||||
|
|
||||||
def gray2bin(gray):
|
def gray2bin(gray):
|
||||||
i = gray >> 1
|
i = gray >> 1
|
||||||
|
|
||||||
while i != 0:
|
while i != 0:
|
||||||
gray ^= i
|
gray ^= i
|
||||||
i >>= 1
|
i >>= 1
|
||||||
|
|
||||||
return gray
|
return gray
|
||||||
|
|
||||||
def encode_alt_modes(alt, bit13):
|
def encode_alt_modes(alt, bit13):
|
||||||
mbit = False
|
mbit = False
|
||||||
qbit = True
|
qbit = True
|
||||||
encalt = (int(alt) + 1000) / 25
|
encalt = (int(alt) + 1000) / 25
|
||||||
|
|
||||||
if bit13 is True:
|
if bit13 is True:
|
||||||
tmp1 = (encalt & 0xfe0) << 2
|
tmp1 = (encalt & 0xfe0) << 2
|
||||||
tmp2 = (encalt & 0x010) << 1
|
tmp2 = (encalt & 0x010) << 1
|
||||||
else:
|
|
||||||
tmp1 = (encalt & 0xff8) << 1
|
else:
|
||||||
tmp2 = 0
|
tmp1 = (encalt & 0xff8) << 1
|
||||||
|
tmp2 = 0
|
||||||
|
|
||||||
return (encalt & 0x0F) | tmp1 | tmp2 | (mbit << 6) | (qbit << 4)
|
return (encalt & 0x0F) | tmp1 | tmp2 | (mbit << 6) | (qbit << 4)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
try:
|
try:
|
||||||
for alt in range(-1000, 101400, 25):
|
for alt in range(-1000, 101400, 25):
|
||||||
dec = decode_alt(encode_alt_modes(alt, False), False)
|
dec = decode_alt(encode_alt_modes(alt, False), False)
|
||||||
if dec != alt:
|
if dec != alt:
|
||||||
print("Failure at %i with bit13 clear (got %s)" % (alt, dec))
|
print "Failure at %i with bit13 clear (got %s)" % (alt, dec)
|
||||||
for alt in range(-1000, 101400, 25):
|
for alt in range(-1000, 101400, 25):
|
||||||
dec = decode_alt(encode_alt_modes(alt, True), True)
|
dec = decode_alt(encode_alt_modes(alt, True), True)
|
||||||
if dec != alt:
|
if dec != alt:
|
||||||
print("Failure at %i with bit13 set (got %s)" % (alt, dec))
|
print "Failure at %i with bit13 set (got %s)" % (alt, dec)
|
||||||
except MetricAltError:
|
except MetricAltError:
|
||||||
print("Failure at %i due to metric alt bit" % alt)
|
print "Failure at %i due to metric alt bit" % alt
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
import threading
|
import threading
|
||||||
import math
|
import math
|
||||||
|
import air_modes
|
||||||
from air_modes.exceptions import *
|
from air_modes.exceptions import *
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
442
python/cpr.py
442
python/cpr.py
@ -31,302 +31,302 @@ from air_modes.exceptions import *
|
|||||||
latz = 15
|
latz = 15
|
||||||
|
|
||||||
def nz(ctype):
|
def nz(ctype):
|
||||||
return 4 * latz - ctype
|
return 4 * latz - ctype
|
||||||
|
|
||||||
def dlat(ctype, surface):
|
def dlat(ctype, surface):
|
||||||
if surface == 1:
|
if surface == 1:
|
||||||
tmp = 90.0
|
tmp = 90.0
|
||||||
else:
|
else:
|
||||||
tmp = 360.0
|
tmp = 360.0
|
||||||
|
|
||||||
nzcalc = nz(ctype)
|
nzcalc = nz(ctype)
|
||||||
if nzcalc == 0:
|
if nzcalc == 0:
|
||||||
return tmp
|
return tmp
|
||||||
else:
|
else:
|
||||||
return tmp / nzcalc
|
return tmp / nzcalc
|
||||||
|
|
||||||
def nl(declat_in):
|
def nl(declat_in):
|
||||||
if abs(declat_in) >= 87.0:
|
if abs(declat_in) >= 87.0:
|
||||||
return 1.0
|
return 1.0
|
||||||
return math.floor( (2.0*math.pi) * math.acos(1.0- (1.0-math.cos(math.pi/(2.0*latz))) / math.cos( (math.pi/180.0)*abs(declat_in) )**2 )**-1)
|
return math.floor( (2.0*math.pi) * math.acos(1.0- (1.0-math.cos(math.pi/(2.0*latz))) / math.cos( (math.pi/180.0)*abs(declat_in) )**2 )**-1)
|
||||||
|
|
||||||
def dlon(declat_in, ctype, surface):
|
def dlon(declat_in, ctype, surface):
|
||||||
if surface:
|
if surface:
|
||||||
tmp = 90.0
|
tmp = 90.0
|
||||||
else:
|
else:
|
||||||
tmp = 360.0
|
tmp = 360.0
|
||||||
nlcalc = max(nl(declat_in)-ctype, 1)
|
nlcalc = max(nl(declat_in)-ctype, 1)
|
||||||
return tmp / nlcalc
|
return tmp / nlcalc
|
||||||
|
|
||||||
def decode_lat(enclat, ctype, my_lat, surface):
|
def decode_lat(enclat, ctype, my_lat, surface):
|
||||||
tmp1 = dlat(ctype, surface)
|
tmp1 = dlat(ctype, surface)
|
||||||
tmp2 = float(enclat) / (2**17)
|
tmp2 = float(enclat) / (2**17)
|
||||||
j = math.floor(my_lat/tmp1) + math.floor(0.5 + ((my_lat % tmp1) / tmp1) - tmp2)
|
j = math.floor(my_lat/tmp1) + math.floor(0.5 + ((my_lat % tmp1) / tmp1) - tmp2)
|
||||||
|
|
||||||
return tmp1 * (j + tmp2)
|
return tmp1 * (j + tmp2)
|
||||||
|
|
||||||
def decode_lon(declat, enclon, ctype, my_lon, surface):
|
def decode_lon(declat, enclon, ctype, my_lon, surface):
|
||||||
tmp1 = dlon(declat, ctype, surface)
|
tmp1 = dlon(declat, ctype, surface)
|
||||||
tmp2 = float(enclon) / (2**17)
|
tmp2 = float(enclon) / (2**17)
|
||||||
m = math.floor(my_lon / tmp1) + math.floor(0.5 + ((my_lon % tmp1) / tmp1) - tmp2)
|
m = math.floor(my_lon / tmp1) + math.floor(0.5 + ((my_lon % tmp1) / tmp1) - tmp2)
|
||||||
|
|
||||||
return tmp1 * (m + tmp2)
|
return tmp1 * (m + tmp2)
|
||||||
|
|
||||||
def cpr_resolve_local(my_location, encoded_location, ctype, surface):
|
def cpr_resolve_local(my_location, encoded_location, ctype, surface):
|
||||||
[my_lat, my_lon] = my_location
|
[my_lat, my_lon] = my_location
|
||||||
[enclat, enclon] = encoded_location
|
[enclat, enclon] = encoded_location
|
||||||
|
|
||||||
decoded_lat = decode_lat(enclat, ctype, my_lat, surface)
|
decoded_lat = decode_lat(enclat, ctype, my_lat, surface)
|
||||||
decoded_lon = decode_lon(decoded_lat, enclon, ctype, my_lon, surface)
|
decoded_lon = decode_lon(decoded_lat, enclon, ctype, my_lon, surface)
|
||||||
|
|
||||||
return [decoded_lat, decoded_lon]
|
return [decoded_lat, decoded_lon]
|
||||||
|
|
||||||
def cpr_resolve_global(evenpos, oddpos, mypos, mostrecent, surface):
|
def cpr_resolve_global(evenpos, oddpos, mypos, mostrecent, surface):
|
||||||
#cannot resolve surface positions unambiguously without knowing receiver position
|
#cannot resolve surface positions unambiguously without knowing receiver position
|
||||||
if surface and mypos is None:
|
if surface and mypos is None:
|
||||||
raise CPRNoPositionError
|
raise CPRNoPositionError
|
||||||
|
|
||||||
dlateven = dlat(0, surface)
|
dlateven = dlat(0, surface)
|
||||||
dlatodd = dlat(1, surface)
|
dlatodd = dlat(1, surface)
|
||||||
|
|
||||||
evenpos = [float(evenpos[0]), float(evenpos[1])]
|
evenpos = [float(evenpos[0]), float(evenpos[1])]
|
||||||
oddpos = [float(oddpos[0]), float(oddpos[1])]
|
oddpos = [float(oddpos[0]), float(oddpos[1])]
|
||||||
|
|
||||||
j = math.floor(((nz(1)*evenpos[0] - nz(0)*oddpos[0])/2**17) + 0.5) #latitude index
|
j = math.floor(((nz(1)*evenpos[0] - nz(0)*oddpos[0])/2**17) + 0.5) #latitude index
|
||||||
|
|
||||||
rlateven = dlateven * ((j % nz(0))+evenpos[0]/2**17)
|
rlateven = dlateven * ((j % nz(0))+evenpos[0]/2**17)
|
||||||
rlatodd = dlatodd * ((j % nz(1))+ oddpos[0]/2**17)
|
rlatodd = dlatodd * ((j % nz(1))+ oddpos[0]/2**17)
|
||||||
|
|
||||||
#limit to -90, 90
|
#limit to -90, 90
|
||||||
if rlateven > 270.0:
|
if rlateven > 270.0:
|
||||||
rlateven -= 360.0
|
rlateven -= 360.0
|
||||||
if rlatodd > 270.0:
|
if rlatodd > 270.0:
|
||||||
rlatodd -= 360.0
|
rlatodd -= 360.0
|
||||||
|
|
||||||
#This checks to see if the latitudes of the reports straddle a transition boundary
|
#This checks to see if the latitudes of the reports straddle a transition boundary
|
||||||
#If so, you can't get a globally-resolvable location.
|
#If so, you can't get a globally-resolvable location.
|
||||||
if nl(rlateven) != nl(rlatodd):
|
if nl(rlateven) != nl(rlatodd):
|
||||||
raise CPRBoundaryStraddleError
|
raise CPRBoundaryStraddleError
|
||||||
|
|
||||||
if mostrecent == 0:
|
if mostrecent == 0:
|
||||||
rlat = rlateven
|
rlat = rlateven
|
||||||
else:
|
else:
|
||||||
rlat = rlatodd
|
rlat = rlatodd
|
||||||
|
|
||||||
#disambiguate latitude
|
#disambiguate latitude
|
||||||
if surface:
|
if surface:
|
||||||
if mypos[0] < 0:
|
if mypos[0] < 0:
|
||||||
rlat -= 90
|
rlat -= 90
|
||||||
|
|
||||||
dl = dlon(rlat, mostrecent, surface)
|
dl = dlon(rlat, mostrecent, surface)
|
||||||
nl_rlat = nl(rlat)
|
nl_rlat = nl(rlat)
|
||||||
|
|
||||||
m = math.floor(((evenpos[1]*(nl_rlat-1)-oddpos[1]*nl_rlat)/2**17)+0.5) #longitude index
|
m = math.floor(((evenpos[1]*(nl_rlat-1)-oddpos[1]*nl_rlat)/2**17)+0.5) #longitude index
|
||||||
|
|
||||||
#when surface positions straddle a disambiguation boundary (90 degrees),
|
#when surface positions straddle a disambiguation boundary (90 degrees),
|
||||||
#surface decoding will fail. this might never be a problem in real life, but it'll fail in the
|
#surface decoding will fail. this might never be a problem in real life, but it'll fail in the
|
||||||
#test case. the documentation doesn't mention it.
|
#test case. the documentation doesn't mention it.
|
||||||
|
|
||||||
if mostrecent == 0:
|
if mostrecent == 0:
|
||||||
enclon = evenpos[1]
|
enclon = evenpos[1]
|
||||||
else:
|
else:
|
||||||
enclon = oddpos[1]
|
enclon = oddpos[1]
|
||||||
|
|
||||||
rlon = dl * ((m % max(nl_rlat-mostrecent,1)) + enclon/2.**17)
|
rlon = dl * ((m % max(nl_rlat-mostrecent,1)) + enclon/2.**17)
|
||||||
|
|
||||||
#print "DL: %f nl: %f m: %f rlon: %f" % (dl, nl_rlat, m, rlon)
|
#print "DL: %f nl: %f m: %f rlon: %f" % (dl, nl_rlat, m, rlon)
|
||||||
#print "evenpos: %x, oddpos: %x, mostrecent: %i" % (evenpos[1], oddpos[1], mostrecent)
|
#print "evenpos: %x, oddpos: %x, mostrecent: %i" % (evenpos[1], oddpos[1], mostrecent)
|
||||||
|
|
||||||
if surface:
|
if surface:
|
||||||
#longitudes need to be resolved to the nearest 90 degree segment to the receiver.
|
#longitudes need to be resolved to the nearest 90 degree segment to the receiver.
|
||||||
wat = mypos[1]
|
wat = mypos[1]
|
||||||
if wat < 0:
|
if wat < 0:
|
||||||
wat += 360
|
wat += 360
|
||||||
zone = lambda lon: 90 * (int(lon) / 90)
|
zone = lambda lon: 90 * (int(lon) / 90)
|
||||||
rlon += (zone(wat) - zone(rlon))
|
rlon += (zone(wat) - zone(rlon))
|
||||||
|
|
||||||
#limit to (-180, 180)
|
#limit to (-180, 180)
|
||||||
if rlon > 180:
|
if rlon > 180:
|
||||||
rlon -= 360.0
|
rlon -= 360.0
|
||||||
|
|
||||||
return [rlat, rlon]
|
return [rlat, rlon]
|
||||||
|
|
||||||
|
|
||||||
#calculate range and bearing between two lat/lon points
|
#calculate range and bearing between two lat/lon points
|
||||||
#should probably throw this in the mlat py somewhere or make another lib
|
#should probably throw this in the mlat py somewhere or make another lib
|
||||||
def range_bearing(loc_a, loc_b):
|
def range_bearing(loc_a, loc_b):
|
||||||
[a_lat, a_lon] = loc_a
|
[a_lat, a_lon] = loc_a
|
||||||
[b_lat, b_lon] = loc_b
|
[b_lat, b_lon] = loc_b
|
||||||
|
|
||||||
esquared = (1/298.257223563)*(2-(1/298.257223563))
|
esquared = (1/298.257223563)*(2-(1/298.257223563))
|
||||||
earth_radius_mi = 3963.19059 * (math.pi / 180)
|
earth_radius_mi = 3963.19059 * (math.pi / 180)
|
||||||
|
|
||||||
delta_lat = b_lat - a_lat
|
delta_lat = b_lat - a_lat
|
||||||
delta_lon = b_lon - a_lon
|
delta_lon = b_lon - a_lon
|
||||||
|
|
||||||
avg_lat = ((a_lat + b_lat) / 2.0) * math.pi / 180
|
avg_lat = ((a_lat + b_lat) / 2.0) * math.pi / 180
|
||||||
|
|
||||||
R1 = earth_radius_mi*(1.0-esquared)/pow((1.0-esquared*pow(math.sin(avg_lat),2)),1.5)
|
R1 = earth_radius_mi*(1.0-esquared)/pow((1.0-esquared*pow(math.sin(avg_lat),2)),1.5)
|
||||||
|
|
||||||
R2 = earth_radius_mi/math.sqrt(1.0-esquared*pow(math.sin(avg_lat),2))
|
R2 = earth_radius_mi/math.sqrt(1.0-esquared*pow(math.sin(avg_lat),2))
|
||||||
|
|
||||||
distance_North = R1*delta_lat
|
distance_North = R1*delta_lat
|
||||||
distance_East = R2*math.cos(avg_lat)*delta_lon
|
distance_East = R2*math.cos(avg_lat)*delta_lon
|
||||||
|
|
||||||
bearing = math.atan2(distance_East,distance_North) * (180.0 / math.pi)
|
bearing = math.atan2(distance_East,distance_North) * (180.0 / math.pi)
|
||||||
if bearing < 0.0:
|
if bearing < 0.0:
|
||||||
bearing += 360.0
|
bearing += 360.0
|
||||||
|
|
||||||
rnge = math.hypot(distance_East,distance_North)
|
rnge = math.hypot(distance_East,distance_North)
|
||||||
return [rnge, bearing]
|
return [rnge, bearing]
|
||||||
|
|
||||||
class cpr_decoder:
|
class cpr_decoder:
|
||||||
def __init__(self, my_location):
|
def __init__(self, my_location):
|
||||||
self.my_location = my_location
|
self.my_location = my_location
|
||||||
self.evenlist = {}
|
self.evenlist = {}
|
||||||
self.oddlist = {}
|
self.oddlist = {}
|
||||||
self.evenlist_sfc = {}
|
self.evenlist_sfc = {}
|
||||||
self.oddlist_sfc = {}
|
self.oddlist_sfc = {}
|
||||||
|
|
||||||
def set_location(self, new_location):
|
def set_location(self, new_location):
|
||||||
self.my_location = new_location
|
self.my_location = new_location
|
||||||
|
|
||||||
def weed_poslists(self):
|
def weed_poslists(self):
|
||||||
for poslist in [self.evenlist, self.oddlist]:
|
for poslist in [self.evenlist, self.oddlist]:
|
||||||
for key, item in tuple(poslist.items()):
|
for key, item in poslist.items():
|
||||||
if time.time() - item[2] > 10:
|
if time.time() - item[2] > 10:
|
||||||
del poslist[key]
|
del poslist[key]
|
||||||
for poslist in [self.evenlist_sfc, self.oddlist_sfc]:
|
for poslist in [self.evenlist_sfc, self.oddlist_sfc]:
|
||||||
for key, item in tuple(poslist.items()):
|
for key, item in poslist.items():
|
||||||
if time.time() - item[2] > 25:
|
if time.time() - item[2] > 25:
|
||||||
del poslist[key]
|
del poslist[key]
|
||||||
|
|
||||||
def decode(self, icao24, encoded_lat, encoded_lon, cpr_format, surface):
|
def decode(self, icao24, encoded_lat, encoded_lon, cpr_format, surface):
|
||||||
if surface:
|
if surface:
|
||||||
oddlist = self.oddlist_sfc
|
oddlist = self.oddlist_sfc
|
||||||
evenlist = self.evenlist_sfc
|
evenlist = self.evenlist_sfc
|
||||||
else:
|
else:
|
||||||
oddlist = self.oddlist
|
oddlist = self.oddlist
|
||||||
evenlist = self.evenlist
|
evenlist = self.evenlist
|
||||||
|
|
||||||
#add the info to the position reports list for global decoding
|
#add the info to the position reports list for global decoding
|
||||||
if cpr_format==1:
|
if cpr_format==1:
|
||||||
oddlist[icao24] = [encoded_lat, encoded_lon, time.time()]
|
oddlist[icao24] = [encoded_lat, encoded_lon, time.time()]
|
||||||
else:
|
else:
|
||||||
evenlist[icao24] = [encoded_lat, encoded_lon, time.time()]
|
evenlist[icao24] = [encoded_lat, encoded_lon, time.time()]
|
||||||
|
|
||||||
[decoded_lat, decoded_lon] = [None, None]
|
[decoded_lat, decoded_lon] = [None, None]
|
||||||
|
|
||||||
#okay, let's traverse the lists and weed out those entries that are older than 10 seconds
|
#okay, let's traverse the lists and weed out those entries that are older than 10 seconds
|
||||||
self.weed_poslists()
|
self.weed_poslists()
|
||||||
|
|
||||||
if (icao24 in evenlist) \
|
if (icao24 in evenlist) \
|
||||||
and (icao24 in oddlist):
|
and (icao24 in oddlist):
|
||||||
newer = (oddlist[icao24][2] - evenlist[icao24][2]) > 0 #figure out which report is newer
|
newer = (oddlist[icao24][2] - evenlist[icao24][2]) > 0 #figure out which report is newer
|
||||||
[decoded_lat, decoded_lon] = cpr_resolve_global(evenlist[icao24][0:2], oddlist[icao24][0:2], self.my_location, newer, surface) #do a global decode
|
[decoded_lat, decoded_lon] = cpr_resolve_global(evenlist[icao24][0:2], oddlist[icao24][0:2], self.my_location, newer, surface) #do a global decode
|
||||||
else:
|
else:
|
||||||
raise CPRNoPositionError
|
raise CPRNoPositionError
|
||||||
|
|
||||||
if self.my_location is not None:
|
if self.my_location is not None:
|
||||||
[rnge, bearing] = range_bearing(self.my_location, [decoded_lat, decoded_lon])
|
[rnge, bearing] = range_bearing(self.my_location, [decoded_lat, decoded_lon])
|
||||||
else:
|
else:
|
||||||
rnge = None
|
rnge = None
|
||||||
bearing = None
|
bearing = None
|
||||||
|
|
||||||
return [decoded_lat, decoded_lon, rnge, bearing]
|
return [decoded_lat, decoded_lon, rnge, bearing]
|
||||||
|
|
||||||
#encode CPR position
|
#encode CPR position
|
||||||
def cpr_encode(lat, lon, ctype, surface):
|
def cpr_encode(lat, lon, ctype, surface):
|
||||||
if surface is True:
|
if surface is True:
|
||||||
scalar = 2.**19
|
scalar = 2.**19
|
||||||
else:
|
else:
|
||||||
scalar = 2.**17
|
scalar = 2.**17
|
||||||
|
|
||||||
#encode using 360 constant for segment size.
|
#encode using 360 constant for segment size.
|
||||||
dlati = dlat(ctype, False)
|
dlati = dlat(ctype, False)
|
||||||
yz = math.floor(scalar * ((lat % dlati)/dlati) + 0.5)
|
yz = math.floor(scalar * ((lat % dlati)/dlati) + 0.5)
|
||||||
rlat = dlati * ((yz / scalar) + math.floor(lat / dlati))
|
rlat = dlati * ((yz / scalar) + math.floor(lat / dlati))
|
||||||
|
|
||||||
#encode using 360 constant for segment size.
|
#encode using 360 constant for segment size.
|
||||||
dloni = dlon(lat, ctype, False)
|
dloni = dlon(lat, ctype, False)
|
||||||
xz = math.floor(scalar * ((lon % dloni)/dloni) + 0.5)
|
xz = math.floor(scalar * ((lon % dloni)/dloni) + 0.5)
|
||||||
|
|
||||||
yz = int(yz) & (2**17-1)
|
yz = int(yz) & (2**17-1)
|
||||||
xz = int(xz) & (2**17-1)
|
xz = int(xz) & (2**17-1)
|
||||||
|
|
||||||
return (yz, xz) #lat, lon
|
return (yz, xz) #lat, lon
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys, random
|
import sys, random
|
||||||
|
|
||||||
rounds = 10001
|
rounds = 10001
|
||||||
threshold = 1e-3 #0.001 deg lat/lon
|
threshold = 1e-3 #0.001 deg lat/lon
|
||||||
#this accuracy is highly dependent on latitude, since at high
|
#this accuracy is highly dependent on latitude, since at high
|
||||||
#latitudes the corresponding error in longitude is greater
|
#latitudes the corresponding error in longitude is greater
|
||||||
|
|
||||||
bs = 0
|
bs = 0
|
||||||
surface = False
|
surface = False
|
||||||
|
|
||||||
lats = [i/(rounds/170.)-85 for i in range(0,rounds)]
|
lats = [i/(rounds/170.)-85 for i in range(0,rounds)]
|
||||||
lons = [i/(rounds/360.)-180 for i in range(0,rounds)]
|
lons = [i/(rounds/360.)-180 for i in range(0,rounds)]
|
||||||
|
|
||||||
for i in range(0, rounds):
|
for i in range(0, rounds):
|
||||||
even_lat = lats[i]
|
even_lat = lats[i]
|
||||||
#even_lat = random.uniform(-85, 85)
|
#even_lat = random.uniform(-85, 85)
|
||||||
even_lon = lons[i]
|
even_lon = lons[i]
|
||||||
#even_lon = random.uniform(-180, 180)
|
#even_lon = random.uniform(-180, 180)
|
||||||
odd_lat = even_lat + 1e-3
|
odd_lat = even_lat + 1e-3
|
||||||
odd_lon = min(even_lon + 1e-3, 180)
|
odd_lon = min(even_lon + 1e-3, 180)
|
||||||
decoder = cpr_decoder([odd_lat, odd_lon])
|
decoder = cpr_decoder([odd_lat, odd_lon])
|
||||||
|
|
||||||
#encode that position
|
#encode that position
|
||||||
(evenenclat, evenenclon) = cpr_encode(even_lat, even_lon, False, surface)
|
(evenenclat, evenenclon) = cpr_encode(even_lat, even_lon, False, surface)
|
||||||
(oddenclat, oddenclon) = cpr_encode(odd_lat, odd_lon, True, surface)
|
(oddenclat, oddenclon) = cpr_encode(odd_lat, odd_lon, True, surface)
|
||||||
|
|
||||||
#try to perform a global decode -- this should fail since the decoder
|
#try to perform a global decode -- this should fail since the decoder
|
||||||
#only has heard one position. need two for global decoding.
|
#only has heard one position. need two for global decoding.
|
||||||
icao = random.randint(0, 0xffffff)
|
icao = random.randint(0, 0xffffff)
|
||||||
try:
|
try:
|
||||||
evenpos = decoder.decode(icao, evenenclat, evenenclon, False, surface)
|
evenpos = decoder.decode(icao, evenenclat, evenenclon, False, surface)
|
||||||
raise Exception("CPR test failure: global decode with only one report")
|
raise Exception("CPR test failure: global decode with only one report")
|
||||||
except CPRNoPositionError:
|
except CPRNoPositionError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
#now try to do a real decode with the last packet's odd complement
|
#now try to do a real decode with the last packet's odd complement
|
||||||
#watch for a boundary straddle -- this isn't fatal, it just indicates
|
#watch for a boundary straddle -- this isn't fatal, it just indicates
|
||||||
#that the even and odd reports lie on either side of a longitudinal boundary
|
#that the even and odd reports lie on either side of a longitudinal boundary
|
||||||
#and so you can't get a position
|
#and so you can't get a position
|
||||||
try:
|
try:
|
||||||
(odddeclat, odddeclon, rng, brg) = decoder.decode(icao, oddenclat, oddenclon, True, surface)
|
(odddeclat, odddeclon, rng, brg) = decoder.decode(icao, oddenclat, oddenclon, True, surface)
|
||||||
except CPRBoundaryStraddleError:
|
except CPRBoundaryStraddleError:
|
||||||
bs += 1
|
bs += 1
|
||||||
continue
|
continue
|
||||||
except CPRNoPositionError:
|
except CPRNoPositionError:
|
||||||
raise Exception("CPR test failure: no decode after even/odd inputs")
|
raise Exception("CPR test failure: no decode after even/odd inputs")
|
||||||
|
|
||||||
if abs(odddeclat - odd_lat) > threshold or abs(odddeclon - odd_lon) > threshold:
|
if abs(odddeclat - odd_lat) > threshold or abs(odddeclon - odd_lon) > threshold:
|
||||||
print("F odddeclat: %f odd_lat: %f" % (odddeclat, odd_lat))
|
print "F odddeclat: %f odd_lat: %f" % (odddeclat, odd_lat)
|
||||||
print( "F odddeclon: %f odd_lon: %f" % (odddeclon, odd_lon))
|
print "F odddeclon: %f odd_lon: %f" % (odddeclon, odd_lon)
|
||||||
raise Exception("CPR test failure: global decode error greater than threshold")
|
raise Exception("CPR test failure: global decode error greater than threshold")
|
||||||
# else:
|
# else:
|
||||||
# print("S odddeclat: %f odd_lat: %f" % (odddeclat, odd_lat))
|
# print "S odddeclat: %f odd_lat: %f" % (odddeclat, odd_lat)
|
||||||
# print("S odddeclon: %f odd_lon: %f" % (odddeclon, odd_lon))
|
# print "S odddeclon: %f odd_lon: %f" % (odddeclon, odd_lon)
|
||||||
|
|
||||||
nexteven_lat = odd_lat + 1e-3
|
nexteven_lat = odd_lat + 1e-3
|
||||||
nexteven_lon = min(odd_lon + 1e-3, 180)
|
nexteven_lon = min(odd_lon + 1e-3, 180)
|
||||||
|
|
||||||
(nexteven_enclat, nexteven_enclon) = cpr_encode(nexteven_lat, nexteven_lon, False, surface)
|
(nexteven_enclat, nexteven_enclon) = cpr_encode(nexteven_lat, nexteven_lon, False, surface)
|
||||||
|
|
||||||
#try a locally-referenced decode
|
#try a locally-referenced decode
|
||||||
try:
|
try:
|
||||||
(evendeclat, evendeclon) = cpr_resolve_local([even_lat, even_lon], [nexteven_enclat, nexteven_enclon], False, surface)
|
(evendeclat, evendeclon) = cpr_resolve_local([even_lat, even_lon], [nexteven_enclat, nexteven_enclon], False, surface)
|
||||||
except CPRNoPositionError:
|
except CPRNoPositionError:
|
||||||
raise Exception("CPR test failure: local decode failure to resolve")
|
raise Exception("CPR test failure: local decode failure to resolve")
|
||||||
|
|
||||||
#check to see if the positions were valid
|
#check to see if the positions were valid
|
||||||
if abs(evendeclat - nexteven_lat) > threshold or abs(evendeclon - nexteven_lon) > threshold:
|
if abs(evendeclat - nexteven_lat) > threshold or abs(evendeclon - nexteven_lon) > threshold:
|
||||||
print("F evendeclat: %f nexteven_lat: %f evenlat: %f" % (evendeclat, nexteven_lat, even_lat))
|
print "F evendeclat: %f nexteven_lat: %f evenlat: %f" % (evendeclat, nexteven_lat, even_lat)
|
||||||
print("F evendeclon: %f nexteven_lon: %f evenlon: %f" % (evendeclon, nexteven_lon, even_lon))
|
print "F evendeclon: %f nexteven_lon: %f evenlon: %f" % (evendeclon, nexteven_lon, even_lon)
|
||||||
raise Exception("CPR test failure: local decode error greater than threshold")
|
raise Exception("CPR test failure: local decode error greater than threshold")
|
||||||
|
|
||||||
print("CPR test successful. There were %i boundary straddles over %i rounds." % (bs, rounds))
|
print "CPR test successful. There were %i boundary straddles over %i rounds." % (bs, rounds)
|
||||||
|
@ -24,7 +24,7 @@ class output_flightgear:
|
|||||||
self._cpr = cprdec
|
self._cpr = cprdec
|
||||||
|
|
||||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
# self.sock.connect((self.hostname, self.port))
|
self.sock.connect((self.hostname, self.port))
|
||||||
pub.subscribe("type17_dl", self.output)
|
pub.subscribe("type17_dl", self.output)
|
||||||
|
|
||||||
def output(self, msg):
|
def output(self, msg):
|
||||||
@ -69,7 +69,7 @@ class output_flightgear:
|
|||||||
and (icao24 in self.velocities)\
|
and (icao24 in self.velocities)\
|
||||||
and (icao24 in self.callsigns)
|
and (icao24 in self.callsigns)
|
||||||
if complete:
|
if complete:
|
||||||
print("FG update: %s" % (self.callsigns[icao24][0]))
|
print "FG update: %s" % (self.callsigns[icao24][0])
|
||||||
msg = fg_posmsg(self.callsigns[icao24][0],
|
msg = fg_posmsg(self.callsigns[icao24][0],
|
||||||
self.callsigns[icao24][1],
|
self.callsigns[icao24][1],
|
||||||
self.positions[icao24][0],
|
self.positions[icao24][0],
|
||||||
@ -80,7 +80,7 @@ class output_flightgear:
|
|||||||
self.velocities[icao24][2],
|
self.velocities[icao24][2],
|
||||||
self.velocities[icao24][3]).pack()
|
self.velocities[icao24][3]).pack()
|
||||||
|
|
||||||
self.sock.sendto(msg, (self.hostname, self.port))
|
self.sock.send(msg)
|
||||||
|
|
||||||
class fg_header:
|
class fg_header:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -119,7 +119,7 @@ modelmap = { None: 'Aircraft/777-200/Models/777-200ER.xml'
|
|||||||
"SMALL": 'Aircraft/CitationX/Models/Citation-X.xml',
|
"SMALL": 'Aircraft/CitationX/Models/Citation-X.xml',
|
||||||
"LARGE": 'Aircraft/CRJ700-family/Models/CRJ700.xml',
|
"LARGE": 'Aircraft/CRJ700-family/Models/CRJ700.xml',
|
||||||
"LARGE HIGH VORTEX": 'Aircraft/757-200/Models/757-200.xml',
|
"LARGE HIGH VORTEX": 'Aircraft/757-200/Models/757-200.xml',
|
||||||
"HEAVY": 'Aircraft/IDG-A32X/Models/A320neo-CFM.xml',
|
"HEAVY": 'Aircraft/747-200/Models/boeing747-200.xml',
|
||||||
"HIGH PERFORMANCE": 'Aircraft/SR71-BlackBird/Models/Blackbird-SR71B.xml', #yeah i know
|
"HIGH PERFORMANCE": 'Aircraft/SR71-BlackBird/Models/Blackbird-SR71B.xml', #yeah i know
|
||||||
"ROTORCRAFT": 'Aircraft/ec130/Models/ec130b4.xml',
|
"ROTORCRAFT": 'Aircraft/ec130/Models/ec130b4.xml',
|
||||||
"GLIDER": 'Aircraft/ASK21-MI/Models/ask21mi.xml',
|
"GLIDER": 'Aircraft/ASK21-MI/Models/ask21mi.xml',
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#HTML template for Mode S map display
|
#HTML template for Mode S map display
|
||||||
#Nick Foster, 2013
|
#Nick Foster, 2013
|
||||||
|
|
||||||
def html_template(my_apikey, my_position, json_file):
|
def html_template(my_position, json_file):
|
||||||
if my_position is None:
|
if my_position is None:
|
||||||
my_position = [37, -122]
|
my_position = [37, -122]
|
||||||
|
|
||||||
@ -25,9 +25,9 @@ def html_template(my_apikey, my_position, json_file):
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script type="text/javascript" src="http://maps.google.com/maps/api/js?key=%s">
|
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false">
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript" src="https://raw.githubusercontent.com/googlemaps/v3-utility-library/master/markerwithlabel/src/markerwithlabel.js">
|
<script type="text/javascript" src="http://google-maps-utility-library-v3.googlecode.com/svn/tags/markerwithlabel/1.1.9/src/markerwithlabel.js">
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var map;
|
var map;
|
||||||
@ -152,4 +152,4 @@ def html_template(my_apikey, my_position, json_file):
|
|||||||
<div id="map_canvas" style="width:100%%; height:100%%">
|
<div id="map_canvas" style="width:100%%; height:100%%">
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>""" % (my_apikey, my_position[0], my_position[1], json_file)
|
</html>""" % (my_position[0], my_position[1], json_file)
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import math, threading, time
|
import string, math, threading, time
|
||||||
|
|
||||||
class output_kml(threading.Thread):
|
class output_kml(threading.Thread):
|
||||||
def __init__(self, filename, dbname, localpos, lock, timeout=5):
|
def __init__(self, filename, dbname, localpos, lock, timeout=5):
|
||||||
@ -89,7 +89,7 @@ class output_kml(threading.Thread):
|
|||||||
lon_out = center_lon + math.degrees(math.atan2(math.sin(bearing)*math.sin(tmp0)*math.cos(lat_rad), math.cos(tmp0)-math.sin(lat_rad)*math.sin(math.radians(lat_out))))
|
lon_out = center_lon + math.degrees(math.atan2(math.sin(bearing)*math.sin(tmp0)*math.cos(lat_rad), math.cos(tmp0)-math.sin(lat_rad)*math.sin(math.radians(lat_out))))
|
||||||
retstr += " %.8f,%.8f, 0" % (lon_out, lat_out,)
|
retstr += " %.8f,%.8f, 0" % (lon_out, lat_out,)
|
||||||
|
|
||||||
retstr = retstr.lstrip()
|
retstr = string.lstrip(retstr)
|
||||||
return retstr
|
return retstr
|
||||||
|
|
||||||
def genkml(self):
|
def genkml(self):
|
||||||
@ -132,7 +132,7 @@ class output_kml(threading.Thread):
|
|||||||
for pos in track:
|
for pos in track:
|
||||||
trackstr += " %f,%f,%f" % (pos[4], pos[3], pos[2]*0.3048)
|
trackstr += " %f,%f,%f" % (pos[4], pos[3], pos[2]*0.3048)
|
||||||
|
|
||||||
trackstr = trackstr.lstrip()
|
trackstr = string.lstrip(trackstr)
|
||||||
else:
|
else:
|
||||||
alt = 0
|
alt = 0
|
||||||
metric_alt = 0
|
metric_alt = 0
|
||||||
|
@ -55,8 +55,7 @@ wgs84_b2 = wgs84_b**2
|
|||||||
|
|
||||||
#convert ECEF to lat/lon/alt without geoid correction
|
#convert ECEF to lat/lon/alt without geoid correction
|
||||||
#returns alt in meters
|
#returns alt in meters
|
||||||
def ecef2llh(ecef):
|
def ecef2llh((x,y,z)):
|
||||||
x, y, z = ecef
|
|
||||||
ep = math.sqrt((wgs84_a2 - wgs84_b2) / wgs84_b2)
|
ep = math.sqrt((wgs84_a2 - wgs84_b2) / wgs84_b2)
|
||||||
p = math.sqrt(x**2+y**2)
|
p = math.sqrt(x**2+y**2)
|
||||||
th = math.atan2(wgs84_a*z, wgs84_b*p)
|
th = math.atan2(wgs84_a*z, wgs84_b*p)
|
||||||
@ -72,8 +71,7 @@ def ecef2llh(ecef):
|
|||||||
|
|
||||||
#convert lat/lon/alt coords to ECEF without geoid correction, WGS84 model
|
#convert lat/lon/alt coords to ECEF without geoid correction, WGS84 model
|
||||||
#remember that alt is in meters
|
#remember that alt is in meters
|
||||||
def llh2ecef(lla):
|
def llh2ecef((lat, lon, alt)):
|
||||||
lat, lon, alt = lla
|
|
||||||
lat *= (math.pi / 180.0)
|
lat *= (math.pi / 180.0)
|
||||||
lon *= (math.pi / 180.0)
|
lon *= (math.pi / 180.0)
|
||||||
|
|
||||||
@ -86,8 +84,7 @@ def llh2ecef(lla):
|
|||||||
return [x,y,z]
|
return [x,y,z]
|
||||||
|
|
||||||
#do both of the above to get a geoid-corrected x,y,z position
|
#do both of the above to get a geoid-corrected x,y,z position
|
||||||
def llh2geoid(lla):
|
def llh2geoid((lat, lon, alt)):
|
||||||
lat, lon, alt = lla
|
|
||||||
(x,y,z) = llh2ecef((lat, lon, alt + wgs84_height(lat, lon)))
|
(x,y,z) = llh2ecef((lat, lon, alt + wgs84_height(lat, lon)))
|
||||||
return [x,y,z]
|
return [x,y,z]
|
||||||
|
|
||||||
@ -188,7 +185,7 @@ if __name__ == '__main__':
|
|||||||
10 + numpy.linalg.norm(testplane-numpy.array(llh2geoid(teststations[3]))) / c,
|
10 + numpy.linalg.norm(testplane-numpy.array(llh2geoid(teststations[3]))) / c,
|
||||||
]
|
]
|
||||||
|
|
||||||
print(teststamps)
|
print teststamps
|
||||||
|
|
||||||
replies = []
|
replies = []
|
||||||
for i in range(0, len(teststations)):
|
for i in range(0, len(teststations)):
|
||||||
@ -196,7 +193,7 @@ if __name__ == '__main__':
|
|||||||
ans = mlat(replies, testalt)
|
ans = mlat(replies, testalt)
|
||||||
error = numpy.linalg.norm(numpy.array(llh2ecef(ans))-numpy.array(testplane))
|
error = numpy.linalg.norm(numpy.array(llh2ecef(ans))-numpy.array(testplane))
|
||||||
range = numpy.linalg.norm(llh2geoid(ans)-numpy.array(testme))
|
range = numpy.linalg.norm(llh2geoid(ans)-numpy.array(testme))
|
||||||
print(testplane-testme)
|
print testplane-testme
|
||||||
print(ans)
|
print ans
|
||||||
print("Error: %.2fm" % (error))
|
print "Error: %.2fm" % (error)
|
||||||
print("Range: %.2fkm (from first station in list)" % (range/1000))
|
print "Range: %.2fkm (from first station in list)" % (range/1000)
|
||||||
|
1
python/mlat_types.py
Normal file
1
python/mlat_types.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -20,6 +20,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import time, os, sys
|
import time, os, sys
|
||||||
|
from string import split, join
|
||||||
import air_modes
|
import air_modes
|
||||||
from air_modes.exceptions import *
|
from air_modes.exceptions import *
|
||||||
import math
|
import math
|
||||||
@ -43,7 +44,7 @@ class output_print:
|
|||||||
|
|
||||||
def _print(self, msg):
|
def _print(self, msg):
|
||||||
if self._callback is None:
|
if self._callback is None:
|
||||||
print(msg)
|
print msg
|
||||||
else:
|
else:
|
||||||
self._callback(msg)
|
self._callback(msg)
|
||||||
|
|
||||||
@ -80,7 +81,7 @@ class output_print:
|
|||||||
except ADSBError:
|
except ADSBError:
|
||||||
return
|
return
|
||||||
|
|
||||||
if msg.data["vs"] == 1:
|
if msg.data["vs"] is 1:
|
||||||
retstr += " (aircraft is on the ground)"
|
retstr += " (aircraft is on the ground)"
|
||||||
|
|
||||||
self._print(retstr)
|
self._print(retstr)
|
||||||
|
@ -20,7 +20,8 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import time, os, sys
|
import time, os, sys
|
||||||
from air_modes.altitude import decode_alt
|
from string import split, join
|
||||||
|
from altitude import decode_alt
|
||||||
import math
|
import math
|
||||||
import air_modes
|
import air_modes
|
||||||
from air_modes.exceptions import *
|
from air_modes.exceptions import *
|
||||||
@ -31,14 +32,14 @@ class data_field:
|
|||||||
self.data = data
|
self.data = data
|
||||||
self.fields = self.parse()
|
self.fields = self.parse()
|
||||||
|
|
||||||
dtypes = { }
|
types = { }
|
||||||
offset = 1 #field offset applied to all fields. used for offsetting
|
offset = 1 #field offset applied to all fields. used for offsetting
|
||||||
#subtypes to reconcile with the spec. Really just for readability.
|
#subtypes to reconcile with the spec. Really just for readability.
|
||||||
|
|
||||||
#get a particular field from the data
|
#get a particular field from the data
|
||||||
def __getitem__(self, fieldname):
|
def __getitem__(self, fieldname):
|
||||||
mytype = self.get_type()
|
mytype = self.get_type()
|
||||||
if mytype in self.dtypes:
|
if mytype in self.types:
|
||||||
if fieldname in self.fields: #verify it exists in this packet type
|
if fieldname in self.fields: #verify it exists in this packet type
|
||||||
return self.fields[fieldname]
|
return self.fields[fieldname]
|
||||||
else:
|
else:
|
||||||
@ -51,9 +52,9 @@ class data_field:
|
|||||||
def parse(self):
|
def parse(self):
|
||||||
fields = {}
|
fields = {}
|
||||||
mytype = self.get_type()
|
mytype = self.get_type()
|
||||||
if mytype in self.dtypes:
|
if mytype in self.types:
|
||||||
for field in self.dtypes[mytype]:
|
for field in self.types[mytype]:
|
||||||
bits = self.dtypes[self.get_type()][field]
|
bits = self.types[self.get_type()][field]
|
||||||
if len(bits) == 3:
|
if len(bits) == 3:
|
||||||
obj = bits[2](self.get_bits(bits[0], bits[1]))
|
obj = bits[2](self.get_bits(bits[0], bits[1]))
|
||||||
fields.update(obj.parse())
|
fields.update(obj.parse())
|
||||||
@ -92,7 +93,7 @@ class data_field:
|
|||||||
|
|
||||||
class bds09_reply(data_field):
|
class bds09_reply(data_field):
|
||||||
offset = 6
|
offset = 6
|
||||||
dtypes = { #BDS0,9 subtype 0
|
types = { #BDS0,9 subtype 0
|
||||||
0: {"sub": (6,3), "dew": (10,1), "vew": (11,11), "dns": (22,1),
|
0: {"sub": (6,3), "dew": (10,1), "vew": (11,11), "dns": (22,1),
|
||||||
"vns": (23,11), "str": (34,1), "tr": (35,6), "dvr": (41,1),
|
"vns": (23,11), "str": (34,1), "tr": (35,6), "dvr": (41,1),
|
||||||
"vr": (42,9)},
|
"vr": (42,9)},
|
||||||
@ -122,7 +123,7 @@ class bds09_reply(data_field):
|
|||||||
class me_reply(data_field):
|
class me_reply(data_field):
|
||||||
#types in this format are listed by BDS register
|
#types in this format are listed by BDS register
|
||||||
#TODO: add comments explaining these fields
|
#TODO: add comments explaining these fields
|
||||||
dtypes = { 0x05: {"ftc": (1,5), "ss": (6,2), "saf": (8,1), "alt": (9,12), "time": (21,1), "cpr": (22,1), "lat": (23,17), "lon": (40,17)}, #airborne position
|
types = { 0x05: {"ftc": (1,5), "ss": (6,2), "saf": (8,1), "alt": (9,12), "time": (21,1), "cpr": (22,1), "lat": (23,17), "lon": (40,17)}, #airborne position
|
||||||
0x06: {"ftc": (1,5), "mvt": (6,7), "gts": (13,1), "gtk": (14,7), "time": (21,1), "cpr": (22,1), "lat": (23,17), "lon": (40,17)}, #surface position
|
0x06: {"ftc": (1,5), "mvt": (6,7), "gts": (13,1), "gtk": (14,7), "time": (21,1), "cpr": (22,1), "lat": (23,17), "lon": (40,17)}, #surface position
|
||||||
0x07: {"ftc": (1,5),}, #TODO extended squitter status
|
0x07: {"ftc": (1,5),}, #TODO extended squitter status
|
||||||
0x08: {"ftc": (1,5), "cat": (6,3), "ident": (9,48)}, #extended squitter identification and type
|
0x08: {"ftc": (1,5), "cat": (6,3), "ident": (9,48)}, #extended squitter identification and type
|
||||||
@ -156,7 +157,7 @@ class me_reply(data_field):
|
|||||||
#resolves the TCAS reply types from TTI info
|
#resolves the TCAS reply types from TTI info
|
||||||
class tcas_reply(data_field):
|
class tcas_reply(data_field):
|
||||||
offset = 61
|
offset = 61
|
||||||
dtypes = { 0: {"tti": (61,2)}, #UNKNOWN
|
types = { 0: {"tti": (61,2)}, #UNKNOWN
|
||||||
1: {"tti": (61,2), "tid": (63,26)},
|
1: {"tti": (61,2), "tid": (63,26)},
|
||||||
2: {"tti": (61,2), "tida": (63,13), "tidr": (76,7), "tidb": (83,6)}
|
2: {"tti": (61,2), "tida": (63,13), "tidr": (76,7), "tidb": (83,6)}
|
||||||
}
|
}
|
||||||
@ -170,7 +171,7 @@ class tcas_reply(data_field):
|
|||||||
class mb_reply(data_field):
|
class mb_reply(data_field):
|
||||||
offset = 33 #fields offset by 33 to match documentation
|
offset = 33 #fields offset by 33 to match documentation
|
||||||
#types are based on bds1 subfield
|
#types are based on bds1 subfield
|
||||||
dtypes = { 0: {"bds1": (33,4), "bds2": (37,4)}, #TODO
|
types = { 0: {"bds1": (33,4), "bds2": (37,4)}, #TODO
|
||||||
1: {"bds1": (33,4), "bds2": (37,4), "cfs": (41,4), "acs": (45,20), "bcs": (65,16), "ecs": (81,8)},
|
1: {"bds1": (33,4), "bds2": (37,4), "cfs": (41,4), "acs": (45,20), "bcs": (65,16), "ecs": (81,8)},
|
||||||
2: {"bds1": (33,4), "bds2": (37,4), "ais": (41,48)},
|
2: {"bds1": (33,4), "bds2": (37,4), "ais": (41,48)},
|
||||||
3: {"bds1": (33,4), "bds2": (37,4), "ara": (41,14), "rac": (55,4), "rat": (59,1),
|
3: {"bds1": (33,4), "bds2": (37,4), "ara": (41,14), "rac": (55,4), "rat": (59,1),
|
||||||
@ -194,7 +195,7 @@ class mb_reply(data_field):
|
|||||||
|
|
||||||
class mv_reply(data_field):
|
class mv_reply(data_field):
|
||||||
offset = 33
|
offset = 33
|
||||||
dtypes = { "ara": (41,14), "mte": (60,1), "rac": (55,4), "rat": (59,1),
|
types = { "ara": (41,14), "mte": (60,1), "rac": (55,4), "rat": (59,1),
|
||||||
"vds": (33,8), "vds1": (33,4), "vds2": (37,4)
|
"vds": (33,8), "vds1": (33,4), "vds2": (37,4)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,7 +211,7 @@ class mv_reply(data_field):
|
|||||||
|
|
||||||
#the whole Mode S packet type
|
#the whole Mode S packet type
|
||||||
class modes_reply(data_field):
|
class modes_reply(data_field):
|
||||||
dtypes = { 0: {"df": (1,5), "vs": (6,1), "cc": (7,1), "sl": (9,3), "ri": (14,4), "ac": (20,13), "ap": (33,24)},
|
types = { 0: {"df": (1,5), "vs": (6,1), "cc": (7,1), "sl": (9,3), "ri": (14,4), "ac": (20,13), "ap": (33,24)},
|
||||||
4: {"df": (1,5), "fs": (6,3), "dr": (9,5), "um": (14,6), "ac": (20,13), "ap": (33,24)},
|
4: {"df": (1,5), "fs": (6,3), "dr": (9,5), "um": (14,6), "ac": (20,13), "ap": (33,24)},
|
||||||
5: {"df": (1,5), "fs": (6,3), "dr": (9,5), "um": (14,6), "id": (20,13), "ap": (33,24)},
|
5: {"df": (1,5), "fs": (6,3), "dr": (9,5), "um": (14,6), "id": (20,13), "ap": (33,24)},
|
||||||
11: {"df": (1,5), "ca": (6,3), "aa": (9,24), "pi": (33,24)},
|
11: {"df": (1,5), "ca": (6,3), "aa": (9,24), "pi": (33,24)},
|
||||||
@ -334,13 +335,13 @@ def parseBDS09_1(data):
|
|||||||
ew = bool(data["dew"])
|
ew = bool(data["dew"])
|
||||||
subtype = data["sub"]
|
subtype = data["sub"]
|
||||||
if subtype == 0x02:
|
if subtype == 0x02:
|
||||||
ns_vel *= 4
|
ns_vel <<= 2
|
||||||
ew_vel *= 4
|
ew_vel <<= 2
|
||||||
|
|
||||||
velocity = math.hypot(ns_vel, ew_vel)
|
velocity = math.hypot(ns_vel, ew_vel)
|
||||||
if ew:
|
if ew:
|
||||||
ew_vel = 0 - ew_vel
|
ew_vel = 0 - ew_vel
|
||||||
|
|
||||||
if ns_vel == 0:
|
if ns_vel == 0:
|
||||||
heading = 0
|
heading = 0
|
||||||
else:
|
else:
|
||||||
@ -422,12 +423,12 @@ def parse_TCAS_CRM(data):
|
|||||||
def make_parser(pub):
|
def make_parser(pub):
|
||||||
publisher = pub
|
publisher = pub
|
||||||
def publish(message):
|
def publish(message):
|
||||||
[data, ecc, reference, int_timestamp, frac_timestamp] = message.split()
|
[data, ecc, reference, timestamp] = message.split()
|
||||||
try:
|
try:
|
||||||
ret = air_modes.modes_report(modes_reply(int(data, 16)),
|
ret = air_modes.modes_report(modes_reply(int(data, 16)),
|
||||||
int(ecc, 16),
|
int(ecc, 16),
|
||||||
10.0*math.log10(max(1e-8,float(reference))),
|
10.0*math.log10(max(1e-8,float(reference))),
|
||||||
air_modes.stamp(int(int_timestamp), float(frac_timestamp)))
|
air_modes.stamp(0, float(timestamp)))
|
||||||
pub["modes_dl"] = ret
|
pub["modes_dl"] = ret
|
||||||
pub["type%i_dl" % ret.data.get_type()] = ret
|
pub["type%i_dl" % ret.data.get_type()] = ret
|
||||||
except ADSBError:
|
except ADSBError:
|
||||||
|
59
python/qa_gr-air-modes.py
Executable file
59
python/qa_gr-air-modes.py
Executable file
@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2004,2007 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of GNU Radio
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
from gnuradio import gr, gr_unittest
|
||||||
|
import gr-air-modes_swig
|
||||||
|
|
||||||
|
class qa_gr-air-modes (gr_unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp (self):
|
||||||
|
self.tb = gr.top_block ()
|
||||||
|
|
||||||
|
def tearDown (self):
|
||||||
|
self.tb = None
|
||||||
|
|
||||||
|
def test_001_square_ff (self):
|
||||||
|
src_data = (-3, 4, -5.5, 2, 3)
|
||||||
|
expected_result = (9, 16, 30.25, 4, 9)
|
||||||
|
src = gr.vector_source_f (src_data)
|
||||||
|
sqr = gr-air-modes_swig.square_ff ()
|
||||||
|
dst = gr.vector_sink_f ()
|
||||||
|
self.tb.connect (src, sqr)
|
||||||
|
self.tb.connect (sqr, dst)
|
||||||
|
self.tb.run ()
|
||||||
|
result_data = dst.data ()
|
||||||
|
self.assertFloatTuplesAlmostEqual (expected_result, result_data, 6)
|
||||||
|
|
||||||
|
def test_002_square2_ff (self):
|
||||||
|
src_data = (-3, 4, -5.5, 2, 3)
|
||||||
|
expected_result = (9, 16, 30.25, 4, 9)
|
||||||
|
src = gr.vector_source_f (src_data)
|
||||||
|
sqr = gr-air-modes_swig.square2_ff ()
|
||||||
|
dst = gr.vector_sink_f ()
|
||||||
|
self.tb.connect (src, sqr)
|
||||||
|
self.tb.connect (sqr, dst)
|
||||||
|
self.tb.run ()
|
||||||
|
result_data = dst.data ()
|
||||||
|
self.assertFloatTuplesAlmostEqual (expected_result, result_data, 6)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
gr_unittest.main ()
|
@ -113,7 +113,7 @@ class modes_radio (gr.top_block, pubsub):
|
|||||||
help="set sample rate [default=%default]")
|
help="set sample rate [default=%default]")
|
||||||
group.add_option("-T", "--threshold", type="eng_float", default=7.0,
|
group.add_option("-T", "--threshold", type="eng_float", default=7.0,
|
||||||
help="set pulse detection threshold above noise in dB [default=%default]")
|
help="set pulse detection threshold above noise in dB [default=%default]")
|
||||||
group.add_option("-p","--pmf", action="store_true", default=True,
|
group.add_option("-p","--pmf", action="store_true", default=False,
|
||||||
help="Use pulse matched filtering [default=%default]")
|
help="Use pulse matched filtering [default=%default]")
|
||||||
group.add_option("-d","--dcblock", action="store_true", default=False,
|
group.add_option("-d","--dcblock", action="store_true", default=False,
|
||||||
help="Use a DC blocking filter (best for HackRF Jawbreaker) [default=%default]")
|
help="Use a DC blocking filter (best for HackRF Jawbreaker) [default=%default]")
|
||||||
@ -129,7 +129,7 @@ class modes_radio (gr.top_block, pubsub):
|
|||||||
def set_gain(self, gain):
|
def set_gain(self, gain):
|
||||||
if self.live_source():
|
if self.live_source():
|
||||||
self._u.set_gain(gain)
|
self._u.set_gain(gain)
|
||||||
print("Gain is %f" % self.get_gain())
|
print "Gain is %f" % self.get_gain()
|
||||||
return self.get_gain()
|
return self.get_gain()
|
||||||
|
|
||||||
def set_rate(self, rate):
|
def set_rate(self, rate):
|
||||||
@ -164,19 +164,13 @@ class modes_radio (gr.top_block, pubsub):
|
|||||||
if options.source == "uhd":
|
if options.source == "uhd":
|
||||||
#UHD source by default
|
#UHD source by default
|
||||||
from gnuradio import uhd
|
from gnuradio import uhd
|
||||||
self._u = uhd.usrp_source(
|
self._u = uhd.single_usrp_source(options.args, uhd.io_type_t.COMPLEX_FLOAT32, 1)
|
||||||
options.args,
|
|
||||||
uhd.stream_args(
|
|
||||||
cpu_format="fc32",
|
|
||||||
channels=range(1),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
if(options.subdev):
|
if(options.subdev):
|
||||||
self._u.set_subdev_spec(options.subdev, 0)
|
self._u.set_subdev_spec(options.subdev, 0)
|
||||||
|
|
||||||
if not self._u.set_center_freq(options.freq):
|
if not self._u.set_center_freq(options.freq):
|
||||||
print("Failed to set initial frequency")
|
print "Failed to set initial frequency"
|
||||||
|
|
||||||
#check for GPSDO
|
#check for GPSDO
|
||||||
#if you have a GPSDO, UHD will automatically set the timestamp to UTC time
|
#if you have a GPSDO, UHD will automatically set the timestamp to UTC time
|
||||||
@ -194,9 +188,9 @@ class modes_radio (gr.top_block, pubsub):
|
|||||||
g = self._u.get_gain_range()
|
g = self._u.get_gain_range()
|
||||||
options.gain = (g.start()+g.stop()) / 2.0
|
options.gain = (g.start()+g.stop()) / 2.0
|
||||||
|
|
||||||
print("Setting gain to %i" % options.gain)
|
print "Setting gain to %i" % options.gain
|
||||||
self._u.set_gain(options.gain)
|
self._u.set_gain(options.gain)
|
||||||
print("Gain is %i" % self._u.get_gain())
|
print "Gain is %i" % self._u.get_gain()
|
||||||
|
|
||||||
#TODO: detect if you're using an RTLSDR or Jawbreaker
|
#TODO: detect if you're using an RTLSDR or Jawbreaker
|
||||||
#and set up accordingly.
|
#and set up accordingly.
|
||||||
@ -206,13 +200,13 @@ class modes_radio (gr.top_block, pubsub):
|
|||||||
# self._u.set_sample_rate(3.2e6) #fixed for RTL dongles
|
# self._u.set_sample_rate(3.2e6) #fixed for RTL dongles
|
||||||
self._u.set_sample_rate(options.rate)
|
self._u.set_sample_rate(options.rate)
|
||||||
if not self._u.set_center_freq(options.freq):
|
if not self._u.set_center_freq(options.freq):
|
||||||
print("Failed to set initial frequency")
|
print "Failed to set initial frequency"
|
||||||
|
|
||||||
# self._u.set_gain_mode(0) #manual gain mode
|
# self._u.set_gain_mode(0) #manual gain mode
|
||||||
if options.gain is None:
|
if options.gain is None:
|
||||||
options.gain = 34
|
options.gain = 34
|
||||||
self._u.set_gain(options.gain)
|
self._u.set_gain(options.gain)
|
||||||
print("Gain is %i" % self._u.get_gain())
|
print "Gain is %i" % self._u.get_gain()
|
||||||
|
|
||||||
#Note: this should only come into play if using an RTLSDR.
|
#Note: this should only come into play if using an RTLSDR.
|
||||||
# lpfiltcoeffs = gr.firdes.low_pass(1, 5*3.2e6, 1.6e6, 300e3)
|
# lpfiltcoeffs = gr.firdes.low_pass(1, 5*3.2e6, 1.6e6, 300e3)
|
||||||
@ -225,13 +219,13 @@ class modes_radio (gr.top_block, pubsub):
|
|||||||
ip, port = re.search("(.*)\:(\d{1,5})", options.source).groups()
|
ip, port = re.search("(.*)\:(\d{1,5})", options.source).groups()
|
||||||
except:
|
except:
|
||||||
raise Exception("Please input UDP source e.g. 192.168.10.1:12345")
|
raise Exception("Please input UDP source e.g. 192.168.10.1:12345")
|
||||||
self._u = blocks.udp_source(gr.sizeof_gr_complex, ip, int(port))
|
self._u = gr.udp_source(gr.sizeof_gr_complex, ip, int(port))
|
||||||
print("Using UDP source %s:%s" % (ip, port))
|
print "Using UDP source %s:%s" % (ip, port)
|
||||||
else:
|
else:
|
||||||
self._u = blocks.file_source(gr.sizeof_gr_complex, options.source)
|
self._u = blocks.file_source(gr.sizeof_gr_complex, options.source)
|
||||||
print("Using file source %s" % options.source)
|
print "Using file source %s" % options.source
|
||||||
|
|
||||||
print("Rate is %i" % (options.rate,))
|
print "Rate is %i" % (options.rate,)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.stop()
|
self.stop()
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import time, os, sys, socket
|
import time, os, sys, socket
|
||||||
|
from string import split, join
|
||||||
from datetime import *
|
from datetime import *
|
||||||
|
|
||||||
class raw_server:
|
class raw_server:
|
||||||
@ -40,12 +41,12 @@ class raw_server:
|
|||||||
conn.send(msg)
|
conn.send(msg)
|
||||||
except socket.error:
|
except socket.error:
|
||||||
self._conns.remove(conn)
|
self._conns.remove(conn)
|
||||||
print("Connections: ", len(self._conns))
|
print "Connections: ", len(self._conns)
|
||||||
|
|
||||||
def add_pending_conns(self):
|
def add_pending_conns(self):
|
||||||
try:
|
try:
|
||||||
conn, addr = self._s.accept()
|
conn, addr = self._s.accept()
|
||||||
self._conns.append(conn)
|
self._conns.append(conn)
|
||||||
print("Connections: ", len(self._conns))
|
print "Connections: ", len(self._conns)
|
||||||
except socket.error:
|
except socket.error:
|
||||||
pass
|
pass
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
from gnuradio import gr, blocks, filter
|
from gnuradio import gr, blocks, filter
|
||||||
import air_modes
|
import air_modes_swig
|
||||||
|
|
||||||
class rx_path(gr.hier_block2):
|
class rx_path(gr.hier_block2):
|
||||||
|
|
||||||
@ -54,10 +54,10 @@ class rx_path(gr.hier_block2):
|
|||||||
self._avg = blocks.moving_average_ff(48*self._spc, 1.0/(48*self._spc))#, self._rate) # 3 preambles
|
self._avg = blocks.moving_average_ff(48*self._spc, 1.0/(48*self._spc))#, self._rate) # 3 preambles
|
||||||
|
|
||||||
# Synchronize to Mode-S preamble
|
# Synchronize to Mode-S preamble
|
||||||
self._sync = air_modes.preamble(self._rate, self._threshold)
|
self._sync = air_modes_swig.preamble(self._rate, self._threshold)
|
||||||
|
|
||||||
# Slice Mode-S bits and send to message queue
|
# Slice Mode-S bits and send to message queue
|
||||||
self._slicer = air_modes.slicer(self._queue)
|
self._slicer = air_modes_swig.slicer(self._queue)
|
||||||
|
|
||||||
# Wire up the flowgraph
|
# Wire up the flowgraph
|
||||||
self.connect(self._bb, (self._sync, 0))
|
self.connect(self._bb, (self._sync, 0))
|
||||||
@ -83,6 +83,6 @@ class rx_path(gr.hier_block2):
|
|||||||
def get_pmf(self, pmf):
|
def get_pmf(self, pmf):
|
||||||
return not (self._bb == self._demod)
|
return not (self._bb == self._demod)
|
||||||
|
|
||||||
def get_threshold(self):
|
def get_threshold(self, threshold):
|
||||||
return self._sync.get_threshold()
|
return self._sync.get_threshold()
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import time, os, sys, socket
|
import time, os, sys, socket
|
||||||
|
from string import split, join
|
||||||
import air_modes
|
import air_modes
|
||||||
import datetime
|
import datetime
|
||||||
from air_modes.exceptions import *
|
from air_modes.exceptions import *
|
||||||
@ -82,7 +83,7 @@ class output_sbs1:
|
|||||||
# dictionary is getting too large.
|
# dictionary is getting too large.
|
||||||
if len(self._aircraft_id_map) > 1e4:
|
if len(self._aircraft_id_map) > 1e4:
|
||||||
minimum = min(self._aircraft_id_map.values()) + (len(self._aircraft_id_map) - 1e4)
|
minimum = min(self._aircraft_id_map.values()) + (len(self._aircraft_id_map) - 1e4)
|
||||||
for icao, _id in dict(self._aircraft_id_map).iteritems():
|
for icao, _id in self._aircraft_id_map.iteritems():
|
||||||
if _id < minimum:
|
if _id < minimum:
|
||||||
del self._aircraft_id_map[icao]
|
del self._aircraft_id_map[icao]
|
||||||
|
|
||||||
@ -93,12 +94,11 @@ class output_sbs1:
|
|||||||
try:
|
try:
|
||||||
sbs1_msg = self.parse(msg)
|
sbs1_msg = self.parse(msg)
|
||||||
if sbs1_msg is not None:
|
if sbs1_msg is not None:
|
||||||
sbs1_bytes = sbs1_msg.encode('utf-8')
|
|
||||||
for conn in self._conns[:]: #iterate over a copy of the list
|
for conn in self._conns[:]: #iterate over a copy of the list
|
||||||
conn.send(sbs1_bytes)
|
conn.send(sbs1_msg)
|
||||||
except socket.error:
|
except socket.error:
|
||||||
self._conns.remove(conn)
|
self._conns.remove(conn)
|
||||||
print("Connections: ", len(self._conns))
|
print "Connections: ", len(self._conns)
|
||||||
except ADSBError:
|
except ADSBError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ class output_sbs1:
|
|||||||
try:
|
try:
|
||||||
conn, addr = self._s.accept()
|
conn, addr = self._s.accept()
|
||||||
self._conns.append(conn)
|
self._conns.append(conn)
|
||||||
print("Connections: ", len(self._conns))
|
print "Connections: ", len(self._conns)
|
||||||
except socket.error:
|
except socket.error:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import time, os, sys, threading
|
import time, os, sys, threading
|
||||||
|
from string import split, join
|
||||||
import air_modes
|
import air_modes
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from air_modes.exceptions import *
|
from air_modes.exceptions import *
|
||||||
|
@ -27,13 +27,13 @@ import time
|
|||||||
import threading
|
import threading
|
||||||
import zmq
|
import zmq
|
||||||
from gnuradio.gr.pubsub import pubsub
|
from gnuradio.gr.pubsub import pubsub
|
||||||
import queue
|
import Queue
|
||||||
|
|
||||||
class zmq_pubsub_iface(threading.Thread):
|
class zmq_pubsub_iface(threading.Thread):
|
||||||
def __init__(self, context, subaddr=None, pubaddr=None):
|
def __init__(self, context, subaddr=None, pubaddr=None):
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
#private data
|
#private data
|
||||||
self._queue = queue.Queue()
|
self._queue = Queue.Queue()
|
||||||
self._subsocket = context.socket(zmq.SUB)
|
self._subsocket = context.socket(zmq.SUB)
|
||||||
self._pubsocket = context.socket(zmq.PUB)
|
self._pubsocket = context.socket(zmq.PUB)
|
||||||
self._subaddr = subaddr
|
self._subaddr = subaddr
|
||||||
@ -46,11 +46,11 @@ class zmq_pubsub_iface(threading.Thread):
|
|||||||
self._pubsub = pubsub()
|
self._pubsub = pubsub()
|
||||||
if self._pubaddr is not None:
|
if self._pubaddr is not None:
|
||||||
for addr in self._pubaddr:
|
for addr in self._pubaddr:
|
||||||
self._pubsocket.bind(addr.encode('ascii'))
|
self._pubsocket.bind(addr)
|
||||||
|
|
||||||
self._poller = zmq.Poller()
|
self._poller = zmq.Poller()
|
||||||
self._poller.register(self._subsocket, zmq.POLLIN)
|
self._poller.register(self._subsocket, zmq.POLLIN)
|
||||||
|
|
||||||
#public data
|
#public data
|
||||||
self.shutdown = threading.Event()
|
self.shutdown = threading.Event()
|
||||||
self.finished = threading.Event()
|
self.finished = threading.Event()
|
||||||
@ -63,14 +63,14 @@ class zmq_pubsub_iface(threading.Thread):
|
|||||||
if not self._subaddr:
|
if not self._subaddr:
|
||||||
raise Exception("No subscriber address set")
|
raise Exception("No subscriber address set")
|
||||||
for addr in self._subaddr:
|
for addr in self._subaddr:
|
||||||
self._subsocket.connect(addr.encode('ascii'))
|
self._subsocket.connect(addr)
|
||||||
self._sub_connected = True
|
self._sub_connected = True
|
||||||
self._subsocket.setsockopt(zmq.SUBSCRIBE, key.encode('ascii'))
|
self._subsocket.setsockopt(zmq.SUBSCRIBE, key)
|
||||||
self._pubsub.subscribe(key.encode('ascii'), subscriber)
|
self._pubsub.subscribe(key, subscriber)
|
||||||
|
|
||||||
def unsubscribe(self, key, subscriber):
|
def unsubscribe(self, key, subscriber):
|
||||||
self._subsocket.setsockopt(zmq.UNSUBSCRIBE, key.encode('ascii'))
|
self._subsocket.setsockopt(zmq.UNSUBSCRIBE, key)
|
||||||
self._pubsub.unsubscribe(key.encode('ascii'), subscriber)
|
self._pubsub.unsubscribe(key, subscriber)
|
||||||
|
|
||||||
#executed from the thread context(s) of the caller(s)
|
#executed from the thread context(s) of the caller(s)
|
||||||
#so we use a queue to push sending into the run loop
|
#so we use a queue to push sending into the run loop
|
||||||
@ -79,10 +79,10 @@ class zmq_pubsub_iface(threading.Thread):
|
|||||||
if not self._pubaddr:
|
if not self._pubaddr:
|
||||||
raise Exception("No publisher address set")
|
raise Exception("No publisher address set")
|
||||||
if not self.shutdown.is_set():
|
if not self.shutdown.is_set():
|
||||||
self._queue.put([key.encode('ascii'), val])
|
self._queue.put([key, val])
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return self._pubsub[key.encode('ascii')]
|
return self._pubsub[key]
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
done = False
|
done = False
|
||||||
@ -90,19 +90,16 @@ class zmq_pubsub_iface(threading.Thread):
|
|||||||
if self.shutdown.is_set():
|
if self.shutdown.is_set():
|
||||||
done = True
|
done = True
|
||||||
#send
|
#send
|
||||||
while True:
|
while not self._queue.empty():
|
||||||
try:
|
self._pubsocket.send_multipart(self._queue.get())
|
||||||
msg = self._queue.get(block=False)
|
|
||||||
self._pubsocket.send_multipart(msg)
|
|
||||||
except queue.Empty:
|
|
||||||
break
|
|
||||||
#receive
|
#receive
|
||||||
if self._sub_connected:
|
if self._sub_connected:
|
||||||
socks = [s[0].underlying for s in self._poller.poll(timeout=0) if s[1] == zmq.POLLIN]
|
socks = dict(self._poller.poll(timeout=0))
|
||||||
while self._subsocket.underlying in socks:
|
while self._subsocket in socks \
|
||||||
|
and socks[self._subsocket] == zmq.POLLIN:
|
||||||
[address, msg] = self._subsocket.recv_multipart()
|
[address, msg] = self._subsocket.recv_multipart()
|
||||||
self._pubsub[address] = msg
|
self._pubsub[address] = msg
|
||||||
socks = [s[0].underlying for s in self._poller.poll(timeout=0) if s[1] == zmq.POLLIN]
|
socks = dict(self._poller.poll(timeout=0))
|
||||||
#snooze
|
#snooze
|
||||||
if not done:
|
if not done:
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
@ -117,7 +114,7 @@ class zmq_pubsub_iface(threading.Thread):
|
|||||||
self.finished.wait(0.2)
|
self.finished.wait(0.2)
|
||||||
|
|
||||||
def pr(x):
|
def pr(x):
|
||||||
print(x)
|
print x
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
#create socket pair
|
#create socket pair
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>719</width>
|
<width>687</width>
|
||||||
<height>454</height>
|
<height>422</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -102,8 +102,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>10</x>
|
<x>10</x>
|
||||||
<y>20</y>
|
<y>20</y>
|
||||||
<width>241</width>
|
<width>236</width>
|
||||||
<height>281</height>
|
<height>251</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@ -307,7 +307,7 @@
|
|||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>10</x>
|
<x>10</x>
|
||||||
<y>190</y>
|
<y>200</y>
|
||||||
<width>221</width>
|
<width>221</width>
|
||||||
<height>22</height>
|
<height>22</height>
|
||||||
</rect>
|
</rect>
|
||||||
@ -320,7 +320,7 @@
|
|||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>10</x>
|
<x>10</x>
|
||||||
<y>210</y>
|
<y>220</y>
|
||||||
<width>221</width>
|
<width>221</width>
|
||||||
<height>22</height>
|
<height>22</height>
|
||||||
</rect>
|
</rect>
|
||||||
@ -329,16 +329,6 @@
|
|||||||
<string>Use DC blocking filter</string>
|
<string>Use DC blocking filter</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QLineEdit" name="line_my_api_key">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>90</x>
|
|
||||||
<y>250</y>
|
|
||||||
<width>121</width>
|
|
||||||
<height>27</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QGroupBox" name="group_output">
|
<widget class="QGroupBox" name="group_output">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
@ -559,19 +549,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QLabel" name="label_34">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>20</x>
|
|
||||||
<y>270</y>
|
|
||||||
<width>67</width>
|
|
||||||
<height>17</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>API Key</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="dashboard">
|
<widget class="QWidget" name="dashboard">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
@ -1054,7 +1031,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>719</width>
|
<width>687</width>
|
||||||
<height>25</height>
|
<height>25</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
@ -31,12 +31,15 @@ include(GrPython)
|
|||||||
########################################################################
|
########################################################################
|
||||||
# Setup swig generation
|
# Setup swig generation
|
||||||
########################################################################
|
########################################################################
|
||||||
set(GR_SWIG_INCLUDE_DIRS $<TARGET_PROPERTY:gnuradio::runtime_swig,INTERFACE_INCLUDE_DIRECTORIES>)
|
foreach(incdir ${GNURADIO_RUNTIME_INCLUDE_DIRS})
|
||||||
set(GR_SWIG_TARGET_DEPS gnuradio::runtime_swig)
|
list(APPEND GR_SWIG_INCLUDE_DIRS ${incdir}/gnuradio/swig)
|
||||||
|
endforeach(incdir)
|
||||||
|
|
||||||
set(GR_SWIG_LIBRARIES air_modes)
|
set(GR_SWIG_LIBRARIES air_modes)
|
||||||
|
#set(GR_SWIG_DOC_FILE ${CMAKE_CURRENT_BINARY_DIR}/gr-air-modes_swig_doc.i)
|
||||||
|
#set(GR_SWIG_DOC_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../include)
|
||||||
|
|
||||||
GR_SWIG_MAKE(air_modes_swig air_modes_swig.i)
|
GR_SWIG_MAKE(air_modes_swig air_modes.i)
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
# Install the build swig module
|
# Install the build swig module
|
||||||
|
Loading…
Reference in New Issue
Block a user