Compare commits

..

3 Commits

Author SHA1 Message Date
Nick Foster
0c98c44011 Fix PyQt4 finding during compile. 2015-01-29 11:23:14 -08:00
Philip Balister
2182e5c6b8 Update doxygen config to eliminate warning from current doxygen.
Signed-off-by: Philip Balister <philip@balister.org>
2015-01-29 14:38:27 +01:00
Philip Balister
77f4245c35 Update cmake files from gnuradio master gr_modtool output.
I ran gr_modtool to create a new module. Then replaces the top level
CMakeLists file and tweaked the details. Also about the cmake Modules.
The output compiles for x86 native and armv7a cross.

Signed-off-by: Philip Balister <philip@balister.org>
2015-01-29 14:37:30 +01:00
48 changed files with 2361 additions and 727 deletions

View File

@ -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
)

View File

@ -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
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View 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)

View 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
View 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)

View 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)

View 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)

View 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")

View 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
View 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
View 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
View 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()

View File

@ -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)

View File

@ -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")

View File

@ -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.

View File

@ -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;
}; };

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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);
} }

View File

@ -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;

View File

@ -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

View File

@ -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
# ----------------------------------------------------------------

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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',

View File

@ -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)

View 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

View File

@ -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
View File

@ -0,0 +1 @@

View File

@ -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)

View File

@ -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
View 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 ()

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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 *

View File

@ -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

View File

@ -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>

View File

@ -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