Compare commits
42 Commits
gui_model
...
e310-updat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c98c44011 | ||
|
|
2182e5c6b8 | ||
|
|
77f4245c35 | ||
|
|
da15a2daf2 | ||
|
|
9891907e97 | ||
|
|
1536dae56e | ||
|
|
48f9c2a29a | ||
|
|
78c5500c80 | ||
|
|
6f11777724 | ||
|
|
cc0fa1801b | ||
|
|
42bf16ffc4 | ||
|
|
27e0f87361 | ||
|
|
585ecf1ba6 | ||
|
|
ca4edd8808 | ||
|
|
aa5fdd17ea | ||
|
|
e47992d800 | ||
|
|
9f522cf082 | ||
|
|
3f86a74132 | ||
|
|
b3021720d6 | ||
|
|
b7627fa2d4 | ||
|
|
4d2587574a | ||
|
|
ca58874861 | ||
|
|
55559086ac | ||
|
|
c878d80e28 | ||
|
|
a528f375f7 | ||
|
|
1630e67c3b | ||
|
|
8e1bdafc51 | ||
|
|
e52e4039c0 | ||
|
|
640b13e62d | ||
|
|
2c92b15a34 | ||
|
|
797bef13d1 | ||
|
|
366e4d1736 | ||
|
|
96679fbd35 | ||
|
|
fb6143596d | ||
|
|
dfa62d0621 | ||
|
|
8d3b4d4da1 | ||
|
|
2869446a9a | ||
|
|
3540114c94 | ||
|
|
041305fd49 | ||
|
|
48c55fa7f8 | ||
|
|
1eca043bac | ||
|
|
6e230a7d9e |
@@ -1,28 +1,27 @@
|
|||||||
# 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 2.6)
|
cmake_minimum_required(VERSION 2.6)
|
||||||
project(gr-gr-air-modes CXX)
|
project(gr-gr-air-modes CXX C)
|
||||||
set(gr-gr-air-modes_VERSION_MAJOR 0)
|
set(gr-gr-air-modes_VERSION_MAJOR 0)
|
||||||
set(gr-gr-air-modes_VERSION_MINOR 0)
|
set(gr-gr-air-modes_VERSION_MINOR 0)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
@@ -34,7 +33,8 @@ if(NOT CMAKE_BUILD_TYPE)
|
|||||||
endif(NOT CMAKE_BUILD_TYPE)
|
endif(NOT CMAKE_BUILD_TYPE)
|
||||||
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "")
|
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "")
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
|
#make sure our local CMake Modules path comes first
|
||||||
|
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules)
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
# Compiler specific setup
|
# Compiler specific setup
|
||||||
@@ -47,7 +47,23 @@ endif()
|
|||||||
########################################################################
|
########################################################################
|
||||||
# Find boost
|
# Find boost
|
||||||
########################################################################
|
########################################################################
|
||||||
include(GrBoost)
|
if(UNIX AND EXISTS "/usr/lib64")
|
||||||
|
list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix
|
||||||
|
endif(UNIX AND EXISTS "/usr/lib64")
|
||||||
|
set(Boost_ADDITIONAL_VERSIONS
|
||||||
|
"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"
|
||||||
|
"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(NOT Boost_FOUND)
|
||||||
|
message(FATAL_ERROR "Boost required to compile air-modes")
|
||||||
|
endif()
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
# Install directories
|
# Install directories
|
||||||
@@ -55,7 +71,7 @@ include(GrBoost)
|
|||||||
include(GrPlatform) #define LIB_SUFFIX
|
include(GrPlatform) #define LIB_SUFFIX
|
||||||
set(GR_RUNTIME_DIR bin)
|
set(GR_RUNTIME_DIR bin)
|
||||||
set(GR_LIBRARY_DIR lib${LIB_SUFFIX})
|
set(GR_LIBRARY_DIR lib${LIB_SUFFIX})
|
||||||
set(GR_INCLUDE_DIR include)
|
set(GR_INCLUDE_DIR include/gr_air_modes)
|
||||||
set(GR_DATA_DIR share)
|
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_DOC_DIR ${GR_DATA_DIR}/doc)
|
||||||
@@ -66,26 +82,68 @@ 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)
|
set(GRC_BLOCKS_DIR ${GR_PKG_DATA_DIR}/grc/blocks)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# On Apple only, set install name and use rpath correctly, if not already set
|
||||||
|
########################################################################
|
||||||
|
if(APPLE)
|
||||||
|
if(NOT CMAKE_INSTALL_NAME_DIR)
|
||||||
|
set(CMAKE_INSTALL_NAME_DIR
|
||||||
|
${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE
|
||||||
|
PATH "Library Install Name Destination Directory" FORCE)
|
||||||
|
endif(NOT CMAKE_INSTALL_NAME_DIR)
|
||||||
|
if(NOT CMAKE_INSTALL_RPATH)
|
||||||
|
set(CMAKE_INSTALL_RPATH
|
||||||
|
${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE
|
||||||
|
PATH "Library Install RPath" FORCE)
|
||||||
|
endif(NOT CMAKE_INSTALL_RPATH)
|
||||||
|
if(NOT CMAKE_BUILD_WITH_INSTALL_RPATH)
|
||||||
|
set(CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE
|
||||||
|
BOOL "Do Build Using Library Install RPath" FORCE)
|
||||||
|
endif(NOT CMAKE_BUILD_WITH_INSTALL_RPATH)
|
||||||
|
endif(APPLE)
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
# Find gnuradio build dependencies
|
# Find gnuradio build dependencies
|
||||||
########################################################################
|
########################################################################
|
||||||
find_package(GnuradioRuntime)
|
find_package(CppUnit)
|
||||||
|
find_package(Doxygen)
|
||||||
|
|
||||||
if(NOT GNURADIO_RUNTIME_FOUND)
|
# Search for GNU Radio and its components and versions. Add any
|
||||||
message(FATAL_ERROR "GnuRadio Runtime required to compile gr-air-modes")
|
# 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()
|
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
|
# Setup the include and linker paths
|
||||||
########################################################################
|
########################################################################
|
||||||
include_directories(
|
include_directories(
|
||||||
|
${CMAKE_SOURCE_DIR}/lib
|
||||||
${CMAKE_SOURCE_DIR}/include
|
${CMAKE_SOURCE_DIR}/include
|
||||||
|
${CMAKE_BINARY_DIR}/lib
|
||||||
|
${CMAKE_BINARY_DIR}/include
|
||||||
${Boost_INCLUDE_DIRS}
|
${Boost_INCLUDE_DIRS}
|
||||||
${GNURADIO_RUNTIME_INCLUDE_DIRS}
|
${CPPUNIT_INCLUDE_DIRS}
|
||||||
|
${GNURADIO_ALL_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
link_directories(
|
link_directories(
|
||||||
${Boost_LIBRARY_DIRS}
|
${Boost_LIBRARY_DIRS}
|
||||||
|
${CPPUNIT_LIBRARY_DIRS}
|
||||||
${GNURADIO_RUNTIME_LIBRARY_DIRS}
|
${GNURADIO_RUNTIME_LIBRARY_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -108,7 +166,7 @@ add_custom_target(uninstall
|
|||||||
########################################################################
|
########################################################################
|
||||||
# Add subdirectories
|
# Add subdirectories
|
||||||
########################################################################
|
########################################################################
|
||||||
add_subdirectory(include)
|
add_subdirectory(include/gr_air_modes)
|
||||||
add_subdirectory(lib)
|
add_subdirectory(lib)
|
||||||
add_subdirectory(swig)
|
add_subdirectory(swig)
|
||||||
add_subdirectory(python)
|
add_subdirectory(python)
|
||||||
@@ -116,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
|
||||||
|
)
|
||||||
|
|||||||
176
apps/modes_gui
176
apps/modes_gui
@@ -19,7 +19,7 @@
|
|||||||
# Boston, MA 02110-1301, USA.
|
# Boston, MA 02110-1301, USA.
|
||||||
#
|
#
|
||||||
|
|
||||||
import os, sys, time, threading, datetime, math, csv, tempfile
|
import os, sys, time, threading, datetime, math, csv, tempfile, ConfigParser
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
from PyQt4 import QtCore,QtGui,QtWebKit
|
from PyQt4 import QtCore,QtGui,QtWebKit
|
||||||
from PyQt4.Qwt5 import Qwt
|
from PyQt4.Qwt5 import Qwt
|
||||||
@@ -48,27 +48,45 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
#populate antenna, rate combo boxes based on source
|
#populate antenna, rate combo boxes based on source
|
||||||
self.populate_source_options()
|
self.populate_source_options()
|
||||||
|
|
||||||
|
defaults = self.get_defaults()
|
||||||
|
|
||||||
#should round to actual achieved gain
|
#should round to actual achieved gain
|
||||||
self.ui.line_gain.insert("30")
|
self.ui.line_gain.insert(defaults["gain"])
|
||||||
|
|
||||||
#default to 5dB
|
#default to 5dB
|
||||||
self.ui.line_threshold.insert("5")
|
self.ui.line_threshold.insert(defaults["threshold"])
|
||||||
|
|
||||||
self.ui.prog_rssi.setMinimum(0)
|
if defaults["pmf"] is not None:
|
||||||
self.ui.prog_rssi.setMaximum(40)
|
self.ui.check_pmf.setChecked(bool(defaults["pmf"]))
|
||||||
|
if defaults["dcblock"] is not None:
|
||||||
|
self.ui.check_dcblock.setChecked(bool(defaults["dcblock"]))
|
||||||
|
if defaults["samplerate"] is not None:
|
||||||
|
if defaults["samplerate"] in self.rates:
|
||||||
|
self.ui.combo_rate.setCurrentIndex(self.rates.index(int(defaults["samplerate"])))
|
||||||
|
|
||||||
self.ui.combo_ant.setCurrentIndex(self.ui.combo_ant.findText("RX2"))
|
self.ui.prog_rssi.setMinimum(-60)
|
||||||
|
self.ui.prog_rssi.setMaximum(0)
|
||||||
|
|
||||||
|
if defaults["antenna"] is None:
|
||||||
|
self.ui.combo_ant.setCurrentIndex(self.ui.combo_ant.findText("RX2"))
|
||||||
|
else:
|
||||||
|
self.ui.combo_ant.setCurrentIndex(self.ui.combo_ant.findText(defaults["antenna"]))
|
||||||
|
|
||||||
#check KML by default, leave the rest unchecked.
|
#check KML by default, leave the rest unchecked.
|
||||||
self.ui.check_sbs1.setCheckState(QtCore.Qt.Unchecked)
|
self.ui.check_sbs1.setChecked(bool(defaults["sbs1"] == "1"))
|
||||||
self.ui.check_raw.setCheckState(QtCore.Qt.Unchecked)
|
self.ui.check_raw.setChecked(bool(defaults["raw"] == "1"))
|
||||||
self.ui.check_fgfs.setCheckState(QtCore.Qt.Unchecked)
|
self.ui.check_fgfs.setChecked(bool(defaults["fgfs"] == "1"))
|
||||||
self.ui.check_kml.setCheckState(QtCore.Qt.Checked)
|
self.ui.check_kml.setChecked(bool(defaults["kml"] == "1"))
|
||||||
|
|
||||||
self.ui.line_sbs1port.insert("30003")
|
self.ui.line_sbs1port.insert(defaults["sbs1port"])#"30003")
|
||||||
self.ui.line_rawport.insert("9988")
|
self.ui.line_rawport.insert(defaults["rawport"])#"9988")
|
||||||
self.ui.line_fgfsport.insert("5500")
|
self.ui.line_fgfsport.insert(defaults["fgfsport"])#"5500")
|
||||||
self.ui.line_kmlfilename.insert("modes.kml")
|
self.ui.line_kmlfilename.insert(defaults["kmlfile"])#"modes.kml")
|
||||||
|
|
||||||
|
if defaults["latitude"] is not None:
|
||||||
|
self.ui.line_my_lat.insert(defaults["latitude"])
|
||||||
|
if defaults["longitude"] is not None:
|
||||||
|
self.ui.line_my_lon.insert(defaults["longitude"])
|
||||||
|
|
||||||
#disable by default
|
#disable by default
|
||||||
self.ui.check_adsbonly.setCheckState(QtCore.Qt.Unchecked)
|
self.ui.check_adsbonly.setCheckState(QtCore.Qt.Unchecked)
|
||||||
@@ -122,9 +140,27 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
self.ui.list_aircraft.selectionModel().currentRowChanged.connect(self.update_map_highlight)
|
self.ui.list_aircraft.selectionModel().currentRowChanged.connect(self.update_map_highlight)
|
||||||
self.datamodel.dataChanged.connect(self.unmapped_widgets_dataChanged)
|
self.datamodel.dataChanged.connect(self.unmapped_widgets_dataChanged)
|
||||||
|
|
||||||
|
#hook up parameter-changed signals so we can change gain, rate, etc. while running
|
||||||
|
self.ui.combo_rate.currentIndexChanged['QString'].connect(self.update_sample_rate)
|
||||||
|
self.ui.line_gain.editingFinished.connect(self.update_gain)
|
||||||
|
self.ui.combo_source.currentIndexChanged['QString'].connect(self.populate_source_options)
|
||||||
|
|
||||||
#hook up live data text box update signal
|
#hook up live data text box update signal
|
||||||
self.live_data_changed_signal.connect(self.on_append_live_data)
|
self.live_data_changed_signal.connect(self.on_append_live_data)
|
||||||
|
|
||||||
|
self._last_live_data_update = time.time()
|
||||||
|
self._pending_msgstr = ""
|
||||||
|
|
||||||
|
self.prefs = None
|
||||||
|
|
||||||
|
def update_sample_rate(self, rate):
|
||||||
|
if self.running:
|
||||||
|
self._radio.set_rate(int(float(rate)*1e6))
|
||||||
|
|
||||||
|
def update_gain(self):
|
||||||
|
if self.running:
|
||||||
|
self._radio.set_gain(float(self.ui.line_gain.text()))
|
||||||
|
|
||||||
############ widget update functions for non-mapped widgets ############
|
############ widget update functions for non-mapped widgets ############
|
||||||
def update_heading_widget(self, index):
|
def update_heading_widget(self, index):
|
||||||
if index.model() is not None:
|
if index.model() is not None:
|
||||||
@@ -196,8 +232,10 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
elif sourceid == "Osmocom":
|
elif sourceid == "Osmocom":
|
||||||
try:
|
try:
|
||||||
import osmosdr
|
import osmosdr
|
||||||
self.src = osmosdr.source_c("")
|
self.src = osmosdr.source("")
|
||||||
self.rates = [rate.start() for rate in self.src.get_sample_rates() if (rate.start() % 2.e6) == 0]
|
self.rates = [rate.start() for rate in self.src.get_sample_rates()
|
||||||
|
if ((rate.start() % 2.e6) == 0)
|
||||||
|
or (rate.start() < 4.e6 and ((rate.start()%0.2e6) == 0))]
|
||||||
self.antennas = ["RX"]
|
self.antennas = ["RX"]
|
||||||
self.src = None
|
self.src = None
|
||||||
self.ui.combo_ant.setEnabled(False)
|
self.ui.combo_ant.setEnabled(False)
|
||||||
@@ -226,11 +264,17 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
self.ui.combo_ant.addItems(self.antennas)
|
self.ui.combo_ant.addItems(self.antennas)
|
||||||
|
|
||||||
#set up recommended sample rate
|
#set up recommended sample rate
|
||||||
recommended_rate = min(x for x in self.rates if x >= 4e6 and
|
if len(self.rates) > 1:
|
||||||
max(self.rates) % x == 0)
|
if max(self.rates) > 4.e6:
|
||||||
if recommended_rate >= 8.e6:
|
recommended_rate = min(x for x in self.rates if x >= 4e6 and
|
||||||
self.ui.check_pmf.setChecked(True)
|
max(self.rates) % x == 0)
|
||||||
self.ui.combo_rate.setCurrentIndex(self.rates.index(recommended_rate))
|
else:
|
||||||
|
recommended_rate = max(self.rates)
|
||||||
|
if recommended_rate >= 8.e6:
|
||||||
|
self.ui.check_pmf.setChecked(True)
|
||||||
|
else:
|
||||||
|
self.ui.check_pmf.setChecked(False)
|
||||||
|
self.ui.combo_rate.setCurrentIndex(self.rates.index(recommended_rate))
|
||||||
|
|
||||||
################ action handlers ####################
|
################ action handlers ####################
|
||||||
def on_combo_source_currentIndexChanged(self, index):
|
def on_combo_source_currentIndexChanged(self, index):
|
||||||
@@ -259,7 +303,8 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
options.antenna = str(self.ui.combo_ant.currentText())
|
options.antenna = str(self.ui.combo_ant.currentText())
|
||||||
options.gain = float(self.ui.line_gain.text())
|
options.gain = float(self.ui.line_gain.text())
|
||||||
options.threshold = float(self.ui.line_threshold.text())
|
options.threshold = float(self.ui.line_threshold.text())
|
||||||
options.pmf = self.ui.check_pmf.checkState()
|
options.pmf = self.ui.check_pmf.isChecked()
|
||||||
|
options.dcblock = self.ui.check_dcblock.isChecked()
|
||||||
|
|
||||||
self._servers = ["inproc://modes-radio-pub"] #TODO ADD REMOTES
|
self._servers = ["inproc://modes-radio-pub"] #TODO ADD REMOTES
|
||||||
self._relay = air_modes.zmq_pubsub_iface(self.context, subaddr=self._servers, pubaddr=None)
|
self._relay = air_modes.zmq_pubsub_iface(self.context, subaddr=self._servers, pubaddr=None)
|
||||||
@@ -337,12 +382,35 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
self.ui.button_start.setText("Stop")
|
self.ui.button_start.setText("Stop")
|
||||||
self.running = True
|
self.running = True
|
||||||
|
|
||||||
|
#grab prefs and save them
|
||||||
|
self.prefs = {}
|
||||||
|
self.prefs["samplerate"] = options.rate
|
||||||
|
self.prefs["antenna"] = options.antenna
|
||||||
|
self.prefs["gain"] = options.gain
|
||||||
|
self.prefs["pmf"] = "1" if options.pmf else "0"
|
||||||
|
self.prefs["dcblock"] = "1" if options.dcblock else "0"
|
||||||
|
self.prefs["source"] = self.ui.combo_source.currentText()
|
||||||
|
self.prefs["threshold"] = options.threshold
|
||||||
|
self.prefs["sbs1"] = "1" if self.ui.check_sbs1.isChecked() else "0"
|
||||||
|
self.prefs["sbs1port"] = int(self.ui.line_sbs1port.text())
|
||||||
|
self.prefs["fgfs"] = "1" if self.ui.check_fgfs.isChecked() else "0"
|
||||||
|
self.prefs["fgfsport"] = int(self.ui.line_fgfsport.text())
|
||||||
|
self.prefs["raw"] = "1" if self.ui.check_raw.isChecked() else "0"
|
||||||
|
self.prefs["rawport"] = int(self.ui.line_rawport.text())
|
||||||
|
self.prefs["kml"] = "1" if self.ui.check_kml.isChecked() else "0"
|
||||||
|
self.prefs["kmlfile"] = self.ui.line_kmlfilename.text()
|
||||||
|
try:
|
||||||
|
self.prefs["latitude"] = float(self.ui.line_my_lat.text())
|
||||||
|
self.prefs["longitude"] = float(self.ui.line_my_lon.text())
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
def on_quit(self):
|
def on_quit(self):
|
||||||
if self.running is True:
|
if self.running is True:
|
||||||
self._relay.close()
|
|
||||||
self._radio.close()
|
self._radio.close()
|
||||||
self._relay = None
|
|
||||||
self._radio = None
|
self._radio = None
|
||||||
|
self._relay.close()
|
||||||
|
self._relay = None
|
||||||
self._rps_timer = None
|
self._rps_timer = None
|
||||||
try:
|
try:
|
||||||
self.kmlgen.done = True
|
self.kmlgen.done = True
|
||||||
@@ -352,9 +420,19 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
if self.prefs is not None:
|
||||||
|
self.write_defaults(self.prefs)
|
||||||
|
|
||||||
#slot to catch signal emitted by output_live_data (necessary for
|
#slot to catch signal emitted by output_live_data (necessary for
|
||||||
#thread safety since output_live_data is called by another thread)
|
#thread safety since output_live_data is called by another thread)
|
||||||
def on_append_live_data(self, msgstr):
|
def on_append_live_data(self, msgstr):
|
||||||
|
self._pending_msgstr += msgstr + "\n"
|
||||||
|
if time.time() - self._last_live_data_update >= 0.1:
|
||||||
|
self._last_live_data_update = time.time()
|
||||||
|
self.update_live_data(self._pending_msgstr)
|
||||||
|
self._pending_msgstr = ""
|
||||||
|
|
||||||
|
def update_live_data(self, msgstr):
|
||||||
#limit scrollback buffer size -- is there a faster way?
|
#limit scrollback buffer size -- is there a faster way?
|
||||||
if(self.ui.text_livedata.document().lineCount() > 500):
|
if(self.ui.text_livedata.document().lineCount() > 500):
|
||||||
cursor = self.ui.text_livedata.textCursor()
|
cursor = self.ui.text_livedata.textCursor()
|
||||||
@@ -365,6 +443,56 @@ class mainwindow(QtGui.QMainWindow):
|
|||||||
self.ui.text_livedata.append(msgstr)
|
self.ui.text_livedata.append(msgstr)
|
||||||
self.ui.text_livedata.verticalScrollBar().setSliderPosition(self.ui.text_livedata.verticalScrollBar().maximum())
|
self.ui.text_livedata.verticalScrollBar().setSliderPosition(self.ui.text_livedata.verticalScrollBar().maximum())
|
||||||
|
|
||||||
|
opt_file = "~/.gr-air-modes/prefs"
|
||||||
|
def get_defaults(self):
|
||||||
|
defaults = {}
|
||||||
|
defaults["samplerate"] = None #let app pick it
|
||||||
|
defaults["pmf"] = None
|
||||||
|
defaults["dcblock"] = None
|
||||||
|
defaults["antenna"] = None
|
||||||
|
defaults["gain"] = "25"
|
||||||
|
defaults["kml"] = "1"
|
||||||
|
defaults["kmlfile"] = "modes.kml"
|
||||||
|
defaults["sbs1"] = "0"
|
||||||
|
defaults["sbs1port"] = "30003"
|
||||||
|
defaults["raw"] = "0"
|
||||||
|
defaults["rawport"] = "9988"
|
||||||
|
defaults["fgfs"] = "0"
|
||||||
|
defaults["fgfsport"] = "5500"
|
||||||
|
defaults["source"] = "UHD"
|
||||||
|
defaults["threshold"] = "5"
|
||||||
|
defaults["latitude"] = None
|
||||||
|
defaults["longitude"] = None
|
||||||
|
|
||||||
|
prefs = ConfigParser.ConfigParser(defaults)
|
||||||
|
prefs.optionxform = str
|
||||||
|
|
||||||
|
try:
|
||||||
|
prefs.read(os.path.expanduser(self.opt_file))
|
||||||
|
for item in prefs.items("GUI"):
|
||||||
|
defaults[item[0]] = item[1]
|
||||||
|
except (IOError, ConfigParser.NoSectionError):
|
||||||
|
print "No preferences file %s found, creating..." % os.path.expanduser(self.opt_file)
|
||||||
|
self.write_defaults(defaults)
|
||||||
|
|
||||||
|
return defaults
|
||||||
|
|
||||||
|
|
||||||
|
def write_defaults(self, defaults):
|
||||||
|
config = ConfigParser.RawConfigParser()
|
||||||
|
config.add_section('GUI')
|
||||||
|
|
||||||
|
for item in defaults:
|
||||||
|
config.set('GUI', item, str(defaults[item]))
|
||||||
|
|
||||||
|
dirname = os.path.dirname(os.path.expanduser(self.opt_file))
|
||||||
|
if not os.path.exists(dirname):
|
||||||
|
os.makedirs(dirname)
|
||||||
|
|
||||||
|
with open(os.path.expanduser(self.opt_file), 'wb') as prefsfile:
|
||||||
|
config.write(prefsfile)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app = QtGui.QApplication(sys.argv)
|
app = QtGui.QApplication(sys.argv)
|
||||||
window = mainwindow()
|
window = mainwindow()
|
||||||
|
|||||||
@@ -86,8 +86,9 @@ def main():
|
|||||||
sbs1port = air_modes.output_sbs1(cpr_dec, 30003, publisher)
|
sbs1port = air_modes.output_sbs1(cpr_dec, 30003, publisher)
|
||||||
|
|
||||||
tb.run()
|
tb.run()
|
||||||
|
time.sleep(0.2)
|
||||||
tb.close()
|
tb.close()
|
||||||
|
time.sleep(0.2)
|
||||||
relay.close()
|
relay.close()
|
||||||
|
|
||||||
if options.kml is not None:
|
if options.kml is not None:
|
||||||
|
|||||||
39
cmake/Modules/FindCppUnit.cmake
Normal file
39
cmake/Modules/FindCppUnit.cmake
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# http://www.cmake.org/pipermail/cmake/2006-October/011446.html
|
||||||
|
# Modified to use pkg config and use standard var names
|
||||||
|
|
||||||
|
#
|
||||||
|
# Find the CppUnit includes and library
|
||||||
|
#
|
||||||
|
# This module defines
|
||||||
|
# CPPUNIT_INCLUDE_DIR, where to find tiff.h, etc.
|
||||||
|
# CPPUNIT_LIBRARIES, the libraries to link against to use CppUnit.
|
||||||
|
# CPPUNIT_FOUND, If false, do not try to use CppUnit.
|
||||||
|
|
||||||
|
INCLUDE(FindPkgConfig)
|
||||||
|
PKG_CHECK_MODULES(PC_CPPUNIT "cppunit")
|
||||||
|
|
||||||
|
FIND_PATH(CPPUNIT_INCLUDE_DIRS
|
||||||
|
NAMES cppunit/TestCase.h
|
||||||
|
HINTS ${PC_CPPUNIT_INCLUDE_DIR}
|
||||||
|
${CMAKE_INSTALL_PREFIX}/include
|
||||||
|
PATHS
|
||||||
|
/usr/local/include
|
||||||
|
/usr/include
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(CPPUNIT_LIBRARIES
|
||||||
|
NAMES cppunit
|
||||||
|
HINTS ${PC_CPPUNIT_LIBDIR}
|
||||||
|
${CMAKE_INSTALL_PREFIX}/lib
|
||||||
|
${CMAKE_INSTALL_PREFIX}/lib64
|
||||||
|
PATHS
|
||||||
|
${CPPUNIT_INCLUDE_DIRS}/../lib
|
||||||
|
/usr/local/lib
|
||||||
|
/usr/lib
|
||||||
|
)
|
||||||
|
|
||||||
|
LIST(APPEND CPPUNIT_LIBRARIES ${CMAKE_DL_LIBS})
|
||||||
|
|
||||||
|
INCLUDE(FindPackageHandleStandardArgs)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(CPPUNIT DEFAULT_MSG CPPUNIT_LIBRARIES CPPUNIT_INCLUDE_DIRS)
|
||||||
|
MARK_AS_ADVANCED(CPPUNIT_LIBRARIES CPPUNIT_INCLUDE_DIRS)
|
||||||
@@ -1,6 +1,36 @@
|
|||||||
INCLUDE(FindPkgConfig)
|
INCLUDE(FindPkgConfig)
|
||||||
PKG_CHECK_MODULES(GNURADIO_RUNTIME gnuradio-runtime)
|
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)
|
INCLUDE(FindPackageHandleStandardArgs)
|
||||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNURADIO_RUNTIME DEFAULT_MSG GNURADIO_RUNTIME_LIBRARIES GNURADIO_RUNTIME_INCLUDE_DIRS)
|
# 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)
|
MARK_AS_ADVANCED(GNURADIO_RUNTIME_LIBRARIES GNURADIO_RUNTIME_INCLUDE_DIRS)
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
# - try to find Qwt libraries and include files
|
|
||||||
# QWT_INCLUDE_DIR where to find qwt_plot.h, etc.
|
|
||||||
# QWT_LIBRARIES libraries to link against
|
|
||||||
# QWT_FOUND If false, do not try to use Qwt
|
|
||||||
|
|
||||||
find_path (QWT_INCLUDE_DIRS
|
|
||||||
NAMES qwt_plot.h
|
|
||||||
PATHS
|
|
||||||
/usr/local/include/qwt-qt4
|
|
||||||
/usr/local/include/qwt
|
|
||||||
/usr/include/qwt-qt4
|
|
||||||
/usr/include/qwt
|
|
||||||
/opt/local/include/qwt
|
|
||||||
/sw/include/qwt
|
|
||||||
)
|
|
||||||
|
|
||||||
find_library (QWT_LIBRARIES
|
|
||||||
NAMES qwt-qt4 qwt
|
|
||||||
PATHS
|
|
||||||
/usr/local/lib
|
|
||||||
/usr/lib
|
|
||||||
/opt/local/lib
|
|
||||||
/sw/lib
|
|
||||||
)
|
|
||||||
|
|
||||||
# handle the QUIETLY and REQUIRED arguments and set QWT_FOUND to TRUE if
|
|
||||||
# all listed variables are TRUE
|
|
||||||
include ( FindPackageHandleStandardArgs )
|
|
||||||
find_package_handle_standard_args( Qwt DEFAULT_MSG QWT_LIBRARIES QWT_INCLUDE_DIRS )
|
|
||||||
MARK_AS_ADVANCED(QWT_LIBRARIES QWT_INCLUDE_DIRS)
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
# - Find zeromq libraries
|
|
||||||
# This module finds zeromq if it is installed and determines where the
|
|
||||||
# include files and libraries are. It also determines what the name of
|
|
||||||
# the library is. This code sets the following variables:
|
|
||||||
#
|
|
||||||
# ZEROMQ_FOUND - have the zeromq libs been found
|
|
||||||
# ZEROMQ_LIBRARIES - path to the zeromq library
|
|
||||||
# ZEROMQ_INCLUDE_DIRS - path to where zmq.h is found
|
|
||||||
# ZEROMQ_DEBUG_LIBRARIES - path to the debug library
|
|
||||||
|
|
||||||
#INCLUDE(CMakeFindFrameworks)
|
|
||||||
# Search for the zeromq framework on Apple.
|
|
||||||
#CMAKE_FIND_FRAMEWORKS(ZeroMQ)
|
|
||||||
|
|
||||||
IF(WIN32)
|
|
||||||
FIND_LIBRARY(ZEROMQ_DEBUG_LIBRARY
|
|
||||||
NAMES libzmq_d zmq_d
|
|
||||||
PATHS
|
|
||||||
${ZEROMQ_LIBRARIES}
|
|
||||||
)
|
|
||||||
ENDIF(WIN32)
|
|
||||||
|
|
||||||
FIND_LIBRARY(ZEROMQ_LIBRARY
|
|
||||||
NAMES libzmq zmq
|
|
||||||
PATHS
|
|
||||||
${ZEROMQ_LIBRARIES}
|
|
||||||
${NSCP_LIBRARYDIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
# IF(ZeroMQ_FRAMEWORKS AND NOT ZEROMQ_INCLUDE_DIR)
|
|
||||||
# FOREACH(dir ${ZeroMQ_FRAMEWORKS})
|
|
||||||
# SET(ZEROMQ_FRAMEWORK_INCLUDES ${ZEROMQ_FRAMEWORK_INCLUDES}
|
|
||||||
# ${dir}/Versions/${_CURRENT_VERSION}/include/zeromq${_CURRENT_VERSION})
|
|
||||||
# ENDFOREACH(dir)
|
|
||||||
# ENDIF(ZeroMQ_FRAMEWORKS AND NOT ZEROMQ_INCLUDE_DIR)
|
|
||||||
|
|
||||||
FIND_PATH(ZEROMQ_INCLUDE_DIR
|
|
||||||
NAMES zmq.hpp
|
|
||||||
PATHS
|
|
||||||
# ${ZEROMQ_FRAMEWORK_INCLUDES}
|
|
||||||
${ZEROMQ_INCLUDE_DIRS}
|
|
||||||
${NSCP_INCLUDEDIR}
|
|
||||||
${ZEROMQ_INCLUDE_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
MARK_AS_ADVANCED(
|
|
||||||
ZEROMQ_DEBUG_LIBRARY
|
|
||||||
ZEROMQ_LIBRARY
|
|
||||||
ZEROMQ_INCLUDE_DIR
|
|
||||||
)
|
|
||||||
SET(ZEROMQ_INCLUDE_DIRS "${ZEROMQ_INCLUDE_DIR}")
|
|
||||||
SET(ZEROMQ_LIBRARIES "${ZEROMQ_LIBRARY}")
|
|
||||||
SET(ZEROMQ_DEBUG_LIBRARIES "${ZEROMQ_DEBUG_LIBRARY}")
|
|
||||||
|
|
||||||
INCLUDE(FindPackageHandleStandardArgs)
|
|
||||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(ZeroMQ DEFAULT_MSG ZEROMQ_LIBRARIES ZEROMQ_INCLUDE_DIRS)
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
# 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_BOOST_CMAKE)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
set(__INCLUDED_GR_BOOST_CMAKE TRUE)
|
|
||||||
|
|
||||||
########################################################################
|
|
||||||
# Setup Boost and handle some system specific things
|
|
||||||
########################################################################
|
|
||||||
|
|
||||||
set(BOOST_REQUIRED_COMPONENTS
|
|
||||||
date_time
|
|
||||||
program_options
|
|
||||||
filesystem
|
|
||||||
system
|
|
||||||
thread
|
|
||||||
)
|
|
||||||
|
|
||||||
if(UNIX AND NOT BOOST_ROOT AND EXISTS "/usr/lib64")
|
|
||||||
list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix
|
|
||||||
endif(UNIX AND NOT BOOST_ROOT AND EXISTS "/usr/lib64")
|
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
set(BOOST_REQUIRED_COMPONENTS ${BOOST_REQUIRED_COMPONENTS} chrono)
|
|
||||||
|
|
||||||
if (NOT DEFINED BOOST_ALL_DYN_LINK)
|
|
||||||
set(BOOST_ALL_DYN_LINK TRUE)
|
|
||||||
endif()
|
|
||||||
set(BOOST_ALL_DYN_LINK "${BOOST_ALL_DYN_LINK}" CACHE BOOL "boost enable dynamic linking")
|
|
||||||
if(BOOST_ALL_DYN_LINK)
|
|
||||||
add_definitions(-DBOOST_ALL_DYN_LINK) #setup boost auto-linking in msvc
|
|
||||||
else(BOOST_ALL_DYN_LINK)
|
|
||||||
unset(BOOST_REQUIRED_COMPONENTS) #empty components list for static link
|
|
||||||
endif(BOOST_ALL_DYN_LINK)
|
|
||||||
endif(MSVC)
|
|
||||||
|
|
||||||
find_package(Boost "1.35" COMPONENTS ${BOOST_REQUIRED_COMPONENTS})
|
|
||||||
|
|
||||||
# This does not allow us to disable specific versions. It is used
|
|
||||||
# internally by cmake to know the formation newer versions. As newer
|
|
||||||
# Boost version beyond what is shown here are produced, we must extend
|
|
||||||
# this list. To disable Boost versions, see below.
|
|
||||||
set(Boost_ADDITIONAL_VERSIONS
|
|
||||||
"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"
|
|
||||||
"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"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Boost 1.52 disabled, see https://svn.boost.org/trac/boost/ticket/7669
|
|
||||||
# Similar problems with Boost 1.46 and 1.47.
|
|
||||||
|
|
||||||
OPTION(ENABLE_BAD_BOOST "Enable known bad versions of Boost" OFF)
|
|
||||||
if(ENABLE_BAD_BOOST)
|
|
||||||
MESSAGE(STATUS "Enabling use of known bad versions of Boost.")
|
|
||||||
endif(ENABLE_BAD_BOOST)
|
|
||||||
|
|
||||||
# For any unsuitable Boost version, add the version number below in
|
|
||||||
# the following format: XXYYZZ
|
|
||||||
# Where:
|
|
||||||
# XX is the major version ('10' for version 1)
|
|
||||||
# YY is the minor version number ('46' for 1.46)
|
|
||||||
# ZZ is the patcher version number (typically just '00')
|
|
||||||
set(Boost_NOGO_VERSIONS
|
|
||||||
104600 104601 104700 105200
|
|
||||||
)
|
|
||||||
|
|
||||||
foreach(ver ${Boost_NOGO_VERSIONS})
|
|
||||||
if(${Boost_VERSION} EQUAL ${ver})
|
|
||||||
if(NOT ENABLE_BAD_BOOST)
|
|
||||||
MESSAGE(STATUS "WARNING: Found a known bad version of Boost (v${Boost_VERSION}). Disabling.")
|
|
||||||
set(Boost_FOUND FALSE)
|
|
||||||
else(NOT ENABLE_BAD_BOOST)
|
|
||||||
MESSAGE(STATUS "WARNING: Found a known bad version of Boost (v${Boost_VERSION}). Continuing anyway.")
|
|
||||||
set(Boost_FOUND TRUE)
|
|
||||||
endif(NOT ENABLE_BAD_BOOST)
|
|
||||||
endif(${Boost_VERSION} EQUAL ${ver})
|
|
||||||
endforeach(ver)
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright 2010-2011 Free Software Foundation, Inc.
|
# Copyright 2010-2011,2014 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is part of GNU Radio
|
# This file is part of GNU Radio
|
||||||
#
|
#
|
||||||
@@ -94,7 +94,13 @@ macro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE flag have)
|
|||||||
include(CheckCXXCompilerFlag)
|
include(CheckCXXCompilerFlag)
|
||||||
CHECK_CXX_COMPILER_FLAG(${flag} ${have})
|
CHECK_CXX_COMPILER_FLAG(${flag} ${have})
|
||||||
if(${have})
|
if(${have})
|
||||||
add_definitions(${flag})
|
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})
|
endif(${have})
|
||||||
endmacro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE)
|
endmacro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE)
|
||||||
|
|
||||||
@@ -208,3 +214,312 @@ function(GR_GEN_TARGET_DEPS name var)
|
|||||||
set(${var} "DEPENDS;${name};COMMAND;${name}" PARENT_SCOPE)
|
set(${var} "DEPENDS;${name};COMMAND;${name}" PARENT_SCOPE)
|
||||||
endif()
|
endif()
|
||||||
endfunction(GR_GEN_TARGET_DEPS)
|
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)
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ if(PYTHON_EXECUTABLE)
|
|||||||
else(PYTHON_EXECUTABLE)
|
else(PYTHON_EXECUTABLE)
|
||||||
|
|
||||||
#use the built-in find script
|
#use the built-in find script
|
||||||
find_package(PythonInterp)
|
find_package(PythonInterp 2)
|
||||||
|
|
||||||
#and if that fails use the find program routine
|
#and if that fails use the find program routine
|
||||||
if(NOT PYTHONINTERP_FOUND)
|
if(NOT PYTHONINTERP_FOUND)
|
||||||
find_program(PYTHON_EXECUTABLE NAMES python python2.7 python2.6 python2.5)
|
find_program(PYTHON_EXECUTABLE NAMES python python2 python2.7 python2.6 python2.5)
|
||||||
if(PYTHON_EXECUTABLE)
|
if(PYTHON_EXECUTABLE)
|
||||||
set(PYTHONINTERP_FOUND TRUE)
|
set(PYTHONINTERP_FOUND TRUE)
|
||||||
endif(PYTHON_EXECUTABLE)
|
endif(PYTHON_EXECUTABLE)
|
||||||
@@ -48,8 +48,15 @@ else(PYTHON_EXECUTABLE)
|
|||||||
|
|
||||||
endif(PYTHON_EXECUTABLE)
|
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
|
#make the path to the executable appear in the cmake gui
|
||||||
set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter")
|
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)
|
#make sure we can use -B with python (introduced in 2.6)
|
||||||
if(PYTHON_EXECUTABLE)
|
if(PYTHON_EXECUTABLE)
|
||||||
@@ -96,11 +103,13 @@ endmacro(GR_PYTHON_CHECK_MODULE)
|
|||||||
########################################################################
|
########################################################################
|
||||||
# Sets the python installation directory GR_PYTHON_DIR
|
# Sets the python installation directory GR_PYTHON_DIR
|
||||||
########################################################################
|
########################################################################
|
||||||
|
if(NOT DEFINED GR_PYTHON_DIR)
|
||||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "
|
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "
|
||||||
from distutils import sysconfig
|
from distutils import sysconfig
|
||||||
print sysconfig.get_python_lib(plat_specific=True, prefix='')
|
print sysconfig.get_python_lib(plat_specific=True, prefix='')
|
||||||
" OUTPUT_VARIABLE GR_PYTHON_DIR OUTPUT_STRIP_TRAILING_WHITESPACE
|
" OUTPUT_VARIABLE GR_PYTHON_DIR OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
)
|
)
|
||||||
|
endif()
|
||||||
file(TO_CMAKE_PATH ${GR_PYTHON_DIR} GR_PYTHON_DIR)
|
file(TO_CMAKE_PATH ${GR_PYTHON_DIR} GR_PYTHON_DIR)
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
@@ -183,7 +192,7 @@ function(GR_PYTHON_INSTALL)
|
|||||||
file(TO_NATIVE_PATH ${PYTHON_EXECUTABLE} pyexe_native)
|
file(TO_NATIVE_PATH ${PYTHON_EXECUTABLE} pyexe_native)
|
||||||
|
|
||||||
if (CMAKE_CROSSCOMPILING)
|
if (CMAKE_CROSSCOMPILING)
|
||||||
set(pyexe_native /usr/bin/env python)
|
set(pyexe_native "/usr/bin/env python")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
foreach(pyfile ${GR_PYTHON_INSTALL_PROGRAMS})
|
foreach(pyfile ${GR_PYTHON_INSTALL_PROGRAMS})
|
||||||
@@ -198,8 +207,9 @@ function(GR_PYTHON_INSTALL)
|
|||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${pyexefile} DEPENDS ${pyfile}
|
OUTPUT ${pyexefile} DEPENDS ${pyfile}
|
||||||
COMMAND ${PYTHON_EXECUTABLE} -c
|
COMMAND ${PYTHON_EXECUTABLE} -c
|
||||||
\"open('${pyexefile}', 'w').write('\#!${pyexe_native}\\n'+open('${pyfile}').read())\"
|
"open('${pyexefile}','w').write('\#!${pyexe_native}\\n'+open('${pyfile}').read())"
|
||||||
COMMENT "Shebangin ${pyfile_name}"
|
COMMENT "Shebangin ${pyfile_name}"
|
||||||
|
VERBATIM
|
||||||
)
|
)
|
||||||
|
|
||||||
#on windows, python files need an extension to execute
|
#on windows, python files need an extension to execute
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ function(GR_SWIG_MAKE_DOCS output_file)
|
|||||||
set(input_files)
|
set(input_files)
|
||||||
unset(INPUT_PATHS)
|
unset(INPUT_PATHS)
|
||||||
foreach(input_path ${ARGN})
|
foreach(input_path ${ARGN})
|
||||||
if (IS_DIRECTORY ${input_path}) #when input path is a directory
|
if(IS_DIRECTORY ${input_path}) #when input path is a directory
|
||||||
file(GLOB input_path_h_files ${input_path}/*.h)
|
file(GLOB input_path_h_files ${input_path}/*.h)
|
||||||
else() #otherwise its just a file, no glob
|
else() #otherwise its just a file, no glob
|
||||||
set(input_path_h_files ${input_path})
|
set(input_path_h_files ${input_path})
|
||||||
@@ -105,23 +105,35 @@ endfunction(GR_SWIG_MAKE_DOCS)
|
|||||||
macro(GR_SWIG_MAKE name)
|
macro(GR_SWIG_MAKE name)
|
||||||
set(ifiles ${ARGN})
|
set(ifiles ${ARGN})
|
||||||
|
|
||||||
list(APPEND GR_SWIG_TARGET_DEPS ${GR_SWIG_LIBRARIES})
|
# 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
|
#do swig doc generation if specified
|
||||||
if (GR_SWIG_DOC_FILE)
|
if(GR_SWIG_DOC_FILE)
|
||||||
set(GR_SWIG_DOCS_SOURCE_DEPS ${GR_SWIG_SOURCE_DEPS})
|
set(GR_SWIG_DOCS_SOURCE_DEPS ${GR_SWIG_SOURCE_DEPS})
|
||||||
set(GR_SWIG_DOCS_TAREGT_DEPS ${GR_SWIG_TARGET_DEPS})
|
list(APPEND GR_SWIG_DOCS_TARGET_DEPS ${GR_SWIG_TARGET_DEPS})
|
||||||
GR_SWIG_MAKE_DOCS(${GR_SWIG_DOC_FILE} ${GR_SWIG_DOC_DIRS})
|
GR_SWIG_MAKE_DOCS(${GR_SWIG_DOC_FILE} ${GR_SWIG_DOC_DIRS})
|
||||||
add_custom_target(${name}_swig_doc DEPENDS ${GR_SWIG_DOC_FILE})
|
add_custom_target(${name}_swig_doc DEPENDS ${GR_SWIG_DOC_FILE})
|
||||||
list(APPEND GR_SWIG_TARGET_DEPS ${name}_swig_doc)
|
list(APPEND GR_SWIG_TARGET_DEPS ${name}_swig_doc ${GR_RUNTIME_SWIG_DOC_FILE})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#append additional include directories
|
#append additional include directories
|
||||||
find_package(PythonLibs)
|
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_PATH}) #deprecated name (now dirs)
|
||||||
list(APPEND GR_SWIG_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS})
|
list(APPEND GR_SWIG_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS})
|
||||||
list(APPEND GR_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR})
|
|
||||||
list(APPEND GR_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR})
|
#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
|
#determine include dependencies for swig file
|
||||||
execute_process(
|
execute_process(
|
||||||
@@ -160,6 +172,9 @@ macro(GR_SWIG_MAKE name)
|
|||||||
include(UseSWIG)
|
include(UseSWIG)
|
||||||
SWIG_ADD_MODULE(${name} python ${ifiles})
|
SWIG_ADD_MODULE(${name} python ${ifiles})
|
||||||
SWIG_LINK_LIBRARIES(${name} ${PYTHON_LIBRARIES} ${GR_SWIG_LIBRARIES})
|
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)
|
endmacro(GR_SWIG_MAKE)
|
||||||
|
|
||||||
@@ -207,21 +222,25 @@ file(WRITE ${CMAKE_BINARY_DIR}/get_swig_deps.py "
|
|||||||
|
|
||||||
import os, sys, re
|
import os, sys, re
|
||||||
|
|
||||||
include_matcher = re.compile('[#|%]include\\s*[<|\"](.*)[>|\"]')
|
i_include_matcher = re.compile('%(include|import)\\s*[<|\"](.*)[>|\"]')
|
||||||
|
h_include_matcher = re.compile('#(include)\\s*[<|\"](.*)[>|\"]')
|
||||||
include_dirs = sys.argv[2].split(';')
|
include_dirs = sys.argv[2].split(';')
|
||||||
|
|
||||||
def get_swig_incs(file_path):
|
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()
|
file_contents = open(file_path, 'r').read()
|
||||||
return include_matcher.findall(file_contents, re.MULTILINE)
|
return matcher.findall(file_contents, re.MULTILINE)
|
||||||
|
|
||||||
def get_swig_deps(file_path, level):
|
def get_swig_deps(file_path, level):
|
||||||
deps = [file_path]
|
deps = [file_path]
|
||||||
if level == 0: return deps
|
if level == 0: return deps
|
||||||
for inc_file in get_swig_incs(file_path):
|
for keyword, inc_file in get_swig_incs(file_path):
|
||||||
for inc_dir in include_dirs:
|
for inc_dir in include_dirs:
|
||||||
inc_path = os.path.join(inc_dir, inc_file)
|
inc_path = os.path.join(inc_dir, inc_file)
|
||||||
if not os.path.exists(inc_path): continue
|
if not os.path.exists(inc_path): continue
|
||||||
deps.extend(get_swig_deps(inc_path, level-1))
|
deps.extend(get_swig_deps(inc_path, level-1))
|
||||||
|
break #found, we dont search in lower prio inc dirs
|
||||||
return deps
|
return deps
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ set(__INCLUDED_GR_TEST_CMAKE TRUE)
|
|||||||
# GR_TEST_TARGET_DEPS - built targets for the library path
|
# GR_TEST_TARGET_DEPS - built targets for the library path
|
||||||
# GR_TEST_LIBRARY_DIRS - directories for the library path
|
# GR_TEST_LIBRARY_DIRS - directories for the library path
|
||||||
# GR_TEST_PYTHON_DIRS - directories for the python path
|
# GR_TEST_PYTHON_DIRS - directories for the python path
|
||||||
|
# GR_TEST_ENVIRONS - other environment key/value pairs
|
||||||
########################################################################
|
########################################################################
|
||||||
function(GR_ADD_TEST test_name)
|
function(GR_ADD_TEST test_name)
|
||||||
|
|
||||||
@@ -65,7 +66,8 @@ function(GR_ADD_TEST test_name)
|
|||||||
file(TO_NATIVE_PATH "${GR_TEST_LIBRARY_DIRS}" libpath) #ok to use on dir list?
|
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?
|
file(TO_NATIVE_PATH "${GR_TEST_PYTHON_DIRS}" pypath) #ok to use on dir list?
|
||||||
|
|
||||||
set(environs "GR_DONT_LOAD_PREFS=1" "srcdir=${srcdir}")
|
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
|
#http://www.cmake.org/pipermail/cmake/2009-May/029464.html
|
||||||
#Replaced this add test + set environs code with the shell script generation.
|
#Replaced this add test + set environs code with the shell script generation.
|
||||||
@@ -89,7 +91,11 @@ function(GR_ADD_TEST test_name)
|
|||||||
list(APPEND environs "PATH=${binpath}" "${LD_PATH_VAR}=${libpath}" "PYTHONPATH=${pypath}")
|
list(APPEND environs "PATH=${binpath}" "${LD_PATH_VAR}=${libpath}" "PYTHONPATH=${pypath}")
|
||||||
|
|
||||||
#generate a bat file that sets the environment and runs the test
|
#generate a bat file that sets the environment and runs the test
|
||||||
find_program(SHELL sh)
|
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)
|
set(sh_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.sh)
|
||||||
file(WRITE ${sh_file} "#!${SHELL}\n")
|
file(WRITE ${sh_file} "#!${SHELL}\n")
|
||||||
#each line sets an environment variable
|
#each line sets an environment variable
|
||||||
|
|||||||
304
cmake/Modules/UseSWIG.cmake
Normal file
304
cmake/Modules/UseSWIG.cmake
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
# - SWIG module for CMake
|
||||||
|
# Defines the following macros:
|
||||||
|
# SWIG_ADD_MODULE(name language [ files ])
|
||||||
|
# - Define swig module with given name and specified language
|
||||||
|
# SWIG_LINK_LIBRARIES(name [ libraries ])
|
||||||
|
# - Link libraries to swig module
|
||||||
|
# All other macros are for internal use only.
|
||||||
|
# To get the actual name of the swig module,
|
||||||
|
# use: ${SWIG_MODULE_${name}_REAL_NAME}.
|
||||||
|
# Set Source files properties such as CPLUSPLUS and SWIG_FLAGS to specify
|
||||||
|
# special behavior of SWIG. Also global CMAKE_SWIG_FLAGS can be used to add
|
||||||
|
# special flags to all swig calls.
|
||||||
|
# Another special variable is CMAKE_SWIG_OUTDIR, it allows one to specify
|
||||||
|
# where to write all the swig generated module (swig -outdir option)
|
||||||
|
# The name-specific variable SWIG_MODULE_<name>_EXTRA_DEPS may be used
|
||||||
|
# to specify extra dependencies for the generated modules.
|
||||||
|
# If the source file generated by swig need some special flag you can use
|
||||||
|
# set_source_files_properties( ${swig_generated_file_fullname}
|
||||||
|
# PROPERTIES COMPILE_FLAGS "-bla")
|
||||||
|
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# Copyright 2004-2009 Kitware, Inc.
|
||||||
|
# Copyright 2009 Mathieu Malaterre <mathieu.malaterre@gmail.com>
|
||||||
|
#
|
||||||
|
# Distributed under the OSI-approved BSD License (the "License");
|
||||||
|
# see accompanying file Copyright.txt for details.
|
||||||
|
#
|
||||||
|
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||||
|
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
# See the License for more information.
|
||||||
|
#=============================================================================
|
||||||
|
# (To distribute this file outside of CMake, substitute the full
|
||||||
|
# License text for the above reference.)
|
||||||
|
|
||||||
|
set(SWIG_CXX_EXTENSION "cxx")
|
||||||
|
set(SWIG_EXTRA_LIBRARIES "")
|
||||||
|
|
||||||
|
set(SWIG_PYTHON_EXTRA_FILE_EXTENSION "py")
|
||||||
|
|
||||||
|
#
|
||||||
|
# For given swig module initialize variables associated with it
|
||||||
|
#
|
||||||
|
macro(SWIG_MODULE_INITIALIZE name language)
|
||||||
|
string(TOUPPER "${language}" swig_uppercase_language)
|
||||||
|
string(TOLOWER "${language}" swig_lowercase_language)
|
||||||
|
set(SWIG_MODULE_${name}_LANGUAGE "${swig_uppercase_language}")
|
||||||
|
set(SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG "${swig_lowercase_language}")
|
||||||
|
|
||||||
|
set(SWIG_MODULE_${name}_REAL_NAME "${name}")
|
||||||
|
if("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "UNKNOWN")
|
||||||
|
message(FATAL_ERROR "SWIG Error: Language \"${language}\" not found")
|
||||||
|
elseif("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "PYTHON")
|
||||||
|
# when swig is used without the -interface it will produce in the module.py
|
||||||
|
# a 'import _modulename' statement, which implies having a corresponding
|
||||||
|
# _modulename.so (*NIX), _modulename.pyd (Win32).
|
||||||
|
set(SWIG_MODULE_${name}_REAL_NAME "_${name}")
|
||||||
|
elseif("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "PERL")
|
||||||
|
set(SWIG_MODULE_${name}_EXTRA_FLAGS "-shadow")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#
|
||||||
|
# For a given language, input file, and output file, determine extra files that
|
||||||
|
# will be generated. This is internal swig macro.
|
||||||
|
#
|
||||||
|
|
||||||
|
macro(SWIG_GET_EXTRA_OUTPUT_FILES language outfiles generatedpath infile)
|
||||||
|
set(${outfiles} "")
|
||||||
|
get_source_file_property(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename
|
||||||
|
${infile} SWIG_MODULE_NAME)
|
||||||
|
if(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename STREQUAL "NOTFOUND")
|
||||||
|
get_filename_component(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename "${infile}" NAME_WE)
|
||||||
|
endif()
|
||||||
|
foreach(it ${SWIG_${language}_EXTRA_FILE_EXTENSION})
|
||||||
|
set(${outfiles} ${${outfiles}}
|
||||||
|
"${generatedpath}/${SWIG_GET_EXTRA_OUTPUT_FILES_module_basename}.${it}")
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Take swig (*.i) file and add proper custom commands for it
|
||||||
|
#
|
||||||
|
macro(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
|
||||||
|
set(swig_full_infile ${infile})
|
||||||
|
get_filename_component(swig_source_file_path "${infile}" PATH)
|
||||||
|
get_filename_component(swig_source_file_name_we "${infile}" NAME_WE)
|
||||||
|
get_source_file_property(swig_source_file_generated ${infile} GENERATED)
|
||||||
|
get_source_file_property(swig_source_file_cplusplus ${infile} CPLUSPLUS)
|
||||||
|
get_source_file_property(swig_source_file_flags ${infile} SWIG_FLAGS)
|
||||||
|
if("${swig_source_file_flags}" STREQUAL "NOTFOUND")
|
||||||
|
set(swig_source_file_flags "")
|
||||||
|
endif()
|
||||||
|
set(swig_source_file_fullname "${infile}")
|
||||||
|
if(${swig_source_file_path} MATCHES "^${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
string(REGEX REPLACE
|
||||||
|
"^${CMAKE_CURRENT_SOURCE_DIR}" ""
|
||||||
|
swig_source_file_relative_path
|
||||||
|
"${swig_source_file_path}")
|
||||||
|
else()
|
||||||
|
if(${swig_source_file_path} MATCHES "^${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
|
string(REGEX REPLACE
|
||||||
|
"^${CMAKE_CURRENT_BINARY_DIR}" ""
|
||||||
|
swig_source_file_relative_path
|
||||||
|
"${swig_source_file_path}")
|
||||||
|
set(swig_source_file_generated 1)
|
||||||
|
else()
|
||||||
|
set(swig_source_file_relative_path "${swig_source_file_path}")
|
||||||
|
if(swig_source_file_generated)
|
||||||
|
set(swig_source_file_fullname "${CMAKE_CURRENT_BINARY_DIR}/${infile}")
|
||||||
|
else()
|
||||||
|
set(swig_source_file_fullname "${CMAKE_CURRENT_SOURCE_DIR}/${infile}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(swig_generated_file_fullname
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
|
if(swig_source_file_relative_path)
|
||||||
|
set(swig_generated_file_fullname
|
||||||
|
"${swig_generated_file_fullname}/${swig_source_file_relative_path}")
|
||||||
|
endif()
|
||||||
|
# If CMAKE_SWIG_OUTDIR was specified then pass it to -outdir
|
||||||
|
if(CMAKE_SWIG_OUTDIR)
|
||||||
|
set(swig_outdir ${CMAKE_SWIG_OUTDIR})
|
||||||
|
else()
|
||||||
|
set(swig_outdir ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
endif()
|
||||||
|
SWIG_GET_EXTRA_OUTPUT_FILES(${SWIG_MODULE_${name}_LANGUAGE}
|
||||||
|
swig_extra_generated_files
|
||||||
|
"${swig_outdir}"
|
||||||
|
"${infile}")
|
||||||
|
set(swig_generated_file_fullname
|
||||||
|
"${swig_generated_file_fullname}/${swig_source_file_name_we}")
|
||||||
|
# add the language into the name of the file (i.e. TCL_wrap)
|
||||||
|
# this allows for the same .i file to be wrapped into different languages
|
||||||
|
set(swig_generated_file_fullname
|
||||||
|
"${swig_generated_file_fullname}${SWIG_MODULE_${name}_LANGUAGE}_wrap")
|
||||||
|
|
||||||
|
if(swig_source_file_cplusplus)
|
||||||
|
set(swig_generated_file_fullname
|
||||||
|
"${swig_generated_file_fullname}.${SWIG_CXX_EXTENSION}")
|
||||||
|
else()
|
||||||
|
set(swig_generated_file_fullname
|
||||||
|
"${swig_generated_file_fullname}.c")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Shut up some warnings from poor SWIG code generation that we
|
||||||
|
# can do nothing about, when this flag is available
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
check_cxx_compiler_flag("-Wno-unused-but-set-variable" HAVE_WNO_UNUSED_BUT_SET_VARIABLE)
|
||||||
|
if(HAVE_WNO_UNUSED_BUT_SET_VARIABLE)
|
||||||
|
set_source_files_properties(${swig_generated_file_fullname}
|
||||||
|
PROPERTIES COMPILE_FLAGS "-Wno-unused-but-set-variable")
|
||||||
|
endif(HAVE_WNO_UNUSED_BUT_SET_VARIABLE)
|
||||||
|
|
||||||
|
get_directory_property(cmake_include_directories INCLUDE_DIRECTORIES)
|
||||||
|
set(swig_include_dirs)
|
||||||
|
foreach(it ${cmake_include_directories})
|
||||||
|
set(swig_include_dirs ${swig_include_dirs} "-I${it}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(swig_special_flags)
|
||||||
|
# default is c, so add c++ flag if it is c++
|
||||||
|
if(swig_source_file_cplusplus)
|
||||||
|
set(swig_special_flags ${swig_special_flags} "-c++")
|
||||||
|
endif()
|
||||||
|
set(swig_extra_flags)
|
||||||
|
if(SWIG_MODULE_${name}_EXTRA_FLAGS)
|
||||||
|
set(swig_extra_flags ${swig_extra_flags} ${SWIG_MODULE_${name}_EXTRA_FLAGS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# hack to work around CMake bug in add_custom_command with multiple OUTPUT files
|
||||||
|
|
||||||
|
file(RELATIVE_PATH reldir ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} -c "import re, hashlib
|
||||||
|
unique = hashlib.md5('${reldir}${ARGN}').hexdigest()[:5]
|
||||||
|
print(re.sub('\\W', '_', '${name} ${reldir} ' + unique))"
|
||||||
|
OUTPUT_VARIABLE _target OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
)
|
||||||
|
|
||||||
|
file(
|
||||||
|
WRITE ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp.in
|
||||||
|
"int main(void){return 0;}\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
# create dummy dependencies
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp
|
||||||
|
DEPENDS "${swig_source_file_fullname}" ${SWIG_MODULE_${name}_EXTRA_DEPS}
|
||||||
|
COMMENT ""
|
||||||
|
)
|
||||||
|
|
||||||
|
# create the dummy target
|
||||||
|
add_executable(${_target} ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp)
|
||||||
|
|
||||||
|
# add a custom command to the dummy target
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${_target}
|
||||||
|
# Let's create the ${swig_outdir} at execution time, in case dir contains $(OutDir)
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${swig_outdir}
|
||||||
|
COMMAND "${SWIG_EXECUTABLE}"
|
||||||
|
ARGS "-${SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG}"
|
||||||
|
${swig_source_file_flags}
|
||||||
|
${CMAKE_SWIG_FLAGS}
|
||||||
|
-outdir ${swig_outdir}
|
||||||
|
${swig_special_flags}
|
||||||
|
${swig_extra_flags}
|
||||||
|
${swig_include_dirs}
|
||||||
|
-o "${swig_generated_file_fullname}"
|
||||||
|
"${swig_source_file_fullname}"
|
||||||
|
COMMENT "Swig source"
|
||||||
|
)
|
||||||
|
|
||||||
|
#add dummy independent dependencies from the _target to each file
|
||||||
|
#that will be generated by the SWIG command above
|
||||||
|
|
||||||
|
set(${outfiles} "${swig_generated_file_fullname}" ${swig_extra_generated_files})
|
||||||
|
|
||||||
|
foreach(swig_gen_file ${${outfiles}})
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${swig_gen_file}
|
||||||
|
COMMAND ""
|
||||||
|
DEPENDS ${_target}
|
||||||
|
COMMENT ""
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set_source_files_properties(
|
||||||
|
${outfiles} PROPERTIES GENERATED 1
|
||||||
|
)
|
||||||
|
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create Swig module
|
||||||
|
#
|
||||||
|
macro(SWIG_ADD_MODULE name language)
|
||||||
|
SWIG_MODULE_INITIALIZE(${name} ${language})
|
||||||
|
set(swig_dot_i_sources)
|
||||||
|
set(swig_other_sources)
|
||||||
|
foreach(it ${ARGN})
|
||||||
|
if(${it} MATCHES ".*\\.i$")
|
||||||
|
set(swig_dot_i_sources ${swig_dot_i_sources} "${it}")
|
||||||
|
else()
|
||||||
|
set(swig_other_sources ${swig_other_sources} "${it}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(swig_generated_sources)
|
||||||
|
foreach(it ${swig_dot_i_sources})
|
||||||
|
SWIG_ADD_SOURCE_TO_MODULE(${name} swig_generated_source ${it})
|
||||||
|
set(swig_generated_sources ${swig_generated_sources} "${swig_generated_source}")
|
||||||
|
endforeach()
|
||||||
|
get_directory_property(swig_extra_clean_files ADDITIONAL_MAKE_CLEAN_FILES)
|
||||||
|
set_directory_properties(PROPERTIES
|
||||||
|
ADDITIONAL_MAKE_CLEAN_FILES "${swig_extra_clean_files};${swig_generated_sources}")
|
||||||
|
add_library(${SWIG_MODULE_${name}_REAL_NAME}
|
||||||
|
MODULE
|
||||||
|
${swig_generated_sources}
|
||||||
|
${swig_other_sources})
|
||||||
|
string(TOLOWER "${language}" swig_lowercase_language)
|
||||||
|
if ("${swig_lowercase_language}" STREQUAL "java")
|
||||||
|
if (APPLE)
|
||||||
|
# In java you want:
|
||||||
|
# System.loadLibrary("LIBRARY");
|
||||||
|
# then JNI will look for a library whose name is platform dependent, namely
|
||||||
|
# MacOS : libLIBRARY.jnilib
|
||||||
|
# Windows: LIBRARY.dll
|
||||||
|
# Linux : libLIBRARY.so
|
||||||
|
set_target_properties (${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".jnilib")
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
if ("${swig_lowercase_language}" STREQUAL "python")
|
||||||
|
# this is only needed for the python case where a _modulename.so is generated
|
||||||
|
set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "")
|
||||||
|
# Python extension modules on Windows must have the extension ".pyd"
|
||||||
|
# instead of ".dll" as of Python 2.5. Older python versions do support
|
||||||
|
# this suffix.
|
||||||
|
# http://docs.python.org/whatsnew/ports.html#SECTION0001510000000000000000
|
||||||
|
# <quote>
|
||||||
|
# Windows: .dll is no longer supported as a filename extension for extension modules.
|
||||||
|
# .pyd is now the only filename extension that will be searched for.
|
||||||
|
# </quote>
|
||||||
|
if(WIN32 AND NOT CYGWIN)
|
||||||
|
set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".pyd")
|
||||||
|
endif()
|
||||||
|
endif ()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Like TARGET_LINK_LIBRARIES but for swig modules
|
||||||
|
#
|
||||||
|
macro(SWIG_LINK_LIBRARIES name)
|
||||||
|
if(SWIG_MODULE_${name}_REAL_NAME)
|
||||||
|
target_link_libraries(${SWIG_MODULE_${name}_REAL_NAME} ${ARGN})
|
||||||
|
else()
|
||||||
|
message(SEND_ERROR "Cannot find Swig library \"${name}\".")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
@@ -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.
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
# Copyright 2010 Nick Foster
|
|
||||||
#
|
|
||||||
# This file is part of gr-air-modes
|
|
||||||
#
|
|
||||||
# gr-air-modes is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 3, or (at your option)
|
|
||||||
# any later version.
|
|
||||||
#
|
|
||||||
# gr-air-modes is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with gr-air-modes; see the file COPYING. If not, write to
|
|
||||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
# Boston, MA 02110-1301, USA.
|
|
||||||
#
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef INCLUDED_AIR_MODES_int_and_dump_H
|
|
||||||
#define INCLUDED_AIR_MODES_int_and_dump_H
|
|
||||||
|
|
||||||
#include <gr_block.h>
|
|
||||||
|
|
||||||
class air_modes_int_and_dump;
|
|
||||||
typedef boost::shared_ptr<air_modes_int_and_dump> air_modes_int_and_dump_sptr;
|
|
||||||
|
|
||||||
air_modes_int_and_dump_sptr air_make_modes_int_and_dump(int samples_per_chip);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief mode select int_and_dump filter
|
|
||||||
* \ingroup block
|
|
||||||
*/
|
|
||||||
class air_modes_int_and_dump : public gr_block
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
friend air_modes_int_and_dump_sptr air_make_modes_int_and_dump(int samples_per_chip);
|
|
||||||
air_modes_int_and_dump(int samples_per_chip);
|
|
||||||
|
|
||||||
int d_samples_per_chip;
|
|
||||||
float d_acc;
|
|
||||||
float d_pos;
|
|
||||||
|
|
||||||
public:
|
|
||||||
int general_work (int noutput_items,
|
|
||||||
gr_vector_int &ninput_items,
|
|
||||||
gr_vector_const_void_star &input_items,
|
|
||||||
gr_vector_void_star &output_items);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* INCLUDED_AIR_MODES_int_and_dump_H */
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
# Copyright 2010 Nick Foster
|
|
||||||
#
|
|
||||||
# This file is part of gr-air-modes
|
|
||||||
#
|
|
||||||
# gr-air-modes is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 3, or (at your option)
|
|
||||||
# any later version.
|
|
||||||
#
|
|
||||||
# gr-air-modes is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with gr-air-modes; see the file COPYING. If not, write to
|
|
||||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
# Boston, MA 02110-1301, USA.
|
|
||||||
#
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef INCLUDED_AIR_MODES_PREAMBLE_H
|
|
||||||
#define INCLUDED_AIR_MODES_PREAMBLE_H
|
|
||||||
|
|
||||||
#include <gnuradio/block.h>
|
|
||||||
#include <air_modes_api.h>
|
|
||||||
|
|
||||||
class air_modes_preamble;
|
|
||||||
typedef boost::shared_ptr<air_modes_preamble> air_modes_preamble_sptr;
|
|
||||||
|
|
||||||
AIR_MODES_API air_modes_preamble_sptr air_make_modes_preamble(int channel_rate, float threshold_db);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief mode select preamble detection
|
|
||||||
* \ingroup block
|
|
||||||
*/
|
|
||||||
class AIR_MODES_API air_modes_preamble : public gr::block
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
friend air_modes_preamble_sptr air_make_modes_preamble(int channel_rate, float threshold_db);
|
|
||||||
air_modes_preamble(int channel_rate, float threshold_db);
|
|
||||||
|
|
||||||
int d_check_width;
|
|
||||||
int d_chip_rate;
|
|
||||||
float d_preamble_length_us;
|
|
||||||
int d_samples_per_chip;
|
|
||||||
int d_samples_per_symbol;
|
|
||||||
float d_threshold_db;
|
|
||||||
float d_threshold;
|
|
||||||
pmt::pmt_t d_me, d_key;
|
|
||||||
gr::tag_t d_timestamp;
|
|
||||||
double d_secs_per_sample;
|
|
||||||
|
|
||||||
public:
|
|
||||||
int general_work (int noutput_items,
|
|
||||||
gr_vector_int &ninput_items,
|
|
||||||
gr_vector_const_void_star &input_items,
|
|
||||||
gr_vector_void_star &output_items);
|
|
||||||
|
|
||||||
void set_rate(int channel_rate);
|
|
||||||
void set_threshold(float threshold_db);
|
|
||||||
float get_threshold(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* INCLUDED_AIR_MODES_PREAMBLE_H */
|
|
||||||
@@ -21,9 +21,9 @@
|
|||||||
# Install public header files
|
# Install public header files
|
||||||
########################################################################
|
########################################################################
|
||||||
install(FILES
|
install(FILES
|
||||||
air_modes_preamble.h
|
preamble.h
|
||||||
air_modes_slicer.h
|
slicer.h
|
||||||
air_modes_types.h
|
types.h
|
||||||
air_modes_api.h
|
api.h
|
||||||
DESTINATION include/gr-air-modes
|
DESTINATION include/gr_air_modes
|
||||||
)
|
)
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
#ifndef INCLUDED_MODES_CRC_H
|
#ifndef INCLUDED_MODES_CRC_H
|
||||||
#define INCLUDED_MODES_CRC_H
|
#define INCLUDED_MODES_CRC_H
|
||||||
extern const unsigned int modes_crc_table[112];
|
extern const unsigned int modes_crc_table[112];
|
||||||
int modes_check_crc(unsigned char data[], int length);
|
unsigned int modes_check_crc(unsigned char data[], int length);
|
||||||
bruteResultTypeDef modes_ec_brute(modes_packet &err_packet);
|
bruteResultTypeDef modes_ec_brute(modes_packet &err_packet);
|
||||||
unsigned next_set_of_n_elements(unsigned x);
|
unsigned next_set_of_n_elements(unsigned x);
|
||||||
|
|
||||||
51
include/gr_air_modes/preamble.h
Normal file
51
include/gr_air_modes/preamble.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
# Copyright 2013 Nick Foster
|
||||||
|
#
|
||||||
|
# This file is part of gr-air-modes
|
||||||
|
#
|
||||||
|
# gr-air-modes is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# gr-air-modes is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with gr-air-modes; see the file COPYING. If not, write to
|
||||||
|
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INCLUDED_AIR_MODES_PREAMBLE_H
|
||||||
|
#define INCLUDED_AIR_MODES_PREAMBLE_H
|
||||||
|
|
||||||
|
#include <gnuradio/block.h>
|
||||||
|
#include <gr_air_modes/api.h>
|
||||||
|
|
||||||
|
namespace gr {
|
||||||
|
namespace air_modes {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief mode select preamble detection
|
||||||
|
* \ingroup block
|
||||||
|
*/
|
||||||
|
class AIR_MODES_API preamble : virtual public gr::block
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef boost::shared_ptr<preamble> sptr;
|
||||||
|
static sptr make(int channel_rate, float threshold_db);
|
||||||
|
|
||||||
|
virtual void set_rate(int channel_rate) = 0;
|
||||||
|
virtual void set_threshold(float threshold_db) = 0;
|
||||||
|
virtual int get_rate(void) = 0;
|
||||||
|
virtual float get_threshold(void) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace air_modes
|
||||||
|
} // namespace gr
|
||||||
|
|
||||||
|
#endif /* INCLUDED_AIR_MODES_PREAMBLE_H */
|
||||||
47
include/gr_air_modes/slicer.h
Normal file
47
include/gr_air_modes/slicer.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
# Copyright 2013 Nick Foster
|
||||||
|
#
|
||||||
|
# This file is part of gr-air-modes
|
||||||
|
#
|
||||||
|
# gr-air-modes is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# gr-air-modes is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with gr-air-modes; see the file COPYING. If not, write to
|
||||||
|
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INCLUDED_AIR_MODES_SLICER_H
|
||||||
|
#define INCLUDED_AIR_MODES_SLICER_H
|
||||||
|
|
||||||
|
#include <gnuradio/block.h>
|
||||||
|
#include <gr_air_modes/api.h>
|
||||||
|
#include <gnuradio/msg_queue.h>
|
||||||
|
|
||||||
|
namespace gr {
|
||||||
|
namespace air_modes {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief mode select slicer
|
||||||
|
* \ingroup block
|
||||||
|
*/
|
||||||
|
class AIR_MODES_API slicer : virtual public gr::sync_block
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef boost::shared_ptr<slicer> sptr;
|
||||||
|
static sptr make(gr::msg_queue::sptr queue);
|
||||||
|
};
|
||||||
|
|
||||||
|
} //namespace air_modes
|
||||||
|
} //namespace gr
|
||||||
|
|
||||||
|
#endif /* INCLUDED_AIR_MODES_SLICER_H */
|
||||||
@@ -23,8 +23,8 @@
|
|||||||
include(GrPlatform) #define LIB_SUFFIX
|
include(GrPlatform) #define LIB_SUFFIX
|
||||||
|
|
||||||
add_library(air_modes SHARED
|
add_library(air_modes SHARED
|
||||||
air_modes_preamble.cc
|
preamble_impl.cc
|
||||||
air_modes_slicer.cc
|
slicer_impl.cc
|
||||||
modes_crc.cc
|
modes_crc.cc
|
||||||
)
|
)
|
||||||
target_link_libraries(air_modes ${Boost_LIBRARIES} ${GNURADIO_RUNTIME_LIBRARIES})
|
target_link_libraries(air_modes ${Boost_LIBRARIES} ${GNURADIO_RUNTIME_LIBRARIES})
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
# Copyright 2010 Nick Foster
|
|
||||||
#
|
|
||||||
# This file is part of gr-air-modes
|
|
||||||
#
|
|
||||||
# gr-air-modes is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 3, or (at your option)
|
|
||||||
# any later version.
|
|
||||||
#
|
|
||||||
# gr-air-modes is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with gr-air-modes; see the file COPYING. If not, write to
|
|
||||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
# Boston, MA 02110-1301, USA.
|
|
||||||
#
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <air_modes_int_and_dump.h>
|
|
||||||
#include <gr_io_signature.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
air_modes_int_and_dump_sptr air_make_modes_int_and_dump(int samples_per_symbol)
|
|
||||||
{
|
|
||||||
return air_modes_int_and_dump_sptr (new air_modes_int_and_dump(samples_per_symbol));
|
|
||||||
}
|
|
||||||
|
|
||||||
air_modes_int_and_dump::air_modes_int_and_dump(int samps_per_chip) :
|
|
||||||
gr_block ("modes_int_and_dump",
|
|
||||||
gr_make_io_signature (1, 1, sizeof(float)),
|
|
||||||
gr_make_io_signature (1, 1, sizeof(float)))
|
|
||||||
{
|
|
||||||
d_samples_per_symbol = samples_per_symbol;
|
|
||||||
set_output_multiple(d_samples_per_symbol);
|
|
||||||
set_history(d_samples_per_symbol);
|
|
||||||
|
|
||||||
d_acc = 0;
|
|
||||||
d_pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int air_modes_int_and_dump::general_work(int noutput_items,
|
|
||||||
gr_vector_int &ninput_items,
|
|
||||||
gr_vector_const_void_star &input_items,
|
|
||||||
gr_vector_void_star &output_items)
|
|
||||||
{
|
|
||||||
const float *in = (const float *) input_items[0];
|
|
||||||
float *out = (float *) output_items[0];
|
|
||||||
|
|
||||||
int input_items = std::min(ninput_items[0], ninput_items[1]); //just in case
|
|
||||||
|
|
||||||
//ok first of all we look for "preamble_found" tags in our input range.
|
|
||||||
//get a vector of these tags, then every time we hit one
|
|
||||||
//reset the integrator position and accumulator
|
|
||||||
std::vector<pmt::pmt_t> tags;
|
|
||||||
uint64_t abs_sample_cnt = nitems_read(0);
|
|
||||||
get_tags_in_range(tags, 0, abs_sample_cnt, abs_sample_cnt + ninput_items, pmt::pmt_string_to_symbol("preamble_found"));
|
|
||||||
|
|
||||||
int out_items = 0;
|
|
||||||
|
|
||||||
int offset = gr_tags::get_nitems(&tags[0]) - abs_sample_cnt;
|
|
||||||
|
|
||||||
for(int i=0; i<120*2; i++) { //for each symbol in a potential long packet
|
|
||||||
out[out_items] = 0;
|
|
||||||
for(int j=0; j<d_samples_per_symbol; j++) { //for each sample in the symbol
|
|
||||||
out[out_items] += in[offset+i+j]; //integrate
|
|
||||||
}
|
|
||||||
out_items++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//insert tag here
|
|
||||||
add_item_tag(0, //stream ID
|
|
||||||
nitems_written(0), //sample number
|
|
||||||
pmt::pmt_string_to_symbol("preamble_found");
|
|
||||||
pmt::PMT_T,
|
|
||||||
pmt::pmt_string_to_symbol(unique_id());
|
|
||||||
);
|
|
||||||
|
|
||||||
consume_each(wat);
|
|
||||||
return out_items;
|
|
||||||
}
|
|
||||||
@@ -1,216 +0,0 @@
|
|||||||
/*
|
|
||||||
# Copyright 2010 Nick Foster
|
|
||||||
# Copyright 2013 Nicholas Corgan
|
|
||||||
#
|
|
||||||
# This file is part of gr-air-modes
|
|
||||||
#
|
|
||||||
# gr-air-modes is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 3, or (at your option)
|
|
||||||
# any later version.
|
|
||||||
#
|
|
||||||
# gr-air-modes is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with gr-air-modes; see the file COPYING. If not, write to
|
|
||||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
# Boston, MA 02110-1301, USA.
|
|
||||||
#
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ciso646>
|
|
||||||
#include <air_modes_preamble.h>
|
|
||||||
#include <gnuradio/io_signature.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <gnuradio/tags.h>
|
|
||||||
|
|
||||||
air_modes_preamble_sptr air_make_modes_preamble(int channel_rate, float threshold_db)
|
|
||||||
{
|
|
||||||
return air_modes_preamble_sptr (new air_modes_preamble(channel_rate, threshold_db));
|
|
||||||
}
|
|
||||||
|
|
||||||
air_modes_preamble::air_modes_preamble(int channel_rate, float threshold_db) :
|
|
||||||
gr::block ("modes_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::make (1, 1, sizeof(float))) //the output packets
|
|
||||||
{
|
|
||||||
d_chip_rate = 2000000; //2Mchips per second
|
|
||||||
d_samples_per_chip = channel_rate / d_chip_rate; //must be integer number of samples per chip to work
|
|
||||||
d_samples_per_symbol = d_samples_per_chip * 2;
|
|
||||||
d_check_width = 120 * d_samples_per_symbol; //only search to this far from the end of the stream buffer
|
|
||||||
d_threshold_db = threshold_db;
|
|
||||||
d_threshold = powf(10., threshold_db/20.); //the level that the sample must be above the moving average in order to qualify as a pulse
|
|
||||||
d_secs_per_sample = 1.0 / channel_rate;
|
|
||||||
set_output_multiple(1+d_check_width*2);
|
|
||||||
|
|
||||||
std::stringstream str;
|
|
||||||
str << name() << unique_id();
|
|
||||||
d_me = pmt::string_to_symbol(str.str());
|
|
||||||
d_key = pmt::string_to_symbol("preamble_found");
|
|
||||||
set_history(d_samples_per_symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void integrate_and_dump(float *out, const float *in, int chips, int samps_per_chip) {
|
|
||||||
for(int i=0; i<chips; i++) {
|
|
||||||
float acc = 0;
|
|
||||||
for(int j=0; j<samps_per_chip; j++) {
|
|
||||||
acc += in[i*samps_per_chip+j];
|
|
||||||
}
|
|
||||||
out[i] = acc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//the preamble pattern in bits
|
|
||||||
//fixme goes in .h
|
|
||||||
static const bool preamble_bits[] = {1, 0, 1, 0, 0, 0, 0, 1, 0, 1};
|
|
||||||
static double correlate_preamble(const float *in, int samples_per_chip) {
|
|
||||||
double corr = 0.0;
|
|
||||||
for(int i=0; i<10; i++) {
|
|
||||||
for(int j=0; j<samples_per_chip;j++)
|
|
||||||
if(preamble_bits[i]) corr += in[i*samples_per_chip+j];
|
|
||||||
}
|
|
||||||
return corr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//todo: make it return a pair of some kind, otherwise you can lose precision
|
|
||||||
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;
|
|
||||||
|
|
||||||
if(tstamp.key == NULL || pmt::symbol_to_string(tstamp.key) != "rx_time") return 0;
|
|
||||||
|
|
||||||
last_whole_stamp = pmt::to_uint64(pmt::tuple_ref(tstamp.value, 0));
|
|
||||||
last_frac_stamp = pmt::to_double(pmt::tuple_ref(tstamp.value, 1));
|
|
||||||
ts_sample = tstamp.offset;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int air_modes_preamble::general_work(int noutput_items,
|
|
||||||
gr_vector_int &ninput_items,
|
|
||||||
gr_vector_const_void_star &input_items,
|
|
||||||
gr_vector_void_star &output_items)
|
|
||||||
{
|
|
||||||
const float *in = (const float *) input_items[0];
|
|
||||||
const float *inavg = (const float *) input_items[1];
|
|
||||||
|
|
||||||
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
|
|
||||||
//we also subtract off d_samples_per_chip to allow the bit center finder some leeway
|
|
||||||
const int ninputs = std::max(mininputs - (mininputs % d_samples_per_chip) - d_samples_per_chip, 0);
|
|
||||||
if (ninputs <= 0) { consume_each(0); return 0; }
|
|
||||||
|
|
||||||
float *out = (float *) output_items[0];
|
|
||||||
|
|
||||||
if(0) std::cout << "Preamble called with " << ninputs << " samples" << std::endl;
|
|
||||||
|
|
||||||
//fixme move into .h
|
|
||||||
const int pulse_offsets[4] = { 0,
|
|
||||||
int(2 * d_samples_per_chip),
|
|
||||||
int(7 * d_samples_per_chip),
|
|
||||||
int(9 * d_samples_per_chip)
|
|
||||||
};
|
|
||||||
|
|
||||||
uint64_t abs_sample_cnt = nitems_read(0);
|
|
||||||
std::vector<gr::tag_t> tstamp_tags;
|
|
||||||
get_tags_in_range(tstamp_tags, 0, abs_sample_cnt, abs_sample_cnt + ninputs, pmt::string_to_symbol("rx_time"));
|
|
||||||
//tags.back() is the most recent timestamp, then.
|
|
||||||
if(tstamp_tags.size() > 0) {
|
|
||||||
d_timestamp = tstamp_tags.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i=0; i < ninputs; i++) {
|
|
||||||
float pulse_threshold = inavg[i] * d_threshold;
|
|
||||||
if(in[i] > pulse_threshold) { //hey we got a candidate
|
|
||||||
if(in[i+1] > in[i]) continue; //wait for the peak
|
|
||||||
//check to see the rest of the pulses are there
|
|
||||||
if( in[i+pulse_offsets[1]] < pulse_threshold ) continue;
|
|
||||||
if( in[i+pulse_offsets[2]] < pulse_threshold ) continue;
|
|
||||||
if( in[i+pulse_offsets[3]] < pulse_threshold ) continue;
|
|
||||||
|
|
||||||
//get a more accurate bit center by finding the correlation peak across all four preamble bits
|
|
||||||
bool late, early;
|
|
||||||
int how_late = 0;
|
|
||||||
do {
|
|
||||||
double now_corr = correlate_preamble(in+i, d_samples_per_chip);
|
|
||||||
double late_corr = correlate_preamble(in+i+1, d_samples_per_chip);
|
|
||||||
double early_corr = correlate_preamble(in+i-1, d_samples_per_chip);
|
|
||||||
late = (late_corr > now_corr);
|
|
||||||
//early = (early_corr > now_corr);
|
|
||||||
if(late) { i++; how_late++; }
|
|
||||||
//if(early && i>0) { std::cout << "EARLY " << i << std::endl; i--; }
|
|
||||||
} while(late and how_late < d_samples_per_chip);// xor early);
|
|
||||||
|
|
||||||
if(0) std::cout << "We were " << how_late << " samples late" << std::endl;
|
|
||||||
|
|
||||||
//now check to see that the non-peak symbols in the preamble
|
|
||||||
//are below the peaks by threshold dB
|
|
||||||
float avgpeak = ( in[i+pulse_offsets[0]]
|
|
||||||
+ in[i+pulse_offsets[1]]
|
|
||||||
+ in[i+pulse_offsets[2]]
|
|
||||||
+ in[i+pulse_offsets[3]]) / 4.0;
|
|
||||||
|
|
||||||
float space_threshold = inavg[i] + (avgpeak - inavg[i])/d_threshold;
|
|
||||||
bool valid_preamble = true; //f'in c++
|
|
||||||
for( int j=1.5*d_samples_per_symbol; j<=3*d_samples_per_symbol; j++)
|
|
||||||
if(in[i+j] > space_threshold) valid_preamble = false;
|
|
||||||
for( int j=5*d_samples_per_symbol; j<=7.5*d_samples_per_symbol; j++)
|
|
||||||
if(in[i+j] > space_threshold) valid_preamble = false;
|
|
||||||
if(!valid_preamble) continue;
|
|
||||||
|
|
||||||
//be sure we've got enough room in the input buffer to copy out a whole packet
|
|
||||||
if(ninputs-i < 240*d_samples_per_chip) {
|
|
||||||
consume_each(std::max(i-1,0));
|
|
||||||
if(0) std::cout << "Preamble consumed " << std::max(i-1,0) << ", returned 0 (no room)" << std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//all right i'm prepared to call this a preamble
|
|
||||||
//let's integrate and dump the output
|
|
||||||
//FIXME: disable and use center sample
|
|
||||||
bool life_sucks = true;
|
|
||||||
if(life_sucks) {
|
|
||||||
for(int j=0; j<240; j++) {
|
|
||||||
out[j] = in[i+j*d_samples_per_chip];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
i -= d_samples_per_chip-1;
|
|
||||||
integrate_and_dump(out, &in[i], 240, d_samples_per_chip);
|
|
||||||
}
|
|
||||||
|
|
||||||
//get the timestamp of the preamble
|
|
||||||
double tstamp = tag_to_timestamp(d_timestamp, abs_sample_cnt + i, d_secs_per_sample);
|
|
||||||
|
|
||||||
//now tag the preamble
|
|
||||||
add_item_tag(0, //stream ID
|
|
||||||
nitems_written(0), //sample
|
|
||||||
d_key, //frame_info
|
|
||||||
pmt::from_double(tstamp),
|
|
||||||
d_me //block src id
|
|
||||||
);
|
|
||||||
|
|
||||||
//std::cout << "PREAMBLE" << std::endl;
|
|
||||||
|
|
||||||
//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;
|
|
||||||
|
|
||||||
consume_each(i+240*d_samples_per_chip);
|
|
||||||
return 240;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//didn't get anything this time
|
|
||||||
if(0) std::cout << "Preamble consumed " << ninputs << ", returned 0" << std::endl;
|
|
||||||
consume_each(ninputs);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,197 +0,0 @@
|
|||||||
/*
|
|
||||||
# Copyright 2010 Nick Foster
|
|
||||||
# Copyright 2013 Nicholas Corgan
|
|
||||||
#
|
|
||||||
# This file is part of gr-air-modes
|
|
||||||
#
|
|
||||||
# gr-air-modes is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 3, or (at your option)
|
|
||||||
# any later version.
|
|
||||||
#
|
|
||||||
# gr-air-modes is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with gr-air-modes; see the file COPYING. If not, write to
|
|
||||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
# Boston, MA 02110-1301, USA.
|
|
||||||
#
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ciso646>
|
|
||||||
#include <air_modes_slicer.h>
|
|
||||||
#include <gnuradio/io_signature.h>
|
|
||||||
#include <air_modes_types.h>
|
|
||||||
#include <sstream>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <modes_crc.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <gnuradio/tags.h>
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
air_modes_slicer_sptr air_make_modes_slicer(int channel_rate, gr::msg_queue::sptr queue)
|
|
||||||
{
|
|
||||||
return air_modes_slicer_sptr (new air_modes_slicer(channel_rate, queue));
|
|
||||||
}
|
|
||||||
|
|
||||||
air_modes_slicer::air_modes_slicer(int channel_rate, gr::msg_queue::sptr queue) :
|
|
||||||
gr::sync_block ("modes_slicer",
|
|
||||||
gr::io_signature::make (1, 1, sizeof(float)), //stream 0 is received data, stream 1 is binary preamble detector output
|
|
||||||
gr::io_signature::make (0, 0, 0) )
|
|
||||||
{
|
|
||||||
//initialize private data here
|
|
||||||
d_chip_rate = 2000000; //2Mchips per second
|
|
||||||
d_samples_per_chip = 2;//FIXME this is constant now channel_rate / d_chip_rate;
|
|
||||||
d_samples_per_symbol = d_samples_per_chip * 2;
|
|
||||||
d_check_width = 120 * d_samples_per_symbol; //how far you will have to look ahead
|
|
||||||
d_queue = queue;
|
|
||||||
|
|
||||||
set_output_multiple(d_check_width*2); //how do you specify buffer size for sinks?
|
|
||||||
}
|
|
||||||
|
|
||||||
//this slicer is courtesy of Lincoln Labs. supposedly it is more resistant to mode A/C FRUIT.
|
|
||||||
//see http://adsb.tc.faa.gov/WG3_Meetings/Meeting8/Squitter-Lon.pdf
|
|
||||||
static slice_result_t slicer(const float bit0, const float bit1, const float ref) {
|
|
||||||
slice_result_t result;
|
|
||||||
|
|
||||||
//3dB limits for bit slicing and confidence measurement
|
|
||||||
float highlimit=ref*1.414;
|
|
||||||
float lowlimit=ref*0.707;
|
|
||||||
|
|
||||||
bool firstchip_inref = ((bit0 > lowlimit) && (bit0 < highlimit));
|
|
||||||
bool secondchip_inref = ((bit1 > lowlimit) && (bit1 < highlimit));
|
|
||||||
|
|
||||||
if(firstchip_inref && !secondchip_inref) {
|
|
||||||
result.decision = 1;
|
|
||||||
result.confidence = 1;
|
|
||||||
}
|
|
||||||
else if(secondchip_inref && !firstchip_inref) {
|
|
||||||
result.decision = 0;
|
|
||||||
result.confidence = 1;
|
|
||||||
}
|
|
||||||
else if(firstchip_inref && secondchip_inref) {
|
|
||||||
result.decision = bit0 > bit1;
|
|
||||||
result.confidence = 0;
|
|
||||||
}
|
|
||||||
else {//if(!firstchip_inref && !secondchip_inref) {
|
|
||||||
result.decision = bit0 > bit1;
|
|
||||||
if(result.decision) {
|
|
||||||
if(bit1 < lowlimit * 0.5) result.confidence = 1;
|
|
||||||
else result.confidence = 0;
|
|
||||||
} else {
|
|
||||||
if(bit0 < lowlimit * 0.5) result.confidence = 1;
|
|
||||||
else result.confidence = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int air_modes_slicer::work(int noutput_items,
|
|
||||||
gr_vector_const_void_star &input_items,
|
|
||||||
gr_vector_void_star &output_items)
|
|
||||||
{
|
|
||||||
const float *in = (const float *) input_items[0];
|
|
||||||
int size = noutput_items - d_check_width; //since it's a sync block, i assume that it runs with ninput_items = noutput_items
|
|
||||||
|
|
||||||
if(0) std::cout << "Slicer called with " << size << " samples" << std::endl;
|
|
||||||
|
|
||||||
std::vector<gr::tag_t> tags;
|
|
||||||
uint64_t abs_sample_cnt = nitems_read(0);
|
|
||||||
get_tags_in_range(tags, 0, abs_sample_cnt, abs_sample_cnt + size, pmt::string_to_symbol("preamble_found"));
|
|
||||||
std::vector<gr::tag_t>::iterator tag_iter;
|
|
||||||
|
|
||||||
for(tag_iter = tags.begin(); tag_iter != tags.end(); tag_iter++) {
|
|
||||||
uint64_t i = tag_iter->offset - abs_sample_cnt;
|
|
||||||
modes_packet rx_packet;
|
|
||||||
|
|
||||||
memset(&rx_packet.data, 0x00, 14 * sizeof(unsigned char));
|
|
||||||
memset(&rx_packet.lowconfbits, 0x00, 24 * sizeof(unsigned char));
|
|
||||||
rx_packet.numlowconf = 0;
|
|
||||||
|
|
||||||
//let's use the preamble to get a reference level for the packet
|
|
||||||
//fixme: a better thing to do is create a bi-level avg 1 and avg 0
|
|
||||||
//through simple statistics, then take the median for your slice level
|
|
||||||
//this won't improve decoding but will improve confidence
|
|
||||||
rx_packet.reference_level = (in[i]
|
|
||||||
+ in[i+2]
|
|
||||||
+ in[i+7]
|
|
||||||
+ in[i+9]) / 4.0;
|
|
||||||
|
|
||||||
i += 16; //move on up to the first bit of the packet data
|
|
||||||
//now let's slice the header so we can determine if it's a short pkt or a long pkt
|
|
||||||
unsigned char pkt_hdr = 0;
|
|
||||||
for(int j=0; j < 5; j++) {
|
|
||||||
slice_result_t slice_result = slicer(in[i+j*2], in[i+j*2+1], rx_packet.reference_level);
|
|
||||||
if(slice_result.decision) pkt_hdr += 1 << (4-j);
|
|
||||||
}
|
|
||||||
if(pkt_hdr == 16 or pkt_hdr == 17 or pkt_hdr == 20 or pkt_hdr == 21) rx_packet.type = Long_Packet;
|
|
||||||
else rx_packet.type = Short_Packet;
|
|
||||||
int packet_length = (rx_packet.type == framer_packet_type(Short_Packet)) ? 56 : 112;
|
|
||||||
|
|
||||||
//it's slice time!
|
|
||||||
//TODO: don't repeat your work here, you already have the first 5 bits
|
|
||||||
for(int j = 0; j < packet_length; j++) {
|
|
||||||
slice_result_t slice_result = slicer(in[i+j*2], in[i+j*2+1], rx_packet.reference_level);
|
|
||||||
|
|
||||||
//put the data into the packet
|
|
||||||
if(slice_result.decision) {
|
|
||||||
rx_packet.data[j/8] += 1 << (7-(j%8));
|
|
||||||
}
|
|
||||||
//put the confidence decision into the packet
|
|
||||||
if(slice_result.confidence) {
|
|
||||||
//rx_packet.confidence[j/8] += 1 << (7-(j%8));
|
|
||||||
} else {
|
|
||||||
if(rx_packet.numlowconf < 24) rx_packet.lowconfbits[rx_packet.numlowconf++] = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************** BEGIN TIMESTAMP BS ******************/
|
|
||||||
rx_packet.timestamp = pmt::to_double(tag_iter->value);
|
|
||||||
/******************* END TIMESTAMP BS *********************/
|
|
||||||
|
|
||||||
//increment for the next round
|
|
||||||
|
|
||||||
//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;
|
|
||||||
for(int m = 0; m < 14; m++) {
|
|
||||||
if(rx_packet.data[m]) zeroes = 0;
|
|
||||||
}
|
|
||||||
if(zeroes) {continue;} //toss it
|
|
||||||
|
|
||||||
rx_packet.message_type = (rx_packet.data[0] >> 3) & 0x1F; //get the message type to make decisions on ECC methods
|
|
||||||
|
|
||||||
if(rx_packet.type == Short_Packet && rx_packet.message_type != 11 && rx_packet.numlowconf > 0) {continue;}
|
|
||||||
if(rx_packet.message_type == 11 && rx_packet.numlowconf >= 10) {continue;}
|
|
||||||
|
|
||||||
rx_packet.crc = modes_check_crc(rx_packet.data, packet_length);
|
|
||||||
|
|
||||||
//crc for packets that aren't type 11 or type 17 is encoded with the transponder ID, which we don't know
|
|
||||||
//therefore we toss 'em if there's syndrome
|
|
||||||
//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;}
|
|
||||||
|
|
||||||
d_payload.str("");
|
|
||||||
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::setw(6) << rx_packet.crc << " " << std::dec << rx_packet.reference_level
|
|
||||||
<< " " << std::setprecision(10) << std::setw(10) << rx_packet.timestamp;
|
|
||||||
gr::message::sptr msg = gr::message::make_from_string(std::string(d_payload.str()));
|
|
||||||
d_queue->handle(msg);
|
|
||||||
}
|
|
||||||
if(0) std::cout << "Slicer consumed " << size << ", returned " << size << std::endl;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
172
lib/modes_crc.cc
172
lib/modes_crc.cc
@@ -1,165 +1,63 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2007 Free Software Foundation, Inc.
|
* Copyright 2013 Nick Foster
|
||||||
*
|
*
|
||||||
* This file is part of GNU Radio
|
* This file is part of gr-air-modes
|
||||||
*
|
*
|
||||||
* GNU Radio is free software; you can redistribute it and/or modify
|
* gr-air-modes 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 2, or (at your option)
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
* any later version.
|
* any later version.
|
||||||
*
|
*
|
||||||
* GNU Radio is distributed in the hope that it will be useful,
|
* gr-air-modes 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 gr-air-modes; 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//this is copied almost verbatim from Eric Cottrell's gr-air platform.
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <air_modes_types.h>
|
#include <gr_air_modes/types.h>
|
||||||
#include <modes_crc.h>
|
#include <gr_air_modes/modes_crc.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
/* Mode S Parity Table
|
unsigned int crc_table[256];
|
||||||
* Index is bit position with bit 0 being the first bit after preamble
|
const unsigned int POLY=0xFFF409;
|
||||||
* On short frames an offset of 56 is used.
|
|
||||||
*/
|
|
||||||
const unsigned int modes_crc_table[112] =
|
|
||||||
{
|
|
||||||
0x3935ea, // Start of Long Frame CRC
|
|
||||||
0x1c9af5,
|
|
||||||
0xf1b77e,
|
|
||||||
0x78dbbf,
|
|
||||||
0xc397db,
|
|
||||||
0x9e31e9,
|
|
||||||
0xb0e2f0,
|
|
||||||
0x587178,
|
|
||||||
0x2c38bc,
|
|
||||||
0x161c5e,
|
|
||||||
0x0b0e2f,
|
|
||||||
0xfa7d13,
|
|
||||||
0x82c48d,
|
|
||||||
0xbe9842,
|
|
||||||
0x5f4c21,
|
|
||||||
0xd05c14,
|
|
||||||
0x682e0a,
|
|
||||||
0x341705,
|
|
||||||
0xe5f186,
|
|
||||||
0x72f8c3,
|
|
||||||
0xc68665,
|
|
||||||
0x9cb936,
|
|
||||||
0x4e5c9b,
|
|
||||||
0xd8d449,
|
|
||||||
0x939020,
|
|
||||||
0x49c810,
|
|
||||||
0x24e408,
|
|
||||||
0x127204,
|
|
||||||
0x093902,
|
|
||||||
0x049c81,
|
|
||||||
0xfdb444,
|
|
||||||
0x7eda22,
|
|
||||||
0x3f6d11, // Extended 56 bit field
|
|
||||||
0xe04c8c,
|
|
||||||
0x702646,
|
|
||||||
0x381323,
|
|
||||||
0xe3f395,
|
|
||||||
0x8e03ce,
|
|
||||||
0x4701e7,
|
|
||||||
0xdc7af7,
|
|
||||||
0x91c77f,
|
|
||||||
0xb719bb,
|
|
||||||
0xa476d9,
|
|
||||||
0xadc168,
|
|
||||||
0x56e0b4,
|
|
||||||
0x2b705a,
|
|
||||||
0x15b82d,
|
|
||||||
0xf52612,
|
|
||||||
0x7a9309,
|
|
||||||
0xc2b380,
|
|
||||||
0x6159c0,
|
|
||||||
0x30ace0,
|
|
||||||
0x185670,
|
|
||||||
0x0c2b38,
|
|
||||||
0x06159c,
|
|
||||||
0x030ace,
|
|
||||||
0x018567,
|
|
||||||
0xff38b7, // Start of Short Frame CRC
|
|
||||||
0x80665f,
|
|
||||||
0xbfc92b,
|
|
||||||
0xa01e91,
|
|
||||||
0xaff54c,
|
|
||||||
0x57faa6,
|
|
||||||
0x2bfd53,
|
|
||||||
0xea04ad,
|
|
||||||
0x8af852,
|
|
||||||
0x457c29,
|
|
||||||
0xdd4410,
|
|
||||||
0x6ea208,
|
|
||||||
0x375104,
|
|
||||||
0x1ba882,
|
|
||||||
0x0dd441,
|
|
||||||
0xf91024,
|
|
||||||
0x7c8812,
|
|
||||||
0x3e4409,
|
|
||||||
0xe0d800,
|
|
||||||
0x706c00,
|
|
||||||
0x383600,
|
|
||||||
0x1c1b00,
|
|
||||||
0x0e0d80,
|
|
||||||
0x0706c0,
|
|
||||||
0x038360,
|
|
||||||
0x01c1b0,
|
|
||||||
0x00e0d8,
|
|
||||||
0x00706c,
|
|
||||||
0x003836,
|
|
||||||
0x001c1b,
|
|
||||||
0xfff409,
|
|
||||||
0x800000, // 24 PI or PA bits
|
|
||||||
0x400000,
|
|
||||||
0x200000,
|
|
||||||
0x100000,
|
|
||||||
0x080000,
|
|
||||||
0x040000,
|
|
||||||
0x020000,
|
|
||||||
0x010000,
|
|
||||||
0x008000,
|
|
||||||
0x004000,
|
|
||||||
0x002000,
|
|
||||||
0x001000,
|
|
||||||
0x000800,
|
|
||||||
0x000400,
|
|
||||||
0x000200,
|
|
||||||
0x000100,
|
|
||||||
0x000080,
|
|
||||||
0x000040,
|
|
||||||
0x000020,
|
|
||||||
0x000010,
|
|
||||||
0x000008,
|
|
||||||
0x000004,
|
|
||||||
0x000002,
|
|
||||||
0x000001,
|
|
||||||
};
|
|
||||||
|
|
||||||
int modes_check_crc(unsigned char data[], int length)
|
//generate a bytewise lookup CRC table
|
||||||
|
|
||||||
|
void generate_crc_table(void)
|
||||||
{
|
{
|
||||||
int crc=0, i;
|
unsigned int crc = 0;
|
||||||
for(i = 0; i < length; i++)
|
for(int n=0; n<256; n++) {
|
||||||
{
|
crc = n<<16;
|
||||||
if(data[i/8] & (1 << (7-(i%8))))
|
for(int k=0; k<8; k++) {
|
||||||
{
|
if(crc & 0x800000) {
|
||||||
crc ^= modes_crc_table[i+(112-length)];
|
crc = ((crc<<1) ^ POLY) & 0xFFFFFF;
|
||||||
}
|
} else {
|
||||||
}
|
crc = (crc<<1) & 0xFFFFFF;
|
||||||
return crc;
|
}
|
||||||
|
}
|
||||||
|
crc_table[n] = crc & 0xFFFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Perform a bytewise CRC check
|
||||||
|
unsigned int modes_check_crc(unsigned char data[], int length)
|
||||||
|
{
|
||||||
|
if(crc_table[1] != POLY) generate_crc_table();
|
||||||
|
unsigned int crc=0;
|
||||||
|
for(int i=0; i<length; i++) {
|
||||||
|
crc = crc_table[((crc>>16) ^ data[i]) & 0xff] ^ (crc << 8);
|
||||||
|
}
|
||||||
|
return crc & 0xFFFFFF;
|
||||||
}
|
}
|
||||||
|
|||||||
227
lib/preamble_impl.cc
Normal file
227
lib/preamble_impl.cc
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
/*
|
||||||
|
# Copyright 2010 Nick Foster
|
||||||
|
# Copyright 2013 Nicholas Corgan
|
||||||
|
#
|
||||||
|
# This file is part of gr-air-modes
|
||||||
|
#
|
||||||
|
# gr-air-modes is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# gr-air-modes is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with gr-air-modes; see the file COPYING. If not, write to
|
||||||
|
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <ciso646>
|
||||||
|
#include "preamble_impl.h"
|
||||||
|
#include <gnuradio/io_signature.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <gnuradio/tags.h>
|
||||||
|
|
||||||
|
namespace gr {
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
air_modes::preamble_impl::preamble_impl(int channel_rate, float threshold_db) :
|
||||||
|
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::make (1, 1, sizeof(float))) //the output soft symbols
|
||||||
|
{
|
||||||
|
d_chip_rate = 2000000; //2Mchips per second
|
||||||
|
set_rate(channel_rate);
|
||||||
|
set_threshold(threshold_db);
|
||||||
|
|
||||||
|
std::stringstream str;
|
||||||
|
str << name() << unique_id();
|
||||||
|
d_me = pmt::string_to_symbol(str.str());
|
||||||
|
d_key = pmt::string_to_symbol("preamble_found");
|
||||||
|
}
|
||||||
|
|
||||||
|
void air_modes::preamble_impl::set_rate(int channel_rate) {
|
||||||
|
d_samples_per_chip = channel_rate / d_chip_rate;
|
||||||
|
d_samples_per_symbol = d_samples_per_chip * 2;
|
||||||
|
d_check_width = 120 * d_samples_per_symbol;
|
||||||
|
d_secs_per_sample = 1.0/channel_rate;
|
||||||
|
set_output_multiple(1+d_check_width*2);
|
||||||
|
set_history(d_samples_per_symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
void air_modes::preamble_impl::set_threshold(float threshold_db) {
|
||||||
|
d_threshold_db = threshold_db;
|
||||||
|
d_threshold = powf(10., threshold_db/20.); //the level that the sample must be above the moving average in order to qualify as a pulse
|
||||||
|
}
|
||||||
|
|
||||||
|
float air_modes::preamble_impl::get_threshold(void) {
|
||||||
|
return d_threshold_db;
|
||||||
|
}
|
||||||
|
|
||||||
|
int air_modes::preamble_impl::get_rate(void) {
|
||||||
|
return d_samples_per_chip * d_chip_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void integrate_and_dump(float *out, const float *in, int chips, int samps_per_chip) {
|
||||||
|
for(int i=0; i<chips; i++) {
|
||||||
|
float acc = 0;
|
||||||
|
for(int j=0; j<samps_per_chip; j++) {
|
||||||
|
acc += in[i*samps_per_chip+j];
|
||||||
|
}
|
||||||
|
out[i] = acc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//the preamble pattern in bits
|
||||||
|
//fixme goes in .h
|
||||||
|
static const bool preamble_bits[] = {1, 0, 1, 0, 0, 0, 0, 1, 0, 1};
|
||||||
|
static double correlate_preamble(const float *in, int samples_per_chip) {
|
||||||
|
double corr = 0.0;
|
||||||
|
for(int i=0; i<10; i++) {
|
||||||
|
for(int j=0; j<samples_per_chip;j++)
|
||||||
|
if(preamble_bits[i]) corr += in[i*samples_per_chip+j];
|
||||||
|
}
|
||||||
|
return corr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo: make it return a pair of some kind, otherwise you can lose precision
|
||||||
|
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;
|
||||||
|
|
||||||
|
if(tstamp.key == NULL || pmt::symbol_to_string(tstamp.key) != "rx_time") return 0;
|
||||||
|
|
||||||
|
last_whole_stamp = pmt::to_uint64(pmt::tuple_ref(tstamp.value, 0));
|
||||||
|
last_frac_stamp = pmt::to_double(pmt::tuple_ref(tstamp.value, 1));
|
||||||
|
ts_sample = tstamp.offset;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int air_modes::preamble_impl::general_work(int noutput_items,
|
||||||
|
gr_vector_int &ninput_items,
|
||||||
|
gr_vector_const_void_star &input_items,
|
||||||
|
gr_vector_void_star &output_items)
|
||||||
|
{
|
||||||
|
const float *in = (const float *) input_items[0];
|
||||||
|
const float *inavg = (const float *) input_items[1];
|
||||||
|
|
||||||
|
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
|
||||||
|
//we also subtract off d_samples_per_chip to allow the bit center finder some leeway
|
||||||
|
const int ninputs = std::max(mininputs - (mininputs % d_samples_per_chip) - d_samples_per_chip, 0);
|
||||||
|
if (ninputs <= 0) { consume_each(0); return 0; }
|
||||||
|
|
||||||
|
float *out = (float *) output_items[0];
|
||||||
|
|
||||||
|
if(0) std::cout << "Preamble called with " << ninputs << " samples" << std::endl;
|
||||||
|
|
||||||
|
//fixme move into .h
|
||||||
|
const int pulse_offsets[4] = { 0,
|
||||||
|
int(2 * d_samples_per_chip),
|
||||||
|
int(7 * d_samples_per_chip),
|
||||||
|
int(9 * d_samples_per_chip)
|
||||||
|
};
|
||||||
|
|
||||||
|
uint64_t abs_sample_cnt = nitems_read(0);
|
||||||
|
std::vector<gr::tag_t> tstamp_tags;
|
||||||
|
get_tags_in_range(tstamp_tags, 0, abs_sample_cnt, abs_sample_cnt + ninputs, pmt::string_to_symbol("rx_time"));
|
||||||
|
//tags.back() is the most recent timestamp, then.
|
||||||
|
if(tstamp_tags.size() > 0) {
|
||||||
|
d_timestamp = tstamp_tags.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0; i < ninputs; i++) {
|
||||||
|
float pulse_threshold = inavg[i] * d_threshold;
|
||||||
|
if(in[i] > pulse_threshold) { //hey we got a candidate
|
||||||
|
if(in[i+1] > in[i]) continue; //wait for the peak
|
||||||
|
//check to see the rest of the pulses are there
|
||||||
|
if( in[i+pulse_offsets[1]] < pulse_threshold ) continue;
|
||||||
|
if( in[i+pulse_offsets[2]] < pulse_threshold ) continue;
|
||||||
|
if( in[i+pulse_offsets[3]] < pulse_threshold ) continue;
|
||||||
|
|
||||||
|
//get a more accurate bit center by finding the correlation peak across all four preamble bits
|
||||||
|
bool late, early;
|
||||||
|
int how_late = 0;
|
||||||
|
do {
|
||||||
|
double now_corr = correlate_preamble(in+i, d_samples_per_chip);
|
||||||
|
double late_corr = correlate_preamble(in+i+1, d_samples_per_chip);
|
||||||
|
double early_corr = correlate_preamble(in+i-1, d_samples_per_chip);
|
||||||
|
late = (late_corr > now_corr);
|
||||||
|
//early = (early_corr > now_corr);
|
||||||
|
if(late) { i++; how_late++; }
|
||||||
|
//if(early && i>0) { std::cout << "EARLY " << i << std::endl; i--; }
|
||||||
|
} while(late and how_late < d_samples_per_chip);// xor early);
|
||||||
|
|
||||||
|
if(0) std::cout << "We were " << how_late << " samples late" << std::endl;
|
||||||
|
|
||||||
|
//now check to see that the non-peak symbols in the preamble
|
||||||
|
//are below the peaks by threshold dB
|
||||||
|
float avgpeak = ( in[i+pulse_offsets[0]]
|
||||||
|
+ in[i+pulse_offsets[1]]
|
||||||
|
+ in[i+pulse_offsets[2]]
|
||||||
|
+ in[i+pulse_offsets[3]]) / 4.0;
|
||||||
|
|
||||||
|
float space_threshold = inavg[i] + (avgpeak - inavg[i])/d_threshold;
|
||||||
|
bool valid_preamble = true; //f'in c++
|
||||||
|
for( int j=1.5*d_samples_per_symbol; j<=3*d_samples_per_symbol; j++)
|
||||||
|
if(in[i+j] > space_threshold) valid_preamble = false;
|
||||||
|
for( int j=5*d_samples_per_symbol; j<=7.5*d_samples_per_symbol; j++)
|
||||||
|
if(in[i+j] > space_threshold) valid_preamble = false;
|
||||||
|
if(!valid_preamble) continue;
|
||||||
|
|
||||||
|
//be sure we've got enough room in the input buffer to copy out a whole packet
|
||||||
|
if(ninputs-i < 240*d_samples_per_chip) {
|
||||||
|
consume_each(std::max(i-1,0));
|
||||||
|
if(0) std::cout << "Preamble consumed " << std::max(i-1,0) << ", returned 0 (no room)" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//all right i'm prepared to call this a preamble
|
||||||
|
for(int j=0; j<240; j++) {
|
||||||
|
out[j] = in[i+j*d_samples_per_chip] - inavg[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
//get the timestamp of the preamble
|
||||||
|
double tstamp = tag_to_timestamp(d_timestamp, abs_sample_cnt + i, d_secs_per_sample);
|
||||||
|
|
||||||
|
//now tag the preamble
|
||||||
|
add_item_tag(0, //stream ID
|
||||||
|
nitems_written(0), //sample
|
||||||
|
d_key, //frame_info
|
||||||
|
pmt::from_double(tstamp),
|
||||||
|
d_me //block src id
|
||||||
|
);
|
||||||
|
|
||||||
|
//std::cout << "PREAMBLE" << std::endl;
|
||||||
|
|
||||||
|
//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;
|
||||||
|
|
||||||
|
consume_each(i+240*d_samples_per_chip);
|
||||||
|
return 240;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//didn't get anything this time
|
||||||
|
if(0) std::cout << "Preamble consumed " << ninputs << ", returned 0" << std::endl;
|
||||||
|
consume_each(ninputs);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} //namespace gr
|
||||||
43
lib/preamble_impl.h
Normal file
43
lib/preamble_impl.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
#ifndef _AIR_MODES_PREAMBLE_IMPL_H_
|
||||||
|
#define _AIR_MODES_PREAMBLE_IMPL_H_
|
||||||
|
|
||||||
|
#include <gnuradio/block.h>
|
||||||
|
#include <gr_air_modes/api.h>
|
||||||
|
#include <gr_air_modes/preamble.h>
|
||||||
|
|
||||||
|
namespace gr {
|
||||||
|
namespace air_modes {
|
||||||
|
|
||||||
|
class AIR_MODES_API preamble_impl : public preamble
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int d_check_width;
|
||||||
|
int d_chip_rate;
|
||||||
|
float d_preamble_length_us;
|
||||||
|
int d_samples_per_chip;
|
||||||
|
int d_samples_per_symbol;
|
||||||
|
float d_threshold_db;
|
||||||
|
float d_threshold;
|
||||||
|
pmt::pmt_t d_me, d_key;
|
||||||
|
gr::tag_t d_timestamp;
|
||||||
|
double d_secs_per_sample;
|
||||||
|
|
||||||
|
public:
|
||||||
|
preamble_impl(int channel_rate, float threshold_db);
|
||||||
|
|
||||||
|
int general_work (int noutput_items,
|
||||||
|
gr_vector_int &ninput_items,
|
||||||
|
gr_vector_const_void_star &input_items,
|
||||||
|
gr_vector_void_star &output_items);
|
||||||
|
|
||||||
|
void set_rate(int channel_rate);
|
||||||
|
void set_threshold(float threshold_db);
|
||||||
|
float get_threshold(void);
|
||||||
|
int get_rate(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
} //namespace air_modes
|
||||||
|
} //namespace gr
|
||||||
|
|
||||||
|
#endif //_AIR_MODES_PREAMBLE_IMPL_H_
|
||||||
200
lib/slicer_impl.cc
Normal file
200
lib/slicer_impl.cc
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
/*
|
||||||
|
# Copyright 2010 Nick Foster
|
||||||
|
# Copyright 2013 Nicholas Corgan
|
||||||
|
#
|
||||||
|
# This file is part of gr-air-modes
|
||||||
|
#
|
||||||
|
# gr-air-modes is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# gr-air-modes is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with gr-air-modes; see the file COPYING. If not, write to
|
||||||
|
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <ciso646>
|
||||||
|
#include "slicer_impl.h"
|
||||||
|
#include <gnuradio/io_signature.h>
|
||||||
|
#include <gr_air_modes/types.h>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <gr_air_modes/modes_crc.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <gnuradio/tags.h>
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace gr {
|
||||||
|
|
||||||
|
air_modes::slicer::sptr air_modes::slicer::make(gr::msg_queue::sptr queue) {
|
||||||
|
return gnuradio::get_initial_sptr(new air_modes::slicer_impl(queue));
|
||||||
|
}
|
||||||
|
|
||||||
|
air_modes::slicer_impl::slicer_impl(gr::msg_queue::sptr queue) :
|
||||||
|
gr::sync_block ("slicer",
|
||||||
|
gr::io_signature::make (1, 1, sizeof(float)),
|
||||||
|
gr::io_signature::make (0, 0, 0) )
|
||||||
|
{
|
||||||
|
//initialize private data here
|
||||||
|
d_chip_rate = 2000000; //2Mchips per second
|
||||||
|
d_samples_per_chip = 2;//FIXME this is constant now channel_rate / d_chip_rate;
|
||||||
|
d_samples_per_symbol = d_samples_per_chip * 2;
|
||||||
|
d_check_width = 120 * d_samples_per_symbol; //how far you will have to look ahead
|
||||||
|
d_queue = queue;
|
||||||
|
|
||||||
|
set_output_multiple(d_check_width*2); //how do you specify buffer size for sinks?
|
||||||
|
}
|
||||||
|
|
||||||
|
//this slicer is courtesy of Lincoln Labs. supposedly it is more resistant to mode A/C FRUIT.
|
||||||
|
//see http://adsb.tc.faa.gov/WG3_Meetings/Meeting8/Squitter-Lon.pdf
|
||||||
|
static slice_result_t llslicer(const float bit0, const float bit1, const float ref) {
|
||||||
|
slice_result_t result;
|
||||||
|
|
||||||
|
//3dB limits for bit slicing and confidence measurement
|
||||||
|
float highlimit=ref*1.414;
|
||||||
|
float lowlimit=ref*0.707;
|
||||||
|
|
||||||
|
bool firstchip_inref = ((bit0 > lowlimit) && (bit0 < highlimit));
|
||||||
|
bool secondchip_inref = ((bit1 > lowlimit) && (bit1 < highlimit));
|
||||||
|
|
||||||
|
if(firstchip_inref && !secondchip_inref) {
|
||||||
|
result.decision = 1;
|
||||||
|
result.confidence = 1;
|
||||||
|
}
|
||||||
|
else if(secondchip_inref && !firstchip_inref) {
|
||||||
|
result.decision = 0;
|
||||||
|
result.confidence = 1;
|
||||||
|
}
|
||||||
|
else if(firstchip_inref && secondchip_inref) {
|
||||||
|
result.decision = bit0 > bit1;
|
||||||
|
result.confidence = 0;
|
||||||
|
}
|
||||||
|
else {//if(!firstchip_inref && !secondchip_inref) {
|
||||||
|
result.decision = bit0 > bit1;
|
||||||
|
if(result.decision) {
|
||||||
|
if(bit1 < lowlimit * 0.5) result.confidence = 1;
|
||||||
|
else result.confidence = 0;
|
||||||
|
} else {
|
||||||
|
if(bit0 < lowlimit * 0.5) result.confidence = 1;
|
||||||
|
else result.confidence = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int air_modes::slicer_impl::work(int noutput_items,
|
||||||
|
gr_vector_const_void_star &input_items,
|
||||||
|
gr_vector_void_star &output_items)
|
||||||
|
{
|
||||||
|
const float *in = (const float *) input_items[0];
|
||||||
|
int size = noutput_items - d_check_width; //since it's a sync block, i assume that it runs with ninput_items = noutput_items
|
||||||
|
|
||||||
|
if(0) std::cout << "Slicer called with " << size << " samples" << std::endl;
|
||||||
|
|
||||||
|
std::vector<gr::tag_t> tags;
|
||||||
|
uint64_t abs_sample_cnt = nitems_read(0);
|
||||||
|
get_tags_in_range(tags, 0, abs_sample_cnt, abs_sample_cnt + size, pmt::string_to_symbol("preamble_found"));
|
||||||
|
std::vector<gr::tag_t>::iterator tag_iter;
|
||||||
|
|
||||||
|
for(tag_iter = tags.begin(); tag_iter != tags.end(); tag_iter++) {
|
||||||
|
uint64_t i = tag_iter->offset - abs_sample_cnt;
|
||||||
|
modes_packet rx_packet;
|
||||||
|
|
||||||
|
memset(&rx_packet.data, 0x00, 14 * sizeof(unsigned char));
|
||||||
|
memset(&rx_packet.lowconfbits, 0x00, 24 * sizeof(unsigned char));
|
||||||
|
rx_packet.numlowconf = 0;
|
||||||
|
|
||||||
|
//let's use the preamble to get a reference level for the packet
|
||||||
|
//fixme: a better thing to do is create a bi-level avg 1 and avg 0
|
||||||
|
//through simple statistics, then take the median for your slice level
|
||||||
|
//this won't improve decoding but will improve confidence
|
||||||
|
rx_packet.reference_level = (in[i]
|
||||||
|
+ in[i+2]
|
||||||
|
+ in[i+7]
|
||||||
|
+ in[i+9]) / 4.0;
|
||||||
|
|
||||||
|
i += 16; //move on up to the first bit of the packet data
|
||||||
|
//now let's slice the header so we can determine if it's a short pkt or a long pkt
|
||||||
|
unsigned char pkt_hdr = 0;
|
||||||
|
for(int j=0; j < 5; j++) {
|
||||||
|
slice_result_t slice_result = llslicer(in[i+j*2], in[i+j*2+1], rx_packet.reference_level);
|
||||||
|
if(slice_result.decision) pkt_hdr += 1 << (4-j);
|
||||||
|
}
|
||||||
|
if(pkt_hdr == 16 or pkt_hdr == 17 or pkt_hdr == 20 or pkt_hdr == 21) rx_packet.type = Long_Packet;
|
||||||
|
else rx_packet.type = Short_Packet;
|
||||||
|
int packet_length = (rx_packet.type == framer_packet_type(Short_Packet)) ? 56 : 112;
|
||||||
|
|
||||||
|
//it's slice time!
|
||||||
|
//TODO: don't repeat your work here, you already have the first 5 bits
|
||||||
|
for(int j = 0; j < packet_length; j++) {
|
||||||
|
slice_result_t slice_result = llslicer(in[i+j*2], in[i+j*2+1], rx_packet.reference_level);
|
||||||
|
|
||||||
|
//put the data into the packet
|
||||||
|
if(slice_result.decision) {
|
||||||
|
rx_packet.data[j/8] += 1 << (7-(j%8));
|
||||||
|
}
|
||||||
|
//put the confidence decision into the packet
|
||||||
|
if(slice_result.confidence) {
|
||||||
|
//rx_packet.confidence[j/8] += 1 << (7-(j%8));
|
||||||
|
} else {
|
||||||
|
if(rx_packet.numlowconf < 24) rx_packet.lowconfbits[rx_packet.numlowconf++] = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
bool zeroes = 1;
|
||||||
|
for(int m = 0; m < 14; m++) {
|
||||||
|
if(rx_packet.data[m]) zeroes = 0;
|
||||||
|
}
|
||||||
|
if(zeroes) {continue;} //toss it
|
||||||
|
|
||||||
|
rx_packet.message_type = (rx_packet.data[0] >> 3) & 0x1F; //get the message type to make decisions on ECC methods
|
||||||
|
|
||||||
|
if(rx_packet.type == Short_Packet && rx_packet.message_type != 11 && rx_packet.numlowconf > 0) {continue;}
|
||||||
|
if(rx_packet.message_type == 11 && rx_packet.numlowconf >= 10) {continue;}
|
||||||
|
|
||||||
|
rx_packet.crc = modes_check_crc(rx_packet.data, (packet_length/8)-3);
|
||||||
|
unsigned int ap = rx_packet.data[packet_length/8-3] << 16
|
||||||
|
| rx_packet.data[packet_length/8-2] << 8
|
||||||
|
| rx_packet.data[packet_length/8-1] << 0;
|
||||||
|
rx_packet.crc ^= ap;
|
||||||
|
|
||||||
|
//crc for packets that aren't type 11 or type 17 is encoded with the transponder ID, which we don't know
|
||||||
|
//therefore we toss 'em if there's syndrome
|
||||||
|
//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;}
|
||||||
|
|
||||||
|
d_payload.str("");
|
||||||
|
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::setw(6) << rx_packet.crc << " " << std::dec << rx_packet.reference_level
|
||||||
|
<< " " << std::setprecision(10) << std::setw(10) << rx_packet.timestamp;
|
||||||
|
gr::message::sptr msg = gr::message::make_from_string(std::string(d_payload.str()));
|
||||||
|
d_queue->handle(msg);
|
||||||
|
}
|
||||||
|
if(0) std::cout << "Slicer consumed " << size << ", returned " << size << std::endl;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
} //namespace gr
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
# Copyright 2010 Nick Foster
|
# Copyright 2013 Nick Foster
|
||||||
#
|
#
|
||||||
# This file is part of gr-air-modes
|
# This file is part of gr-air-modes
|
||||||
#
|
#
|
||||||
@@ -20,28 +20,20 @@
|
|||||||
#
|
#
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef INCLUDED_AIR_MODES_slicer_H
|
#ifndef INCLUDED_AIR_MODES_SLICER_IMPL_H
|
||||||
#define INCLUDED_AIR_MODES_slicer_H
|
#define INCLUDED_AIR_MODES_SLICER_IMPL_H
|
||||||
|
|
||||||
#include <gnuradio/sync_block.h>
|
#include <gnuradio/sync_block.h>
|
||||||
#include <gnuradio/msg_queue.h>
|
#include <gnuradio/msg_queue.h>
|
||||||
#include <air_modes_api.h>
|
#include <gr_air_modes/api.h>
|
||||||
|
#include <gr_air_modes/slicer.h>
|
||||||
|
|
||||||
class air_modes_slicer;
|
namespace gr {
|
||||||
typedef boost::shared_ptr<air_modes_slicer> air_modes_slicer_sptr;
|
namespace air_modes {
|
||||||
|
|
||||||
AIR_MODES_API air_modes_slicer_sptr air_make_modes_slicer(int channel_rate, gr::msg_queue::sptr queue);
|
class AIR_MODES_API slicer_impl : public slicer
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief mode select slicer detection
|
|
||||||
* \ingroup block
|
|
||||||
*/
|
|
||||||
class AIR_MODES_API air_modes_slicer : public gr::sync_block
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
friend air_modes_slicer_sptr air_make_modes_slicer(int channel_rate, gr::msg_queue::sptr queue);
|
|
||||||
air_modes_slicer(int channel_rate, gr::msg_queue::sptr queue);
|
|
||||||
|
|
||||||
int d_check_width;
|
int d_check_width;
|
||||||
int d_chip_rate;
|
int d_chip_rate;
|
||||||
int d_samples_per_chip;
|
int d_samples_per_chip;
|
||||||
@@ -50,9 +42,14 @@ private:
|
|||||||
std::ostringstream d_payload;
|
std::ostringstream d_payload;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
slicer_impl(gr::msg_queue::sptr queue);
|
||||||
|
|
||||||
int work (int noutput_items,
|
int work (int noutput_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);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* INCLUDED_AIR_MODES_slicer_H */
|
} //namespace air_modes
|
||||||
|
} //namespace gr
|
||||||
|
|
||||||
|
#endif /* INCLUDED_AIR_MODES_SLICER_IMPL_H */
|
||||||
@@ -51,6 +51,12 @@ from air_modes_swig import *
|
|||||||
|
|
||||||
# import any pure python here
|
# import any pure python here
|
||||||
#
|
#
|
||||||
|
|
||||||
|
try:
|
||||||
|
import zmq
|
||||||
|
except ImportError:
|
||||||
|
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 *
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import threading
|
|||||||
import math
|
import math
|
||||||
import air_modes
|
import air_modes
|
||||||
from air_modes.exceptions import *
|
from air_modes.exceptions import *
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
# model has max range vs. azimuth in n-degree increments
|
# model has max range vs. azimuth in n-degree increments
|
||||||
# contains separate max range for a variety of altitudes so
|
# contains separate max range for a variety of altitudes so
|
||||||
@@ -53,7 +53,7 @@ class az_map_model(QtCore.QObject):
|
|||||||
|
|
||||||
def data(self, row, col):
|
def data(self, row, col):
|
||||||
return self._data[row][col]
|
return self._data[row][col]
|
||||||
|
|
||||||
def addRecord(self, bearing, altitude, distance):
|
def addRecord(self, bearing, altitude, distance):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
#round up to nearest altitude in altitudes list
|
#round up to nearest altitude in altitudes list
|
||||||
@@ -85,18 +85,15 @@ class az_map_model(QtCore.QObject):
|
|||||||
|
|
||||||
# the azimuth map widget
|
# the azimuth map widget
|
||||||
class az_map(QtGui.QWidget):
|
class az_map(QtGui.QWidget):
|
||||||
maxrange = 450
|
maxrange = 200
|
||||||
ringsize = 100
|
|
||||||
bgcolor = QtCore.Qt.black
|
bgcolor = QtCore.Qt.black
|
||||||
ringpen = QtGui.QPen(QtGui.QColor(0, 96, 127, 255), 1.3)
|
ringpen = QtGui.QPen(QtGui.QColor(0, 96, 127, 255), 1.3)
|
||||||
#rangepen = QtGui.QPen(QtGui.QColor(255, 255, 0, 255), 1.0)
|
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(az_map, self).__init__(parent)
|
super(az_map, self).__init__(parent)
|
||||||
self._model = None
|
self._model = None
|
||||||
self._paths = []
|
self._paths = []
|
||||||
self.maxrange = az_map.maxrange
|
self.maxrange = az_map.maxrange
|
||||||
self.ringsize = az_map.ringsize
|
|
||||||
|
|
||||||
def minimumSizeHint(self):
|
def minimumSizeHint(self):
|
||||||
return QtCore.QSize(50, 50)
|
return QtCore.QSize(50, 50)
|
||||||
@@ -118,7 +115,7 @@ class az_map(QtGui.QWidget):
|
|||||||
|
|
||||||
#set background
|
#set background
|
||||||
painter.fillRect(event.rect(), QtGui.QBrush(az_map.bgcolor))
|
painter.fillRect(event.rect(), QtGui.QBrush(az_map.bgcolor))
|
||||||
|
|
||||||
#draw the range rings
|
#draw the range rings
|
||||||
self.drawRangeRings(painter)
|
self.drawRangeRings(painter)
|
||||||
for i in range(len(self._paths)):
|
for i in range(len(self._paths)):
|
||||||
@@ -136,12 +133,12 @@ class az_map(QtGui.QWidget):
|
|||||||
bearing = (i+0.5) * 360./az_map_model.npoints
|
bearing = (i+0.5) * 360./az_map_model.npoints
|
||||||
distance = self._model._data[i][alt]
|
distance = self._model._data[i][alt]
|
||||||
radius = min(self.width(), self.height()) / 2.0
|
radius = min(self.width(), self.height()) / 2.0
|
||||||
scale = radius * distance / self.maxrange
|
scale = radius * distance / self.get_range()
|
||||||
#convert bearing,distance to x,y
|
#convert bearing,distance to x,y
|
||||||
xpts = scale * math.sin(bearing * math.pi / 180)
|
xpts = scale * math.sin(bearing * math.pi / 180)
|
||||||
ypts = scale * math.cos(bearing * math.pi / 180)
|
ypts = scale * math.cos(bearing * math.pi / 180)
|
||||||
#get the bounding rectangle of the arc
|
#get the bounding rectangle of the arc
|
||||||
|
|
||||||
arcrect = QtCore.QRectF(QtCore.QPointF(0-scale, 0-scale),
|
arcrect = QtCore.QRectF(QtCore.QPointF(0-scale, 0-scale),
|
||||||
QtCore.QPointF(scale, scale))
|
QtCore.QPointF(scale, scale))
|
||||||
|
|
||||||
@@ -153,44 +150,55 @@ class az_map(QtGui.QWidget):
|
|||||||
|
|
||||||
self._paths.append(path)
|
self._paths.append(path)
|
||||||
|
|
||||||
|
#this is just to add a little buffer space for showing the ring & range
|
||||||
|
def get_range(self):
|
||||||
|
return int(self.maxrange * 1.1)
|
||||||
|
|
||||||
def drawRangeRings(self, painter):
|
def drawRangeRings(self, painter):
|
||||||
painter.translate(self.width()/2, self.height()/2)
|
painter.translate(self.width()/2, self.height()/2)
|
||||||
painter.setPen(az_map.ringpen)
|
#choose intelligent range step -- keep it between 3-5 rings
|
||||||
for i in range(0, self.maxrange, self.ringsize):
|
rangestep = 100
|
||||||
diameter = (float(i) / az_map.maxrange) * min(self.width(), self.height())
|
while self.get_range() / rangestep < 3:
|
||||||
|
rangestep /= 2.0
|
||||||
|
for i in np.arange(rangestep, self.get_range(), rangestep):
|
||||||
|
diameter = (float(i) / self.get_range()) * min(self.width(), self.height())
|
||||||
|
painter.setPen(az_map.ringpen)
|
||||||
painter.drawEllipse(QtCore.QRectF(-diameter / 2.0,
|
painter.drawEllipse(QtCore.QRectF(-diameter / 2.0,
|
||||||
-diameter / 2.0, diameter, diameter))
|
-diameter / 2.0, diameter, diameter))
|
||||||
|
painter.setPen(QtGui.QColor(255,127,0,255))
|
||||||
|
|
||||||
|
painter.drawText(0-70/2.0, diameter/2.0, 70, 30, QtCore.Qt.AlignHCenter,
|
||||||
|
"%.1fnm" % i)
|
||||||
|
|
||||||
def setMaxRange(self, maxrange):
|
def setMaxRange(self, maxrange):
|
||||||
|
maxrange = max(3.25, maxrange)
|
||||||
|
maxrange = min(500., maxrange)
|
||||||
self.maxrange = maxrange
|
self.maxrange = maxrange
|
||||||
self.drawPath()
|
self.repaint()
|
||||||
|
|
||||||
def setRingSize(self, ringsize):
|
def wheelEvent(self, event):
|
||||||
self.ringsize = ringsize
|
self.setMaxRange(self.maxrange + (event.delta()/120.)*self.maxrange/4.)
|
||||||
self.drawPath()
|
|
||||||
|
|
||||||
class az_map_output:
|
class az_map_output:
|
||||||
def __init__(self, cprdec, model, pub):
|
def __init__(self, cprdec, model, pub):
|
||||||
self._cpr = cprdec
|
self._cpr = cprdec
|
||||||
self.model = model
|
self.model = model
|
||||||
pub.subscribe("type17_dl", self.output)
|
pub.subscribe("type17_dl", self.output)
|
||||||
|
|
||||||
def output(self, msg):
|
def output(self, msg):
|
||||||
try:
|
try:
|
||||||
msgtype = msg.data["df"]
|
|
||||||
now = time.time()
|
now = time.time()
|
||||||
|
|
||||||
if msgtype == 17:
|
icao = msg.data["aa"]
|
||||||
icao = msg.data["aa"]
|
subtype = msg.data["ftc"]
|
||||||
subtype = msg.data["ftc"]
|
distance, altitude, bearing = [0,0,0]
|
||||||
distance, altitude, bearing = [0,0,0]
|
if 5 <= subtype <= 8:
|
||||||
if 5 <= subtype <= 8:
|
(ground_track, decoded_lat, decoded_lon, distance, bearing) = air_modes.parseBDS06(msg.data, self._cpr)
|
||||||
(ground_track, decoded_lat, decoded_lon, distance, bearing) = air_modes.parseBDS06(msg.data, self._cpr)
|
altitude = 0
|
||||||
altitude = 0
|
elif 9 <= subtype <= 18:
|
||||||
elif 9 <= subtype <= 18:
|
|
||||||
(altitude, decoded_lat, decoded_lon, distance, bearing) = air_modes.parseBDS05(msg.data, self._cpr)
|
(altitude, decoded_lat, decoded_lon, distance, bearing) = air_modes.parseBDS05(msg.data, self._cpr)
|
||||||
|
|
||||||
self.model.addRecord(bearing, altitude, distance)
|
self.model.addRecord(bearing, altitude, distance)
|
||||||
except ADSBError:
|
except ADSBError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ class output_flightgear:
|
|||||||
def __init__(self, cprdec, hostname, port, pub):
|
def __init__(self, cprdec, hostname, port, pub):
|
||||||
self.hostname = hostname
|
self.hostname = hostname
|
||||||
self.port = port
|
self.port = port
|
||||||
self.localpos = localpos
|
|
||||||
self.positions = {}
|
self.positions = {}
|
||||||
self.velocities = {}
|
self.velocities = {}
|
||||||
self.callsigns = {}
|
self.callsigns = {}
|
||||||
@@ -26,42 +25,41 @@ class output_flightgear:
|
|||||||
|
|
||||||
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", output)
|
pub.subscribe("type17_dl", self.output)
|
||||||
|
|
||||||
def output(self, msg):
|
def output(self, msg):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
msgtype = msg.data["df"]
|
msgtype = msg.data["df"]
|
||||||
if msgtype == 17: #ADS-B report
|
if msgtype == 17: #ADS-B report
|
||||||
icao24 = msg.data["aa"]
|
icao24 = msg.data["aa"]
|
||||||
bdsreg = msg.data["me"].get_type()
|
bdsreg = msg.data["me"].get_type()
|
||||||
if bdsreg == 0x08: #ident packet
|
if bdsreg == 0x08: #ident packet
|
||||||
(ident, actype) = air_modes.parseBDS08(data)
|
(ident, actype) = air_modes.parseBDS08(msg.data)
|
||||||
#select model based on actype
|
#select model based on actype
|
||||||
self.callsigns[icao24] = [ident, actype]
|
self.callsigns[icao24] = [ident, actype]
|
||||||
|
|
||||||
elif bdsreg == 0x06: #BDS0,6 pos
|
elif bdsreg == 0x06: #BDS0,6 pos
|
||||||
[ground_track, decoded_lat, decoded_lon, rnge, bearing] = air_modes.parseBDS06(data, self._cpr)
|
[ground_track, decoded_lat, decoded_lon, rnge, bearing] = air_modes.parseBDS06(msg.data, self._cpr)
|
||||||
self.positions[icao24] = [decoded_lat, decoded_lon, 0]
|
self.positions[icao24] = [decoded_lat, decoded_lon, 0]
|
||||||
self.update(icao24)
|
self.update(icao24)
|
||||||
|
|
||||||
elif bdsreg == 0x05: #BDS0,5 pos
|
elif bdsreg == 0x05: #BDS0,5 pos
|
||||||
[altitude, decoded_lat, decoded_lon, rnge, bearing] = air_modes.parseBDS05(data, self._cpr)
|
[altitude, decoded_lat, decoded_lon, rnge, bearing] = air_modes.parseBDS05(msg.data, self._cpr)
|
||||||
self.positions[icao24] = [decoded_lat, decoded_lon, altitude]
|
self.positions[icao24] = [decoded_lat, decoded_lon, altitude]
|
||||||
self.update(icao24)
|
self.update(icao24)
|
||||||
|
|
||||||
elif bdsreg == 0x09: #velocity
|
elif bdsreg == 0x09: #velocity
|
||||||
subtype = data["bds09"].get_type()
|
subtype = msg.data["bds09"].get_type()
|
||||||
if subtype == 0:
|
if subtype == 0:
|
||||||
[velocity, heading, vert_spd, turnrate] = air_modes.parseBDS09_0(data)
|
[velocity, heading, vert_spd, turnrate] = air_modes.parseBDS09_0(msg.data)
|
||||||
elif subtype == 1:
|
elif subtype == 1:
|
||||||
[velocity, heading, vert_spd] = air_modes.parseBDS09_1(data)
|
[velocity, heading, vert_spd] = air_modes.parseBDS09_1(msg.data)
|
||||||
turnrate = 0
|
turnrate = 0
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.velocities[icao24] = [velocity, heading, vert_spd, turnrate]
|
self.velocities[icao24] = [velocity, heading, vert_spd, turnrate]
|
||||||
|
|
||||||
except ADSBError:
|
except ADSBError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
21
python/get_uniq.py
Executable file
21
python/get_uniq.py
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import sys, re
|
||||||
|
|
||||||
|
if __name__== '__main__':
|
||||||
|
data = sys.stdin.readlines()
|
||||||
|
icaos = []
|
||||||
|
num_icaos = 0
|
||||||
|
for line in data:
|
||||||
|
match = re.match(".*from (\w+)", line)
|
||||||
|
if match is not None:
|
||||||
|
icao = int(match.group(1), 16)
|
||||||
|
icaos.append(icao)
|
||||||
|
|
||||||
|
#get dupes
|
||||||
|
dupes = sorted([icao for icao in set(icaos) if icaos.count(icao) > 1])
|
||||||
|
for icao in dupes:
|
||||||
|
print "%x" % icao
|
||||||
|
print "Found non-unique replies from %i aircraft" % len(dupes)
|
||||||
|
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ class dashboard_data_model(QtCore.QAbstractTableModel):
|
|||||||
self.lock.release()
|
self.lock.release()
|
||||||
self.prune()
|
self.prune()
|
||||||
|
|
||||||
#weeds out ICAOs older than 5 minutes
|
#weeds out ICAOs older than 1 minute
|
||||||
def prune(self):
|
def prune(self):
|
||||||
self.lock.acquire()
|
self.lock.acquire()
|
||||||
for (index,row) in enumerate(self._data):
|
for (index,row) in enumerate(self._data):
|
||||||
|
|||||||
@@ -14,19 +14,21 @@ def html_template(my_position, json_file):
|
|||||||
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
|
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
.labels {
|
.labels {
|
||||||
color: red;
|
color: blue;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
font-family: "Lucida Grande", "Arial", sans-serif;
|
font-family: "Lucida Grande", "Arial", sans-serif;
|
||||||
font-size: 10px;
|
font-size: 13px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 40px;
|
width: 70px;
|
||||||
border: 2px solid black;
|
border: none;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false">
|
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false">
|
||||||
</script>
|
</script>
|
||||||
|
<script type="text/javascript" src="http://google-maps-utility-library-v3.googlecode.com/svn/tags/markerwithlabel/1.1.9/src/markerwithlabel.js">
|
||||||
|
</script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var map;
|
var map;
|
||||||
var markers = [];
|
var markers = [];
|
||||||
@@ -51,7 +53,6 @@ def html_template(my_position, json_file):
|
|||||||
};
|
};
|
||||||
|
|
||||||
function jsonp_callback(results) { // from JSONP
|
function jsonp_callback(results) { // from JSONP
|
||||||
clearMarkers();
|
|
||||||
airplanes = {};
|
airplanes = {};
|
||||||
for (var i = 0; i < results.length; i++) {
|
for (var i = 0; i < results.length; i++) {
|
||||||
airplanes[results[i].icao] = {
|
airplanes[results[i].icao] = {
|
||||||
@@ -65,10 +66,20 @@ def html_template(my_position, json_file):
|
|||||||
highlight: results[i].highlight
|
highlight: results[i].highlight
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// clearMarkers();
|
||||||
refreshIcons();
|
refreshIcons();
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshIcons() {
|
function refreshIcons() {
|
||||||
|
//prune the list
|
||||||
|
for(var i = 0; i < planes.length; i++) {
|
||||||
|
icao = planes[i].get("icao")
|
||||||
|
if(!(icao in airplanes)) {
|
||||||
|
planes[i].setMap(null)
|
||||||
|
planes.splice(i, 1);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
for (var airplane in airplanes) {
|
for (var airplane in airplanes) {
|
||||||
if (airplanes[airplane].highlight != 0) {
|
if (airplanes[airplane].highlight != 0) {
|
||||||
icon_file = "http://www.nerdnetworks.org/~bistromath/airplane_sprite_highlight.png";
|
icon_file = "http://www.nerdnetworks.org/~bistromath/airplane_sprite_highlight.png";
|
||||||
@@ -83,23 +94,40 @@ def html_template(my_position, json_file):
|
|||||||
//scaledSize: new google.maps.Size(4608,126)
|
//scaledSize: new google.maps.Size(4608,126)
|
||||||
};
|
};
|
||||||
|
|
||||||
identstr = airplanes[airplane].ident;
|
if (airplanes[airplane].ident.length != 8) {
|
||||||
if (identstr === "" || !identstr) {
|
identstr = airplane;
|
||||||
identstr = airplanes[airplane].icao;
|
} else {
|
||||||
|
identstr = airplanes[airplane].ident;
|
||||||
};
|
};
|
||||||
|
|
||||||
var planeOptions = {
|
var planeOptions = {
|
||||||
map: map,
|
map: map,
|
||||||
position: airplanes[airplane].center,
|
position: airplanes[airplane].center,
|
||||||
|
icao: airplane,
|
||||||
icon: plane_icon,
|
icon: plane_icon,
|
||||||
//label content meaningless unless you use the MarkerWithLabel class from the Maps Utility Library
|
|
||||||
labelContent: identstr,
|
labelContent: identstr,
|
||||||
labelAnchor: new google.maps.Point(64, 0),
|
labelAnchor: new google.maps.Point(35, -32),
|
||||||
labelClass: "labels",
|
labelClass: "labels",
|
||||||
labelStyle: {opacity: 0.75}
|
labelStyle: {opacity: 0.75}
|
||||||
};
|
};
|
||||||
planeMarker = new google.maps.Marker(planeOptions);
|
|
||||||
planes.push(planeMarker);
|
var i = 0;
|
||||||
|
for(i; i<planes.length; i++) {
|
||||||
|
if(planes[i].get("icao") == airplane) {
|
||||||
|
planes[i].setPosition(airplanes[airplane].center);
|
||||||
|
if(planes[i].get("icon") != plane_icon) {
|
||||||
|
planes[i].setIcon(plane_icon); //handles highlight and heading
|
||||||
|
};
|
||||||
|
if(planes[i].get("labelContent") != identstr) {
|
||||||
|
planes[i].set("labelContent", identstr);
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if(i == planes.length) {
|
||||||
|
planeMarker = new MarkerWithLabel(planeOptions);
|
||||||
|
planes.push(planeMarker);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ class output_kml(threading.Thread):
|
|||||||
def run(self):
|
def run(self):
|
||||||
self._db = sqlite3.connect(self._dbname) #read from the db
|
self._db = sqlite3.connect(self._dbname) #read from the db
|
||||||
while self.shutdown.is_set() is False:
|
while self.shutdown.is_set() is False:
|
||||||
self.writekml()
|
|
||||||
time.sleep(self._timeout)
|
time.sleep(self._timeout)
|
||||||
|
self.writekml()
|
||||||
|
|
||||||
self._db.close()
|
self._db.close()
|
||||||
self._db = None
|
self._db = None
|
||||||
@@ -188,7 +188,7 @@ class output_jsonp(output_kml):
|
|||||||
# retstr += """\t<Folder>\n\t\t<name>Aircraft locations</name>\n\t\t<open>0</open>"""
|
# retstr += """\t<Folder>\n\t\t<name>Aircraft locations</name>\n\t\t<open>0</open>"""
|
||||||
|
|
||||||
#read the database and add KML
|
#read the database and add KML
|
||||||
q = "select distinct icao from positions where seen > datetime('now', '-5 minute')"
|
q = "select distinct icao from positions where seen > datetime('now', '-1 minute')"
|
||||||
c = self._db.cursor()
|
c = self._db.cursor()
|
||||||
self.locked_execute(c, q)
|
self.locked_execute(c, q)
|
||||||
icaolist = c.fetchall()
|
icaolist = c.fetchall()
|
||||||
|
|||||||
87
python/mlat_client.py
Normal file
87
python/mlat_client.py
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2012 Nick Foster
|
||||||
|
#
|
||||||
|
# This file is part of gr-air-modes
|
||||||
|
#
|
||||||
|
# gr-air-modes is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# gr-air-modes is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with gr-air-modes; see the file COPYING. If not, write to
|
||||||
|
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
|
||||||
|
#multilateration client
|
||||||
|
#outputs stamps to server, receives multilaterated outputs back
|
||||||
|
|
||||||
|
import socket, pickle, time, sys
|
||||||
|
import air_modes
|
||||||
|
from gnuradio import gr
|
||||||
|
|
||||||
|
pickle_prot = 0
|
||||||
|
#pickle_prot = pickle.HIGHEST_PROTOCOL
|
||||||
|
|
||||||
|
class client_info:
|
||||||
|
def __init__(self):
|
||||||
|
self.name = ""
|
||||||
|
self.position = []
|
||||||
|
self.offset_secs = 0
|
||||||
|
self.offset_frac_secs = 0.0
|
||||||
|
self.time_source = None
|
||||||
|
|
||||||
|
class mlat_client:
|
||||||
|
def __init__(self, queue, position, server_addr, time_source):
|
||||||
|
self._queue = queue
|
||||||
|
self._pos = position
|
||||||
|
self._name = socket.gethostname()
|
||||||
|
#connect to server
|
||||||
|
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self._sock.setblocking(1)
|
||||||
|
self._sock.connect((server_addr, 19005))
|
||||||
|
info = client_info()
|
||||||
|
info.name = self._name
|
||||||
|
info.position = self._pos
|
||||||
|
info.time_source = time_source #"gpsdo" or None
|
||||||
|
self._sock.send(pickle.dumps(info))
|
||||||
|
reply = self._sock.recv(1024)
|
||||||
|
if reply != "HELO": #i know, shut up
|
||||||
|
raise Exception("Invalid reply from server: %s" % reply)
|
||||||
|
self._sock.setblocking(0)
|
||||||
|
self._remnant = None
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self._sock.close()
|
||||||
|
|
||||||
|
#send a stamped report to the server
|
||||||
|
def output(self, message):
|
||||||
|
self._sock.send(message+"\n")
|
||||||
|
|
||||||
|
#this is called from the update() method list of the main app thread
|
||||||
|
def get_mlat_positions(self):
|
||||||
|
msg = None
|
||||||
|
try:
|
||||||
|
msg = self._sock.recv(1024)
|
||||||
|
except socket.error:
|
||||||
|
pass
|
||||||
|
if msg:
|
||||||
|
for line in msg.splitlines(True):
|
||||||
|
if line.endswith("\n"):
|
||||||
|
if self._remnant:
|
||||||
|
line = self._remnant + line
|
||||||
|
self._remnant = None
|
||||||
|
self._queue.insert_tail(gr.message_from_string(line))
|
||||||
|
|
||||||
|
else:
|
||||||
|
if self._remnant is not None:
|
||||||
|
raise Exception("Malformed data: " + line)
|
||||||
|
else:
|
||||||
|
self._remnant = line
|
||||||
1
python/mlat_types.py
Normal file
1
python/mlat_types.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -427,7 +427,7 @@ def make_parser(pub):
|
|||||||
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),
|
||||||
20.0*math.log10(float(reference)),
|
10.0*math.log10(max(1e-8,float(reference))),
|
||||||
air_modes.stamp(0, float(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
|
||||||
|
|||||||
@@ -23,10 +23,11 @@
|
|||||||
# You pass it options, it gives you data.
|
# You pass it options, it gives you data.
|
||||||
# It uses the pubsub interface to allow clients to subscribe to its data feeds.
|
# It uses the pubsub interface to allow clients to subscribe to its data feeds.
|
||||||
|
|
||||||
from gnuradio import gr, gru, eng_notation, filter
|
from gnuradio import gr, gru, eng_notation, filter, blocks
|
||||||
from gnuradio.filter import optfir
|
from gnuradio.filter import optfir
|
||||||
from gnuradio.eng_option import eng_option
|
from gnuradio.eng_option import eng_option
|
||||||
from gnuradio.gr.pubsub import pubsub
|
from gnuradio.gr.pubsub import pubsub
|
||||||
|
from gnuradio.filter import pfb
|
||||||
from optparse import OptionParser, OptionGroup
|
from optparse import OptionParser, OptionGroup
|
||||||
import air_modes
|
import air_modes
|
||||||
import zmq
|
import zmq
|
||||||
@@ -45,7 +46,15 @@ class modes_radio (gr.top_block, pubsub):
|
|||||||
self._resample = None
|
self._resample = None
|
||||||
self._setup_source(options)
|
self._setup_source(options)
|
||||||
|
|
||||||
self._rx_path = air_modes.rx_path(self._rate, options.threshold, self._queue, options.pmf)
|
if self._rate < 4e6:
|
||||||
|
self._resample = pfb.arb_resampler_ccf(4.e6/self._rate)
|
||||||
|
self._rx_rate = 4e6
|
||||||
|
else:
|
||||||
|
self._rx_rate = self._rate
|
||||||
|
|
||||||
|
self._rx_path = air_modes.rx_path(self._rx_rate, options.threshold,
|
||||||
|
self._queue, options.pmf, options.dcblock)
|
||||||
|
|
||||||
|
|
||||||
#now subscribe to set various options via pubsub
|
#now subscribe to set various options via pubsub
|
||||||
self.subscribe("freq", self.set_freq)
|
self.subscribe("freq", self.set_freq)
|
||||||
@@ -80,7 +89,7 @@ class modes_radio (gr.top_block, pubsub):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def add_radio_options(parser):
|
def add_radio_options(parser):
|
||||||
group = OptionGroup(parser, "Receiver setup options")
|
group = OptionGroup(parser, "Receiver setup options")
|
||||||
|
|
||||||
#Choose source
|
#Choose source
|
||||||
group.add_option("-s","--source", type="string", default="uhd",
|
group.add_option("-s","--source", type="string", default="uhd",
|
||||||
help="Choose source: uhd, osmocom, <filename>, or <ip:port> [default=%default]")
|
help="Choose source: uhd, osmocom, <filename>, or <ip:port> [default=%default]")
|
||||||
@@ -102,33 +111,54 @@ class modes_radio (gr.top_block, pubsub):
|
|||||||
#RX path args
|
#RX path args
|
||||||
group.add_option("-r", "--rate", type="eng_float", default=4e6,
|
group.add_option("-r", "--rate", type="eng_float", default=4e6,
|
||||||
help="set sample rate [default=%default]")
|
help="set sample rate [default=%default]")
|
||||||
group.add_option("-T", "--threshold", type="eng_float", default=5.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=False,
|
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,
|
||||||
|
help="Use a DC blocking filter (best for HackRF Jawbreaker) [default=%default]")
|
||||||
|
|
||||||
parser.add_option_group(group)
|
parser.add_option_group(group)
|
||||||
|
|
||||||
def live_source(self):
|
def live_source(self):
|
||||||
return self._options.source is 'uhd' or self._options.source is 'osmocom'
|
return self._options.source=="uhd" or self._options.source=="osmocom"
|
||||||
|
|
||||||
def set_freq(self, freq):
|
def set_freq(self, freq):
|
||||||
return self._u.set_center_freq(freq, 0) if live_source() else 0
|
return self._u.set_center_freq(freq, 0) if self.live_source() else 0
|
||||||
|
|
||||||
def set_gain(self, gain):
|
def set_gain(self, gain):
|
||||||
return self._u.set_gain(gain) if live_source() else 0
|
if self.live_source():
|
||||||
|
self._u.set_gain(gain)
|
||||||
|
print "Gain is %f" % self.get_gain()
|
||||||
|
return self.get_gain()
|
||||||
|
|
||||||
def set_rate(self, rate):
|
def set_rate(self, rate):
|
||||||
return self._u.set_rate(rate) if live_source() else 0
|
if(rate < 4e6 and self._rate > 4e6):
|
||||||
|
raise NotImplementedError("Lowering rate <4e6Msps not currently supported.")
|
||||||
|
if(rate < 4e6):
|
||||||
|
self._resample.set_rate(4e6/rate)
|
||||||
|
self._rx_rate = 4e6
|
||||||
|
else:
|
||||||
|
self._rx_rate = rate
|
||||||
|
self._rx_path.set_rate(self._rx_rate)
|
||||||
|
if self._options.source in ("osmocom"):
|
||||||
|
return self._u.set_sample_rate(rate)
|
||||||
|
if self._options.source in ("uhd"):
|
||||||
|
return self._u.set_rate(rate)
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def set_threshold(self, threshold):
|
||||||
|
self._rx_path.set_threshold(threshold)
|
||||||
|
|
||||||
def get_freq(self, freq):
|
def get_freq(self, freq):
|
||||||
return self._u.get_center_freq(freq, 0) if live_source() else 1090e6
|
return self._u.get_center_freq(freq, 0) if self.live_source() else 1090e6
|
||||||
|
|
||||||
def get_gain(self, gain):
|
|
||||||
return self._u.get_gain() if live_source() else 0
|
|
||||||
|
|
||||||
def get_rate(self, rate):
|
def get_gain(self):
|
||||||
return self._u.get_rate() if live_source() else self._rate
|
return self._u.get_gain() if self.live_source() else 0
|
||||||
|
|
||||||
|
def get_rate(self):
|
||||||
|
return self._u.get_rate() if self.live_source() else self._rate
|
||||||
|
|
||||||
def _setup_source(self, options):
|
def _setup_source(self, options):
|
||||||
if options.source == "uhd":
|
if options.source == "uhd":
|
||||||
@@ -164,31 +194,24 @@ class modes_radio (gr.top_block, pubsub):
|
|||||||
|
|
||||||
#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.
|
||||||
#ALSO TODO: Actually set gain appropriately using gain bins in HackRF driver.
|
|
||||||
#osmocom doesn't have gain bucket distribution like UHD does
|
|
||||||
elif options.source == "osmocom": #RTLSDR dongle or HackRF Jawbreaker
|
elif options.source == "osmocom": #RTLSDR dongle or HackRF Jawbreaker
|
||||||
import osmosdr
|
import osmosdr
|
||||||
self._u = osmosdr.source_c(options.args)
|
self._u = osmosdr.source(options.args)
|
||||||
# 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
|
||||||
###DO NOT COMMIT
|
self._u.set_gain(options.gain)
|
||||||
self._u.set_gain(14, "RF", 0)
|
|
||||||
self._u.set_gain(40, "IF", 0)
|
|
||||||
#self._u.set_gain(14, "BB", 0)
|
|
||||||
###DO NOT COMMIT
|
|
||||||
# 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)
|
||||||
# self._resample = filter.rational_resampler_ccf(interpolation=5, decimation=4, taps=lpfiltcoeffs)
|
# self._resample = filter.rational_resampler_ccf(interpolation=5, decimation=4, taps=lpfiltcoeffs)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
#semantically detect whether it's ip.ip.ip.ip:port or filename
|
#semantically detect whether it's ip.ip.ip.ip:port or filename
|
||||||
if ':' in options.source:
|
if ':' in options.source:
|
||||||
@@ -199,10 +222,13 @@ class modes_radio (gr.top_block, pubsub):
|
|||||||
self._u = gr.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 = gr.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.wait()
|
||||||
self._sender.close()
|
self._sender.close()
|
||||||
|
self._u = None
|
||||||
|
|||||||
@@ -19,12 +19,12 @@
|
|||||||
# Boston, MA 02110-1301, USA.
|
# Boston, MA 02110-1301, USA.
|
||||||
#
|
#
|
||||||
|
|
||||||
from gnuradio import gr, blocks
|
from gnuradio import gr, blocks, filter
|
||||||
import air_modes_swig
|
import air_modes_swig
|
||||||
|
|
||||||
class rx_path(gr.hier_block2):
|
class rx_path(gr.hier_block2):
|
||||||
|
|
||||||
def __init__(self, rate, threshold, queue, use_pmf=False):
|
def __init__(self, rate, threshold, queue, use_pmf=False, use_dcblock=False):
|
||||||
gr.hier_block2.__init__(self, "modes_rx_path",
|
gr.hier_block2.__init__(self, "modes_rx_path",
|
||||||
gr.io_signature(1, 1, gr.sizeof_gr_complex),
|
gr.io_signature(1, 1, gr.sizeof_gr_complex),
|
||||||
gr.io_signature(0,0,0))
|
gr.io_signature(0,0,0))
|
||||||
@@ -35,9 +35,15 @@ class rx_path(gr.hier_block2):
|
|||||||
self._spc = int(rate/2e6)
|
self._spc = int(rate/2e6)
|
||||||
|
|
||||||
# Convert incoming I/Q baseband to amplitude
|
# Convert incoming I/Q baseband to amplitude
|
||||||
self._demod = blocks.complex_to_mag()
|
self._demod = blocks.complex_to_mag_squared()
|
||||||
self._bb = self._demod
|
if use_dcblock:
|
||||||
|
self._dcblock = filter.dc_blocker_cc(100*self._spc,False)
|
||||||
|
self.connect(self, self._dcblock, self._demod)
|
||||||
|
else:
|
||||||
|
self.connect(self, self._demod)
|
||||||
|
self._dcblock = None
|
||||||
|
|
||||||
|
self._bb = self._demod
|
||||||
# Pulse matched filter for 0.5us pulses
|
# Pulse matched filter for 0.5us pulses
|
||||||
if use_pmf:
|
if use_pmf:
|
||||||
self._pmf = blocks.moving_average_ff(self._spc, 1.0/self._spc)#, self._rate)
|
self._pmf = blocks.moving_average_ff(self._spc, 1.0/self._spc)#, self._rate)
|
||||||
@@ -48,24 +54,24 @@ 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_swig.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_swig.modes_slicer(self._rate, self._queue)
|
self._slicer = air_modes_swig.slicer(self._queue)
|
||||||
|
|
||||||
# Wire up the flowgraph
|
# Wire up the flowgraph
|
||||||
self.connect(self, self._demod)
|
|
||||||
self.connect(self._bb, (self._sync, 0))
|
self.connect(self._bb, (self._sync, 0))
|
||||||
self.connect(self._bb, self._avg, (self._sync, 1))
|
self.connect(self._bb, self._avg, (self._sync, 1))
|
||||||
self.connect(self._sync, self._slicer)
|
self.connect(self._sync, self._slicer)
|
||||||
|
|
||||||
def set_rate(self, rate):
|
def set_rate(self, rate):
|
||||||
self._sync.set_rate(rate)
|
self._sync.set_rate(int(rate))
|
||||||
self._slicer.set_rate(rate)
|
|
||||||
self._spc = int(rate/2e6)
|
self._spc = int(rate/2e6)
|
||||||
self._avg.set_length_and_scale(48*self._spc, 1.0/(48*self._spc))
|
self._avg.set_length_and_scale(48*self._spc, 1.0/(48*self._spc))
|
||||||
if self._bb != self._demod:
|
if self._bb != self._demod:
|
||||||
self._pmf.set_length_and_scale(self._spc, 1.0/self._spc)
|
self._pmf.set_length_and_scale(self._spc, 1.0/self._spc)
|
||||||
|
# if self._dcblock is not None:
|
||||||
|
# self._dcblock.set_length(100*self._spc)
|
||||||
|
|
||||||
def set_threshold(self, threshold):
|
def set_threshold(self, threshold):
|
||||||
self._sync.set_threshold(threshold)
|
self._sync.set_threshold(threshold)
|
||||||
@@ -79,4 +85,4 @@ class rx_path(gr.hier_block2):
|
|||||||
|
|
||||||
def get_threshold(self, threshold):
|
def get_threshold(self, threshold):
|
||||||
return self._sync.get_threshold()
|
return self._sync.get_threshold()
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
import time, os, sys, socket
|
import time, os, sys, socket
|
||||||
from string import split, join
|
from string import split, join
|
||||||
import air_modes
|
import air_modes
|
||||||
from datetime import *
|
import datetime
|
||||||
from air_modes.exceptions import *
|
from air_modes.exceptions import *
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ class output_sbs1:
|
|||||||
#it could be cleaner if there were separate output_* fns
|
#it could be cleaner if there were separate output_* fns
|
||||||
#but this works
|
#but this works
|
||||||
for i in (0, 4, 5, 11, 17):
|
for i in (0, 4, 5, 11, 17):
|
||||||
pub.subscribe("type%i_dl" % i, output)
|
pub.subscribe("type%i_dl" % i, self.output)
|
||||||
|
|
||||||
#spawn thread to add new connections as they come in
|
#spawn thread to add new connections as they come in
|
||||||
self._runner = dumb_task_runner(self.add_pending_conns, 0.1)
|
self._runner = dumb_task_runner(self.add_pending_conns, 0.1)
|
||||||
@@ -83,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 self._aircraft_id_map:
|
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]
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ class output_sbs1:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def current_time(self):
|
def current_time(self):
|
||||||
timenow = datetime.now()
|
timenow = datetime.datetime.now()
|
||||||
return [timenow.strftime("%Y/%m/%d"), timenow.strftime("%H:%M:%S.%f")[0:-3]]
|
return [timenow.strftime("%Y/%m/%d"), timenow.strftime("%H:%M:%S.%f")[0:-3]]
|
||||||
|
|
||||||
def decode_fs(self, fs):
|
def decode_fs(self, fs):
|
||||||
@@ -154,7 +154,7 @@ class output_sbs1:
|
|||||||
[datestr, timestr] = self.current_time()
|
[datestr, timestr] = self.current_time()
|
||||||
aircraft_id = self.get_aircraft_id(ecc)
|
aircraft_id = self.get_aircraft_id(ecc)
|
||||||
retstr = "MSG,7,0,%i,%06X,%i,%s,%s,%s,%s,,%s,,,,,,,,,," % (aircraft_id, ecc, aircraft_id+100, datestr, timestr, datestr, timestr, air_modes.decode_alt(shortdata["ac"], True))
|
retstr = "MSG,7,0,%i,%06X,%i,%s,%s,%s,%s,,%s,,,,,,,,,," % (aircraft_id, ecc, aircraft_id+100, datestr, timestr, datestr, timestr, air_modes.decode_alt(shortdata["ac"], True))
|
||||||
if vs:
|
if shortdata["vs"]:
|
||||||
retstr += "1\r\n"
|
retstr += "1\r\n"
|
||||||
else:
|
else:
|
||||||
retstr += "0\r\n"
|
retstr += "0\r\n"
|
||||||
@@ -174,7 +174,7 @@ class output_sbs1:
|
|||||||
|
|
||||||
def pp11(self, shortdata, ecc):
|
def pp11(self, shortdata, ecc):
|
||||||
[datestr, timestr] = self.current_time()
|
[datestr, timestr] = self.current_time()
|
||||||
aircraft_id = self.get_aircraft_id(icao24)
|
aircraft_id = self.get_aircraft_id(shortdata["aa"])
|
||||||
return "MSG,8,0,%i,%06X,%i,%s,%s,%s,%s,,,,,,,,,,,,\r\n" % (aircraft_id, shortdata["aa"], aircraft_id+100, datestr, timestr, datestr, timestr)
|
return "MSG,8,0,%i,%06X,%i,%s,%s,%s,%s,,,,,,,,,,,,\r\n" % (aircraft_id, shortdata["aa"], aircraft_id+100, datestr, timestr, datestr, timestr)
|
||||||
|
|
||||||
def pp17(self, data):
|
def pp17(self, data):
|
||||||
|
|||||||
@@ -316,6 +316,19 @@
|
|||||||
<string>Use Pulse Matched Filtering</string>
|
<string>Use Pulse Matched Filtering</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QCheckBox" name="check_dcblock">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>220</y>
|
||||||
|
<width>221</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Use DC blocking filter</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QGroupBox" name="group_output">
|
<widget class="QGroupBox" name="group_output">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
@@ -835,12 +848,12 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>483</x>
|
<x>483</x>
|
||||||
<y>125</y>
|
<y>125</y>
|
||||||
<width>31</width>
|
<width>51</width>
|
||||||
<height>17</height>
|
<height>17</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>ft/s</string>
|
<string>ft/min</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QLabel" name="label_31">
|
<widget class="QLabel" name="label_31">
|
||||||
|
|||||||
@@ -1,45 +1,17 @@
|
|||||||
/* -*- c++ -*- */
|
/* -*- c++ -*- */
|
||||||
|
|
||||||
%include "gnuradio.i" // the common stuff
|
#define AIR_MODES_API
|
||||||
|
|
||||||
|
%include "gnuradio.i"
|
||||||
|
|
||||||
%{
|
%{
|
||||||
#include "air_modes_preamble.h"
|
#include "gr_air_modes/preamble.h"
|
||||||
#include "air_modes_slicer.h"
|
#include "gr_air_modes/slicer.h"
|
||||||
#include <gnuradio/msg_queue.h>
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
%include "gr_air_modes/preamble.h"
|
||||||
|
%include "gr_air_modes/slicer.h"
|
||||||
|
|
||||||
/*
|
GR_SWIG_BLOCK_MAGIC2(air_modes,preamble);
|
||||||
* First arg is the package prefix.
|
GR_SWIG_BLOCK_MAGIC2(air_modes,slicer);
|
||||||
* Second arg is the name of the class minus the prefix.
|
|
||||||
*
|
|
||||||
* This does some behind-the-scenes magic so we can
|
|
||||||
* access howto_square_ff from python as howto.square_ff
|
|
||||||
*/
|
|
||||||
GR_SWIG_BLOCK_MAGIC(air,modes_preamble);
|
|
||||||
|
|
||||||
air_modes_preamble_sptr air_make_modes_preamble (int channel_rate, float threshold_db);
|
|
||||||
|
|
||||||
class air_modes_preamble : public gr::sync_block
|
|
||||||
{
|
|
||||||
set_rate(int channel_rate);
|
|
||||||
set_threshold(float threshold_db);
|
|
||||||
int get_threshold(void);
|
|
||||||
private:
|
|
||||||
air_modes_preamble (int channel_rate, float threshold_db);
|
|
||||||
};
|
|
||||||
|
|
||||||
GR_SWIG_BLOCK_MAGIC(air,modes_slicer);
|
|
||||||
|
|
||||||
air_modes_slicer_sptr air_make_modes_slicer (int channel_rate, gr::msg_queue::sptr queue);
|
|
||||||
|
|
||||||
class air_modes_slicer : public gr::block
|
|
||||||
{
|
|
||||||
set_rate(int channel_rate);
|
|
||||||
private:
|
|
||||||
air_modes_slicer (int channel_rate, gr::msg_queue::sptr queue);
|
|
||||||
};
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user