mirror of
https://github.com/RfidResearchGroup/mayhem-firmware.git
synced 2026-05-12 11:27:21 -07:00
Merge remote-tracking branch 'upstream/master'
Conflicts: firmware/Makefile firmware/application/Makefile firmware/application/event_m0.cpp firmware/application/ui_setup.cpp firmware/application/ui_setup.hpp firmware/baseband/baseband_thread.cpp firmware/baseband/baseband_thread.hpp firmware/bootstrap/CMakeLists.txt firmware/common/message.hpp firmware/common/portapack_shared_memory.hpp hardware/.gitignore
This commit is contained in:
+16
-10
@@ -11,27 +11,33 @@ notifications:
|
||||
- "Change view : %{compare_url}"
|
||||
- "Build details : %{build_url}"
|
||||
# TODO: The "build_number.1" in this URL is almost certainly wrong, but correct value not available from Travis?
|
||||
- "Firmware download : https://portapack-h1-builds.s3.amazonaws.com/%{repository_slug}/%{build_number}/%{build_number}.1/firmware/portapack-h1-firmware-%{commit}.tar.bz2"
|
||||
- "Firmware download : https://portapack-h1-builds.s3.amazonaws.com/%{repository_slug}/%{build_number}/%{build_number}.1/build/firmware/portapack-h1-firmware-%{commit}.tar.bz2"
|
||||
|
||||
before_script:
|
||||
- wget https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q1-update/+download/gcc-arm-none-eabi-5_3-2016q1-20160330-linux.tar.bz2 -O /tmp/gcc-arm.tar.bz2
|
||||
- wget https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q2-update/+download/gcc-arm-none-eabi-5_4-2016q2-20160622-linux.tar.bz2 -O /tmp/gcc-arm.tar.bz2
|
||||
- tar -xf /tmp/gcc-arm.tar.bz2
|
||||
- export PATH=$PWD/gcc-arm-none-eabi-5_3-2016q1/bin:$PATH
|
||||
- export PATH=$PWD/gcc-arm-none-eabi-5_4-2016q2/bin:$PATH
|
||||
- export CC="arm-none-eabi-gcc"
|
||||
- export CXX="arm-none-eabi-g++"
|
||||
|
||||
script:
|
||||
# TODO: Introduce top-level Makefile, this is lame.
|
||||
- pushd firmware/
|
||||
- mkdir build/
|
||||
- pushd build/
|
||||
- cmake ..
|
||||
- make release
|
||||
- popd
|
||||
|
||||
addons:
|
||||
apt_packages:
|
||||
- lib32bz2-1.0
|
||||
- lib32ncurses5
|
||||
- lib32z1
|
||||
apt:
|
||||
packages:
|
||||
- lib32bz2-1.0
|
||||
- lib32ncurses5
|
||||
- lib32z1
|
||||
- cmake
|
||||
sources:
|
||||
- kalakris-cmake
|
||||
artifacts:
|
||||
paths:
|
||||
- $(ls firmware/portapack-h1-firmware-*.tar.bz2 | tr "\n" ":")
|
||||
- $(ls firmware/portapack-h1-firmware-*.zip | tr "\n" ":")
|
||||
- $(ls build/firmware/portapack-h1-firmware-*.tar.bz2 | tr "\n" ":")
|
||||
- $(ls build/firmware/portapack-h1-firmware-*.zip | tr "\n" ":")
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# Copyright 2016 Jared Boone <jared@sharebrained.com>
|
||||
#
|
||||
# This file is part of PortaPack.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.9)
|
||||
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/firmware/toolchain-arm-cortex-m.cmake)
|
||||
|
||||
project(portapack-h1)
|
||||
|
||||
execute_process(
|
||||
COMMAND git log -n 1 --format=%h
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||
RESULT_VARIABLE GIT_REVISION_FOUND
|
||||
ERROR_QUIET
|
||||
OUTPUT_VARIABLE GIT_REVISION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if (GIT_REVISION_FOUND)
|
||||
set(VERSION "unknown")
|
||||
else (GIT_REVISION_FOUND)
|
||||
set(VERSION ${GIT_REVISION})
|
||||
endif (GIT_REVISION_FOUND)
|
||||
|
||||
set(LICENSE_PATH ${CMAKE_CURRENT_LIST_DIR}/LICENSE)
|
||||
set(HARDWARE_PATH ${CMAKE_CURRENT_LIST_DIR}/hardware)
|
||||
|
||||
add_subdirectory(firmware)
|
||||
@@ -0,0 +1,83 @@
|
||||
# Copyright 2016 Jared Boone <jared@sharebrained.com>
|
||||
#
|
||||
# This file is part of PortaPack.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
project(firmware)
|
||||
|
||||
set(COMMON ${PROJECT_SOURCE_DIR}/common)
|
||||
set(CHIBIOS ${PROJECT_SOURCE_DIR}/chibios)
|
||||
set(CHIBIOS_PORTAPACK ${PROJECT_SOURCE_DIR}/chibios-portapack)
|
||||
|
||||
set(HACKRF_FIRMWARE_FILENAME hackrf_one_usb_ram.dfu)
|
||||
set(HACKRF_FIRMWARE_IMAGE ${PROJECT_SOURCE_DIR}/${HACKRF_FIRMWARE_FILENAME})
|
||||
|
||||
set(HACKRF_CPLD_SVF_FILENAME hackrf_cpld_default.svf)
|
||||
set(HACKRF_CPLD_SVF_PATH ${PROJECT_SOURCE_DIR}/${HACKRF_CPLD_SVF_FILENAME})
|
||||
|
||||
set(EXTRACT_CPLD_DATA ${PROJECT_SOURCE_DIR}/tools/extract_cpld_data.py)
|
||||
set(EXTRACT_SVF_DATA_XC2C64A ${PROJECT_SOURCE_DIR}/tools/extract_svf_data_xc2c64a.py)
|
||||
set(STRIP_DFU ${PROJECT_SOURCE_DIR}/tools/strip_dfu.py)
|
||||
set(MAKE_SPI_IMAGE ${PROJECT_SOURCE_DIR}/tools/make_spi_image.py)
|
||||
set(MAKE_IMAGE_CHUNK ${PROJECT_SOURCE_DIR}/tools/make_image_chunk.py)
|
||||
|
||||
set(FIRMWARE_NAME portapack-h1-firmware)
|
||||
set(FIRMWARE_FILENAME ${FIRMWARE_NAME}.bin)
|
||||
|
||||
add_subdirectory(application)
|
||||
add_subdirectory(baseband)
|
||||
add_subdirectory(bootstrap)
|
||||
|
||||
# NOTE: Dependencies break if the .bin files aren't included in DEPENDS. WTF, CMake?
|
||||
add_custom_command(
|
||||
OUTPUT ${FIRMWARE_FILENAME}
|
||||
COMMAND ${MAKE_SPI_IMAGE} ${bootstrap_BINARY_DIR}/bootstrap.bin ${baseband_BINARY_DIR}/baseband.img ${application_BINARY_DIR}/application.bin ${FIRMWARE_FILENAME}
|
||||
DEPENDS bootstrap baseband application ${MAKE_SPI_IMAGE}
|
||||
${bootstrap_BINARY_DIR}/bootstrap.bin ${baseband_BINARY_DIR}/baseband.img ${application_BINARY_DIR}/application.bin
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
firmware
|
||||
DEPENDS ${FIRMWARE_FILENAME}
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
program
|
||||
COMMAND dfu-util --device 1fc9:000c --download ${HACKRF_FIRMWARE_IMAGE} --reset
|
||||
COMMAND sleep 1s
|
||||
COMMAND hackrf_spiflash -w ${FIRMWARE_FILENAME}
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${FIRMWARE_FILENAME}
|
||||
)
|
||||
|
||||
# TODO: Bad hack to fix location of LICENSE file for tar.
|
||||
add_custom_command(
|
||||
OUTPUT ${FIRMWARE_NAME}-${GIT_REVISION}.tar.bz2 ${FIRMWARE_NAME}-${GIT_REVISION}.zip
|
||||
COMMAND cp ${LICENSE_PATH} LICENSE
|
||||
COMMAND cp ${HACKRF_FIRMWARE_IMAGE} ${HACKRF_FIRMWARE_FILENAME}
|
||||
COMMAND tar -c -j -f ${FIRMWARE_NAME}-${GIT_REVISION}.tar.bz2 ${FIRMWARE_FILENAME} ${HACKRF_FIRMWARE_FILENAME} LICENSE
|
||||
COMMAND zip -9 -q ${FIRMWARE_NAME}-${GIT_REVISION}.zip ${FIRMWARE_FILENAME} ${HACKRF_FIRMWARE_FILENAME} LICENSE
|
||||
COMMAND rm -f LICENSE ${HACKRF_FIRMWARE_FILENAME}
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${FIRMWARE_FILENAME} ${LICENSE_PATH} ${HACKRF_FIRMWARE_IMAGE}
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
release
|
||||
DEPENDS ${FIRMWARE_NAME}-${GIT_REVISION}.tar.bz2 ${FIRMWARE_NAME}-${GIT_REVISION}.zip
|
||||
)
|
||||
@@ -0,0 +1,334 @@
|
||||
#
|
||||
# Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
#
|
||||
# This file is part of PortaPack.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
# Build global options
|
||||
# NOTE: Can be overridden externally.
|
||||
#
|
||||
|
||||
enable_language(C CXX ASM)
|
||||
|
||||
project(application)
|
||||
|
||||
# Compiler options here.
|
||||
set(USE_OPT "-Os --specs=nano.specs")
|
||||
|
||||
# C specific options here (added to USE_OPT).
|
||||
set(USE_COPT "-std=gnu99")
|
||||
|
||||
# C++ specific options here (added to USE_OPT).
|
||||
set(USE_CPPOPT "-std=c++11 -fno-rtti -fno-exceptions")
|
||||
|
||||
# Enable this if you want the linker to remove unused code and data
|
||||
set(USE_LINK_GC yes)
|
||||
|
||||
# Linker extra options here.
|
||||
set(USE_LDOPT)
|
||||
|
||||
# Enable this if you want link time optimizations (LTO)
|
||||
set(USE_LTO no)
|
||||
|
||||
# If enabled, this option allows to compile the application in THUMB mode.
|
||||
set(USE_THUMB yes)
|
||||
|
||||
# Enable this if you want to see the full log while compiling.
|
||||
set(USE_VERBOSE_COMPILE no)
|
||||
|
||||
#
|
||||
# Build global options
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Architecture or project specific options
|
||||
#
|
||||
|
||||
# Enables the use of FPU on Cortex-M4 (no, softfp, hard).
|
||||
set(USE_FPU no)
|
||||
|
||||
#
|
||||
# Architecture or project specific options
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Project, sources and paths
|
||||
#
|
||||
|
||||
set(CPLD_SVF_PATH ${HARDWARE_PATH}/portapack_h1/cpld/output_files/portapack_h1_cpld.svf)
|
||||
set(CPLD_DATA_CPP ${CMAKE_CURRENT_BINARY_DIR}/portapack_cpld_data.cpp)
|
||||
|
||||
set(HACKRF_CPLD_DATA_HPP ${CMAKE_CURRENT_BINARY_DIR}/hackrf_cpld_data.hpp)
|
||||
set(HACKRF_CPLD_DATA_CPP ${CMAKE_CURRENT_BINARY_DIR}/hackrf_cpld_data.cpp)
|
||||
|
||||
# Imported source files and paths
|
||||
include(${CHIBIOS_PORTAPACK}/boards/GSG_HACKRF_ONE/board.cmake)
|
||||
include(${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M0/platform.cmake)
|
||||
include(${CHIBIOS}/os/hal/hal.cmake)
|
||||
include(${CHIBIOS_PORTAPACK}/os/ports/GCC/ARMCMx/LPC43xx_M0/port.cmake)
|
||||
include(${CHIBIOS}/os/kernel/kernel.cmake)
|
||||
include(${CHIBIOS_PORTAPACK}/os/various/fatfs_bindings/fatfs.cmake)
|
||||
include(${CHIBIOS}/test/test.cmake)
|
||||
|
||||
# Define linker script file here
|
||||
set(LDSCRIPT ${PORTLD}/LPC43xx_M0.ld)
|
||||
|
||||
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
||||
# setting.
|
||||
set(CSRC
|
||||
${PORTSRC}
|
||||
${KERNSRC}
|
||||
${TESTSRC}
|
||||
${HALSRC}
|
||||
${PLATFORMSRC}
|
||||
${BOARDSRC}
|
||||
${FATFSSRC}
|
||||
)
|
||||
|
||||
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
||||
# setting.
|
||||
set(CPPSRC
|
||||
main.cpp
|
||||
irq_lcd_frame.cpp
|
||||
irq_controls.cpp
|
||||
irq_rtc.cpp
|
||||
${COMMON}/event.cpp
|
||||
event_m0.cpp
|
||||
${COMMON}/message_queue.cpp
|
||||
${COMMON}/hackrf_hal.cpp
|
||||
portapack.cpp
|
||||
${COMMON}/portapack_shared_memory.cpp
|
||||
baseband_api.cpp
|
||||
${COMMON}/portapack_persistent_memory.cpp
|
||||
${COMMON}/portapack_io.cpp
|
||||
${COMMON}/i2c_pp.cpp
|
||||
spi_pp.cpp
|
||||
clock_manager.cpp
|
||||
si5351.cpp
|
||||
${COMMON}/wm8731.cpp
|
||||
radio.cpp
|
||||
baseband_cpld.cpp
|
||||
tuning.cpp
|
||||
rf_path.cpp
|
||||
rffc507x.cpp
|
||||
rffc507x_spi.cpp
|
||||
max2837.cpp
|
||||
max5864.cpp
|
||||
debounce.cpp
|
||||
touch.cpp
|
||||
touch_adc.cpp
|
||||
encoder.cpp
|
||||
audio.cpp
|
||||
${COMMON}/lcd_ili9341.cpp
|
||||
${COMMON}/ui.cpp
|
||||
${COMMON}/ui_text.cpp
|
||||
${COMMON}/ui_widget.cpp
|
||||
${COMMON}/ui_painter.cpp
|
||||
${COMMON}/ui_focus.cpp
|
||||
ui_navigation.cpp
|
||||
ui_menu.cpp
|
||||
ui_rssi.cpp
|
||||
ui_channel.cpp
|
||||
ui_audio.cpp
|
||||
ui_font_fixed_8x16.cpp
|
||||
ui_setup.cpp
|
||||
ui_debug.cpp
|
||||
ui_baseband_stats_view.cpp
|
||||
ui_sd_card_status_view.cpp
|
||||
ui_sd_card_debug.cpp
|
||||
ui_console.cpp
|
||||
ui_receiver.cpp
|
||||
ui_record_view.cpp
|
||||
ui_spectrum.cpp
|
||||
recent_entries.cpp
|
||||
receiver_model.cpp
|
||||
spectrum_color_lut.cpp
|
||||
analog_audio_app.cpp
|
||||
${COMMON}/ais_baseband.cpp
|
||||
${COMMON}/ais_packet.cpp
|
||||
ais_app.cpp
|
||||
tpms_app.cpp
|
||||
${COMMON}/tpms_packet.cpp
|
||||
ert_app.cpp
|
||||
${COMMON}/ert_packet.cpp
|
||||
capture_app.cpp
|
||||
sd_card.cpp
|
||||
time.cpp
|
||||
file.cpp
|
||||
log_file.cpp
|
||||
${COMMON}/png_writer.cpp
|
||||
capture_thread.cpp
|
||||
${COMMON}/manchester.cpp
|
||||
string_format.cpp
|
||||
temperature_logger.cpp
|
||||
${COMMON}/utility.cpp
|
||||
${COMMON}/chibios_cpp.cpp
|
||||
${COMMON}/debug.cpp
|
||||
${COMMON}/gcc.cpp
|
||||
${COMMON}/lfsr_random.cpp
|
||||
core_control.cpp
|
||||
${COMMON}/cpld_max5.cpp
|
||||
${COMMON}/cpld_xilinx.cpp
|
||||
${COMMON}/jtag.cpp
|
||||
${COMMON}/jtag_tap.cpp
|
||||
cpld_update.cpp
|
||||
${CPLD_DATA_CPP}
|
||||
${HACKRF_CPLD_DATA_CPP}
|
||||
)
|
||||
|
||||
# C sources to be compiled in ARM mode regardless of the global setting.
|
||||
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
|
||||
# option that results in lower performance and larger code size.
|
||||
set(ACSRC)
|
||||
|
||||
# C++ sources to be compiled in ARM mode regardless of the global setting.
|
||||
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
|
||||
# option that results in lower performance and larger code size.
|
||||
set(ACPPSRC)
|
||||
|
||||
# C sources to be compiled in THUMB mode regardless of the global setting.
|
||||
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
|
||||
# option that results in lower performance and larger code size.
|
||||
set(TCSRC)
|
||||
|
||||
# C sources to be compiled in THUMB mode regardless of the global setting.
|
||||
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
|
||||
# option that results in lower performance and larger code size.
|
||||
set(TCPPSRC)
|
||||
|
||||
# List ASM source files here
|
||||
set(ASMSRC ${PORTASM})
|
||||
|
||||
set(INCDIR ${CMAKE_CURRENT_BINARY_DIR} ${COMMON} ${PORTINC} ${KERNINC} ${TESTINC}
|
||||
${HALINC} ${PLATFORMINC} ${BOARDINC}
|
||||
${FATFSINC}
|
||||
${CHIBIOS}/os/various
|
||||
)
|
||||
|
||||
#
|
||||
# Project, sources and paths
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Compiler settings
|
||||
#
|
||||
|
||||
# TODO: Entertain using MCU=cortex-m0.small-multiply for LPC43xx M0 core.
|
||||
# However, on GCC-ARM-Embedded 4.9 2015q2, it seems to produce non-functional
|
||||
# binaries.
|
||||
set(MCU cortex-m0)
|
||||
|
||||
# ARM-specific options here
|
||||
set(AOPT)
|
||||
|
||||
# THUMB-specific options here
|
||||
set(TOPT "-mthumb -DTHUMB")
|
||||
|
||||
# Define C warning options here
|
||||
set(CWARN "-Wall -Wextra -Wstrict-prototypes")
|
||||
|
||||
# Define C++ warning options here
|
||||
set(CPPWARN "-Wall -Wextra")
|
||||
|
||||
#
|
||||
# Compiler settings
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Start of default section
|
||||
#
|
||||
|
||||
# List all default C defines here, like -D_DEBUG=1
|
||||
# TODO: Switch -DCRT0_INIT_DATA depending on load from RAM or SPIFI?
|
||||
# NOTE: _RANDOM_TCC to kill a GCC 4.9.3 error with std::max argument types
|
||||
set(DDEFS -DLPC43XX -DLPC43XX_M0 -D__NEWLIB__ -DHACKRF_ONE -DTOOLCHAIN_GCC -DTOOLCHAIN_GCC_ARM -D_RANDOM_TCC=0 -DGIT_REVISION=\"${GIT_REVISION}\")
|
||||
|
||||
# List all default ASM defines here, like -D_DEBUG=1
|
||||
set(DADEFS)
|
||||
|
||||
# List all default directories to look for include files here
|
||||
set(DINCDIR)
|
||||
|
||||
# List the default directory to look for the libraries here
|
||||
set(DLIBDIR)
|
||||
|
||||
# List all default libraries here
|
||||
set(DLIBS)
|
||||
|
||||
#
|
||||
# End of default section
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Start of user section
|
||||
#
|
||||
|
||||
# List all user C define here, like -D_DEBUG=1
|
||||
set(UDEFS)
|
||||
|
||||
# Define ASM defines here
|
||||
set(UADEFS)
|
||||
|
||||
# List all user directories here
|
||||
set(UINCDIR)
|
||||
|
||||
# List the user directory to look for the libraries here
|
||||
set(ULIBDIR)
|
||||
|
||||
# List all user libraries here
|
||||
set(ULIBS)
|
||||
|
||||
#
|
||||
# End of user defines
|
||||
##############################################################################
|
||||
|
||||
set(RULESPATH ${CHIBIOS}/os/ports/GCC/ARMCMx)
|
||||
include(${RULESPATH}/rules.cmake)
|
||||
|
||||
##############################################################################
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CPLD_DATA_CPP}
|
||||
COMMAND ${EXTRACT_CPLD_DATA} ${CPLD_SVF_PATH} >${CPLD_DATA_CPP}
|
||||
DEPENDS ${EXTRACT_CPLD_DATA} ${CPLD_SVF_PATH}
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${HACKRF_CPLD_DATA_HPP} ${HACKRF_CPLD_DATA_CPP}
|
||||
COMMAND ${EXTRACT_SVF_DATA_XC2C64A} ${HACKRF_CPLD_SVF_PATH} hackrf::one::cpld::verify_blocks ${HACKRF_CPLD_DATA_HPP} ${HACKRF_CPLD_DATA_CPP}
|
||||
DEPENDS ${EXTRACT_SVF_DATA_XC2C64A} ${HACKRF_CPLD_SVF_PATH}
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME}.elf ${CSRC} ${CPPSRC} ${ASMSRC})
|
||||
set_target_properties(${PROJECT_NAME}.elf PROPERTIES LINK_DEPENDS ${LDSCRIPT})
|
||||
add_definitions(${DEFS})
|
||||
include_directories(. ${INCDIR})
|
||||
link_directories(${LLIBDIR})
|
||||
target_link_libraries(${PROJECT_NAME}.elf ${LIBS})
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${PROJECT_NAME}.bin
|
||||
COMMAND ${CMAKE_OBJCOPY} -O binary ${PROJECT_NAME}.elf ${PROJECT_NAME}.bin
|
||||
DEPENDS ${PROJECT_NAME}.elf
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
${PROJECT_NAME}
|
||||
DEPENDS ${PROJECT_NAME}.bin
|
||||
)
|
||||
@@ -21,8 +21,6 @@
|
||||
|
||||
#include "ais_app.hpp"
|
||||
|
||||
#include "event_m0.hpp"
|
||||
|
||||
#include "string_format.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
@@ -128,25 +126,17 @@ static std::string true_heading(const TrueHeading value) {
|
||||
} /* namespace format */
|
||||
} /* namespace ais */
|
||||
|
||||
AISLogger::AISLogger(
|
||||
const std::string& file_path
|
||||
) : log_file { file_path }
|
||||
{
|
||||
}
|
||||
|
||||
void AISLogger::on_packet(const ais::Packet& packet) {
|
||||
// TODO: Unstuff here, not in baseband!
|
||||
if( log_file.is_open() ) {
|
||||
std::string entry;
|
||||
entry.reserve((packet.length() + 3) / 4);
|
||||
std::string entry;
|
||||
entry.reserve((packet.length() + 3) / 4);
|
||||
|
||||
for(size_t i=0; i<packet.length(); i+=4) {
|
||||
const auto nibble = packet.read(i, 4);
|
||||
entry += (nibble >= 10) ? ('W' + nibble) : ('0' + nibble);
|
||||
}
|
||||
|
||||
log_file.write_entry(packet.received_at(), entry);
|
||||
for(size_t i=0; i<packet.length(); i+=4) {
|
||||
const auto nibble = packet.read(i, 4);
|
||||
entry += (nibble >= 10) ? ('W' + nibble) : ('0' + nibble);
|
||||
}
|
||||
|
||||
log_file.write_entry(packet.received_at(), entry);
|
||||
}
|
||||
|
||||
void AISRecentEntry::update(const ais::Packet& packet) {
|
||||
@@ -296,6 +286,8 @@ void AISRecentEntryDetailView::set_entry(const AISRecentEntry& entry) {
|
||||
}
|
||||
|
||||
AISAppView::AISAppView(NavigationView&) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_ais);
|
||||
|
||||
add_children({ {
|
||||
&label_channel,
|
||||
&options_channel,
|
||||
@@ -305,16 +297,6 @@ AISAppView::AISAppView(NavigationView&) {
|
||||
|
||||
recent_entry_detail_view.hidden(true);
|
||||
|
||||
EventDispatcher::message_map().register_handler(Message::ID::AISPacket,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const AISPacketMessage*>(p);
|
||||
const ais::Packet packet { message->packet };
|
||||
if( packet.is_valid() ) {
|
||||
this->on_packet(packet);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
target_frequency_ = initial_target_frequency;
|
||||
|
||||
radio::enable({
|
||||
@@ -326,12 +308,6 @@ AISAppView::AISAppView(NavigationView&) {
|
||||
1,
|
||||
});
|
||||
|
||||
baseband::start({
|
||||
.mode = 3,
|
||||
.sampling_rate = sampling_rate,
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
|
||||
options_channel.on_change = [this](size_t, OptionsField::value_t v) {
|
||||
this->on_frequency_changed(v);
|
||||
};
|
||||
@@ -344,14 +320,16 @@ AISAppView::AISAppView(NavigationView&) {
|
||||
this->on_show_list();
|
||||
};
|
||||
|
||||
logger = std::make_unique<AISLogger>("ais.txt");
|
||||
logger = std::make_unique<AISLogger>();
|
||||
if( logger ) {
|
||||
logger->append("ais.txt");
|
||||
}
|
||||
}
|
||||
|
||||
AISAppView::~AISAppView() {
|
||||
baseband::stop();
|
||||
radio::disable();
|
||||
|
||||
EventDispatcher::message_map().unregister_handler(Message::ID::AISPacket);
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void AISAppView::focus() {
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include "ui_widget.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
|
||||
#include "event_m0.hpp"
|
||||
|
||||
#include "log_file.hpp"
|
||||
|
||||
#include "ais_packet.hpp"
|
||||
@@ -90,8 +92,10 @@ using AISRecentEntries = RecentEntries<ais::Packet, AISRecentEntry>;
|
||||
|
||||
class AISLogger {
|
||||
public:
|
||||
AISLogger(const std::string& file_path);
|
||||
|
||||
Optional<File::Error> append(const std::string& filename) {
|
||||
return log_file.append(filename);
|
||||
}
|
||||
|
||||
void on_packet(const ais::Packet& packet);
|
||||
|
||||
private:
|
||||
@@ -173,6 +177,17 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
MessageHandlerRegistration message_handler_packet {
|
||||
Message::ID::AISPacket,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const AISPacketMessage*>(p);
|
||||
const ais::Packet packet { message->packet };
|
||||
if( packet.is_valid() ) {
|
||||
this->on_packet(packet);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
uint32_t target_frequency_ = initial_target_frequency;
|
||||
|
||||
void on_packet(const ais::Packet& packet);
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#include "analog_audio_app.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
using namespace portapack;
|
||||
@@ -108,19 +110,10 @@ AnalogAudioView::AnalogAudioView(
|
||||
this->on_show_options_frequency();
|
||||
};
|
||||
|
||||
field_lna.set_value(receiver_model.lna());
|
||||
field_lna.on_change = [this](int32_t v) {
|
||||
this->on_lna_changed(v);
|
||||
};
|
||||
|
||||
field_lna.on_show_options = [this]() {
|
||||
this->on_show_options_rf_gain();
|
||||
};
|
||||
|
||||
field_vga.set_value(receiver_model.vga());
|
||||
field_vga.on_change = [this](int32_t v_db) {
|
||||
this->on_vga_changed(v_db);
|
||||
};
|
||||
field_vga.on_show_options = [this]() {
|
||||
this->on_show_options_rf_gain();
|
||||
};
|
||||
@@ -139,6 +132,10 @@ AnalogAudioView::AnalogAudioView(
|
||||
this->on_headphone_volume_changed(v);
|
||||
};
|
||||
|
||||
record_view.on_error = [&nav](std::string message) {
|
||||
nav.display_modal("Error", message);
|
||||
};
|
||||
|
||||
audio::output::start();
|
||||
|
||||
update_modulation(static_cast<ReceiverModel::Mode>(modulation));
|
||||
@@ -150,6 +147,8 @@ AnalogAudioView::~AnalogAudioView() {
|
||||
audio::output::stop();
|
||||
|
||||
receiver_model.disable();
|
||||
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_hide() {
|
||||
@@ -178,18 +177,6 @@ void AnalogAudioView::on_baseband_bandwidth_changed(uint32_t bandwidth_hz) {
|
||||
receiver_model.set_baseband_bandwidth(bandwidth_hz);
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_rf_amp_changed(bool v) {
|
||||
receiver_model.set_rf_amp(v);
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_lna_changed(int32_t v_db) {
|
||||
receiver_model.set_lna(v_db);
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_vga_changed(int32_t v_db) {
|
||||
receiver_model.set_vga(v_db);
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_modulation_changed(const ReceiverModel::Mode modulation) {
|
||||
// TODO: Terrible kludge because widget system doesn't notify Waterfall that
|
||||
// it's being shown or hidden.
|
||||
@@ -215,8 +202,11 @@ void AnalogAudioView::set_options_widget(std::unique_ptr<Widget> new_widget) {
|
||||
|
||||
if( new_widget ) {
|
||||
options_widget = std::move(new_widget);
|
||||
add_child(options_widget.get());
|
||||
} else {
|
||||
// TODO: Lame hack to hide options view due to my bad paint/damage algorithm.
|
||||
options_widget = std::make_unique<Rectangle>(options_view_rect, style_options_group.background);
|
||||
}
|
||||
add_child(options_widget.get());
|
||||
}
|
||||
|
||||
void AnalogAudioView::on_show_options_frequency() {
|
||||
@@ -238,11 +228,6 @@ void AnalogAudioView::on_show_options_frequency() {
|
||||
void AnalogAudioView::on_show_options_rf_gain() {
|
||||
auto widget = std::make_unique<RadioGainOptionsView>(options_view_rect, &style_options_group);
|
||||
|
||||
widget->set_rf_amp(receiver_model.rf_amp());
|
||||
widget->on_change_rf_amp = [this](bool enable) {
|
||||
this->on_rf_amp_changed(enable);
|
||||
};
|
||||
|
||||
set_options_widget(std::move(widget));
|
||||
field_lna.set_style(&style_options_group);
|
||||
}
|
||||
@@ -286,6 +271,20 @@ void AnalogAudioView::update_modulation(const ReceiverModel::Mode modulation) {
|
||||
audio::output::mute();
|
||||
record_view.stop();
|
||||
|
||||
baseband::shutdown();
|
||||
|
||||
portapack::spi_flash::image_tag_t image_tag;
|
||||
switch(modulation) {
|
||||
case ReceiverModel::Mode::AMAudio: image_tag = portapack::spi_flash::image_tag_am_audio; break;
|
||||
case ReceiverModel::Mode::NarrowbandFMAudio: image_tag = portapack::spi_flash::image_tag_nfm_audio; break;
|
||||
case ReceiverModel::Mode::WidebandFMAudio: image_tag = portapack::spi_flash::image_tag_wfm_audio; break;
|
||||
case ReceiverModel::Mode::SpectrumAnalysis: image_tag = portapack::spi_flash::image_tag_wideband_spectrum; break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
baseband::run_image(image_tag);
|
||||
|
||||
const auto is_wideband_spectrum_mode = (modulation == ReceiverModel::Mode::SpectrumAnalysis);
|
||||
receiver_model.set_baseband_configuration({
|
||||
.mode = toUType(modulation),
|
||||
|
||||
@@ -143,16 +143,13 @@ private:
|
||||
|
||||
RecordView record_view {
|
||||
{ 0 * 8, 2 * 16, 30 * 8, 1 * 16 },
|
||||
"AUD_????", RecordView::FileType::WAV, 12, 2,
|
||||
"AUD_????", RecordView::FileType::WAV, 4096, 4
|
||||
};
|
||||
|
||||
spectrum::WaterfallWidget waterfall;
|
||||
|
||||
void on_tuning_frequency_changed(rf::Frequency f);
|
||||
void on_baseband_bandwidth_changed(uint32_t bandwidth_hz);
|
||||
void on_rf_amp_changed(bool v);
|
||||
void on_lna_changed(int32_t v_db);
|
||||
void on_vga_changed(int32_t v_db);
|
||||
void on_modulation_changed(const ReceiverModel::Mode modulation);
|
||||
void on_show_options_frequency();
|
||||
void on_show_options_rf_gain();
|
||||
|
||||
@@ -26,8 +26,18 @@
|
||||
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include "core_control.hpp"
|
||||
|
||||
namespace baseband {
|
||||
|
||||
static void send_message(const Message* const message) {
|
||||
// If message is only sent by this function via one thread, no need to check if
|
||||
// another message is present before setting new message.
|
||||
shared_memory.baseband_message = message;
|
||||
creg::m0apptxevent::assert();
|
||||
while(shared_memory.baseband_message);
|
||||
}
|
||||
|
||||
void AMConfig::apply() const {
|
||||
const AMConfigureMessage message {
|
||||
taps_6k0_decim_0,
|
||||
@@ -37,7 +47,7 @@ void AMConfig::apply() const {
|
||||
modulation,
|
||||
audio_12k_hpf_300hz_config
|
||||
};
|
||||
shared_memory.baseband_queue.push(message);
|
||||
send_message(&message);
|
||||
audio::set_rate(audio::Rate::Hz_12000);
|
||||
}
|
||||
|
||||
@@ -51,7 +61,7 @@ void NBFMConfig::apply() const {
|
||||
audio_24k_hpf_300hz_config,
|
||||
audio_24k_deemph_300_6_config
|
||||
};
|
||||
shared_memory.baseband_queue.push(message);
|
||||
send_message(&message);
|
||||
audio::set_rate(audio::Rate::Hz_24000);
|
||||
}
|
||||
|
||||
@@ -64,26 +74,38 @@ void WFMConfig::apply() const {
|
||||
audio_48k_hpf_30hz_config,
|
||||
audio_48k_deemph_2122_6_config
|
||||
};
|
||||
shared_memory.baseband_queue.push(message);
|
||||
send_message(&message);
|
||||
audio::set_rate(audio::Rate::Hz_48000);
|
||||
}
|
||||
|
||||
void start(BasebandConfiguration configuration) {
|
||||
BasebandConfigurationMessage message { configuration };
|
||||
shared_memory.baseband_queue.push(message);
|
||||
}
|
||||
static bool baseband_image_running = false;
|
||||
|
||||
void stop() {
|
||||
shared_memory.baseband_queue.push_and_wait(
|
||||
BasebandConfigurationMessage {
|
||||
.configuration = { },
|
||||
}
|
||||
);
|
||||
void run_image(const portapack::spi_flash::image_tag_t image_tag) {
|
||||
if( baseband_image_running ) {
|
||||
chDbgPanic("BBRunning");
|
||||
}
|
||||
|
||||
creg::m4txevent::clear();
|
||||
|
||||
m4_init(image_tag, portapack::memory::map::m4_code);
|
||||
baseband_image_running = true;
|
||||
|
||||
creg::m4txevent::enable();
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
ShutdownMessage shutdown_message;
|
||||
shared_memory.baseband_queue.push(shutdown_message);
|
||||
if( !baseband_image_running ) {
|
||||
return;
|
||||
}
|
||||
|
||||
creg::m4txevent::disable();
|
||||
|
||||
ShutdownMessage message;
|
||||
send_message(&message);
|
||||
|
||||
shared_memory.application_queue.reset();
|
||||
|
||||
baseband_image_running = false;
|
||||
}
|
||||
|
||||
void spectrum_streaming_start(size_t decimation_factor) {
|
||||
@@ -96,19 +118,27 @@ void spectrum_streaming_start(size_t decimation_factor) {
|
||||
}
|
||||
|
||||
void spectrum_streaming_start() {
|
||||
shared_memory.baseband_queue.push_and_wait(
|
||||
SpectrumStreamingConfigMessage {
|
||||
SpectrumStreamingConfigMessage::Mode::Running
|
||||
}
|
||||
);
|
||||
SpectrumStreamingConfigMessage message {
|
||||
SpectrumStreamingConfigMessage::Mode::Running
|
||||
};
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
void spectrum_streaming_stop() {
|
||||
shared_memory.baseband_queue.push_and_wait(
|
||||
SpectrumStreamingConfigMessage {
|
||||
SpectrumStreamingConfigMessage::Mode::Stopped
|
||||
}
|
||||
);
|
||||
SpectrumStreamingConfigMessage message {
|
||||
SpectrumStreamingConfigMessage::Mode::Stopped
|
||||
};
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
void capture_start(CaptureConfig* const config) {
|
||||
CaptureConfigMessage message { config };
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
void capture_stop() {
|
||||
CaptureConfigMessage message { nullptr };
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
} /* namespace baseband */
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
#include "dsp_fir_taps.hpp"
|
||||
|
||||
#include "spi_image.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace baseband {
|
||||
@@ -50,15 +52,16 @@ struct WFMConfig {
|
||||
void apply() const;
|
||||
};
|
||||
|
||||
void start(BasebandConfiguration configuration);
|
||||
void stop();
|
||||
|
||||
void run_image(const portapack::spi_flash::image_tag_t image_tag);
|
||||
void shutdown();
|
||||
|
||||
void spectrum_streaming_start(size_t decimation_factor);
|
||||
void spectrum_streaming_start();
|
||||
void spectrum_streaming_stop();
|
||||
|
||||
void capture_start(CaptureConfig* const config);
|
||||
void capture_stop();
|
||||
|
||||
} /* namespace baseband */
|
||||
|
||||
#endif/*__BASEBAND_API_H__*/
|
||||
|
||||
@@ -21,59 +21,72 @@
|
||||
|
||||
#include "capture_app.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
using namespace portapack;
|
||||
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
|
||||
CaptureAppView::CaptureAppView(NavigationView& nav) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_capture);
|
||||
|
||||
add_children({ {
|
||||
&rssi,
|
||||
&channel,
|
||||
&field_frequency,
|
||||
&field_frequency_step,
|
||||
&field_rf_amp,
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&record_view,
|
||||
&waterfall,
|
||||
} });
|
||||
|
||||
field_frequency.set_value(receiver_model.tuning_frequency());
|
||||
field_frequency.set_value(target_frequency());
|
||||
field_frequency.set_step(receiver_model.frequency_step());
|
||||
field_frequency.on_change = [this](rf::Frequency f) {
|
||||
this->on_tuning_frequency_changed(f);
|
||||
this->on_target_frequency_changed(f);
|
||||
};
|
||||
field_frequency.on_edit = [this, &nav]() {
|
||||
// TODO: Provide separate modal method/scheme?
|
||||
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
|
||||
auto new_view = nav.push<FrequencyKeypadView>(this->target_frequency());
|
||||
new_view->on_changed = [this](rf::Frequency f) {
|
||||
this->on_tuning_frequency_changed(f);
|
||||
this->on_target_frequency_changed(f);
|
||||
this->field_frequency.set_value(f);
|
||||
};
|
||||
};
|
||||
|
||||
field_lna.set_value(receiver_model.lna());
|
||||
field_lna.on_change = [this](int32_t v) {
|
||||
this->on_lna_changed(v);
|
||||
field_frequency_step.set_by_value(receiver_model.frequency_step());
|
||||
field_frequency_step.on_change = [this](size_t, OptionsField::value_t v) {
|
||||
receiver_model.set_frequency_step(v);
|
||||
this->field_frequency.set_step(v);
|
||||
};
|
||||
|
||||
field_vga.set_value(receiver_model.vga());
|
||||
field_vga.on_change = [this](int32_t v_db) {
|
||||
this->on_vga_changed(v_db);
|
||||
};
|
||||
|
||||
receiver_model.set_baseband_configuration({
|
||||
.mode = toUType(ReceiverModel::Mode::Capture),
|
||||
.sampling_rate = sampling_rate,
|
||||
.decimation_factor = 1,
|
||||
radio::enable({
|
||||
tuning_frequency(),
|
||||
sampling_rate,
|
||||
baseband_bandwidth,
|
||||
rf::Direction::Receive,
|
||||
receiver_model.rf_amp(),
|
||||
static_cast<int8_t>(receiver_model.lna()),
|
||||
static_cast<int8_t>(receiver_model.vga()),
|
||||
1,
|
||||
});
|
||||
receiver_model.set_baseband_bandwidth(baseband_bandwidth);
|
||||
receiver_model.enable();
|
||||
|
||||
record_view.set_sampling_rate(sampling_rate / 8);
|
||||
record_view.on_error = [&nav](std::string message) {
|
||||
nav.display_modal("Error", message);
|
||||
};
|
||||
}
|
||||
|
||||
CaptureAppView::~CaptureAppView() {
|
||||
receiver_model.disable();
|
||||
radio::disable();
|
||||
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void CaptureAppView::on_hide() {
|
||||
@@ -94,16 +107,21 @@ void CaptureAppView::focus() {
|
||||
record_view.focus();
|
||||
}
|
||||
|
||||
void CaptureAppView::on_tuning_frequency_changed(rf::Frequency f) {
|
||||
receiver_model.set_tuning_frequency(f);
|
||||
void CaptureAppView::on_target_frequency_changed(rf::Frequency f) {
|
||||
set_target_frequency(f);
|
||||
}
|
||||
|
||||
void CaptureAppView::on_lna_changed(int32_t v_db) {
|
||||
receiver_model.set_lna(v_db);
|
||||
void CaptureAppView::set_target_frequency(const rf::Frequency new_value) {
|
||||
persistent_memory::set_tuned_frequency(new_value);;
|
||||
radio::set_tuning_frequency(tuning_frequency());
|
||||
}
|
||||
|
||||
void CaptureAppView::on_vga_changed(int32_t v_db) {
|
||||
receiver_model.set_vga(v_db);
|
||||
rf::Frequency CaptureAppView::target_frequency() const {
|
||||
return persistent_memory::tuned_frequency();
|
||||
}
|
||||
|
||||
rf::Frequency CaptureAppView::tuning_frequency() const {
|
||||
return target_frequency() - (sampling_rate / 4);
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -47,38 +47,49 @@ public:
|
||||
std::string title() const override { return "Capture"; };
|
||||
|
||||
private:
|
||||
static constexpr ui::Dim header_height = 3 * 16;
|
||||
static constexpr ui::Dim header_height = 2 * 16;
|
||||
|
||||
static constexpr uint32_t sampling_rate = 4000000;
|
||||
static constexpr uint32_t baseband_bandwidth = 2500000;
|
||||
|
||||
void on_tuning_frequency_changed(rf::Frequency f);
|
||||
void on_lna_changed(int32_t v_db);
|
||||
void on_vga_changed(int32_t v_db);
|
||||
void on_target_frequency_changed(rf::Frequency f);
|
||||
|
||||
rf::Frequency target_frequency() const;
|
||||
void set_target_frequency(const rf::Frequency new_value);
|
||||
|
||||
rf::Frequency tuning_frequency() const;
|
||||
|
||||
RSSI rssi {
|
||||
{ 21 * 8, 0, 6 * 8, 4 },
|
||||
{ 24 * 8, 0, 6 * 8, 4 },
|
||||
};
|
||||
|
||||
Channel channel {
|
||||
{ 21 * 8, 5, 6 * 8, 4 },
|
||||
{ 24 * 8, 5, 6 * 8, 4 },
|
||||
};
|
||||
|
||||
FrequencyField field_frequency {
|
||||
{ 5 * 8, 0 * 16 },
|
||||
{ 0 * 8, 0 * 16 },
|
||||
};
|
||||
|
||||
FrequencyStepView field_frequency_step {
|
||||
{ 10 * 8, 0 * 16 },
|
||||
};
|
||||
|
||||
RFAmpField field_rf_amp {
|
||||
{ 16 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
LNAGainField field_lna {
|
||||
{ 15 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
VGAGainField field_vga {
|
||||
{ 18 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
VGAGainField field_vga {
|
||||
{ 21 * 8, 0 * 16 }
|
||||
};
|
||||
|
||||
RecordView record_view {
|
||||
{ 0 * 8, 2 * 16, 30 * 8, 1 * 16 },
|
||||
"BBD_????", RecordView::FileType::RawS16, 14, 1,
|
||||
{ 0 * 8, 1 * 16, 30 * 8, 1 * 16 },
|
||||
"BBD_????", RecordView::FileType::RawS16, 16384, 3
|
||||
};
|
||||
|
||||
spectrum::WaterfallWidget waterfall;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "capture_thread.hpp"
|
||||
|
||||
#include "portapack_shared_memory.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
|
||||
// StreamOutput ///////////////////////////////////////////////////////////
|
||||
|
||||
@@ -31,36 +31,43 @@ public:
|
||||
~StreamOutput();
|
||||
|
||||
size_t available() {
|
||||
return fifo->len();
|
||||
return fifo_buffers_full->len();
|
||||
}
|
||||
|
||||
size_t read(void* const data, const size_t length) {
|
||||
return fifo->out(reinterpret_cast<uint8_t*>(data), length);
|
||||
StreamBuffer* get_buffer() {
|
||||
StreamBuffer* p { nullptr };
|
||||
fifo_buffers_full->out(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static FIFO<uint8_t>* fifo;
|
||||
bool release_buffer(StreamBuffer* const p) {
|
||||
p->empty();
|
||||
return fifo_buffers_empty->in(p);
|
||||
}
|
||||
|
||||
static FIFO<StreamBuffer*>* fifo_buffers_empty;
|
||||
static FIFO<StreamBuffer*>* fifo_buffers_full;
|
||||
|
||||
private:
|
||||
CaptureConfig* const config;
|
||||
};
|
||||
|
||||
FIFO<uint8_t>* StreamOutput::fifo = nullptr;
|
||||
FIFO<StreamBuffer*>* StreamOutput::fifo_buffers_empty = nullptr;
|
||||
FIFO<StreamBuffer*>* StreamOutput::fifo_buffers_full = nullptr;
|
||||
|
||||
StreamOutput::StreamOutput(
|
||||
CaptureConfig* const config
|
||||
) : config { config }
|
||||
{
|
||||
shared_memory.baseband_queue.push_and_wait(
|
||||
CaptureConfigMessage { config }
|
||||
);
|
||||
fifo = config->fifo;
|
||||
baseband::capture_start(config);
|
||||
fifo_buffers_empty = config->fifo_buffers_empty;
|
||||
fifo_buffers_full = config->fifo_buffers_full;
|
||||
}
|
||||
|
||||
StreamOutput::~StreamOutput() {
|
||||
fifo = nullptr;
|
||||
shared_memory.baseband_queue.push_and_wait(
|
||||
CaptureConfigMessage { nullptr }
|
||||
);
|
||||
fifo_buffers_full = nullptr;
|
||||
fifo_buffers_empty = nullptr;
|
||||
baseband::capture_stop();
|
||||
}
|
||||
|
||||
// CaptureThread //////////////////////////////////////////////////////////
|
||||
@@ -69,10 +76,14 @@ Thread* CaptureThread::thread = nullptr;
|
||||
|
||||
CaptureThread::CaptureThread(
|
||||
std::unique_ptr<Writer> writer,
|
||||
size_t write_size_log2,
|
||||
size_t buffer_count_log2
|
||||
) : config { write_size_log2, buffer_count_log2 },
|
||||
writer { std::move(writer) }
|
||||
size_t write_size,
|
||||
size_t buffer_count,
|
||||
std::function<void()> success_callback,
|
||||
std::function<void(File::Error)> error_callback
|
||||
) : config { write_size, buffer_count },
|
||||
writer { std::move(writer) },
|
||||
success_callback { std::move(success_callback) },
|
||||
error_callback { std::move(error_callback) }
|
||||
{
|
||||
// Need significant stack for FATFS
|
||||
thread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO + 10, CaptureThread::static_fn, this);
|
||||
@@ -81,7 +92,7 @@ CaptureThread::CaptureThread(
|
||||
CaptureThread::~CaptureThread() {
|
||||
if( thread ) {
|
||||
chThdTerminate(thread);
|
||||
chEvtSignal(thread, EVT_MASK_CAPTURE_THREAD);
|
||||
chEvtSignal(thread, event_mask_loop_wake);
|
||||
chThdWait(thread);
|
||||
thread = nullptr;
|
||||
}
|
||||
@@ -90,33 +101,42 @@ CaptureThread::~CaptureThread() {
|
||||
void CaptureThread::check_fifo_isr() {
|
||||
// TODO: Prevent over-signalling by transmitting a set of
|
||||
// flags from the baseband core.
|
||||
const auto fifo = StreamOutput::fifo;
|
||||
const auto fifo = StreamOutput::fifo_buffers_full;
|
||||
if( fifo ) {
|
||||
chEvtSignalI(thread, EVT_MASK_CAPTURE_THREAD);
|
||||
if( !fifo->is_empty() ) {
|
||||
chEvtSignalI(thread, event_mask_loop_wake);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msg_t CaptureThread::run() {
|
||||
const size_t write_size = 1U << config.write_size_log2;
|
||||
const auto write_buffer = std::make_unique<uint8_t[]>(write_size);
|
||||
if( !write_buffer ) {
|
||||
return false;
|
||||
msg_t CaptureThread::static_fn(void* arg) {
|
||||
auto obj = static_cast<CaptureThread*>(arg);
|
||||
const auto error = obj->run();
|
||||
if( error.is_valid() && obj->error_callback ) {
|
||||
obj->error_callback(error.value());
|
||||
} else {
|
||||
if( obj->success_callback ) {
|
||||
obj->success_callback();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Optional<File::Error> CaptureThread::run() {
|
||||
StreamOutput stream { &config };
|
||||
|
||||
while( !chThdShouldTerminate() ) {
|
||||
if( stream.available() >= write_size ) {
|
||||
if( stream.read(write_buffer.get(), write_size) != write_size ) {
|
||||
return false;
|
||||
}
|
||||
if( !writer->write(write_buffer.get(), write_size) ) {
|
||||
return false;
|
||||
if( stream.available() ) {
|
||||
auto buffer = stream.get_buffer();
|
||||
auto write_result = writer->write(buffer->data(), buffer->size());
|
||||
if( write_result.is_error() ) {
|
||||
return write_result.error();
|
||||
}
|
||||
stream.release_buffer(buffer);
|
||||
} else {
|
||||
chEvtWaitAny(EVT_MASK_CAPTURE_THREAD);
|
||||
chEvtWaitAny(event_mask_loop_wake);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return { };
|
||||
}
|
||||
|
||||
@@ -26,13 +26,16 @@
|
||||
|
||||
#include "event_m0.hpp"
|
||||
|
||||
#include "file.hpp"
|
||||
#include "optional.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
class Writer {
|
||||
public:
|
||||
virtual bool write(const void* const buffer, const size_t bytes) = 0;
|
||||
virtual File::Result<size_t> write(const void* const buffer, const size_t bytes) = 0;
|
||||
virtual ~Writer() = default;
|
||||
};
|
||||
|
||||
@@ -40,8 +43,10 @@ class CaptureThread {
|
||||
public:
|
||||
CaptureThread(
|
||||
std::unique_ptr<Writer> writer,
|
||||
size_t write_size_log2,
|
||||
size_t buffer_count_log2
|
||||
size_t write_size,
|
||||
size_t buffer_count,
|
||||
std::function<void()> success_callback,
|
||||
std::function<void(File::Error)> error_callback
|
||||
);
|
||||
~CaptureThread();
|
||||
|
||||
@@ -52,16 +57,17 @@ public:
|
||||
static void check_fifo_isr();
|
||||
|
||||
private:
|
||||
static constexpr auto event_mask_loop_wake = EVENT_MASK(0);
|
||||
|
||||
CaptureConfig config;
|
||||
std::unique_ptr<Writer> writer;
|
||||
std::function<void()> success_callback;
|
||||
std::function<void(File::Error)> error_callback;
|
||||
static Thread* thread;
|
||||
|
||||
static msg_t static_fn(void* arg) {
|
||||
auto obj = static_cast<CaptureThread*>(arg);
|
||||
return obj->run();
|
||||
}
|
||||
static msg_t static_fn(void* arg);
|
||||
|
||||
msg_t run();
|
||||
Optional<File::Error> run();
|
||||
};
|
||||
|
||||
#endif/*__CAPTURE_THREAD_H__*/
|
||||
|
||||
@@ -41,17 +41,27 @@ char * modhash;
|
||||
* I suppose I could force M4MEMMAP to an invalid memory reason which would
|
||||
* cause an exception and effectively halt the M4. But that feels gross.
|
||||
*/
|
||||
void m4_init(const portapack::spi_flash::region_t from, const portapack::memory::region_t to) {
|
||||
/* Initialize M4 code RAM */
|
||||
std::memcpy(reinterpret_cast<void*>(to.base()), from.base(), from.size);
|
||||
void m4_init(const portapack::spi_flash::image_tag_t image_tag, const portapack::memory::region_t to) {
|
||||
const portapack::spi_flash::chunk_t* chunk = reinterpret_cast<const portapack::spi_flash::chunk_t*>(portapack::spi_flash::images.base());
|
||||
while(chunk->tag) {
|
||||
if( chunk->tag == image_tag ) {
|
||||
/* Initialize M4 code RAM */
|
||||
std::memcpy(reinterpret_cast<void*>(to.base()), &chunk->data[0], chunk->length);
|
||||
|
||||
/* M4 core is assumed to be sleeping with interrupts off, so we can mess
|
||||
* with its address space and RAM without concern.
|
||||
*/
|
||||
LPC_CREG->M4MEMMAP = to.base();
|
||||
/* M4 core is assumed to be sleeping with interrupts off, so we can mess
|
||||
* with its address space and RAM without concern.
|
||||
*/
|
||||
LPC_CREG->M4MEMMAP = to.base();
|
||||
|
||||
/* Reset M4 core */
|
||||
LPC_RGU->RESET_CTRL[0] = (1 << 13);
|
||||
/* Reset M4 core */
|
||||
LPC_RGU->RESET_CTRL[0] = (1 << 13);
|
||||
|
||||
return;
|
||||
}
|
||||
chunk = chunk->next();
|
||||
}
|
||||
|
||||
chDbgPanic("NoImg");
|
||||
}
|
||||
|
||||
void m4_request_shutdown() {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "spi_image.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
|
||||
void m4_init(const portapack::spi_flash::region_t from, const portapack::memory::region_t to);
|
||||
void m4_init(const portapack::spi_flash::image_tag_t image_tag, const portapack::memory::region_t to);
|
||||
void m4_request_shutdown();
|
||||
void m4_switch(const char * hash);
|
||||
int m4_load_image(void);
|
||||
|
||||
@@ -21,11 +21,14 @@
|
||||
|
||||
#include "cpld_update.hpp"
|
||||
|
||||
#include "hackrf_gpio.hpp"
|
||||
#include "portapack_hal.hpp"
|
||||
|
||||
#include "jtag_target_gpio.hpp"
|
||||
#include "cpld_max5.hpp"
|
||||
#include "cpld_xilinx.hpp"
|
||||
#include "portapack_cpld_data.hpp"
|
||||
#include "hackrf_cpld_data.hpp"
|
||||
|
||||
bool cpld_update_if_necessary() {
|
||||
jtag::GPIOTarget target {
|
||||
@@ -82,3 +85,38 @@ bool cpld_update_if_necessary() {
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static jtag::GPIOTarget jtag_target_hackrf() {
|
||||
return {
|
||||
hackrf::one::gpio_cpld_tck,
|
||||
hackrf::one::gpio_cpld_tms,
|
||||
hackrf::one::gpio_cpld_tdi,
|
||||
hackrf::one::gpio_cpld_tdo,
|
||||
};
|
||||
}
|
||||
|
||||
bool cpld_hackrf_load_sram() {
|
||||
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
|
||||
cpld::xilinx::XC2C64A hackrf_cpld { jtag_target_hackrf_cpld };
|
||||
|
||||
hackrf_cpld.write_sram(hackrf::one::cpld::verify_blocks);
|
||||
const auto ok = hackrf_cpld.verify_sram(hackrf::one::cpld::verify_blocks);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool cpld_hackrf_verify_eeprom() {
|
||||
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
|
||||
cpld::xilinx::XC2C64A hackrf_cpld { jtag_target_hackrf_cpld };
|
||||
|
||||
const auto ok = hackrf_cpld.verify_eeprom(hackrf::one::cpld::verify_blocks);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void cpld_hackrf_init_from_eeprom() {
|
||||
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
|
||||
cpld::xilinx::XC2C64A hackrf_cpld { jtag_target_hackrf_cpld };
|
||||
|
||||
hackrf_cpld.init_from_eeprom();
|
||||
}
|
||||
|
||||
@@ -24,4 +24,8 @@
|
||||
|
||||
bool cpld_update_if_necessary();
|
||||
|
||||
bool cpld_hackrf_load_sram();
|
||||
bool cpld_hackrf_verify_eeprom();
|
||||
void cpld_hackrf_init_from_eeprom();
|
||||
|
||||
#endif/*__CPLD_UPDATE_H__*/
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
|
||||
#include "ert_app.hpp"
|
||||
|
||||
#include "event_m0.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
|
||||
#include "manchester.hpp"
|
||||
@@ -59,17 +57,9 @@ std::string commodity_type(CommodityType value) {
|
||||
|
||||
} /* namespace ert */
|
||||
|
||||
ERTLogger::ERTLogger(
|
||||
const std::string& file_path
|
||||
) : log_file { file_path }
|
||||
{
|
||||
}
|
||||
|
||||
void ERTLogger::on_packet(const ert::Packet& packet) {
|
||||
if( log_file.is_open() ) {
|
||||
const auto formatted = packet.symbols_formatted();
|
||||
log_file.write_entry(packet.received_at(), formatted.data + "/" + formatted.errors);
|
||||
}
|
||||
const auto formatted = packet.symbols_formatted();
|
||||
log_file.write_entry(packet.received_at(), formatted.data + "/" + formatted.errors);
|
||||
}
|
||||
|
||||
const ERTRecentEntry::Key ERTRecentEntry::invalid_key { };
|
||||
@@ -131,18 +121,12 @@ void RecentEntriesView<ERTRecentEntries>::draw(
|
||||
}
|
||||
|
||||
ERTAppView::ERTAppView(NavigationView&) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_ert);
|
||||
|
||||
add_children({ {
|
||||
&recent_entries_view,
|
||||
} });
|
||||
|
||||
EventDispatcher::message_map().register_handler(Message::ID::ERTPacket,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const ERTPacketMessage*>(p);
|
||||
const ert::Packet packet { message->type, message->packet };
|
||||
this->on_packet(packet);
|
||||
}
|
||||
);
|
||||
|
||||
radio::enable({
|
||||
initial_target_frequency,
|
||||
sampling_rate,
|
||||
@@ -152,20 +136,16 @@ ERTAppView::ERTAppView(NavigationView&) {
|
||||
1,
|
||||
});
|
||||
|
||||
baseband::start({
|
||||
.mode = 6,
|
||||
.sampling_rate = sampling_rate,
|
||||
.decimation_factor = 1,
|
||||
});
|
||||
|
||||
logger = std::make_unique<ERTLogger>("ert.txt");
|
||||
logger = std::make_unique<ERTLogger>();
|
||||
if( logger ) {
|
||||
logger->append("ert.txt");
|
||||
}
|
||||
}
|
||||
|
||||
ERTAppView::~ERTAppView() {
|
||||
baseband::stop();
|
||||
radio::disable();
|
||||
|
||||
EventDispatcher::message_map().unregister_handler(Message::ID::ERTPacket);
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void ERTAppView::focus() {
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
#include "ui_navigation.hpp"
|
||||
|
||||
#include "event_m0.hpp"
|
||||
|
||||
#include "log_file.hpp"
|
||||
|
||||
#include "ert_packet.hpp"
|
||||
@@ -85,8 +87,10 @@ struct ERTRecentEntry {
|
||||
|
||||
class ERTLogger {
|
||||
public:
|
||||
ERTLogger(const std::string& file_path);
|
||||
|
||||
Optional<File::Error> append(const std::string& filename) {
|
||||
return log_file.append(filename);
|
||||
}
|
||||
|
||||
void on_packet(const ert::Packet& packet);
|
||||
|
||||
private:
|
||||
@@ -124,6 +128,15 @@ private:
|
||||
|
||||
ERTRecentEntriesView recent_entries_view { recent };
|
||||
|
||||
MessageHandlerRegistration message_handler_packet {
|
||||
Message::ID::ERTPacket,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const ERTPacketMessage*>(p);
|
||||
const ert::Packet packet { message->type, message->packet };
|
||||
this->on_packet(packet);
|
||||
}
|
||||
};
|
||||
|
||||
void on_packet(const ert::Packet& packet);
|
||||
void on_show_list();
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user