├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── MANIFEST.md
├── README.md
├── apps
└── CMakeLists.txt
├── cmake
├── Modules
│ ├── CMakeParseArgumentsCopy.cmake
│ ├── FindCppUnit.cmake
│ ├── FindGnuradioRuntime.cmake
│ ├── GrMiscUtils.cmake
│ ├── GrPlatform.cmake
│ ├── GrPython.cmake
│ ├── GrSwig.cmake
│ ├── GrTest.cmake
│ ├── UseSWIG.cmake
│ └── nordicConfig.cmake
└── cmake_uninstall.cmake.in
├── docs
├── CMakeLists.txt
├── README.nordic
└── doxygen
│ ├── CMakeLists.txt
│ ├── Doxyfile.in
│ ├── Doxyfile.swig_doc.in
│ ├── doxyxml
│ ├── __init__.py
│ ├── base.py
│ ├── doxyindex.py
│ ├── generated
│ │ ├── __init__.py
│ │ ├── compound.py
│ │ ├── compoundsuper.py
│ │ ├── index.py
│ │ └── indexsuper.py
│ └── text.py
│ ├── other
│ ├── group_defs.dox
│ └── main_page.dox
│ └── swig_doc.py
├── examples
├── microsoft_mouse_sniffer.py
├── nordic_auto_ack.py
├── nordic_channelized_receiver.py
├── nordic_channelized_transmitter.py
├── nordic_receiver.py
└── nordic_sniffer_scanner.py
├── grc
├── CMakeLists.txt
├── nordic_nordic_rx.xml
└── nordic_nordic_tx.xml
├── include
└── nordic
│ ├── CMakeLists.txt
│ ├── api.h
│ ├── nordic_rx.h
│ └── nordic_tx.h
├── lib
├── CMakeLists.txt
├── bit_shifting_byte_vector.cc
├── bit_shifting_byte_vector.h
├── enhanced_shockburst_packet.cc
├── enhanced_shockburst_packet.h
├── nordic_rx_impl.cc
├── nordic_rx_impl.h
├── nordic_tx_impl.cc
├── nordic_tx_impl.h
├── nordictap.h
├── qa_nordic.cc
├── qa_nordic.h
└── test_nordic.cc
├── python
├── CMakeLists.txt
├── __init__.py
├── build_utils.py
└── build_utils_codes.py
├── swig
├── CMakeLists.txt
└── nordic_swig.i
└── wireshark
└── nordic_dissector.lua
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | *.pyc
3 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2016 Bastille Networks
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 |
16 |
17 | ########################################################################
18 | # Project setup
19 | ########################################################################
20 | cmake_minimum_required(VERSION 2.6)
21 | project(gr-nordic CXX C)
22 | enable_testing()
23 |
24 | #select the release build type by default to get optimization flags
25 | if(NOT CMAKE_BUILD_TYPE)
26 | set(CMAKE_BUILD_TYPE "Release")
27 | message(STATUS "Build type not specified: defaulting to release.")
28 | endif(NOT CMAKE_BUILD_TYPE)
29 | set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "")
30 |
31 | #make sure our local CMake Modules path comes first
32 | list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules)
33 |
34 | ########################################################################
35 | # Compiler specific setup
36 | ########################################################################
37 | if(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32)
38 | #http://gcc.gnu.org/wiki/Visibility
39 | add_definitions(-fvisibility=hidden)
40 | endif()
41 |
42 | ########################################################################
43 | # Find boost
44 | ########################################################################
45 | if(UNIX AND EXISTS "/usr/lib64")
46 | list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix
47 | endif(UNIX AND EXISTS "/usr/lib64")
48 | set(Boost_ADDITIONAL_VERSIONS
49 | "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"
50 | "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"
51 | "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"
52 | "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"
53 | "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"
54 | "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"
55 | "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"
56 | )
57 | find_package(Boost "1.35" COMPONENTS filesystem system)
58 |
59 | if(NOT Boost_FOUND)
60 | message(FATAL_ERROR "Boost required to compile nordic")
61 | endif()
62 |
63 | ########################################################################
64 | # Install directories
65 | ########################################################################
66 | include(GrPlatform) #define LIB_SUFFIX
67 | set(GR_RUNTIME_DIR bin)
68 | set(GR_LIBRARY_DIR lib${LIB_SUFFIX})
69 | set(GR_INCLUDE_DIR include/nordic)
70 | set(GR_DATA_DIR share)
71 | set(GR_PKG_DATA_DIR ${GR_DATA_DIR}/${CMAKE_PROJECT_NAME})
72 | set(GR_DOC_DIR ${GR_DATA_DIR}/doc)
73 | set(GR_PKG_DOC_DIR ${GR_DOC_DIR}/${CMAKE_PROJECT_NAME})
74 | set(GR_CONF_DIR etc)
75 | set(GR_PKG_CONF_DIR ${GR_CONF_DIR}/${CMAKE_PROJECT_NAME}/conf.d)
76 | set(GR_LIBEXEC_DIR libexec)
77 | set(GR_PKG_LIBEXEC_DIR ${GR_LIBEXEC_DIR}/${CMAKE_PROJECT_NAME})
78 | set(GRC_BLOCKS_DIR ${GR_PKG_DATA_DIR}/grc/blocks)
79 |
80 | ########################################################################
81 | # On Apple only, set install name and use rpath correctly, if not already set
82 | ########################################################################
83 | if(APPLE)
84 | if(NOT CMAKE_INSTALL_NAME_DIR)
85 | set(CMAKE_INSTALL_NAME_DIR
86 | ${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE
87 | PATH "Library Install Name Destination Directory" FORCE)
88 | endif(NOT CMAKE_INSTALL_NAME_DIR)
89 | if(NOT CMAKE_INSTALL_RPATH)
90 | set(CMAKE_INSTALL_RPATH
91 | ${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE
92 | PATH "Library Install RPath" FORCE)
93 | endif(NOT CMAKE_INSTALL_RPATH)
94 | if(NOT CMAKE_BUILD_WITH_INSTALL_RPATH)
95 | set(CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE
96 | BOOL "Do Build Using Library Install RPath" FORCE)
97 | endif(NOT CMAKE_BUILD_WITH_INSTALL_RPATH)
98 | endif(APPLE)
99 |
100 | ########################################################################
101 | # Find gnuradio build dependencies
102 | ########################################################################
103 | find_package(CppUnit)
104 | find_package(Doxygen)
105 |
106 | # Search for GNU Radio and its components and versions. Add any
107 | # components required to the list of GR_REQUIRED_COMPONENTS (in all
108 | # caps such as FILTER or FFT) and change the version to the minimum
109 | # API compatible version required.
110 | set(GR_REQUIRED_COMPONENTS RUNTIME)
111 | find_package(Gnuradio "3.7.2" REQUIRED)
112 |
113 | if(NOT CPPUNIT_FOUND)
114 | message(FATAL_ERROR "CppUnit required to compile nordic")
115 | endif()
116 |
117 | ########################################################################
118 | # Setup doxygen option
119 | ########################################################################
120 | if(DOXYGEN_FOUND)
121 | option(ENABLE_DOXYGEN "Build docs using Doxygen" ON)
122 | else(DOXYGEN_FOUND)
123 | option(ENABLE_DOXYGEN "Build docs using Doxygen" OFF)
124 | endif(DOXYGEN_FOUND)
125 |
126 | ########################################################################
127 | # Setup the include and linker paths
128 | ########################################################################
129 | include_directories(
130 | ${CMAKE_SOURCE_DIR}/lib
131 | ${CMAKE_SOURCE_DIR}/include
132 | ${CMAKE_BINARY_DIR}/lib
133 | ${CMAKE_BINARY_DIR}/include
134 | ${Boost_INCLUDE_DIRS}
135 | ${CPPUNIT_INCLUDE_DIRS}
136 | ${GNURADIO_ALL_INCLUDE_DIRS}
137 | )
138 |
139 | link_directories(
140 | ${Boost_LIBRARY_DIRS}
141 | ${CPPUNIT_LIBRARY_DIRS}
142 | ${GNURADIO_RUNTIME_LIBRARY_DIRS}
143 | )
144 |
145 | # Set component parameters
146 | set(GR_NORDIC_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "" FORCE)
147 | set(GR_NORDIC_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/swig CACHE INTERNAL "" FORCE)
148 |
149 | ########################################################################
150 | # Create uninstall target
151 | ########################################################################
152 | configure_file(
153 | ${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in
154 | ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
155 | @ONLY)
156 |
157 | add_custom_target(uninstall
158 | ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
159 | )
160 |
161 | ########################################################################
162 | # Add subdirectories
163 | ########################################################################
164 | add_subdirectory(include/nordic)
165 | add_subdirectory(lib)
166 | add_subdirectory(swig)
167 | add_subdirectory(python)
168 | add_subdirectory(grc)
169 | add_subdirectory(apps)
170 | add_subdirectory(docs)
171 |
172 | ########################################################################
173 | # Install cmake search helper for this library
174 | ########################################################################
175 | if(NOT CMAKE_MODULES_DIR)
176 | set(CMAKE_MODULES_DIR lib${LIB_SUFFIX}/cmake)
177 | endif(NOT CMAKE_MODULES_DIR)
178 |
179 | install(FILES cmake/Modules/nordicConfig.cmake
180 | DESTINATION ${CMAKE_MODULES_DIR}/nordic
181 | )
182 |
--------------------------------------------------------------------------------
/MANIFEST.md:
--------------------------------------------------------------------------------
1 | title: The NORDIC OOT Module
2 | brief: Short description of gr-nordic
3 | tags: # Tags are arbitrary, but look at CGRAN what other authors are using
4 | - sdr
5 | author:
6 | - Author Name
7 | copyright_owner:
8 | - Copyright Owner 1
9 | license:
10 | #repo: # Put the URL of the repository here, or leave blank for default
11 | #website: # If you have a separate project website, put it here
12 | #icon: # Put a URL to a square image here that will be used as an icon on CGRAN
13 | ---
14 | A longer, multi-line description of gr-nordic.
15 | You may use some *basic* Markdown here.
16 | If left empty, it will try to find a README file instead.
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # gr-nordic
2 |
3 | GNU Radio module and Wireshark dissector for the Nordic Semiconductor nRF24L Enhanced Shockburst protocol.
4 |
5 | ## external c++ classes
6 |
7 | ### nordic_rx
8 |
9 | Receiver class which consumes a GFSK demodulated bitstream and reconstructs Enhanced Shockburst packets. PDUs are printed standard out and sent to Wireshark.
10 |
11 | ### nordic_tx
12 |
13 | Transmitter class which consumes nordictap structs, generates Enhanced Shockburst packets, and produces a byte stream to be fed to a GFSK modulator.
14 |
15 | ## python examples
16 |
17 | All python examples use the osmosdr_source/osmosdr_sink blocks, and are SDR agnostic.
18 |
19 | ### nordic_receiver.py
20 |
21 | Single channel receiver. Listening on channel 4 (2404MHz) with a 2Mbps data rate, 5 byte address, and 2 byte CRC is invoked as follows:
22 |
23 | ```./nordic_receiver.py --channel 4 --data_rate 2e6 --crc_length 2 --address_length 5 --samples_per_symbol 2 --gain 40```
24 |
25 | ### nordic_auto_ack.py
26 |
27 | Single channel receiver with auto-ACK. Listening (and ACKing) on channel 4 (2404MHz) with a 2Mbps data rate, 5 byte address, and 2 byte CRC is invoked as follows:
28 |
29 | ```./nordic_auto_ack.py --channel 4 --data_rate 2e6 --crc_length 2 --address_length 5 --samples_per_symbol 2 --gain 40```
30 |
31 | ### nordic_sniffer_scanner.py
32 |
33 | Sweeping single channel receiver, which sweeps between channels 2-83 looking for Enhanced Shockburst packets. During receive activity, it camps on a given channel until idle.
34 |
35 | ```./nordic_sniffer_scanner.py ```
36 |
37 | ### microsoft_mouse_sniffer.py
38 |
39 | Microsoft mouse/keyboard following receiver. When launched, this script will sweep between the 24 possible Microsoft wireless keyboard/mouse channels. When a device is found, it switches to that device's 4-channel group, sweeping between that set to follow the device.
40 |
41 | ```./microsoft_mouse_sniffer.py ```
42 |
43 | ### nordic_channelized_receiver.py
44 |
45 | Channelized receiver example, which tunes to 2414MHz, and receives 2Mbps Enhanced Shockburst packets on channels 10, 14, and 18.
46 |
47 | ```./nordic_channelized_receiver.py ```
48 |
49 | ### nordic_channelized_transmitter.py
50 |
51 | Channelized transmitter example, which tunes to 2414MHz, and transmits 2Mbps Enhanced Shockburst packets on channels 10, 14, and 18.
52 |
53 | ```./nordic_channelized_transmitter.py ```
54 |
55 | ## wireshark dissector
56 |
57 | The wireshark dissector will display Enhanced Shockburst packets in Wireshark. The logic is very straightforward, and will be simple to extend to classify various device types.
58 |
59 | ### wireshark/nordic_dissector.lua
60 |
61 | ```wireshark -X lua_script:wireshark/nordic_dissector.lua -i lo -k -f udp ```
62 |
63 | ## nRF24LU1+ research firmware
64 |
65 | Corresponding research firmware for the nRF24LU1+ chips (including Logitech Unifying dongles) is available [here](https://github.com/BastilleResearch/nrf-research-firmware/).
66 |
67 | Documentation on the packet formats covered by the MouseJack and KeySniffer vulnerability sets is available [here](https://github.com/BastilleResearch/mousejack/tree/master/doc/pdf).
68 |
--------------------------------------------------------------------------------
/apps/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2016 Bastille Networks
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 |
16 | include(GrPython)
17 |
18 | GR_PYTHON_INSTALL(
19 | PROGRAMS
20 | DESTINATION bin
21 | )
22 |
--------------------------------------------------------------------------------
/cmake/Modules/CMakeParseArgumentsCopy.cmake:
--------------------------------------------------------------------------------
1 | # CMAKE_PARSE_ARGUMENTS( args...)
2 | #
3 | # CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions for
4 | # parsing the arguments given to that macro or function.
5 | # It processes the arguments and defines a set of variables which hold the
6 | # values of the respective options.
7 | #
8 | # The argument contains all options for the respective macro,
9 | # i.e. keywords which can be used when calling the macro without any value
10 | # following, like e.g. the OPTIONAL keyword of the install() command.
11 | #
12 | # The argument contains all keywords for this macro
13 | # which are followed by one value, like e.g. DESTINATION keyword of the
14 | # install() command.
15 | #
16 | # The argument contains all keywords for this macro
17 | # which can be followed by more than one value, like e.g. the TARGETS or
18 | # FILES keywords of the install() command.
19 | #
20 | # When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the
21 | # keywords listed in , and
22 | # a variable composed of the given
23 | # followed by "_" and the name of the respective keyword.
24 | # These variables will then hold the respective value from the argument list.
25 | # For the keywords this will be TRUE or FALSE.
26 | #
27 | # All remaining arguments are collected in a variable
28 | # _UNPARSED_ARGUMENTS, this can be checked afterwards to see whether
29 | # your macro was called with unrecognized parameters.
30 | #
31 | # As an example here a my_install() macro, which takes similar arguments as the
32 | # real install() command:
33 | #
34 | # function(MY_INSTALL)
35 | # set(options OPTIONAL FAST)
36 | # set(oneValueArgs DESTINATION RENAME)
37 | # set(multiValueArgs TARGETS CONFIGURATIONS)
38 | # cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
39 | # ...
40 | #
41 | # Assume my_install() has been called like this:
42 | # my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub)
43 | #
44 | # After the cmake_parse_arguments() call the macro will have set the following
45 | # variables:
46 | # MY_INSTALL_OPTIONAL = TRUE
47 | # MY_INSTALL_FAST = FALSE (this option was not used when calling my_install()
48 | # MY_INSTALL_DESTINATION = "bin"
49 | # MY_INSTALL_RENAME = "" (was not used)
50 | # MY_INSTALL_TARGETS = "foo;bar"
51 | # MY_INSTALL_CONFIGURATIONS = "" (was not used)
52 | # MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL"
53 | #
54 | # You can the continue and process these variables.
55 | #
56 | # Keywords terminate lists of values, e.g. if directly after a one_value_keyword
57 | # another recognized keyword follows, this is interpreted as the beginning of
58 | # the new option.
59 | # E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in
60 | # MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would
61 | # be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor.
62 |
63 | #=============================================================================
64 | # Copyright 2010 Alexander Neundorf
65 | #
66 | # Distributed under the OSI-approved BSD License (the "License");
67 | # see accompanying file Copyright.txt for details.
68 | #
69 | # This software is distributed WITHOUT ANY WARRANTY; without even the
70 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
71 | # See the License for more information.
72 | #=============================================================================
73 | # (To distribute this file outside of CMake, substitute the full
74 | # License text for the above reference.)
75 |
76 |
77 | if(__CMAKE_PARSE_ARGUMENTS_INCLUDED)
78 | return()
79 | endif()
80 | set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE)
81 |
82 |
83 | function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames)
84 | # first set all result variables to empty/FALSE
85 | foreach(arg_name ${_singleArgNames} ${_multiArgNames})
86 | set(${prefix}_${arg_name})
87 | endforeach(arg_name)
88 |
89 | foreach(option ${_optionNames})
90 | set(${prefix}_${option} FALSE)
91 | endforeach(option)
92 |
93 | set(${prefix}_UNPARSED_ARGUMENTS)
94 |
95 | set(insideValues FALSE)
96 | set(currentArgName)
97 |
98 | # now iterate over all arguments and fill the result variables
99 | foreach(currentArg ${ARGN})
100 | list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword
101 | list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword
102 | list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword
103 |
104 | if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1)
105 | if(insideValues)
106 | if("${insideValues}" STREQUAL "SINGLE")
107 | set(${prefix}_${currentArgName} ${currentArg})
108 | set(insideValues FALSE)
109 | elseif("${insideValues}" STREQUAL "MULTI")
110 | list(APPEND ${prefix}_${currentArgName} ${currentArg})
111 | endif()
112 | else(insideValues)
113 | list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg})
114 | endif(insideValues)
115 | else()
116 | if(NOT ${optionIndex} EQUAL -1)
117 | set(${prefix}_${currentArg} TRUE)
118 | set(insideValues FALSE)
119 | elseif(NOT ${singleArgIndex} EQUAL -1)
120 | set(currentArgName ${currentArg})
121 | set(${prefix}_${currentArgName})
122 | set(insideValues "SINGLE")
123 | elseif(NOT ${multiArgIndex} EQUAL -1)
124 | set(currentArgName ${currentArg})
125 | set(${prefix}_${currentArgName})
126 | set(insideValues "MULTI")
127 | endif()
128 | endif()
129 |
130 | endforeach(currentArg)
131 |
132 | # propagate the result variables to the caller:
133 | foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames})
134 | set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE)
135 | endforeach(arg_name)
136 | set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE)
137 |
138 | endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs)
139 |
--------------------------------------------------------------------------------
/cmake/Modules/FindCppUnit.cmake:
--------------------------------------------------------------------------------
1 | # http://www.cmake.org/pipermail/cmake/2006-October/011446.html
2 | # Modified to use pkg config and use standard var names
3 |
4 | #
5 | # Find the CppUnit includes and library
6 | #
7 | # This module defines
8 | # CPPUNIT_INCLUDE_DIR, where to find tiff.h, etc.
9 | # CPPUNIT_LIBRARIES, the libraries to link against to use CppUnit.
10 | # CPPUNIT_FOUND, If false, do not try to use CppUnit.
11 |
12 | INCLUDE(FindPkgConfig)
13 | PKG_CHECK_MODULES(PC_CPPUNIT "cppunit")
14 |
15 | FIND_PATH(CPPUNIT_INCLUDE_DIRS
16 | NAMES cppunit/TestCase.h
17 | HINTS ${PC_CPPUNIT_INCLUDE_DIR}
18 | ${CMAKE_INSTALL_PREFIX}/include
19 | PATHS
20 | /usr/local/include
21 | /usr/include
22 | )
23 |
24 | FIND_LIBRARY(CPPUNIT_LIBRARIES
25 | NAMES cppunit
26 | HINTS ${PC_CPPUNIT_LIBDIR}
27 | ${CMAKE_INSTALL_PREFIX}/lib
28 | ${CMAKE_INSTALL_PREFIX}/lib64
29 | PATHS
30 | ${CPPUNIT_INCLUDE_DIRS}/../lib
31 | /usr/local/lib
32 | /usr/lib
33 | )
34 |
35 | LIST(APPEND CPPUNIT_LIBRARIES ${CMAKE_DL_LIBS})
36 |
37 | INCLUDE(FindPackageHandleStandardArgs)
38 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(CPPUNIT DEFAULT_MSG CPPUNIT_LIBRARIES CPPUNIT_INCLUDE_DIRS)
39 | MARK_AS_ADVANCED(CPPUNIT_LIBRARIES CPPUNIT_INCLUDE_DIRS)
40 |
--------------------------------------------------------------------------------
/cmake/Modules/FindGnuradioRuntime.cmake:
--------------------------------------------------------------------------------
1 | INCLUDE(FindPkgConfig)
2 | PKG_CHECK_MODULES(PC_GNURADIO_RUNTIME gnuradio-runtime)
3 |
4 | if(PC_GNURADIO_RUNTIME_FOUND)
5 | # look for include files
6 | FIND_PATH(
7 | GNURADIO_RUNTIME_INCLUDE_DIRS
8 | NAMES gnuradio/top_block.h
9 | HINTS $ENV{GNURADIO_RUNTIME_DIR}/include
10 | ${PC_GNURADIO_RUNTIME_INCLUDE_DIRS}
11 | ${CMAKE_INSTALL_PREFIX}/include
12 | PATHS /usr/local/include
13 | /usr/include
14 | )
15 |
16 | # look for libs
17 | FIND_LIBRARY(
18 | GNURADIO_RUNTIME_LIBRARIES
19 | NAMES gnuradio-runtime
20 | HINTS $ENV{GNURADIO_RUNTIME_DIR}/lib
21 | ${PC_GNURADIO_RUNTIME_LIBDIR}
22 | ${CMAKE_INSTALL_PREFIX}/lib/
23 | ${CMAKE_INSTALL_PREFIX}/lib64/
24 | PATHS /usr/local/lib
25 | /usr/local/lib64
26 | /usr/lib
27 | /usr/lib64
28 | )
29 |
30 | set(GNURADIO_RUNTIME_FOUND ${PC_GNURADIO_RUNTIME_FOUND})
31 | endif(PC_GNURADIO_RUNTIME_FOUND)
32 |
33 | INCLUDE(FindPackageHandleStandardArgs)
34 | # do not check GNURADIO_RUNTIME_INCLUDE_DIRS, is not set when default include path us used.
35 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNURADIO_RUNTIME DEFAULT_MSG GNURADIO_RUNTIME_LIBRARIES)
36 | MARK_AS_ADVANCED(GNURADIO_RUNTIME_LIBRARIES GNURADIO_RUNTIME_INCLUDE_DIRS)
37 |
--------------------------------------------------------------------------------
/cmake/Modules/GrMiscUtils.cmake:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2016 Bastille Networks
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 |
16 | if(DEFINED __INCLUDED_GR_MISC_UTILS_CMAKE)
17 | return()
18 | endif()
19 | set(__INCLUDED_GR_MISC_UTILS_CMAKE TRUE)
20 |
21 | ########################################################################
22 | # Set global variable macro.
23 | # Used for subdirectories to export settings.
24 | # Example: include and library paths.
25 | ########################################################################
26 | function(GR_SET_GLOBAL var)
27 | set(${var} ${ARGN} CACHE INTERNAL "" FORCE)
28 | endfunction(GR_SET_GLOBAL)
29 |
30 | ########################################################################
31 | # Set the pre-processor definition if the condition is true.
32 | # - def the pre-processor definition to set and condition name
33 | ########################################################################
34 | function(GR_ADD_COND_DEF def)
35 | if(${def})
36 | add_definitions(-D${def})
37 | endif(${def})
38 | endfunction(GR_ADD_COND_DEF)
39 |
40 | ########################################################################
41 | # Check for a header and conditionally set a compile define.
42 | # - hdr the relative path to the header file
43 | # - def the pre-processor definition to set
44 | ########################################################################
45 | function(GR_CHECK_HDR_N_DEF hdr def)
46 | include(CheckIncludeFileCXX)
47 | CHECK_INCLUDE_FILE_CXX(${hdr} ${def})
48 | GR_ADD_COND_DEF(${def})
49 | endfunction(GR_CHECK_HDR_N_DEF)
50 |
51 | ########################################################################
52 | # Include subdirectory macro.
53 | # Sets the CMake directory variables,
54 | # includes the subdirectory CMakeLists.txt,
55 | # resets the CMake directory variables.
56 | #
57 | # This macro includes subdirectories rather than adding them
58 | # so that the subdirectory can affect variables in the level above.
59 | # This provides a work-around for the lack of convenience libraries.
60 | # This way a subdirectory can append to the list of library sources.
61 | ########################################################################
62 | macro(GR_INCLUDE_SUBDIRECTORY subdir)
63 | #insert the current directories on the front of the list
64 | list(INSERT _cmake_source_dirs 0 ${CMAKE_CURRENT_SOURCE_DIR})
65 | list(INSERT _cmake_binary_dirs 0 ${CMAKE_CURRENT_BINARY_DIR})
66 |
67 | #set the current directories to the names of the subdirs
68 | set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${subdir})
69 | set(CMAKE_CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${subdir})
70 |
71 | #include the subdirectory CMakeLists to run it
72 | file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
73 | include(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt)
74 |
75 | #reset the value of the current directories
76 | list(GET _cmake_source_dirs 0 CMAKE_CURRENT_SOURCE_DIR)
77 | list(GET _cmake_binary_dirs 0 CMAKE_CURRENT_BINARY_DIR)
78 |
79 | #pop the subdir names of the front of the list
80 | list(REMOVE_AT _cmake_source_dirs 0)
81 | list(REMOVE_AT _cmake_binary_dirs 0)
82 | endmacro(GR_INCLUDE_SUBDIRECTORY)
83 |
84 | ########################################################################
85 | # Check if a compiler flag works and conditionally set a compile define.
86 | # - flag the compiler flag to check for
87 | # - have the variable to set with result
88 | ########################################################################
89 | macro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE flag have)
90 | include(CheckCXXCompilerFlag)
91 | CHECK_CXX_COMPILER_FLAG(${flag} ${have})
92 | if(${have})
93 | if(${CMAKE_VERSION} VERSION_GREATER "2.8.4")
94 | STRING(FIND "${CMAKE_CXX_FLAGS}" "${flag}" flag_dup)
95 | if(${flag_dup} EQUAL -1)
96 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}")
97 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flag}")
98 | endif(${flag_dup} EQUAL -1)
99 | endif(${CMAKE_VERSION} VERSION_GREATER "2.8.4")
100 | endif(${have})
101 | endmacro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE)
102 |
103 | ########################################################################
104 | # Generates the .la libtool file
105 | # This appears to generate libtool files that cannot be used by auto*.
106 | # Usage GR_LIBTOOL(TARGET [target] DESTINATION [dest])
107 | # Notice: there is not COMPONENT option, these will not get distributed.
108 | ########################################################################
109 | function(GR_LIBTOOL)
110 | if(NOT DEFINED GENERATE_LIBTOOL)
111 | set(GENERATE_LIBTOOL OFF) #disabled by default
112 | endif()
113 |
114 | if(GENERATE_LIBTOOL)
115 | include(CMakeParseArgumentsCopy)
116 | CMAKE_PARSE_ARGUMENTS(GR_LIBTOOL "" "TARGET;DESTINATION" "" ${ARGN})
117 |
118 | find_program(LIBTOOL libtool)
119 | if(LIBTOOL)
120 | include(CMakeMacroLibtoolFile)
121 | CREATE_LIBTOOL_FILE(${GR_LIBTOOL_TARGET} /${GR_LIBTOOL_DESTINATION})
122 | endif(LIBTOOL)
123 | endif(GENERATE_LIBTOOL)
124 |
125 | endfunction(GR_LIBTOOL)
126 |
127 | ########################################################################
128 | # Do standard things to the library target
129 | # - set target properties
130 | # - make install rules
131 | # Also handle gnuradio custom naming conventions w/ extras mode.
132 | ########################################################################
133 | function(GR_LIBRARY_FOO target)
134 | #parse the arguments for component names
135 | include(CMakeParseArgumentsCopy)
136 | CMAKE_PARSE_ARGUMENTS(GR_LIBRARY "" "RUNTIME_COMPONENT;DEVEL_COMPONENT" "" ${ARGN})
137 |
138 | #set additional target properties
139 | set_target_properties(${target} PROPERTIES SOVERSION ${LIBVER})
140 |
141 | #install the generated files like so...
142 | install(TARGETS ${target}
143 | LIBRARY DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} # .so/.dylib file
144 | ARCHIVE DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_DEVEL_COMPONENT} # .lib file
145 | RUNTIME DESTINATION ${GR_RUNTIME_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} # .dll file
146 | )
147 |
148 | #extras mode enabled automatically on linux
149 | if(NOT DEFINED LIBRARY_EXTRAS)
150 | set(LIBRARY_EXTRAS ${LINUX})
151 | endif()
152 |
153 | #special extras mode to enable alternative naming conventions
154 | if(LIBRARY_EXTRAS)
155 |
156 | #create .la file before changing props
157 | GR_LIBTOOL(TARGET ${target} DESTINATION ${GR_LIBRARY_DIR})
158 |
159 | #give the library a special name with ultra-zero soversion
160 | set_target_properties(${target} PROPERTIES OUTPUT_NAME ${target}-${LIBVER} SOVERSION "0.0.0")
161 | set(target_name lib${target}-${LIBVER}.so.0.0.0)
162 |
163 | #custom command to generate symlinks
164 | add_custom_command(
165 | TARGET ${target}
166 | POST_BUILD
167 | COMMAND ${CMAKE_COMMAND} -E create_symlink ${target_name} ${CMAKE_CURRENT_BINARY_DIR}/lib${target}.so
168 | COMMAND ${CMAKE_COMMAND} -E create_symlink ${target_name} ${CMAKE_CURRENT_BINARY_DIR}/lib${target}-${LIBVER}.so.0
169 | COMMAND ${CMAKE_COMMAND} -E touch ${target_name} #so the symlinks point to something valid so cmake 2.6 will install
170 | )
171 |
172 | #and install the extra symlinks
173 | install(
174 | FILES
175 | ${CMAKE_CURRENT_BINARY_DIR}/lib${target}.so
176 | ${CMAKE_CURRENT_BINARY_DIR}/lib${target}-${LIBVER}.so.0
177 | DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT}
178 | )
179 |
180 | endif(LIBRARY_EXTRAS)
181 | endfunction(GR_LIBRARY_FOO)
182 |
183 | ########################################################################
184 | # Create a dummy custom command that depends on other targets.
185 | # Usage:
186 | # GR_GEN_TARGET_DEPS(unique_name target_deps ...)
187 | # ADD_CUSTOM_COMMAND( ${target_deps})
188 | #
189 | # Custom command cant depend on targets, but can depend on executables,
190 | # and executables can depend on targets. So this is the process:
191 | ########################################################################
192 | function(GR_GEN_TARGET_DEPS name var)
193 | file(
194 | WRITE ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp.in
195 | "int main(void){return 0;}\n"
196 | )
197 | execute_process(
198 | COMMAND ${CMAKE_COMMAND} -E copy_if_different
199 | ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp.in
200 | ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp
201 | )
202 | add_executable(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp)
203 | if(ARGN)
204 | add_dependencies(${name} ${ARGN})
205 | endif(ARGN)
206 |
207 | if(CMAKE_CROSSCOMPILING)
208 | set(${var} "DEPENDS;${name}" PARENT_SCOPE) #cant call command when cross
209 | else()
210 | set(${var} "DEPENDS;${name};COMMAND;${name}" PARENT_SCOPE)
211 | endif()
212 | endfunction(GR_GEN_TARGET_DEPS)
213 |
214 | ########################################################################
215 | # Control use of gr_logger
216 | # Usage:
217 | # GR_LOGGING()
218 | #
219 | # Will set ENABLE_GR_LOG to 1 by default.
220 | # Can manually set with -DENABLE_GR_LOG=0|1
221 | ########################################################################
222 | function(GR_LOGGING)
223 | find_package(Log4cpp)
224 |
225 | OPTION(ENABLE_GR_LOG "Use gr_logger" ON)
226 | if(ENABLE_GR_LOG)
227 | # If gr_logger is enabled, make it usable
228 | add_definitions( -DENABLE_GR_LOG )
229 |
230 | # also test LOG4CPP; if we have it, use this version of the logger
231 | # otherwise, default to the stdout/stderr model.
232 | if(LOG4CPP_FOUND)
233 | SET(HAVE_LOG4CPP True CACHE INTERNAL "" FORCE)
234 | add_definitions( -DHAVE_LOG4CPP )
235 | else(not LOG4CPP_FOUND)
236 | SET(HAVE_LOG4CPP False CACHE INTERNAL "" FORCE)
237 | SET(LOG4CPP_INCLUDE_DIRS "" CACHE INTERNAL "" FORCE)
238 | SET(LOG4CPP_LIBRARY_DIRS "" CACHE INTERNAL "" FORCE)
239 | SET(LOG4CPP_LIBRARIES "" CACHE INTERNAL "" FORCE)
240 | endif(LOG4CPP_FOUND)
241 |
242 | SET(ENABLE_GR_LOG ${ENABLE_GR_LOG} CACHE INTERNAL "" FORCE)
243 |
244 | else(ENABLE_GR_LOG)
245 | SET(HAVE_LOG4CPP False CACHE INTERNAL "" FORCE)
246 | SET(LOG4CPP_INCLUDE_DIRS "" CACHE INTERNAL "" FORCE)
247 | SET(LOG4CPP_LIBRARY_DIRS "" CACHE INTERNAL "" FORCE)
248 | SET(LOG4CPP_LIBRARIES "" CACHE INTERNAL "" FORCE)
249 | endif(ENABLE_GR_LOG)
250 |
251 | message(STATUS "ENABLE_GR_LOG set to ${ENABLE_GR_LOG}.")
252 | message(STATUS "HAVE_LOG4CPP set to ${HAVE_LOG4CPP}.")
253 | message(STATUS "LOG4CPP_LIBRARIES set to ${LOG4CPP_LIBRARIES}.")
254 |
255 | endfunction(GR_LOGGING)
256 |
257 | ########################################################################
258 | # Run GRCC to compile .grc files into .py files.
259 | #
260 | # Usage: GRCC(filename, directory)
261 | # - filenames: List of file name of .grc file
262 | # - directory: directory of built .py file - usually in
263 | # ${CMAKE_CURRENT_BINARY_DIR}
264 | # - Sets PYFILES: output converted GRC file names to Python files.
265 | ########################################################################
266 | function(GRCC)
267 | # Extract directory from list of args, remove it for the list of filenames.
268 | list(GET ARGV -1 directory)
269 | list(REMOVE_AT ARGV -1)
270 | set(filenames ${ARGV})
271 | file(MAKE_DIRECTORY ${directory})
272 |
273 | SET(GRCC_COMMAND ${CMAKE_SOURCE_DIR}/gr-utils/python/grcc)
274 |
275 | # GRCC uses some stuff in grc and gnuradio-runtime, so we force
276 | # the known paths here
277 | list(APPEND PYTHONPATHS
278 | ${CMAKE_SOURCE_DIR}
279 | ${CMAKE_SOURCE_DIR}/gnuradio-runtime/python
280 | ${CMAKE_SOURCE_DIR}/gnuradio-runtime/lib/swig
281 | ${CMAKE_BINARY_DIR}/gnuradio-runtime/lib/swig
282 | )
283 |
284 | if(WIN32)
285 | #SWIG generates the python library files into a subdirectory.
286 | #Therefore, we must append this subdirectory into PYTHONPATH.
287 | #Only do this for the python directories matching the following:
288 | foreach(pydir ${PYTHONPATHS})
289 | get_filename_component(name ${pydir} NAME)
290 | if(name MATCHES "^(swig|lib|src)$")
291 | list(APPEND PYTHONPATHS ${pydir}/${CMAKE_BUILD_TYPE})
292 | endif()
293 | endforeach(pydir)
294 | endif(WIN32)
295 |
296 | file(TO_NATIVE_PATH "${PYTHONPATHS}" pypath)
297 |
298 | if(UNIX)
299 | list(APPEND pypath "$PYTHONPATH")
300 | string(REPLACE ";" ":" pypath "${pypath}")
301 | set(ENV{PYTHONPATH} ${pypath})
302 | endif(UNIX)
303 |
304 | if(WIN32)
305 | list(APPEND pypath "%PYTHONPATH%")
306 | string(REPLACE ";" "\\;" pypath "${pypath}")
307 | #list(APPEND environs "PYTHONPATH=${pypath}")
308 | set(ENV{PYTHONPATH} ${pypath})
309 | endif(WIN32)
310 |
311 | foreach(f ${filenames})
312 | execute_process(
313 | COMMAND ${GRCC_COMMAND} -d ${directory} ${f}
314 | )
315 | string(REPLACE ".grc" ".py" pyfile "${f}")
316 | string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" pyfile "${pyfile}")
317 | list(APPEND pyfiles ${pyfile})
318 | endforeach(f)
319 |
320 | set(PYFILES ${pyfiles} PARENT_SCOPE)
321 | endfunction(GRCC)
322 |
323 | ########################################################################
324 | # Check if HAVE_PTHREAD_SETSCHEDPARAM and HAVE_SCHED_SETSCHEDULER
325 | # should be defined
326 | ########################################################################
327 | macro(GR_CHECK_LINUX_SCHED_AVAIL)
328 | set(CMAKE_REQUIRED_LIBRARIES -lpthread)
329 | CHECK_CXX_SOURCE_COMPILES("
330 | #include
331 | int main(){
332 | pthread_t pthread;
333 | pthread_setschedparam(pthread, 0, 0);
334 | return 0;
335 | } " HAVE_PTHREAD_SETSCHEDPARAM
336 | )
337 | GR_ADD_COND_DEF(HAVE_PTHREAD_SETSCHEDPARAM)
338 |
339 | CHECK_CXX_SOURCE_COMPILES("
340 | #include
341 | int main(){
342 | pid_t pid;
343 | sched_setscheduler(pid, 0, 0);
344 | return 0;
345 | } " HAVE_SCHED_SETSCHEDULER
346 | )
347 | GR_ADD_COND_DEF(HAVE_SCHED_SETSCHEDULER)
348 | endmacro(GR_CHECK_LINUX_SCHED_AVAIL)
349 |
350 | ########################################################################
351 | # Macros to generate source and header files from template
352 | ########################################################################
353 | macro(GR_EXPAND_X_H component root)
354 |
355 | include(GrPython)
356 |
357 | file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
358 | "#!${PYTHON_EXECUTABLE}
359 |
360 | import sys, os, re
361 | sys.path.append('${GR_RUNTIME_PYTHONPATH}')
362 | os.environ['srcdir'] = '${CMAKE_CURRENT_SOURCE_DIR}'
363 | os.chdir('${CMAKE_CURRENT_BINARY_DIR}')
364 |
365 | if __name__ == '__main__':
366 | import build_utils
367 | root, inp = sys.argv[1:3]
368 | for sig in sys.argv[3:]:
369 | name = re.sub ('X+', sig, root)
370 | d = build_utils.standard_dict2(name, sig, '${component}')
371 | build_utils.expand_template(d, inp)
372 | ")
373 |
374 | #make a list of all the generated headers
375 | unset(expanded_files_h)
376 | foreach(sig ${ARGN})
377 | string(REGEX REPLACE "X+" ${sig} name ${root})
378 | list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/${name}.h)
379 | endforeach(sig)
380 | unset(name)
381 |
382 | #create a command to generate the headers
383 | add_custom_command(
384 | OUTPUT ${expanded_files_h}
385 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}.h.t
386 | COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
387 | ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
388 | ${root} ${root}.h.t ${ARGN}
389 | )
390 |
391 | #install rules for the generated headers
392 | list(APPEND generated_includes ${expanded_files_h})
393 |
394 | endmacro(GR_EXPAND_X_H)
395 |
396 | macro(GR_EXPAND_X_CC_H component root)
397 |
398 | include(GrPython)
399 |
400 | file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
401 | "#!${PYTHON_EXECUTABLE}
402 |
403 | import sys, os, re
404 | sys.path.append('${GR_RUNTIME_PYTHONPATH}')
405 | os.environ['srcdir'] = '${CMAKE_CURRENT_SOURCE_DIR}'
406 | os.chdir('${CMAKE_CURRENT_BINARY_DIR}')
407 |
408 | if __name__ == '__main__':
409 | import build_utils
410 | root, inp = sys.argv[1:3]
411 | for sig in sys.argv[3:]:
412 | name = re.sub ('X+', sig, root)
413 | d = build_utils.standard_impl_dict2(name, sig, '${component}')
414 | build_utils.expand_template(d, inp)
415 | ")
416 |
417 | #make a list of all the generated files
418 | unset(expanded_files_cc)
419 | unset(expanded_files_h)
420 | foreach(sig ${ARGN})
421 | string(REGEX REPLACE "X+" ${sig} name ${root})
422 | list(APPEND expanded_files_cc ${CMAKE_CURRENT_BINARY_DIR}/${name}.cc)
423 | list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/${name}.h)
424 | endforeach(sig)
425 | unset(name)
426 |
427 | #create a command to generate the source files
428 | add_custom_command(
429 | OUTPUT ${expanded_files_cc}
430 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}.cc.t
431 | COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
432 | ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
433 | ${root} ${root}.cc.t ${ARGN}
434 | )
435 |
436 | #create a command to generate the header files
437 | add_custom_command(
438 | OUTPUT ${expanded_files_h}
439 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}.h.t
440 | COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
441 | ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
442 | ${root} ${root}.h.t ${ARGN}
443 | )
444 |
445 | #make source files depends on headers to force generation
446 | set_source_files_properties(${expanded_files_cc}
447 | PROPERTIES OBJECT_DEPENDS "${expanded_files_h}"
448 | )
449 |
450 | #install rules for the generated files
451 | list(APPEND generated_sources ${expanded_files_cc})
452 | list(APPEND generated_headers ${expanded_files_h})
453 |
454 | endmacro(GR_EXPAND_X_CC_H)
455 |
456 | macro(GR_EXPAND_X_CC_H_IMPL component root)
457 |
458 | include(GrPython)
459 |
460 | file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
461 | "#!${PYTHON_EXECUTABLE}
462 |
463 | import sys, os, re
464 | sys.path.append('${GR_RUNTIME_PYTHONPATH}')
465 | os.environ['srcdir'] = '${CMAKE_CURRENT_SOURCE_DIR}'
466 | os.chdir('${CMAKE_CURRENT_BINARY_DIR}')
467 |
468 | if __name__ == '__main__':
469 | import build_utils
470 | root, inp = sys.argv[1:3]
471 | for sig in sys.argv[3:]:
472 | name = re.sub ('X+', sig, root)
473 | d = build_utils.standard_dict(name, sig, '${component}')
474 | build_utils.expand_template(d, inp, '_impl')
475 | ")
476 |
477 | #make a list of all the generated files
478 | unset(expanded_files_cc_impl)
479 | unset(expanded_files_h_impl)
480 | unset(expanded_files_h)
481 | foreach(sig ${ARGN})
482 | string(REGEX REPLACE "X+" ${sig} name ${root})
483 | list(APPEND expanded_files_cc_impl ${CMAKE_CURRENT_BINARY_DIR}/${name}_impl.cc)
484 | list(APPEND expanded_files_h_impl ${CMAKE_CURRENT_BINARY_DIR}/${name}_impl.h)
485 | list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/../include/gnuradio/${component}/${name}.h)
486 | endforeach(sig)
487 | unset(name)
488 |
489 | #create a command to generate the _impl.cc files
490 | add_custom_command(
491 | OUTPUT ${expanded_files_cc_impl}
492 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}_impl.cc.t
493 | COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
494 | ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
495 | ${root} ${root}_impl.cc.t ${ARGN}
496 | )
497 |
498 | #create a command to generate the _impl.h files
499 | add_custom_command(
500 | OUTPUT ${expanded_files_h_impl}
501 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}_impl.h.t
502 | COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
503 | ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
504 | ${root} ${root}_impl.h.t ${ARGN}
505 | )
506 |
507 | #make _impl.cc source files depend on _impl.h to force generation
508 | set_source_files_properties(${expanded_files_cc_impl}
509 | PROPERTIES OBJECT_DEPENDS "${expanded_files_h_impl}"
510 | )
511 |
512 | #make _impl.h source files depend on headers to force generation
513 | set_source_files_properties(${expanded_files_h_impl}
514 | PROPERTIES OBJECT_DEPENDS "${expanded_files_h}"
515 | )
516 |
517 | #install rules for the generated files
518 | list(APPEND generated_sources ${expanded_files_cc_impl})
519 | list(APPEND generated_headers ${expanded_files_h_impl})
520 |
521 | endmacro(GR_EXPAND_X_CC_H_IMPL)
522 |
--------------------------------------------------------------------------------
/cmake/Modules/GrPlatform.cmake:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2016 Bastille Networks
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 |
16 | if(DEFINED __INCLUDED_GR_PLATFORM_CMAKE)
17 | return()
18 | endif()
19 | set(__INCLUDED_GR_PLATFORM_CMAKE TRUE)
20 |
21 | ########################################################################
22 | # Setup additional defines for OS types
23 | ########################################################################
24 | if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
25 | set(LINUX TRUE)
26 | endif()
27 |
28 | if(NOT CMAKE_CROSSCOMPILING AND LINUX AND EXISTS "/etc/debian_version")
29 | set(DEBIAN TRUE)
30 | endif()
31 |
32 | if(NOT CMAKE_CROSSCOMPILING AND LINUX AND EXISTS "/etc/redhat-release")
33 | set(REDHAT TRUE)
34 | endif()
35 |
36 | if(NOT CMAKE_CROSSCOMPILING AND LINUX AND EXISTS "/etc/slackware-version")
37 | set(SLACKWARE TRUE)
38 | endif()
39 |
40 | ########################################################################
41 | # when the library suffix should be 64 (applies to redhat linux family)
42 | ########################################################################
43 | if (REDHAT OR SLACKWARE)
44 | set(LIB64_CONVENTION TRUE)
45 | endif()
46 |
47 | if(NOT DEFINED LIB_SUFFIX AND LIB64_CONVENTION AND CMAKE_SYSTEM_PROCESSOR MATCHES "64$")
48 | set(LIB_SUFFIX 64)
49 | endif()
50 | set(LIB_SUFFIX ${LIB_SUFFIX} CACHE STRING "lib directory suffix")
51 |
--------------------------------------------------------------------------------
/cmake/Modules/GrPython.cmake:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2016 Bastille Networks
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 |
16 | if(DEFINED __INCLUDED_GR_PYTHON_CMAKE)
17 | return()
18 | endif()
19 | set(__INCLUDED_GR_PYTHON_CMAKE TRUE)
20 |
21 | ########################################################################
22 | # Setup the python interpreter:
23 | # This allows the user to specify a specific interpreter,
24 | # or finds the interpreter via the built-in cmake module.
25 | ########################################################################
26 | #this allows the user to override PYTHON_EXECUTABLE
27 | if(PYTHON_EXECUTABLE)
28 |
29 | set(PYTHONINTERP_FOUND TRUE)
30 |
31 | #otherwise if not set, try to automatically find it
32 | else(PYTHON_EXECUTABLE)
33 |
34 | #use the built-in find script
35 | find_package(PythonInterp 2)
36 |
37 | #and if that fails use the find program routine
38 | if(NOT PYTHONINTERP_FOUND)
39 | find_program(PYTHON_EXECUTABLE NAMES python python2 python2.7 python2.6 python2.5)
40 | if(PYTHON_EXECUTABLE)
41 | set(PYTHONINTERP_FOUND TRUE)
42 | endif(PYTHON_EXECUTABLE)
43 | endif(NOT PYTHONINTERP_FOUND)
44 |
45 | endif(PYTHON_EXECUTABLE)
46 |
47 | if (CMAKE_CROSSCOMPILING)
48 | set(QA_PYTHON_EXECUTABLE "/usr/bin/python")
49 | else (CMAKE_CROSSCOMPILING)
50 | set(QA_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE})
51 | endif(CMAKE_CROSSCOMPILING)
52 |
53 | #make the path to the executable appear in the cmake gui
54 | set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter")
55 | set(QA_PYTHON_EXECUTABLE ${QA_PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter for QA tests")
56 |
57 | #make sure we can use -B with python (introduced in 2.6)
58 | if(PYTHON_EXECUTABLE)
59 | execute_process(
60 | COMMAND ${PYTHON_EXECUTABLE} -B -c ""
61 | OUTPUT_QUIET ERROR_QUIET
62 | RESULT_VARIABLE PYTHON_HAS_DASH_B_RESULT
63 | )
64 | if(PYTHON_HAS_DASH_B_RESULT EQUAL 0)
65 | set(PYTHON_DASH_B "-B")
66 | endif()
67 | endif(PYTHON_EXECUTABLE)
68 |
69 | ########################################################################
70 | # Check for the existence of a python module:
71 | # - desc a string description of the check
72 | # - mod the name of the module to import
73 | # - cmd an additional command to run
74 | # - have the result variable to set
75 | ########################################################################
76 | macro(GR_PYTHON_CHECK_MODULE desc mod cmd have)
77 | message(STATUS "")
78 | message(STATUS "Python checking for ${desc}")
79 | execute_process(
80 | COMMAND ${PYTHON_EXECUTABLE} -c "
81 | #########################################
82 | try:
83 | import ${mod}
84 | assert ${cmd}
85 | except ImportError, AssertionError: exit(-1)
86 | except: pass
87 | #########################################"
88 | RESULT_VARIABLE ${have}
89 | )
90 | if(${have} EQUAL 0)
91 | message(STATUS "Python checking for ${desc} - found")
92 | set(${have} TRUE)
93 | else(${have} EQUAL 0)
94 | message(STATUS "Python checking for ${desc} - not found")
95 | set(${have} FALSE)
96 | endif(${have} EQUAL 0)
97 | endmacro(GR_PYTHON_CHECK_MODULE)
98 |
99 | ########################################################################
100 | # Sets the python installation directory GR_PYTHON_DIR
101 | ########################################################################
102 | if(NOT DEFINED GR_PYTHON_DIR)
103 | execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "
104 | from distutils import sysconfig
105 | print sysconfig.get_python_lib(plat_specific=True, prefix='')
106 | " OUTPUT_VARIABLE GR_PYTHON_DIR OUTPUT_STRIP_TRAILING_WHITESPACE
107 | )
108 | endif()
109 | file(TO_CMAKE_PATH ${GR_PYTHON_DIR} GR_PYTHON_DIR)
110 |
111 | ########################################################################
112 | # Create an always-built target with a unique name
113 | # Usage: GR_UNIQUE_TARGET( )
114 | ########################################################################
115 | function(GR_UNIQUE_TARGET desc)
116 | file(RELATIVE_PATH reldir ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR})
117 | execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import re, hashlib
118 | unique = hashlib.md5('${reldir}${ARGN}').hexdigest()[:5]
119 | print(re.sub('\\W', '_', '${desc} ${reldir} ' + unique))"
120 | OUTPUT_VARIABLE _target OUTPUT_STRIP_TRAILING_WHITESPACE)
121 | add_custom_target(${_target} ALL DEPENDS ${ARGN})
122 | endfunction(GR_UNIQUE_TARGET)
123 |
124 | ########################################################################
125 | # Install python sources (also builds and installs byte-compiled python)
126 | ########################################################################
127 | function(GR_PYTHON_INSTALL)
128 | include(CMakeParseArgumentsCopy)
129 | CMAKE_PARSE_ARGUMENTS(GR_PYTHON_INSTALL "" "DESTINATION;COMPONENT" "FILES;PROGRAMS" ${ARGN})
130 |
131 | ####################################################################
132 | if(GR_PYTHON_INSTALL_FILES)
133 | ####################################################################
134 | install(${ARGN}) #installs regular python files
135 |
136 | #create a list of all generated files
137 | unset(pysrcfiles)
138 | unset(pycfiles)
139 | unset(pyofiles)
140 | foreach(pyfile ${GR_PYTHON_INSTALL_FILES})
141 | get_filename_component(pyfile ${pyfile} ABSOLUTE)
142 | list(APPEND pysrcfiles ${pyfile})
143 |
144 | #determine if this file is in the source or binary directory
145 | file(RELATIVE_PATH source_rel_path ${CMAKE_CURRENT_SOURCE_DIR} ${pyfile})
146 | string(LENGTH "${source_rel_path}" source_rel_path_len)
147 | file(RELATIVE_PATH binary_rel_path ${CMAKE_CURRENT_BINARY_DIR} ${pyfile})
148 | string(LENGTH "${binary_rel_path}" binary_rel_path_len)
149 |
150 | #and set the generated path appropriately
151 | if(${source_rel_path_len} GREATER ${binary_rel_path_len})
152 | set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${binary_rel_path})
153 | else()
154 | set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${source_rel_path})
155 | endif()
156 | list(APPEND pycfiles ${pygenfile}c)
157 | list(APPEND pyofiles ${pygenfile}o)
158 |
159 | #ensure generation path exists
160 | get_filename_component(pygen_path ${pygenfile} PATH)
161 | file(MAKE_DIRECTORY ${pygen_path})
162 |
163 | endforeach(pyfile)
164 |
165 | #the command to generate the pyc files
166 | add_custom_command(
167 | DEPENDS ${pysrcfiles} OUTPUT ${pycfiles}
168 | COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pycfiles}
169 | )
170 |
171 | #the command to generate the pyo files
172 | add_custom_command(
173 | DEPENDS ${pysrcfiles} OUTPUT ${pyofiles}
174 | COMMAND ${PYTHON_EXECUTABLE} -O ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pyofiles}
175 | )
176 |
177 | #create install rule and add generated files to target list
178 | set(python_install_gen_targets ${pycfiles} ${pyofiles})
179 | install(FILES ${python_install_gen_targets}
180 | DESTINATION ${GR_PYTHON_INSTALL_DESTINATION}
181 | COMPONENT ${GR_PYTHON_INSTALL_COMPONENT}
182 | )
183 |
184 | ####################################################################
185 | elseif(GR_PYTHON_INSTALL_PROGRAMS)
186 | ####################################################################
187 | file(TO_NATIVE_PATH ${PYTHON_EXECUTABLE} pyexe_native)
188 |
189 | if (CMAKE_CROSSCOMPILING)
190 | set(pyexe_native "/usr/bin/env python")
191 | endif()
192 |
193 | foreach(pyfile ${GR_PYTHON_INSTALL_PROGRAMS})
194 | get_filename_component(pyfile_name ${pyfile} NAME)
195 | get_filename_component(pyfile ${pyfile} ABSOLUTE)
196 | string(REPLACE "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" pyexefile "${pyfile}.exe")
197 | list(APPEND python_install_gen_targets ${pyexefile})
198 |
199 | get_filename_component(pyexefile_path ${pyexefile} PATH)
200 | file(MAKE_DIRECTORY ${pyexefile_path})
201 |
202 | add_custom_command(
203 | OUTPUT ${pyexefile} DEPENDS ${pyfile}
204 | COMMAND ${PYTHON_EXECUTABLE} -c
205 | "import re; R=re.compile('^\#!.*$\\n',flags=re.MULTILINE); open('${pyexefile}','w').write('\#!${pyexe_native}\\n'+R.sub('',open('${pyfile}','r').read()))"
206 | COMMENT "Shebangin ${pyfile_name}"
207 | VERBATIM
208 | )
209 |
210 | #on windows, python files need an extension to execute
211 | get_filename_component(pyfile_ext ${pyfile} EXT)
212 | if(WIN32 AND NOT pyfile_ext)
213 | set(pyfile_name "${pyfile_name}.py")
214 | endif()
215 |
216 | install(PROGRAMS ${pyexefile} RENAME ${pyfile_name}
217 | DESTINATION ${GR_PYTHON_INSTALL_DESTINATION}
218 | COMPONENT ${GR_PYTHON_INSTALL_COMPONENT}
219 | )
220 | endforeach(pyfile)
221 |
222 | endif()
223 |
224 | GR_UNIQUE_TARGET("pygen" ${python_install_gen_targets})
225 |
226 | endfunction(GR_PYTHON_INSTALL)
227 |
228 | ########################################################################
229 | # Write the python helper script that generates byte code files
230 | ########################################################################
231 | file(WRITE ${CMAKE_BINARY_DIR}/python_compile_helper.py "
232 | import sys, py_compile
233 | files = sys.argv[1:]
234 | srcs, gens = files[:len(files)/2], files[len(files)/2:]
235 | for src, gen in zip(srcs, gens):
236 | py_compile.compile(file=src, cfile=gen, doraise=True)
237 | ")
238 |
--------------------------------------------------------------------------------
/cmake/Modules/GrSwig.cmake:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2016 Bastille Networks
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 |
16 | if(DEFINED __INCLUDED_GR_SWIG_CMAKE)
17 | return()
18 | endif()
19 | set(__INCLUDED_GR_SWIG_CMAKE TRUE)
20 |
21 | include(GrPython)
22 |
23 | ########################################################################
24 | # Builds a swig documentation file to be generated into python docstrings
25 | # Usage: GR_SWIG_MAKE_DOCS(output_file input_path input_path....)
26 | #
27 | # Set the following variable to specify extra dependent targets:
28 | # - GR_SWIG_DOCS_SOURCE_DEPS
29 | # - GR_SWIG_DOCS_TARGET_DEPS
30 | ########################################################################
31 | function(GR_SWIG_MAKE_DOCS output_file)
32 | if(ENABLE_DOXYGEN)
33 |
34 | #setup the input files variable list, quote formated
35 | set(input_files)
36 | unset(INPUT_PATHS)
37 | foreach(input_path ${ARGN})
38 | if(IS_DIRECTORY ${input_path}) #when input path is a directory
39 | file(GLOB input_path_h_files ${input_path}/*.h)
40 | else() #otherwise its just a file, no glob
41 | set(input_path_h_files ${input_path})
42 | endif()
43 | list(APPEND input_files ${input_path_h_files})
44 | set(INPUT_PATHS "${INPUT_PATHS} \"${input_path}\"")
45 | endforeach(input_path)
46 |
47 | #determine the output directory
48 | get_filename_component(name ${output_file} NAME_WE)
49 | get_filename_component(OUTPUT_DIRECTORY ${output_file} PATH)
50 | set(OUTPUT_DIRECTORY ${OUTPUT_DIRECTORY}/${name}_swig_docs)
51 | make_directory(${OUTPUT_DIRECTORY})
52 |
53 | #generate the Doxyfile used by doxygen
54 | configure_file(
55 | ${CMAKE_SOURCE_DIR}/docs/doxygen/Doxyfile.swig_doc.in
56 | ${OUTPUT_DIRECTORY}/Doxyfile
57 | @ONLY)
58 |
59 | #Create a dummy custom command that depends on other targets
60 | include(GrMiscUtils)
61 | GR_GEN_TARGET_DEPS(_${name}_tag tag_deps ${GR_SWIG_DOCS_TARGET_DEPS})
62 |
63 | #call doxygen on the Doxyfile + input headers
64 | add_custom_command(
65 | OUTPUT ${OUTPUT_DIRECTORY}/xml/index.xml
66 | DEPENDS ${input_files} ${GR_SWIG_DOCS_SOURCE_DEPS} ${tag_deps}
67 | COMMAND ${DOXYGEN_EXECUTABLE} ${OUTPUT_DIRECTORY}/Doxyfile
68 | COMMENT "Generating doxygen xml for ${name} docs"
69 | )
70 |
71 | #call the swig_doc script on the xml files
72 | add_custom_command(
73 | OUTPUT ${output_file}
74 | DEPENDS ${input_files} ${stamp-file} ${OUTPUT_DIRECTORY}/xml/index.xml
75 | COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
76 | ${CMAKE_SOURCE_DIR}/docs/doxygen/swig_doc.py
77 | ${OUTPUT_DIRECTORY}/xml
78 | ${output_file}
79 | COMMENT "Generating python docstrings for ${name}"
80 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/docs/doxygen
81 | )
82 |
83 | else(ENABLE_DOXYGEN)
84 | file(WRITE ${output_file} "\n") #no doxygen -> empty file
85 | endif(ENABLE_DOXYGEN)
86 | endfunction(GR_SWIG_MAKE_DOCS)
87 |
88 | ########################################################################
89 | # Build a swig target for the common gnuradio use case. Usage:
90 | # GR_SWIG_MAKE(target ifile ifile ifile...)
91 | #
92 | # Set the following variables before calling:
93 | # - GR_SWIG_FLAGS
94 | # - GR_SWIG_INCLUDE_DIRS
95 | # - GR_SWIG_LIBRARIES
96 | # - GR_SWIG_SOURCE_DEPS
97 | # - GR_SWIG_TARGET_DEPS
98 | # - GR_SWIG_DOC_FILE
99 | # - GR_SWIG_DOC_DIRS
100 | ########################################################################
101 | macro(GR_SWIG_MAKE name)
102 | set(ifiles ${ARGN})
103 |
104 | # Shimming this in here to take care of a SWIG bug with handling
105 | # vector and vector (on 32-bit machines) and
106 | # vector (on 64-bit machines). Use this to test
107 | # the size of size_t, then set SIZE_T_32 if it's a 32-bit machine
108 | # or not if it's 64-bit. The logic in gr_type.i handles the rest.
109 | INCLUDE(CheckTypeSize)
110 | CHECK_TYPE_SIZE("size_t" SIZEOF_SIZE_T)
111 | CHECK_TYPE_SIZE("unsigned int" SIZEOF_UINT)
112 | if(${SIZEOF_SIZE_T} EQUAL ${SIZEOF_UINT})
113 | list(APPEND GR_SWIG_FLAGS -DSIZE_T_32)
114 | endif(${SIZEOF_SIZE_T} EQUAL ${SIZEOF_UINT})
115 |
116 | #do swig doc generation if specified
117 | if(GR_SWIG_DOC_FILE)
118 | set(GR_SWIG_DOCS_SOURCE_DEPS ${GR_SWIG_SOURCE_DEPS})
119 | list(APPEND GR_SWIG_DOCS_TARGET_DEPS ${GR_SWIG_TARGET_DEPS})
120 | GR_SWIG_MAKE_DOCS(${GR_SWIG_DOC_FILE} ${GR_SWIG_DOC_DIRS})
121 | add_custom_target(${name}_swig_doc DEPENDS ${GR_SWIG_DOC_FILE})
122 | list(APPEND GR_SWIG_TARGET_DEPS ${name}_swig_doc ${GR_RUNTIME_SWIG_DOC_FILE})
123 | endif()
124 |
125 | #append additional include directories
126 | find_package(PythonLibs 2)
127 | list(APPEND GR_SWIG_INCLUDE_DIRS ${PYTHON_INCLUDE_PATH}) #deprecated name (now dirs)
128 | list(APPEND GR_SWIG_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS})
129 |
130 | #prepend local swig directories
131 | list(INSERT GR_SWIG_INCLUDE_DIRS 0 ${CMAKE_CURRENT_SOURCE_DIR})
132 | list(INSERT GR_SWIG_INCLUDE_DIRS 0 ${CMAKE_CURRENT_BINARY_DIR})
133 |
134 | #determine include dependencies for swig file
135 | execute_process(
136 | COMMAND ${PYTHON_EXECUTABLE}
137 | ${CMAKE_BINARY_DIR}/get_swig_deps.py
138 | "${ifiles}" "${GR_SWIG_INCLUDE_DIRS}"
139 | OUTPUT_STRIP_TRAILING_WHITESPACE
140 | OUTPUT_VARIABLE SWIG_MODULE_${name}_EXTRA_DEPS
141 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
142 | )
143 |
144 | #Create a dummy custom command that depends on other targets
145 | include(GrMiscUtils)
146 | GR_GEN_TARGET_DEPS(_${name}_swig_tag tag_deps ${GR_SWIG_TARGET_DEPS})
147 | set(tag_file ${CMAKE_CURRENT_BINARY_DIR}/${name}.tag)
148 | add_custom_command(
149 | OUTPUT ${tag_file}
150 | DEPENDS ${GR_SWIG_SOURCE_DEPS} ${tag_deps}
151 | COMMAND ${CMAKE_COMMAND} -E touch ${tag_file}
152 | )
153 |
154 | #append the specified include directories
155 | include_directories(${GR_SWIG_INCLUDE_DIRS})
156 | list(APPEND SWIG_MODULE_${name}_EXTRA_DEPS ${tag_file})
157 |
158 | #setup the swig flags with flags and include directories
159 | set(CMAKE_SWIG_FLAGS -fvirtual -modern -keyword -w511 -module ${name} ${GR_SWIG_FLAGS})
160 | foreach(dir ${GR_SWIG_INCLUDE_DIRS})
161 | list(APPEND CMAKE_SWIG_FLAGS "-I${dir}")
162 | endforeach(dir)
163 |
164 | #set the C++ property on the swig .i file so it builds
165 | set_source_files_properties(${ifiles} PROPERTIES CPLUSPLUS ON)
166 |
167 | #setup the actual swig library target to be built
168 | include(UseSWIG)
169 | SWIG_ADD_MODULE(${name} python ${ifiles})
170 | SWIG_LINK_LIBRARIES(${name} ${PYTHON_LIBRARIES} ${GR_SWIG_LIBRARIES})
171 | if(${name} STREQUAL "runtime_swig")
172 | SET_TARGET_PROPERTIES(${SWIG_MODULE_runtime_swig_REAL_NAME} PROPERTIES DEFINE_SYMBOL "gnuradio_runtime_EXPORTS")
173 | endif(${name} STREQUAL "runtime_swig")
174 |
175 | endmacro(GR_SWIG_MAKE)
176 |
177 | ########################################################################
178 | # Install swig targets generated by GR_SWIG_MAKE. Usage:
179 | # GR_SWIG_INSTALL(
180 | # TARGETS target target target...
181 | # [DESTINATION destination]
182 | # [COMPONENT component]
183 | # )
184 | ########################################################################
185 | macro(GR_SWIG_INSTALL)
186 |
187 | include(CMakeParseArgumentsCopy)
188 | CMAKE_PARSE_ARGUMENTS(GR_SWIG_INSTALL "" "DESTINATION;COMPONENT" "TARGETS" ${ARGN})
189 |
190 | foreach(name ${GR_SWIG_INSTALL_TARGETS})
191 | install(TARGETS ${SWIG_MODULE_${name}_REAL_NAME}
192 | DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
193 | COMPONENT ${GR_SWIG_INSTALL_COMPONENT}
194 | )
195 |
196 | include(GrPython)
197 | GR_PYTHON_INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}.py
198 | DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
199 | COMPONENT ${GR_SWIG_INSTALL_COMPONENT}
200 | )
201 |
202 | GR_LIBTOOL(
203 | TARGET ${SWIG_MODULE_${name}_REAL_NAME}
204 | DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
205 | )
206 |
207 | endforeach(name)
208 |
209 | endmacro(GR_SWIG_INSTALL)
210 |
211 | ########################################################################
212 | # Generate a python file that can determine swig dependencies.
213 | # Used by the make macro above to determine extra dependencies.
214 | # When you build C++, CMake figures out the header dependencies.
215 | # This code essentially performs that logic for swig includes.
216 | ########################################################################
217 | file(WRITE ${CMAKE_BINARY_DIR}/get_swig_deps.py "
218 |
219 | import os, sys, re
220 |
221 | i_include_matcher = re.compile('%(include|import)\\s*[<|\"](.*)[>|\"]')
222 | h_include_matcher = re.compile('#(include)\\s*[<|\"](.*)[>|\"]')
223 | include_dirs = sys.argv[2].split(';')
224 |
225 | def get_swig_incs(file_path):
226 | if file_path.endswith('.i'): matcher = i_include_matcher
227 | else: matcher = h_include_matcher
228 | file_contents = open(file_path, 'r').read()
229 | return matcher.findall(file_contents, re.MULTILINE)
230 |
231 | def get_swig_deps(file_path, level):
232 | deps = [file_path]
233 | if level == 0: return deps
234 | for keyword, inc_file in get_swig_incs(file_path):
235 | for inc_dir in include_dirs:
236 | inc_path = os.path.join(inc_dir, inc_file)
237 | if not os.path.exists(inc_path): continue
238 | deps.extend(get_swig_deps(inc_path, level-1))
239 | break #found, we dont search in lower prio inc dirs
240 | return deps
241 |
242 | if __name__ == '__main__':
243 | ifiles = sys.argv[1].split(';')
244 | deps = sum([get_swig_deps(ifile, 3) for ifile in ifiles], [])
245 | #sys.stderr.write(';'.join(set(deps)) + '\\n\\n')
246 | print(';'.join(set(deps)))
247 | ")
248 |
--------------------------------------------------------------------------------
/cmake/Modules/GrTest.cmake:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2016 Bastille Networks
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 |
16 | if(DEFINED __INCLUDED_GR_TEST_CMAKE)
17 | return()
18 | endif()
19 | set(__INCLUDED_GR_TEST_CMAKE TRUE)
20 |
21 | ########################################################################
22 | # Add a unit test and setup the environment for a unit test.
23 | # Takes the same arguments as the ADD_TEST function.
24 | #
25 | # Before calling set the following variables:
26 | # GR_TEST_TARGET_DEPS - built targets for the library path
27 | # GR_TEST_LIBRARY_DIRS - directories for the library path
28 | # GR_TEST_PYTHON_DIRS - directories for the python path
29 | # GR_TEST_ENVIRONS - other environment key/value pairs
30 | ########################################################################
31 | function(GR_ADD_TEST test_name)
32 |
33 | #Ensure that the build exe also appears in the PATH.
34 | list(APPEND GR_TEST_TARGET_DEPS ${ARGN})
35 |
36 | #In the land of windows, all libraries must be in the PATH.
37 | #Since the dependent libraries are not yet installed,
38 | #we must manually set them in the PATH to run tests.
39 | #The following appends the path of a target dependency.
40 | foreach(target ${GR_TEST_TARGET_DEPS})
41 | get_target_property(location ${target} LOCATION)
42 | if(location)
43 | get_filename_component(path ${location} PATH)
44 | string(REGEX REPLACE "\\$\\(.*\\)" ${CMAKE_BUILD_TYPE} path ${path})
45 | list(APPEND GR_TEST_LIBRARY_DIRS ${path})
46 | endif(location)
47 | endforeach(target)
48 |
49 | if(WIN32)
50 | #SWIG generates the python library files into a subdirectory.
51 | #Therefore, we must append this subdirectory into PYTHONPATH.
52 | #Only do this for the python directories matching the following:
53 | foreach(pydir ${GR_TEST_PYTHON_DIRS})
54 | get_filename_component(name ${pydir} NAME)
55 | if(name MATCHES "^(swig|lib|src)$")
56 | list(APPEND GR_TEST_PYTHON_DIRS ${pydir}/${CMAKE_BUILD_TYPE})
57 | endif()
58 | endforeach(pydir)
59 | endif(WIN32)
60 |
61 | file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} srcdir)
62 | file(TO_NATIVE_PATH "${GR_TEST_LIBRARY_DIRS}" libpath) #ok to use on dir list?
63 | file(TO_NATIVE_PATH "${GR_TEST_PYTHON_DIRS}" pypath) #ok to use on dir list?
64 |
65 | set(environs "VOLK_GENERIC=1" "GR_DONT_LOAD_PREFS=1" "srcdir=${srcdir}")
66 | list(APPEND environs ${GR_TEST_ENVIRONS})
67 |
68 | #http://www.cmake.org/pipermail/cmake/2009-May/029464.html
69 | #Replaced this add test + set environs code with the shell script generation.
70 | #Its nicer to be able to manually run the shell script to diagnose problems.
71 | #ADD_TEST(${ARGV})
72 | #SET_TESTS_PROPERTIES(${test_name} PROPERTIES ENVIRONMENT "${environs}")
73 |
74 | if(UNIX)
75 | set(LD_PATH_VAR "LD_LIBRARY_PATH")
76 | if(APPLE)
77 | set(LD_PATH_VAR "DYLD_LIBRARY_PATH")
78 | endif()
79 |
80 | set(binpath "${CMAKE_CURRENT_BINARY_DIR}:$PATH")
81 | list(APPEND libpath "$${LD_PATH_VAR}")
82 | list(APPEND pypath "$PYTHONPATH")
83 |
84 | #replace list separator with the path separator
85 | string(REPLACE ";" ":" libpath "${libpath}")
86 | string(REPLACE ";" ":" pypath "${pypath}")
87 | list(APPEND environs "PATH=${binpath}" "${LD_PATH_VAR}=${libpath}" "PYTHONPATH=${pypath}")
88 |
89 | #generate a bat file that sets the environment and runs the test
90 | if (CMAKE_CROSSCOMPILING)
91 | set(SHELL "/bin/sh")
92 | else(CMAKE_CROSSCOMPILING)
93 | find_program(SHELL sh)
94 | endif(CMAKE_CROSSCOMPILING)
95 | set(sh_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.sh)
96 | file(WRITE ${sh_file} "#!${SHELL}\n")
97 | #each line sets an environment variable
98 | foreach(environ ${environs})
99 | file(APPEND ${sh_file} "export ${environ}\n")
100 | endforeach(environ)
101 | #load the command to run with its arguments
102 | foreach(arg ${ARGN})
103 | file(APPEND ${sh_file} "${arg} ")
104 | endforeach(arg)
105 | file(APPEND ${sh_file} "\n")
106 |
107 | #make the shell file executable
108 | execute_process(COMMAND chmod +x ${sh_file})
109 |
110 | add_test(${test_name} ${SHELL} ${sh_file})
111 |
112 | endif(UNIX)
113 |
114 | if(WIN32)
115 | list(APPEND libpath ${DLL_PATHS} "%PATH%")
116 | list(APPEND pypath "%PYTHONPATH%")
117 |
118 | #replace list separator with the path separator (escaped)
119 | string(REPLACE ";" "\\;" libpath "${libpath}")
120 | string(REPLACE ";" "\\;" pypath "${pypath}")
121 | list(APPEND environs "PATH=${libpath}" "PYTHONPATH=${pypath}")
122 |
123 | #generate a bat file that sets the environment and runs the test
124 | set(bat_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.bat)
125 | file(WRITE ${bat_file} "@echo off\n")
126 | #each line sets an environment variable
127 | foreach(environ ${environs})
128 | file(APPEND ${bat_file} "SET ${environ}\n")
129 | endforeach(environ)
130 | #load the command to run with its arguments
131 | foreach(arg ${ARGN})
132 | file(APPEND ${bat_file} "${arg} ")
133 | endforeach(arg)
134 | file(APPEND ${bat_file} "\n")
135 |
136 | add_test(${test_name} ${bat_file})
137 | endif(WIN32)
138 |
139 | endfunction(GR_ADD_TEST)
140 |
--------------------------------------------------------------------------------
/cmake/Modules/UseSWIG.cmake:
--------------------------------------------------------------------------------
1 | # - SWIG module for CMake
2 | # Defines the following macros:
3 | # SWIG_ADD_MODULE(name language [ files ])
4 | # - Define swig module with given name and specified language
5 | # SWIG_LINK_LIBRARIES(name [ libraries ])
6 | # - Link libraries to swig module
7 | # All other macros are for internal use only.
8 | # To get the actual name of the swig module,
9 | # use: ${SWIG_MODULE_${name}_REAL_NAME}.
10 | # Set Source files properties such as CPLUSPLUS and SWIG_FLAGS to specify
11 | # special behavior of SWIG. Also global CMAKE_SWIG_FLAGS can be used to add
12 | # special flags to all swig calls.
13 | # Another special variable is CMAKE_SWIG_OUTDIR, it allows one to specify
14 | # where to write all the swig generated module (swig -outdir option)
15 | # The name-specific variable SWIG_MODULE__EXTRA_DEPS may be used
16 | # to specify extra dependencies for the generated modules.
17 | # If the source file generated by swig need some special flag you can use
18 | # set_source_files_properties( ${swig_generated_file_fullname}
19 | # PROPERTIES COMPILE_FLAGS "-bla")
20 |
21 |
22 | #=============================================================================
23 | # Copyright 2004-2009 Kitware, Inc.
24 | # Copyright 2009 Mathieu Malaterre
25 | #
26 | # Distributed under the OSI-approved BSD License (the "License");
27 | # see accompanying file Copyright.txt for details.
28 | #
29 | # This software is distributed WITHOUT ANY WARRANTY; without even the
30 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
31 | # See the License for more information.
32 | #=============================================================================
33 | # (To distribute this file outside of CMake, substitute the full
34 | # License text for the above reference.)
35 |
36 | set(SWIG_CXX_EXTENSION "cxx")
37 | set(SWIG_EXTRA_LIBRARIES "")
38 |
39 | set(SWIG_PYTHON_EXTRA_FILE_EXTENSION "py")
40 |
41 | #
42 | # For given swig module initialize variables associated with it
43 | #
44 | macro(SWIG_MODULE_INITIALIZE name language)
45 | string(TOUPPER "${language}" swig_uppercase_language)
46 | string(TOLOWER "${language}" swig_lowercase_language)
47 | set(SWIG_MODULE_${name}_LANGUAGE "${swig_uppercase_language}")
48 | set(SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG "${swig_lowercase_language}")
49 |
50 | set(SWIG_MODULE_${name}_REAL_NAME "${name}")
51 | if("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "UNKNOWN")
52 | message(FATAL_ERROR "SWIG Error: Language \"${language}\" not found")
53 | elseif("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "PYTHON")
54 | # when swig is used without the -interface it will produce in the module.py
55 | # a 'import _modulename' statement, which implies having a corresponding
56 | # _modulename.so (*NIX), _modulename.pyd (Win32).
57 | set(SWIG_MODULE_${name}_REAL_NAME "_${name}")
58 | elseif("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "PERL")
59 | set(SWIG_MODULE_${name}_EXTRA_FLAGS "-shadow")
60 | endif()
61 | endmacro()
62 |
63 | #
64 | # For a given language, input file, and output file, determine extra files that
65 | # will be generated. This is internal swig macro.
66 | #
67 |
68 | macro(SWIG_GET_EXTRA_OUTPUT_FILES language outfiles generatedpath infile)
69 | set(${outfiles} "")
70 | get_source_file_property(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename
71 | ${infile} SWIG_MODULE_NAME)
72 | if(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename STREQUAL "NOTFOUND")
73 | get_filename_component(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename "${infile}" NAME_WE)
74 | endif()
75 | foreach(it ${SWIG_${language}_EXTRA_FILE_EXTENSION})
76 | set(${outfiles} ${${outfiles}}
77 | "${generatedpath}/${SWIG_GET_EXTRA_OUTPUT_FILES_module_basename}.${it}")
78 | endforeach()
79 | endmacro()
80 |
81 | #
82 | # Take swig (*.i) file and add proper custom commands for it
83 | #
84 | macro(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
85 | set(swig_full_infile ${infile})
86 | get_filename_component(swig_source_file_path "${infile}" PATH)
87 | get_filename_component(swig_source_file_name_we "${infile}" NAME_WE)
88 | get_source_file_property(swig_source_file_generated ${infile} GENERATED)
89 | get_source_file_property(swig_source_file_cplusplus ${infile} CPLUSPLUS)
90 | get_source_file_property(swig_source_file_flags ${infile} SWIG_FLAGS)
91 | if("${swig_source_file_flags}" STREQUAL "NOTFOUND")
92 | set(swig_source_file_flags "")
93 | endif()
94 | set(swig_source_file_fullname "${infile}")
95 | if(${swig_source_file_path} MATCHES "^${CMAKE_CURRENT_SOURCE_DIR}")
96 | string(REGEX REPLACE
97 | "^${CMAKE_CURRENT_SOURCE_DIR}" ""
98 | swig_source_file_relative_path
99 | "${swig_source_file_path}")
100 | else()
101 | if(${swig_source_file_path} MATCHES "^${CMAKE_CURRENT_BINARY_DIR}")
102 | string(REGEX REPLACE
103 | "^${CMAKE_CURRENT_BINARY_DIR}" ""
104 | swig_source_file_relative_path
105 | "${swig_source_file_path}")
106 | set(swig_source_file_generated 1)
107 | else()
108 | set(swig_source_file_relative_path "${swig_source_file_path}")
109 | if(swig_source_file_generated)
110 | set(swig_source_file_fullname "${CMAKE_CURRENT_BINARY_DIR}/${infile}")
111 | else()
112 | set(swig_source_file_fullname "${CMAKE_CURRENT_SOURCE_DIR}/${infile}")
113 | endif()
114 | endif()
115 | endif()
116 |
117 | set(swig_generated_file_fullname
118 | "${CMAKE_CURRENT_BINARY_DIR}")
119 | if(swig_source_file_relative_path)
120 | set(swig_generated_file_fullname
121 | "${swig_generated_file_fullname}/${swig_source_file_relative_path}")
122 | endif()
123 | # If CMAKE_SWIG_OUTDIR was specified then pass it to -outdir
124 | if(CMAKE_SWIG_OUTDIR)
125 | set(swig_outdir ${CMAKE_SWIG_OUTDIR})
126 | else()
127 | set(swig_outdir ${CMAKE_CURRENT_BINARY_DIR})
128 | endif()
129 | SWIG_GET_EXTRA_OUTPUT_FILES(${SWIG_MODULE_${name}_LANGUAGE}
130 | swig_extra_generated_files
131 | "${swig_outdir}"
132 | "${infile}")
133 | set(swig_generated_file_fullname
134 | "${swig_generated_file_fullname}/${swig_source_file_name_we}")
135 | # add the language into the name of the file (i.e. TCL_wrap)
136 | # this allows for the same .i file to be wrapped into different languages
137 | set(swig_generated_file_fullname
138 | "${swig_generated_file_fullname}${SWIG_MODULE_${name}_LANGUAGE}_wrap")
139 |
140 | if(swig_source_file_cplusplus)
141 | set(swig_generated_file_fullname
142 | "${swig_generated_file_fullname}.${SWIG_CXX_EXTENSION}")
143 | else()
144 | set(swig_generated_file_fullname
145 | "${swig_generated_file_fullname}.c")
146 | endif()
147 |
148 | # Shut up some warnings from poor SWIG code generation that we
149 | # can do nothing about, when this flag is available
150 | include(CheckCXXCompilerFlag)
151 | check_cxx_compiler_flag("-Wno-unused-but-set-variable" HAVE_WNO_UNUSED_BUT_SET_VARIABLE)
152 | if(HAVE_WNO_UNUSED_BUT_SET_VARIABLE)
153 | set_source_files_properties(${swig_generated_file_fullname}
154 | PROPERTIES COMPILE_FLAGS "-Wno-unused-but-set-variable")
155 | endif(HAVE_WNO_UNUSED_BUT_SET_VARIABLE)
156 |
157 | get_directory_property(cmake_include_directories INCLUDE_DIRECTORIES)
158 | set(swig_include_dirs)
159 | foreach(it ${cmake_include_directories})
160 | set(swig_include_dirs ${swig_include_dirs} "-I${it}")
161 | endforeach()
162 |
163 | set(swig_special_flags)
164 | # default is c, so add c++ flag if it is c++
165 | if(swig_source_file_cplusplus)
166 | set(swig_special_flags ${swig_special_flags} "-c++")
167 | endif()
168 | set(swig_extra_flags)
169 | if(SWIG_MODULE_${name}_EXTRA_FLAGS)
170 | set(swig_extra_flags ${swig_extra_flags} ${SWIG_MODULE_${name}_EXTRA_FLAGS})
171 | endif()
172 |
173 | # hack to work around CMake bug in add_custom_command with multiple OUTPUT files
174 |
175 | file(RELATIVE_PATH reldir ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR})
176 | execute_process(
177 | COMMAND ${PYTHON_EXECUTABLE} -c "import re, hashlib
178 | unique = hashlib.md5('${reldir}${ARGN}').hexdigest()[:5]
179 | print(re.sub('\\W', '_', '${name} ${reldir} ' + unique))"
180 | OUTPUT_VARIABLE _target OUTPUT_STRIP_TRAILING_WHITESPACE
181 | )
182 |
183 | file(
184 | WRITE ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp.in
185 | "int main(void){return 0;}\n"
186 | )
187 |
188 | # create dummy dependencies
189 | add_custom_command(
190 | OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp
191 | COMMAND ${CMAKE_COMMAND} -E copy
192 | ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp.in
193 | ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp
194 | DEPENDS "${swig_source_file_fullname}" ${SWIG_MODULE_${name}_EXTRA_DEPS}
195 | COMMENT ""
196 | )
197 |
198 | # create the dummy target
199 | add_executable(${_target} ${CMAKE_CURRENT_BINARY_DIR}/${_target}.cpp)
200 |
201 | # add a custom command to the dummy target
202 | add_custom_command(
203 | TARGET ${_target}
204 | # Let's create the ${swig_outdir} at execution time, in case dir contains $(OutDir)
205 | COMMAND ${CMAKE_COMMAND} -E make_directory ${swig_outdir}
206 | COMMAND "${SWIG_EXECUTABLE}"
207 | ARGS "-${SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG}"
208 | ${swig_source_file_flags}
209 | ${CMAKE_SWIG_FLAGS}
210 | -outdir ${swig_outdir}
211 | ${swig_special_flags}
212 | ${swig_extra_flags}
213 | ${swig_include_dirs}
214 | -o "${swig_generated_file_fullname}"
215 | "${swig_source_file_fullname}"
216 | COMMENT "Swig source"
217 | )
218 |
219 | #add dummy independent dependencies from the _target to each file
220 | #that will be generated by the SWIG command above
221 |
222 | set(${outfiles} "${swig_generated_file_fullname}" ${swig_extra_generated_files})
223 |
224 | foreach(swig_gen_file ${${outfiles}})
225 | add_custom_command(
226 | OUTPUT ${swig_gen_file}
227 | COMMAND ""
228 | DEPENDS ${_target}
229 | COMMENT ""
230 | )
231 | endforeach()
232 |
233 | set_source_files_properties(
234 | ${outfiles} PROPERTIES GENERATED 1
235 | )
236 |
237 | endmacro()
238 |
239 | #
240 | # Create Swig module
241 | #
242 | macro(SWIG_ADD_MODULE name language)
243 | SWIG_MODULE_INITIALIZE(${name} ${language})
244 | set(swig_dot_i_sources)
245 | set(swig_other_sources)
246 | foreach(it ${ARGN})
247 | if(${it} MATCHES ".*\\.i$")
248 | set(swig_dot_i_sources ${swig_dot_i_sources} "${it}")
249 | else()
250 | set(swig_other_sources ${swig_other_sources} "${it}")
251 | endif()
252 | endforeach()
253 |
254 | set(swig_generated_sources)
255 | foreach(it ${swig_dot_i_sources})
256 | SWIG_ADD_SOURCE_TO_MODULE(${name} swig_generated_source ${it})
257 | set(swig_generated_sources ${swig_generated_sources} "${swig_generated_source}")
258 | endforeach()
259 | get_directory_property(swig_extra_clean_files ADDITIONAL_MAKE_CLEAN_FILES)
260 | set_directory_properties(PROPERTIES
261 | ADDITIONAL_MAKE_CLEAN_FILES "${swig_extra_clean_files};${swig_generated_sources}")
262 | add_library(${SWIG_MODULE_${name}_REAL_NAME}
263 | MODULE
264 | ${swig_generated_sources}
265 | ${swig_other_sources})
266 | string(TOLOWER "${language}" swig_lowercase_language)
267 | if ("${swig_lowercase_language}" STREQUAL "java")
268 | if (APPLE)
269 | # In java you want:
270 | # System.loadLibrary("LIBRARY");
271 | # then JNI will look for a library whose name is platform dependent, namely
272 | # MacOS : libLIBRARY.jnilib
273 | # Windows: LIBRARY.dll
274 | # Linux : libLIBRARY.so
275 | set_target_properties (${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".jnilib")
276 | endif ()
277 | endif ()
278 | if ("${swig_lowercase_language}" STREQUAL "python")
279 | # this is only needed for the python case where a _modulename.so is generated
280 | set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "")
281 | # Python extension modules on Windows must have the extension ".pyd"
282 | # instead of ".dll" as of Python 2.5. Older python versions do support
283 | # this suffix.
284 | # http://docs.python.org/whatsnew/ports.html#SECTION0001510000000000000000
285 | #
286 | # Windows: .dll is no longer supported as a filename extension for extension modules.
287 | # .pyd is now the only filename extension that will be searched for.
288 | #
289 | if(WIN32 AND NOT CYGWIN)
290 | set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".pyd")
291 | endif()
292 | endif ()
293 | endmacro()
294 |
295 | #
296 | # Like TARGET_LINK_LIBRARIES but for swig modules
297 | #
298 | macro(SWIG_LINK_LIBRARIES name)
299 | if(SWIG_MODULE_${name}_REAL_NAME)
300 | target_link_libraries(${SWIG_MODULE_${name}_REAL_NAME} ${ARGN})
301 | else()
302 | message(SEND_ERROR "Cannot find Swig library \"${name}\".")
303 | endif()
304 | endmacro()
305 |
--------------------------------------------------------------------------------
/cmake/Modules/nordicConfig.cmake:
--------------------------------------------------------------------------------
1 | INCLUDE(FindPkgConfig)
2 | PKG_CHECK_MODULES(PC_NORDIC nordic)
3 |
4 | FIND_PATH(
5 | NORDIC_INCLUDE_DIRS
6 | NAMES nordic/api.h
7 | HINTS $ENV{NORDIC_DIR}/include
8 | ${PC_NORDIC_INCLUDEDIR}
9 | PATHS ${CMAKE_INSTALL_PREFIX}/include
10 | /usr/local/include
11 | /usr/include
12 | )
13 |
14 | FIND_LIBRARY(
15 | NORDIC_LIBRARIES
16 | NAMES gnuradio-nordic
17 | HINTS $ENV{NORDIC_DIR}/lib
18 | ${PC_NORDIC_LIBDIR}
19 | PATHS ${CMAKE_INSTALL_PREFIX}/lib
20 | ${CMAKE_INSTALL_PREFIX}/lib64
21 | /usr/local/lib
22 | /usr/local/lib64
23 | /usr/lib
24 | /usr/lib64
25 | )
26 |
27 | INCLUDE(FindPackageHandleStandardArgs)
28 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(NORDIC DEFAULT_MSG NORDIC_LIBRARIES NORDIC_INCLUDE_DIRS)
29 | MARK_AS_ADVANCED(NORDIC_LIBRARIES NORDIC_INCLUDE_DIRS)
30 |
31 |
--------------------------------------------------------------------------------
/cmake/cmake_uninstall.cmake.in:
--------------------------------------------------------------------------------
1 | # http://www.vtk.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F
2 |
3 | IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
4 | MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
5 | ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
6 |
7 | FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
8 | STRING(REGEX REPLACE "\n" ";" files "${files}")
9 | FOREACH(file ${files})
10 | MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
11 | IF(EXISTS "$ENV{DESTDIR}${file}")
12 | EXEC_PROGRAM(
13 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
14 | OUTPUT_VARIABLE rm_out
15 | RETURN_VALUE rm_retval
16 | )
17 | IF(NOT "${rm_retval}" STREQUAL 0)
18 | MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
19 | ENDIF(NOT "${rm_retval}" STREQUAL 0)
20 | ELSEIF(IS_SYMLINK "$ENV{DESTDIR}${file}")
21 | EXEC_PROGRAM(
22 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
23 | OUTPUT_VARIABLE rm_out
24 | RETURN_VALUE rm_retval
25 | )
26 | IF(NOT "${rm_retval}" STREQUAL 0)
27 | MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
28 | ENDIF(NOT "${rm_retval}" STREQUAL 0)
29 | ELSE(EXISTS "$ENV{DESTDIR}${file}")
30 | MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
31 | ENDIF(EXISTS "$ENV{DESTDIR}${file}")
32 | ENDFOREACH(file)
33 |
--------------------------------------------------------------------------------
/docs/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2016 Bastille Networks
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 |
16 | ########################################################################
17 | # Setup dependencies
18 | ########################################################################
19 | find_package(Doxygen)
20 |
21 | ########################################################################
22 | # Begin conditional configuration
23 | ########################################################################
24 | if(ENABLE_DOXYGEN)
25 |
26 | ########################################################################
27 | # Add subdirectories
28 | ########################################################################
29 | add_subdirectory(doxygen)
30 |
31 | endif(ENABLE_DOXYGEN)
32 |
--------------------------------------------------------------------------------
/docs/README.nordic:
--------------------------------------------------------------------------------
1 | This is the nordic-write-a-block package meant as a guide to building
2 | out-of-tree packages. To use the nordic blocks, the Python namespaces
3 | is in 'nordic', which is imported as:
4 |
5 | import nordic
6 |
7 | See the Doxygen documentation for details about the blocks available
8 | in this package. A quick listing of the details can be found in Python
9 | after importing by using:
10 |
11 | help(nordic)
12 |
--------------------------------------------------------------------------------
/docs/doxygen/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2016 Bastille Networks
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 |
16 | ########################################################################
17 | # Create the doxygen configuration file
18 | ########################################################################
19 | file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} top_srcdir)
20 | file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} top_builddir)
21 | file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} abs_top_srcdir)
22 | file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} abs_top_builddir)
23 |
24 | set(HAVE_DOT ${DOXYGEN_DOT_FOUND})
25 | set(enable_html_docs YES)
26 | set(enable_latex_docs NO)
27 | set(enable_xml_docs YES)
28 |
29 | configure_file(
30 | ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in
31 | ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
32 | @ONLY)
33 |
34 | set(BUILT_DIRS ${CMAKE_CURRENT_BINARY_DIR}/xml ${CMAKE_CURRENT_BINARY_DIR}/html)
35 |
36 | ########################################################################
37 | # Make and install doxygen docs
38 | ########################################################################
39 | add_custom_command(
40 | OUTPUT ${BUILT_DIRS}
41 | COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
42 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
43 | COMMENT "Generating documentation with doxygen"
44 | )
45 |
46 | add_custom_target(doxygen_target ALL DEPENDS ${BUILT_DIRS})
47 |
48 | install(DIRECTORY ${BUILT_DIRS} DESTINATION ${GR_PKG_DOC_DIR})
49 |
--------------------------------------------------------------------------------
/docs/doxygen/doxyxml/__init__.py:
--------------------------------------------------------------------------------
1 | '''
2 | Copyright (C) 2016 Bastille Networks
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | '''
17 |
18 | """
19 | Python interface to contents of doxygen xml documentation.
20 |
21 | Example use:
22 | See the contents of the example folder for the C++ and
23 | doxygen-generated xml used in this example.
24 |
25 | >>> # Parse the doxygen docs.
26 | >>> import os
27 | >>> this_dir = os.path.dirname(globals()['__file__'])
28 | >>> xml_path = this_dir + "/example/xml/"
29 | >>> di = DoxyIndex(xml_path)
30 |
31 | Get a list of all top-level objects.
32 |
33 | >>> print([mem.name() for mem in di.members()])
34 | [u'Aadvark', u'aadvarky_enough', u'main']
35 |
36 | Get all functions.
37 |
38 | >>> print([mem.name() for mem in di.in_category(DoxyFunction)])
39 | [u'aadvarky_enough', u'main']
40 |
41 | Check if an object is present.
42 |
43 | >>> di.has_member(u'Aadvark')
44 | True
45 | >>> di.has_member(u'Fish')
46 | False
47 |
48 | Get an item by name and check its properties.
49 |
50 | >>> aad = di.get_member(u'Aadvark')
51 | >>> print(aad.brief_description)
52 | Models the mammal Aadvark.
53 | >>> print(aad.detailed_description)
54 | Sadly the model is incomplete and cannot capture all aspects of an aadvark yet.
55 |
56 | This line is uninformative and is only to test line breaks in the comments.
57 | >>> [mem.name() for mem in aad.members()]
58 | [u'aadvarkness', u'print', u'Aadvark', u'get_aadvarkness']
59 | >>> aad.get_member(u'print').brief_description
60 | u'Outputs the vital aadvark statistics.'
61 |
62 | """
63 |
64 | from doxyindex import DoxyIndex, DoxyFunction, DoxyParam, DoxyClass, DoxyFile, DoxyNamespace, DoxyGroup, DoxyFriend, DoxyOther
65 |
66 | def _test():
67 | import os
68 | this_dir = os.path.dirname(globals()['__file__'])
69 | xml_path = this_dir + "/example/xml/"
70 | di = DoxyIndex(xml_path)
71 | # Get the Aadvark class
72 | aad = di.get_member('Aadvark')
73 | aad.brief_description
74 | import doctest
75 | return doctest.testmod()
76 |
77 | if __name__ == "__main__":
78 | _test()
79 |
80 |
--------------------------------------------------------------------------------
/docs/doxygen/doxyxml/base.py:
--------------------------------------------------------------------------------
1 | '''
2 | Copyright (C) 2016 Bastille Networks
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | '''
17 |
18 | """
19 | A base class is created.
20 |
21 | Classes based upon this are used to make more user-friendly interfaces
22 | to the doxygen xml docs than the generated classes provide.
23 | """
24 |
25 | import os
26 | import pdb
27 |
28 | from xml.parsers.expat import ExpatError
29 |
30 | from generated import compound
31 |
32 |
33 | class Base(object):
34 |
35 | class Duplicate(StandardError):
36 | pass
37 |
38 | class NoSuchMember(StandardError):
39 | pass
40 |
41 | class ParsingError(StandardError):
42 | pass
43 |
44 | def __init__(self, parse_data, top=None):
45 | self._parsed = False
46 | self._error = False
47 | self._parse_data = parse_data
48 | self._members = []
49 | self._dict_members = {}
50 | self._in_category = {}
51 | self._data = {}
52 | if top is not None:
53 | self._xml_path = top._xml_path
54 | # Set up holder of references
55 | else:
56 | top = self
57 | self._refs = {}
58 | self._xml_path = parse_data
59 | self.top = top
60 |
61 | @classmethod
62 | def from_refid(cls, refid, top=None):
63 | """ Instantiate class from a refid rather than parsing object. """
64 | # First check to see if its already been instantiated.
65 | if top is not None and refid in top._refs:
66 | return top._refs[refid]
67 | # Otherwise create a new instance and set refid.
68 | inst = cls(None, top=top)
69 | inst.refid = refid
70 | inst.add_ref(inst)
71 | return inst
72 |
73 | @classmethod
74 | def from_parse_data(cls, parse_data, top=None):
75 | refid = getattr(parse_data, 'refid', None)
76 | if refid is not None and top is not None and refid in top._refs:
77 | return top._refs[refid]
78 | inst = cls(parse_data, top=top)
79 | if refid is not None:
80 | inst.refid = refid
81 | inst.add_ref(inst)
82 | return inst
83 |
84 | def add_ref(self, obj):
85 | if hasattr(obj, 'refid'):
86 | self.top._refs[obj.refid] = obj
87 |
88 | mem_classes = []
89 |
90 | def get_cls(self, mem):
91 | for cls in self.mem_classes:
92 | if cls.can_parse(mem):
93 | return cls
94 | raise StandardError(("Did not find a class for object '%s'." \
95 | % (mem.get_name())))
96 |
97 | def convert_mem(self, mem):
98 | try:
99 | cls = self.get_cls(mem)
100 | converted = cls.from_parse_data(mem, self.top)
101 | if converted is None:
102 | raise StandardError('No class matched this object.')
103 | self.add_ref(converted)
104 | return converted
105 | except StandardError, e:
106 | print e
107 |
108 | @classmethod
109 | def includes(cls, inst):
110 | return isinstance(inst, cls)
111 |
112 | @classmethod
113 | def can_parse(cls, obj):
114 | return False
115 |
116 | def _parse(self):
117 | self._parsed = True
118 |
119 | def _get_dict_members(self, cat=None):
120 | """
121 | For given category a dictionary is returned mapping member names to
122 | members of that category. For names that are duplicated the name is
123 | mapped to None.
124 | """
125 | self.confirm_no_error()
126 | if cat not in self._dict_members:
127 | new_dict = {}
128 | for mem in self.in_category(cat):
129 | if mem.name() not in new_dict:
130 | new_dict[mem.name()] = mem
131 | else:
132 | new_dict[mem.name()] = self.Duplicate
133 | self._dict_members[cat] = new_dict
134 | return self._dict_members[cat]
135 |
136 | def in_category(self, cat):
137 | self.confirm_no_error()
138 | if cat is None:
139 | return self._members
140 | if cat not in self._in_category:
141 | self._in_category[cat] = [mem for mem in self._members
142 | if cat.includes(mem)]
143 | return self._in_category[cat]
144 |
145 | def get_member(self, name, cat=None):
146 | self.confirm_no_error()
147 | # Check if it's in a namespace or class.
148 | bits = name.split('::')
149 | first = bits[0]
150 | rest = '::'.join(bits[1:])
151 | member = self._get_dict_members(cat).get(first, self.NoSuchMember)
152 | # Raise any errors that are returned.
153 | if member in set([self.NoSuchMember, self.Duplicate]):
154 | raise member()
155 | if rest:
156 | return member.get_member(rest, cat=cat)
157 | return member
158 |
159 | def has_member(self, name, cat=None):
160 | try:
161 | mem = self.get_member(name, cat=cat)
162 | return True
163 | except self.NoSuchMember:
164 | return False
165 |
166 | def data(self):
167 | self.confirm_no_error()
168 | return self._data
169 |
170 | def members(self):
171 | self.confirm_no_error()
172 | return self._members
173 |
174 | def process_memberdefs(self):
175 | mdtss = []
176 | for sec in self._retrieved_data.compounddef.sectiondef:
177 | mdtss += sec.memberdef
178 | # At the moment we lose all information associated with sections.
179 | # Sometimes a memberdef is in several sectiondef.
180 | # We make sure we don't get duplicates here.
181 | uniques = set([])
182 | for mem in mdtss:
183 | converted = self.convert_mem(mem)
184 | pair = (mem.name, mem.__class__)
185 | if pair not in uniques:
186 | uniques.add(pair)
187 | self._members.append(converted)
188 |
189 | def retrieve_data(self):
190 | filename = os.path.join(self._xml_path, self.refid + '.xml')
191 | try:
192 | self._retrieved_data = compound.parse(filename)
193 | except ExpatError:
194 | print('Error in xml in file %s' % filename)
195 | self._error = True
196 | self._retrieved_data = None
197 |
198 | def check_parsed(self):
199 | if not self._parsed:
200 | self._parse()
201 |
202 | def confirm_no_error(self):
203 | self.check_parsed()
204 | if self._error:
205 | raise self.ParsingError()
206 |
207 | def error(self):
208 | self.check_parsed()
209 | return self._error
210 |
211 | def name(self):
212 | # first see if we can do it without processing.
213 | if self._parse_data is not None:
214 | return self._parse_data.name
215 | self.check_parsed()
216 | return self._retrieved_data.compounddef.name
217 |
--------------------------------------------------------------------------------
/docs/doxygen/doxyxml/doxyindex.py:
--------------------------------------------------------------------------------
1 | '''
2 | Copyright (C) 2016 Bastille Networks
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | '''
17 |
18 | """
19 | Classes providing more user-friendly interfaces to the doxygen xml
20 | docs than the generated classes provide.
21 | """
22 |
23 | import os
24 |
25 | from generated import index
26 | from base import Base
27 | from text import description
28 |
29 | class DoxyIndex(Base):
30 | """
31 | Parses a doxygen xml directory.
32 | """
33 |
34 | __module__ = "gnuradio.utils.doxyxml"
35 |
36 | def _parse(self):
37 | if self._parsed:
38 | return
39 | super(DoxyIndex, self)._parse()
40 | self._root = index.parse(os.path.join(self._xml_path, 'index.xml'))
41 | for mem in self._root.compound:
42 | converted = self.convert_mem(mem)
43 | # For files we want the contents to be accessible directly
44 | # from the parent rather than having to go through the file
45 | # object.
46 | if self.get_cls(mem) == DoxyFile:
47 | if mem.name.endswith('.h'):
48 | self._members += converted.members()
49 | self._members.append(converted)
50 | else:
51 | self._members.append(converted)
52 |
53 |
54 | def generate_swig_doc_i(self):
55 | """
56 | %feature("docstring") gr_make_align_on_samplenumbers_ss::align_state "
57 | Wraps the C++: gr_align_on_samplenumbers_ss::align_state";
58 | """
59 | pass
60 |
61 |
62 | class DoxyCompMem(Base):
63 |
64 |
65 | kind = None
66 |
67 | def __init__(self, *args, **kwargs):
68 | super(DoxyCompMem, self).__init__(*args, **kwargs)
69 |
70 | @classmethod
71 | def can_parse(cls, obj):
72 | return obj.kind == cls.kind
73 |
74 | def set_descriptions(self, parse_data):
75 | bd = description(getattr(parse_data, 'briefdescription', None))
76 | dd = description(getattr(parse_data, 'detaileddescription', None))
77 | self._data['brief_description'] = bd
78 | self._data['detailed_description'] = dd
79 |
80 | class DoxyCompound(DoxyCompMem):
81 | pass
82 |
83 | class DoxyMember(DoxyCompMem):
84 | pass
85 |
86 |
87 | class DoxyFunction(DoxyMember):
88 |
89 | __module__ = "gnuradio.utils.doxyxml"
90 |
91 | kind = 'function'
92 |
93 | def _parse(self):
94 | if self._parsed:
95 | return
96 | super(DoxyFunction, self)._parse()
97 | self.set_descriptions(self._parse_data)
98 | self._data['params'] = []
99 | prms = self._parse_data.param
100 | for prm in prms:
101 | self._data['params'].append(DoxyParam(prm))
102 |
103 | brief_description = property(lambda self: self.data()['brief_description'])
104 | detailed_description = property(lambda self: self.data()['detailed_description'])
105 | params = property(lambda self: self.data()['params'])
106 |
107 | Base.mem_classes.append(DoxyFunction)
108 |
109 |
110 | class DoxyParam(DoxyMember):
111 |
112 | __module__ = "gnuradio.utils.doxyxml"
113 |
114 | def _parse(self):
115 | if self._parsed:
116 | return
117 | super(DoxyParam, self)._parse()
118 | self.set_descriptions(self._parse_data)
119 | self._data['declname'] = self._parse_data.declname
120 |
121 | brief_description = property(lambda self: self.data()['brief_description'])
122 | detailed_description = property(lambda self: self.data()['detailed_description'])
123 | declname = property(lambda self: self.data()['declname'])
124 |
125 | class DoxyClass(DoxyCompound):
126 |
127 | __module__ = "gnuradio.utils.doxyxml"
128 |
129 | kind = 'class'
130 |
131 | def _parse(self):
132 | if self._parsed:
133 | return
134 | super(DoxyClass, self)._parse()
135 | self.retrieve_data()
136 | if self._error:
137 | return
138 | self.set_descriptions(self._retrieved_data.compounddef)
139 | # Sectiondef.kind tells about whether private or public.
140 | # We just ignore this for now.
141 | self.process_memberdefs()
142 |
143 | brief_description = property(lambda self: self.data()['brief_description'])
144 | detailed_description = property(lambda self: self.data()['detailed_description'])
145 |
146 | Base.mem_classes.append(DoxyClass)
147 |
148 |
149 | class DoxyFile(DoxyCompound):
150 |
151 | __module__ = "gnuradio.utils.doxyxml"
152 |
153 | kind = 'file'
154 |
155 | def _parse(self):
156 | if self._parsed:
157 | return
158 | super(DoxyFile, self)._parse()
159 | self.retrieve_data()
160 | self.set_descriptions(self._retrieved_data.compounddef)
161 | if self._error:
162 | return
163 | self.process_memberdefs()
164 |
165 | brief_description = property(lambda self: self.data()['brief_description'])
166 | detailed_description = property(lambda self: self.data()['detailed_description'])
167 |
168 | Base.mem_classes.append(DoxyFile)
169 |
170 |
171 | class DoxyNamespace(DoxyCompound):
172 |
173 | __module__ = "gnuradio.utils.doxyxml"
174 |
175 | kind = 'namespace'
176 |
177 | Base.mem_classes.append(DoxyNamespace)
178 |
179 |
180 | class DoxyGroup(DoxyCompound):
181 |
182 | __module__ = "gnuradio.utils.doxyxml"
183 |
184 | kind = 'group'
185 |
186 | def _parse(self):
187 | if self._parsed:
188 | return
189 | super(DoxyGroup, self)._parse()
190 | self.retrieve_data()
191 | if self._error:
192 | return
193 | cdef = self._retrieved_data.compounddef
194 | self._data['title'] = description(cdef.title)
195 | # Process inner groups
196 | grps = cdef.innergroup
197 | for grp in grps:
198 | converted = DoxyGroup.from_refid(grp.refid, top=self.top)
199 | self._members.append(converted)
200 | # Process inner classes
201 | klasses = cdef.innerclass
202 | for kls in klasses:
203 | converted = DoxyClass.from_refid(kls.refid, top=self.top)
204 | self._members.append(converted)
205 | # Process normal members
206 | self.process_memberdefs()
207 |
208 | title = property(lambda self: self.data()['title'])
209 |
210 |
211 | Base.mem_classes.append(DoxyGroup)
212 |
213 |
214 | class DoxyFriend(DoxyMember):
215 |
216 | __module__ = "gnuradio.utils.doxyxml"
217 |
218 | kind = 'friend'
219 |
220 | Base.mem_classes.append(DoxyFriend)
221 |
222 |
223 | class DoxyOther(Base):
224 |
225 | __module__ = "gnuradio.utils.doxyxml"
226 |
227 | kinds = set(['variable', 'struct', 'union', 'define', 'typedef', 'enum', 'dir', 'page'])
228 |
229 | @classmethod
230 | def can_parse(cls, obj):
231 | return obj.kind in cls.kinds
232 |
233 | Base.mem_classes.append(DoxyOther)
234 |
235 |
--------------------------------------------------------------------------------
/docs/doxygen/doxyxml/generated/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Contains generated files produced by generateDS.py.
3 |
4 | These do the real work of parsing the doxygen xml files but the
5 | resultant classes are not very friendly to navigate so the rest of the
6 | doxyxml module processes them further.
7 | """
8 |
--------------------------------------------------------------------------------
/docs/doxygen/doxyxml/generated/index.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """
4 | Generated Mon Feb 9 19:08:05 2009 by generateDS.py.
5 | """
6 |
7 | from xml.dom import minidom
8 |
9 | import os
10 | import sys
11 | import compound
12 |
13 | import indexsuper as supermod
14 |
15 | class DoxygenTypeSub(supermod.DoxygenType):
16 | def __init__(self, version=None, compound=None):
17 | supermod.DoxygenType.__init__(self, version, compound)
18 |
19 | def find_compounds_and_members(self, details):
20 | """
21 | Returns a list of all compounds and their members which match details
22 | """
23 |
24 | results = []
25 | for compound in self.compound:
26 | members = compound.find_members(details)
27 | if members:
28 | results.append([compound, members])
29 | else:
30 | if details.match(compound):
31 | results.append([compound, []])
32 |
33 | return results
34 |
35 | supermod.DoxygenType.subclass = DoxygenTypeSub
36 | # end class DoxygenTypeSub
37 |
38 |
39 | class CompoundTypeSub(supermod.CompoundType):
40 | def __init__(self, kind=None, refid=None, name='', member=None):
41 | supermod.CompoundType.__init__(self, kind, refid, name, member)
42 |
43 | def find_members(self, details):
44 | """
45 | Returns a list of all members which match details
46 | """
47 |
48 | results = []
49 |
50 | for member in self.member:
51 | if details.match(member):
52 | results.append(member)
53 |
54 | return results
55 |
56 | supermod.CompoundType.subclass = CompoundTypeSub
57 | # end class CompoundTypeSub
58 |
59 |
60 | class MemberTypeSub(supermod.MemberType):
61 |
62 | def __init__(self, kind=None, refid=None, name=''):
63 | supermod.MemberType.__init__(self, kind, refid, name)
64 |
65 | supermod.MemberType.subclass = MemberTypeSub
66 | # end class MemberTypeSub
67 |
68 |
69 | def parse(inFilename):
70 |
71 | doc = minidom.parse(inFilename)
72 | rootNode = doc.documentElement
73 | rootObj = supermod.DoxygenType.factory()
74 | rootObj.build(rootNode)
75 |
76 | return rootObj
77 |
78 |
--------------------------------------------------------------------------------
/docs/doxygen/doxyxml/text.py:
--------------------------------------------------------------------------------
1 | '''
2 | Copyright (C) 2016 Bastille Networks
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | '''
17 |
18 | """
19 | Utilities for extracting text from generated classes.
20 | """
21 |
22 | def is_string(txt):
23 | if isinstance(txt, str):
24 | return True
25 | try:
26 | if isinstance(txt, unicode):
27 | return True
28 | except NameError:
29 | pass
30 | return False
31 |
32 | def description(obj):
33 | if obj is None:
34 | return None
35 | return description_bit(obj).strip()
36 |
37 | def description_bit(obj):
38 | if hasattr(obj, 'content'):
39 | contents = [description_bit(item) for item in obj.content]
40 | result = ''.join(contents)
41 | elif hasattr(obj, 'content_'):
42 | contents = [description_bit(item) for item in obj.content_]
43 | result = ''.join(contents)
44 | elif hasattr(obj, 'value'):
45 | result = description_bit(obj.value)
46 | elif is_string(obj):
47 | return obj
48 | else:
49 | raise StandardError('Expecting a string or something with content, content_ or value attribute')
50 | # If this bit is a paragraph then add one some line breaks.
51 | if hasattr(obj, 'name') and obj.name == 'para':
52 | result += "\n\n"
53 | return result
54 |
--------------------------------------------------------------------------------
/docs/doxygen/other/group_defs.dox:
--------------------------------------------------------------------------------
1 | /*!
2 | * \defgroup block GNU Radio NORDIC C++ Signal Processing Blocks
3 | * \brief All C++ blocks that can be used from the NORDIC GNU Radio
4 | * module are listed here or in the subcategories below.
5 | *
6 | */
7 |
8 |
--------------------------------------------------------------------------------
/docs/doxygen/other/main_page.dox:
--------------------------------------------------------------------------------
1 | /*! \mainpage
2 |
3 | Welcome to the GNU Radio NORDIC Block
4 |
5 | This is the intro page for the Doxygen manual generated for the NORDIC
6 | block (docs/doxygen/other/main_page.dox). Edit it to add more detailed
7 | documentation about the new GNU Radio modules contained in this
8 | project.
9 |
10 | */
11 |
--------------------------------------------------------------------------------
/docs/doxygen/swig_doc.py:
--------------------------------------------------------------------------------
1 | '''
2 | Copyright (C) 2016 Bastille Networks
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | '''
17 |
18 | """
19 | Creates the swig_doc.i SWIG interface file.
20 | Execute using: python swig_doc.py xml_path outputfilename
21 |
22 | The file instructs SWIG to transfer the doxygen comments into the
23 | python docstrings.
24 |
25 | """
26 |
27 | import sys
28 |
29 | try:
30 | from doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile, base
31 | except ImportError:
32 | from gnuradio.doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile, base
33 |
34 |
35 | def py_name(name):
36 | bits = name.split('_')
37 | return '_'.join(bits[1:])
38 |
39 | def make_name(name):
40 | bits = name.split('_')
41 | return bits[0] + '_make_' + '_'.join(bits[1:])
42 |
43 |
44 | class Block(object):
45 | """
46 | Checks if doxyxml produced objects correspond to a gnuradio block.
47 | """
48 |
49 | @classmethod
50 | def includes(cls, item):
51 | if not isinstance(item, DoxyClass):
52 | return False
53 | # Check for a parsing error.
54 | if item.error():
55 | return False
56 | return item.has_member(make_name(item.name()), DoxyFriend)
57 |
58 |
59 | def utoascii(text):
60 | """
61 | Convert unicode text into ascii and escape quotes.
62 | """
63 | if text is None:
64 | return ''
65 | out = text.encode('ascii', 'replace')
66 | out = out.replace('"', '\\"')
67 | return out
68 |
69 |
70 | def combine_descriptions(obj):
71 | """
72 | Combines the brief and detailed descriptions of an object together.
73 | """
74 | description = []
75 | bd = obj.brief_description.strip()
76 | dd = obj.detailed_description.strip()
77 | if bd:
78 | description.append(bd)
79 | if dd:
80 | description.append(dd)
81 | return utoascii('\n\n'.join(description)).strip()
82 |
83 |
84 | entry_templ = '%feature("docstring") {name} "{docstring}"'
85 | def make_entry(obj, name=None, templ="{description}", description=None):
86 | """
87 | Create a docstring entry for a swig interface file.
88 |
89 | obj - a doxyxml object from which documentation will be extracted.
90 | name - the name of the C object (defaults to obj.name())
91 | templ - an optional template for the docstring containing only one
92 | variable named 'description'.
93 | description - if this optional variable is set then it's value is
94 | used as the description instead of extracting it from obj.
95 | """
96 | if name is None:
97 | name=obj.name()
98 | if "operator " in name:
99 | return ''
100 | if description is None:
101 | description = combine_descriptions(obj)
102 | docstring = templ.format(description=description)
103 | if not docstring:
104 | return ''
105 | return entry_templ.format(
106 | name=name,
107 | docstring=docstring,
108 | )
109 |
110 |
111 | def make_func_entry(func, name=None, description=None, params=None):
112 | """
113 | Create a function docstring entry for a swig interface file.
114 |
115 | func - a doxyxml object from which documentation will be extracted.
116 | name - the name of the C object (defaults to func.name())
117 | description - if this optional variable is set then it's value is
118 | used as the description instead of extracting it from func.
119 | params - a parameter list that overrides using func.params.
120 | """
121 | if params is None:
122 | params = func.params
123 | params = [prm.declname for prm in params]
124 | if params:
125 | sig = "Params: (%s)" % ", ".join(params)
126 | else:
127 | sig = "Params: (NONE)"
128 | templ = "{description}\n\n" + sig
129 | return make_entry(func, name=name, templ=utoascii(templ),
130 | description=description)
131 |
132 |
133 | def make_class_entry(klass, description=None):
134 | """
135 | Create a class docstring for a swig interface file.
136 | """
137 | output = []
138 | output.append(make_entry(klass, description=description))
139 | for func in klass.in_category(DoxyFunction):
140 | name = klass.name() + '::' + func.name()
141 | output.append(make_func_entry(func, name=name))
142 | return "\n\n".join(output)
143 |
144 |
145 | def make_block_entry(di, block):
146 | """
147 | Create class and function docstrings of a gnuradio block for a
148 | swig interface file.
149 | """
150 | descriptions = []
151 | # Get the documentation associated with the class.
152 | class_desc = combine_descriptions(block)
153 | if class_desc:
154 | descriptions.append(class_desc)
155 | # Get the documentation associated with the make function
156 | make_func = di.get_member(make_name(block.name()), DoxyFunction)
157 | make_func_desc = combine_descriptions(make_func)
158 | if make_func_desc:
159 | descriptions.append(make_func_desc)
160 | # Get the documentation associated with the file
161 | try:
162 | block_file = di.get_member(block.name() + ".h", DoxyFile)
163 | file_desc = combine_descriptions(block_file)
164 | if file_desc:
165 | descriptions.append(file_desc)
166 | except base.Base.NoSuchMember:
167 | # Don't worry if we can't find a matching file.
168 | pass
169 | # And join them all together to make a super duper description.
170 | super_description = "\n\n".join(descriptions)
171 | # Associate the combined description with the class and
172 | # the make function.
173 | output = []
174 | output.append(make_class_entry(block, description=super_description))
175 | creator = block.get_member(block.name(), DoxyFunction)
176 | output.append(make_func_entry(make_func, description=super_description,
177 | params=creator.params))
178 | return "\n\n".join(output)
179 |
180 |
181 | def make_swig_interface_file(di, swigdocfilename, custom_output=None):
182 |
183 | output = ["""
184 | /*
185 | * This file was automatically generated using swig_doc.py.
186 | *
187 | * Any changes to it will be lost next time it is regenerated.
188 | */
189 | """]
190 |
191 | if custom_output is not None:
192 | output.append(custom_output)
193 |
194 | # Create docstrings for the blocks.
195 | blocks = di.in_category(Block)
196 | make_funcs = set([])
197 | for block in blocks:
198 | try:
199 | make_func = di.get_member(make_name(block.name()), DoxyFunction)
200 | make_funcs.add(make_func.name())
201 | output.append(make_block_entry(di, block))
202 | except block.ParsingError:
203 | print('Parsing error for block %s' % block.name())
204 |
205 | # Create docstrings for functions
206 | # Don't include the make functions since they have already been dealt with.
207 | funcs = [f for f in di.in_category(DoxyFunction) if f.name() not in make_funcs]
208 | for f in funcs:
209 | try:
210 | output.append(make_func_entry(f))
211 | except f.ParsingError:
212 | print('Parsing error for function %s' % f.name())
213 |
214 | # Create docstrings for classes
215 | block_names = [block.name() for block in blocks]
216 | klasses = [k for k in di.in_category(DoxyClass) if k.name() not in block_names]
217 | for k in klasses:
218 | try:
219 | output.append(make_class_entry(k))
220 | except k.ParsingError:
221 | print('Parsing error for class %s' % k.name())
222 |
223 | # Docstrings are not created for anything that is not a function or a class.
224 | # If this excludes anything important please add it here.
225 |
226 | output = "\n\n".join(output)
227 |
228 | swig_doc = file(swigdocfilename, 'w')
229 | swig_doc.write(output)
230 | swig_doc.close()
231 |
232 | if __name__ == "__main__":
233 | # Parse command line options and set up doxyxml.
234 | err_msg = "Execute using: python swig_doc.py xml_path outputfilename"
235 | if len(sys.argv) != 3:
236 | raise StandardError(err_msg)
237 | xml_path = sys.argv[1]
238 | swigdocfilename = sys.argv[2]
239 | di = DoxyIndex(xml_path)
240 |
241 | # gnuradio.gr.msq_queue.insert_tail and delete_head create errors unless docstrings are defined!
242 | # This is presumably a bug in SWIG.
243 | #msg_q = di.get_member(u'gr_msg_queue', DoxyClass)
244 | #insert_tail = msg_q.get_member(u'insert_tail', DoxyFunction)
245 | #delete_head = msg_q.get_member(u'delete_head', DoxyFunction)
246 | output = []
247 | #output.append(make_func_entry(insert_tail, name='gr_py_msg_queue__insert_tail'))
248 | #output.append(make_func_entry(delete_head, name='gr_py_msg_queue__delete_head'))
249 | custom_output = "\n\n".join(output)
250 |
251 | # Generate the docstrings interface file.
252 | make_swig_interface_file(di, swigdocfilename, custom_output=custom_output)
253 |
--------------------------------------------------------------------------------
/examples/microsoft_mouse_sniffer.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 |
3 | from gnuradio import gr, blocks, digital, filter
4 | from gnuradio.filter import firdes
5 | import thread
6 | import osmosdr
7 | import nordic
8 | import pmt
9 | import struct
10 | import time
11 |
12 |
13 | class top_block(gr.top_block):
14 |
15 | def __init__(self):
16 | gr.top_block.__init__(self, "Microsoft Mouse Sniffer")
17 |
18 | # SDR configuration
19 | self.freq = 2403e6
20 | self.gain = 70
21 | self.symbol_rate = 2e6
22 | self.sample_rate = 4e6
23 |
24 | # SDR source (gr-osmosdr source)
25 | self.osmosdr_source = osmosdr.source()
26 | self.osmosdr_source.set_sample_rate(self.sample_rate)
27 | self.osmosdr_source.set_center_freq(self.freq)
28 | self.osmosdr_source.set_gain(self.gain)
29 | self.osmosdr_source.set_antenna('TX/RX')
30 |
31 | # Low pass filter
32 | self.lpf = filter.fir_filter_ccf(
33 | 1, firdes.low_pass_2(1, self.sample_rate, self.symbol_rate / 2, 50e3, 50))
34 |
35 | # GFSK demod, defaults to 2 samples per symbol
36 | self.gfsk_demod = digital.gfsk_demod()
37 |
38 | # Nordic RX
39 | self.nordic_rx = nordic.nordic_rx(3, 5, 2, 2)
40 |
41 | # Connect the blocks
42 | self.connect((self.osmosdr_source, 0), (self.lpf, 0))
43 | self.connect((self.lpf, 0), (self.gfsk_demod, 0))
44 | self.connect((self.gfsk_demod, 0), (self.nordic_rx, 0))
45 |
46 | # Handle incoming packets
47 | self.nordictap_handler = microsoft_nordictap_handler(self)
48 | self.msg_connect(
49 | self.nordic_rx, "nordictap_out", self.nordictap_handler, "nordictap_in")
50 |
51 | # Tune the USRP by nRF24L channel number
52 | def set_channel(self, channel):
53 |
54 | new_channel = 2400e6 + channel * 1e6
55 | self.osmosdr_source.set_center_freq(2400e6 + channel * 1e6)
56 | self.nordic_rx.set_channel(channel)
57 |
58 |
59 | # Microsoft mouse nordictap handler
60 | class microsoft_nordictap_handler(gr.sync_block):
61 |
62 | def __init__(self, tb):
63 | gr.sync_block.__init__(
64 | self, name="Nordictap Handler", in_sig=None, out_sig=None)
65 |
66 | self.tb = tb
67 | self.message_port_register_in(pmt.intern("nordictap_in"))
68 | self.set_msg_handler(
69 | pmt.intern("nordictap_in"), self.nordictap_handler)
70 |
71 | # Tick / channel hopping state and logic
72 | self.last_rx = time.time()
73 | self.last_tune = time.time()
74 | self.ch_timeout = 0.4 # timeout a channel after 200ms
75 | self.last_ch = 0
76 | thread.start_new_thread(self.tick, ())
77 |
78 | # Channels and channel groups
79 | self.channels = [3, 29, 21, 5, 23, 17, 19, 50, 31, 25,
80 | 46, 27, 78, 70, 72, 44, 56, 48, 68, 80, 54, 52, 74, 76]
81 | self.channel_groups = []
82 | for x in range(6):
83 | chs = []
84 | for y in range(4):
85 | chs.append(self.channels[y * 6 + x])
86 | self.channel_groups.append(chs)
87 |
88 | # Discovered device state
89 | self.mouse_address = None
90 |
91 | # 10ms tick
92 | def tick(self):
93 |
94 | while True:
95 |
96 | # Check for a stale channel
97 | if ((time.time() - self.last_rx) > self.ch_timeout * 5) and \
98 | ((time.time() - self.last_tune) > self.ch_timeout):
99 |
100 | self.last_ch += 1
101 | if self.last_ch >= len(self.channels):
102 | self.last_ch = 0
103 | print 'Tuning to 24%02i MHz' % self.channels[self.last_ch]
104 | self.last_tune = time.time()
105 | self.tb.set_channel(self.channels[self.last_ch])
106 |
107 | # Wait 10ms
108 | time.sleep(0.01)
109 |
110 | def nordictap_handler(self, msg):
111 |
112 | data = pmt.to_python(msg).tostring()
113 |
114 | # Unpack the header
115 | values = struct.unpack('BBBBBBB', data[0:7])
116 | channel = values[0]
117 | data_rate = values[1]
118 | address_length = values[2]
119 | payload_length = values[3]
120 | sequence_number = values[4]
121 | no_ack = values[5]
122 | crc_length = values[6]
123 |
124 | # Parse the address, payload, and crc
125 | address = data[7:7 + address_length]
126 | payload = data[7 + address_length:7 + address_length + payload_length]
127 | crc = data[7 + address_length + payload_length:
128 | 7 + address_length + payload_length + crc_length]
129 |
130 | # Check for a Microsoft mouse
131 | if self.mouse_address is None:
132 | if ((ord(address[0]) & 0xF0) == 0xA0) and \
133 | ((ord(address[4]) & 0x0F) == 0x06) and \
134 | payload_length == 19:
135 |
136 | # Set the mouse address
137 | self.mouse_address = address
138 |
139 | # Set the channel group
140 | for x in range(6):
141 | if channel in self.channel_groups[x]:
142 | self.channels = self.channel_groups[x]
143 | break
144 |
145 | # Camp on the channel and print out the packet if this is our target
146 | # device
147 | if self.mouse_address == address:
148 |
149 | self.last_rx = time.time()
150 |
151 | # Print the channel, sequence number, address and payload
152 | print 'CH=' + str(2400 + channel),
153 | print 'SEQ=' + str(sequence_number),
154 | print 'ADDR=' + ':'.join('%02X' % ord(b) for b in address),
155 | print 'PLD=' + ':'.join('%02X' % ord(b) for b in payload),
156 | print 'CRC=' + ':'.join('%02X' % ord(b) for b in crc)
157 |
158 |
159 | def main():
160 | tb = top_block()
161 | tb.start()
162 | try:
163 | raw_input('Press Enter to quit: ')
164 | except EOFError:
165 | pass
166 | tb.stop()
167 | tb.wait()
168 |
169 |
170 | if __name__ == '__main__':
171 | main()
172 |
--------------------------------------------------------------------------------
/examples/nordic_auto_ack.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 |
3 | from gnuradio import gr, blocks, digital, filter
4 | from gnuradio.filter import firdes
5 | import thread
6 | import nordic
7 | import pmt
8 | import struct
9 | import time
10 | import numpy
11 | import array
12 | import osmosdr
13 | import argparse
14 | from bitstring import BitArray
15 | from gnuradio import uhd
16 | from Queue import Queue
17 |
18 |
19 | class top_block(gr.top_block):
20 |
21 | def __init__(self, args):
22 | gr.top_block.__init__(self, "Nordic Auto-ACK Example")
23 |
24 | # SDR configuration
25 | self.freq = 2400e6 + args.channel * 1e6
26 | self.gain = args.gain
27 | self.symbol_rate = args.data_rate
28 | self.sample_rate = args.data_rate * args.samples_per_symbol
29 |
30 | # SDR source (gr-osmosdr source)
31 | self.osmosdr_source = osmosdr.source()
32 | self.osmosdr_source.set_sample_rate(self.sample_rate)
33 | self.osmosdr_source.set_center_freq(self.freq)
34 | self.osmosdr_source.set_gain(self.gain)
35 | self.osmosdr_source.set_antenna('TX/RX')
36 |
37 | # SDR sink (gr-osmosdr source)
38 | self.osmosdr_sink = osmosdr.sink()
39 | self.osmosdr_sink.set_sample_rate(self.sample_rate)
40 | self.osmosdr_sink.set_center_freq(self.freq)
41 | self.osmosdr_sink.set_gain(self.gain)
42 | self.osmosdr_sink.set_antenna('TX/RX')
43 |
44 | # Transmit chain
45 | self.tx = nordic.nordic_tx()
46 | self.gfsk_mod = digital.gfsk_mod(
47 | samples_per_symbol=args.samples_per_symbol)
48 | self.connect(self.tx, self.gfsk_mod)
49 | self.connect(self.gfsk_mod, self.osmosdr_sink)
50 |
51 | # Receive chain
52 | dr = 0
53 | if args.data_rate == 1e6:
54 | dr = 1
55 | elif args.data_rate == 2e6:
56 | dr = 2
57 | self.rx = nordic.nordic_rx(
58 | args.channel, args.address_length, args.crc_length, dr)
59 | self.gfsk_demod = digital.gfsk_demod(
60 | samples_per_symbol=args.samples_per_symbol)
61 | self.lpf = filter.fir_filter_ccf(
62 | 1, firdes.low_pass_2(1, self.sample_rate, self.symbol_rate / 2, 50e3, 50))
63 | self.connect(self.osmosdr_source, self.lpf)
64 | self.connect(self.lpf, self.gfsk_demod)
65 | self.connect(self.gfsk_demod, self.rx)
66 |
67 | # Handle incoming packets
68 | self.nordictap_ack_handler = nordictap_ack_handler()
69 | self.msg_connect(self.rx, "nordictap_out",
70 | self.nordictap_ack_handler, "nordictap_in")
71 |
72 | # Reply with ACKs
73 | self.msg_connect(self.nordictap_ack_handler,
74 | "nordictap_out", self.tx, "nordictap_in")
75 |
76 |
77 | # Nordic Auto-ACK handler
78 | class nordictap_ack_handler(gr.sync_block):
79 |
80 | # Constructor
81 |
82 | def __init__(self):
83 | gr.sync_block.__init__(
84 | self, name="Nordictap Handler", in_sig=None, out_sig=None)
85 |
86 | # Received packet input port
87 | self.message_port_register_in(pmt.intern("nordictap_in"))
88 | self.set_msg_handler(
89 | pmt.intern("nordictap_in"), self.nordictap_handler)
90 |
91 | # ACK output port
92 | self.message_port_register_out(pmt.intern("nordictap_out"))
93 |
94 | # Handle incoming packets, and reply with ACKs
95 | def nordictap_handler(self, msg):
96 |
97 | # PMT to byte string
98 | data = pmt.to_python(msg).tostring()
99 |
100 | # Unpack the header
101 | values = struct.unpack('BBBBBBBB', data[0:8])
102 | channel = values[0]
103 | data_rate = values[1]
104 | address_length = values[2]
105 | payload_length = values[3]
106 | sequence_number = values[4]
107 | no_ack = values[5]
108 | crc_length = values[6]
109 |
110 | # Parse the address, payload, and crc
111 | address = data[7:7 + address_length]
112 | payload = data[7 + address_length:7 + address_length + payload_length]
113 | crc = data[7 + address_length + payload_length:
114 | 7 + address_length + payload_length + crc_length]
115 |
116 | # ACK if needed
117 | if payload_length > 0 and no_ack == 0:
118 |
119 | # Print the channel, sequence number, address and payload
120 | print "ACK'd Packet: ",
121 | print 'CH=' + str(2400 + channel),
122 | print 'SEQ=' + str(sequence_number),
123 | print 'ADDR=' + ':'.join('%02X' % ord(b) for b in address),
124 | print 'PLD=' + ':'.join('%02X' % ord(b) for b in payload),
125 | print 'CRC=' + ':'.join('%02X' % ord(b) for b in crc)
126 |
127 | # Build an ACK
128 | nordictap = [0] + [4, 2, 5, 0, sequence_number, 0, 2]
129 | for c in address:
130 | nordictap.append(ord(c))
131 |
132 | # Transmit an ACK
133 | vec = pmt.make_u8vector(len(nordictap), 0)
134 | for x in range(len(nordictap)):
135 | pmt.u8vector_set(vec, x, nordictap[x])
136 | self.message_port_pub(pmt.intern("nordictap_out"), vec)
137 |
138 |
139 | def main():
140 |
141 | # Parse command line arguments
142 | parser = argparse.ArgumentParser('Nordic Auto-ACK Example',
143 | formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=50, width=120))
144 | parser.add_argument(
145 | '-c', '--channel', type=int, help='RF channel (0-125)', default=4)
146 | parser.add_argument('-r', '--data_rate', type=float,
147 | help='Data Rate (250e3, 1e6 or 2e6', default=2e6, choices=[250e3, 1e6, 2e6])
148 | parser.add_argument('-l', '--crc_length', type=int,
149 | help='CRC Length (1-2)', default=2, choices=[1, 2])
150 | parser.add_argument('-a', '--address_length', type=int,
151 | help='Address Length (3-5)', default=5, choices=[3, 4, 5])
152 | parser.add_argument('-s', '--samples_per_symbol',
153 | type=int, help='Samples Per Symbol', default=2)
154 | parser.add_argument(
155 | '-g', '--gain', type=float, help='Radio Gain', default=80)
156 |
157 | args = parser.parse_args()
158 |
159 | tb = top_block(args)
160 | tb.start()
161 | try:
162 | raw_input('Press Enter to quit: ')
163 | except EOFError:
164 | pass
165 | tb.stop()
166 | tb.wait()
167 |
168 |
169 | if __name__ == '__main__':
170 | main()
171 |
--------------------------------------------------------------------------------
/examples/nordic_channelized_receiver.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 |
3 | from gnuradio import gr, blocks, digital, filter
4 | from gnuradio.filter import firdes
5 | import thread
6 | import nordic
7 | import pmt
8 | import struct
9 | import time
10 | import numpy
11 | import array
12 | import osmosdr
13 | import argparse
14 | from bitstring import BitArray
15 | from gnuradio import uhd
16 | from Queue import Queue
17 |
18 |
19 | class top_block(gr.top_block):
20 |
21 | def __init__(self, args):
22 | gr.top_block.__init__(self, "Nordic Single-Channel Receiver Example")
23 |
24 | self.freq = 2414e6
25 | self.gain = args.gain
26 | self.symbol_rate = 2e6
27 | self.sample_rate = 4e6
28 |
29 | # Channel map
30 | channel_count = 3
31 | channel_map = [14, 18, 10]
32 |
33 | # Data rate index
34 | dr = 2 # 2M
35 |
36 | # SDR source (gr-osmosdr source)
37 | self.osmosdr_source = osmosdr.source()
38 | self.osmosdr_source.set_sample_rate(self.sample_rate * channel_count)
39 | self.osmosdr_source.set_center_freq(self.freq)
40 | self.osmosdr_source.set_gain(self.gain)
41 | self.osmosdr_source.set_antenna('TX/RX')
42 |
43 | # PFB channelizer
44 | taps = firdes.low_pass_2(
45 | 1, self.sample_rate, self.symbol_rate / 2, 100e3, 30)
46 | self.channelizer = filter.pfb_channelizer_ccf(channel_count, taps, 1)
47 |
48 | # Stream to streams (PFB channelizer input)
49 | self.s2ss = blocks.stream_to_streams(
50 | gr.sizeof_gr_complex, channel_count)
51 | self.connect(self.osmosdr_source, self.s2ss)
52 |
53 | # Demodulators and packet deframers
54 | self.nordictap_printer = nordictap_printer()
55 | self.demods = []
56 | self.rxs = []
57 | for x in range(channel_count):
58 | self.connect((self.s2ss, x), (self.channelizer, x))
59 | self.demods.append(digital.gfsk_demod())
60 | self.rxs.append(nordic.nordic_rx(x, 5, 2, dr))
61 | self.connect((self.channelizer, x), self.demods[x])
62 | self.connect(self.demods[x], self.rxs[x])
63 | self.msg_connect(
64 | self.rxs[x], "nordictap_out", self.nordictap_printer, "nordictap_in")
65 |
66 |
67 | # Nordic Printer
68 | class nordictap_printer(gr.sync_block):
69 |
70 | # Constructor
71 |
72 | def __init__(self):
73 | gr.sync_block.__init__(
74 | self, name="Nordictap Printer", in_sig=None, out_sig=None)
75 |
76 | # Received packet input port
77 | self.message_port_register_in(pmt.intern("nordictap_in"))
78 | self.set_msg_handler(
79 | pmt.intern("nordictap_in"), self.nordictap_handler)
80 |
81 | # Handle incoming packets, and print payloads
82 | def nordictap_handler(self, msg):
83 |
84 | # PMT to byte string
85 | data = pmt.to_python(msg).tostring()
86 |
87 | # Unpack the header
88 | values = struct.unpack('BBBBBBBB', data[0:8])
89 | channel = values[0]
90 | data_rate = values[1]
91 | address_length = values[2]
92 | payload_length = values[3]
93 | sequence_number = values[4]
94 | no_ack = values[5]
95 | crc_length = values[6]
96 |
97 | # Parse the address, payload, and crc
98 | address = data[7:7 + address_length]
99 | payload = data[7 + address_length:7 + address_length + payload_length]
100 | crc = data[7 + address_length + payload_length:
101 | 7 + address_length + payload_length + crc_length]
102 |
103 | # Print the channel, sequence number, address and payload
104 | print 'CH=' + str(2400 + channel),
105 | print 'SEQ=' + str(sequence_number),
106 | print 'ADDR=' + ':'.join('%02X' % ord(b) for b in address),
107 | print 'PLD=' + ':'.join('%02X' % ord(b) for b in payload),
108 | print 'CRC=' + ':'.join('%02X' % ord(b) for b in crc)
109 |
110 |
111 | def main():
112 |
113 | # Parse command line arguments
114 | parser = argparse.ArgumentParser('Nordic Channelized Receiver Example',
115 | formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=50, width=120))
116 | parser.add_argument(
117 | '-g', '--gain', type=float, help='Radio Gain', default=30)
118 |
119 | args = parser.parse_args()
120 |
121 | tb = top_block(args)
122 | tb.start()
123 | try:
124 | raw_input('Press Enter to quit: ')
125 | except EOFError:
126 | pass
127 | tb.stop()
128 | tb.wait()
129 |
130 |
131 | if __name__ == '__main__':
132 | main()
133 |
--------------------------------------------------------------------------------
/examples/nordic_channelized_transmitter.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 |
3 | from gnuradio import gr, blocks, digital, filter
4 | from gnuradio.filter import firdes
5 | import thread
6 | import nordic
7 | import pmt
8 | import struct
9 | import time
10 | import numpy
11 | import array
12 | import random
13 | import osmosdr
14 | import argparse
15 | from bitstring import BitArray
16 | from gnuradio import uhd
17 | from Queue import Queue
18 |
19 |
20 | class top_block(gr.top_block):
21 |
22 | def __init__(self, args):
23 | gr.top_block.__init__(self, "Nordic Single-Channel Receiver Example")
24 |
25 | self.freq = 2414e6
26 | self.gain = args.gain
27 | self.symbol_rate = 2e6
28 | self.sample_rate = 4e6
29 |
30 | # Channel map
31 | channel_count = 3
32 | channel_map = [14, 18, 10]
33 |
34 | # Data rate index
35 | dr = 2 # 2M
36 |
37 | # SDR sink (gr-osmosdr sink)
38 | self.osmosdr_sink = osmosdr.sink()
39 | self.osmosdr_sink.set_sample_rate(self.sample_rate * channel_count)
40 | self.osmosdr_sink.set_center_freq(self.freq)
41 | self.osmosdr_sink.set_gain(self.gain)
42 | self.osmosdr_sink.set_antenna('TX/RX')
43 |
44 | # PFB channelizer
45 | taps = firdes.low_pass_2(
46 | 1, self.sample_rate, self.symbol_rate / 2, 100e3, 30)
47 | self.synthesizer = filter.pfb_synthesizer_ccf(channel_count, taps)
48 |
49 | # Modulators and packet framers
50 | self.nordictap_transmitter = nordictap_transmitter(channel_map)
51 | self.mods = []
52 | self.tx = nordic.nordic_tx(channel_count)
53 | for x in range(channel_count):
54 | self.mods.append(digital.gfsk_mod())
55 | self.connect((self.tx, x), self.mods[x])
56 | self.connect(self.mods[x], (self.synthesizer, x))
57 | self.connect(self.synthesizer, self.osmosdr_sink)
58 |
59 | # Wire up output packet connection
60 | self.msg_connect(self.nordictap_transmitter,
61 | "nordictap_out", self.tx, "nordictap_in")
62 |
63 |
64 | # Nordic transmitter strobe
65 | class nordictap_transmitter(gr.sync_block):
66 |
67 | # Constructor
68 |
69 | def __init__(self, channel_map):
70 | gr.sync_block.__init__(
71 | self, name="Nordictap Printer/Transmitter", in_sig=None, out_sig=None)
72 |
73 | self.channel_map = channel_map
74 |
75 | # Packet output port
76 | self.message_port_register_out(pmt.intern("nordictap_out"))
77 |
78 | # Transmit a packet
79 | def transmit(self, address, payload, channel_index, sequence_number):
80 |
81 | channel = self.channel_map[channel_index]
82 |
83 | # Build a payload
84 | nordictap = [channel_index] + [
85 | channel, 2, len(address), len(payload), sequence_number, 0, 2]
86 | for c in address:
87 | nordictap.append(ord(c))
88 | for c in payload:
89 | nordictap.append(ord(c))
90 |
91 | # Transmit packet
92 | vec = pmt.make_u8vector(len(nordictap), 0)
93 | for x in range(len(nordictap)):
94 | pmt.u8vector_set(vec, x, nordictap[x])
95 | self.message_port_pub(pmt.intern("nordictap_out"), vec)
96 |
97 |
98 | def main():
99 |
100 | # Parse command line arguments
101 | parser = argparse.ArgumentParser('Nordic Channelized Transmitter Example',
102 | formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=50, width=120))
103 | parser.add_argument(
104 | '-g', '--gain', type=float, help='Radio Gain', default=30)
105 |
106 | args = parser.parse_args()
107 |
108 | tb = top_block(args)
109 | tb.start()
110 |
111 | # Transmit some packets, hopping between three channels
112 | address = '\x11\x22\x11\x22\x11'
113 | payload = '\x55\x44\x33\x22\x11'
114 | sequence_number = 0
115 | while True:
116 | for x in range(3):
117 | tb.nordictap_transmitter.transmit(
118 | address, payload, x, sequence_number)
119 | sequence_number += 1
120 | if sequence_number > 3:
121 | sequence_number = 0
122 | time.sleep(0.1)
123 |
124 | try:
125 | raw_input('Press Enter to quit: ')
126 | except EOFError:
127 | pass
128 | tb.stop()
129 | tb.wait()
130 |
131 |
132 | if __name__ == '__main__':
133 | main()
134 |
--------------------------------------------------------------------------------
/examples/nordic_receiver.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 |
3 | from gnuradio import gr, blocks, digital, filter
4 | from gnuradio.filter import firdes
5 | import thread
6 | import nordic
7 | import pmt
8 | import struct
9 | import time
10 | import numpy
11 | import array
12 | import osmosdr
13 | import argparse
14 | from bitstring import BitArray
15 | from gnuradio import uhd
16 | from Queue import Queue
17 |
18 |
19 | class top_block(gr.top_block):
20 |
21 | def __init__(self, args):
22 | gr.top_block.__init__(self, "Nordic Single-Channel Receiver Example")
23 |
24 | # SDR configuration
25 | self.freq = 2400e6 + args.channel * 1e6
26 | self.gain = args.gain
27 | self.symbol_rate = args.data_rate
28 | self.sample_rate = args.data_rate * args.samples_per_symbol
29 |
30 | # SDR source (gr-osmosdr source)_tx_queue.push(msg);
31 | self.osmosdr_source = osmosdr.source()
32 | self.osmosdr_source.set_sample_rate(self.sample_rate)
33 | self.osmosdr_source.set_center_freq(self.freq)
34 | self.osmosdr_source.set_gain(self.gain)
35 | self.osmosdr_source.set_antenna('TX/RX')
36 |
37 | # Receive chain
38 | dr = 0
39 | if args.data_rate == 1e6:
40 | dr = 1
41 | elif args.data_rate == 2e6:
42 | dr = 2
43 | self.rx = nordic.nordic_rx(
44 | args.channel, args.address_length, args.crc_length, dr)
45 | self.gfsk_demod = digital.gfsk_demod(
46 | samples_per_symbol=args.samples_per_symbol)
47 | self.lpf = filter.fir_filter_ccf(
48 | 1, firdes.low_pass_2(1, self.sample_rate, self.symbol_rate / 2, 50e3, 50))
49 | self.connect(self.osmosdr_source, self.lpf)
50 | self.connect(self.lpf, self.gfsk_demod)
51 | self.connect(self.gfsk_demod, self.rx)
52 |
53 | # Handle incoming packets
54 | self.nordictap_printer = nordictap_printer()
55 | self.msg_connect(
56 | self.rx, "nordictap_out", self.nordictap_printer, "nordictap_in")
57 |
58 |
59 | # Nordic Printer
60 | class nordictap_printer(gr.sync_block):
61 |
62 | # Constructor
63 |
64 | def __init__(self):
65 | gr.sync_block.__init__(
66 | self, name="Nordictap Handler", in_sig=None, out_sig=None)
67 |
68 | # Received packet input port
69 | self.message_port_register_in(pmt.intern("nordictap_in"))
70 | self.set_msg_handler(
71 | pmt.intern("nordictap_in"), self.nordictap_handler)
72 |
73 | # Handle incoming packets, and print payloads
74 | def nordictap_handler(self, msg):
75 |
76 | # PMT to byte string
77 | data = pmt.to_python(msg).tostring()
78 |
79 | # Unpack the header
80 | values = struct.unpack('BBBBBBBB', data[0:8])
81 | channel = values[0]
82 | data_rate = values[1]
83 | address_length = values[2]
84 | payload_length = values[3]
85 | sequence_number = values[4]
86 | no_ack = values[5]
87 | crc_length = values[6]
88 |
89 | # Parse the address, payload, and crc
90 | address = data[7:7 + address_length]
91 | payload = data[7 + address_length:7 + address_length + payload_length]
92 | crc = data[7 + address_length + payload_length:
93 | 7 + address_length + payload_length + crc_length]
94 |
95 | # Print the channel, sequence number, address and payload
96 | print 'CH=' + str(2400 + channel),
97 | print 'SEQ=' + str(sequence_number),
98 | print 'ADDR=' + ':'.join('%02X' % ord(b) for b in address),
99 | print 'PLD=' + ':'.join('%02X' % ord(b) for b in payload),
100 | print 'CRC=' + ':'.join('%02X' % ord(b) for b in crc)
101 |
102 |
103 | def main():
104 |
105 | # Parse command line arguments
106 | parser = argparse.ArgumentParser('Nordic Single-Channel Receiver Example',
107 | formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=50, width=120))
108 | parser.add_argument(
109 | '-c', '--channel', type=int, help='RF channel (0-125)', default=4)
110 | parser.add_argument('-r', '--data_rate', type=float,
111 | help='Data Rate (250e3, 1e6 or 2e6', default=2e6, choices=[250e3, 1e6, 2e6])
112 | parser.add_argument('-l', '--crc_length', type=int,
113 | help='CRC Length (1-2)', default=2, choices=[1, 2])
114 | parser.add_argument('-a', '--address_length', type=int,
115 | help='Address Length (3-5)', default=5, choices=[3, 4, 5])
116 | parser.add_argument('-s', '--samples_per_symbol',
117 | type=int, help='Samples Per Symbol', default=2)
118 | parser.add_argument(
119 | '-g', '--gain', type=float, help='Radio Gain', default=80)
120 |
121 | args = parser.parse_args()
122 |
123 | tb = top_block(args)
124 | tb.start()
125 | try:
126 | raw_input('Press Enter to quit: ')
127 | except EOFError:
128 | pass
129 | tb.stop()
130 | tb.wait()
131 |
132 |
133 | if __name__ == '__main__':
134 | main()
135 |
--------------------------------------------------------------------------------
/examples/nordic_sniffer_scanner.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 |
3 | from gnuradio import gr, blocks, digital, filter
4 | from gnuradio.filter import firdes
5 | import thread
6 | import osmosdr
7 | import nordic
8 | import pmt
9 | import struct
10 | import time
11 |
12 |
13 | class top_block(gr.top_block):
14 |
15 | def __init__(self):
16 | gr.top_block.__init__(self, "AirHogs Sync Framer Example")
17 |
18 | # SDR configuration
19 | self.freq = 2402e6
20 | self.gain = 70
21 | self.symbol_rate = 2e6
22 | self.sample_rate = 4e6
23 |
24 | # SDR source (gr-osmosdr source)
25 | self.osmosdr_source = osmosdr.source()
26 | self.osmosdr_source.set_sample_rate(self.sample_rate)
27 | self.osmosdr_source.set_center_freq(self.freq)
28 | self.osmosdr_source.set_gain(self.gain)
29 | self.osmosdr_source.set_antenna('TX/RX')
30 |
31 | # Low pass filter
32 | self.lpf = filter.fir_filter_ccf(
33 | 1, firdes.low_pass_2(1, self.sample_rate, self.symbol_rate / 2, 50e3, 50))
34 |
35 | # GFSK demod, defaults to 2 samples per symbol
36 | self.gfsk_demod = digital.gfsk_demod()
37 |
38 | # Nordic RX
39 | self.nordic_rx = nordic.nordic_rx(3, 5, 2, 2)
40 |
41 | # Connect the blocks
42 | self.connect((self.osmosdr_source, 0), (self.lpf, 0))
43 | self.connect((self.lpf, 0), (self.gfsk_demod, 0))
44 | self.connect((self.gfsk_demod, 0), (self.nordic_rx, 0))
45 |
46 | # Handle incoming packets
47 | self.nordictap_handler = microsoft_nordictap_handler(self)
48 | self.msg_connect(
49 | self.nordic_rx, "nordictap_out", self.nordictap_handler, "nordictap_in")
50 |
51 | # Tune the USRP by nRF24L channel number
52 | def set_channel(self, channel):
53 |
54 | new_channel = 2400e6 + channel * 1e6
55 | self.osmosdr_source.set_center_freq(2400e6 + channel * 1e6)
56 | self.nordic_rx.set_channel(channel)
57 |
58 |
59 | # Microsoft mouse nordictap handler
60 | class microsoft_nordictap_handler(gr.sync_block):
61 |
62 | def __init__(self, tb):
63 | gr.sync_block.__init__(
64 | self, name="Nordictap Handler", in_sig=None, out_sig=None)
65 |
66 | self.tb = tb
67 | self.message_port_register_in(pmt.intern("nordictap_in"))
68 | self.set_msg_handler(
69 | pmt.intern("nordictap_in"), self.nordictap_handler)
70 |
71 | # Tick / channel hopping state and logic
72 | self.last_rx = time.time()
73 | self.last_tune = time.time()
74 | self.ch_timeout = 0.4 # timeout a channel after 200ms
75 | self.last_ch = 0
76 | thread.start_new_thread(self.tick, ())
77 |
78 | # Channels and channel groups
79 | self.channels = range(2, 84)
80 |
81 | # 10ms tick
82 | def tick(self):
83 |
84 | while True:
85 |
86 | # Check for a stale channel
87 | if ((time.time() - self.last_rx) > self.ch_timeout * 5) and \
88 | ((time.time() - self.last_tune) > self.ch_timeout):
89 |
90 | self.last_ch += 1
91 | if self.last_ch >= len(self.channels):
92 | self.last_ch = 0
93 | print 'Tuning to 24%02i MHz' % self.channels[self.last_ch]
94 | self.last_tune = time.time()
95 | self.tb.set_channel(self.channels[self.last_ch])
96 |
97 | # Wait 10ms
98 | time.sleep(0.01)
99 |
100 | def nordictap_handler(self, msg):
101 |
102 | data = pmt.to_python(msg).tostring()
103 |
104 | # Unpack the header
105 | values = struct.unpack('BBBBBBB', data[0:7])
106 | channel = values[0]
107 | data_rate = values[1]
108 | address_length = values[2]
109 | payload_length = values[3]
110 | sequence_number = values[4]
111 | no_ack = values[5]
112 | crc_length = values[6]
113 |
114 | # Parse the address, payload, and crc
115 | address = data[7:7 + address_length]
116 | payload = data[7 + address_length:7 + address_length + payload_length]
117 | crc = data[7 + address_length + payload_length:
118 | 7 + address_length + payload_length + crc_length]
119 |
120 | self.last_rx = time.time()
121 |
122 | # Print the channel, sequence number, address and payload
123 | print 'CH=' + str(2400 + channel),
124 | print 'SEQ=' + str(sequence_number),
125 | print 'ADDR=' + ':'.join('%02X' % ord(b) for b in address),
126 | print 'PLD=' + ':'.join('%02X' % ord(b) for b in payload),
127 | print 'CRC=' + ':'.join('%02X' % ord(b) for b in crc)
128 |
129 |
130 | def main():
131 | tb = top_block()
132 | tb.start()
133 | try:
134 | raw_input('Press Enter to quit: ')
135 | except EOFError:
136 | pass
137 | tb.stop()
138 | tb.wait()
139 |
140 |
141 | if __name__ == '__main__':
142 | main()
143 |
--------------------------------------------------------------------------------
/grc/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2016 Bastille Networks
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 | install(FILES
16 | nordic_nordic_rx.xml
17 | nordic_nordic_tx.xml DESTINATION share/gnuradio/grc/blocks
18 | )
19 |
--------------------------------------------------------------------------------
/grc/nordic_nordic_rx.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | nordic_rx
4 | nordic_nordic_rx
5 | nordic
6 | import nordic
7 | nordic.nordic_rx()
8 |
13 |
14 | ...
15 | ...
16 | ...
17 |
18 |
19 |
24 |
25 | in
26 |
27 |
28 |
29 |
34 |
35 | out
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/grc/nordic_nordic_tx.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | nordic_tx
4 | nordic_nordic_tx
5 | nordic
6 | import nordic
7 | nordic.nordic_tx()
8 |
13 |
14 | ...
15 | ...
16 | ...
17 |
18 |
19 |
24 |
25 | in
26 |
27 |
28 |
29 |
34 |
35 | out
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/include/nordic/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2016 Bastille Networks
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 |
16 | ########################################################################
17 | # Install public header files
18 | ########################################################################
19 | install(FILES
20 | api.h
21 | nordic_rx.h
22 | nordic_tx.h DESTINATION include/nordic
23 | )
24 |
25 |
--------------------------------------------------------------------------------
/include/nordic/api.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2016 Bastille Networks
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | */
17 |
18 | #ifndef INCLUDED_NORDIC_API_H
19 | #define INCLUDED_NORDIC_API_H
20 |
21 | #include
22 |
23 | #ifdef gnuradio_nordic_EXPORTS
24 | # define NORDIC_API __GR_ATTR_EXPORT
25 | #else
26 | # define NORDIC_API __GR_ATTR_IMPORT
27 | #endif
28 |
29 | #endif /* INCLUDED_NORDIC_API_H */
30 |
--------------------------------------------------------------------------------
/include/nordic/nordic_rx.h:
--------------------------------------------------------------------------------
1 | /* -*- c++ -*- */
2 | /*
3 | * Copyright 2016 Bastille Networks
4 | *
5 | * This is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 3, or (at your option)
8 | * any later version.
9 | *
10 | * This software is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this software; see the file COPYING. If not, write to
17 | * the Free Software Foundation, Inc., 51 Franklin Street,
18 | * Boston, MA 02110-1301, USA.
19 | */
20 |
21 |
22 | #ifndef INCLUDED_NORDIC_NORDIC_RX_H
23 | #define INCLUDED_NORDIC_NORDIC_RX_H
24 |
25 | #include
26 | #include
27 |
28 | namespace gr {
29 | namespace nordic {
30 |
31 | /*!
32 | * \brief <+description of block+>
33 | * \ingroup nordic
34 | *
35 | */
36 | class NORDIC_API nordic_rx : virtual public gr::sync_block
37 | {
38 | public:
39 | typedef boost::shared_ptr sptr;
40 |
41 | /*!
42 | * \brief Return a shared_ptr to a new instance of nordic::nordic_rx.
43 | *
44 | * To avoid accidental use of raw pointers, nordic::nordic_rx's
45 | * constructor is in a private implementation
46 | * class. nordic::nordic_rx::make is the public interface for
47 | * creating new instances.
48 | */
49 | static sptr make(uint8_t channel=0,
50 | uint8_t address_length=5,
51 | uint8_t crc_length=2,
52 | uint8_t data_rate=0);
53 |
54 | // Channel getter/setter
55 | virtual uint8_t get_channel()=0;
56 | virtual void set_channel(uint8_t channel)=0;
57 | };
58 |
59 | } // namespace nordic
60 | } // namespace gr
61 |
62 | #endif /* INCLUDED_NORDIC_NORDIC_RX_H */
63 |
64 |
--------------------------------------------------------------------------------
/include/nordic/nordic_tx.h:
--------------------------------------------------------------------------------
1 | /* -*- c++ -*- */
2 | /*
3 | * Copyright 2016 Bastille Networks
4 | *
5 | * This is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 3, or (at your option)
8 | * any later version.
9 | *
10 | * This software is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this software; see the file COPYING. If not, write to
17 | * the Free Software Foundation, Inc., 51 Franklin Street,
18 | * Boston, MA 02110-1301, USA.
19 | */
20 |
21 |
22 | #ifndef INCLUDED_NORDIC_NORDIC_TX_H
23 | #define INCLUDED_NORDIC_NORDIC_TX_H
24 |
25 | #include
26 | #include
27 |
28 | namespace gr {
29 | namespace nordic {
30 |
31 | /*!
32 | * \brief <+description of block+>
33 | * \ingroup nordic
34 | *
35 | */
36 | class NORDIC_API nordic_tx : virtual public gr::sync_block
37 | {
38 | public:
39 | typedef boost::shared_ptr sptr;
40 |
41 | /*!
42 | * \brief Return a shared_ptr to a new instance of nordic::nordic_tx.
43 | *
44 | * To avoid accidental use of raw pointers, nordic::nordic_tx's
45 | * constructor is in a private implementation
46 | * class. nordic::nordic_tx::make is the public interface for
47 | * creating new instances.
48 | */
49 | static sptr make(uint8_t channel_count=1);
50 | };
51 |
52 | } // namespace nordic
53 | } // namespace gr
54 |
55 | #endif /* INCLUDED_NORDIC_NORDIC_TX_H */
56 |
57 |
--------------------------------------------------------------------------------
/lib/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2016 Bastille Networks
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 |
16 | ########################################################################
17 | # Setup library
18 | ########################################################################
19 | include(GrPlatform) #define LIB_SUFFIX
20 |
21 | include_directories(${Boost_INCLUDE_DIR})
22 | link_directories(${Boost_LIBRARY_DIRS})
23 | list(APPEND nordic_sources
24 | nordic_rx_impl.cc
25 | bit_shifting_byte_vector.cc
26 | nordic_tx_impl.cc
27 | enhanced_shockburst_packet.cc )
28 |
29 | set(nordic_sources "${nordic_sources}" PARENT_SCOPE)
30 | if(NOT nordic_sources)
31 | MESSAGE(STATUS "No C++ sources... skipping lib/")
32 | return()
33 | endif(NOT nordic_sources)
34 |
35 | add_library(gnuradio-nordic SHARED ${nordic_sources})
36 | target_link_libraries(gnuradio-nordic ${Boost_LIBRARIES} ${GNURADIO_ALL_LIBRARIES})
37 | set_target_properties(gnuradio-nordic PROPERTIES DEFINE_SYMBOL "gnuradio_nordic_EXPORTS")
38 |
39 | if(APPLE)
40 | set_target_properties(gnuradio-nordic PROPERTIES
41 | INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib"
42 | )
43 | endif(APPLE)
44 |
45 | ########################################################################
46 | # Install built library files
47 | ########################################################################
48 | install(TARGETS gnuradio-nordic
49 | LIBRARY DESTINATION lib${LIB_SUFFIX} # .so/.dylib file
50 | ARCHIVE DESTINATION lib${LIB_SUFFIX} # .lib file
51 | RUNTIME DESTINATION bin # .dll file
52 | )
53 |
54 | ########################################################################
55 | # Build and register unit test
56 | ########################################################################
57 | include(GrTest)
58 |
59 | include_directories(${CPPUNIT_INCLUDE_DIRS})
60 |
61 | list(APPEND test_nordic_sources
62 | ${CMAKE_CURRENT_SOURCE_DIR}/test_nordic.cc
63 | ${CMAKE_CURRENT_SOURCE_DIR}/qa_nordic.cc
64 | )
65 |
66 | add_executable(test-nordic ${test_nordic_sources})
67 |
68 | target_link_libraries(
69 | test-nordic
70 | ${GNURADIO_RUNTIME_LIBRARIES}
71 | ${Boost_LIBRARIES}
72 | ${CPPUNIT_LIBRARIES}
73 | gnuradio-nordic
74 | )
75 |
76 | GR_ADD_TEST(test_nordic test-nordic)
77 |
--------------------------------------------------------------------------------
/lib/bit_shifting_byte_vector.cc:
--------------------------------------------------------------------------------
1 | /* -*- c++ -*- */
2 | /*
3 | * Copyright 2016 Bastille Networks
4 | *
5 | * This is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 3, or (at your option)
8 | * any later version.
9 | *
10 | * This software is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this software; see the file COPYING. If not, write to
17 | * the Free Software Foundation, Inc., 51 Franklin Street,
18 | * Boston, MA 02110-1301, USA.
19 | */
20 |
21 |
22 | #include "bit_shifting_byte_vector.h"
23 |
24 | #include
25 |
26 | // Constructor
27 | bit_shifting_byte_vector::bit_shifting_byte_vector(int length) :
28 | m_length(length),
29 | m_previous_state_write(7),
30 | m_previous_state_read(0)
31 | {
32 | m_bytes = new unsigned char[m_length];
33 | for(int x = 0; x < 8; x++)
34 | m_previous_states[x] = new unsigned char[m_length];
35 | }
36 |
37 | // Copy constructor
38 | bit_shifting_byte_vector::bit_shifting_byte_vector(const bit_shifting_byte_vector ©)
39 | {
40 | m_length = copy.m_length;
41 | m_bytes = new unsigned char[m_length];
42 | memcpy(m_bytes, copy.m_bytes, m_length);
43 | for(int x = 0; x < 8; x++)
44 | {
45 | m_previous_states[x] = new unsigned char[m_length];
46 | memcpy(m_previous_states[x], copy.m_previous_states[x], m_length);
47 | }
48 | m_previous_state_write = copy.m_previous_state_write;
49 | m_previous_state_read = copy.m_previous_state_read;
50 | }
51 |
52 | // Destructor
53 | bit_shifting_byte_vector::~bit_shifting_byte_vector()
54 | {
55 | delete[] m_bytes;
56 | for(int x = 0; x < 8; x++)
57 | {
58 | delete[] m_previous_states[x];
59 | }
60 | }
61 |
62 | // Add a new bit
63 | void bit_shifting_byte_vector::add_bit(unsigned char bit)
64 | {
65 | // Update the previous state vector
66 | memcpy(m_previous_states[m_previous_state_write], m_bytes, m_length);
67 |
68 | // For the left m_length-1 bytes, we'll
69 | // use values from m_previous_states
70 | memcpy(m_bytes, m_previous_states[m_previous_state_read]+1, m_length - 1);
71 |
72 | // For the rightmost byte, we'll tack on
73 | // the the current new bit
74 | m_bytes[m_length - 1] = m_bytes[m_length - 1] << 1 | bit;
75 |
76 | // Update the previous state indices
77 | if(++m_previous_state_read > 7) m_previous_state_read = 0;
78 | if(++m_previous_state_write > 7) m_previous_state_write = 0;
79 | }
--------------------------------------------------------------------------------
/lib/bit_shifting_byte_vector.h:
--------------------------------------------------------------------------------
1 | /* -*- c++ -*- */
2 | /*
3 | * Copyright 2016 Bastille Networks
4 | *
5 | * This is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 3, or (at your option)
8 | * any later version.
9 | *
10 | * This software is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this software; see the file COPYING. If not, write to
17 | * the Free Software Foundation, Inc., 51 Franklin Street,
18 | * Boston, MA 02110-1301, USA.
19 | */
20 |
21 |
22 | #ifndef BIT_SHIFTING_BYTE_VECTOR_H
23 | #define BIT_SHIFTING_BYTE_VECTOR_H
24 |
25 | // Byte vector that can be added to one bit at a time
26 | class bit_shifting_byte_vector
27 | {
28 | public:
29 |
30 | // Constructor
31 | bit_shifting_byte_vector(int length);
32 |
33 | // Copy constructor
34 | bit_shifting_byte_vector(const bit_shifting_byte_vector ©);
35 |
36 | // Destructor
37 | ~bit_shifting_byte_vector();
38 |
39 | // Add a new bit
40 | void add_bit(unsigned char bit);
41 |
42 | // Get the byte array
43 | const unsigned char * bytes() { return m_bytes; }
44 |
45 | // Get a previous byte array state
46 | const unsigned char * bytes(int index)
47 | {
48 | index += m_previous_state_read;
49 | while(index < 0) index += 7;
50 | while(index > 7) index -= 7;
51 | return m_previous_states[index];
52 | }
53 |
54 | private:
55 |
56 | // Bytes - current state
57 | unsigned char * m_bytes;
58 |
59 | // Length, in bytes
60 | int m_length;
61 |
62 | // Bytes - previous 8 states
63 | unsigned char * m_previous_states[8];
64 |
65 | // Previous state index - write
66 | int m_previous_state_write;
67 |
68 | // Previous state index - read
69 | int m_previous_state_read;
70 | };
71 |
72 | #endif // BIT_SHIFTING_BYTE_VECTOR_H
73 |
--------------------------------------------------------------------------------
/lib/enhanced_shockburst_packet.cc:
--------------------------------------------------------------------------------
1 | /* -*- c++ -*- */
2 | /*
3 | * Copyright 2016 Bastille Networks
4 | *
5 | * This is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 3, or (at your option)
8 | * any later version.
9 | *
10 | * This software is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this software; see the file COPYING. If not, write to
17 | * the Free Software Foundation, Inc., 51 Franklin Street,
18 | * Boston, MA 02110-1301, USA.
19 | */
20 |
21 |
22 | #include
23 | #include
24 | #include
25 |
26 | #include "enhanced_shockburst_packet.h"
27 |
28 | enhanced_shockburst_packet::enhanced_shockburst_packet(uint8_t address_length,
29 | uint8_t payload_length,
30 | uint8_t sequence_number,
31 | uint8_t no_ack,
32 | uint8_t crc_length,
33 | uint8_t * address,
34 | uint8_t * payload
35 | ) :
36 | m_address_length(address_length),
37 | m_payload_length(payload_length),
38 | m_sequence_number(sequence_number),
39 | m_no_ack(no_ack),
40 | m_crc_length(crc_length)
41 | {
42 | // Allocate buffers
43 | m_address = new uint8_t[m_address_length];
44 | m_payload = new uint8_t[m_payload_length];
45 | m_crc = new uint8_t[m_crc_length];
46 |
47 | // Copy over address and payload
48 | memcpy(m_address, address, m_address_length);
49 | memcpy(m_payload, payload, m_payload_length);
50 |
51 | // Build the packet bytes
52 | const int blen = 3 /* preamble + PCF */ +
53 | m_crc_length +
54 | m_address_length +
55 | m_payload_length;
56 | m_packet_length_bytes = blen;
57 | m_packet_length_bits = blen*8;
58 | m_packet_bytes = new uint8_t[blen];
59 |
60 | // Preamble
61 | if((address[0] & 0x80) == 0x80) m_packet_bytes[0] = 0xAA;
62 | else m_packet_bytes[0] = 0x55;
63 |
64 | // Address
65 | memcpy(&m_packet_bytes[1], address, m_address_length);
66 |
67 | // PCF
68 | m_packet_bytes[1 + m_address_length] = (m_payload_length & 0x3F) << 2;
69 | m_packet_bytes[1 + m_address_length] |= (m_sequence_number & 0x3);
70 | m_packet_bytes[2 + m_address_length] = m_no_ack << 7;
71 |
72 | // Payload
73 | for(int b = 0; b < m_payload_length; b++)
74 | {
75 | m_packet_bytes[2 + m_address_length + b] |= (payload[b] >> 1);
76 | m_packet_bytes[3 + m_address_length + b] |= (payload[b] << 7);
77 | }
78 |
79 | // Calculate the CRC
80 | uint16_t crc = 0xFFFF;
81 | for(int b = 1; b < 7 + m_payload_length; b++) crc = crc_update(crc, m_packet_bytes[b]);
82 | crc = crc_update(crc, m_packet_bytes[7 + m_payload_length] & 0x80, 1);
83 | memcpy(m_crc, &crc, m_crc_length);
84 | m_packet_bytes[2 + m_address_length + m_payload_length] |= ((crc >> 9) & 0xFF);
85 | m_packet_bytes[3 + m_address_length + m_payload_length] |= ((crc >> 1) & 0xFF);
86 | m_packet_bytes[4 + m_address_length + m_payload_length] |= ((crc << 7) & 0x80);
87 | }
88 |
89 | // Destructur
90 | enhanced_shockburst_packet::~enhanced_shockburst_packet()
91 | {
92 | delete[] m_address;
93 | delete[] m_payload;
94 | delete[] m_crc;
95 | }
96 |
97 | // Attempt to parse a packet from some incoming bytes
98 | bool enhanced_shockburst_packet::try_parse(const uint8_t * bytes,
99 | const uint8_t * bytes_shifted,
100 | uint8_t address_length,
101 | uint8_t crc_length,
102 | enhanced_shockburst_packet *& packet)
103 | {
104 | // Read the payload length
105 | uint8_t payload_length = bytes[6] >> 2;
106 | if(payload_length > 32) return false;
107 |
108 | // Read the address
109 | uint8_t * address = new uint8_t[address_length];
110 | memcpy(address, &bytes[1], address_length);
111 |
112 | // Read the given CRC
113 | uint16_t crc_given;
114 | memcpy(&crc_given, &bytes_shifted[8 + payload_length], 2);
115 |
116 | // Calculate the CRC
117 | uint16_t crc = 0xFFFF;
118 | for(int b = 1; b < 7 + payload_length; b++) crc = crc_update(crc, bytes[b]);
119 | crc = crc_update(crc, bytes[7 + payload_length] & 0x80, 1);
120 | crc = htons(crc);
121 |
122 | // Validate the CRC
123 | if(memcmp(&crc, &crc_given, 2) != 0)
124 | {
125 | delete[] address;
126 | return false;
127 | }
128 |
129 | // Read the sequence number and no-ACK bit
130 | uint8_t seq = bytes[6] & 0x3;
131 | uint8_t no_ack = bytes[7] >> 7;
132 |
133 | // Read the payload
134 | uint8_t payload[32];
135 | memcpy(payload, &bytes_shifted[8], payload_length);
136 |
137 | // Update the fields
138 | packet = new enhanced_shockburst_packet(address_length, payload_length, seq, no_ack, crc_length, address, payload);
139 |
140 | // Cleanup
141 | delete[] address;
142 |
143 | return true;
144 | }
145 |
146 | // Print the packet details to standard out
147 | void enhanced_shockburst_packet::print()
148 | {
149 | printf("Address: ");
150 | for(int x = 0; x < m_address_length; x++) printf("%02X ", m_address[x]);
151 | printf("\n");
152 |
153 | printf("Payload: ");
154 | for(int x = 0; x < m_payload_length; x++) printf("%02X ", m_payload[x]);
155 | printf("\n");
156 |
157 | printf("CRC: ");
158 | for(int x = 0; x < m_crc_length; x++) printf("%02X ", m_crc[x]);
159 | printf("\n");
160 |
161 | printf("Bytes: ");
162 | for(int x = 0; x < m_packet_length_bytes; x++) printf("%02X ", m_packet_bytes[x]);
163 | printf("\n");
164 |
165 | printf("\n");
166 | }
167 |
168 | // Process a crc byte (or partial byte)
169 | uint16_t enhanced_shockburst_packet::crc_update (uint16_t crc, uint8_t data, uint8_t bits)
170 | {
171 | crc = crc ^ ((uint16_t)data << 8);
172 | for (int x = 0; x < bits; x++)
173 | {
174 | if(crc & 0x8000) crc = (crc << 1) ^ 0x1021;
175 | else crc <<= 1;
176 | }
177 | return crc;
178 | }
--------------------------------------------------------------------------------
/lib/enhanced_shockburst_packet.h:
--------------------------------------------------------------------------------
1 | /* -*- c++ -*- */
2 | /*
3 | * Copyright 2016 Bastille Networks
4 | *
5 | * This is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 3, or (at your option)
8 | * any later version.
9 | *
10 | * This software is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this software; see the file COPYING. If not, write to
17 | * the Free Software Foundation, Inc., 51 Franklin Street,
18 | * Boston, MA 02110-1301, USA.
19 | */
20 |
21 |
22 | #ifndef ENHANCED_SHOCKBURST_PACKET_H
23 | #define ENHANCED_SHOCKBURST_PACKET_H
24 |
25 | #include
26 |
27 | class enhanced_shockburst_packet
28 | {
29 | public:
30 |
31 | // Constructor
32 | enhanced_shockburst_packet(uint8_t address_length,
33 | uint8_t payload_length,
34 | uint8_t sequence_number,
35 | uint8_t no_ack,
36 | uint8_t crc_length,
37 | uint8_t * address,
38 | uint8_t * payload
39 | );
40 |
41 | // Destructur
42 | ~enhanced_shockburst_packet();
43 |
44 | // Attempt to parse a packet from some incoming bytes
45 | static bool try_parse(const uint8_t * bytes,
46 | const uint8_t * bytes_shifted,
47 | uint8_t address_length,
48 | uint8_t crc_length,
49 | enhanced_shockburst_packet *& packet);
50 |
51 | // Process a crc byte (or partial byte)
52 | static uint16_t crc_update (uint16_t crc, uint8_t data, uint8_t bits=8);
53 |
54 | // Print the packet details to standard out
55 | void print();
56 |
57 | // Getters
58 | const uint8_t payload_length() { return m_payload_length; }
59 | const uint8_t bytes_length() { return m_packet_length_bytes; }
60 | const uint8_t sequence_number() { return m_sequence_number; }
61 | const uint8_t no_ack() { return m_no_ack; }
62 | const uint8_t * address() { return m_address; }
63 | const uint8_t * payload() { return m_payload; }
64 | const uint8_t * crc() { return m_crc; }
65 | const uint8_t * bytes() { return m_packet_bytes; }
66 |
67 | private:
68 |
69 | // Address length
70 | uint8_t m_address_length;
71 |
72 | // Payload length
73 | uint8_t m_payload_length;
74 |
75 | // Packet length
76 | uint8_t m_packet_length_bytes;
77 | uint16_t m_packet_length_bits;
78 |
79 | // Sequence number (ESB)
80 | uint8_t m_sequence_number;
81 |
82 | // No ACK bit (ESB)
83 | bool m_no_ack;
84 |
85 | // CRC length
86 | uint8_t m_crc_length;
87 |
88 | // Address
89 | uint8_t * m_address;
90 |
91 | // Payload
92 | uint8_t * m_payload;
93 |
94 | // CRC
95 | uint8_t * m_crc;
96 |
97 | // Assembled packet bytes
98 | uint8_t * m_packet_bytes;
99 |
100 | } __attribute__((packed));
101 |
102 | #endif // ENHANCED_SHOCKBURST_PACKET_H
--------------------------------------------------------------------------------
/lib/nordic_rx_impl.cc:
--------------------------------------------------------------------------------
1 | /* -*- c++ -*- */
2 | /*
3 | * Copyright 2016 Bastille Networks.
4 | *
5 | * This is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 3, or (at your option)
8 | * any later version.
9 | *
10 | * This software is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this software; see the file COPYING. If not, write to
17 | * the Free Software Foundation, Inc., 51 Franklin Street,
18 | * Boston, MA 02110-1301, USA.
19 | */
20 |
21 | #ifdef HAVE_CONFIG_H
22 | #include "config.h"
23 | #endif
24 |
25 | #include
26 | #include
27 | #include
28 | #include "nordic_rx_impl.h"
29 | #include "nordictap.h"
30 |
31 | namespace gr {
32 | namespace nordic {
33 |
34 | nordic_rx::sptr
35 | nordic_rx::make(uint8_t channel,
36 | uint8_t address_length,
37 | uint8_t crc_length,
38 | uint8_t data_rate)
39 | {
40 | return gnuradio::get_initial_sptr
41 | (new nordic_rx_impl(channel, address_length, crc_length, data_rate));
42 | }
43 |
44 | /*
45 | * The private constructor
46 | */
47 | nordic_rx_impl::nordic_rx_impl(uint8_t channel,
48 | uint8_t address_length,
49 | uint8_t crc_length,
50 | uint8_t data_rate)
51 | : gr::sync_block("nordic_rx",
52 | gr::io_signature::make(1, 1, sizeof(uint8_t)),
53 | gr::io_signature::make(0, 0, 0)),
54 | m_decoded_bits_bytes(42*8 /* buffer sufficient for max ESB frame length */),
55 | m_crc_length(crc_length),
56 | m_address_length(address_length),
57 | m_channel(channel),
58 | m_data_rate(data_rate)
59 | {
60 | message_port_register_out(pmt::mp("nordictap_out"));
61 | }
62 |
63 | /*
64 | * Our virtual destructor.
65 | */
66 | nordic_rx_impl::~nordic_rx_impl()
67 | {
68 |
69 | }
70 |
71 | int
72 | nordic_rx_impl::work(int noutput_items,
73 | gr_vector_const_void_star &input_items,
74 | gr_vector_void_star &output_items)
75 | {
76 | const uint8_t *in = (const uint8_t *) input_items[0];
77 |
78 | // Step through the incoming demodulated bits
79 | for(int x = 0; x < noutput_items; x++)
80 | {
81 | // Add the incoming bit to the bit shifted byte array
82 | m_decoded_bits_bytes.add_bit(in[x]);
83 | const uint8_t * bytes = m_decoded_bits_bytes.bytes();
84 |
85 | // Check for a valid preamble
86 | if(bytes[0] == 0xAA || bytes[0] == 0x55)
87 | {
88 | // Check for a valid first address bit
89 | if((bytes[0] & 0x80) == (bytes[1] & 0x80))
90 | {
91 | // Attempt to decode a payload
92 | if(enhanced_shockburst_packet::try_parse(bytes,
93 | m_decoded_bits_bytes.bytes(0),
94 | m_address_length,
95 | m_crc_length,
96 | m_enhanced_shockburst))
97 | {
98 | // Build the wireshark header
99 | nordictap_header header;
100 | header.channel = m_channel;
101 | header.data_rate = m_data_rate;
102 | header.address_length = m_address_length;
103 | header.payload_length = m_enhanced_shockburst->payload_length();
104 | header.sequence_number = m_enhanced_shockburst->sequence_number();
105 | header.no_ack = m_enhanced_shockburst->no_ack();
106 | header.crc_length = m_crc_length;
107 |
108 | // Concatenate the header, address, payload, and CRC
109 | uint8_t buffer_length = sizeof(nordictap_header) + m_address_length + header.payload_length + m_crc_length;
110 | uint8_t * buffer = new uint8_t[buffer_length];
111 | memcpy(&buffer[0], &header, sizeof(nordictap_header));
112 | memcpy(&buffer[sizeof(nordictap_header)], m_enhanced_shockburst->address(), m_address_length);
113 | memcpy(&buffer[sizeof(nordictap_header) + m_address_length], m_enhanced_shockburst->payload(), header.payload_length);
114 | memcpy(&buffer[sizeof(nordictap_header) + m_address_length + header.payload_length], m_enhanced_shockburst->crc(), m_crc_length);
115 |
116 | // Send the packet to wireshark
117 | boost::asio::io_service io_service;
118 | boost::asio::ip::udp::resolver resolver(io_service);
119 | boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), "127.0.0.1", "9451");
120 | boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query);
121 | boost::asio::ip::udp::socket socket(io_service);
122 | socket.open(boost::asio::ip::udp::v4());
123 | socket.send_to(boost::asio::buffer(buffer, buffer_length), receiver_endpoint);
124 |
125 | // Send the packet to nordictap_out
126 | message_port_pub(pmt::intern("nordictap_out"), pmt::init_u8vector(buffer_length, buffer));
127 |
128 | // Cleanup
129 | delete[] buffer;
130 | }
131 | }
132 | }
133 | }
134 |
135 | return noutput_items;
136 | }
137 |
138 | // Channel getter
139 | uint8_t nordic_rx_impl::get_channel()
140 | {
141 | return m_channel;
142 | }
143 |
144 | // Channel setter
145 | void nordic_rx_impl::set_channel(uint8_t channel)
146 | {
147 | m_channel = channel;
148 | }
149 |
150 | } /* namespace nordic */
151 | } /* namespace gr */
152 |
153 |
--------------------------------------------------------------------------------
/lib/nordic_rx_impl.h:
--------------------------------------------------------------------------------
1 | /* -*- c++ -*- */
2 | /*
3 | * Copyright 2016 Bastille Networks.
4 | *
5 | * This is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 3, or (at your option)
8 | * any later version.
9 | *
10 | * This software is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this software; see the file COPYING. If not, write to
17 | * the Free Software Foundation, Inc., 51 Franklin Street,
18 | * Boston, MA 02110-1301, USA.
19 | */
20 |
21 | #ifndef INCLUDED_NORDIC_NORDIC_RX_IMPL_H
22 | #define INCLUDED_NORDIC_NORDIC_RX_IMPL_H
23 |
24 | #include
25 | #include
26 | #include "bit_shifting_byte_vector.h"
27 | #include "enhanced_shockburst_packet.h"
28 |
29 | namespace gr {
30 | namespace nordic {
31 |
32 | class nordic_rx_impl : public nordic_rx
33 | {
34 | private:
35 |
36 | // CRC16-CCITT
37 | boost::crc_optimal<16, 0x1021, 0, 0, false, false> m_crc;
38 |
39 | // Configuration
40 | uint8_t m_address_length;
41 | uint8_t m_crc_length;
42 | uint8_t m_channel;
43 | uint8_t m_data_rate;
44 |
45 | // Incoming bit/byte vector
46 | bit_shifting_byte_vector m_decoded_bits_bytes;
47 |
48 | // Enhanced shockburst packet
49 | enhanced_shockburst_packet * m_enhanced_shockburst;
50 |
51 | public:
52 |
53 | // Constructor/destructor
54 | nordic_rx_impl(uint8_t channel,
55 | uint8_t address_length,
56 | uint8_t crc_length,
57 | uint8_t data_rate);
58 | ~nordic_rx_impl();
59 |
60 | // Main work method
61 | int work(int noutput_items,
62 | gr_vector_const_void_star &input_items,
63 | gr_vector_void_star &output_items);
64 |
65 | // Channel getter/setter
66 | uint8_t get_channel();
67 | void set_channel(uint8_t channel);
68 | };
69 |
70 | } // namespace nordic
71 | } // namespace gr
72 |
73 | #endif /* INCLUDED_NORDIC_NORDIC_RX_IMPL_H */
74 |
75 |
--------------------------------------------------------------------------------
/lib/nordic_tx_impl.cc:
--------------------------------------------------------------------------------
1 | /* -*- c++ -*- */
2 | /*
3 | * Copyright 2016 Bastille Networks.
4 | *
5 | * This is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 3, or (at your option)
8 | * any later version.
9 | *
10 | * This software is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this software; see the file COPYING. If not, write to
17 | * the Free Software Foundation, Inc., 51 Franklin Street,
18 | * Boston, MA 02110-1301, USA.
19 | */
20 |
21 | #ifdef HAVE_CONFIG_H
22 | #include "config.h"
23 | #endif
24 |
25 | #include
26 | #include
27 | #include "nordic_tx_impl.h"
28 | #include "nordictap.h"
29 | #include "enhanced_shockburst_packet.h"
30 |
31 | namespace gr {
32 | namespace nordic {
33 |
34 | nordic_tx::sptr
35 | nordic_tx::make(uint8_t channel_count)
36 | {
37 | return gnuradio::get_initial_sptr
38 | (new nordic_tx_impl(channel_count));
39 | }
40 |
41 | /*
42 | * The private constructor
43 | */
44 | nordic_tx_impl::nordic_tx_impl(uint8_t channel_count)
45 | : gr::sync_block("nordic_tx",
46 | gr::io_signature::make(0, 0, 0),
47 | gr::io_signature::make(1, channel_count, sizeof(uint8_t))),
48 | m_channel_count(channel_count)
49 | {
50 | // Register nordictap input, which accepts packets to transmit
51 | message_port_register_in(pmt::intern("nordictap_in"));
52 | set_msg_handler(pmt::intern("nordictap_in"), boost::bind(&nordic_tx_impl::nordictap_message_handler, this, _1));
53 | }
54 |
55 | /*
56 | * Our virtual destructor.
57 | */
58 | nordic_tx_impl::~nordic_tx_impl()
59 | {
60 | }
61 |
62 | // Incoming message handler
63 | void nordic_tx_impl::nordictap_message_handler(pmt::pmt_t msg)
64 | {
65 | m_tx_queue.push(msg);
66 | }
67 |
68 | int
69 | nordic_tx_impl::work(int noutput_items,
70 | gr_vector_const_void_star &input_items,
71 | gr_vector_void_star &output_items)
72 | {
73 | // uint8_t *out = (uint8_t *) output_items[0];
74 |
75 | // Check for new input
76 | if(m_tx_queue.size())
77 | {
78 | // Get the blob
79 | std::vector vec = pmt::u8vector_elements(m_tx_queue.front());
80 | uint8_t * blob = vec.data();
81 |
82 | // Read the channel index
83 | uint8_t channel = blob[0];
84 |
85 | // Read the nordictap header, address, and payload
86 | nordictap_header header;
87 | memcpy(&header, &blob[1], sizeof(nordictap_header));
88 |
89 | // Read the address and payload
90 | const uint8_t alen = header.address_length;
91 | const uint8_t plen = header.payload_length;
92 | uint8_t * address = new uint8_t[alen];
93 | uint8_t * payload = new uint8_t[plen];
94 | memcpy(address, &blob[sizeof(nordictap_header)+1], alen);
95 | memcpy(payload, &blob[sizeof(nordictap_header)+1 + alen], plen);
96 |
97 | // Build the packet
98 | enhanced_shockburst_packet * packet =
99 | new enhanced_shockburst_packet(header.address_length,
100 | header.payload_length,
101 | header.sequence_number,
102 | header.no_ack,
103 | header.crc_length,
104 | address,
105 | payload);
106 |
107 | // Remove the blob from the queue
108 | m_tx_queue.pop();
109 |
110 | // Write the output bytes
111 | uint8_t * out = (uint8_t *)output_items[channel];
112 | for(int b = 0; b < packet->bytes_length(); b++)
113 | {
114 | out[b] = packet->bytes()[b];
115 | out[packet->bytes_length()*2+b] = packet->bytes()[b];
116 | }
117 |
118 | // Write zeros to the other channels' buffers
119 | for(int c = 0; c < m_channel_count; c++)
120 | {
121 | if(c != channel)
122 | {
123 | memset(output_items[c], 0, packet->bytes_length()*2);
124 | }
125 | }
126 |
127 | // Cleanup
128 | delete[] address;
129 | delete[] payload;
130 | delete packet;
131 |
132 | // Return the number of bytes produced
133 | return packet->bytes_length()*2;
134 | }
135 | else
136 | {
137 | return 0;
138 | }
139 | }
140 |
141 | // Process a crc byte (or partial byte)
142 | uint16_t nordic_tx_impl::crc_update (uint16_t crc, uint8_t data, uint8_t bits)
143 | {
144 | crc = crc ^ ((uint16_t)data << 8);
145 | for (int x = 0; x < bits; x++)
146 | {
147 | if(crc & 0x8000) crc = (crc << 1) ^ 0x1021;
148 | else crc <<= 1;
149 | }
150 | return crc;
151 | }
152 |
153 | } /* namespace nordic */
154 | } /* namespace gr */
155 |
156 |
--------------------------------------------------------------------------------
/lib/nordic_tx_impl.h:
--------------------------------------------------------------------------------
1 | /* -*- c++ -*- */
2 | /*
3 | * Copyright 2016 Bastille Networks.
4 | *
5 | * This is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 3, or (at your option)
8 | * any later version.
9 | *
10 | * This software is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this software; see the file COPYING. If not, write to
17 | * the Free Software Foundation, Inc., 51 Franklin Street,
18 | * Boston, MA 02110-1301, USA.
19 | */
20 |
21 | #ifndef INCLUDED_NORDIC_NORDIC_TX_IMPL_H
22 | #define INCLUDED_NORDIC_NORDIC_TX_IMPL_H
23 |
24 | #include
25 | #include
26 |
27 | namespace gr {
28 | namespace nordic {
29 |
30 | class nordic_tx_impl : public nordic_tx
31 | {
32 | private:
33 |
34 | // TX nordictap queue
35 | std::queue m_tx_queue;
36 |
37 | // Lookup table to unpack bytes to bits (NRZ)
38 | char m_unpack_table[256][8];
39 |
40 | // Number of output channels
41 | uint8_t m_channel_count;
42 |
43 | // Incoming message handler
44 | void nordictap_message_handler(pmt::pmt_t msg);
45 |
46 | // Process a crc byte (or partial byte)
47 | uint16_t crc_update (uint16_t crc, uint8_t data, uint8_t bits=8);
48 |
49 | public:
50 | nordic_tx_impl(uint8_t channel_count);
51 | ~nordic_tx_impl();
52 |
53 | // Where all the action really happens
54 | int work(int noutput_items,
55 | gr_vector_const_void_star &input_items,
56 | gr_vector_void_star &output_items);
57 | };
58 |
59 | } // namespace nordic
60 | } // namespace gr
61 |
62 | #endif /* INCLUDED_NORDIC_NORDIC_TX_IMPL_H */
63 |
64 |
--------------------------------------------------------------------------------
/lib/nordictap.h:
--------------------------------------------------------------------------------
1 | #ifndef NORDICTAP_H
2 | #define NORDICTAP_H
3 |
4 | #define NORDICTAP_GSM_PORT 9451
5 |
6 | // Data rates
7 | #define NORDICTAP_RATE_250K 0
8 | #define NORDICTAP_RATE_1M 1
9 | #define NORDICTAP_RATE_2M 2
10 |
11 | struct nordictap_header
12 | {
13 | // Channel number
14 | uint8_t channel;
15 |
16 | // Data rate
17 | uint8_t data_rate;
18 |
19 | // Address length
20 | uint8_t address_length;
21 |
22 | // Payload length
23 | uint8_t payload_length;
24 |
25 | // Sequence number (ESB)
26 | uint8_t sequence_number;
27 |
28 | // No ACK bit (ESB)
29 | bool no_ack;
30 |
31 | // CRC length, in bytes
32 | uint8_t crc_length;
33 |
34 | } __attribute__((packed));
35 |
36 | #endif // NORDICTAP_H
--------------------------------------------------------------------------------
/lib/qa_nordic.cc:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2016 Bastille Networks
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | */
17 |
18 | /*
19 | * This class gathers together all the test cases for the gr-filter
20 | * directory into a single test suite. As you create new test cases,
21 | * add them here.
22 | */
23 |
24 | #include "qa_nordic.h"
25 |
26 | CppUnit::TestSuite *
27 | qa_nordic::suite()
28 | {
29 | CppUnit::TestSuite *s = new CppUnit::TestSuite("nordic");
30 |
31 | return s;
32 | }
33 |
--------------------------------------------------------------------------------
/lib/qa_nordic.h:
--------------------------------------------------------------------------------
1 | /* -*- c++ -*- */
2 | /*
3 | Copyright (C) 2016 Bastille Networks
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #ifndef _QA_NORDIC_H_
20 | #define _QA_NORDIC_H_
21 |
22 | #include
23 | #include
24 |
25 | //! collect all the tests for the gr-filter directory
26 |
27 | class __GR_ATTR_EXPORT qa_nordic
28 | {
29 | public:
30 | //! return suite of tests for all of gr-filter directory
31 | static CppUnit::TestSuite *suite();
32 | };
33 |
34 | #endif /* _QA_NORDIC_H_ */
35 |
--------------------------------------------------------------------------------
/lib/test_nordic.cc:
--------------------------------------------------------------------------------
1 | /* -*- c++ -*- */
2 | /*
3 | Copyright (C) 2016 Bastille Networks
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #ifdef HAVE_CONFIG_H
20 | #include "config.h"
21 | #endif
22 |
23 | #include
24 | #include
25 |
26 | #include
27 | #include "qa_nordic.h"
28 | #include
29 | #include
30 |
31 | int
32 | main (int argc, char **argv)
33 | {
34 | CppUnit::TextTestRunner runner;
35 | std::ofstream xmlfile(get_unittest_path("nordic.xml").c_str());
36 | CppUnit::XmlOutputter *xmlout = new CppUnit::XmlOutputter(&runner.result(), xmlfile);
37 |
38 | runner.addTest(qa_nordic::suite());
39 | runner.setOutputter(xmlout);
40 |
41 | bool was_successful = runner.run("", false);
42 |
43 | return was_successful ? 0 : 1;
44 | }
45 |
--------------------------------------------------------------------------------
/python/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2016 Bastille Networks
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 |
16 | ########################################################################
17 | # Include python install macros
18 | ########################################################################
19 | include(GrPython)
20 | if(NOT PYTHONINTERP_FOUND)
21 | return()
22 | endif()
23 |
24 | ########################################################################
25 | # Install python sources
26 | ########################################################################
27 | GR_PYTHON_INSTALL(
28 | FILES
29 | __init__.py
30 | DESTINATION ${GR_PYTHON_DIR}/nordic
31 | )
32 |
33 | ########################################################################
34 | # Handle the unit tests
35 | ########################################################################
36 | include(GrTest)
37 |
38 | set(GR_TEST_TARGET_DEPS gnuradio-nordic)
39 | set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig)
40 |
--------------------------------------------------------------------------------
/python/__init__.py:
--------------------------------------------------------------------------------
1 | '''
2 | Copyright (C) 2016 Bastille Networks
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | '''
17 |
18 | # The presence of this file turns this directory into a Python package
19 |
20 | '''
21 | This is the GNU Radio NORDIC module. Place your Python package
22 | description here (python/__init__.py).
23 | '''
24 |
25 | # import swig generated symbols into the nordic namespace
26 | try:
27 | # this might fail if the module is python-only
28 | from nordic_swig import *
29 | except ImportError:
30 | pass
31 |
32 | # import any pure python here
33 |
34 |
35 | #
36 |
--------------------------------------------------------------------------------
/python/build_utils.py:
--------------------------------------------------------------------------------
1 | '''
2 | Copyright (C) 2016 Bastille Networks
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | '''
17 |
18 | """Misc utilities used at build time
19 | """
20 |
21 | import re, os, os.path
22 | from build_utils_codes import *
23 |
24 |
25 | # set srcdir to the directory that contains Makefile.am
26 | try:
27 | srcdir = os.environ['srcdir']
28 | except KeyError, e:
29 | srcdir = "."
30 | srcdir = srcdir + '/'
31 |
32 | # set do_makefile to either true or false dependeing on the environment
33 | try:
34 | if os.environ['do_makefile'] == '0':
35 | do_makefile = False
36 | else:
37 | do_makefile = True
38 | except KeyError, e:
39 | do_makefile = False
40 |
41 | # set do_sources to either true or false dependeing on the environment
42 | try:
43 | if os.environ['do_sources'] == '0':
44 | do_sources = False
45 | else:
46 | do_sources = True
47 | except KeyError, e:
48 | do_sources = True
49 |
50 | name_dict = {}
51 |
52 | def log_output_name (name):
53 | (base, ext) = os.path.splitext (name)
54 | ext = ext[1:] # drop the leading '.'
55 |
56 | entry = name_dict.setdefault (ext, [])
57 | entry.append (name)
58 |
59 | def open_and_log_name (name, dir):
60 | global do_sources
61 | if do_sources:
62 | f = open (name, dir)
63 | else:
64 | f = None
65 | log_output_name (name)
66 | return f
67 |
68 | def expand_template (d, template_filename, extra = ""):
69 | '''Given a dictionary D and a TEMPLATE_FILENAME, expand template into output file
70 | '''
71 | global do_sources
72 | output_extension = extract_extension (template_filename)
73 | template = open_src (template_filename, 'r')
74 | output_name = d['NAME'] + extra + '.' + output_extension
75 | log_output_name (output_name)
76 | if do_sources:
77 | output = open (output_name, 'w')
78 | do_substitution (d, template, output)
79 | output.close ()
80 | template.close ()
81 |
82 | def output_glue (dirname):
83 | output_makefile_fragment ()
84 | output_ifile_include (dirname)
85 |
86 | def output_makefile_fragment ():
87 | global do_makefile
88 | if not do_makefile:
89 | return
90 | # overwrite the source, which must be writable; this should have been
91 | # checked for beforehand in the top-level Makefile.gen.gen .
92 | f = open (os.path.join (os.environ.get('gendir', os.environ.get('srcdir', '.')), 'Makefile.gen'), 'w')
93 | f.write ('#\n# This file is machine generated. All edits will be overwritten\n#\n')
94 | output_subfrag (f, 'h')
95 | output_subfrag (f, 'i')
96 | output_subfrag (f, 'cc')
97 | f.close ()
98 |
99 | def output_ifile_include (dirname):
100 | global do_sources
101 | if do_sources:
102 | f = open ('%s_generated.i' % (dirname,), 'w')
103 | f.write ('//\n// This file is machine generated. All edits will be overwritten\n//\n')
104 | files = name_dict.setdefault ('i', [])
105 | files.sort ()
106 | f.write ('%{\n')
107 | for file in files:
108 | f.write ('#include <%s>\n' % (file[0:-1] + 'h',))
109 | f.write ('%}\n\n')
110 | for file in files:
111 | f.write ('%%include <%s>\n' % (file,))
112 |
113 | def output_subfrag (f, ext):
114 | files = name_dict.setdefault (ext, [])
115 | files.sort ()
116 | f.write ("GENERATED_%s =" % (ext.upper ()))
117 | for file in files:
118 | f.write (" \\\n\t%s" % (file,))
119 | f.write ("\n\n")
120 |
121 | def extract_extension (template_name):
122 | # template name is something like: GrFIRfilterXXX.h.t
123 | # we return everything between the penultimate . and .t
124 | mo = re.search (r'\.([a-z]+)\.t$', template_name)
125 | if not mo:
126 | raise ValueError, "Incorrectly formed template_name '%s'" % (template_name,)
127 | return mo.group (1)
128 |
129 | def open_src (name, mode):
130 | global srcdir
131 | return open (os.path.join (srcdir, name), mode)
132 |
133 | def do_substitution (d, in_file, out_file):
134 | def repl (match_obj):
135 | key = match_obj.group (1)
136 | # print key
137 | return d[key]
138 |
139 | inp = in_file.read ()
140 | out = re.sub (r"@([a-zA-Z0-9_]+)@", repl, inp)
141 | out_file.write (out)
142 |
143 |
144 |
145 | copyright = '''/* -*- c++ -*- */
146 | /*
147 | Copyright (C) 2016 Bastille Networks
148 |
149 | This program is free software: you can redistribute it and/or modify
150 | it under the terms of the GNU General Public License as published by
151 | the Free Software Foundation, either version 3 of the License, or
152 | (at your option) any later version.
153 |
154 | This program is distributed in the hope that it will be useful,
155 | but WITHOUT ANY WARRANTY; without even the implied warranty of
156 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
157 | GNU General Public License for more details.
158 |
159 | You should have received a copy of the GNU General Public License
160 | along with this program. If not, see .
161 | */
162 | '''
163 |
164 | def is_complex (code3):
165 | if i_code (code3) == 'c' or o_code (code3) == 'c':
166 | return '1'
167 | else:
168 | return '0'
169 |
170 |
171 | def standard_dict (name, code3, package='gr'):
172 | d = {}
173 | d['NAME'] = name
174 | d['NAME_IMPL'] = name+'_impl'
175 | d['GUARD_NAME'] = 'INCLUDED_%s_%s_H' % (package.upper(), name.upper())
176 | d['GUARD_NAME_IMPL'] = 'INCLUDED_%s_%s_IMPL_H' % (package.upper(), name.upper())
177 | d['BASE_NAME'] = re.sub ('^' + package + '_', '', name)
178 | d['SPTR_NAME'] = '%s_sptr' % name
179 | d['WARNING'] = 'WARNING: this file is machine generated. Edits will be overwritten'
180 | d['COPYRIGHT'] = copyright
181 | d['TYPE'] = i_type (code3)
182 | d['I_TYPE'] = i_type (code3)
183 | d['O_TYPE'] = o_type (code3)
184 | d['TAP_TYPE'] = tap_type (code3)
185 | d['IS_COMPLEX'] = is_complex (code3)
186 | return d
187 |
188 |
189 | def standard_dict2 (name, code3, package):
190 | d = {}
191 | d['NAME'] = name
192 | d['BASE_NAME'] = name
193 | d['GUARD_NAME'] = 'INCLUDED_%s_%s_H' % (package.upper(), name.upper())
194 | d['WARNING'] = 'WARNING: this file is machine generated. Edits will be overwritten'
195 | d['COPYRIGHT'] = copyright
196 | d['TYPE'] = i_type (code3)
197 | d['I_TYPE'] = i_type (code3)
198 | d['O_TYPE'] = o_type (code3)
199 | d['TAP_TYPE'] = tap_type (code3)
200 | d['IS_COMPLEX'] = is_complex (code3)
201 | return d
202 |
203 | def standard_impl_dict2 (name, code3, package):
204 | d = {}
205 | d['NAME'] = name
206 | d['IMPL_NAME'] = name
207 | d['BASE_NAME'] = name.rstrip("impl").rstrip("_")
208 | d['GUARD_NAME'] = 'INCLUDED_%s_%s_H' % (package.upper(), name.upper())
209 | d['WARNING'] = 'WARNING: this file is machine generated. Edits will be overwritten'
210 | d['COPYRIGHT'] = copyright
211 | d['FIR_TYPE'] = "fir_filter_" + code3
212 | d['CFIR_TYPE'] = "fir_filter_" + code3[0:2] + 'c'
213 | d['TYPE'] = i_type (code3)
214 | d['I_TYPE'] = i_type (code3)
215 | d['O_TYPE'] = o_type (code3)
216 | d['TAP_TYPE'] = tap_type (code3)
217 | d['IS_COMPLEX'] = is_complex (code3)
218 | return d
219 |
--------------------------------------------------------------------------------
/python/build_utils_codes.py:
--------------------------------------------------------------------------------
1 | '''
2 | Copyright (C) 2016 Bastille Networks
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | '''
17 |
18 | def i_code (code3):
19 | return code3[0]
20 |
21 | def o_code (code3):
22 | if len (code3) >= 2:
23 | return code3[1]
24 | else:
25 | return code3[0]
26 |
27 | def tap_code (code3):
28 | if len (code3) >= 3:
29 | return code3[2]
30 | else:
31 | return code3[0]
32 |
33 | def i_type (code3):
34 | return char_to_type[i_code (code3)]
35 |
36 | def o_type (code3):
37 | return char_to_type[o_code (code3)]
38 |
39 | def tap_type (code3):
40 | return char_to_type[tap_code (code3)]
41 |
42 |
43 | char_to_type = {}
44 | char_to_type['s'] = 'short'
45 | char_to_type['i'] = 'int'
46 | char_to_type['f'] = 'float'
47 | char_to_type['c'] = 'gr_complex'
48 | char_to_type['b'] = 'unsigned char'
49 |
--------------------------------------------------------------------------------
/swig/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2016 Bastille Networks
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 |
16 | ########################################################################
17 | # Check if there is C++ code at all
18 | ########################################################################
19 | if(NOT nordic_sources)
20 | MESSAGE(STATUS "No C++ sources... skipping swig/")
21 | return()
22 | endif(NOT nordic_sources)
23 |
24 | ########################################################################
25 | # Include swig generation macros
26 | ########################################################################
27 | find_package(SWIG)
28 | find_package(PythonLibs 2)
29 | if(NOT SWIG_FOUND OR NOT PYTHONLIBS_FOUND)
30 | return()
31 | endif()
32 | include(GrSwig)
33 | include(GrPython)
34 |
35 | ########################################################################
36 | # Setup swig generation
37 | ########################################################################
38 | foreach(incdir ${GNURADIO_RUNTIME_INCLUDE_DIRS})
39 | list(APPEND GR_SWIG_INCLUDE_DIRS ${incdir}/gnuradio/swig)
40 | endforeach(incdir)
41 |
42 | set(GR_SWIG_LIBRARIES gnuradio-nordic)
43 | set(GR_SWIG_DOC_FILE ${CMAKE_CURRENT_BINARY_DIR}/nordic_swig_doc.i)
44 | set(GR_SWIG_DOC_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../include)
45 |
46 | GR_SWIG_MAKE(nordic_swig nordic_swig.i)
47 |
48 | ########################################################################
49 | # Install the build swig module
50 | ########################################################################
51 | GR_SWIG_INSTALL(TARGETS nordic_swig DESTINATION ${GR_PYTHON_DIR}/nordic)
52 |
53 | ########################################################################
54 | # Install swig .i files for development
55 | ########################################################################
56 | install(
57 | FILES
58 | nordic_swig.i
59 | ${CMAKE_CURRENT_BINARY_DIR}/nordic_swig_doc.i
60 | DESTINATION ${GR_INCLUDE_DIR}/nordic/swig
61 | )
62 |
--------------------------------------------------------------------------------
/swig/nordic_swig.i:
--------------------------------------------------------------------------------
1 | /* -*- c++ -*- */
2 |
3 | #define NORDIC_API
4 |
5 | %include "gnuradio.i" // the common stuff
6 |
7 | //load generated python docstrings
8 | %include "nordic_swig_doc.i"
9 |
10 | %{
11 | #include "nordic/nordic_rx.h"
12 | #include "nordic/nordic_tx.h"
13 | %}
14 |
15 |
16 | %include "nordic/nordic_rx.h"
17 | GR_SWIG_BLOCK_MAGIC2(nordic, nordic_rx);
18 | %include "nordic/nordic_tx.h"
19 | GR_SWIG_BLOCK_MAGIC2(nordic, nordic_tx);
20 |
--------------------------------------------------------------------------------
/wireshark/nordic_dissector.lua:
--------------------------------------------------------------------------------
1 | -- trivial protocol example
2 | -- declare our protocol
3 | nordic_proto = Proto("nordic","Nordic Semiconductor nRF24L")
4 | -- create a function to dissect it
5 | function nordic_proto.dissector(buffer,pinfo,tree)
6 | pinfo.cols.protocol = "NORDIC"
7 | local subtree = tree:add(nordic_proto,buffer(),"nRF24L Packet")
8 | pinfo.cols.info = ""
9 |
10 | -- channel
11 | local channel = buffer(0,1):uint()
12 |
13 | -- data rate
14 | local data_rate = buffer(1,1):uint()
15 | local data_rate_string = ""
16 | if data_rate == 0 then data_rate_string = "250K" end
17 | if data_rate == 1 then data_rate_string = "1M" end
18 | if data_rate == 2 then data_rate_string = "2M" end
19 |
20 | -- address length
21 | local address_length = buffer(2,1):uint()
22 |
23 | -- payload length
24 | local payload_length = buffer(3,1):uint()
25 |
26 | -- sequence number
27 | local sequence_number = buffer(4,1):uint()
28 |
29 | -- no ack bit
30 | local no_ack = buffer(5,1):uint()
31 |
32 | -- crc length
33 | local crc_length = buffer(6,1):uint()
34 |
35 | -- address
36 | local address = buffer(7,address_length)
37 | local address_bytes = address:bytes()
38 |
39 | -- payload
40 | local payload = buffer(7+address_length,payload_length)
41 | local payload_bytes = payload:bytes()
42 |
43 | -- crc
44 | local crc = buffer(7+address_length+payload_length, crc_length)
45 |
46 | subtree:add(buffer(0,1), "Channel: " .. (2400+channel) .. "MHz")
47 | subtree:add(buffer(1,1), "Data Rate: " .. data_rate_string)
48 | subtree:add(buffer(2,1), "Address Length: " .. address_length)
49 | subtree:add(buffer(3,1), "Payload Length: " .. payload_length)
50 | subtree:add(buffer(4,1), "Sequence Number: " .. sequence_number)
51 | subtree:add(buffer(5,1), "No ACK: " .. no_ack)
52 | subtree:add(buffer(6,1), "CRC Length: " .. crc_length)
53 | subtree:add(buffer(7,address_length), "Address: " .. address)
54 | subtree:add(buffer(7+address_length,payload_length), "Payload: " .. payload)
55 | subtree:add(buffer(7+address_length+payload_length, crc_length), "CRC: " .. crc)
56 |
57 | -- Keepalive (vendor agnostic)
58 | if payload_bytes:len() == 0 then
59 | pinfo.cols.info = "ACK"
60 | end
61 |
62 | -- Microsoft
63 | if bit.band(buffer(7,1):uint(), 0xF0) == 0xA0 and payload_length > 0 then
64 |
65 | -- Validate the checksum (AES encrypted series)
66 | local sum = 0xFF
67 | for x = 0, payload_bytes:len()-1 do
68 | sum = bit.bxor(sum, payload_bytes:get_index(x))
69 | end
70 | sum = bit.band(sum, 0xFF)
71 | if sum == 0 then
72 |
73 | -- Microsoft keepalive
74 | if payload_bytes:get_index(1) == 0x38 and payload_bytes:len() == 8 then
75 | pinfo.cols.info = "Keepalive"
76 | end
77 |
78 | -- Microsoft mouse movement/click
79 | if payload_bytes:get_index(1) == 0x90 then
80 |
81 | local vtree = subtree:add(nordic_proto, buffer(), "Microsoft Movement/Click")
82 | pinfo.cols.info = "Microsoft Mouse Movement/Click"
83 | vtree:add(string.format("Device Type: 0x%02x", payload_bytes:get_index(2)))
84 |
85 | -- Movement X/Y
86 | local movement_x = payload(9, 2):le_int()
87 | local movement_y = payload(11, 2):le_int()
88 | local scroll = payload(13, 2):le_int()
89 | vtree:add(string.format("Movement X: %i", movement_x))
90 | vtree:add(string.format("Movement Y: %i", movement_y))
91 | vtree:add(string.format("Scroll Wheel: %i", scroll))
92 |
93 | -- Button mask
94 | local button_mask = payload(8, 1):uint()
95 | vtree:add(string.format("Button 0: %i", bit.band(bit.rshift(button_mask, 0), 1)))
96 | vtree:add(string.format("Button 1: %i", bit.band(bit.rshift(button_mask, 1), 1)))
97 | vtree:add(string.format("Button 2: %i", bit.band(bit.rshift(button_mask, 2), 1)))
98 | vtree:add(string.format("Button 3: %i", bit.band(bit.rshift(button_mask, 3), 1)))
99 | vtree:add(string.format("Button 4: %i", bit.band(bit.rshift(button_mask, 4), 1)))
100 | vtree:add(string.format("Button 5: %i", bit.band(bit.rshift(button_mask, 5), 1)))
101 | vtree:add(string.format("Button 6: %i", bit.band(bit.rshift(button_mask, 6), 1)))
102 | vtree:add(string.format("Button 7: %i", bit.band(bit.rshift(button_mask, 7), 1)))
103 |
104 | end
105 |
106 | end
107 | end
108 |
109 | end
110 |
111 | -- load the udp.port table
112 | udp_table = DissectorTable.get("udp.port")
113 |
114 | -- register our protocol to handle udp port 7777
115 | udp_table:add(9451,nordic_proto)
--------------------------------------------------------------------------------