Add software
This commit is contained in:
		
							
								
								
									
										544
									
								
								Software/portapack-mayhem/firmware/baseband/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										544
									
								
								Software/portapack-mayhem/firmware/baseband/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,544 @@
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
# Copyright (C) 2016 Furrtek
 | 
			
		||||
#
 | 
			
		||||
# 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(baseband_shared)
 | 
			
		||||
 | 
			
		||||
# Compiler options here.
 | 
			
		||||
set(USE_OPT "-O3 -g -falign-functions=16 -fno-math-errno --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++17 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized")
 | 
			
		||||
 | 
			
		||||
# 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 hard)
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Architecture or project specific options
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
##############################################################################
 | 
			
		||||
# Project, sources and paths
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
# Imported source files and paths
 | 
			
		||||
include(${CHIBIOS_PORTAPACK}/boards/PORTAPACK_BASEBAND/board.cmake)
 | 
			
		||||
include(${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M4/platform.cmake)
 | 
			
		||||
include(${CHIBIOS}/os/hal/hal.cmake)
 | 
			
		||||
include(${CHIBIOS_PORTAPACK}/os/ports/GCC/ARMCMx/LPC43xx_M4/port.cmake)
 | 
			
		||||
include(${CHIBIOS}/os/kernel/kernel.cmake)
 | 
			
		||||
 | 
			
		||||
include(${CHIBIOS}/test/test.cmake)
 | 
			
		||||
 | 
			
		||||
# Define linker script file here
 | 
			
		||||
set(LDSCRIPT ${PORTLD}/LPC43xx_M4.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}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
 | 
			
		||||
# setting.
 | 
			
		||||
set(CPPSRC
 | 
			
		||||
	baseband.cpp
 | 
			
		||||
	${COMMON}/message_queue.cpp
 | 
			
		||||
	${COMMON}/event.cpp
 | 
			
		||||
	event_m4.cpp
 | 
			
		||||
	${COMMON}/thread_wait.cpp
 | 
			
		||||
	${COMMON}/gpdma.cpp
 | 
			
		||||
	baseband_dma.cpp
 | 
			
		||||
	${COMMON}/baseband_sgpio.cpp
 | 
			
		||||
	${COMMON}/portapack_shared_memory.cpp
 | 
			
		||||
	${COMMON}/buffer.cpp
 | 
			
		||||
	baseband_thread.cpp
 | 
			
		||||
	baseband_processor.cpp
 | 
			
		||||
	baseband_stats_collector.cpp
 | 
			
		||||
	dsp_decimate.cpp
 | 
			
		||||
	dsp_demodulate.cpp
 | 
			
		||||
	dsp_hilbert.cpp
 | 
			
		||||
	dsp_modulate.cpp
 | 
			
		||||
	dsp_goertzel.cpp
 | 
			
		||||
	matched_filter.cpp
 | 
			
		||||
	spectrum_collector.cpp
 | 
			
		||||
	tv_collector.cpp
 | 
			
		||||
	stream_input.cpp
 | 
			
		||||
	stream_output.cpp
 | 
			
		||||
	dsp_squelch.cpp
 | 
			
		||||
	clock_recovery.cpp
 | 
			
		||||
	packet_builder.cpp
 | 
			
		||||
	${COMMON}/dsp_fft.cpp
 | 
			
		||||
	${COMMON}/dsp_fir_taps.cpp
 | 
			
		||||
	${COMMON}/dsp_iir.cpp
 | 
			
		||||
	${COMMON}/dsp_sos.cpp
 | 
			
		||||
	fxpt_atan2.cpp
 | 
			
		||||
	rssi.cpp
 | 
			
		||||
	rssi_dma.cpp
 | 
			
		||||
	rssi_thread.cpp
 | 
			
		||||
	audio_compressor.cpp
 | 
			
		||||
	audio_output.cpp
 | 
			
		||||
	audio_input.cpp
 | 
			
		||||
	audio_dma.cpp
 | 
			
		||||
	audio_stats_collector.cpp
 | 
			
		||||
	${COMMON}/utility.cpp
 | 
			
		||||
	${COMMON}/chibios_cpp.cpp
 | 
			
		||||
	${COMMON}/debug.cpp
 | 
			
		||||
	${COMMON}/gcc.cpp
 | 
			
		||||
	tone_gen.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 ${COMMON} ${PORTINC} ${KERNINC} ${TESTINC}
 | 
			
		||||
	${HALINC} ${PLATFORMINC} ${BOARDINC}
 | 
			
		||||
	${CHIBIOS}/os/various
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Project, sources and paths
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
##############################################################################
 | 
			
		||||
# Compiler settings
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
set(MCU cortex-m4)
 | 
			
		||||
 | 
			
		||||
# 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_M4 -D__NEWLIB__ -DHACKRF_ONE -DTOOLCHAIN_GCC -DTOOLCHAIN_GCC_ARM -D_RANDOM_TCC=0 -D'VERSION_STRING=\"${VERSION}\"'")
 | 
			
		||||
 | 
			
		||||
# 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_library(${PROJECT_NAME} OBJECT ${CSRC} ${CPPSRC} ${ASMSRC})
 | 
			
		||||
include_directories(. ${INCDIR})
 | 
			
		||||
 | 
			
		||||
#######################################################################
 | 
			
		||||
 | 
			
		||||
set(BASEBAND_IMAGES)
 | 
			
		||||
 | 
			
		||||
macro(DeclareTargets chunk_tag name)
 | 
			
		||||
	project("baseband_${name}")
 | 
			
		||||
 | 
			
		||||
	include(${RULESPATH}/rules.cmake)
 | 
			
		||||
	add_executable(${PROJECT_NAME}.elf $<TARGET_OBJECTS:baseband_shared> ${MODE_CPPSRC})
 | 
			
		||||
	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})
 | 
			
		||||
	target_link_libraries(${PROJECT_NAME}.elf -Wl,-Map=${PROJECT_NAME}.map)
 | 
			
		||||
 | 
			
		||||
	add_custom_command(
 | 
			
		||||
		OUTPUT ${PROJECT_NAME}.bin ${PROJECT_NAME}.img
 | 
			
		||||
		COMMAND ${CMAKE_OBJCOPY} -O binary ${PROJECT_NAME}.elf ${PROJECT_NAME}.bin
 | 
			
		||||
		COMMAND ${MAKE_IMAGE_CHUNK} ${PROJECT_NAME}.bin ${chunk_tag} ${PROJECT_NAME}.img
 | 
			
		||||
		DEPENDS ${PROJECT_NAME}.elf ${MAKE_IMAGE_CHUNK}
 | 
			
		||||
		VERBATIM
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	set(BASEBAND_IMAGES ${BASEBAND_IMAGES} ${PROJECT_NAME}.img)
 | 
			
		||||
endmacro()
 | 
			
		||||
 | 
			
		||||
### ACARS RX
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_acars.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PACA acars)
 | 
			
		||||
 | 
			
		||||
### ADS-B RX
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_adsbrx.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PADR adsbrx)
 | 
			
		||||
 | 
			
		||||
### ADS-B TX
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_adsbtx.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PADT adsbtx)
 | 
			
		||||
 | 
			
		||||
### AFSK
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_afsk.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PAFT afsktx)
 | 
			
		||||
 | 
			
		||||
### AFSK RX
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_afskrx.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PAFR afskrx)
 | 
			
		||||
 | 
			
		||||
### APRS RX
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_aprsrx.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PAPR aprsrx)
 | 
			
		||||
 | 
			
		||||
### NRF RX
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_nrfrx.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PNRR nrfrx)
 | 
			
		||||
 | 
			
		||||
### BTLE RX
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_btlerx.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PBTR btlerx)
 | 
			
		||||
### AIS
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_ais.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PAIS ais)
 | 
			
		||||
 | 
			
		||||
### AM Audio
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_am_audio.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PAMA am_audio)
 | 
			
		||||
 | 
			
		||||
### AM TV
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_am_tv.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PAMT am_tv)
 | 
			
		||||
 | 
			
		||||
### Audio transmit
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_audiotx.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PATX audio_tx)
 | 
			
		||||
 | 
			
		||||
### Capture
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_capture.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PCAP capture)
 | 
			
		||||
 | 
			
		||||
### ERT
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_ert.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PERT ert)
 | 
			
		||||
 | 
			
		||||
### Radiosonde
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_sonde.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PSON sonde)
 | 
			
		||||
 | 
			
		||||
### FSK TX
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_fsk.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PFSK fsktx)
 | 
			
		||||
 | 
			
		||||
### Jammer
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_jammer.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PJAM jammer)
 | 
			
		||||
 | 
			
		||||
### Microphone transmit
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_mictx.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PMTX mic_tx)
 | 
			
		||||
 | 
			
		||||
### NFM Audio
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_nfm_audio.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PNFM nfm_audio)
 | 
			
		||||
 | 
			
		||||
### No op
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_noop.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PNOP no_operation)
 | 
			
		||||
 | 
			
		||||
### OOK
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_ook.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(POOK ook)
 | 
			
		||||
 | 
			
		||||
### POCSAG RX
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_pocsag.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PPOC pocsag)
 | 
			
		||||
 | 
			
		||||
### RDS
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_rds.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PRDS rds)
 | 
			
		||||
 | 
			
		||||
### Replay
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_replay.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PREP replay)
 | 
			
		||||
 | 
			
		||||
### GPS Simulator
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_gps_sim.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PGPS gps_sim)
 | 
			
		||||
 | 
			
		||||
### Signal generator
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_siggen.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PSIG siggen)
 | 
			
		||||
 | 
			
		||||
### SSTV TX
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_sstvtx.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PSTX sstvtx)
 | 
			
		||||
 | 
			
		||||
### Test
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_test.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PTST test)
 | 
			
		||||
 | 
			
		||||
### Tones
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_tones.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PTON tones)
 | 
			
		||||
 | 
			
		||||
### TPMS
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_tpms.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PTPM tpms)
 | 
			
		||||
 | 
			
		||||
### Wideband Spectrum
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_wideband_spectrum.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PSPE wideband_spectrum)
 | 
			
		||||
 | 
			
		||||
### WFM Audio
 | 
			
		||||
 | 
			
		||||
set(MODE_CPPSRC
 | 
			
		||||
	proc_wfm_audio.cpp
 | 
			
		||||
)
 | 
			
		||||
DeclareTargets(PWFM wfm_audio)
 | 
			
		||||
 | 
			
		||||
### HackRF "factory" firmware
 | 
			
		||||
 | 
			
		||||
add_custom_command(
 | 
			
		||||
	OUTPUT hackrf.img
 | 
			
		||||
	COMMAND ${MAKE_IMAGE_CHUNK} ${HACKRF_FIRMWARE_BIN_IMAGE} HRF1 hackrf.img 98304
 | 
			
		||||
	DEPENDS ${HACKRF_FIRMWARE_BIN_FILENAME} ${MAKE_IMAGE_CHUNK}
 | 
			
		||||
	VERBATIM
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(BASEBAND_IMAGES ${BASEBAND_IMAGES} hackrf.img)
 | 
			
		||||
 | 
			
		||||
### Terminator image
 | 
			
		||||
 | 
			
		||||
add_custom_command(
 | 
			
		||||
	OUTPUT terminator.img
 | 
			
		||||
	COMMAND ${MAKE_IMAGE_CHUNK} terminator.img
 | 
			
		||||
	DEPENDS ${MAKE_IMAGE_CHUNK}
 | 
			
		||||
	VERBATIM
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(BASEBAND_IMAGES ${BASEBAND_IMAGES} terminator.img)
 | 
			
		||||
 | 
			
		||||
#######################################################################
 | 
			
		||||
 | 
			
		||||
project(baseband)
 | 
			
		||||
	
 | 
			
		||||
add_custom_command(
 | 
			
		||||
	OUTPUT ${PROJECT_NAME}.img
 | 
			
		||||
	COMMAND cat ${BASEBAND_IMAGES} > ${PROJECT_NAME}.img
 | 
			
		||||
	DEPENDS ${BASEBAND_IMAGES}
 | 
			
		||||
	DEPENDS hackrf.img terminator.img
 | 
			
		||||
	VERBATIM
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
add_custom_target(
 | 
			
		||||
	${PROJECT_NAME}
 | 
			
		||||
	DEPENDS ${PROJECT_NAME}.img
 | 
			
		||||
)
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "audio_compressor.hpp"
 | 
			
		||||
 | 
			
		||||
float GainComputer::operator()(const float x) const {
 | 
			
		||||
	const auto abs_x = std::abs(x);
 | 
			
		||||
	const auto db = (abs_x < lin_floor) ? db_floor : log2_db_k * fast_log2(abs_x);
 | 
			
		||||
	const auto overshoot_db = db - threshold_db;
 | 
			
		||||
	if( knee_width_db > 0.0f ) {
 | 
			
		||||
		const auto w2 = knee_width_db / 2.0f;
 | 
			
		||||
		const auto a = w2 / (knee_width_db * knee_width_db);
 | 
			
		||||
		const auto in_transition = (overshoot_db > -w2) && (overshoot_db < w2);
 | 
			
		||||
		const auto rectified_overshoot = in_transition ? (a * std::pow(overshoot_db + w2, 2.0f)) : std::max(overshoot_db, 0.0f);
 | 
			
		||||
		return rectified_overshoot * slope;
 | 
			
		||||
	} else {
 | 
			
		||||
		const auto rectified_overshoot = std::max(overshoot_db, 0.0f);
 | 
			
		||||
		return rectified_overshoot * slope;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FeedForwardCompressor::execute_in_place(const buffer_f32_t& buffer) {
 | 
			
		||||
	constexpr float makeup_gain = std::pow(10.0f, (threshold - (threshold / ratio)) / -20.0f);
 | 
			
		||||
	for(size_t i=0; i<buffer.count; i++) {
 | 
			
		||||
		buffer.p[i] = execute_once(buffer.p[i]) * makeup_gain;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float FeedForwardCompressor::execute_once(const float x) {
 | 
			
		||||
	const auto gain_db = gain_computer(x);
 | 
			
		||||
	const auto peak_db = -peak_detector(-gain_db);
 | 
			
		||||
	const auto gain = fast_pow2(peak_db * (3.321928094887362f / 20.0f));
 | 
			
		||||
	return x * gain;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										102
									
								
								Software/portapack-mayhem/firmware/baseband/audio_compressor.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								Software/portapack-mayhem/firmware/baseband/audio_compressor.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __AUDIO_COMPRESSOR_H__
 | 
			
		||||
#define __AUDIO_COMPRESSOR_H__
 | 
			
		||||
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cmath>
 | 
			
		||||
 | 
			
		||||
/* Code based on article in Journal of the Audio Engineering Society
 | 
			
		||||
 * Vol. 60, No. 6, 2012 June, by Dimitrios Giannoulis, Michael Massberg,
 | 
			
		||||
 * Joshua D. Reiss "Digital Dynamic Range Compressor Design – A Tutorial
 | 
			
		||||
 * and Analysis"
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
class GainComputer {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr GainComputer(
 | 
			
		||||
		float ratio,
 | 
			
		||||
		float threshold
 | 
			
		||||
	) : ratio { ratio },
 | 
			
		||||
		slope { 1.0f / ratio - 1.0f },
 | 
			
		||||
		threshold_db { threshold }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	float operator()(const float x) const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	const float ratio;
 | 
			
		||||
	const float slope;
 | 
			
		||||
	const float threshold_db;
 | 
			
		||||
 | 
			
		||||
	static constexpr float knee_width_db = 0.0f;
 | 
			
		||||
 | 
			
		||||
	static constexpr float db_floor = -120.0f;
 | 
			
		||||
	static constexpr float lin_floor = std::pow(10.0f, db_floor / 20.0f);
 | 
			
		||||
	static constexpr float log2_db_k = 20.0f * std::log10(2.0f);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class PeakDetectorBranchingSmooth {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr PeakDetectorBranchingSmooth(
 | 
			
		||||
		float att_a,
 | 
			
		||||
		float rel_a
 | 
			
		||||
	) : att_a { att_a },
 | 
			
		||||
		rel_a { rel_a }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	float operator()(const float db) {
 | 
			
		||||
		const auto a = (db > state) ? att_a : rel_a;
 | 
			
		||||
		state = db + a * (state - db);
 | 
			
		||||
		return state;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	float state { 0.0f };
 | 
			
		||||
	const float att_a;
 | 
			
		||||
	const float rel_a;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class FeedForwardCompressor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute_in_place(const buffer_f32_t& buffer);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr float fs = 12000.0f;
 | 
			
		||||
	static constexpr float ratio = 10.0f;
 | 
			
		||||
	static constexpr float threshold = -30.0f;
 | 
			
		||||
 | 
			
		||||
	GainComputer gain_computer { ratio, threshold };
 | 
			
		||||
	PeakDetectorBranchingSmooth peak_detector { tau_alpha(0.010f, fs), tau_alpha(0.300f, fs) };
 | 
			
		||||
 | 
			
		||||
	float execute_once(const float x);
 | 
			
		||||
 | 
			
		||||
	static constexpr float tau_alpha(const float tau, const float fs) {
 | 
			
		||||
		return std::exp(-1.0f / (tau * fs));
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__AUDIO_COMPRESSOR_H__*/
 | 
			
		||||
							
								
								
									
										239
									
								
								Software/portapack-mayhem/firmware/baseband/audio_dma.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								Software/portapack-mayhem/firmware/baseband/audio_dma.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,239 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "audio_dma.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
#include "hal.h"
 | 
			
		||||
#include "gpdma.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace lpc43xx;
 | 
			
		||||
 | 
			
		||||
#include "portapack_dma.hpp"
 | 
			
		||||
 | 
			
		||||
namespace audio {
 | 
			
		||||
namespace dma {
 | 
			
		||||
 | 
			
		||||
constexpr uint32_t gpdma_ahb_master_peripheral = 1;
 | 
			
		||||
constexpr uint32_t gpdma_ahb_master_memory = 0;
 | 
			
		||||
constexpr uint32_t gpdma_ahb_master_lli_fetch = 0;
 | 
			
		||||
 | 
			
		||||
constexpr uint32_t gpdma_rx_peripheral = 0x9;		/* I2S0 DMA request 1 */
 | 
			
		||||
constexpr uint32_t gpdma_rx_src_peripheral = gpdma_rx_peripheral;
 | 
			
		||||
constexpr uint32_t gpdma_rx_dest_peripheral = gpdma_rx_peripheral;
 | 
			
		||||
 | 
			
		||||
constexpr uint32_t gpdma_tx_peripheral = 0xa;		/* I2S0 DMA request 2 */
 | 
			
		||||
constexpr uint32_t gpdma_tx_src_peripheral = gpdma_tx_peripheral;
 | 
			
		||||
constexpr uint32_t gpdma_tx_dest_peripheral = gpdma_tx_peripheral;
 | 
			
		||||
 | 
			
		||||
constexpr gpdma::channel::LLIPointer lli_pointer(const void* lli) {
 | 
			
		||||
	return {
 | 
			
		||||
		.lm = gpdma_ahb_master_lli_fetch,
 | 
			
		||||
		.r = 0,
 | 
			
		||||
		.lli = reinterpret_cast<uint32_t>(lli),
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr gpdma::channel::Control control_tx(const size_t transfer_bytes) {
 | 
			
		||||
	return {
 | 
			
		||||
		.transfersize = gpdma::buffer_words(transfer_bytes, 4),
 | 
			
		||||
		.sbsize = 4,  /* Burst size: 32 */
 | 
			
		||||
		.dbsize = 4,  /* Burst size: 32 */
 | 
			
		||||
		.swidth = 2,  /* Source transfer width: word (32 bits) */
 | 
			
		||||
		.dwidth = 2,  /* Destination transfer width: word (32 bits) */
 | 
			
		||||
		.s = gpdma_ahb_master_memory,
 | 
			
		||||
		.d = gpdma_ahb_master_peripheral,
 | 
			
		||||
		.si = 1,
 | 
			
		||||
		.di = 0,
 | 
			
		||||
		.prot1 = 0,
 | 
			
		||||
		.prot2 = 0,
 | 
			
		||||
		.prot3 = 0,
 | 
			
		||||
		.i = 1,
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr gpdma::channel::Config config_tx() {
 | 
			
		||||
	return {
 | 
			
		||||
		.e = 0,
 | 
			
		||||
		.srcperipheral = gpdma_tx_src_peripheral,
 | 
			
		||||
		.destperipheral = gpdma_tx_dest_peripheral,
 | 
			
		||||
		.flowcntrl = gpdma::FlowControl::MemoryToPeripheral_DMAControl,
 | 
			
		||||
		.ie = 1,
 | 
			
		||||
		.itc = 1,
 | 
			
		||||
		.l = 0,
 | 
			
		||||
		.a = 0,
 | 
			
		||||
		.h = 0,
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr gpdma::channel::Control control_rx(const size_t transfer_bytes) {
 | 
			
		||||
	return {
 | 
			
		||||
		.transfersize = gpdma::buffer_words(transfer_bytes, 4),
 | 
			
		||||
		.sbsize = 4,  /* Burst size: 32 */
 | 
			
		||||
		.dbsize = 4,  /* Burst size: 32 */
 | 
			
		||||
		.swidth = 2,  /* Source transfer width: word (32 bits) */
 | 
			
		||||
		.dwidth = 2,  /* Destination transfer width: word (32 bits) */
 | 
			
		||||
		.s = gpdma_ahb_master_peripheral,
 | 
			
		||||
		.d = gpdma_ahb_master_memory,
 | 
			
		||||
		.si = 0,
 | 
			
		||||
		.di = 1,
 | 
			
		||||
		.prot1 = 0,
 | 
			
		||||
		.prot2 = 0,
 | 
			
		||||
		.prot3 = 0,
 | 
			
		||||
		.i = 1,
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr gpdma::channel::Config config_rx() {
 | 
			
		||||
	return {
 | 
			
		||||
		.e = 0,
 | 
			
		||||
		.srcperipheral = gpdma_rx_src_peripheral,
 | 
			
		||||
		.destperipheral = gpdma_rx_dest_peripheral,
 | 
			
		||||
		.flowcntrl = gpdma::FlowControl::PeripheralToMemory_DMAControl,
 | 
			
		||||
		.ie = 1,
 | 
			
		||||
		.itc = 1,
 | 
			
		||||
		.l = 0,
 | 
			
		||||
		.a = 0,
 | 
			
		||||
		.h = 0,
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* TODO: Clean up terminology around "buffer", "transfer", "samples" */
 | 
			
		||||
 | 
			
		||||
constexpr size_t buffer_samples_log2n = 7;
 | 
			
		||||
constexpr size_t buffer_samples = (1 << buffer_samples_log2n);
 | 
			
		||||
constexpr size_t transfers_per_buffer_log2n = 2;
 | 
			
		||||
constexpr size_t transfers_per_buffer = (1 << transfers_per_buffer_log2n);
 | 
			
		||||
constexpr size_t transfer_samples = buffer_samples / transfers_per_buffer;
 | 
			
		||||
constexpr size_t transfers_mask = transfers_per_buffer - 1;
 | 
			
		||||
 | 
			
		||||
constexpr size_t buffer_bytes = buffer_samples * sizeof(sample_t);
 | 
			
		||||
constexpr size_t transfer_bytes = transfer_samples * sizeof(sample_t);
 | 
			
		||||
 | 
			
		||||
static std::array<sample_t, buffer_samples> buffer_tx;
 | 
			
		||||
static std::array<sample_t, buffer_samples> buffer_rx;
 | 
			
		||||
 | 
			
		||||
static std::array<gpdma::channel::LLI, transfers_per_buffer> lli_tx_loop;
 | 
			
		||||
static std::array<gpdma::channel::LLI, transfers_per_buffer> lli_rx_loop;
 | 
			
		||||
 | 
			
		||||
static constexpr auto& gpdma_channel_i2s0_tx = gpdma::channels[portapack::i2s0_tx_gpdma_channel_number];
 | 
			
		||||
static constexpr auto& gpdma_channel_i2s0_rx = gpdma::channels[portapack::i2s0_rx_gpdma_channel_number];
 | 
			
		||||
 | 
			
		||||
static volatile const gpdma::channel::LLI* tx_next_lli = nullptr;
 | 
			
		||||
static volatile const gpdma::channel::LLI* rx_next_lli = nullptr;
 | 
			
		||||
 | 
			
		||||
static void tx_transfer_complete() {
 | 
			
		||||
	tx_next_lli = gpdma_channel_i2s0_tx.next_lli();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void tx_error() {
 | 
			
		||||
	disable();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rx_transfer_complete() {
 | 
			
		||||
	rx_next_lli = gpdma_channel_i2s0_rx.next_lli();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rx_error() {
 | 
			
		||||
	disable();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void init() {
 | 
			
		||||
	gpdma_channel_i2s0_tx.set_handlers(tx_transfer_complete, tx_error);
 | 
			
		||||
	gpdma_channel_i2s0_rx.set_handlers(rx_transfer_complete, rx_error);
 | 
			
		||||
 | 
			
		||||
	// LPC_GPDMA->SYNC |= (1 << gpdma_rx_peripheral);
 | 
			
		||||
	// LPC_GPDMA->SYNC |= (1 << gpdma_tx_peripheral);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void configure_tx() {
 | 
			
		||||
	const auto peripheral = reinterpret_cast<uint32_t>(&LPC_I2S0->TXFIFO);
 | 
			
		||||
	const auto control_value = control_tx(transfer_bytes);
 | 
			
		||||
	for(size_t i=0; i<lli_tx_loop.size(); i++) {
 | 
			
		||||
		const auto memory = reinterpret_cast<uint32_t>(&buffer_tx[i * transfer_samples]);
 | 
			
		||||
		lli_tx_loop[i].srcaddr = memory;
 | 
			
		||||
		lli_tx_loop[i].destaddr = peripheral;
 | 
			
		||||
		lli_tx_loop[i].lli = lli_pointer(&lli_tx_loop[(i + 1) % lli_tx_loop.size()]);
 | 
			
		||||
		lli_tx_loop[i].control = control_value;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void configure_rx() {
 | 
			
		||||
	const auto peripheral = reinterpret_cast<uint32_t>(&LPC_I2S0->RXFIFO);
 | 
			
		||||
	const auto control_value = control_rx(transfer_bytes);
 | 
			
		||||
	for(size_t i=0; i<lli_rx_loop.size(); i++) {
 | 
			
		||||
		const auto memory = reinterpret_cast<uint32_t>(&buffer_rx[i * transfer_samples]);
 | 
			
		||||
		lli_rx_loop[i].srcaddr = peripheral;
 | 
			
		||||
		lli_rx_loop[i].destaddr = memory;
 | 
			
		||||
		lli_rx_loop[i].lli = lli_pointer(&lli_rx_loop[(i + 1) % lli_rx_loop.size()]);
 | 
			
		||||
		lli_rx_loop[i].control = control_value;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void configure() {
 | 
			
		||||
	configure_tx();
 | 
			
		||||
	configure_rx();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void enable() {
 | 
			
		||||
	const auto gpdma_config_tx = config_tx();
 | 
			
		||||
	const auto gpdma_config_rx = config_rx();
 | 
			
		||||
 | 
			
		||||
	gpdma_channel_i2s0_tx.configure(lli_tx_loop[0], gpdma_config_tx);
 | 
			
		||||
	gpdma_channel_i2s0_rx.configure(lli_rx_loop[0], gpdma_config_rx);
 | 
			
		||||
 | 
			
		||||
	gpdma_channel_i2s0_tx.enable();
 | 
			
		||||
	gpdma_channel_i2s0_rx.enable();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void disable() {
 | 
			
		||||
	gpdma_channel_i2s0_tx.disable();
 | 
			
		||||
	gpdma_channel_i2s0_rx.disable();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_t tx_empty_buffer() {
 | 
			
		||||
	const auto next_lli = tx_next_lli;
 | 
			
		||||
	if( next_lli ) {
 | 
			
		||||
		const size_t next_index = next_lli - &lli_tx_loop[0];
 | 
			
		||||
		const size_t free_index = (next_index + transfers_per_buffer - 2) & transfers_mask;
 | 
			
		||||
		return { reinterpret_cast<sample_t*>(lli_tx_loop[free_index].srcaddr), transfer_samples };
 | 
			
		||||
	} else {
 | 
			
		||||
		return { nullptr, 0 };
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_t rx_empty_buffer() {
 | 
			
		||||
	const auto next_lli = rx_next_lli;
 | 
			
		||||
	if( next_lli ) {
 | 
			
		||||
		const size_t next_index = next_lli - &lli_rx_loop[0];
 | 
			
		||||
		const size_t free_index = (next_index + transfers_per_buffer - 2) & transfers_mask;
 | 
			
		||||
		return { reinterpret_cast<sample_t*>(lli_rx_loop[free_index].destaddr), transfer_samples };
 | 
			
		||||
	} else {
 | 
			
		||||
		return { nullptr, 0 };
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace dma */
 | 
			
		||||
} /* namespace audio */
 | 
			
		||||
							
								
								
									
										57
									
								
								Software/portapack-mayhem/firmware/baseband/audio_dma.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								Software/portapack-mayhem/firmware/baseband/audio_dma.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __AUDIO_DMA_H__
 | 
			
		||||
#define __AUDIO_DMA_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
#include "buffer.hpp"
 | 
			
		||||
 | 
			
		||||
namespace audio {
 | 
			
		||||
 | 
			
		||||
struct sample_t {
 | 
			
		||||
	union {
 | 
			
		||||
		struct {
 | 
			
		||||
			int16_t left;
 | 
			
		||||
			int16_t right;
 | 
			
		||||
		};
 | 
			
		||||
		uint32_t raw;
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using buffer_t = buffer_t<sample_t>;
 | 
			
		||||
 | 
			
		||||
namespace dma {
 | 
			
		||||
 | 
			
		||||
void init();
 | 
			
		||||
void configure();
 | 
			
		||||
void enable();
 | 
			
		||||
void disable();
 | 
			
		||||
 | 
			
		||||
audio::buffer_t tx_empty_buffer();
 | 
			
		||||
audio::buffer_t rx_empty_buffer();
 | 
			
		||||
 | 
			
		||||
} /* namespace dma */
 | 
			
		||||
} /* namespace audio */
 | 
			
		||||
 | 
			
		||||
#endif/*__AUDIO_DMA_H__*/
 | 
			
		||||
							
								
								
									
										40
									
								
								Software/portapack-mayhem/firmware/baseband/audio_input.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								Software/portapack-mayhem/firmware/baseband/audio_input.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "audio_input.hpp"
 | 
			
		||||
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
 | 
			
		||||
#include "audio_dma.hpp"
 | 
			
		||||
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
void AudioInput::read_audio_buffer(buffer_s16_t& audio) {
 | 
			
		||||
	auto audio_buffer = audio::dma::rx_empty_buffer();
 | 
			
		||||
	
 | 
			
		||||
	for (size_t i=0; i<audio_buffer.count; i++)
 | 
			
		||||
		audio.p[i] = audio_buffer.p[i].right;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								Software/portapack-mayhem/firmware/baseband/audio_input.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								Software/portapack-mayhem/firmware/baseband/audio_input.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __AUDIO_INPUT_H__
 | 
			
		||||
#define __AUDIO_INPUT_H__
 | 
			
		||||
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_iir.hpp"
 | 
			
		||||
#include "dsp_squelch.hpp"
 | 
			
		||||
 | 
			
		||||
#include "stream_input.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
class AudioInput {
 | 
			
		||||
public:
 | 
			
		||||
	void read_audio_buffer(buffer_s16_t& audio);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	/*static constexpr float k = 32768.0f;
 | 
			
		||||
	static constexpr float ki = 1.0f / k;
 | 
			
		||||
 | 
			
		||||
	IIRBiquadFilter hpf { };*/
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__AUDIO_INPUT_H__*/
 | 
			
		||||
							
								
								
									
										128
									
								
								Software/portapack-mayhem/firmware/baseband/audio_output.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								Software/portapack-mayhem/firmware/baseband/audio_output.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "audio_output.hpp"
 | 
			
		||||
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
 | 
			
		||||
#include "audio_dma.hpp"
 | 
			
		||||
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
void AudioOutput::configure(
 | 
			
		||||
	const bool do_proc
 | 
			
		||||
) {
 | 
			
		||||
	do_processing = do_proc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioOutput::configure(
 | 
			
		||||
	const iir_biquad_config_t& hpf_config,
 | 
			
		||||
	const iir_biquad_config_t& deemph_config,
 | 
			
		||||
	const float squelch_threshold
 | 
			
		||||
) {
 | 
			
		||||
	hpf.configure(hpf_config);
 | 
			
		||||
	deemph.configure(deemph_config);
 | 
			
		||||
	squelch.set_threshold(squelch_threshold);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioOutput::write(
 | 
			
		||||
	const buffer_s16_t& audio
 | 
			
		||||
) {
 | 
			
		||||
	std::array<float, 32> audio_f;
 | 
			
		||||
	for(size_t i=0; i<audio.count; i++) {
 | 
			
		||||
		audio_f[i] = audio.p[i] * ki;
 | 
			
		||||
	}
 | 
			
		||||
	write(buffer_f32_t {
 | 
			
		||||
		audio_f.data(),
 | 
			
		||||
		audio.count,
 | 
			
		||||
		audio.sampling_rate
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioOutput::write(
 | 
			
		||||
	const buffer_f32_t& audio
 | 
			
		||||
) {
 | 
			
		||||
	block_buffer.feed(
 | 
			
		||||
		audio,
 | 
			
		||||
		[this](const buffer_f32_t& buffer) {
 | 
			
		||||
			this->on_block(buffer);
 | 
			
		||||
		}
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioOutput::on_block(
 | 
			
		||||
	const buffer_f32_t& audio
 | 
			
		||||
) {
 | 
			
		||||
	if (do_processing) {
 | 
			
		||||
		const auto audio_present_now = squelch.execute(audio);
 | 
			
		||||
 | 
			
		||||
		hpf.execute_in_place(audio);
 | 
			
		||||
		deemph.execute_in_place(audio);
 | 
			
		||||
 | 
			
		||||
		audio_present_history = (audio_present_history << 1) | (audio_present_now ? 1 : 0);
 | 
			
		||||
		audio_present = (audio_present_history != 0);
 | 
			
		||||
		
 | 
			
		||||
		if( !audio_present ) {
 | 
			
		||||
			for(size_t i=0; i<audio.count; i++) {
 | 
			
		||||
				audio.p[i] = 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else
 | 
			
		||||
		audio_present = true;
 | 
			
		||||
 | 
			
		||||
	fill_audio_buffer(audio, audio_present);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AudioOutput::is_squelched() {
 | 
			
		||||
	return !audio_present;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioOutput::fill_audio_buffer(const buffer_f32_t& audio, const bool send_to_fifo) {
 | 
			
		||||
	std::array<int16_t, 32> audio_int;
 | 
			
		||||
 | 
			
		||||
	auto audio_buffer = audio::dma::tx_empty_buffer();
 | 
			
		||||
	for(size_t i=0; i<audio_buffer.count; i++) {
 | 
			
		||||
		const int32_t sample_int = audio.p[i] * k;
 | 
			
		||||
		const int32_t sample_saturated = __SSAT(sample_int, 16);
 | 
			
		||||
		audio_buffer.p[i].left = audio_buffer.p[i].right = sample_saturated;
 | 
			
		||||
		audio_int[i] = sample_saturated;
 | 
			
		||||
	}
 | 
			
		||||
	if( stream && send_to_fifo ) {
 | 
			
		||||
		stream->write(audio_int.data(), audio_buffer.count * sizeof(audio_int[0]));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	feed_audio_stats(audio);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioOutput::feed_audio_stats(const buffer_f32_t& audio) {
 | 
			
		||||
	audio_stats.feed(
 | 
			
		||||
		audio,
 | 
			
		||||
		[](const AudioStatistics& statistics) {
 | 
			
		||||
			const AudioStatisticsMessage audio_stats_message { statistics };
 | 
			
		||||
			shared_memory.application_queue.push(audio_stats_message);
 | 
			
		||||
		}
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										81
									
								
								Software/portapack-mayhem/firmware/baseband/audio_output.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								Software/portapack-mayhem/firmware/baseband/audio_output.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __AUDIO_OUTPUT_H__
 | 
			
		||||
#define __AUDIO_OUTPUT_H__
 | 
			
		||||
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_iir.hpp"
 | 
			
		||||
#include "dsp_squelch.hpp"
 | 
			
		||||
 | 
			
		||||
#include "stream_input.hpp"
 | 
			
		||||
#include "block_decimator.hpp"
 | 
			
		||||
#include "audio_stats_collector.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
class AudioOutput {
 | 
			
		||||
public:
 | 
			
		||||
	void configure(const bool do_proc);
 | 
			
		||||
	
 | 
			
		||||
	void configure(
 | 
			
		||||
		const iir_biquad_config_t& hpf_config,
 | 
			
		||||
		const iir_biquad_config_t& deemph_config = iir_config_passthrough,
 | 
			
		||||
		const float squelch_threshold = 0.0f
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	void write(const buffer_s16_t& audio);
 | 
			
		||||
	void write(const buffer_f32_t& audio);
 | 
			
		||||
 | 
			
		||||
	void set_stream(std::unique_ptr<StreamInput> new_stream) {
 | 
			
		||||
		stream = std::move(new_stream);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	bool is_squelched();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr float k = 32768.0f;
 | 
			
		||||
	static constexpr float ki = 1.0f / k;
 | 
			
		||||
 | 
			
		||||
	BlockDecimator<float, 32> block_buffer { 1 };	
 | 
			
		||||
 | 
			
		||||
	IIRBiquadFilter hpf { };
 | 
			
		||||
	IIRBiquadFilter deemph { };
 | 
			
		||||
	FMSquelch squelch { };
 | 
			
		||||
 | 
			
		||||
	std::unique_ptr<StreamInput> stream { };
 | 
			
		||||
 | 
			
		||||
	AudioStatsCollector audio_stats { };
 | 
			
		||||
 | 
			
		||||
	uint64_t audio_present_history = 0;
 | 
			
		||||
	
 | 
			
		||||
	bool audio_present = false;
 | 
			
		||||
	bool do_processing = true;
 | 
			
		||||
 | 
			
		||||
	void on_block(const buffer_f32_t& audio);
 | 
			
		||||
	void fill_audio_buffer(const buffer_f32_t& audio, const bool send_to_fifo);
 | 
			
		||||
	void feed_audio_stats(const buffer_f32_t& audio);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__AUDIO_OUTPUT_H__*/
 | 
			
		||||
@@ -0,0 +1,67 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "audio_stats_collector.hpp"
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
void AudioStatsCollector::consume_audio_buffer(const buffer_f32_t& src) {
 | 
			
		||||
	auto src_p = src.p;
 | 
			
		||||
	const auto src_end = &src.p[src.count];
 | 
			
		||||
	while(src_p < src_end) {
 | 
			
		||||
		const auto sample = *(src_p++);
 | 
			
		||||
		const auto sample_squared = sample * sample;
 | 
			
		||||
		squared_sum += sample_squared;
 | 
			
		||||
		if( sample_squared > max_squared ) {
 | 
			
		||||
			max_squared = sample_squared;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AudioStatsCollector::update_stats(const size_t sample_count, const size_t sampling_rate) {
 | 
			
		||||
	count += sample_count;
 | 
			
		||||
 | 
			
		||||
	const size_t samples_per_update = sampling_rate * update_interval;
 | 
			
		||||
 | 
			
		||||
	if( count >= samples_per_update ) {
 | 
			
		||||
		statistics.rms_db = mag2_to_dbv_norm(squared_sum / count);
 | 
			
		||||
		statistics.max_db = mag2_to_dbv_norm(max_squared);
 | 
			
		||||
		statistics.count = count;
 | 
			
		||||
 | 
			
		||||
		squared_sum = 0;
 | 
			
		||||
		max_squared = 0;
 | 
			
		||||
		count = 0;
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	} else {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AudioStatsCollector::feed(const buffer_f32_t& src) {
 | 
			
		||||
	consume_audio_buffer(src);
 | 
			
		||||
 | 
			
		||||
	return update_stats(src.count, src.sampling_rate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AudioStatsCollector::mute(const size_t sample_count, const size_t sampling_rate) {
 | 
			
		||||
	return update_stats(sample_count, sampling_rate);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,63 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __AUDIO_STATS_COLLECTOR_H__
 | 
			
		||||
#define __AUDIO_STATS_COLLECTOR_H__
 | 
			
		||||
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
class AudioStatsCollector {
 | 
			
		||||
public:
 | 
			
		||||
	template<typename Callback>
 | 
			
		||||
	void feed(const buffer_f32_t& src, Callback callback) {
 | 
			
		||||
		if( feed(src) ) {
 | 
			
		||||
			callback(statistics);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<typename Callback>
 | 
			
		||||
	void mute(const size_t sample_count, const size_t sampling_rate, Callback callback) {
 | 
			
		||||
		if( mute(sample_count, sampling_rate) ) {
 | 
			
		||||
			callback(statistics);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr float update_interval { 0.1f };
 | 
			
		||||
	float squared_sum { 0 };
 | 
			
		||||
	float max_squared { 0 };
 | 
			
		||||
	size_t count { 0 };
 | 
			
		||||
 | 
			
		||||
	AudioStatistics statistics { };
 | 
			
		||||
 | 
			
		||||
	void consume_audio_buffer(const buffer_f32_t& src);
 | 
			
		||||
 | 
			
		||||
	bool update_stats(const size_t sample_count, const size_t sampling_rate);
 | 
			
		||||
 | 
			
		||||
	bool feed(const buffer_f32_t& src);
 | 
			
		||||
	bool mute(const size_t sample_count, const size_t sampling_rate);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__AUDIO_STATS_COLLECTOR_H__*/
 | 
			
		||||
							
								
								
									
										87
									
								
								Software/portapack-mayhem/firmware/baseband/baseband.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								Software/portapack-mayhem/firmware/baseband/baseband.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,87 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "ch.h"
 | 
			
		||||
 | 
			
		||||
#include "lpc43xx_cpp.hpp"
 | 
			
		||||
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
#include "portapack_dma.hpp"
 | 
			
		||||
 | 
			
		||||
#include "gpdma.hpp"
 | 
			
		||||
 | 
			
		||||
#include "audio_dma.hpp"
 | 
			
		||||
 | 
			
		||||
static void init() {
 | 
			
		||||
	audio::dma::init();
 | 
			
		||||
	audio::dma::configure();
 | 
			
		||||
	audio::dma::enable();
 | 
			
		||||
 | 
			
		||||
	nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC_DMA_IRQ_PRIORITY));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void halt() {
 | 
			
		||||
	port_disable();
 | 
			
		||||
	while(true) {
 | 
			
		||||
		port_wait_for_interrupt();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
 | 
			
		||||
void __late_init(void) {
 | 
			
		||||
	/*
 | 
			
		||||
	 * System initializations.
 | 
			
		||||
	 * - HAL initialization, this also initializes the configured device drivers
 | 
			
		||||
	 *   and performs the board-specific initializations.
 | 
			
		||||
	 * - Kernel initialization, the main() function becomes a thread and the
 | 
			
		||||
	 *   RTOS is active.
 | 
			
		||||
	 */
 | 
			
		||||
	halInit();
 | 
			
		||||
 | 
			
		||||
	/* After this call, scheduler, systick, heap, etc. are available. */
 | 
			
		||||
	/* By doing chSysInit() here, it runs before C++ constructors, which may
 | 
			
		||||
	 * require the heap.
 | 
			
		||||
	 */
 | 
			
		||||
	chSysInit();
 | 
			
		||||
 | 
			
		||||
	/* Baseband initialization */
 | 
			
		||||
	init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void _default_exit(void) {
 | 
			
		||||
	// TODO: Is this complete?
 | 
			
		||||
	
 | 
			
		||||
	nvicDisableVector(DMA_IRQn);
 | 
			
		||||
	
 | 
			
		||||
	chSysDisable();
 | 
			
		||||
 | 
			
		||||
	systick_stop();
 | 
			
		||||
 | 
			
		||||
	ShutdownMessage shutdown_message;
 | 
			
		||||
	shared_memory.application_queue.push(shutdown_message);
 | 
			
		||||
 | 
			
		||||
	shared_memory.baseband_message = nullptr;
 | 
			
		||||
 | 
			
		||||
	halt();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										174
									
								
								Software/portapack-mayhem/firmware/baseband/baseband_dma.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								Software/portapack-mayhem/firmware/baseband/baseband_dma.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,174 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "baseband_dma.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
#include "hal.h"
 | 
			
		||||
#include "gpdma.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace lpc43xx;
 | 
			
		||||
 | 
			
		||||
#include "portapack_dma.hpp"
 | 
			
		||||
 | 
			
		||||
#include "thread_wait.hpp"
 | 
			
		||||
 | 
			
		||||
namespace baseband {
 | 
			
		||||
namespace dma {
 | 
			
		||||
 | 
			
		||||
constexpr uint32_t gpdma_ahb_master_sgpio = 0;
 | 
			
		||||
constexpr uint32_t gpdma_ahb_master_memory = 1;
 | 
			
		||||
constexpr uint32_t gpdma_ahb_master_lli_fetch = 0;
 | 
			
		||||
 | 
			
		||||
constexpr uint32_t gpdma_src_peripheral = 0x0;
 | 
			
		||||
constexpr uint32_t gpdma_dest_peripheral = 0x0;
 | 
			
		||||
 | 
			
		||||
constexpr gpdma::channel::LLIPointer lli_pointer(const void* lli) {
 | 
			
		||||
	return {
 | 
			
		||||
		.lm = gpdma_ahb_master_lli_fetch,
 | 
			
		||||
		.r = 0,
 | 
			
		||||
		.lli = reinterpret_cast<uint32_t>(lli),
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr gpdma::channel::Control control(const baseband::Direction direction, const size_t buffer_words) {
 | 
			
		||||
	return {
 | 
			
		||||
		.transfersize = buffer_words,
 | 
			
		||||
		.sbsize = 0,  /* Burst size: 1 */
 | 
			
		||||
		.dbsize = 0,  /* Burst size: 1 */
 | 
			
		||||
		.swidth = 2,  /* Source transfer width: word (32 bits) */
 | 
			
		||||
		.dwidth = 2,  /* Destination transfer width: word (32 bits) */
 | 
			
		||||
		.s = (direction == baseband::Direction::Transmit) ? gpdma_ahb_master_memory : gpdma_ahb_master_sgpio,
 | 
			
		||||
		.d = (direction == baseband::Direction::Transmit) ? gpdma_ahb_master_sgpio : gpdma_ahb_master_memory,
 | 
			
		||||
		.si = (direction == baseband::Direction::Transmit) ? 1U : 0U,
 | 
			
		||||
		.di = (direction == baseband::Direction::Transmit) ? 0U : 1U,
 | 
			
		||||
		.prot1 = 0,
 | 
			
		||||
		.prot2 = 0,
 | 
			
		||||
		.prot3 = 0,
 | 
			
		||||
		.i = 1,
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr gpdma::channel::Config config(const baseband::Direction direction) {
 | 
			
		||||
	return {
 | 
			
		||||
		.e = 0,
 | 
			
		||||
		.srcperipheral = gpdma_src_peripheral,
 | 
			
		||||
		.destperipheral = gpdma_dest_peripheral,
 | 
			
		||||
		.flowcntrl = (direction == baseband::Direction::Transmit)
 | 
			
		||||
			? gpdma::FlowControl::MemoryToPeripheral_DMAControl
 | 
			
		||||
			: gpdma::FlowControl::PeripheralToMemory_DMAControl,
 | 
			
		||||
		.ie = 1,
 | 
			
		||||
		.itc = 1,
 | 
			
		||||
		.l = 0,
 | 
			
		||||
		.a = 0,
 | 
			
		||||
		.h = 0,
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr size_t buffer_samples_log2n = 13;
 | 
			
		||||
constexpr size_t buffer_samples = (1 << buffer_samples_log2n);
 | 
			
		||||
constexpr size_t transfers_per_buffer_log2n = 2;
 | 
			
		||||
constexpr size_t transfers_per_buffer = (1 << transfers_per_buffer_log2n);
 | 
			
		||||
constexpr size_t transfer_samples = buffer_samples / transfers_per_buffer;
 | 
			
		||||
constexpr size_t transfers_mask = transfers_per_buffer - 1;
 | 
			
		||||
 | 
			
		||||
constexpr size_t buffer_bytes = buffer_samples * sizeof(baseband::sample_t);
 | 
			
		||||
constexpr size_t transfer_bytes = transfer_samples * sizeof(baseband::sample_t);
 | 
			
		||||
 | 
			
		||||
constexpr size_t msg_count = transfers_per_buffer - 1;
 | 
			
		||||
 | 
			
		||||
static std::array<gpdma::channel::LLI, transfers_per_buffer> lli_loop;
 | 
			
		||||
static constexpr auto& gpdma_channel_sgpio = gpdma::channels[portapack::sgpio_gpdma_channel_number];
 | 
			
		||||
 | 
			
		||||
static ThreadWait thread_wait;
 | 
			
		||||
 | 
			
		||||
static void transfer_complete() {
 | 
			
		||||
	const auto next_lli_index = gpdma_channel_sgpio.next_lli() - &lli_loop[0];
 | 
			
		||||
	thread_wait.wake_from_interrupt(next_lli_index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dma_error() {
 | 
			
		||||
	thread_wait.wake_from_interrupt(-1);
 | 
			
		||||
	disable();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void init() {
 | 
			
		||||
	gpdma_channel_sgpio.set_handlers(transfer_complete, dma_error);
 | 
			
		||||
#if defined(PORTAPACK_BASEBAND_DMA_NO_SYNC)
 | 
			
		||||
	/* Disable synchronization logic to improve(?) DMA response time.
 | 
			
		||||
	 * SGPIO (peripheral) must be on same clock as GPDMA peripheral.
 | 
			
		||||
	 * SGPIO runs from BASE_PERIPH_CLK, which is set to PLL1 in normal
 | 
			
		||||
	 * operation, same as the M4 and M0 cores. Memory, of course, is
 | 
			
		||||
	 * running from the same clock as the cores.
 | 
			
		||||
	 */
 | 
			
		||||
	LPC_GPDMA->SYNC |= (1 << gpdma_src_peripheral);
 | 
			
		||||
	LPC_GPDMA->SYNC |= (1 << gpdma_dest_peripheral);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void configure(
 | 
			
		||||
	baseband::sample_t* const buffer_base,
 | 
			
		||||
	const baseband::Direction direction
 | 
			
		||||
) {
 | 
			
		||||
	const auto peripheral = reinterpret_cast<uint32_t>(&LPC_SGPIO->REG_SS[0]);
 | 
			
		||||
	const auto control_value = control(direction, gpdma::buffer_words(transfer_bytes, 4));
 | 
			
		||||
	for(size_t i=0; i<lli_loop.size(); i++) {
 | 
			
		||||
		const auto memory = reinterpret_cast<uint32_t>(&buffer_base[i * transfer_samples]);
 | 
			
		||||
		lli_loop[i].srcaddr = (direction == Direction::Transmit) ? memory : peripheral;
 | 
			
		||||
		lli_loop[i].destaddr = (direction == Direction::Transmit) ? peripheral : memory;
 | 
			
		||||
		lli_loop[i].lli = lli_pointer(&lli_loop[(i + 1) % lli_loop.size()]);
 | 
			
		||||
		lli_loop[i].control = control_value;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void enable(const baseband::Direction direction) {
 | 
			
		||||
	const auto gpdma_config = config(direction);
 | 
			
		||||
	gpdma_channel_sgpio.configure(lli_loop[0], gpdma_config);
 | 
			
		||||
	gpdma_channel_sgpio.enable();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool is_enabled() {
 | 
			
		||||
	return gpdma_channel_sgpio.is_enabled();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void disable() {
 | 
			
		||||
	gpdma_channel_sgpio.disable();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
baseband::buffer_t wait_for_buffer() {
 | 
			
		||||
	const auto next_index = thread_wait.sleep();
 | 
			
		||||
	
 | 
			
		||||
	if( next_index >= 0 ) {
 | 
			
		||||
		const size_t free_index = (next_index + transfers_per_buffer - 2) & transfers_mask;
 | 
			
		||||
		const auto src = lli_loop[free_index].srcaddr;
 | 
			
		||||
		const auto dst = lli_loop[free_index].destaddr;
 | 
			
		||||
		const auto p = (src == reinterpret_cast<uint32_t>(&LPC_SGPIO->REG_SS[0])) ? dst : src;
 | 
			
		||||
		return { reinterpret_cast<sample_t*>(p), transfer_samples };
 | 
			
		||||
	} else {
 | 
			
		||||
		return { };
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace dma */
 | 
			
		||||
} /* namespace baseband */
 | 
			
		||||
							
								
								
									
										50
									
								
								Software/portapack-mayhem/firmware/baseband/baseband_dma.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								Software/portapack-mayhem/firmware/baseband/baseband_dma.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __BASEBAND_DMA_H__
 | 
			
		||||
#define __BASEBAND_DMA_H__
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
#include "complex.hpp"
 | 
			
		||||
#include "baseband.hpp"
 | 
			
		||||
 | 
			
		||||
namespace baseband {
 | 
			
		||||
namespace dma {
 | 
			
		||||
 | 
			
		||||
void init();
 | 
			
		||||
void configure(
 | 
			
		||||
	baseband::sample_t* const buffer_base,
 | 
			
		||||
	const baseband::Direction direction
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
void enable(const baseband::Direction direction);
 | 
			
		||||
bool is_enabled();
 | 
			
		||||
 | 
			
		||||
void disable();
 | 
			
		||||
 | 
			
		||||
baseband::buffer_t wait_for_buffer();
 | 
			
		||||
 | 
			
		||||
} /* namespace dma */
 | 
			
		||||
} /* namespace baseband */
 | 
			
		||||
 | 
			
		||||
#endif/*__BASEBAND_DMA_H__*/
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
 | 
			
		||||
void BasebandProcessor::feed_channel_stats(const buffer_c16_t& channel) {
 | 
			
		||||
	channel_stats.feed(
 | 
			
		||||
		channel,
 | 
			
		||||
		[](const ChannelStatistics& statistics) {
 | 
			
		||||
			const ChannelStatisticsMessage channel_stats_message { statistics };
 | 
			
		||||
			shared_memory.application_queue.push(channel_stats_message);
 | 
			
		||||
		}
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,46 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __BASEBAND_PROCESSOR_H__
 | 
			
		||||
#define __BASEBAND_PROCESSOR_H__
 | 
			
		||||
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
 | 
			
		||||
#include "channel_stats_collector.hpp"
 | 
			
		||||
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
 | 
			
		||||
class BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	virtual ~BasebandProcessor() = default;
 | 
			
		||||
 | 
			
		||||
	virtual void execute(const buffer_c8_t& buffer) = 0;
 | 
			
		||||
 | 
			
		||||
	virtual void on_message(const Message* const) { };
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
	void feed_channel_stats(const buffer_c16_t& channel);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	ChannelStatsCollector channel_stats { };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__BASEBAND_PROCESSOR_H__*/
 | 
			
		||||
@@ -0,0 +1,59 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "baseband_stats_collector.hpp"
 | 
			
		||||
 | 
			
		||||
#include "lpc43xx_cpp.hpp"
 | 
			
		||||
 | 
			
		||||
bool BasebandStatsCollector::process(const buffer_c8_t& buffer) {
 | 
			
		||||
	samples += buffer.count;
 | 
			
		||||
 | 
			
		||||
	const size_t report_samples = buffer.sampling_rate * report_interval;
 | 
			
		||||
	const auto report_delta = samples - samples_last_report;
 | 
			
		||||
	return report_delta >= report_samples;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BasebandStatistics BasebandStatsCollector::capture_statistics() {
 | 
			
		||||
	BasebandStatistics statistics;
 | 
			
		||||
 | 
			
		||||
	const auto idle_ticks = thread_idle->total_ticks;
 | 
			
		||||
	statistics.idle_ticks = (idle_ticks - last_idle_ticks);
 | 
			
		||||
	last_idle_ticks = idle_ticks;
 | 
			
		||||
 | 
			
		||||
	const auto main_ticks = thread_main->total_ticks;
 | 
			
		||||
	statistics.main_ticks = (main_ticks - last_main_ticks);
 | 
			
		||||
	last_main_ticks = main_ticks;
 | 
			
		||||
 | 
			
		||||
	const auto rssi_ticks = thread_rssi->total_ticks;
 | 
			
		||||
	statistics.rssi_ticks = (rssi_ticks - last_rssi_ticks);
 | 
			
		||||
	last_rssi_ticks = rssi_ticks;
 | 
			
		||||
 | 
			
		||||
	const auto baseband_ticks = thread_baseband->total_ticks;
 | 
			
		||||
	statistics.baseband_ticks = (baseband_ticks - last_baseband_ticks);
 | 
			
		||||
	last_baseband_ticks = baseband_ticks;
 | 
			
		||||
 | 
			
		||||
	statistics.saturation = lpc43xx::m4::flag_saturation();
 | 
			
		||||
	lpc43xx::m4::clear_flag_saturation();
 | 
			
		||||
 | 
			
		||||
	samples_last_report = samples;
 | 
			
		||||
 | 
			
		||||
	return statistics;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,71 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __BASEBAND_STATS_COLLECTOR_H__
 | 
			
		||||
#define __BASEBAND_STATS_COLLECTOR_H__
 | 
			
		||||
 | 
			
		||||
#include "ch.h"
 | 
			
		||||
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
class BasebandStatsCollector {
 | 
			
		||||
public:
 | 
			
		||||
	BasebandStatsCollector(
 | 
			
		||||
		const Thread* const thread_idle,
 | 
			
		||||
		const Thread* const thread_main,
 | 
			
		||||
		const Thread* const thread_rssi,
 | 
			
		||||
		const Thread* const thread_baseband
 | 
			
		||||
	) : thread_idle { thread_idle },
 | 
			
		||||
		thread_main { thread_main },
 | 
			
		||||
		thread_rssi { thread_rssi },
 | 
			
		||||
		thread_baseband { thread_baseband }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<typename Callback>
 | 
			
		||||
	void process(const buffer_c8_t& buffer, Callback callback) {
 | 
			
		||||
		if( process(buffer) ) {
 | 
			
		||||
			callback(capture_statistics());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr float report_interval { 1.0f };
 | 
			
		||||
	size_t samples { 0 };
 | 
			
		||||
	size_t samples_last_report { 0 };
 | 
			
		||||
	const Thread* const thread_idle;
 | 
			
		||||
	uint32_t last_idle_ticks { 0 };
 | 
			
		||||
	const Thread* const thread_main;
 | 
			
		||||
	uint32_t last_main_ticks { 0 };
 | 
			
		||||
	const Thread* const thread_rssi;
 | 
			
		||||
	uint32_t last_rssi_ticks { 0 };
 | 
			
		||||
	const Thread* const thread_baseband;
 | 
			
		||||
	uint32_t last_baseband_ticks { 0 };
 | 
			
		||||
 | 
			
		||||
	bool process(const buffer_c8_t& buffer);
 | 
			
		||||
	BasebandStatistics capture_statistics();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__BASEBAND_STATS_COLLECTOR_H__*/
 | 
			
		||||
							
								
								
									
										103
									
								
								Software/portapack-mayhem/firmware/baseband/baseband_thread.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								Software/portapack-mayhem/firmware/baseband/baseband_thread.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
 | 
			
		||||
#include "baseband.hpp"
 | 
			
		||||
#include "baseband_sgpio.hpp"
 | 
			
		||||
#include "baseband_dma.hpp"
 | 
			
		||||
 | 
			
		||||
#include "rssi.hpp"
 | 
			
		||||
#include "i2s.hpp"
 | 
			
		||||
using namespace lpc43xx;
 | 
			
		||||
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
static baseband::SGPIO baseband_sgpio;
 | 
			
		||||
 | 
			
		||||
WORKING_AREA(baseband_thread_wa, 4096);
 | 
			
		||||
 | 
			
		||||
Thread* BasebandThread::thread = nullptr;
 | 
			
		||||
 | 
			
		||||
BasebandThread::BasebandThread(
 | 
			
		||||
	uint32_t sampling_rate,
 | 
			
		||||
	BasebandProcessor* const baseband_processor,
 | 
			
		||||
	const tprio_t priority,
 | 
			
		||||
	baseband::Direction direction
 | 
			
		||||
) : baseband_processor { baseband_processor },
 | 
			
		||||
	_direction { direction },
 | 
			
		||||
	sampling_rate { sampling_rate }
 | 
			
		||||
{
 | 
			
		||||
	thread = chThdCreateStatic(baseband_thread_wa, sizeof(baseband_thread_wa),
 | 
			
		||||
		priority, ThreadBase::fn,
 | 
			
		||||
		this
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BasebandThread::~BasebandThread() {
 | 
			
		||||
	chThdTerminate(thread);
 | 
			
		||||
	chThdWait(thread);
 | 
			
		||||
	thread = nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BasebandThread::set_sampling_rate(uint32_t new_sampling_rate) {
 | 
			
		||||
	sampling_rate = new_sampling_rate;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BasebandThread::run() {
 | 
			
		||||
	baseband_sgpio.init();
 | 
			
		||||
	baseband::dma::init();
 | 
			
		||||
 | 
			
		||||
	const auto baseband_buffer = std::make_unique<std::array<baseband::sample_t, 8192>>();
 | 
			
		||||
	baseband::dma::configure(
 | 
			
		||||
		baseband_buffer->data(),
 | 
			
		||||
		direction()
 | 
			
		||||
	);
 | 
			
		||||
	//baseband::dma::allocate(4, 2048);
 | 
			
		||||
 | 
			
		||||
	baseband_sgpio.configure(direction());
 | 
			
		||||
	baseband::dma::enable(direction());
 | 
			
		||||
	baseband_sgpio.streaming_enable();
 | 
			
		||||
 | 
			
		||||
	while( !chThdShouldTerminate() ) {
 | 
			
		||||
		// TODO: Place correct sampling rate into buffer returned here:
 | 
			
		||||
		const auto buffer_tmp = baseband::dma::wait_for_buffer();
 | 
			
		||||
		if( buffer_tmp ) {
 | 
			
		||||
			buffer_c8_t buffer {
 | 
			
		||||
				buffer_tmp.p, buffer_tmp.count, sampling_rate
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			if( baseband_processor ) {
 | 
			
		||||
				baseband_processor->execute(buffer);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	i2s::i2s0::tx_mute();
 | 
			
		||||
	baseband::dma::disable();
 | 
			
		||||
	baseband_sgpio.streaming_disable();
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,64 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __BASEBAND_THREAD_H__
 | 
			
		||||
#define __BASEBAND_THREAD_H__
 | 
			
		||||
 | 
			
		||||
#include "thread_base.hpp"
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
 | 
			
		||||
#include <ch.h>
 | 
			
		||||
 | 
			
		||||
class BasebandThread : public ThreadBase {
 | 
			
		||||
public:
 | 
			
		||||
	BasebandThread(
 | 
			
		||||
		uint32_t sampling_rate,
 | 
			
		||||
		BasebandProcessor* const baseband_processor,
 | 
			
		||||
		const tprio_t priority,
 | 
			
		||||
		const baseband::Direction direction = baseband::Direction::Receive
 | 
			
		||||
	);
 | 
			
		||||
	~BasebandThread();
 | 
			
		||||
 | 
			
		||||
	BasebandThread(const BasebandThread&) = delete;
 | 
			
		||||
	BasebandThread(BasebandThread&&) = delete;
 | 
			
		||||
	BasebandThread& operator=(const BasebandThread&) = delete;
 | 
			
		||||
	BasebandThread& operator=(BasebandThread&&) = delete;
 | 
			
		||||
	
 | 
			
		||||
	// This getter should die, it's just here to leak information to code that
 | 
			
		||||
	// isn't in the right place to begin with.
 | 
			
		||||
	baseband::Direction direction() const {
 | 
			
		||||
		return _direction;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	void set_sampling_rate(uint32_t new_sampling_rate);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static Thread* thread;
 | 
			
		||||
 | 
			
		||||
	BasebandProcessor* baseband_processor { nullptr };
 | 
			
		||||
	baseband::Direction _direction { baseband::Direction::Receive };
 | 
			
		||||
	uint32_t sampling_rate { 0 };
 | 
			
		||||
 | 
			
		||||
	void run() override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__BASEBAND_THREAD_H__*/
 | 
			
		||||
							
								
								
									
										100
									
								
								Software/portapack-mayhem/firmware/baseband/block_decimator.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								Software/portapack-mayhem/firmware/baseband/block_decimator.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __BLOCK_DECIMATOR_H__
 | 
			
		||||
#define __BLOCK_DECIMATOR_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
#include "complex.hpp"
 | 
			
		||||
 | 
			
		||||
template<typename T, size_t N>
 | 
			
		||||
class BlockDecimator {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr BlockDecimator(
 | 
			
		||||
		const size_t factor
 | 
			
		||||
	) : factor_ { factor }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set_input_sampling_rate(const uint32_t new_sampling_rate) {
 | 
			
		||||
		if( new_sampling_rate != input_sampling_rate() ) {
 | 
			
		||||
			input_sampling_rate_ = new_sampling_rate;
 | 
			
		||||
			reset_state();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t input_sampling_rate() const {
 | 
			
		||||
		return input_sampling_rate_;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set_factor(const size_t new_factor) {
 | 
			
		||||
		if( new_factor != factor() ) {
 | 
			
		||||
			factor_ = new_factor;
 | 
			
		||||
			reset_state();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t factor() const {
 | 
			
		||||
		return factor_;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t output_sampling_rate() const {
 | 
			
		||||
		return input_sampling_rate() / factor();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<typename BlockCallback>
 | 
			
		||||
	void feed(const buffer_t<T>& src, BlockCallback callback) {
 | 
			
		||||
		/* NOTE: Input block size must be >= factor */
 | 
			
		||||
 | 
			
		||||
		set_input_sampling_rate(src.sampling_rate);
 | 
			
		||||
 | 
			
		||||
		while( src_i < src.count ) {
 | 
			
		||||
			buffer[dst_i++] = src.p[src_i];
 | 
			
		||||
			if( dst_i == buffer.size() ) {
 | 
			
		||||
				callback({ buffer.data(), buffer.size(), output_sampling_rate() });
 | 
			
		||||
				reset_state();
 | 
			
		||||
				dst_i = 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			src_i += factor();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		src_i -= src.count;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	std::array<T, N> buffer { };
 | 
			
		||||
	uint32_t input_sampling_rate_ { 0 };
 | 
			
		||||
	size_t factor_ { 1 };
 | 
			
		||||
	size_t src_i { 0 };
 | 
			
		||||
	size_t dst_i { 0 };
 | 
			
		||||
 | 
			
		||||
	void reset_state() {
 | 
			
		||||
		src_i = 0;
 | 
			
		||||
		dst_i = 0;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__BLOCK_DECIMATOR_H__*/
 | 
			
		||||
@@ -0,0 +1,91 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "channel_decimator.hpp"
 | 
			
		||||
 | 
			
		||||
buffer_c16_t ChannelDecimator::execute_decimation(const buffer_c8_t& buffer) {
 | 
			
		||||
	const buffer_c16_t work_baseband_buffer {
 | 
			
		||||
		work_baseband.data(),
 | 
			
		||||
		work_baseband.size()
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	const buffer_s16_t work_audio_buffer {
 | 
			
		||||
		(int16_t*)work_baseband.data(),
 | 
			
		||||
		sizeof(work_baseband) / sizeof(int16_t)
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	/* 3.072MHz complex<int8_t>[2048], [-128, 127]
 | 
			
		||||
	 * -> Shift by -fs/4
 | 
			
		||||
	 * -> 3rd order CIC: -0.1dB @ 0.028fs, -1dB @ 0.088fs, -60dB @ 0.468fs
 | 
			
		||||
	 *                   -0.1dB @ 86kHz,   -1dB @ 270kHz,  -60dB @ 1.44MHz
 | 
			
		||||
	 * -> gain of 256
 | 
			
		||||
	 * -> decimation by 2
 | 
			
		||||
	 * -> 1.544MHz complex<int16_t>[1024], [-32768, 32512] */
 | 
			
		||||
	auto stage_0_out = execute_stage_0(buffer, work_baseband_buffer);
 | 
			
		||||
	if( decimation_factor == DecimationFactor::By2 ) {
 | 
			
		||||
		return stage_0_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* 1.536MHz complex<int16_t>[1024], [-32768, 32512]
 | 
			
		||||
	 * -> 3rd order CIC: -0.1dB @ 0.028fs, -1dB @ 0.088fs, -60dB @ 0.468fs
 | 
			
		||||
	 *                   -0.1dB @ 43kHz,   -1dB @ 136kHz,  -60dB @ 723kHz
 | 
			
		||||
	 * -> gain of 1
 | 
			
		||||
	 * -> decimation by 2
 | 
			
		||||
	 * -> 768kHz complex<int16_t>[512], [-8192, 8128] */
 | 
			
		||||
	auto cic_1_out = cic_1.execute(stage_0_out, work_baseband_buffer);
 | 
			
		||||
	if( decimation_factor == DecimationFactor::By4 ) {
 | 
			
		||||
		return cic_1_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* 768kHz complex<int16_t>[512], [-32768, 32512]
 | 
			
		||||
	 * -> 3rd order CIC decimation by 2, gain of 1
 | 
			
		||||
	 * -> 384kHz complex<int16_t>[256], [-32768, 32512] */
 | 
			
		||||
	auto cic_2_out = cic_2.execute(cic_1_out, work_baseband_buffer);
 | 
			
		||||
	if( decimation_factor == DecimationFactor::By8 ) {
 | 
			
		||||
		return cic_2_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* 384kHz complex<int16_t>[256], [-32768, 32512]
 | 
			
		||||
	 * -> 3rd order CIC decimation by 2, gain of 1
 | 
			
		||||
	 * -> 192kHz complex<int16_t>[128], [-32768, 32512] */
 | 
			
		||||
	auto cic_3_out = cic_3.execute(cic_2_out, work_baseband_buffer);
 | 
			
		||||
	if( decimation_factor == DecimationFactor::By16 ) {
 | 
			
		||||
		return cic_3_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* 192kHz complex<int16_t>[128], [-32768, 32512]
 | 
			
		||||
	 * -> 3rd order CIC decimation by 2, gain of 1
 | 
			
		||||
	 * -> 96kHz complex<int16_t>[64], [-32768, 32512] */
 | 
			
		||||
	auto cic_4_out = cic_4.execute(cic_3_out, work_baseband_buffer);
 | 
			
		||||
 | 
			
		||||
	return cic_4_out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_c16_t ChannelDecimator::execute_stage_0(
 | 
			
		||||
	const buffer_c8_t& buffer,
 | 
			
		||||
	const buffer_c16_t& work_baseband_buffer
 | 
			
		||||
) {
 | 
			
		||||
	if( fs_over_4_downconvert ) {
 | 
			
		||||
		return translate.execute(buffer, work_baseband_buffer);
 | 
			
		||||
	} else {
 | 
			
		||||
		return cic_0.execute(buffer, work_baseband_buffer);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,81 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __CHANNEL_DECIMATOR_H__
 | 
			
		||||
#define __CHANNEL_DECIMATOR_H__
 | 
			
		||||
 | 
			
		||||
#include "buffer.hpp"
 | 
			
		||||
#include "complex.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_decimate.hpp"
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
class ChannelDecimator {
 | 
			
		||||
public:
 | 
			
		||||
	enum class DecimationFactor {
 | 
			
		||||
		By2,
 | 
			
		||||
		By4,
 | 
			
		||||
		By8,
 | 
			
		||||
		By16,
 | 
			
		||||
		By32,
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	constexpr ChannelDecimator(
 | 
			
		||||
		const DecimationFactor decimation_factor,
 | 
			
		||||
		const bool fs_over_4_downconvert = true
 | 
			
		||||
	) : decimation_factor { decimation_factor },
 | 
			
		||||
		fs_over_4_downconvert { fs_over_4_downconvert }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set_decimation_factor(const DecimationFactor f) {
 | 
			
		||||
		decimation_factor = f;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	buffer_c16_t execute(const buffer_c8_t& buffer) {
 | 
			
		||||
		auto decimated = execute_decimation(buffer);
 | 
			
		||||
 | 
			
		||||
		return decimated;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	std::array<complex16_t, 1024> work_baseband { };
 | 
			
		||||
 | 
			
		||||
	dsp::decimate::TranslateByFSOver4AndDecimateBy2CIC3 translate { };
 | 
			
		||||
	dsp::decimate::Complex8DecimateBy2CIC3 cic_0 { };
 | 
			
		||||
	dsp::decimate::DecimateBy2CIC3 cic_1 { };
 | 
			
		||||
	dsp::decimate::DecimateBy2CIC3 cic_2 { };
 | 
			
		||||
	dsp::decimate::DecimateBy2CIC3 cic_3 { };
 | 
			
		||||
	dsp::decimate::DecimateBy2CIC3 cic_4 { };
 | 
			
		||||
 | 
			
		||||
	DecimationFactor decimation_factor { DecimationFactor::By32 };
 | 
			
		||||
	const bool fs_over_4_downconvert { true };
 | 
			
		||||
 | 
			
		||||
	buffer_c16_t execute_decimation(const buffer_c8_t& buffer);
 | 
			
		||||
 | 
			
		||||
	buffer_c16_t execute_stage_0(
 | 
			
		||||
		const buffer_c8_t& buffer,
 | 
			
		||||
		const buffer_c16_t& work_baseband_buffer
 | 
			
		||||
	);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__CHANNEL_DECIMATOR_H__*/
 | 
			
		||||
@@ -0,0 +1,66 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __CHANNEL_STATS_COLLECTOR_H__
 | 
			
		||||
#define __CHANNEL_STATS_COLLECTOR_H__
 | 
			
		||||
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
#include <hal.h>
 | 
			
		||||
 | 
			
		||||
class ChannelStatsCollector {
 | 
			
		||||
public:
 | 
			
		||||
	template<typename Callback>
 | 
			
		||||
	void feed(const buffer_c16_t& src, Callback callback) {
 | 
			
		||||
		void *src_p = src.p;
 | 
			
		||||
		while(src_p < &src.p[src.count]) {
 | 
			
		||||
			const uint32_t sample = *__SIMD32(src_p)++;
 | 
			
		||||
			const uint32_t mag_sq = __SMUAD(sample, sample);
 | 
			
		||||
			if( mag_sq > max_squared ) {
 | 
			
		||||
				max_squared = mag_sq;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		count += src.count;
 | 
			
		||||
 | 
			
		||||
		const size_t samples_per_update = src.sampling_rate * update_interval;
 | 
			
		||||
 | 
			
		||||
		if( count >= samples_per_update ) {
 | 
			
		||||
			const float max_squared_f = max_squared;
 | 
			
		||||
			const int32_t max_db = mag2_to_dbv_norm(max_squared_f * (1.0f / (32768.0f * 32768.0f)));
 | 
			
		||||
			callback({ max_db, count });
 | 
			
		||||
 | 
			
		||||
			max_squared = 0;
 | 
			
		||||
			count = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr float update_interval { 0.1f };
 | 
			
		||||
	uint32_t max_squared { 0 };
 | 
			
		||||
	size_t count { 0 };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__CHANNEL_STATS_COLLECTOR_H__*/
 | 
			
		||||
							
								
								
									
										546
									
								
								Software/portapack-mayhem/firmware/baseband/chconf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										546
									
								
								Software/portapack-mayhem/firmware/baseband/chconf.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,546 @@
 | 
			
		||||
/*
 | 
			
		||||
    ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
 | 
			
		||||
                 Copyright (C) 2014 Jared Boone, ShareBrained Technology
 | 
			
		||||
 | 
			
		||||
    Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
    you may not use this file except in compliance with the License.
 | 
			
		||||
    You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
        http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
    Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
    distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
    See the License for the specific language governing permissions and
 | 
			
		||||
    limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file    templates/chconf.h
 | 
			
		||||
 * @brief   Configuration file template.
 | 
			
		||||
 * @details A copy of this file must be placed in each project directory, it
 | 
			
		||||
 *          contains the application specific kernel settings.
 | 
			
		||||
 *
 | 
			
		||||
 * @addtogroup config
 | 
			
		||||
 * @details Kernel related settings and hooks.
 | 
			
		||||
 * @{
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _CHCONF_H_
 | 
			
		||||
#define _CHCONF_H_
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
/**
 | 
			
		||||
 * @name Kernel parameters and options
 | 
			
		||||
 * @{
 | 
			
		||||
 */
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   System tick frequency.
 | 
			
		||||
 * @details Frequency of the system timer that drives the system ticks. This
 | 
			
		||||
 *          setting also defines the system tick time unit.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_FREQUENCY) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_FREQUENCY                    1000
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Round robin interval.
 | 
			
		||||
 * @details This constant is the number of system ticks allowed for the
 | 
			
		||||
 *          threads before preemption occurs. Setting this value to zero
 | 
			
		||||
 *          disables the preemption for threads with equal priority and the
 | 
			
		||||
 *          round robin becomes cooperative. Note that higher priority
 | 
			
		||||
 *          threads can still preempt, the kernel is always preemptive.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    Disabling the round robin preemption makes the kernel more compact
 | 
			
		||||
 *          and generally faster.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_TIME_QUANTUM) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_TIME_QUANTUM                 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Managed RAM size.
 | 
			
		||||
 * @details Size of the RAM area to be managed by the OS. If set to zero
 | 
			
		||||
 *          then the whole available RAM is used. The core memory is made
 | 
			
		||||
 *          available to the heap allocator and/or can be used directly through
 | 
			
		||||
 *          the simplified core memory allocator.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    In order to let the OS manage the whole RAM the linker script must
 | 
			
		||||
 *          provide the @p __heap_base__ and @p __heap_end__ symbols.
 | 
			
		||||
 * @note    Requires @p CH_USE_MEMCORE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_MEMCORE_SIZE) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_MEMCORE_SIZE                 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Idle thread automatic spawn suppression.
 | 
			
		||||
 * @details When this option is activated the function @p chSysInit()
 | 
			
		||||
 *          does not spawn the idle thread automatically. The application has
 | 
			
		||||
 *          then the responsibility to do one of the following:
 | 
			
		||||
 *          - Spawn a custom idle thread at priority @p IDLEPRIO.
 | 
			
		||||
 *          - Change the main() thread priority to @p IDLEPRIO then enter
 | 
			
		||||
 *            an endless loop. In this scenario the @p main() thread acts as
 | 
			
		||||
 *            the idle thread.
 | 
			
		||||
 *          .
 | 
			
		||||
 * @note    Unless an idle thread is spawned the @p main() thread must not
 | 
			
		||||
 *          enter a sleep state.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_NO_IDLE_THREAD) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_NO_IDLE_THREAD               FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
/**
 | 
			
		||||
 * @name Performance options
 | 
			
		||||
 * @{
 | 
			
		||||
 */
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   OS optimization.
 | 
			
		||||
 * @details If enabled then time efficient rather than space efficient code
 | 
			
		||||
 *          is used when two possible implementations exist.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    This is not related to the compiler optimization options.
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_OPTIMIZE_SPEED) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_OPTIMIZE_SPEED               TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
/**
 | 
			
		||||
 * @name Subsystem options
 | 
			
		||||
 * @{
 | 
			
		||||
 */
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Threads registry APIs.
 | 
			
		||||
 * @details If enabled then the registry APIs are included in the kernel.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_REGISTRY) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_REGISTRY                 FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Threads synchronization APIs.
 | 
			
		||||
 * @details If enabled then the @p chThdWait() function is included in
 | 
			
		||||
 *          the kernel.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_WAITEXIT) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_WAITEXIT                 TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Semaphores APIs.
 | 
			
		||||
 * @details If enabled then the Semaphores APIs are included in the kernel.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_SEMAPHORES) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_SEMAPHORES               TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Semaphores queuing mode.
 | 
			
		||||
 * @details If enabled then the threads are enqueued on semaphores by
 | 
			
		||||
 *          priority rather than in FIFO order.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p FALSE. Enable this if you have special requirements.
 | 
			
		||||
 * @note    Requires @p CH_USE_SEMAPHORES.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_SEMAPHORES_PRIORITY) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_SEMAPHORES_PRIORITY      FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Atomic semaphore API.
 | 
			
		||||
 * @details If enabled then the semaphores the @p chSemSignalWait() API
 | 
			
		||||
 *          is included in the kernel.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 * @note    Requires @p CH_USE_SEMAPHORES.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_SEMSW) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_SEMSW                    TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Mutexes APIs.
 | 
			
		||||
 * @details If enabled then the mutexes APIs are included in the kernel.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_MUTEXES) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_MUTEXES                  TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Conditional Variables APIs.
 | 
			
		||||
 * @details If enabled then the conditional variables APIs are included
 | 
			
		||||
 *          in the kernel.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 * @note    Requires @p CH_USE_MUTEXES.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_CONDVARS) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_CONDVARS                 TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Conditional Variables APIs with timeout.
 | 
			
		||||
 * @details If enabled then the conditional variables APIs with timeout
 | 
			
		||||
 *          specification are included in the kernel.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 * @note    Requires @p CH_USE_CONDVARS.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_CONDVARS_TIMEOUT) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_CONDVARS_TIMEOUT         TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Events Flags APIs.
 | 
			
		||||
 * @details If enabled then the event flags APIs are included in the kernel.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_EVENTS) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_EVENTS                   TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Events Flags APIs with timeout.
 | 
			
		||||
 * @details If enabled then the events APIs with timeout specification
 | 
			
		||||
 *          are included in the kernel.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 * @note    Requires @p CH_USE_EVENTS.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_EVENTS_TIMEOUT           TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Synchronous Messages APIs.
 | 
			
		||||
 * @details If enabled then the synchronous messages APIs are included
 | 
			
		||||
 *          in the kernel.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_MESSAGES) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_MESSAGES                 TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Synchronous Messages queuing mode.
 | 
			
		||||
 * @details If enabled then messages are served by priority rather than in
 | 
			
		||||
 *          FIFO order.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p FALSE. Enable this if you have special requirements.
 | 
			
		||||
 * @note    Requires @p CH_USE_MESSAGES.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_MESSAGES_PRIORITY) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_MESSAGES_PRIORITY        FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Mailboxes APIs.
 | 
			
		||||
 * @details If enabled then the asynchronous messages (mailboxes) APIs are
 | 
			
		||||
 *          included in the kernel.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 * @note    Requires @p CH_USE_SEMAPHORES.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_MAILBOXES) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_MAILBOXES                TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   I/O Queues APIs.
 | 
			
		||||
 * @details If enabled then the I/O queues APIs are included in the kernel.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_QUEUES) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_QUEUES                   TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Core Memory Manager APIs.
 | 
			
		||||
 * @details If enabled then the core memory manager APIs are included
 | 
			
		||||
 *          in the kernel.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_MEMCORE) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_MEMCORE                  TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Heap Allocator APIs.
 | 
			
		||||
 * @details If enabled then the memory heap allocator APIs are included
 | 
			
		||||
 *          in the kernel.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 * @note    Requires @p CH_USE_MEMCORE and either @p CH_USE_MUTEXES or
 | 
			
		||||
 *          @p CH_USE_SEMAPHORES.
 | 
			
		||||
 * @note    Mutexes are recommended.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_HEAP) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_HEAP                     TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   C-runtime allocator.
 | 
			
		||||
 * @details If enabled the the heap allocator APIs just wrap the C-runtime
 | 
			
		||||
 *          @p malloc() and @p free() functions.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p FALSE.
 | 
			
		||||
 * @note    Requires @p CH_USE_HEAP.
 | 
			
		||||
 * @note    The C-runtime may or may not require @p CH_USE_MEMCORE, see the
 | 
			
		||||
 *          appropriate documentation.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_MALLOC_HEAP) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_MALLOC_HEAP              FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Memory Pools Allocator APIs.
 | 
			
		||||
 * @details If enabled then the memory pools allocator APIs are included
 | 
			
		||||
 *          in the kernel.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_MEMPOOLS) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_MEMPOOLS                 TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Dynamic Threads APIs.
 | 
			
		||||
 * @details If enabled then the dynamic threads creation APIs are included
 | 
			
		||||
 *          in the kernel.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 * @note    Requires @p CH_USE_WAITEXIT.
 | 
			
		||||
 * @note    Requires @p CH_USE_HEAP and/or @p CH_USE_MEMPOOLS.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_USE_DYNAMIC) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_USE_DYNAMIC                  TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
/**
 | 
			
		||||
 * @name Debug options
 | 
			
		||||
 * @{
 | 
			
		||||
 */
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Debug option, system state check.
 | 
			
		||||
 * @details If enabled the correct call protocol for system APIs is checked
 | 
			
		||||
 *          at runtime.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p FALSE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_DBG_SYSTEM_STATE_CHECK) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_DBG_SYSTEM_STATE_CHECK       TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Debug option, parameters checks.
 | 
			
		||||
 * @details If enabled then the checks on the API functions input
 | 
			
		||||
 *          parameters are activated.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p FALSE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_DBG_ENABLE_CHECKS            TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Debug option, consistency checks.
 | 
			
		||||
 * @details If enabled then all the assertions in the kernel code are
 | 
			
		||||
 *          activated. This includes consistency checks inside the kernel,
 | 
			
		||||
 *          runtime anomalies and port-defined checks.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p FALSE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_DBG_ENABLE_ASSERTS           TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Debug option, trace buffer.
 | 
			
		||||
 * @details If enabled then the context switch circular trace buffer is
 | 
			
		||||
 *          activated.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p FALSE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_DBG_ENABLE_TRACE) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_DBG_ENABLE_TRACE             FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Debug option, stack checks.
 | 
			
		||||
 * @details If enabled then a runtime stack check is performed.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p FALSE.
 | 
			
		||||
 * @note    The stack check is performed in a architecture/port dependent way.
 | 
			
		||||
 *          It may not be implemented or some ports.
 | 
			
		||||
 * @note    The default failure mode is to halt the system with the global
 | 
			
		||||
 *          @p panic_msg variable set to @p NULL.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_DBG_ENABLE_STACK_CHECK       TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Debug option, stacks initialization.
 | 
			
		||||
 * @details If enabled then the threads working area is filled with a byte
 | 
			
		||||
 *          value when a thread is created. This can be useful for the
 | 
			
		||||
 *          runtime measurement of the used stack.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p FALSE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_DBG_FILL_THREADS) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_DBG_FILL_THREADS             TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Debug option, threads profiling.
 | 
			
		||||
 * @details If enabled then a field is added to the @p Thread structure that
 | 
			
		||||
 *          counts the system ticks occurred while executing the thread.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    The default is @p TRUE.
 | 
			
		||||
 * @note    This debug option is defaulted to TRUE because it is required by
 | 
			
		||||
 *          some test cases into the test suite.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__)
 | 
			
		||||
#define CH_DBG_THREADS_PROFILING        TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
/**
 | 
			
		||||
 * @name Kernel hooks
 | 
			
		||||
 * @{
 | 
			
		||||
 */
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Threads descriptor structure extension.
 | 
			
		||||
 * @details User fields added to the end of the @p Thread structure.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(THREAD_EXT_FIELDS) || defined(__DOXYGEN__)
 | 
			
		||||
#define THREAD_EXT_FIELDS                                                   \
 | 
			
		||||
  /* Add threads custom fields here.*/                                      \
 | 
			
		||||
  uint32_t switches;                                                        \
 | 
			
		||||
  uint32_t start_ticks;                                                     \
 | 
			
		||||
  uint32_t total_ticks;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Threads initialization hook.
 | 
			
		||||
 * @details User initialization code added to the @p chThdInit() API.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    It is invoked from within @p chThdInit() and implicitly from all
 | 
			
		||||
 *          the threads creation APIs.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__)
 | 
			
		||||
#define THREAD_EXT_INIT_HOOK(tp) {                                          \
 | 
			
		||||
  /* Add threads initialization code here.*/                                \
 | 
			
		||||
  tp->switches = 0;                                                         \
 | 
			
		||||
  tp->start_ticks = 0;                                                      \
 | 
			
		||||
  tp->total_ticks = 0;                                                      \
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Threads finalization hook.
 | 
			
		||||
 * @details User finalization code added to the @p chThdExit() API.
 | 
			
		||||
 *
 | 
			
		||||
 * @note    It is inserted into lock zone.
 | 
			
		||||
 * @note    It is also invoked when the threads simply return in order to
 | 
			
		||||
 *          terminate.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(THREAD_EXT_EXIT_HOOK) || defined(__DOXYGEN__)
 | 
			
		||||
#define THREAD_EXT_EXIT_HOOK(tp) {                                          \
 | 
			
		||||
  /* Add threads finalization code here.*/                                  \
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Context switch hook.
 | 
			
		||||
 * @details This hook is invoked just before switching between threads.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(THREAD_CONTEXT_SWITCH_HOOK) || defined(__DOXYGEN__)
 | 
			
		||||
#define THREAD_CONTEXT_SWITCH_HOOK(ntp, otp) {                              \
 | 
			
		||||
  /* System halt code here.*/                                               \
 | 
			
		||||
  otp->switches++;                                                          \
 | 
			
		||||
  ntp->start_ticks = *((volatile uint32_t*)0x400C4008);                     \
 | 
			
		||||
  otp->total_ticks += (ntp->start_ticks - otp->start_ticks);                \
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Idle Loop hook.
 | 
			
		||||
 * @details This hook is continuously invoked by the idle thread loop.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(IDLE_LOOP_HOOK) || defined(__DOXYGEN__)
 | 
			
		||||
#define IDLE_LOOP_HOOK() {                                                  \
 | 
			
		||||
  /* Idle loop code here.*/                                                 \
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   System tick event hook.
 | 
			
		||||
 * @details This hook is invoked in the system tick handler immediately
 | 
			
		||||
 *          after processing the virtual timers queue.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(SYSTEM_TICK_EVENT_HOOK) || defined(__DOXYGEN__)
 | 
			
		||||
#define SYSTEM_TICK_EVENT_HOOK() {                                          \
 | 
			
		||||
  /* System tick event code here.*/                                         \
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   System halt hook.
 | 
			
		||||
 * @details This hook is invoked in case to a system halting error before
 | 
			
		||||
 *          the system is halted.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(SYSTEM_HALT_HOOK) || defined(__DOXYGEN__)
 | 
			
		||||
#define SYSTEM_HALT_HOOK() {                                                \
 | 
			
		||||
  /* System halt code here.*/                                               \
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
/* Port-specific settings (override port settings defaulted in chcore.h).    */
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
 | 
			
		||||
/* NOTE: When changing this option you also have to enable or disable the FPU
 | 
			
		||||
   in the project options.*/
 | 
			
		||||
#define CORTEX_USE_FPU                  TRUE
 | 
			
		||||
#define CORTEX_ENABLE_WFI_IDLE          TRUE
 | 
			
		||||
 | 
			
		||||
#endif  /* _CHCONF_H_ */
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
@@ -0,0 +1,22 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "clock_recovery.hpp"
 | 
			
		||||
							
								
								
									
										185
									
								
								Software/portapack-mayhem/firmware/baseband/clock_recovery.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								Software/portapack-mayhem/firmware/baseband/clock_recovery.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,185 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __CLOCK_RECOVERY_H__
 | 
			
		||||
#define __CLOCK_RECOVERY_H__
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
#include "linear_resampler.hpp"
 | 
			
		||||
 | 
			
		||||
namespace clock_recovery {
 | 
			
		||||
 | 
			
		||||
class GardnerTimingErrorDetector {
 | 
			
		||||
public:
 | 
			
		||||
	static constexpr size_t samples_per_symbol { 2 };
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	Expects retimed samples at a rate of twice the expected symbol rate.
 | 
			
		||||
	Calculates timing error, sends symbol and error to handler.
 | 
			
		||||
	*/
 | 
			
		||||
	template<typename SymbolHandler>
 | 
			
		||||
	void operator()(
 | 
			
		||||
		const float in,
 | 
			
		||||
		SymbolHandler symbol_handler
 | 
			
		||||
	) {
 | 
			
		||||
		/* NOTE: Algorithm is sensitive to input magnitude. Timing error value
 | 
			
		||||
		 * will scale proportionally. Best practice is to use error sign only.
 | 
			
		||||
		 */
 | 
			
		||||
		t[2] = t[1];
 | 
			
		||||
		t[1] = t[0];
 | 
			
		||||
		t[0] = in;
 | 
			
		||||
 | 
			
		||||
		if( symbol_phase == 0 ) {
 | 
			
		||||
			const auto symbol = t[0];
 | 
			
		||||
			const float lateness = (t[0] - t[2]) * t[1];
 | 
			
		||||
			symbol_handler(symbol, lateness);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		symbol_phase = (symbol_phase + 1) % samples_per_symbol;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	std::array<float, 3> t { };
 | 
			
		||||
	size_t symbol_phase { 0 };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class LinearErrorFilter {
 | 
			
		||||
public:
 | 
			
		||||
	LinearErrorFilter(
 | 
			
		||||
		const float filter_alpha = 0.95f,
 | 
			
		||||
		const float error_weight = -1.0f
 | 
			
		||||
	) : filter_alpha { filter_alpha },
 | 
			
		||||
		error_weight { error_weight }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	float operator()(
 | 
			
		||||
		const float error
 | 
			
		||||
	) {
 | 
			
		||||
		error_filtered = filter_alpha * error_filtered + (1.0f - filter_alpha) * error;
 | 
			
		||||
		return error_filtered * error_weight;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	const float filter_alpha;
 | 
			
		||||
	const float error_weight;
 | 
			
		||||
	float error_filtered { 0.0f };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class FixedErrorFilter {
 | 
			
		||||
public:
 | 
			
		||||
	FixedErrorFilter(
 | 
			
		||||
	) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FixedErrorFilter(
 | 
			
		||||
		const float weight
 | 
			
		||||
	) : weight_ { weight }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	float operator()(
 | 
			
		||||
		const float lateness
 | 
			
		||||
	) const {
 | 
			
		||||
		return (lateness < 0.0f) ? weight() : -weight();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	float weight() const {
 | 
			
		||||
		return weight_;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	float weight_ { 1.0f / 16.0f };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename ErrorFilter>
 | 
			
		||||
class ClockRecovery {
 | 
			
		||||
public:
 | 
			
		||||
	using SymbolHandler = std::function<void(const float)>;
 | 
			
		||||
 | 
			
		||||
	ClockRecovery(
 | 
			
		||||
		const float sampling_rate,
 | 
			
		||||
		const float symbol_rate,
 | 
			
		||||
		ErrorFilter error_filter,
 | 
			
		||||
		SymbolHandler symbol_handler
 | 
			
		||||
	) : symbol_handler { std::move(symbol_handler) }
 | 
			
		||||
	{
 | 
			
		||||
		configure(sampling_rate, symbol_rate, error_filter);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ClockRecovery(
 | 
			
		||||
		SymbolHandler symbol_handler
 | 
			
		||||
	) : symbol_handler { std::move(symbol_handler) }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void configure(
 | 
			
		||||
		const float sampling_rate,
 | 
			
		||||
		const float symbol_rate,
 | 
			
		||||
		ErrorFilter error_filter
 | 
			
		||||
	) {
 | 
			
		||||
		resampler.configure(sampling_rate, symbol_rate * timing_error_detector.samples_per_symbol);
 | 
			
		||||
		error_filter = error_filter;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void operator()(
 | 
			
		||||
		const float baseband_sample
 | 
			
		||||
	) {
 | 
			
		||||
		resampler(baseband_sample,
 | 
			
		||||
			[this](const float interpolated_sample) {
 | 
			
		||||
				this->resampler_callback(interpolated_sample);
 | 
			
		||||
			}
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	dsp::interpolation::LinearResampler resampler { };
 | 
			
		||||
	GardnerTimingErrorDetector timing_error_detector { };
 | 
			
		||||
	ErrorFilter error_filter { };
 | 
			
		||||
	const SymbolHandler symbol_handler;
 | 
			
		||||
 | 
			
		||||
	void resampler_callback(const float interpolated_sample) {
 | 
			
		||||
		timing_error_detector(interpolated_sample,
 | 
			
		||||
			[this](const float symbol, const float lateness) {
 | 
			
		||||
				this->symbol_callback(symbol, lateness);
 | 
			
		||||
			}
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void symbol_callback(const float symbol, const float lateness) {
 | 
			
		||||
		// NOTE: This check is to avoid std::function nullptr check, which
 | 
			
		||||
		// brings in "_ZSt25__throw_bad_function_callv" and a lot of extra code.
 | 
			
		||||
		// TODO: Make symbol_handler known at compile time.
 | 
			
		||||
		if( symbol_handler) {
 | 
			
		||||
			symbol_handler(symbol);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const float adjustment = error_filter(lateness);
 | 
			
		||||
		resampler.advance(adjustment);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace clock_recovery */
 | 
			
		||||
 | 
			
		||||
#endif/*__CLOCK_RECOVERY_H__*/
 | 
			
		||||
							
								
								
									
										1
									
								
								Software/portapack-mayhem/firmware/baseband/description
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Software/portapack-mayhem/firmware/baseband/description
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
Original firmware's functionalities: Receiver.
 | 
			
		||||
							
								
								
									
										790
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_decimate.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										790
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_decimate.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,790 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dsp_decimate.hpp"
 | 
			
		||||
 | 
			
		||||
#include <hal.h>
 | 
			
		||||
 | 
			
		||||
namespace dsp {
 | 
			
		||||
namespace decimate {
 | 
			
		||||
 | 
			
		||||
static inline complex32_t mac_fs4_shift(
 | 
			
		||||
	const vec2_s16* const z,
 | 
			
		||||
	const vec2_s16* const t,
 | 
			
		||||
	const size_t index,
 | 
			
		||||
	const complex32_t accum
 | 
			
		||||
) {
 | 
			
		||||
	/* Accumulate sample * tap results for samples already in z buffer.
 | 
			
		||||
	 * Multiply using swap/negation to achieve Fs/4 shift.
 | 
			
		||||
	 * For iterations where samples are shifting out of z buffer (being discarded).
 | 
			
		||||
	 * Expect negated tap t[2] to accomodate instruction set limitations.
 | 
			
		||||
	 */
 | 
			
		||||
	const bool negated_t2 = index & 1;
 | 
			
		||||
	const auto q1_i0 = z[index*2 + 0];
 | 
			
		||||
	const auto i1_q0 = z[index*2 + 1];
 | 
			
		||||
	const auto t1_t0 = t[index];
 | 
			
		||||
	const auto real = negated_t2 ? smlsd(q1_i0, t1_t0, accum.real()) : smlad(q1_i0, t1_t0, accum.real());
 | 
			
		||||
	const auto imag = negated_t2 ? smlad(i1_q0, t1_t0, accum.imag()) : smlsd(i1_q0, t1_t0, accum.imag());
 | 
			
		||||
	return { real, imag };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline complex32_t mac_shift(
 | 
			
		||||
	const vec2_s16* const z,
 | 
			
		||||
	const vec2_s16* const t,
 | 
			
		||||
	const size_t index,
 | 
			
		||||
	const complex32_t accum
 | 
			
		||||
) {
 | 
			
		||||
	/* Accumulate sample * tap results for samples already in z buffer.
 | 
			
		||||
	 * For iterations where samples are shifting out of z buffer (being discarded).
 | 
			
		||||
	 * real += i1 * t1 + i0 * t0
 | 
			
		||||
	 * imag += q1 * t1 + q0 * t0
 | 
			
		||||
	 */
 | 
			
		||||
	const auto i1_i0 = z[index*2 + 0];
 | 
			
		||||
	const auto q1_q0 = z[index*2 + 1];
 | 
			
		||||
	const auto t1_t0 = t[index];
 | 
			
		||||
	const auto real = smlad(i1_i0, t1_t0, accum.real());
 | 
			
		||||
	const auto imag = smlad(q1_q0, t1_t0, accum.imag());
 | 
			
		||||
	return { real, imag };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline complex32_t mac_fs4_shift_and_store(
 | 
			
		||||
	vec2_s16* const z,
 | 
			
		||||
	const vec2_s16* const t,
 | 
			
		||||
	const size_t decimation_factor,
 | 
			
		||||
	const size_t index,
 | 
			
		||||
	const complex32_t accum
 | 
			
		||||
) {
 | 
			
		||||
	/* Accumulate sample * tap results for samples already in z buffer.
 | 
			
		||||
	 * Place new samples into z buffer.
 | 
			
		||||
	 * Expect negated tap t[2] to accomodate instruction set limitations.
 | 
			
		||||
	 */
 | 
			
		||||
	const bool negated_t2 = index & 1;
 | 
			
		||||
	const auto q1_i0 = z[decimation_factor + index*2 + 0];
 | 
			
		||||
	const auto i1_q0 = z[decimation_factor + index*2 + 1];
 | 
			
		||||
	const auto t1_t0 = t[decimation_factor / 2 + index];
 | 
			
		||||
	z[index*2 + 0] = q1_i0;
 | 
			
		||||
	const auto real = negated_t2 ? smlsd(q1_i0, t1_t0, accum.real()) : smlad(q1_i0, t1_t0, accum.real());
 | 
			
		||||
	z[index*2 + 1] = i1_q0;
 | 
			
		||||
	const auto imag = negated_t2 ? smlad(i1_q0, t1_t0, accum.imag()) : smlsd(i1_q0, t1_t0, accum.imag());
 | 
			
		||||
	return { real, imag };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline complex32_t mac_shift_and_store(
 | 
			
		||||
	vec2_s16* const z,
 | 
			
		||||
	const vec2_s16* const t,
 | 
			
		||||
	const size_t decimation_factor,
 | 
			
		||||
	const size_t index,
 | 
			
		||||
	const complex32_t accum
 | 
			
		||||
) {
 | 
			
		||||
	/* Accumulate sample * tap results for samples already in z buffer.
 | 
			
		||||
	 * Place new samples into z buffer.
 | 
			
		||||
	 * Expect negated tap t[2] to accomodate instruction set limitations.
 | 
			
		||||
	 */
 | 
			
		||||
	const auto i1_i0 = z[decimation_factor + index*2 + 0];
 | 
			
		||||
	const auto q1_q0 = z[decimation_factor + index*2 + 1];
 | 
			
		||||
	const auto t1_t0 = t[decimation_factor / 2 + index];
 | 
			
		||||
	z[index*2 + 0] = i1_i0;
 | 
			
		||||
	const auto real = smlad(i1_i0, t1_t0, accum.real());
 | 
			
		||||
	z[index*2 + 1] = q1_q0;
 | 
			
		||||
	const auto imag = smlad(q1_q0, t1_t0, accum.imag());
 | 
			
		||||
	return { real, imag };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline complex32_t mac_fs4_shift_and_store_new_c8_samples(
 | 
			
		||||
	vec2_s16* const z,
 | 
			
		||||
	const vec2_s16* const t,
 | 
			
		||||
	const vec4_s8* const in,
 | 
			
		||||
	const size_t decimation_factor,
 | 
			
		||||
	const size_t index,
 | 
			
		||||
	const size_t length,
 | 
			
		||||
	const complex32_t accum
 | 
			
		||||
) {
 | 
			
		||||
	/* Accumulate sample * tap results for new samples.
 | 
			
		||||
	 * Place new samples into z buffer.
 | 
			
		||||
	 * Expect negated tap t[2] to accomodate instruction set limitations.
 | 
			
		||||
	 */
 | 
			
		||||
	const bool negated_t2 = index & 1;
 | 
			
		||||
	const auto q1_i1_q0_i0 = in[index];
 | 
			
		||||
	const auto t1_t0 = t[(length - decimation_factor) / 2 + index];
 | 
			
		||||
	const auto i1_q1_i0_q0 = rev16(q1_i1_q0_i0);
 | 
			
		||||
	const auto i1_q1_q0_i0 = pkhbt(q1_i1_q0_i0, i1_q1_i0_q0);
 | 
			
		||||
	const auto q1_i0 = sxtb16(i1_q1_q0_i0);
 | 
			
		||||
	const auto i1_q0 = sxtb16(i1_q1_q0_i0, 8);
 | 
			
		||||
	z[length - decimation_factor * 2 + index*2 + 0] = q1_i0;
 | 
			
		||||
	const auto real = negated_t2 ? smlsd(q1_i0, t1_t0, accum.real()) : smlad(q1_i0, t1_t0, accum.real());
 | 
			
		||||
	z[length - decimation_factor * 2 + index*2 + 1] = i1_q0;
 | 
			
		||||
	const auto imag = negated_t2 ? smlad(i1_q0, t1_t0, accum.imag()) : smlsd(i1_q0, t1_t0, accum.imag());
 | 
			
		||||
	return { real, imag };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline complex32_t mac_shift_and_store_new_c16_samples(
 | 
			
		||||
	vec2_s16* const z,
 | 
			
		||||
	const vec2_s16* const t,
 | 
			
		||||
	const vec2_s16* const in,
 | 
			
		||||
	const size_t decimation_factor,
 | 
			
		||||
	const size_t index,
 | 
			
		||||
	const size_t length,
 | 
			
		||||
	const complex32_t accum
 | 
			
		||||
) {
 | 
			
		||||
	/* Accumulate sample * tap results for new samples.
 | 
			
		||||
	 * Place new samples into z buffer.
 | 
			
		||||
	 * Expect negated tap t[2] to accomodate instruction set limitations.
 | 
			
		||||
	 */
 | 
			
		||||
	const auto q0_i0 = in[index*2+0];
 | 
			
		||||
	const auto q1_i1 = in[index*2+1];
 | 
			
		||||
	const auto i1_i0 = pkhbt(q0_i0, q1_i1, 16);
 | 
			
		||||
	const auto q1_q0 = pkhtb(q1_i1, q0_i0, 16);
 | 
			
		||||
	const auto t1_t0 = t[(length - decimation_factor) / 2 + index];
 | 
			
		||||
	z[length - decimation_factor * 2 + index*2 + 0] = i1_i0;
 | 
			
		||||
	const auto real = smlad(i1_i0, t1_t0, accum.real());
 | 
			
		||||
	z[length - decimation_factor * 2 + index*2 + 1] = q1_q0;
 | 
			
		||||
	const auto imag = smlad(q1_q0, t1_t0, accum.imag());
 | 
			
		||||
	return { real, imag };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint32_t scale_round_and_pack(
 | 
			
		||||
	const complex32_t value,
 | 
			
		||||
	const int32_t scale_factor
 | 
			
		||||
) {
 | 
			
		||||
	/* Multiply 32-bit components of the complex<int32_t> by a scale factor,
 | 
			
		||||
	 * into int64_ts, then round to nearest LSB (1 << 32), saturate to 16 bits,
 | 
			
		||||
	 * and pack into a complex<int16_t>.
 | 
			
		||||
	 */
 | 
			
		||||
	const auto scaled_real = __SMMULR(value.real(), scale_factor);
 | 
			
		||||
	const auto saturated_real = __SSAT(scaled_real, 16);
 | 
			
		||||
 | 
			
		||||
	const auto scaled_imag = __SMMULR(value.imag(), scale_factor);
 | 
			
		||||
	const auto saturated_imag = __SSAT(scaled_imag, 16);
 | 
			
		||||
 | 
			
		||||
	return __PKHBT(saturated_real, saturated_imag, 16);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename Tap>
 | 
			
		||||
static void taps_copy(
 | 
			
		||||
	const Tap* const source,
 | 
			
		||||
	Tap* const target,
 | 
			
		||||
	const size_t count,
 | 
			
		||||
	const bool shift_up
 | 
			
		||||
) {
 | 
			
		||||
	const uint32_t negate_pattern = shift_up ? 0b1110 : 0b0100;
 | 
			
		||||
	for(size_t i=0; i<count; i++) {
 | 
			
		||||
		const bool negate = (negate_pattern >> (i & 3)) & 1;
 | 
			
		||||
		target[i] = negate ? -source[i] : source[i];
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FIRC8xR16x24FS4Decim4 //////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
void FIRC8xR16x24FS4Decim4::configure(
 | 
			
		||||
	const std::array<tap_t, taps_count>& taps,
 | 
			
		||||
	const int32_t scale,
 | 
			
		||||
	const Shift shift
 | 
			
		||||
) {
 | 
			
		||||
	taps_copy(taps.data(), taps_.data(), taps_.size(), shift == Shift::Up);
 | 
			
		||||
	output_scale = scale;
 | 
			
		||||
	z_.fill({});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_c16_t FIRC8xR16x24FS4Decim4::execute(
 | 
			
		||||
	const buffer_c8_t& src,
 | 
			
		||||
	const buffer_c16_t& dst
 | 
			
		||||
) {
 | 
			
		||||
	vec2_s16* const z = static_cast<vec2_s16*>(__builtin_assume_aligned(z_.data(), 4));
 | 
			
		||||
	const vec2_s16* const t = static_cast<vec2_s16*>(__builtin_assume_aligned(taps_.data(), 4));
 | 
			
		||||
	uint32_t* const d = static_cast<uint32_t*>(__builtin_assume_aligned(dst.p, 4));
 | 
			
		||||
 | 
			
		||||
	const auto k = output_scale;
 | 
			
		||||
 | 
			
		||||
	const size_t count = src.count / decimation_factor;
 | 
			
		||||
	for(size_t i=0; i<count; i++) {
 | 
			
		||||
		const vec4_s8* const in = static_cast<const vec4_s8*>(__builtin_assume_aligned(&src.p[i * decimation_factor], 4));
 | 
			
		||||
 | 
			
		||||
		complex32_t accum;
 | 
			
		||||
 | 
			
		||||
		// Oldest samples are discarded.
 | 
			
		||||
		accum = mac_fs4_shift(z, t, 0, accum);
 | 
			
		||||
		accum = mac_fs4_shift(z, t, 1, accum);
 | 
			
		||||
 | 
			
		||||
		// Middle samples are shifted earlier in the "z" delay buffer.
 | 
			
		||||
		accum = mac_fs4_shift_and_store(z, t, decimation_factor, 0, accum);
 | 
			
		||||
		accum = mac_fs4_shift_and_store(z, t, decimation_factor, 1, accum);
 | 
			
		||||
		accum = mac_fs4_shift_and_store(z, t, decimation_factor, 2, accum);
 | 
			
		||||
		accum = mac_fs4_shift_and_store(z, t, decimation_factor, 3, accum);
 | 
			
		||||
		accum = mac_fs4_shift_and_store(z, t, decimation_factor, 4, accum);
 | 
			
		||||
		accum = mac_fs4_shift_and_store(z, t, decimation_factor, 5, accum);
 | 
			
		||||
		accum = mac_fs4_shift_and_store(z, t, decimation_factor, 6, accum);
 | 
			
		||||
		accum = mac_fs4_shift_and_store(z, t, decimation_factor, 7, accum);
 | 
			
		||||
 | 
			
		||||
		// Newest samples come from "in" buffer, are copied to "z" delay buffer.
 | 
			
		||||
		accum = mac_fs4_shift_and_store_new_c8_samples(z, t, in, decimation_factor, 0, taps_count, accum);
 | 
			
		||||
		accum = mac_fs4_shift_and_store_new_c8_samples(z, t, in, decimation_factor, 1, taps_count, accum);
 | 
			
		||||
 | 
			
		||||
		d[i] = scale_round_and_pack(accum, k);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return {
 | 
			
		||||
		dst.p,
 | 
			
		||||
		count,
 | 
			
		||||
		src.sampling_rate / decimation_factor
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FIRC8xR16x24FS4Decim8 //////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
void FIRC8xR16x24FS4Decim8::configure(
 | 
			
		||||
	const std::array<tap_t, taps_count>& taps,
 | 
			
		||||
	const int32_t scale,
 | 
			
		||||
	const Shift shift
 | 
			
		||||
) {
 | 
			
		||||
	taps_copy(taps.data(), taps_.data(), taps_.size(), shift == Shift::Up);
 | 
			
		||||
	output_scale = scale;
 | 
			
		||||
	z_.fill({});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_c16_t FIRC8xR16x24FS4Decim8::execute(
 | 
			
		||||
	const buffer_c8_t& src,
 | 
			
		||||
	const buffer_c16_t& dst
 | 
			
		||||
) {
 | 
			
		||||
	vec2_s16* const z = static_cast<vec2_s16*>(__builtin_assume_aligned(z_.data(), 4));
 | 
			
		||||
	const vec2_s16* const t = static_cast<vec2_s16*>(__builtin_assume_aligned(taps_.data(), 4));
 | 
			
		||||
	uint32_t* const d = static_cast<uint32_t*>(__builtin_assume_aligned(dst.p, 4));
 | 
			
		||||
 | 
			
		||||
	const auto k = output_scale;
 | 
			
		||||
 | 
			
		||||
	const size_t count = src.count / decimation_factor;
 | 
			
		||||
	for(size_t i=0; i<count; i++) {
 | 
			
		||||
		const vec4_s8* const in = static_cast<const vec4_s8*>(__builtin_assume_aligned(&src.p[i * decimation_factor], 4));
 | 
			
		||||
 | 
			
		||||
		complex32_t accum;
 | 
			
		||||
 | 
			
		||||
		// Oldest samples are discarded.
 | 
			
		||||
		accum = mac_fs4_shift(z, t, 0, accum);
 | 
			
		||||
		accum = mac_fs4_shift(z, t, 1, accum);
 | 
			
		||||
		accum = mac_fs4_shift(z, t, 2, accum);
 | 
			
		||||
		accum = mac_fs4_shift(z, t, 3, accum);
 | 
			
		||||
 | 
			
		||||
		// Middle samples are shifted earlier in the "z" delay buffer.
 | 
			
		||||
		accum = mac_fs4_shift_and_store(z, t, decimation_factor, 0, accum);
 | 
			
		||||
		accum = mac_fs4_shift_and_store(z, t, decimation_factor, 1, accum);
 | 
			
		||||
		accum = mac_fs4_shift_and_store(z, t, decimation_factor, 2, accum);
 | 
			
		||||
		accum = mac_fs4_shift_and_store(z, t, decimation_factor, 3, accum);
 | 
			
		||||
 | 
			
		||||
		// Newest samples come from "in" buffer, are copied to "z" delay buffer.
 | 
			
		||||
		accum = mac_fs4_shift_and_store_new_c8_samples(z, t, in, decimation_factor, 0, taps_count, accum);
 | 
			
		||||
		accum = mac_fs4_shift_and_store_new_c8_samples(z, t, in, decimation_factor, 1, taps_count, accum);
 | 
			
		||||
		accum = mac_fs4_shift_and_store_new_c8_samples(z, t, in, decimation_factor, 2, taps_count, accum);
 | 
			
		||||
		accum = mac_fs4_shift_and_store_new_c8_samples(z, t, in, decimation_factor, 3, taps_count, accum);
 | 
			
		||||
 | 
			
		||||
		d[i] = scale_round_and_pack(accum, k);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return {
 | 
			
		||||
		dst.p,
 | 
			
		||||
		count,
 | 
			
		||||
		src.sampling_rate / decimation_factor
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FIRC16xR16x16Decim2 ////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
void FIRC16xR16x16Decim2::configure(
 | 
			
		||||
	const std::array<tap_t, taps_count>& taps,
 | 
			
		||||
	const int32_t scale
 | 
			
		||||
) {
 | 
			
		||||
	std::copy(taps.cbegin(), taps.cend(), taps_.begin());
 | 
			
		||||
	output_scale = scale;
 | 
			
		||||
	z_.fill({});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_c16_t FIRC16xR16x16Decim2::execute(
 | 
			
		||||
	const buffer_c16_t& src,
 | 
			
		||||
	const buffer_c16_t& dst
 | 
			
		||||
) {
 | 
			
		||||
	vec2_s16* const z = static_cast<vec2_s16*>(__builtin_assume_aligned(z_.data(), 4));
 | 
			
		||||
	const vec2_s16* const t = static_cast<vec2_s16*>(__builtin_assume_aligned(taps_.data(), 4));
 | 
			
		||||
	uint32_t* const d = static_cast<uint32_t*>(__builtin_assume_aligned(dst.p, 4));
 | 
			
		||||
 | 
			
		||||
	const auto k = output_scale;
 | 
			
		||||
 | 
			
		||||
	const size_t count = src.count / decimation_factor;
 | 
			
		||||
	for(size_t i=0; i<count; i++) {
 | 
			
		||||
		const vec2_s16* const in = static_cast<const vec2_s16*>(__builtin_assume_aligned(&src.p[i * decimation_factor], 4));
 | 
			
		||||
 | 
			
		||||
		complex32_t accum;
 | 
			
		||||
 | 
			
		||||
		// Oldest samples are discarded.
 | 
			
		||||
		accum = mac_shift(z, t, 0, accum);
 | 
			
		||||
 | 
			
		||||
		// Middle samples are shifted earlier in the "z" delay buffer.
 | 
			
		||||
		accum = mac_shift_and_store(z, t, decimation_factor, 0, accum);
 | 
			
		||||
		accum = mac_shift_and_store(z, t, decimation_factor, 1, accum);
 | 
			
		||||
		accum = mac_shift_and_store(z, t, decimation_factor, 2, accum);
 | 
			
		||||
		accum = mac_shift_and_store(z, t, decimation_factor, 3, accum);
 | 
			
		||||
		accum = mac_shift_and_store(z, t, decimation_factor, 4, accum);
 | 
			
		||||
		accum = mac_shift_and_store(z, t, decimation_factor, 5, accum);
 | 
			
		||||
 | 
			
		||||
		// Newest samples come from "in" buffer, are copied to "z" delay buffer.
 | 
			
		||||
		accum = mac_shift_and_store_new_c16_samples(z, t, in, decimation_factor, 0, taps_count, accum);
 | 
			
		||||
 | 
			
		||||
		d[i] = scale_round_and_pack(accum, k);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return {
 | 
			
		||||
		dst.p,
 | 
			
		||||
		count,
 | 
			
		||||
		src.sampling_rate / decimation_factor
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FIRC16xR16x32Decim8 ////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
void FIRC16xR16x32Decim8::configure(
 | 
			
		||||
	const std::array<tap_t, taps_count>& taps,
 | 
			
		||||
	const int32_t scale
 | 
			
		||||
) {
 | 
			
		||||
	std::copy(taps.cbegin(), taps.cend(), taps_.begin());
 | 
			
		||||
	output_scale = scale;
 | 
			
		||||
	z_.fill({});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_c16_t FIRC16xR16x32Decim8::execute(
 | 
			
		||||
	const buffer_c16_t& src,
 | 
			
		||||
	const buffer_c16_t& dst
 | 
			
		||||
) {
 | 
			
		||||
	vec2_s16* const z = static_cast<vec2_s16*>(__builtin_assume_aligned(z_.data(), 4));
 | 
			
		||||
	const vec2_s16* const t = static_cast<vec2_s16*>(__builtin_assume_aligned(taps_.data(), 4));
 | 
			
		||||
	uint32_t* const d = static_cast<uint32_t*>(__builtin_assume_aligned(dst.p, 4));
 | 
			
		||||
 | 
			
		||||
	const auto k = output_scale;
 | 
			
		||||
 | 
			
		||||
	const size_t count = src.count / decimation_factor;
 | 
			
		||||
	for(size_t i=0; i<count; i++) {
 | 
			
		||||
		const vec2_s16* const in = static_cast<const vec2_s16*>(__builtin_assume_aligned(&src.p[i * decimation_factor], 4));
 | 
			
		||||
 | 
			
		||||
		complex32_t accum;
 | 
			
		||||
 | 
			
		||||
		// Oldest samples are discarded.
 | 
			
		||||
		accum = mac_shift(z, t, 0, accum);
 | 
			
		||||
		accum = mac_shift(z, t, 1, accum);
 | 
			
		||||
		accum = mac_shift(z, t, 2, accum);
 | 
			
		||||
		accum = mac_shift(z, t, 3, accum);
 | 
			
		||||
 | 
			
		||||
		// Middle samples are shifted earlier in the "z" delay buffer.
 | 
			
		||||
		accum = mac_shift_and_store(z, t, decimation_factor, 0, accum);
 | 
			
		||||
		accum = mac_shift_and_store(z, t, decimation_factor, 1, accum);
 | 
			
		||||
		accum = mac_shift_and_store(z, t, decimation_factor, 2, accum);
 | 
			
		||||
		accum = mac_shift_and_store(z, t, decimation_factor, 3, accum);
 | 
			
		||||
		accum = mac_shift_and_store(z, t, decimation_factor, 4, accum);
 | 
			
		||||
		accum = mac_shift_and_store(z, t, decimation_factor, 5, accum);
 | 
			
		||||
		accum = mac_shift_and_store(z, t, decimation_factor, 6, accum);
 | 
			
		||||
		accum = mac_shift_and_store(z, t, decimation_factor, 7, accum);
 | 
			
		||||
 | 
			
		||||
		// Newest samples come from "in" buffer, are copied to "z" delay buffer.
 | 
			
		||||
		accum = mac_shift_and_store_new_c16_samples(z, t, in, decimation_factor, 0, taps_count, accum);
 | 
			
		||||
		accum = mac_shift_and_store_new_c16_samples(z, t, in, decimation_factor, 1, taps_count, accum);
 | 
			
		||||
		accum = mac_shift_and_store_new_c16_samples(z, t, in, decimation_factor, 2, taps_count, accum);
 | 
			
		||||
		accum = mac_shift_and_store_new_c16_samples(z, t, in, decimation_factor, 3, taps_count, accum);
 | 
			
		||||
 | 
			
		||||
		d[i] = scale_round_and_pack(accum, k);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return {
 | 
			
		||||
		dst.p,
 | 
			
		||||
		count,
 | 
			
		||||
		src.sampling_rate / decimation_factor
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_c16_t Complex8DecimateBy2CIC3::execute(const buffer_c8_t& src, const buffer_c16_t& dst) {
 | 
			
		||||
	/* Decimates by two using a non-recursive third-order CIC filter.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	/* CIC filter (decimating by two):
 | 
			
		||||
	 * 	D_I0 = i3 * 1 + i2 * 3 + i1 * 3 + i0 * 1
 | 
			
		||||
	 * 	D_Q0 = q3 * 1 + q2 * 3 + q1 * 3 + q0 * 1
 | 
			
		||||
	 *
 | 
			
		||||
	 * 	D_I1 = i5 * 1 + i4 * 3 + i3 * 3 + i2 * 1
 | 
			
		||||
	 * 	D_Q1 = q5 * 1 + q4 * 3 + q3 * 3 + q2 * 1
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	uint32_t i1_i0 = _i1_i0;
 | 
			
		||||
	uint32_t q1_q0 = _q1_q0;
 | 
			
		||||
 | 
			
		||||
	/* 3:1 Scaled by 32 to normalize output to +/-32768-ish. */
 | 
			
		||||
	constexpr uint32_t scale_factor = 32;
 | 
			
		||||
	constexpr uint32_t k_3_1 = 0x00030001 * scale_factor;
 | 
			
		||||
	uint32_t* src_p = reinterpret_cast<uint32_t*>(&src.p[0]);
 | 
			
		||||
	uint32_t* const src_end = reinterpret_cast<uint32_t*>(&src.p[src.count]);
 | 
			
		||||
	uint32_t* dst_p = reinterpret_cast<uint32_t*>(&dst.p[0]);
 | 
			
		||||
	while(src_p < src_end) {
 | 
			
		||||
		const uint32_t q3_i3_q2_i2 = *(src_p++);						// 3
 | 
			
		||||
		const uint32_t q5_i5_q4_i4 = *(src_p++);
 | 
			
		||||
 | 
			
		||||
		const uint32_t d_i0_partial = __SMUAD(k_3_1, i1_i0);			// 1: = 3 * i1 + 1 * i0
 | 
			
		||||
		const uint32_t i3_i2 = __SXTB16(q3_i3_q2_i2,  0);				// 1: (q3_i3_q2_i2 ror  0)[23:16]:(q3_i3_q2_i2 ror  0)[7:0]
 | 
			
		||||
		const uint32_t d_i0 = __SMLADX(k_3_1, i3_i2, d_i0_partial);		// 1: + 3 * i2 + 1 * i3
 | 
			
		||||
 | 
			
		||||
		const uint32_t d_q0_partial = __SMUAD(k_3_1, q1_q0);			// 1: = 3 * q1 * 1 * q0
 | 
			
		||||
		const uint32_t q3_q2 = __SXTB16(q3_i3_q2_i2,  8);				// 1: (q3_i3_q2_i2 ror  8)[23:16]:(q3_i3_q2_i2 ror  8)[7:0]
 | 
			
		||||
		const uint32_t d_q0 = __SMLADX(k_3_1, q3_q2, d_q0_partial);		// 1: + 3 * q2 + 1 * q3 
 | 
			
		||||
 | 
			
		||||
		const uint32_t d_q0_i0 = __PKHBT(d_i0, d_q0, 16);				// 1: (Rm<<16)[31:16]:Rn[15:0]
 | 
			
		||||
 | 
			
		||||
		const uint32_t d_i1_partial = __SMUAD(k_3_1, i3_i2);			// 1: = 3 * i3 + 1 * i2
 | 
			
		||||
		const uint32_t i5_i4 = __SXTB16(q5_i5_q4_i4,  0);				// 1: (q5_i5_q4_i4 ror  0)[23:16]:(q5_i5_q4_i4 ror  0)[7:0]
 | 
			
		||||
		const uint32_t d_i1 = __SMLADX(k_3_1, i5_i4, d_i1_partial);		// 1: + 1 * i5 + 3 * i4
 | 
			
		||||
 | 
			
		||||
		const uint32_t d_q1_partial = __SMUAD(k_3_1, q3_q2);			// 1: = 3 * q3 * 1 * q2
 | 
			
		||||
		const uint32_t q5_q4 = __SXTB16(q5_i5_q4_i4,  8);				// 1: (q5_i5_q4_i4 ror  8)[23:16]:(q5_i5_q4_i4 ror  8)[7:0]
 | 
			
		||||
		const uint32_t d_q1 = __SMLADX(k_3_1, q5_q4, d_q1_partial);		// 1: + 1 * q5 + 3 * q4 
 | 
			
		||||
 | 
			
		||||
		const uint32_t d_q1_i1 = __PKHBT(d_i1, d_q1, 16);				// 1: (Rm<<16)[31:16]:Rn[15:0]
 | 
			
		||||
 | 
			
		||||
		*(dst_p++) = d_q0_i0;											// 3
 | 
			
		||||
		*(dst_p++) = d_q1_i1;
 | 
			
		||||
 | 
			
		||||
		i1_i0 = i5_i4;
 | 
			
		||||
		q1_q0 = q5_q4;
 | 
			
		||||
	}
 | 
			
		||||
	_i1_i0 = i1_i0;
 | 
			
		||||
	_q1_q0 = q1_q0;
 | 
			
		||||
 | 
			
		||||
	return { dst.p, src.count / 2, src.sampling_rate / 2 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_c16_t TranslateByFSOver4AndDecimateBy2CIC3::execute(const buffer_c8_t& src, const buffer_c16_t& dst) {
 | 
			
		||||
	/* Translates incoming complex<int8_t> samples by -fs/4,
 | 
			
		||||
	 * decimates by two using a non-recursive third-order CIC filter.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	/* Derivation of algorithm:
 | 
			
		||||
	 * Original CIC filter (decimating by two):
 | 
			
		||||
	 * 	D_I0 = i3 * 1 + i2 * 3 + i1 * 3 + i0 * 1
 | 
			
		||||
	 * 	D_Q0 = q3 * 1 + q2 * 3 + q1 * 3 + q0 * 1
 | 
			
		||||
	 *
 | 
			
		||||
	 * 	D_I1 = i5 * 1 + i4 * 3 + i3 * 3 + i2 * 1
 | 
			
		||||
	 * 	D_Q1 = q5 * 1 + q4 * 3 + q3 * 3 + q2 * 1
 | 
			
		||||
	 *
 | 
			
		||||
	 * Translate -fs/4, phased 180 degrees, accomplished by complex multiplication
 | 
			
		||||
	 * of complex length-4 sequence:
 | 
			
		||||
	 *
 | 
			
		||||
	 * Substitute:
 | 
			
		||||
	 *	i0 = -i0, q0 = -q0
 | 
			
		||||
	 *	i1 = -q1, q1 =  i1
 | 
			
		||||
	 *	i2 =  i2, q2 =  q2
 | 
			
		||||
	 *	i3 =  q3, q3 = -i3
 | 
			
		||||
	 *	i4 = -i4, q4 = -q4
 | 
			
		||||
	 *	i5 = -q5, q5 =  i5
 | 
			
		||||
	 *
 | 
			
		||||
	 * Resulting taps (with decimation by 2, four samples in, two samples out):
 | 
			
		||||
	 *	D_I0 =  q3 * 1 +  i2 * 3 + -q1 * 3 + -i0 * 1
 | 
			
		||||
	 *	D_Q0 = -i3 * 1 +  q2 * 3 +  i1 * 3 + -q0 * 1
 | 
			
		||||
 	 *
 | 
			
		||||
	 *	D_I1 = -q5 * 1 + -i4 * 3 +  q3 * 3 +  i2 * 1
 | 
			
		||||
	 *	D_Q1 =  i5 * 1 + -q4 * 3 + -i3 * 3 +  q2 * 1
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	// 6 cycles per complex input sample, not including loop overhead.
 | 
			
		||||
	uint32_t q1_i0 = _q1_i0;
 | 
			
		||||
	uint32_t q0_i1 = _q0_i1;
 | 
			
		||||
	/* 3:1 Scaled by 32 to normalize output to +/-32768-ish. */
 | 
			
		||||
	constexpr uint32_t scale_factor = 32;
 | 
			
		||||
	const uint32_t k_3_1 = 0x00030001 * scale_factor;
 | 
			
		||||
	uint32_t* src_p = reinterpret_cast<uint32_t*>(&src.p[0]);
 | 
			
		||||
	uint32_t* const src_end = reinterpret_cast<uint32_t*>(&src.p[src.count]);
 | 
			
		||||
	uint32_t* dst_p = reinterpret_cast<uint32_t*>(&dst.p[0]);
 | 
			
		||||
	while(src_p < src_end) {
 | 
			
		||||
		const uint32_t q3_i3_q2_i2 = *(src_p++);			// 3
 | 
			
		||||
		const uint32_t q5_i5_q4_i4 = *(src_p++);
 | 
			
		||||
 | 
			
		||||
		const uint32_t i2_i3 = __SXTB16(q3_i3_q2_i2, 16);			// 1: (q3_i3_q2_i2 ror 16)[23:16]:(q3_i3_q2_i2 ror 16)[7:0]
 | 
			
		||||
		const uint32_t q3_q2 = __SXTB16(q3_i3_q2_i2,  8);			// 1: (q3_i3_q2_i2 ror  8)[23:16]:(q3_i3_q2_i2 ror  8)[7:0]
 | 
			
		||||
		const uint32_t i2_q3 = __PKHTB(i2_i3, q3_q2, 16);			// 1: Rn[31:16]:(Rm>>16)[15:0]
 | 
			
		||||
		const uint32_t i3_q2 = __PKHBT(q3_q2, i2_i3, 16);			// 1:(Rm<<16)[31:16]:Rn[15:0]
 | 
			
		||||
 | 
			
		||||
		// D_I0 = 3 * (i2 - q1) + (q3 - i0)
 | 
			
		||||
		const uint32_t i2_m_q1_q3_m_i0 = __QSUB16(i2_q3, q1_i0);	// 1: Rn[31:16]-Rm[31:16]:Rn[15:0]-Rm[15:0]
 | 
			
		||||
		const uint32_t d_i0 = __SMUAD(k_3_1, i2_m_q1_q3_m_i0);		// 1: Rm[15:0]*Rs[15:0]+Rm[31:16]*Rs[31:16]
 | 
			
		||||
 | 
			
		||||
		// D_Q0 = 3 * (q2 + i1) - (i3 + q0)
 | 
			
		||||
		const uint32_t i3_p_q0_q2_p_i1 = __QADD16(i3_q2, q0_i1);	// 1: Rn[31:16]+Rm[31:16]:Rn[15:0]+Rm[15:0]
 | 
			
		||||
		const uint32_t d_q0 = __SMUSDX(i3_p_q0_q2_p_i1, k_3_1);		// 1: Rm[15:0]*Rs[31:16]–Rm[31:16]*RsX[15:0]
 | 
			
		||||
		const uint32_t d_q0_i0 = __PKHBT(d_i0, d_q0, 16);			// 1: (Rm<<16)[31:16]:Rn[15:0]
 | 
			
		||||
 | 
			
		||||
		const uint32_t i5_i4 = __SXTB16(q5_i5_q4_i4,  0);			// 1: (q5_i5_q4_i4 ror  0)[23:16]:(q5_i5_q4_i4 ror  0)[7:0]
 | 
			
		||||
		const uint32_t q4_q5 = __SXTB16(q5_i5_q4_i4, 24);			// 1: (q5_i5_q4_i4 ror 24)[23:16]:(q5_i5_q4_i4 ror 24)[7:0]
 | 
			
		||||
		const uint32_t q4_i5 = __PKHTB(q4_q5, i5_i4, 16);			// 1: Rn[31:16]:(Rm>>16)[15:0]
 | 
			
		||||
		const uint32_t q5_i4 = __PKHBT(i5_i4, q4_q5, 16);			// 1: (Rm<<16)[31:16]:Rn[15:0]
 | 
			
		||||
 | 
			
		||||
		// D_I1 = (i2 - q5) + 3 * (q3 - i4)
 | 
			
		||||
		const uint32_t i2_m_q5_q3_m_i4 = __QSUB16(i2_q3, q5_i4);	// 1: Rn[31:16]-Rm[31:16]:Rn[15:0]-Rm[15:0]
 | 
			
		||||
		const uint32_t d_i1 = __SMUADX(i2_m_q5_q3_m_i4, k_3_1);		// 1: Rm[15:0]*Rs[31:16]+Rm[31:16]*Rs[15:0]
 | 
			
		||||
 | 
			
		||||
		// D_Q1 = (i5 + q2) - 3 * (q4 + i3)
 | 
			
		||||
		const uint32_t q4_p_i3_i5_p_q2 = __QADD16(q4_i5, i3_q2);	// 1: Rn[31:16]+Rm[31:16]:Rn[15:0]+Rm[15:0]
 | 
			
		||||
		const uint32_t d_q1 = __SMUSD(k_3_1, q4_p_i3_i5_p_q2);		// 1: Rm[15:0]*Rs[15:0]–Rm[31:16]*Rs[31:16]
 | 
			
		||||
		const uint32_t d_q1_i1 = __PKHBT(d_i1, d_q1, 16);			// 1: (Rm<<16)[31:16]:Rn[15:0]
 | 
			
		||||
		*(dst_p++) = d_q0_i0;							// 3
 | 
			
		||||
		*(dst_p++) = d_q1_i1;
 | 
			
		||||
 | 
			
		||||
		q1_i0 = q5_i4;
 | 
			
		||||
		q0_i1 = q4_i5;
 | 
			
		||||
	}
 | 
			
		||||
	_q1_i0 = q1_i0;
 | 
			
		||||
	_q0_i1 = q0_i1;
 | 
			
		||||
 | 
			
		||||
	return { dst.p, src.count / 2, src.sampling_rate / 2 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_c16_t DecimateBy2CIC3::execute(
 | 
			
		||||
	const buffer_c16_t& src,
 | 
			
		||||
	const buffer_c16_t& dst
 | 
			
		||||
) {
 | 
			
		||||
	/* Complex non-recursive 3rd-order CIC filter (taps 1,3,3,1).
 | 
			
		||||
	 * Gain of 8.
 | 
			
		||||
	 * Consumes 16 bytes (4 s16:s16 samples) per loop iteration,
 | 
			
		||||
	 * Produces  8 bytes (2 s16:s16 samples) per loop iteration.
 | 
			
		||||
	 */
 | 
			
		||||
	uint32_t t1 = _iq0;
 | 
			
		||||
	uint32_t t2 = _iq1;
 | 
			
		||||
	const uint32_t taps = 0x00000003;
 | 
			
		||||
	void* s = src.p;
 | 
			
		||||
	void* d = dst.p;
 | 
			
		||||
	const auto d_end = &dst.p[src.count / 2];
 | 
			
		||||
	while(d < d_end) {
 | 
			
		||||
		uint32_t i = __SXTH(t1, 0);			/* 1: I0 */
 | 
			
		||||
		uint32_t q = __SXTH(t1, 16);			/* 1: Q0 */
 | 
			
		||||
		i = __SMLABB(t2, taps, i);	/* 1: I1*3 + I0 */
 | 
			
		||||
		q = __SMLATB(t2, taps, q);	/* 1: Q1*3 + Q0 */
 | 
			
		||||
 | 
			
		||||
		const uint32_t t3 = *__SIMD32(s)++;		/* 3: Q2:I2 */
 | 
			
		||||
		const uint32_t t4 = *__SIMD32(s)++;		/*    Q3:I3 */
 | 
			
		||||
 | 
			
		||||
		i = __SMLABB(t3, taps, i);	/* 1: I2*3 + I1*3 + I0 */
 | 
			
		||||
		q = __SMLATB(t3, taps, q);	/* 1: Q2*3 + Q1*3 + Q0 */
 | 
			
		||||
		int32_t si0 = __SXTAH(i, t4,  0);		/* 1: I3 + Q2*3 + Q1*3 + Q0 */
 | 
			
		||||
		int32_t sq0 = __SXTAH(q, t4, 16);		/* 1: Q3 + Q2*3 + Q1*3 + Q0 */
 | 
			
		||||
		i = __BFI(si0 / 8, sq0 / 8, 16, 16);	/* 1: D2_Q0:D2_I0 */
 | 
			
		||||
		*__SIMD32(d)++ = i;			/* D2_Q0:D2_I0 */
 | 
			
		||||
 | 
			
		||||
		i = __SXTH(t3, 0);			/* 1: I2 */
 | 
			
		||||
		q = __SXTH(t3, 16);			/* 1: Q2 */
 | 
			
		||||
		i = __SMLABB(t4, taps, i);	/* 1: I3*3 + I2 */
 | 
			
		||||
		q = __SMLATB(t4, taps, q);	/* 1: Q3*3 + Q2 */
 | 
			
		||||
 | 
			
		||||
		t1 = *__SIMD32(s)++;		/* 3: Q4:I4 */
 | 
			
		||||
		t2 = *__SIMD32(s)++;		/*    Q5:I5 */
 | 
			
		||||
 | 
			
		||||
		i = __SMLABB(t1, taps, i);	/* 1: I4*3 + I3*3 + I2 */
 | 
			
		||||
		q = __SMLATB(t1, taps, q);	/* 1: Q4*3 + Q3*3 + Q2 */
 | 
			
		||||
		int32_t si1 = __SXTAH(i, t2, 0) ;		/* 1: I5 + Q4*3 + Q3*3 + Q2 */
 | 
			
		||||
		int32_t sq1 = __SXTAH(q, t2, 16);		/* 1: Q5 + Q4*3 + Q3*3 + Q2 */
 | 
			
		||||
		i = __BFI(si1 / 8, sq1 / 8, 16, 16);	/* 1: D2_Q1:D2_I1 */
 | 
			
		||||
		*__SIMD32(d)++ = i;			/* D2_Q1:D2_I1 */
 | 
			
		||||
	}
 | 
			
		||||
	_iq0 = t1;
 | 
			
		||||
	_iq1 = t2;
 | 
			
		||||
 | 
			
		||||
	return { dst.p, src.count / 2, src.sampling_rate / 2 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FIR64AndDecimateBy2Real::configure(
 | 
			
		||||
	const std::array<int16_t, taps_count>& new_taps
 | 
			
		||||
) {
 | 
			
		||||
	std::copy(new_taps.cbegin(), new_taps.cend(), taps.begin());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_s16_t FIR64AndDecimateBy2Real::execute(
 | 
			
		||||
	const buffer_s16_t& src,
 | 
			
		||||
	const buffer_s16_t& dst
 | 
			
		||||
) {
 | 
			
		||||
	/* int16_t input (sample count "n" must be multiple of 4)
 | 
			
		||||
	 * -> int16_t output, decimated by 2.
 | 
			
		||||
	 * taps are normalized to 1 << 16 == 1.0.
 | 
			
		||||
	 */
 | 
			
		||||
	auto src_p = src.p;
 | 
			
		||||
	auto dst_p = dst.p;
 | 
			
		||||
	int32_t n = src.count;
 | 
			
		||||
	for(; n>0; n-=2) {
 | 
			
		||||
		z[taps_count-2] = *(src_p++);
 | 
			
		||||
		z[taps_count-1] = *(src_p++);
 | 
			
		||||
 | 
			
		||||
		int32_t t = 0;
 | 
			
		||||
		for(size_t j=0; j<taps_count; j+=4) {
 | 
			
		||||
			t += z[j+0] * taps[j+0];
 | 
			
		||||
			t += z[j+1] * taps[j+1];
 | 
			
		||||
			t += z[j+2] * taps[j+2];
 | 
			
		||||
			t += z[j+3] * taps[j+3];
 | 
			
		||||
 | 
			
		||||
			z[j+0] = z[j+0+2];
 | 
			
		||||
			z[j+1] = z[j+1+2];
 | 
			
		||||
			z[j+2] = z[j+2+2];
 | 
			
		||||
			z[j+3] = z[j+3+2];
 | 
			
		||||
		}
 | 
			
		||||
		*(dst_p++) = t / 65536;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return { dst.p, src.count / 2, src.sampling_rate / 2 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FIRAndDecimateComplex::configure_common(
 | 
			
		||||
	const size_t taps_count, const size_t decimation_factor
 | 
			
		||||
) {
 | 
			
		||||
	samples_ = std::make_unique<samples_t>(taps_count);
 | 
			
		||||
	taps_reversed_ = std::make_unique<taps_t>(taps_count);
 | 
			
		||||
	taps_count_ = taps_count;
 | 
			
		||||
	decimation_factor_ = decimation_factor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_c16_t FIRAndDecimateComplex::execute(
 | 
			
		||||
	const buffer_c16_t& src,
 | 
			
		||||
	const buffer_c16_t& dst
 | 
			
		||||
) {
 | 
			
		||||
	/* int16_t input (sample count "n" must be multiple of decimation_factor)
 | 
			
		||||
	 * -> int16_t output, decimated by decimation_factor.
 | 
			
		||||
	 * taps are normalized to 1 << 16 == 1.0.
 | 
			
		||||
	 */
 | 
			
		||||
	const auto output_sampling_rate = src.sampling_rate / decimation_factor_;
 | 
			
		||||
	const size_t output_samples = src.count / decimation_factor_;
 | 
			
		||||
	
 | 
			
		||||
	void* dst_p = dst.p;
 | 
			
		||||
	const buffer_c16_t result { dst.p, output_samples, output_sampling_rate };
 | 
			
		||||
 | 
			
		||||
	const void* src_p = src.p;
 | 
			
		||||
	size_t outer_count = output_samples;
 | 
			
		||||
	while(outer_count > 0) {
 | 
			
		||||
		/* Put new samples into delay buffer */
 | 
			
		||||
		void* z_new_p = &samples_[taps_count_ - decimation_factor_];
 | 
			
		||||
		for(size_t i=0; i<decimation_factor_; i++) {
 | 
			
		||||
			*__SIMD32(z_new_p)++ = *__SIMD32(src_p)++;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		size_t loop_count = taps_count_ / 8;
 | 
			
		||||
		void* t_p = &taps_reversed_[0];
 | 
			
		||||
		void* z_p = &samples_[0];
 | 
			
		||||
 | 
			
		||||
		int64_t t_real = 0;
 | 
			
		||||
		int64_t t_imag = 0;
 | 
			
		||||
 | 
			
		||||
		while(loop_count > 0) {
 | 
			
		||||
			const auto tap0 = *__SIMD32(t_p)++;
 | 
			
		||||
			const auto sample0 = *__SIMD32(z_p)++;
 | 
			
		||||
			const auto tap1 = *__SIMD32(t_p)++;
 | 
			
		||||
			const auto sample1 = *__SIMD32(z_p)++;
 | 
			
		||||
			t_real = __SMLSLD(sample0, tap0, t_real);
 | 
			
		||||
			t_imag = __SMLALDX(sample0, tap0, t_imag);
 | 
			
		||||
			t_real = __SMLSLD(sample1, tap1, t_real);
 | 
			
		||||
			t_imag = __SMLALDX(sample1, tap1, t_imag);
 | 
			
		||||
 | 
			
		||||
			const auto tap2 = *__SIMD32(t_p)++;
 | 
			
		||||
			const auto sample2 = *__SIMD32(z_p)++;
 | 
			
		||||
			const auto tap3 = *__SIMD32(t_p)++;
 | 
			
		||||
			const auto sample3 = *__SIMD32(z_p)++;
 | 
			
		||||
			t_real = __SMLSLD(sample2, tap2, t_real);
 | 
			
		||||
			t_imag = __SMLALDX(sample2, tap2, t_imag);
 | 
			
		||||
			t_real = __SMLSLD(sample3, tap3, t_real);
 | 
			
		||||
			t_imag = __SMLALDX(sample3, tap3, t_imag);
 | 
			
		||||
 | 
			
		||||
			const auto tap4 = *__SIMD32(t_p)++;
 | 
			
		||||
			const auto sample4 = *__SIMD32(z_p)++;
 | 
			
		||||
			const auto tap5 = *__SIMD32(t_p)++;
 | 
			
		||||
			const auto sample5 = *__SIMD32(z_p)++;
 | 
			
		||||
			t_real = __SMLSLD(sample4, tap4, t_real);
 | 
			
		||||
			t_imag = __SMLALDX(sample4, tap4, t_imag);
 | 
			
		||||
			t_real = __SMLSLD(sample5, tap5, t_real);
 | 
			
		||||
			t_imag = __SMLALDX(sample5, tap5, t_imag);
 | 
			
		||||
 | 
			
		||||
			const auto tap6 = *__SIMD32(t_p)++;
 | 
			
		||||
			const auto sample6 = *__SIMD32(z_p)++;
 | 
			
		||||
			const auto tap7 = *__SIMD32(t_p)++;
 | 
			
		||||
			const auto sample7 = *__SIMD32(z_p)++;
 | 
			
		||||
			t_real = __SMLSLD(sample6, tap6, t_real);
 | 
			
		||||
			t_imag = __SMLALDX(sample6, tap6, t_imag);
 | 
			
		||||
			t_real = __SMLSLD(sample7, tap7, t_real);
 | 
			
		||||
			t_imag = __SMLALDX(sample7, tap7, t_imag);
 | 
			
		||||
 | 
			
		||||
			loop_count--;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* TODO: Re-evaluate whether saturation is performed, normalization,
 | 
			
		||||
		 * all that jazz.
 | 
			
		||||
		 */
 | 
			
		||||
		const int32_t r = t_real >> 16;
 | 
			
		||||
		const int32_t i = t_imag >> 16;
 | 
			
		||||
		const int32_t r_sat = __SSAT(r, 16);
 | 
			
		||||
		const int32_t i_sat = __SSAT(i, 16);
 | 
			
		||||
		*__SIMD32(dst_p)++ = __PKHBT(
 | 
			
		||||
			r_sat,
 | 
			
		||||
			i_sat,
 | 
			
		||||
			16
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
		/* Shift sample buffer left/down by decimation factor. */
 | 
			
		||||
		const size_t unroll_factor = 4;
 | 
			
		||||
		size_t shift_count = (taps_count_ - decimation_factor_) / unroll_factor;
 | 
			
		||||
 | 
			
		||||
		void* t = &samples_[0];
 | 
			
		||||
		const void* s = &samples_[decimation_factor_];
 | 
			
		||||
		
 | 
			
		||||
		while(shift_count > 0) {
 | 
			
		||||
			*__SIMD32(t)++ = *__SIMD32(s)++;
 | 
			
		||||
			*__SIMD32(t)++ = *__SIMD32(s)++;
 | 
			
		||||
			*__SIMD32(t)++ = *__SIMD32(s)++;
 | 
			
		||||
			*__SIMD32(t)++ = *__SIMD32(s)++;
 | 
			
		||||
			shift_count--;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		shift_count = (taps_count_ - decimation_factor_) % unroll_factor;
 | 
			
		||||
		while(shift_count > 0) {
 | 
			
		||||
			*__SIMD32(t)++ = *__SIMD32(s)++;
 | 
			
		||||
			shift_count--;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		outer_count--;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_s16_t DecimateBy2CIC4Real::execute(
 | 
			
		||||
	const buffer_s16_t& src,
 | 
			
		||||
	const buffer_s16_t& dst
 | 
			
		||||
) {
 | 
			
		||||
	auto src_p = src.p;
 | 
			
		||||
	auto dst_p = dst.p;
 | 
			
		||||
	int32_t n = src.count;
 | 
			
		||||
	for(; n>0; n-=2) {
 | 
			
		||||
		/* TODO: Probably a lot of room to optimize... */
 | 
			
		||||
		z[0] = z[2];
 | 
			
		||||
		z[1] = z[3];
 | 
			
		||||
		z[2] = z[4];
 | 
			
		||||
		z[3] = *(src_p++);
 | 
			
		||||
		z[4] = *(src_p++);
 | 
			
		||||
 | 
			
		||||
		int32_t t = z[0] + z[1] * 4 + z[2] * 6 + z[3] * 4 + z[4];
 | 
			
		||||
		*(dst_p++) = t / 16;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return { dst.p, src.count / 2, src.sampling_rate / 2 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace decimate */
 | 
			
		||||
} /* namespace dsp */
 | 
			
		||||
							
								
								
									
										264
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_decimate.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_decimate.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,264 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DSP_DECIMATE_H__
 | 
			
		||||
#define __DSP_DECIMATE_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
 | 
			
		||||
#include "simd.hpp"
 | 
			
		||||
 | 
			
		||||
namespace dsp {
 | 
			
		||||
namespace decimate {
 | 
			
		||||
 | 
			
		||||
class Complex8DecimateBy2CIC3 {
 | 
			
		||||
public:
 | 
			
		||||
	buffer_c16_t execute(
 | 
			
		||||
		const buffer_c8_t& src,
 | 
			
		||||
		const buffer_c16_t& dst
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	uint32_t _i1_i0 { 0 };
 | 
			
		||||
	uint32_t _q1_q0 { 0 };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class TranslateByFSOver4AndDecimateBy2CIC3 {
 | 
			
		||||
public:
 | 
			
		||||
	buffer_c16_t execute(
 | 
			
		||||
		const buffer_c8_t& src,
 | 
			
		||||
		const buffer_c16_t& dst
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	uint32_t _q1_i0 { 0 };
 | 
			
		||||
	uint32_t _q0_i1 { 0 };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class DecimateBy2CIC3 {
 | 
			
		||||
public:
 | 
			
		||||
	buffer_c16_t execute(
 | 
			
		||||
		const buffer_c16_t& src,
 | 
			
		||||
		const buffer_c16_t& dst
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	uint32_t _iq0 { 0 };
 | 
			
		||||
	uint32_t _iq1 { 0 };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class FIR64AndDecimateBy2Real {
 | 
			
		||||
public:
 | 
			
		||||
	static constexpr size_t taps_count = 64;
 | 
			
		||||
 | 
			
		||||
	void configure(
 | 
			
		||||
		const std::array<int16_t, taps_count>& taps
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	buffer_s16_t execute(
 | 
			
		||||
		const buffer_s16_t& src,
 | 
			
		||||
		const buffer_s16_t& dst
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	std::array<int16_t, taps_count + 2> z { };
 | 
			
		||||
	std::array<int16_t, taps_count> taps { };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class FIRC8xR16x24FS4Decim4 {
 | 
			
		||||
public:
 | 
			
		||||
	static constexpr size_t taps_count = 24;
 | 
			
		||||
	static constexpr size_t decimation_factor = 4;
 | 
			
		||||
 | 
			
		||||
	using sample_t = complex8_t;
 | 
			
		||||
	using tap_t = int16_t;
 | 
			
		||||
 | 
			
		||||
	enum class Shift : bool {
 | 
			
		||||
		Down = true,
 | 
			
		||||
		Up = false
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	void configure(
 | 
			
		||||
		const std::array<tap_t, taps_count>& taps,
 | 
			
		||||
		const int32_t scale,
 | 
			
		||||
		const Shift shift = Shift::Down
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	buffer_c16_t execute(
 | 
			
		||||
		const buffer_c8_t& src,
 | 
			
		||||
		const buffer_c16_t& dst
 | 
			
		||||
	);
 | 
			
		||||
	
 | 
			
		||||
private:
 | 
			
		||||
	std::array<vec2_s16, taps_count - decimation_factor> z_ { };
 | 
			
		||||
	std::array<tap_t, taps_count> taps_ { };
 | 
			
		||||
	int32_t output_scale = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class FIRC8xR16x24FS4Decim8 {
 | 
			
		||||
public:
 | 
			
		||||
	static constexpr size_t taps_count = 24;
 | 
			
		||||
	static constexpr size_t decimation_factor = 8;
 | 
			
		||||
 | 
			
		||||
	using sample_t = complex8_t;
 | 
			
		||||
	using tap_t = int16_t;
 | 
			
		||||
 | 
			
		||||
	enum class Shift : bool {
 | 
			
		||||
		Down = true,
 | 
			
		||||
		Up = false
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	void configure(
 | 
			
		||||
		const std::array<tap_t, taps_count>& taps,
 | 
			
		||||
		const int32_t scale,
 | 
			
		||||
		const Shift shift = Shift::Down
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	buffer_c16_t execute(
 | 
			
		||||
		const buffer_c8_t& src,
 | 
			
		||||
		const buffer_c16_t& dst
 | 
			
		||||
	);
 | 
			
		||||
	
 | 
			
		||||
private:
 | 
			
		||||
	std::array<vec2_s16, taps_count - decimation_factor> z_ { };
 | 
			
		||||
	std::array<tap_t, taps_count> taps_ { };
 | 
			
		||||
	int32_t output_scale = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class FIRC16xR16x16Decim2 {
 | 
			
		||||
public:
 | 
			
		||||
	static constexpr size_t taps_count = 16;
 | 
			
		||||
	static constexpr size_t decimation_factor = 2;
 | 
			
		||||
 | 
			
		||||
	using sample_t = complex16_t;
 | 
			
		||||
	using tap_t = int16_t;
 | 
			
		||||
 | 
			
		||||
	void configure(
 | 
			
		||||
		const std::array<tap_t, taps_count>& taps,
 | 
			
		||||
		const int32_t scale
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	buffer_c16_t execute(
 | 
			
		||||
		const buffer_c16_t& src,
 | 
			
		||||
		const buffer_c16_t& dst
 | 
			
		||||
	);
 | 
			
		||||
	
 | 
			
		||||
private:
 | 
			
		||||
	std::array<vec2_s16, taps_count - decimation_factor> z_ { };
 | 
			
		||||
	std::array<tap_t, taps_count> taps_ { };
 | 
			
		||||
	int32_t output_scale = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class FIRC16xR16x32Decim8 {
 | 
			
		||||
public:
 | 
			
		||||
	static constexpr size_t taps_count = 32;
 | 
			
		||||
	static constexpr size_t decimation_factor = 8;
 | 
			
		||||
 | 
			
		||||
	using sample_t = complex16_t;
 | 
			
		||||
	using tap_t = int16_t;
 | 
			
		||||
 | 
			
		||||
	void configure(
 | 
			
		||||
		const std::array<tap_t, taps_count>& taps,
 | 
			
		||||
		const int32_t scale
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	buffer_c16_t execute(
 | 
			
		||||
		const buffer_c16_t& src,
 | 
			
		||||
		const buffer_c16_t& dst
 | 
			
		||||
	);
 | 
			
		||||
	
 | 
			
		||||
private:
 | 
			
		||||
	std::array<vec2_s16, taps_count - decimation_factor> z_ { };
 | 
			
		||||
	std::array<tap_t, taps_count> taps_ { };
 | 
			
		||||
	int32_t output_scale = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class FIRAndDecimateComplex {
 | 
			
		||||
public:
 | 
			
		||||
	using sample_t = complex16_t;
 | 
			
		||||
	using tap_t = complex16_t;
 | 
			
		||||
 | 
			
		||||
	using taps_t = tap_t[];
 | 
			
		||||
 | 
			
		||||
	/* NOTE! Current code makes an assumption that block of samples to be
 | 
			
		||||
	 * processed will be a multiple of the taps_count.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	template<typename T>
 | 
			
		||||
	void configure(
 | 
			
		||||
		const T& taps,
 | 
			
		||||
		const size_t decimation_factor
 | 
			
		||||
	) {
 | 
			
		||||
		configure(taps.data(), taps.size(), decimation_factor);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	buffer_c16_t execute(
 | 
			
		||||
		const buffer_c16_t& src,
 | 
			
		||||
		const buffer_c16_t& dst
 | 
			
		||||
	);
 | 
			
		||||
	
 | 
			
		||||
private:
 | 
			
		||||
	using samples_t = sample_t[];
 | 
			
		||||
 | 
			
		||||
	std::unique_ptr<samples_t> samples_ { };
 | 
			
		||||
	std::unique_ptr<taps_t> taps_reversed_ { };
 | 
			
		||||
	size_t taps_count_ { 0 };
 | 
			
		||||
	size_t decimation_factor_ { 1 };
 | 
			
		||||
 | 
			
		||||
	template<typename T>
 | 
			
		||||
	void configure(
 | 
			
		||||
		const T* const taps,
 | 
			
		||||
		const size_t taps_count,
 | 
			
		||||
		const size_t decimation_factor
 | 
			
		||||
	) {
 | 
			
		||||
		configure_common(taps_count, decimation_factor);
 | 
			
		||||
		std::reverse_copy(&taps[0], &taps[taps_count], &taps_reversed_[0]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void configure_common(
 | 
			
		||||
		const size_t taps_count,
 | 
			
		||||
		const size_t decimation_factor
 | 
			
		||||
	);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class DecimateBy2CIC4Real {
 | 
			
		||||
public:
 | 
			
		||||
	buffer_s16_t execute(
 | 
			
		||||
		const buffer_s16_t& src,
 | 
			
		||||
		const buffer_s16_t& dst
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	int16_t z[5] { };
 | 
			
		||||
	int16_t _dummy { };	// TODO: Addresses GCC bug when constructing a class that's not sizeof() % 4 == 0?
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace decimate */
 | 
			
		||||
} /* namespace dsp */
 | 
			
		||||
 | 
			
		||||
#endif/*__DSP_DECIMATE_H__*/
 | 
			
		||||
							
								
								
									
										151
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_demodulate.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_demodulate.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,151 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dsp_demodulate.hpp"
 | 
			
		||||
 | 
			
		||||
#include "complex.hpp"
 | 
			
		||||
#include "fxpt_atan2.hpp"
 | 
			
		||||
#include "utility_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include <hal.h>
 | 
			
		||||
 | 
			
		||||
namespace dsp {
 | 
			
		||||
namespace demodulate {
 | 
			
		||||
 | 
			
		||||
buffer_f32_t AM::execute(
 | 
			
		||||
	const buffer_c16_t& src,
 | 
			
		||||
	const buffer_f32_t& dst
 | 
			
		||||
) {
 | 
			
		||||
	const void* src_p = src.p;
 | 
			
		||||
	const auto src_end = &src.p[src.count];
 | 
			
		||||
	auto dst_p = dst.p;
 | 
			
		||||
	while(src_p < src_end) {
 | 
			
		||||
		const uint32_t sample0 = *__SIMD32(src_p)++;
 | 
			
		||||
		const uint32_t sample1 = *__SIMD32(src_p)++;
 | 
			
		||||
		const uint32_t mag_sq0 = __SMUAD(sample0, sample0);
 | 
			
		||||
		const uint32_t mag_sq1 = __SMUAD(sample1, sample1);
 | 
			
		||||
		*(dst_p++) = __builtin_sqrtf(mag_sq0) * k;
 | 
			
		||||
		*(dst_p++) = __builtin_sqrtf(mag_sq1) * k;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return { dst.p, src.count, src.sampling_rate };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_f32_t SSB::execute(
 | 
			
		||||
	const buffer_c16_t& src,
 | 
			
		||||
	const buffer_f32_t& dst
 | 
			
		||||
) {
 | 
			
		||||
	const complex16_t* src_p = src.p;
 | 
			
		||||
	const auto src_end = &src.p[src.count];
 | 
			
		||||
	auto dst_p = dst.p;
 | 
			
		||||
	while(src_p < src_end) {
 | 
			
		||||
		*(dst_p++) = (src_p++)->real() * k;
 | 
			
		||||
		*(dst_p++) = (src_p++)->real() * k;
 | 
			
		||||
		*(dst_p++) = (src_p++)->real() * k;
 | 
			
		||||
		*(dst_p++) = (src_p++)->real() * k;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return { dst.p, src.count, src.sampling_rate };
 | 
			
		||||
}
 | 
			
		||||
/*
 | 
			
		||||
static inline float angle_approx_4deg0(const complex32_t t) {
 | 
			
		||||
	const auto x = static_cast<float>(t.imag()) / static_cast<float>(t.real());
 | 
			
		||||
	return 16384.0f * x;
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
static inline float angle_approx_0deg27(const complex32_t t) {
 | 
			
		||||
	if( t.real() ) {
 | 
			
		||||
		const auto x = static_cast<float>(t.imag()) / static_cast<float>(t.real());
 | 
			
		||||
		return x / (1.0f + 0.28086f * x * x);
 | 
			
		||||
	} else {
 | 
			
		||||
		return (t.imag() < 0) ? -1.5707963268f : 1.5707963268f;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline float angle_precise(const complex32_t t) {
 | 
			
		||||
	return atan2f(t.imag(), t.real());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_f32_t FM::execute(
 | 
			
		||||
	const buffer_c16_t& src,
 | 
			
		||||
	const buffer_f32_t& dst
 | 
			
		||||
) {
 | 
			
		||||
	auto z = z_;
 | 
			
		||||
 | 
			
		||||
	const void* src_p = src.p;
 | 
			
		||||
	const auto src_end = &src.p[src.count];
 | 
			
		||||
	auto dst_p = dst.p;
 | 
			
		||||
	while(src_p < src_end) {
 | 
			
		||||
		const auto s0 = *__SIMD32(src_p)++;
 | 
			
		||||
		const auto s1 = *__SIMD32(src_p)++;
 | 
			
		||||
		const auto t0 = multiply_conjugate_s16_s32(s0, z);
 | 
			
		||||
		const auto t1 = multiply_conjugate_s16_s32(s1, s0);
 | 
			
		||||
		z = s1;
 | 
			
		||||
		*(dst_p++) = angle_precise(t0) * kf;
 | 
			
		||||
		*(dst_p++) = angle_precise(t1) * kf;
 | 
			
		||||
	}
 | 
			
		||||
	z_ = z;
 | 
			
		||||
 | 
			
		||||
	return { dst.p, src.count, src.sampling_rate };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_s16_t FM::execute(
 | 
			
		||||
	const buffer_c16_t& src,
 | 
			
		||||
	const buffer_s16_t& dst
 | 
			
		||||
) {
 | 
			
		||||
	auto z = z_;
 | 
			
		||||
 | 
			
		||||
	const void* src_p = src.p;
 | 
			
		||||
	const auto src_end = &src.p[src.count];
 | 
			
		||||
	void* dst_p = dst.p;
 | 
			
		||||
	while(src_p < src_end) {
 | 
			
		||||
		const auto s0 = *__SIMD32(src_p)++;
 | 
			
		||||
		const auto s1 = *__SIMD32(src_p)++;
 | 
			
		||||
		const auto t0 = multiply_conjugate_s16_s32(s0, z);
 | 
			
		||||
		const auto t1 = multiply_conjugate_s16_s32(s1, s0);
 | 
			
		||||
		z = s1;
 | 
			
		||||
		const int32_t theta0_int = angle_approx_0deg27(t0) * ks16;
 | 
			
		||||
		const int32_t theta0_sat = __SSAT(theta0_int, 16);
 | 
			
		||||
		const int32_t theta1_int = angle_approx_0deg27(t1) * ks16;
 | 
			
		||||
		const int32_t theta1_sat = __SSAT(theta1_int, 16);
 | 
			
		||||
		*__SIMD32(dst_p)++ = __PKHBT(
 | 
			
		||||
			theta0_sat,
 | 
			
		||||
			theta1_sat,
 | 
			
		||||
			16
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
	z_ = z;
 | 
			
		||||
 | 
			
		||||
	return { dst.p, src.count, src.sampling_rate };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FM::configure(const float sampling_rate, const float deviation_hz) {
 | 
			
		||||
	/*
 | 
			
		||||
	 * angle: -pi to pi. output range: -32768 to 32767.
 | 
			
		||||
	 * Maximum delta-theta (output of atan2) at maximum deviation frequency:
 | 
			
		||||
	 * delta_theta_max = 2 * pi * deviation / sampling_rate
 | 
			
		||||
	 */
 | 
			
		||||
	kf = static_cast<float>(1.0f / (2.0 * pi * deviation_hz / sampling_rate));
 | 
			
		||||
	ks16 = 32767.0f * kf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,75 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DSP_DEMODULATE_H__
 | 
			
		||||
#define __DSP_DEMODULATE_H__
 | 
			
		||||
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
 | 
			
		||||
namespace dsp {
 | 
			
		||||
namespace demodulate {
 | 
			
		||||
 | 
			
		||||
class AM {
 | 
			
		||||
public:
 | 
			
		||||
	buffer_f32_t execute(
 | 
			
		||||
		const buffer_c16_t& src,
 | 
			
		||||
		const buffer_f32_t& dst
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr float k = 1.0f / 32768.0f;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SSB {
 | 
			
		||||
public:
 | 
			
		||||
	buffer_f32_t execute(
 | 
			
		||||
		const buffer_c16_t& src,
 | 
			
		||||
		const buffer_f32_t& dst
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr float k = 1.0f / 32768.0f;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class FM {
 | 
			
		||||
public:
 | 
			
		||||
	buffer_f32_t execute(
 | 
			
		||||
		const buffer_c16_t& src,
 | 
			
		||||
		const buffer_f32_t& dst
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	buffer_s16_t execute(
 | 
			
		||||
		const buffer_c16_t& src,
 | 
			
		||||
		const buffer_s16_t& dst
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	void configure(const float sampling_rate, const float deviation_hz);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	complex16_t::rep_type z_ { 0 };
 | 
			
		||||
	float kf { 0 };
 | 
			
		||||
	float ks16 { 0 };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace demodulate */
 | 
			
		||||
} /* namespace dsp */
 | 
			
		||||
 | 
			
		||||
#endif/*__DSP_DEMODULATE_H__*/
 | 
			
		||||
							
								
								
									
										56
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_goertzel.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_goertzel.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2018 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dsp_goertzel.hpp"
 | 
			
		||||
 | 
			
		||||
#include "complex.hpp"
 | 
			
		||||
#include "sine_table.hpp"
 | 
			
		||||
 | 
			
		||||
namespace dsp {
 | 
			
		||||
 | 
			
		||||
GoertzelDetector::GoertzelDetector(
 | 
			
		||||
	const float frequency,
 | 
			
		||||
	const uint32_t sample_rate
 | 
			
		||||
) {
 | 
			
		||||
	coefficient = 2.0 * sin_f32((2.0 * pi * frequency / sample_rate) - pi / 2.0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float GoertzelDetector::execute(
 | 
			
		||||
	const buffer_s16_t& src
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
	const size_t count = src.count;
 | 
			
		||||
	
 | 
			
		||||
	for (size_t i = 0; i < count; i++) {
 | 
			
		||||
		s[2] = s[1];
 | 
			
		||||
		s[1] = s[0];
 | 
			
		||||
		s[0] = src.p[i] + coefficient * s[1] - s[2];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const uint32_t sq0 = s[0] * s[0];
 | 
			
		||||
	const uint32_t sq1 = s[1] * s[1];
 | 
			
		||||
	float magnitude = __builtin_sqrtf(sq0 + sq1 - s[0] * s[1] * coefficient);
 | 
			
		||||
 | 
			
		||||
	return magnitude;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace dsp */
 | 
			
		||||
							
								
								
									
										43
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_goertzel.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_goertzel.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2018 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DSP_GOERTZEL_H__
 | 
			
		||||
#define __DSP_GOERTZEL_H__
 | 
			
		||||
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
 | 
			
		||||
namespace dsp {
 | 
			
		||||
 | 
			
		||||
class GoertzelDetector {
 | 
			
		||||
public:
 | 
			
		||||
	GoertzelDetector(const float frequency, const uint32_t sample_rate);
 | 
			
		||||
	
 | 
			
		||||
	float execute(const buffer_s16_t& src);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	float coefficient { };
 | 
			
		||||
	int16_t s[2] { 0 };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace dsp */
 | 
			
		||||
 | 
			
		||||
#endif/*__DSP_GOERTZEL_H__*/
 | 
			
		||||
							
								
								
									
										57
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_hilbert.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_hilbert.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2020 Belousov Oleg
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dsp_hilbert.hpp"
 | 
			
		||||
#include "dsp_sos_config.hpp"
 | 
			
		||||
 | 
			
		||||
namespace dsp {
 | 
			
		||||
 | 
			
		||||
HilbertTransform::HilbertTransform() {
 | 
			
		||||
	n = 0;
 | 
			
		||||
 | 
			
		||||
	sos_i.configure(half_band_lpf_config);
 | 
			
		||||
	sos_q.configure(half_band_lpf_config);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HilbertTransform::execute(float in, float &out_i, float &out_q) {
 | 
			
		||||
	float a = 0, b = 0;
 | 
			
		||||
	
 | 
			
		||||
	switch (n) {
 | 
			
		||||
		case 0:		a = in;		b = 0;		break;
 | 
			
		||||
		case 1:		a = 0;		b = -in;	break;
 | 
			
		||||
		case 2:		a = -in;	b = 0;		break;
 | 
			
		||||
		case 3:		a = 0;		b = in;		break;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	float i = sos_i.execute(a) * 2.0f;
 | 
			
		||||
	float q = sos_q.execute(b) * 2.0f;
 | 
			
		||||
	
 | 
			
		||||
	switch (n) {
 | 
			
		||||
		case 0:		out_i = i;	out_q = q;	break;
 | 
			
		||||
		case 1:		out_i = -q;	out_q = i;	break;
 | 
			
		||||
		case 2:		out_i = -i;	out_q = -q;	break;
 | 
			
		||||
		case 3:		out_i = q;	out_q = -i;	break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	n = (n + 1) % 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace dsp */
 | 
			
		||||
							
								
								
									
										44
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_hilbert.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_hilbert.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2020 Belousov Oleg
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DSP_HILBERT_H__
 | 
			
		||||
#define __DSP_HILBERT_H__
 | 
			
		||||
 | 
			
		||||
#include "dsp_sos.hpp"
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
 | 
			
		||||
namespace dsp {
 | 
			
		||||
 | 
			
		||||
class HilbertTransform {
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
	HilbertTransform();
 | 
			
		||||
	void execute(float in, float &out_i, float &out_q);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	uint8_t			n = 0;
 | 
			
		||||
	SOSFilter<5>	sos_i = {};
 | 
			
		||||
	SOSFilter<5>	sos_q = {};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace dsp */
 | 
			
		||||
 | 
			
		||||
#endif/*__DSP_HILBERT_H__*/
 | 
			
		||||
							
								
								
									
										225
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_modulate.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_modulate.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,225 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2020 Belousov Oleg
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dsp_modulate.hpp"
 | 
			
		||||
#include "sine_table_int8.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
#include "tonesets.hpp"
 | 
			
		||||
 | 
			
		||||
namespace dsp {
 | 
			
		||||
namespace modulate {
 | 
			
		||||
 | 
			
		||||
Modulator::~Modulator() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Mode Modulator::get_mode() {
 | 
			
		||||
	return mode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Modulator::set_mode(Mode new_mode) {
 | 
			
		||||
	mode = new_mode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Modulator::set_over(uint32_t new_over) {
 | 
			
		||||
    over = new_over;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Modulator::set_gain_vumeter_beep(float new_audio_gain , bool new_play_beep ) {
 | 
			
		||||
      audio_gain = new_audio_gain ;    
 | 
			
		||||
	  play_beep = new_play_beep; 
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t Modulator::apply_beep(int32_t sample_in, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message ) {
 | 
			
		||||
 | 
			
		||||
	if (play_beep) {	   		// We need to add audio beep sample.
 | 
			
		||||
			if (new_beep_timer) {
 | 
			
		||||
				new_beep_timer--;
 | 
			
		||||
			} else {
 | 
			
		||||
				new_beep_timer = baseband_fs * 0.05;			// 50ms
 | 
			
		||||
				
 | 
			
		||||
				if (new_beep_index == BEEP_TONES_NB) {
 | 
			
		||||
					configured_in = false;
 | 
			
		||||
					shared_memory.application_queue.push(new_txprogress_message);
 | 
			
		||||
				} else {
 | 
			
		||||
					beep_gen.configure(beep_deltas[new_beep_index], 1.0); // config sequentially the audio beep tone.
 | 
			
		||||
					new_beep_index++;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		    sample_in = beep_gen.process(0);    // Get sample of the selected sequence of 6  beep tones , and overwrite audio sample. Mix 0%.
 | 
			
		||||
		}
 | 
			
		||||
	return sample_in;    // Return audio mic scaled with gain , 8 bit sample or audio beep sample.		
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
SSB::SSB() : hilbert() {
 | 
			
		||||
	mode = Mode::LSB;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SSB::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in,  uint32_t& new_beep_index, uint32_t& new_beep_timer,TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message,  uint32_t& new_power_acc_count, uint32_t& new_divider ) {
 | 
			
		||||
	// No way to activate correctly  the roger beep in this option, Maybe not enough M4 CPU power , Let's  block roger beep in SSB  selection by now . 
 | 
			
		||||
	int32_t		sample = 0;
 | 
			
		||||
	int8_t		re = 0, im = 0;
 | 
			
		||||
	
 | 
			
		||||
	for (size_t counter = 0; counter < buffer.count; counter++) {
 | 
			
		||||
		if (counter % 128 == 0) {
 | 
			
		||||
			float	i = 0.0, q = 0.0;
 | 
			
		||||
 | 
			
		||||
		    sample = audio.p[counter / over] >> 2;
 | 
			
		||||
			sample *= audio_gain;      //  Apply GAIN  Scale factor to the audio TX modulation.
 | 
			
		||||
	
 | 
			
		||||
				//switch (mode) {
 | 
			
		||||
				//case Mode::LSB:	
 | 
			
		||||
			hilbert.execute(sample / 32768.0f, i, q);
 | 
			
		||||
				//case Mode::USB:	hilbert.execute(sample / 32768.0f, q, i);
 | 
			
		||||
				//default:	break;
 | 
			
		||||
			//}
 | 
			
		||||
 | 
			
		||||
			i *= 256.0f;   // Original 64.0f,  now x 4 (+12 dB's SSB BB modulation)	
 | 
			
		||||
			q *= 256.0f;   // Original 64.0f,  now x 4 (+12 dB's SSB BB modulation)	
 | 
			
		||||
			switch (mode) {
 | 
			
		||||
				case Mode::LSB:	re = q;	im = i;	break;
 | 
			
		||||
				case Mode::USB:	re = i;	im = q;	break;
 | 
			
		||||
				default:	re = 0; im = 0;	break;
 | 
			
		||||
			}
 | 
			
		||||
			//re = q;
 | 
			
		||||
			//im = i;
 | 
			
		||||
			//break;
 | 
			
		||||
				
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		buffer.p[counter] = { re, im };
 | 
			
		||||
		
 | 
			
		||||
		// Update vu-meter bar in the LCD screen.
 | 
			
		||||
	    	power_acc += (sample < 0) ? -sample : sample;	// Power average for UI vu-meter
 | 
			
		||||
	
 | 
			
		||||
			if (new_power_acc_count) {
 | 
			
		||||
				new_power_acc_count--;
 | 
			
		||||
			} else {				// power_acc_count = 0
 | 
			
		||||
				new_power_acc_count = new_divider;
 | 
			
		||||
				new_level_message.value = power_acc / (new_divider *8);	// Why ?  . This division is to adj vu-meter sentitivity, to match saturation point to red-muter .
 | 
			
		||||
				shared_memory.application_queue.push(new_level_message);
 | 
			
		||||
				power_acc = 0;
 | 
			
		||||
			}	
 | 
			
		||||
	
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
FM::FM() {
 | 
			
		||||
	mode = Mode::FM;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FM::set_fm_delta(uint32_t new_delta) {
 | 
			
		||||
	fm_delta = new_delta;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FM::set_tone_gen_configure(const uint32_t set_delta, const float set_tone_mix_weight) {
 | 
			
		||||
	 tone_gen.configure(set_delta, set_tone_mix_weight);
 | 
			
		||||
}	
 | 
			
		||||
 | 
			
		||||
void FM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider  ) {
 | 
			
		||||
	int32_t		sample = 0;
 | 
			
		||||
	int8_t		re, im;
 | 
			
		||||
 | 
			
		||||
	for (size_t counter = 0; counter < buffer.count; counter++) {
 | 
			
		||||
	 
 | 
			
		||||
	    sample = audio.p[counter>>6] >> 8;			// 	sample = audio.p[counter / over] >> 8;   (not enough efficient running code, over = 1536000/240000= 64 )
 | 
			
		||||
		sample *= audio_gain;      					// Apply GAIN  Scale factor to the audio TX modulation.
 | 
			
		||||
 | 
			
		||||
		if (play_beep) {
 | 
			
		||||
			sample = apply_beep(sample, configured_in, new_beep_index, new_beep_timer, new_txprogress_message ); 	// Apply beep -if selected - atom ,sample by sample.
 | 
			
		||||
		} else {
 | 
			
		||||
			// Update vu-meter bar in the LCD screen.
 | 
			
		||||
	    	power_acc += (sample < 0) ? -sample : sample;	// Power average for UI vu-meter
 | 
			
		||||
	
 | 
			
		||||
			if (new_power_acc_count) {
 | 
			
		||||
				new_power_acc_count--;
 | 
			
		||||
			} else {				// power_acc_count = 0
 | 
			
		||||
				new_power_acc_count = new_divider;
 | 
			
		||||
				new_level_message.value = power_acc / (new_divider / 4);	// Why ?  . This division is to adj vu-meter sentitivity, to match saturation point to red-muter .
 | 
			
		||||
				shared_memory.application_queue.push(new_level_message);
 | 
			
		||||
				power_acc = 0;
 | 
			
		||||
			}	
 | 
			
		||||
			// TODO: pending to optimize CPU running code. 
 | 
			
		||||
			// So far , we can not handle all 3 issues at the same time (vu-meter , CTCSS, beep).
 | 
			
		||||
			sample = tone_gen.process(sample);			// Add selected Key_Tone or CTCSS subtone , atom function() , sample by sample.
 | 
			
		||||
		}	
 | 
			
		||||
  
 | 
			
		||||
	    delta = sample * fm_delta;						// Modulate FM
 | 
			
		||||
 | 
			
		||||
		phase += delta;
 | 
			
		||||
		sphase = phase >> 24;
 | 
			
		||||
 | 
			
		||||
		re = (sine_table_i8[(sphase + 64) & 255]);
 | 
			
		||||
		im = (sine_table_i8[sphase]);
 | 
			
		||||
		
 | 
			
		||||
		buffer.p[counter] = { re, im };
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AM::AM() {
 | 
			
		||||
	mode = Mode::AM;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider ) {
 | 
			
		||||
	int32_t         sample = 0;
 | 
			
		||||
	int8_t          re = 0, im = 0;
 | 
			
		||||
	float			q = 0.0;
 | 
			
		||||
	
 | 
			
		||||
	for (size_t counter = 0; counter < buffer.count; counter++) {
 | 
			
		||||
		if (counter % 128 == 0) {
 | 
			
		||||
			sample = audio.p[counter / over] >> 2;
 | 
			
		||||
			sample *= audio_gain;      					 // Apply GAIN  Scale factor to the audio TX modulation.
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (play_beep) {
 | 
			
		||||
			sample = apply_beep(sample, configured_in, new_beep_index, new_beep_timer, new_txprogress_message )<<5; 	// Apply beep -if selected - atom sample by sample.
 | 
			
		||||
		} else {
 | 
			
		||||
			// Update vu-meter bar in the LCD screen.
 | 
			
		||||
	    	power_acc += (sample < 0) ? -sample : sample;	// Power average for UI vu-meter
 | 
			
		||||
	
 | 
			
		||||
			if (new_power_acc_count) {
 | 
			
		||||
				new_power_acc_count--;
 | 
			
		||||
			} else {				// power_acc_count = 0
 | 
			
		||||
				new_power_acc_count = new_divider;
 | 
			
		||||
				new_level_message.value = power_acc / (new_divider *8);	// Why ?orig / (new_divider / 4);	// Why ?
 | 
			
		||||
				shared_memory.application_queue.push(new_level_message);
 | 
			
		||||
				power_acc = 0;
 | 
			
		||||
			}	
 | 
			
		||||
		}	
 | 
			
		||||
 | 
			
		||||
		q = sample / 32768.0f;
 | 
			
		||||
		q *= 256.0f;										 // Original 64.0f,now x4 (+12 dB's BB_modulation in AM & DSB)	
 | 
			
		||||
		switch (mode) {
 | 
			
		||||
			case Mode::AM:	re = q + 80; im = q + 80; break; // Original DC add +20_DC_level=carrier,now x4 (+12dB's AM carrier)
 | 
			
		||||
			case Mode::DSB:	re = q; im = q; break;
 | 
			
		||||
			default:	break;
 | 
			
		||||
		}
 | 
			
		||||
		buffer.p[counter] = { re, im };
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										117
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_modulate.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_modulate.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,117 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2020 Belousov Oleg
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DSP_MODULATE_H__
 | 
			
		||||
#define __DSP_MODULATE_H__
 | 
			
		||||
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
#include "dsp_hilbert.hpp"
 | 
			
		||||
#include "tone_gen.hpp"
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
 | 
			
		||||
namespace dsp {
 | 
			
		||||
namespace modulate {
 | 
			
		||||
 | 
			
		||||
enum class Mode {
 | 
			
		||||
	None,
 | 
			
		||||
	AM,
 | 
			
		||||
	DSB,
 | 
			
		||||
	LSB,
 | 
			
		||||
	USB,
 | 
			
		||||
	FM
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
class Modulator {
 | 
			
		||||
public:
 | 
			
		||||
	virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer,bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider   ) = 0;
 | 
			
		||||
	virtual ~Modulator();
 | 
			
		||||
 | 
			
		||||
	Mode get_mode();
 | 
			
		||||
	void set_mode(Mode new_mode);
 | 
			
		||||
 | 
			
		||||
    void set_over(uint32_t new_over);
 | 
			
		||||
	void set_gain_vumeter_beep(float new_audio_gain , bool new_play_beep );
 | 
			
		||||
	int32_t apply_beep(int32_t sample_in, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message );
 | 
			
		||||
	float audio_gain { };
 | 
			
		||||
	bool play_beep { false };
 | 
			
		||||
	uint32_t power_acc_count { 0 };		// this var it is initialized from Proc_mictx.cpp
 | 
			
		||||
	uint32_t divider { };				// this var it is initialized from Proc_mictx.cpp
 | 
			
		||||
    uint64_t power_acc { 0 };	// it is aux Accumulated sum (Absolute sample signal) , initialitzed to zero. 
 | 
			
		||||
	AudioLevelReportMessage level_message { };	
 | 
			
		||||
 | 
			
		||||
private: 
 | 
			
		||||
	static constexpr size_t baseband_fs = 1536000U;
 | 
			
		||||
	TXProgressMessage txprogress_message { };
 | 
			
		||||
   	ToneGen  beep_gen { };
 | 
			
		||||
	uint32_t beep_index { }, beep_timer { };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    uint32_t    over = 1;
 | 
			
		||||
	Mode	    mode = Mode::None;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
class SSB : public Modulator {
 | 
			
		||||
public:
 | 
			
		||||
	SSB();
 | 
			
		||||
 | 
			
		||||
	virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider  );
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	dsp::HilbertTransform	hilbert;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
class FM : public Modulator {
 | 
			
		||||
public:
 | 
			
		||||
	FM();
 | 
			
		||||
 | 
			
		||||
	virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in,  uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider  ) ;
 | 
			
		||||
	void set_fm_delta(uint32_t new_delta);
 | 
			
		||||
	void set_tone_gen_configure(const uint32_t delta, const float tone_mix_weight); 
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	uint32_t	fm_delta { 0 };
 | 
			
		||||
	uint32_t	phase { 0 }, sphase { 0 };
 | 
			
		||||
	int32_t		sample { 0 }, delta { };
 | 
			
		||||
	ToneGen 	tone_gen { };
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class AM : public Modulator {
 | 
			
		||||
public:
 | 
			
		||||
        AM();
 | 
			
		||||
 | 
			
		||||
        virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace modulate */
 | 
			
		||||
} /* namespace dsp */
 | 
			
		||||
 | 
			
		||||
#endif/*__DSP_MODULATE_H__*/
 | 
			
		||||
							
								
								
									
										53
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_squelch.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_squelch.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dsp_squelch.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
bool FMSquelch::execute(const buffer_f32_t& audio) {
 | 
			
		||||
	if( threshold_squared == 0.0f ) {
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: No hard-coded array size.
 | 
			
		||||
	std::array<float, N> squelch_energy_buffer;
 | 
			
		||||
	const buffer_f32_t squelch_energy {
 | 
			
		||||
		squelch_energy_buffer.data(),
 | 
			
		||||
		squelch_energy_buffer.size()
 | 
			
		||||
	};
 | 
			
		||||
	non_audio_hpf.execute(audio, squelch_energy);
 | 
			
		||||
 | 
			
		||||
	float non_audio_max_squared = 0;
 | 
			
		||||
	for(const auto sample : squelch_energy_buffer) {
 | 
			
		||||
		const float sample_squared = sample * sample;
 | 
			
		||||
		if( sample_squared > non_audio_max_squared ) {
 | 
			
		||||
			non_audio_max_squared = sample_squared;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (non_audio_max_squared < threshold_squared);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FMSquelch::set_threshold(const float new_value) {
 | 
			
		||||
	threshold_squared = new_value * new_value;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_squelch.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								Software/portapack-mayhem/firmware/baseband/dsp_squelch.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DSP_SQUELCH_H__
 | 
			
		||||
#define __DSP_SQUELCH_H__
 | 
			
		||||
 | 
			
		||||
#include "buffer.hpp"
 | 
			
		||||
#include "dsp_iir.hpp"
 | 
			
		||||
#include "dsp_iir_config.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
class FMSquelch {
 | 
			
		||||
public:
 | 
			
		||||
	bool execute(const buffer_f32_t& audio);
 | 
			
		||||
 | 
			
		||||
	void set_threshold(const float new_value);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr size_t N = 32;
 | 
			
		||||
	float threshold_squared { 0.0f };
 | 
			
		||||
 | 
			
		||||
	IIRBiquadFilter non_audio_hpf { non_audio_hpf_config };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__DSP_SQUELCH_H__*/
 | 
			
		||||
							
								
								
									
										122
									
								
								Software/portapack-mayhem/firmware/baseband/event_m4.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								Software/portapack-mayhem/firmware/baseband/event_m4.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,122 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
 | 
			
		||||
#include "message_queue.hpp"
 | 
			
		||||
 | 
			
		||||
#include "ch.h"
 | 
			
		||||
 | 
			
		||||
#include "lpc43xx_cpp.hpp"
 | 
			
		||||
using namespace lpc43xx;
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
 | 
			
		||||
CH_IRQ_HANDLER(MAPP_IRQHandler) {
 | 
			
		||||
	CH_IRQ_PROLOGUE();
 | 
			
		||||
 | 
			
		||||
	chSysLockFromIsr();
 | 
			
		||||
	EventDispatcher::events_flag_isr(EVT_MASK_BASEBAND);
 | 
			
		||||
	chSysUnlockFromIsr();
 | 
			
		||||
 | 
			
		||||
	creg::m0apptxevent::clear();
 | 
			
		||||
 | 
			
		||||
	CH_IRQ_EPILOGUE();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Thread* EventDispatcher::thread_event_loop = nullptr;
 | 
			
		||||
 | 
			
		||||
EventDispatcher::EventDispatcher(
 | 
			
		||||
	std::unique_ptr<BasebandProcessor> baseband_processor
 | 
			
		||||
) : baseband_processor { std::move(baseband_processor) }
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EventDispatcher::run() {
 | 
			
		||||
	thread_event_loop = chThdSelf();
 | 
			
		||||
 | 
			
		||||
	lpc43xx::creg::m0apptxevent::enable();
 | 
			
		||||
 | 
			
		||||
	while(is_running) {
 | 
			
		||||
		const auto events = wait();
 | 
			
		||||
		dispatch(events);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lpc43xx::creg::m0apptxevent::disable();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EventDispatcher::request_stop() {
 | 
			
		||||
	is_running = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
eventmask_t EventDispatcher::wait() {
 | 
			
		||||
	return chEvtWaitAny(ALL_EVENTS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EventDispatcher::dispatch(const eventmask_t events) {
 | 
			
		||||
	if( events & EVT_MASK_BASEBAND ) {
 | 
			
		||||
		handle_baseband_queue();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if( events & EVT_MASK_SPECTRUM ) {
 | 
			
		||||
		handle_spectrum();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EventDispatcher::handle_baseband_queue() {
 | 
			
		||||
	const auto message = shared_memory.baseband_message;
 | 
			
		||||
	if( message ) {
 | 
			
		||||
		on_message(message);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EventDispatcher::on_message(const Message* const message) {
 | 
			
		||||
	switch(message->id) {
 | 
			
		||||
	case Message::ID::Shutdown:
 | 
			
		||||
		on_message_shutdown(*reinterpret_cast<const ShutdownMessage*>(message));
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		on_message_default(message);
 | 
			
		||||
		shared_memory.baseband_message = nullptr;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EventDispatcher::on_message_shutdown(const ShutdownMessage&) {
 | 
			
		||||
	request_stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EventDispatcher::on_message_default(const Message* const message) {
 | 
			
		||||
	baseband_processor->on_message(message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EventDispatcher::handle_spectrum() {
 | 
			
		||||
	const UpdateSpectrumMessage message;
 | 
			
		||||
	baseband_processor->on_message(&message);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										72
									
								
								Software/portapack-mayhem/firmware/baseband/event_m4.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								Software/portapack-mayhem/firmware/baseband/event_m4.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __EVENT_M4_H__
 | 
			
		||||
#define __EVENT_M4_H__
 | 
			
		||||
 | 
			
		||||
#include "event.hpp"
 | 
			
		||||
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "rssi_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
 | 
			
		||||
#include "ch.h"
 | 
			
		||||
 | 
			
		||||
constexpr auto EVT_MASK_BASEBAND = EVENT_MASK(0);
 | 
			
		||||
constexpr auto EVT_MASK_SPECTRUM = EVENT_MASK(1);
 | 
			
		||||
 | 
			
		||||
class EventDispatcher {
 | 
			
		||||
public:
 | 
			
		||||
	EventDispatcher(std::unique_ptr<BasebandProcessor> baseband_processor);
 | 
			
		||||
 | 
			
		||||
	void run();
 | 
			
		||||
	void request_stop();
 | 
			
		||||
 | 
			
		||||
	static inline void events_flag(const eventmask_t events) {
 | 
			
		||||
		chEvtSignal(thread_event_loop, events);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static inline void events_flag_isr(const eventmask_t events) {
 | 
			
		||||
		chEvtSignalI(thread_event_loop, events);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static Thread* thread_event_loop;
 | 
			
		||||
 | 
			
		||||
	std::unique_ptr<BasebandProcessor> baseband_processor;
 | 
			
		||||
 | 
			
		||||
	bool is_running = true;
 | 
			
		||||
 | 
			
		||||
	eventmask_t wait();
 | 
			
		||||
 | 
			
		||||
	void dispatch(const eventmask_t events);
 | 
			
		||||
 | 
			
		||||
	void handle_baseband_queue();
 | 
			
		||||
 | 
			
		||||
	void on_message(const Message* const message);
 | 
			
		||||
	void on_message_shutdown(const ShutdownMessage&);
 | 
			
		||||
	void on_message_default(const Message* const message);
 | 
			
		||||
 | 
			
		||||
	void handle_spectrum();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__EVENT_M4_H__*/
 | 
			
		||||
							
								
								
									
										152
									
								
								Software/portapack-mayhem/firmware/baseband/fxpt_atan2.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								Software/portapack-mayhem/firmware/baseband/fxpt_atan2.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,152 @@
 | 
			
		||||
/*
 | 
			
		||||
 * fxpt_atan2.c
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2012, Xo Wang
 | 
			
		||||
 *
 | 
			
		||||
 * Hacked up to be a bit more ARM-friendly by:
 | 
			
		||||
 * Copyright (C) 2013 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 | 
			
		||||
 * this software and associated documentation files (the "Software"), to deal in
 | 
			
		||||
 * the Software without restriction, including without limitation the rights to
 | 
			
		||||
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 | 
			
		||||
 * of the Software, and to permit persons to whom the Software is furnished to do
 | 
			
		||||
 * so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Convert floating point to Q15 (1.0.15 fixed point) format.
 | 
			
		||||
 *
 | 
			
		||||
 * @param d floating-point value within range -1 to (1 - (2**-15)), inclusive
 | 
			
		||||
 * @return Q15 value representing d; same range
 | 
			
		||||
 */
 | 
			
		||||
/*
 | 
			
		||||
static inline int16_t q15_from_double(const double d) {
 | 
			
		||||
	return lrint(d * 32768);
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
/**
 | 
			
		||||
 * Negative absolute value. Used to avoid undefined behavior for most negative
 | 
			
		||||
 * integer (see C99 standard 7.20.6.1.2 and footnote 265 for the description of
 | 
			
		||||
 * abs/labs/llabs behavior).
 | 
			
		||||
 *
 | 
			
		||||
 * @param i 16-bit signed integer
 | 
			
		||||
 * @return negative absolute value of i; defined for all values of i
 | 
			
		||||
 */
 | 
			
		||||
 /*
 | 
			
		||||
static inline int16_t s16_nabs(const int16_t j) {
 | 
			
		||||
#if (((int16_t)-1) >> 1) == ((int16_t)-1)
 | 
			
		||||
	// signed right shift sign-extends (arithmetic)
 | 
			
		||||
	const int16_t negSign = ~(j >> 15); // splat sign bit into all 16 and complement
 | 
			
		||||
	// if j is positive (negSign is -1), xor will invert j and sub will add 1
 | 
			
		||||
	// otherwise j is unchanged
 | 
			
		||||
	return (j ^ negSign) - negSign;
 | 
			
		||||
#else
 | 
			
		||||
	return (j < 0 ? j : -j);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
/**
 | 
			
		||||
 * Q15 (1.0.15 fixed point) multiplication. Various common rounding modes are in
 | 
			
		||||
 * the function definition for reference (and preference).
 | 
			
		||||
 *
 | 
			
		||||
 * @param j 16-bit signed integer representing -1 to (1 - (2**-15)), inclusive
 | 
			
		||||
 * @param k same format as j
 | 
			
		||||
 * @return product of j and k, in same format
 | 
			
		||||
 */
 | 
			
		||||
static inline int16_t q15_mul(const int16_t j, const int16_t k) {
 | 
			
		||||
	const int32_t intermediate = j * k;
 | 
			
		||||
#if 0 // don't round
 | 
			
		||||
	return intermediate >> 15;
 | 
			
		||||
#elif 0 // biased rounding
 | 
			
		||||
	return (intermediate + 0x4000) >> 15;
 | 
			
		||||
#else // unbiased rounding
 | 
			
		||||
	return (intermediate + ((intermediate & 0x7FFF) == 0x4000 ? 0 : 0x4000)) >> 15;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Q15 (1.0.15 fixed point) division (non-saturating). Be careful when using
 | 
			
		||||
 * this function, as it does not behave well when the result is out-of-range.
 | 
			
		||||
 *
 | 
			
		||||
 * Value is not defined if numerator is greater than or equal to denominator.
 | 
			
		||||
 *
 | 
			
		||||
 * @param numer 16-bit signed integer representing -1 to (1 - (2**-15))
 | 
			
		||||
 * @param denom same format as numer; must be greater than numerator
 | 
			
		||||
 * @return numer / denom in same format as numer and denom
 | 
			
		||||
 */
 | 
			
		||||
static inline int16_t q15_div(const int16_t numer, const int16_t denom) {
 | 
			
		||||
	return (static_cast<int32_t>(numer) << 15) / denom;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 16-bit fixed point four-quadrant arctangent. Given some Cartesian vector
 | 
			
		||||
 * (x, y), find the angle subtended by the vector and the positive x-axis.
 | 
			
		||||
 *
 | 
			
		||||
 * The value returned is in units of 1/65536ths of one turn. This allows the use
 | 
			
		||||
 * of the full 16-bit unsigned range to represent a turn. e.g. 0x0000 is 0
 | 
			
		||||
 * radians, 0x8000 is pi radians, and 0xFFFF is (65535 / 32768) * pi radians.
 | 
			
		||||
 *
 | 
			
		||||
 * Because the magnitude of the input vector does not change the angle it
 | 
			
		||||
 * represents, the inputs can be in any signed 16-bit fixed-point format.
 | 
			
		||||
 *
 | 
			
		||||
 * @param y y-coordinate in signed 16-bit
 | 
			
		||||
 * @param x x-coordinate in signed 16-bit
 | 
			
		||||
 * @return angle in (val / 32768) * pi radian increments from 0x0000 to 0xFFFF
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static inline int16_t nabs(const int16_t j) {
 | 
			
		||||
	//return -abs(x);
 | 
			
		||||
	return (j < 0 ? j : -j);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int16_t fxpt_atan2(const int16_t y, const int16_t x) {
 | 
			
		||||
	static const int16_t k1 = 2847;
 | 
			
		||||
	static const int16_t k2 = 11039;
 | 
			
		||||
	if (x == y) { // x/y or y/x would return -1 since 1 isn't representable
 | 
			
		||||
		if (y > 0) { // 1/8
 | 
			
		||||
			return 8192;
 | 
			
		||||
		} else if (y < 0) { // 5/8
 | 
			
		||||
			return 40960;
 | 
			
		||||
		} else { // x = y = 0
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	const int16_t nabs_y = nabs(y);
 | 
			
		||||
	const int16_t nabs_x = nabs(x);
 | 
			
		||||
	if (nabs_x < nabs_y) { // octants 1, 4, 5, 8
 | 
			
		||||
		const int16_t y_over_x = q15_div(y, x);
 | 
			
		||||
		const int16_t correction = q15_mul(k1, nabs(y_over_x));
 | 
			
		||||
		const int16_t unrotated = q15_mul(k2 + correction, y_over_x);
 | 
			
		||||
		if (x > 0) { // octants 1, 8
 | 
			
		||||
			return unrotated;
 | 
			
		||||
		} else { // octants 4, 5
 | 
			
		||||
			return 32768 + unrotated;
 | 
			
		||||
		}
 | 
			
		||||
	} else { // octants 2, 3, 6, 7
 | 
			
		||||
		const int16_t x_over_y = q15_div(x, y);
 | 
			
		||||
		const int16_t correction = q15_mul(k1, nabs(x_over_y));
 | 
			
		||||
		const int16_t unrotated = q15_mul(k2 + correction, x_over_y);
 | 
			
		||||
		if (y > 0) { // octants 2, 3
 | 
			
		||||
			return 16384 - unrotated;
 | 
			
		||||
		} else { // octants 6, 7
 | 
			
		||||
			return 49152 - unrotated;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								Software/portapack-mayhem/firmware/baseband/fxpt_atan2.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								Software/portapack-mayhem/firmware/baseband/fxpt_atan2.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __FXPT_ATAN2_H__
 | 
			
		||||
#define __FXPT_ATAN2_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
int16_t fxpt_atan2(const int16_t y, const int16_t x);
 | 
			
		||||
 | 
			
		||||
#endif/*__FXPT_ATAN2_H__*/
 | 
			
		||||
							
								
								
									
										225
									
								
								Software/portapack-mayhem/firmware/baseband/gpdma_lli.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								Software/portapack-mayhem/firmware/baseband/gpdma_lli.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,225 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#include "gpdma.hpp"
 | 
			
		||||
 | 
			
		||||
namespace lpc43xx {
 | 
			
		||||
namespace gpdma {
 | 
			
		||||
namespace lli {
 | 
			
		||||
 | 
			
		||||
enum class ChainType : uint8_t {
 | 
			
		||||
	Loop = 0,
 | 
			
		||||
	OneShot = 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Interrupt : uint8_t {
 | 
			
		||||
	All = 0,
 | 
			
		||||
	Last = 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ChainConfig {
 | 
			
		||||
	ChainType type;
 | 
			
		||||
	size_t length;
 | 
			
		||||
	Interrupt interrupt;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class BurstSize : uint8_t {
 | 
			
		||||
	Transfer1   = 0,
 | 
			
		||||
	Transfer4   = 1,
 | 
			
		||||
	Transfer8   = 2,
 | 
			
		||||
	Transfer16  = 3,
 | 
			
		||||
	Transfer32  = 4,
 | 
			
		||||
	Transfer64  = 5,
 | 
			
		||||
	Transfer128 = 6,
 | 
			
		||||
	Transfer256 = 7,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class TransferWidth : uint8_t {
 | 
			
		||||
	Byte = 0,
 | 
			
		||||
	HalfWord = 1,
 | 
			
		||||
	Word = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Increment : uint8_t {
 | 
			
		||||
	No = 0,
 | 
			
		||||
	Yes = 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using PeripheralIndex = uint8_t;
 | 
			
		||||
 | 
			
		||||
struct Endpoint {
 | 
			
		||||
	PeripheralIndex peripheral;
 | 
			
		||||
	BurstSize burst_size;
 | 
			
		||||
	TransferWidth transfer_size;
 | 
			
		||||
	Increment increment;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ChannelConfig {
 | 
			
		||||
	ChainConfig chain;
 | 
			
		||||
	FlowControl flow_control;
 | 
			
		||||
	Endpoint source;
 | 
			
		||||
	Endpoint destination;
 | 
			
		||||
 | 
			
		||||
	constexpr gpdma::channel::Control control(
 | 
			
		||||
		const size_t transfer_size,
 | 
			
		||||
		const bool last
 | 
			
		||||
	) {
 | 
			
		||||
		return {
 | 
			
		||||
			.transfersize = transfer_size,
 | 
			
		||||
			.sbsize = toUType(source.burst_size),
 | 
			
		||||
			.dbsize = toUType(destination.burst_size),
 | 
			
		||||
			.swidth = toUType(source.transfer_size),
 | 
			
		||||
			.dwidth = toUType(destination.transfer_size),
 | 
			
		||||
			.s = source_endpoint_type(flow_control),
 | 
			
		||||
			.d = destination_endpoint_type(flow_control),
 | 
			
		||||
			.si = toUType(source.increment),
 | 
			
		||||
			.di = toUType(destination.increment),
 | 
			
		||||
			.prot1 = 0,
 | 
			
		||||
			.prot2 = 0,
 | 
			
		||||
			.prot3 = 0,
 | 
			
		||||
			.i = ((chain.interrupt == Interrupt::All) || last) ? 1U : 0U,
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr gpdma::channel::Config config() {
 | 
			
		||||
		return {
 | 
			
		||||
			.e = 0,
 | 
			
		||||
			.srcperipheral = source.peripheral,
 | 
			
		||||
			.destperipheral = destination.peripheral,
 | 
			
		||||
			.flowcntrl = flow_control,
 | 
			
		||||
			.ie = 1,
 | 
			
		||||
			.itc = 1,
 | 
			
		||||
			.l = 0,
 | 
			
		||||
			.a = 0,
 | 
			
		||||
			.h = 0,
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr ChannelConfig channel_config_baseband_tx {
 | 
			
		||||
	{ ChainType::Loop, 4, Interrupt::All },
 | 
			
		||||
	gpdma::FlowControl::MemoryToPeripheral_DMAControl,
 | 
			
		||||
	{ 0x00, BurstSize::Transfer1, TransferWidth::Word, Increment::Yes },
 | 
			
		||||
	{ 0x00, BurstSize::Transfer1, TransferWidth::Word, Increment::No  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr ChannelConfig channel_config_baseband_rx {
 | 
			
		||||
	{ ChainType::Loop, 4, Interrupt::All },
 | 
			
		||||
	gpdma::FlowControl::PeripheralToMemory_DMAControl,
 | 
			
		||||
	{ 0x00, BurstSize::Transfer1, TransferWidth::Word, Increment::No  },
 | 
			
		||||
	{ 0x00, BurstSize::Transfer1, TransferWidth::Word, Increment::Yes },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr ChannelConfig channel_config_audio_tx {
 | 
			
		||||
	{ ChainType::Loop, 4, Interrupt::All },
 | 
			
		||||
	gpdma::FlowControl::MemoryToPeripheral_DMAControl,
 | 
			
		||||
	{ 0x0a, BurstSize::Transfer32, TransferWidth::Word, Increment::Yes },
 | 
			
		||||
	{ 0x0a, BurstSize::Transfer32, TransferWidth::Word, Increment::No  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr ChannelConfig channel_config_audio_rx {
 | 
			
		||||
	{ ChainType::Loop, 4, Interrupt::All },
 | 
			
		||||
	gpdma::FlowControl::PeripheralToMemory_DMAControl,
 | 
			
		||||
	{ 0x09, BurstSize::Transfer32, TransferWidth::Word, Increment::No  },
 | 
			
		||||
	{ 0x09, BurstSize::Transfer32, TransferWidth::Word, Increment::Yes },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr ChannelConfig channel_config_rssi {
 | 
			
		||||
	{ ChainType::Loop, 4, Interrupt::All },
 | 
			
		||||
	gpdma::FlowControl::PeripheralToMemory_DMAControl,
 | 
			
		||||
	{ 0x0e, BurstSize::Transfer1, TransferWidth::Byte, Increment::No  },
 | 
			
		||||
	{ 0x0e, BurstSize::Transfer1, TransferWidth::Word, Increment::Yes },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Chain {
 | 
			
		||||
public:
 | 
			
		||||
	using chain_t = std::vector<gpdma::channel::LLI>;
 | 
			
		||||
	using chain_p = std::unique_ptr<chain_t>;
 | 
			
		||||
 | 
			
		||||
	Chain(const ChannelConfig& cc) :
 | 
			
		||||
		chain(std::make_unique<chain_t>(cc.chain.length))
 | 
			
		||||
	{
 | 
			
		||||
		set_lli_sequential(cc.chain_type);
 | 
			
		||||
		set_source_address()...
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	chain_p chain;
 | 
			
		||||
 | 
			
		||||
	void set_source_peripheral(void* const address) {
 | 
			
		||||
		set_source_address(address, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set_destination_peripheral(void* const address) {
 | 
			
		||||
		set_destination_address(address, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set_source_address(void* const address, const size_t increment) {
 | 
			
		||||
		size_t offset = 0;
 | 
			
		||||
		for(auto& item : *chain) {
 | 
			
		||||
			item.srcaddr = (uint32_t)address + offset;
 | 
			
		||||
			offset += increment;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set_destination_address(void* const address, const size_t increment) {
 | 
			
		||||
		size_t offset = 0;
 | 
			
		||||
		for(auto& item : *chain) {
 | 
			
		||||
			item.destaddr = (uint32_t)address + offset;
 | 
			
		||||
			offset += increment;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set_control(const gpdma::channel::Control control) {
 | 
			
		||||
		for(auto& item : *chain) {
 | 
			
		||||
			item.control = control;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set_lli_sequential(ChainType chain_type) {
 | 
			
		||||
		for(auto& item : *chain) {
 | 
			
		||||
			item.lli = lli_pointer(&item + 1);
 | 
			
		||||
		}
 | 
			
		||||
		if( chain_type == ChainType::Loop ) {
 | 
			
		||||
			chain[chain->size() - 1].lli = lli_pointer(&chain[0]);
 | 
			
		||||
		} else {
 | 
			
		||||
			chain[chain->size() - 1].lli = lli_pointer(nullptr);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gpdma::channel::LLIPointer lli_pointer(const void* lli) {
 | 
			
		||||
		return {
 | 
			
		||||
			.lm = 0,
 | 
			
		||||
			.r = 0,
 | 
			
		||||
			.lli = reinterpret_cast<uint32_t>(lli),
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace lli */
 | 
			
		||||
} /* namespace gpdma */
 | 
			
		||||
} /* namespace lpc43xx */
 | 
			
		||||
							
								
								
									
										313
									
								
								Software/portapack-mayhem/firmware/baseband/halconf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										313
									
								
								Software/portapack-mayhem/firmware/baseband/halconf.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,313 @@
 | 
			
		||||
/*
 | 
			
		||||
    ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
 | 
			
		||||
                 Copyright (C) 2014 Jared Boone, ShareBrained Technology
 | 
			
		||||
 | 
			
		||||
    Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
    you may not use this file except in compliance with the License.
 | 
			
		||||
    You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
        http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
    Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
    distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
    See the License for the specific language governing permissions and
 | 
			
		||||
    limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file    templates/halconf.h
 | 
			
		||||
 * @brief   HAL configuration header.
 | 
			
		||||
 * @details HAL configuration file, this file allows to enable or disable the
 | 
			
		||||
 *          various device drivers from your application. You may also use
 | 
			
		||||
 *          this file in order to override the device drivers default settings.
 | 
			
		||||
 *
 | 
			
		||||
 * @addtogroup HAL_CONF
 | 
			
		||||
 * @{
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _HALCONF_H_
 | 
			
		||||
#define _HALCONF_H_
 | 
			
		||||
 | 
			
		||||
#include "mcuconf.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the TM subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_TM) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_TM                  FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the PAL subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_PAL                 FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the ADC subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_ADC                 FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the CAN subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_CAN                 FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the EXT subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_EXT) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_EXT                 FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the GPT subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_GPT                 FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the I2C subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_I2C                 FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the ICU subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_ICU                 FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the MAC subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_MAC                 FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the MMC_SPI subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_MMC_SPI             FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the PWM subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_PWM                 FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the RTC subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_RTC                 FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the SDC subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_SDC                 FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the SERIAL subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_SERIAL              FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the SERIAL over USB subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_SERIAL_USB          FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the SPI subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_SPI                 FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the UART subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_UART                FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the USB subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_USB                 FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
/* ADC driver related settings.                                              */
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables synchronous APIs.
 | 
			
		||||
 * @note    Disabling this option saves both code and data space.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
 | 
			
		||||
#define ADC_USE_WAIT                TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
 | 
			
		||||
 * @note    Disabling this option saves both code and data space.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
 | 
			
		||||
#define ADC_USE_MUTUAL_EXCLUSION    TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
/* CAN driver related settings.                                              */
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Sleep mode related APIs inclusion switch.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
 | 
			
		||||
#define CAN_USE_SLEEP_MODE          TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
/* I2C driver related settings.                                              */
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the mutual exclusion APIs on the I2C bus.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
 | 
			
		||||
#define I2C_USE_MUTUAL_EXCLUSION    TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
/* MAC driver related settings.                                              */
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables an event sources for incoming packets.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
 | 
			
		||||
#define MAC_USE_ZERO_COPY           FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables an event sources for incoming packets.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
 | 
			
		||||
#define MAC_USE_EVENTS              TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
/* MMC_SPI driver related settings.                                          */
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Delays insertions.
 | 
			
		||||
 * @details If enabled this options inserts delays into the MMC waiting
 | 
			
		||||
 *          routines releasing some extra CPU time for the threads with
 | 
			
		||||
 *          lower priority, this may slow down the driver a bit however.
 | 
			
		||||
 *          This option is recommended also if the SPI driver does not
 | 
			
		||||
 *          use a DMA channel and heavily loads the CPU.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
 | 
			
		||||
#define MMC_NICE_WAITING            TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
/* SDC driver related settings.                                              */
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Number of initialization attempts before rejecting the card.
 | 
			
		||||
 * @note    Attempts are performed at 10mS intervals.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
 | 
			
		||||
#define SDC_INIT_RETRY              100
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Include support for MMC cards.
 | 
			
		||||
 * @note    MMC support is not yet implemented so this option must be kept
 | 
			
		||||
 *          at @p FALSE.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
 | 
			
		||||
#define SDC_MMC_SUPPORT             FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Delays insertions.
 | 
			
		||||
 * @details If enabled this options inserts delays into the MMC waiting
 | 
			
		||||
 *          routines releasing some extra CPU time for the threads with
 | 
			
		||||
 *          lower priority, this may slow down the driver a bit however.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
 | 
			
		||||
#define SDC_NICE_WAITING            FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
/* SERIAL driver related settings.                                           */
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Default bit rate.
 | 
			
		||||
 * @details Configuration parameter, this is the baud rate selected for the
 | 
			
		||||
 *          default configuration.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
 | 
			
		||||
#define SERIAL_DEFAULT_BITRATE      38400
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Serial buffers size.
 | 
			
		||||
 * @details Configuration parameter, you can change the depth of the queue
 | 
			
		||||
 *          buffers depending on the requirements of your application.
 | 
			
		||||
 * @note    The default is 64 bytes for both the transmission and receive
 | 
			
		||||
 *          buffers.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
 | 
			
		||||
#define SERIAL_BUFFERS_SIZE         16
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
/* SPI driver related settings.                                              */
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables synchronous APIs.
 | 
			
		||||
 * @note    Disabling this option saves both code and data space.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
 | 
			
		||||
#define SPI_USE_WAIT                TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
 | 
			
		||||
 * @note    Disabling this option saves both code and data space.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
 | 
			
		||||
#define SPI_USE_MUTUAL_EXCLUSION    TRUE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* _HALCONF_H_ */
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
@@ -0,0 +1,69 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __LINEAR_RESAMPLER_H__
 | 
			
		||||
#define __LINEAR_RESAMPLER_H__
 | 
			
		||||
 | 
			
		||||
namespace dsp {
 | 
			
		||||
namespace interpolation {
 | 
			
		||||
 | 
			
		||||
class LinearResampler {
 | 
			
		||||
public:
 | 
			
		||||
	void configure(
 | 
			
		||||
		const float input_rate,
 | 
			
		||||
		const float output_rate
 | 
			
		||||
	) {
 | 
			
		||||
		phase_increment = calculate_increment(input_rate, output_rate);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<typename InterpolatedSampleHandler>
 | 
			
		||||
	void operator()(
 | 
			
		||||
		const float sample,
 | 
			
		||||
		InterpolatedSampleHandler interpolated_sample_handler
 | 
			
		||||
	) {
 | 
			
		||||
		const float sample_delta = sample - last_sample;
 | 
			
		||||
		while( phase < 1.0f ) {
 | 
			
		||||
			const float interpolated_value = last_sample + phase * sample_delta;
 | 
			
		||||
			interpolated_sample_handler(interpolated_value);
 | 
			
		||||
			phase += phase_increment;
 | 
			
		||||
		}
 | 
			
		||||
		last_sample = sample;
 | 
			
		||||
		phase -= 1.0f;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void advance(const float fraction) {
 | 
			
		||||
		phase += (fraction * phase_increment);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	float last_sample { 0.0f };
 | 
			
		||||
	float phase { 0.0f };
 | 
			
		||||
	float phase_increment { 0.0f };
 | 
			
		||||
 | 
			
		||||
	static constexpr float calculate_increment(const float input_rate, const float output_rate) {
 | 
			
		||||
		return input_rate / output_rate;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace interpolation */
 | 
			
		||||
} /* namespace dsp */
 | 
			
		||||
 | 
			
		||||
#endif/*__LINEAR_RESAMPLER_H__*/
 | 
			
		||||
							
								
								
									
										121
									
								
								Software/portapack-mayhem/firmware/baseband/main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								Software/portapack-mayhem/firmware/baseband/main.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,121 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "ch.h"
 | 
			
		||||
 | 
			
		||||
#include "lpc43xx_cpp.hpp"
 | 
			
		||||
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
#include "portapack_dma.hpp"
 | 
			
		||||
 | 
			
		||||
#include "gpdma.hpp"
 | 
			
		||||
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include "touch_dma.hpp"
 | 
			
		||||
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "rssi_thread.hpp"
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
 | 
			
		||||
#include "message_queue.hpp"
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
#include "debug.hpp"
 | 
			
		||||
 | 
			
		||||
#include "audio_dma.hpp"
 | 
			
		||||
 | 
			
		||||
#include "gcc.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
 | 
			
		||||
void __late_init(void) {
 | 
			
		||||
	/*
 | 
			
		||||
	 * System initializations.
 | 
			
		||||
	 * - HAL initialization, this also initializes the configured device drivers
 | 
			
		||||
	 *   and performs the board-specific initializations.
 | 
			
		||||
	 * - Kernel initialization, the main() function becomes a thread and the
 | 
			
		||||
	 *   RTOS is active.
 | 
			
		||||
	 */
 | 
			
		||||
	halInit();
 | 
			
		||||
 | 
			
		||||
	/* After this call, scheduler, systick, heap, etc. are available. */
 | 
			
		||||
	/* By doing chSysInit() here, it runs before C++ constructors, which may
 | 
			
		||||
	 * require the heap.
 | 
			
		||||
	 */
 | 
			
		||||
	chSysInit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void init() {
 | 
			
		||||
	audio::dma::init();
 | 
			
		||||
	audio::dma::configure();
 | 
			
		||||
	audio::dma::enable();
 | 
			
		||||
 | 
			
		||||
	LPC_CREG->DMAMUX = portapack::gpdma_mux;
 | 
			
		||||
	gpdma::controller.enable();
 | 
			
		||||
	nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC_DMA_IRQ_PRIORITY));
 | 
			
		||||
 | 
			
		||||
	touch::dma::init();
 | 
			
		||||
	touch::dma::allocate();
 | 
			
		||||
	touch::dma::enable();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void halt() {
 | 
			
		||||
	port_disable();
 | 
			
		||||
	while(true) {
 | 
			
		||||
		port_wait_for_interrupt();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void shutdown() {
 | 
			
		||||
	// TODO: Is this complete?
 | 
			
		||||
	
 | 
			
		||||
	nvicDisableVector(DMA_IRQn);
 | 
			
		||||
	
 | 
			
		||||
	chSysDisable();
 | 
			
		||||
 | 
			
		||||
	systick_stop();
 | 
			
		||||
 | 
			
		||||
	ShutdownMessage shutdown_message;
 | 
			
		||||
	shared_memory.application_queue.push(shutdown_message);
 | 
			
		||||
 | 
			
		||||
	halt();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(void) {
 | 
			
		||||
	init();
 | 
			
		||||
 | 
			
		||||
	/* TODO: Ensure DMAs are configured to point at first LLI in chain. */
 | 
			
		||||
 | 
			
		||||
	EventDispatcher event_dispatcher;
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
 | 
			
		||||
	shutdown();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										107
									
								
								Software/portapack-mayhem/firmware/baseband/matched_filter.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								Software/portapack-mayhem/firmware/baseband/matched_filter.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "matched_filter.hpp"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
namespace dsp {
 | 
			
		||||
namespace matched_filter {
 | 
			
		||||
 | 
			
		||||
void MatchedFilter::configure(
 | 
			
		||||
	const tap_t* const taps,
 | 
			
		||||
	const size_t taps_count,
 | 
			
		||||
	const size_t decimation_factor
 | 
			
		||||
) {
 | 
			
		||||
	samples_ = std::make_unique<samples_t>(taps_count);
 | 
			
		||||
	taps_reversed_ = std::make_unique<taps_t>(taps_count);
 | 
			
		||||
	taps_count_ = taps_count;
 | 
			
		||||
	decimation_factor_ = decimation_factor;
 | 
			
		||||
	output = 0;
 | 
			
		||||
	std::reverse_copy(&taps[0], &taps[taps_count], &taps_reversed_[0]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MatchedFilter::execute_once(
 | 
			
		||||
	const sample_t input
 | 
			
		||||
) {
 | 
			
		||||
	samples_[taps_count_ - decimation_factor_ + decimation_phase] = input;
 | 
			
		||||
 | 
			
		||||
	advance_decimation_phase();
 | 
			
		||||
	if( is_new_decimation_cycle() ) {
 | 
			
		||||
		float sr_tr = 0.0f;
 | 
			
		||||
		float si_tr = 0.0f;
 | 
			
		||||
		float si_ti = 0.0f;
 | 
			
		||||
		float sr_ti = 0.0f;
 | 
			
		||||
		for(size_t n=0; n<taps_count_; n++) {
 | 
			
		||||
			const auto sample = samples_[n];
 | 
			
		||||
			const auto tap = taps_reversed_[n];
 | 
			
		||||
 | 
			
		||||
			sr_tr += sample.real() * tap.real();
 | 
			
		||||
			si_ti += sample.imag() * tap.imag();
 | 
			
		||||
			si_tr += sample.imag() * tap.real();
 | 
			
		||||
			sr_ti += sample.real() * tap.imag();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// N: complex multiple of samples and taps (conjugate, tap.i negated).
 | 
			
		||||
		// P: complex multiply of samples and taps.
 | 
			
		||||
		const auto r_n = sr_tr + si_ti;
 | 
			
		||||
		const auto r_p = sr_tr - si_ti;
 | 
			
		||||
		const auto i_n = si_tr - sr_ti;
 | 
			
		||||
		const auto i_p = si_tr + sr_ti;
 | 
			
		||||
 | 
			
		||||
		const auto mag_n = std::sqrt(r_n * r_n + i_n * i_n);
 | 
			
		||||
		const auto mag_p = std::sqrt(r_p * r_p + i_p * i_p);
 | 
			
		||||
		const auto diff = mag_p - mag_n;
 | 
			
		||||
		output = diff;
 | 
			
		||||
 | 
			
		||||
		shift_by_decimation_factor();
 | 
			
		||||
		return true;
 | 
			
		||||
	} else {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MatchedFilter::shift_by_decimation_factor() {
 | 
			
		||||
	const sample_t* s = &samples_[decimation_factor_];
 | 
			
		||||
	sample_t* t = &samples_[0];
 | 
			
		||||
	
 | 
			
		||||
	const size_t unroll_factor = 4;
 | 
			
		||||
	size_t shift_count = (taps_count_ - decimation_factor_) / unroll_factor;	
 | 
			
		||||
	while(shift_count > 0) {
 | 
			
		||||
		*t++ = *s++;
 | 
			
		||||
		*t++ = *s++;
 | 
			
		||||
		*t++ = *s++;
 | 
			
		||||
		*t++ = *s++;
 | 
			
		||||
		shift_count--;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	shift_count = (taps_count_ - decimation_factor_) % unroll_factor;
 | 
			
		||||
	while(shift_count > 0) {
 | 
			
		||||
		*t++ = *s++;
 | 
			
		||||
		shift_count--;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace matched_filter */
 | 
			
		||||
} /* namespace dsp */
 | 
			
		||||
@@ -0,0 +1,96 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __MATCHED_FILTER_H__
 | 
			
		||||
#define __MATCHED_FILTER_H__
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <complex>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
namespace dsp {
 | 
			
		||||
namespace matched_filter {
 | 
			
		||||
 | 
			
		||||
// This filter contains "magic" (optimizations) that expect the taps to
 | 
			
		||||
// combine a low-pass filter with a complex sinusoid that performs shifting of
 | 
			
		||||
// the input signal to 0Hz/DC. This also means that the taps length must be
 | 
			
		||||
// a multiple of the complex sinusoid period.
 | 
			
		||||
 | 
			
		||||
class MatchedFilter {
 | 
			
		||||
public:
 | 
			
		||||
	using sample_t = std::complex<float>;
 | 
			
		||||
	using tap_t = std::complex<float>;
 | 
			
		||||
 | 
			
		||||
	using taps_t = tap_t[];
 | 
			
		||||
 | 
			
		||||
	template<class T>
 | 
			
		||||
	MatchedFilter(
 | 
			
		||||
		const T& taps,
 | 
			
		||||
		size_t decimation_factor = 1
 | 
			
		||||
	) {
 | 
			
		||||
		configure(taps, decimation_factor);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<class T>
 | 
			
		||||
	void configure(
 | 
			
		||||
		const T& taps,
 | 
			
		||||
		size_t decimation_factor
 | 
			
		||||
	) {
 | 
			
		||||
		configure(taps.data(), taps.size(), decimation_factor);
 | 
			
		||||
 	}
 | 
			
		||||
 | 
			
		||||
	bool execute_once(const sample_t input);
 | 
			
		||||
 | 
			
		||||
	float get_output() const {
 | 
			
		||||
		return output;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	using samples_t = sample_t[];
 | 
			
		||||
 | 
			
		||||
	std::unique_ptr<samples_t> samples_ { };
 | 
			
		||||
	std::unique_ptr<taps_t> taps_reversed_ { };
 | 
			
		||||
	size_t taps_count_ { 0 };
 | 
			
		||||
	size_t decimation_factor_ { 1 };
 | 
			
		||||
	size_t decimation_phase { 0 };
 | 
			
		||||
	float output { 0 };
 | 
			
		||||
 | 
			
		||||
	void shift_by_decimation_factor();
 | 
			
		||||
 | 
			
		||||
	void advance_decimation_phase() {
 | 
			
		||||
		decimation_phase = (decimation_phase + 1) % decimation_factor_;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool is_new_decimation_cycle() const {
 | 
			
		||||
		return (decimation_phase == 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void configure(
 | 
			
		||||
		const tap_t* const taps,
 | 
			
		||||
		const size_t taps_count,
 | 
			
		||||
		const size_t decimation_factor
 | 
			
		||||
	);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} /* namespace matched_filter */
 | 
			
		||||
} /* namespace dsp */
 | 
			
		||||
 | 
			
		||||
#endif/*__MATCHED_FILTER_H__*/
 | 
			
		||||
							
								
								
									
										48
									
								
								Software/portapack-mayhem/firmware/baseband/mcuconf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								Software/portapack-mayhem/firmware/baseband/mcuconf.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
/*
 | 
			
		||||
    ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
 | 
			
		||||
                 Copyright (C) 2014 Jared Boone, ShareBrained Technology
 | 
			
		||||
 | 
			
		||||
    Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
    you may not use this file except in compliance with the License.
 | 
			
		||||
    You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
        http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
    Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
    distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
    See the License for the specific language governing permissions and
 | 
			
		||||
    limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * LPC43xx drivers configuration.
 | 
			
		||||
 * The following settings override the default settings present in
 | 
			
		||||
 * the various device driver implementation headers.
 | 
			
		||||
 * Note that the settings for each driver only have effect if the whole
 | 
			
		||||
 * driver is enabled in halconf.h.
 | 
			
		||||
 *
 | 
			
		||||
 * IRQ priorities:
 | 
			
		||||
 * 7...0       Lowest...Highest.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* NOTE: Beware setting IRQ priorities < "2":
 | 
			
		||||
 * dbg_check_enter_isr "#SV8 means that probably you have some IRQ set at a
 | 
			
		||||
 * priority level above the kernel level (level 0 or 1 usually) so it is able
 | 
			
		||||
 * to preempt the kernel and mess things up.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * DMA driver system settings.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
//#define LPC_ADC0_IRQ_PRIORITY               2
 | 
			
		||||
#define LPC_DMA_IRQ_PRIORITY                3
 | 
			
		||||
//#define LPC_ADC1_IRQ_PRIORITY               4
 | 
			
		||||
 | 
			
		||||
#define LPC43XX_M0APPTXEVENT_IRQ_PRIORITY   4
 | 
			
		||||
 | 
			
		||||
/* M4 is initialized by M0, which has already started PLL1 */
 | 
			
		||||
#if !defined(LPC43XX_M4_CLK) || defined(__DOXYGEN__)
 | 
			
		||||
#define LPC43XX_M4_CLK                      200000000
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										1
									
								
								Software/portapack-mayhem/firmware/baseband/name
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Software/portapack-mayhem/firmware/baseband/name
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
Receiver
 | 
			
		||||
							
								
								
									
										95
									
								
								Software/portapack-mayhem/firmware/baseband/ook.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								Software/portapack-mayhem/firmware/baseband/ook.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __OOK_HPP__
 | 
			
		||||
#define __OOK_HPP__
 | 
			
		||||
 | 
			
		||||
#include "phase_detector.hpp"
 | 
			
		||||
#include "phase_accumulator.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <complex>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
 | 
			
		||||
class OOKSlicerMagSquaredInt {
 | 
			
		||||
public:
 | 
			
		||||
	using symbol_t = bool;
 | 
			
		||||
 | 
			
		||||
	constexpr OOKSlicerMagSquaredInt(
 | 
			
		||||
		const float samples_per_symbol
 | 
			
		||||
	) : mag2_threshold_leak_factor {
 | 
			
		||||
			static_cast<uint32_t>(
 | 
			
		||||
				factor_sq(-1.0f / (8.0f * samples_per_symbol)) * float(1ULL << 32)
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	symbol_t operator()(const std::complex<int16_t> in) {
 | 
			
		||||
		const uint32_t real2 = in.real() * in.real();
 | 
			
		||||
		const uint32_t imag2 = in.imag() * in.imag();
 | 
			
		||||
		const uint32_t mag2 = real2 + imag2;
 | 
			
		||||
 | 
			
		||||
		const uint32_t mag2_attenuated = mag2 >> 3;	// Approximation of (-4.5dB)^2
 | 
			
		||||
		mag2_threshold = (uint64_t(mag2_threshold) * uint64_t(mag2_threshold_leak_factor)) >> 32;
 | 
			
		||||
		mag2_threshold = std::max(mag2_threshold, mag2_attenuated);
 | 
			
		||||
		const bool symbol = (mag2 > mag2_threshold);
 | 
			
		||||
		return symbol;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	const uint32_t mag2_threshold_leak_factor;
 | 
			
		||||
	uint32_t mag2_threshold = 0;
 | 
			
		||||
 | 
			
		||||
	constexpr float factor_sq(float db) {
 | 
			
		||||
		return std::pow(10.0f, db / (10.0f / 2));
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class OOKClockRecovery {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr OOKClockRecovery(
 | 
			
		||||
		const float samples_per_symbol
 | 
			
		||||
	) : symbol_phase_inc_nominal { static_cast<uint32_t>(std::round((1ULL << 32) / samples_per_symbol)) },
 | 
			
		||||
		symbol_phase_inc_k { static_cast<uint32_t>(std::round(symbol_phase_inc_nominal * (2.0f / 8.0f) / samples_per_symbol)) },
 | 
			
		||||
		phase_detector { static_cast<size_t>(std::round(samples_per_symbol)) },
 | 
			
		||||
		phase_accumulator { symbol_phase_inc_nominal }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<typename SymbolHandler>
 | 
			
		||||
	void operator()(const uint32_t slicer_history, SymbolHandler symbol_handler) {
 | 
			
		||||
		if( phase_accumulator() ) {
 | 
			
		||||
			const auto detector_result = phase_detector(slicer_history);
 | 
			
		||||
			phase_accumulator.set_inc(symbol_phase_inc_nominal + detector_result.error * symbol_phase_inc_k);
 | 
			
		||||
			symbol_handler(detector_result.symbol);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	const uint32_t symbol_phase_inc_nominal;
 | 
			
		||||
	const uint32_t symbol_phase_inc_k;
 | 
			
		||||
	PhaseDetectorEarlyLateGate phase_detector;
 | 
			
		||||
	PhaseAccumulator phase_accumulator;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__OOK_HPP__*/
 | 
			
		||||
@@ -0,0 +1,22 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "packet_builder.hpp"
 | 
			
		||||
							
								
								
									
										139
									
								
								Software/portapack-mayhem/firmware/baseband/packet_builder.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								Software/portapack-mayhem/firmware/baseband/packet_builder.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,139 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PACKET_BUILDER_H__
 | 
			
		||||
#define __PACKET_BUILDER_H__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <bitset>
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
#include "bit_pattern.hpp"
 | 
			
		||||
#include "baseband_packet.hpp"
 | 
			
		||||
 | 
			
		||||
struct NeverMatch {
 | 
			
		||||
	bool operator()(const BitHistory&, const size_t) const {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct FixedLength {
 | 
			
		||||
	bool operator()(const BitHistory&, const size_t symbols_received) const {
 | 
			
		||||
		return symbols_received >= length;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const size_t length;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename PreambleMatcher, typename UnstuffMatcher, typename EndMatcher>
 | 
			
		||||
class PacketBuilder {
 | 
			
		||||
public:
 | 
			
		||||
	using PayloadHandlerFunc = std::function<void(const baseband::Packet& packet)>;
 | 
			
		||||
 | 
			
		||||
	PacketBuilder(
 | 
			
		||||
		const PreambleMatcher preamble_matcher,
 | 
			
		||||
		const UnstuffMatcher unstuff_matcher,
 | 
			
		||||
		const EndMatcher end_matcher,
 | 
			
		||||
		PayloadHandlerFunc payload_handler
 | 
			
		||||
	) : payload_handler { std::move(payload_handler) },
 | 
			
		||||
		preamble(preamble_matcher),
 | 
			
		||||
		unstuff(unstuff_matcher),
 | 
			
		||||
		end(end_matcher)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void configure(
 | 
			
		||||
		const PreambleMatcher preamble_matcher,
 | 
			
		||||
		const UnstuffMatcher unstuff_matcher
 | 
			
		||||
	) {
 | 
			
		||||
		preamble = preamble_matcher;
 | 
			
		||||
		unstuff = unstuff_matcher;
 | 
			
		||||
 | 
			
		||||
		reset_state();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void execute(
 | 
			
		||||
		const uint_fast8_t symbol
 | 
			
		||||
	) {
 | 
			
		||||
		bit_history.add(symbol);
 | 
			
		||||
 | 
			
		||||
		switch(state) {
 | 
			
		||||
		case State::Preamble:
 | 
			
		||||
			if( preamble(bit_history, packet.size()) ) {
 | 
			
		||||
				state = State::Payload;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case State::Payload:
 | 
			
		||||
			if( !unstuff(bit_history, packet.size()) ) {
 | 
			
		||||
				packet.add(symbol);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if( end(bit_history, packet.size()) ) {
 | 
			
		||||
				// NOTE: This check is to avoid std::function nullptr check, which
 | 
			
		||||
				// brings in "_ZSt25__throw_bad_function_callv" and a lot of extra code.
 | 
			
		||||
				// TODO: Make payload_handler known at compile time.
 | 
			
		||||
				if( payload_handler ) {
 | 
			
		||||
					packet.set_timestamp(Timestamp::now());
 | 
			
		||||
					payload_handler(packet);
 | 
			
		||||
				}
 | 
			
		||||
				reset_state();
 | 
			
		||||
			} else {
 | 
			
		||||
				if( packet_truncated() ) {
 | 
			
		||||
					reset_state();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			reset_state();
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	enum State {
 | 
			
		||||
		Preamble,
 | 
			
		||||
		Payload,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	bool packet_truncated() const {
 | 
			
		||||
		return packet.size() >= packet.capacity();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const PayloadHandlerFunc payload_handler;
 | 
			
		||||
 | 
			
		||||
	BitHistory bit_history { };
 | 
			
		||||
	PreambleMatcher preamble { };
 | 
			
		||||
	UnstuffMatcher unstuff { };
 | 
			
		||||
	EndMatcher end { };
 | 
			
		||||
 | 
			
		||||
	State state { State::Preamble };
 | 
			
		||||
	baseband::Packet packet { };
 | 
			
		||||
 | 
			
		||||
	void reset_state() {
 | 
			
		||||
		packet.clear();
 | 
			
		||||
		state = State::Preamble;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__PACKET_BUILDER_H__*/
 | 
			
		||||
@@ -0,0 +1,50 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PHASE_ACCUMULATOR_HPP__
 | 
			
		||||
#define __PHASE_ACCUMULATOR_HPP__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
class PhaseAccumulator {
 | 
			
		||||
public:
 | 
			
		||||
	constexpr PhaseAccumulator(
 | 
			
		||||
		const uint32_t phase_inc
 | 
			
		||||
	) : phase_inc { phase_inc }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool operator()() {
 | 
			
		||||
		const auto last_phase = phase;
 | 
			
		||||
		phase += phase_inc;
 | 
			
		||||
		return (phase < last_phase);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void set_inc(const uint32_t new_phase_inc) {
 | 
			
		||||
		phase_inc = new_phase_inc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	uint32_t phase { 0 };
 | 
			
		||||
	uint32_t phase_inc;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__PHASE_ACCUMULATOR_HPP__*/
 | 
			
		||||
@@ -0,0 +1,70 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PHASE_DETECTOR_HPP__
 | 
			
		||||
#define __PHASE_DETECTOR_HPP__
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
 | 
			
		||||
class PhaseDetectorEarlyLateGate {
 | 
			
		||||
public:
 | 
			
		||||
	using history_t = uint32_t;
 | 
			
		||||
 | 
			
		||||
	using symbol_t = bool;
 | 
			
		||||
	using error_t = int;
 | 
			
		||||
 | 
			
		||||
	struct result_t {
 | 
			
		||||
		symbol_t symbol;
 | 
			
		||||
		error_t error;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	constexpr PhaseDetectorEarlyLateGate(
 | 
			
		||||
		const size_t samples_per_symbol
 | 
			
		||||
	) : sample_threshold { samples_per_symbol / 2 },
 | 
			
		||||
		late_mask { (1UL << sample_threshold) - 1UL },
 | 
			
		||||
		early_mask { late_mask << sample_threshold }
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result_t operator()(const history_t symbol_history) const {
 | 
			
		||||
		static_assert(sizeof(history_t) == sizeof(unsigned long), "popcountl size mismatch");
 | 
			
		||||
 | 
			
		||||
		// history = ...0111, early
 | 
			
		||||
		// history = ...1110, late
 | 
			
		||||
 | 
			
		||||
		const size_t late_side = __builtin_popcountl(symbol_history & late_mask);
 | 
			
		||||
		const size_t early_side = __builtin_popcountl(symbol_history & early_mask);
 | 
			
		||||
		const size_t total_count = late_side + early_side;
 | 
			
		||||
		const auto lateness = static_cast<int>(late_side) - static_cast<int>(early_side);
 | 
			
		||||
		const symbol_t symbol = (total_count >= sample_threshold);
 | 
			
		||||
		const error_t error = symbol ? -lateness : lateness;
 | 
			
		||||
		return { symbol, error };
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	const size_t sample_threshold;
 | 
			
		||||
	const history_t late_mask;
 | 
			
		||||
	const history_t early_mask;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__PHASE_DETECTOR_HPP__*/
 | 
			
		||||
							
								
								
									
										81
									
								
								Software/portapack-mayhem/firmware/baseband/proc_acars.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								Software/portapack-mayhem/firmware/baseband/proc_acars.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2018 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_acars.hpp"
 | 
			
		||||
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_fir_taps.hpp"
 | 
			
		||||
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
ACARSProcessor::ACARSProcessor() {
 | 
			
		||||
	decim_0.configure(taps_11k0_decim_0.taps, 33554432);
 | 
			
		||||
	decim_1.configure(taps_11k0_decim_1.taps, 131072);
 | 
			
		||||
	packet.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ACARSProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	/* 2.4576MHz, 2048 samples */
 | 
			
		||||
 | 
			
		||||
	const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
 | 
			
		||||
	const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer);
 | 
			
		||||
	const auto decimator_out = decim_1_out;
 | 
			
		||||
 | 
			
		||||
	/* 38.4kHz, 32 samples */
 | 
			
		||||
	feed_channel_stats(decimator_out);
 | 
			
		||||
 | 
			
		||||
	for(size_t i=0; i<decimator_out.count; i++) {
 | 
			
		||||
		if( mf.execute_once(decimator_out.p[i]) ) {
 | 
			
		||||
			clock_recovery(mf.get_output());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ACARSProcessor::consume_symbol(
 | 
			
		||||
	const float raw_symbol
 | 
			
		||||
) {
 | 
			
		||||
	const uint_fast8_t sliced_symbol = (raw_symbol >= 0.0f) ? 1 : 0;
 | 
			
		||||
	//const auto decoded_symbol = acars_decode(sliced_symbol);
 | 
			
		||||
 | 
			
		||||
	// DEBUG
 | 
			
		||||
	packet.add(sliced_symbol);
 | 
			
		||||
	if (packet.size() == 256) {
 | 
			
		||||
		payload_handler(packet);
 | 
			
		||||
		packet.clear();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//packet_builder.execute(decoded_symbol);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ACARSProcessor::payload_handler(
 | 
			
		||||
	const baseband::Packet& packet
 | 
			
		||||
) {
 | 
			
		||||
	const ACARSPacketMessage message { packet };
 | 
			
		||||
	shared_memory.application_queue.push(message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<ACARSProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										138
									
								
								Software/portapack-mayhem/firmware/baseband/proc_acars.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								Software/portapack-mayhem/firmware/baseband/proc_acars.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,138 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2018 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_ACARS_H__
 | 
			
		||||
#define __PROC_ACARS_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "rssi_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_decimate.hpp"
 | 
			
		||||
 | 
			
		||||
#include "spectrum_collector.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "rssi_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#include "channel_decimator.hpp"
 | 
			
		||||
#include "matched_filter.hpp"
 | 
			
		||||
 | 
			
		||||
#include "clock_recovery.hpp"
 | 
			
		||||
#include "symbol_coding.hpp"
 | 
			
		||||
#include "packet_builder.hpp"
 | 
			
		||||
#include "baseband_packet.hpp"
 | 
			
		||||
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <bitset>
 | 
			
		||||
 | 
			
		||||
// AIS:
 | 
			
		||||
// IN: 2457600/8/8 = 38400
 | 
			
		||||
// Offset: 2457600/4 = 614400 (614400/8/8 = 9600)
 | 
			
		||||
// Deviation: 2400
 | 
			
		||||
// Symbol: 9600
 | 
			
		||||
// Decimate: 2
 | 
			
		||||
// 4 taps, 1 symbol, 1/4 cycle
 | 
			
		||||
 | 
			
		||||
// TPMS:
 | 
			
		||||
// IN: 2457600/4/2 = 307200
 | 
			
		||||
// Offset: 2457600/4 = 614400 (614400/4/2 = 76800)
 | 
			
		||||
// Deviation: 38400
 | 
			
		||||
// Symbol: 19200
 | 
			
		||||
// Decimate: 8
 | 
			
		||||
// 16 taps, 1 symbol, 2 cycles
 | 
			
		||||
 | 
			
		||||
// ACARS:
 | 
			
		||||
// IN: 2457600/8/8 = 38400
 | 
			
		||||
// Offset: 2457600/4 = 614400 (614400/8/8 = 9600)
 | 
			
		||||
// Deviation: ???
 | 
			
		||||
// Symbol: 2400
 | 
			
		||||
// Decimate: 8
 | 
			
		||||
// 16 taps, 1 symbol, 2 cycles
 | 
			
		||||
 | 
			
		||||
// Number of taps: size of one symbol in samples (in/symbol)
 | 
			
		||||
// Cycles: 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Translate+rectangular filter
 | 
			
		||||
// sample=38.4k, deviation=4800, symbol=2400
 | 
			
		||||
// Length: 16 taps, 1 symbol, 2 cycles of sinusoid
 | 
			
		||||
// This is actually the same as rect_taps_307k2_38k4_1t_19k2_p
 | 
			
		||||
constexpr std::array<std::complex<float>, 16> rect_taps_38k4_4k8_1t_2k4_p { {
 | 
			
		||||
	{  6.2500000000e-02f,  0.0000000000e+00f }, {  4.4194173824e-02f,  4.4194173824e-02f },
 | 
			
		||||
	{  0.0000000000e+00f,  6.2500000000e-02f }, { -4.4194173824e-02f,  4.4194173824e-02f },
 | 
			
		||||
	{ -6.2500000000e-02f,  0.0000000000e+00f }, { -4.4194173824e-02f, -4.4194173824e-02f },
 | 
			
		||||
	{  0.0000000000e+00f, -6.2500000000e-02f }, {  4.4194173824e-02f, -4.4194173824e-02f },
 | 
			
		||||
	{  6.2500000000e-02f,  0.0000000000e+00f }, {  4.4194173824e-02f,  4.4194173824e-02f },
 | 
			
		||||
	{  0.0000000000e+00f,  6.2500000000e-02f }, { -4.4194173824e-02f,  4.4194173824e-02f },
 | 
			
		||||
	{ -6.2500000000e-02f,  0.0000000000e+00f }, { -4.4194173824e-02f, -4.4194173824e-02f },
 | 
			
		||||
	{  0.0000000000e+00f, -6.2500000000e-02f }, {  4.4194173824e-02f, -4.4194173824e-02f },
 | 
			
		||||
} };
 | 
			
		||||
 | 
			
		||||
class ACARSProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	ACARSProcessor();
 | 
			
		||||
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr size_t baseband_fs = 2457600;
 | 
			
		||||
 | 
			
		||||
	BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
 | 
			
		||||
	RSSIThread rssi_thread { NORMALPRIO + 10 };
 | 
			
		||||
 | 
			
		||||
	std::array<complex16_t, 512> dst { };
 | 
			
		||||
	const buffer_c16_t dst_buffer {
 | 
			
		||||
		dst.data(),
 | 
			
		||||
		dst.size()
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { };	// Translate already done here !
 | 
			
		||||
	dsp::decimate::FIRC16xR16x32Decim8 decim_1 { };
 | 
			
		||||
	dsp::matched_filter::MatchedFilter mf { rect_taps_38k4_4k8_1t_2k4_p, 8 };
 | 
			
		||||
 | 
			
		||||
	clock_recovery::ClockRecovery<clock_recovery::FixedErrorFilter> clock_recovery {
 | 
			
		||||
		4800, 2400, { 0.0555f },
 | 
			
		||||
		[this](const float symbol) { this->consume_symbol(symbol); }
 | 
			
		||||
	};
 | 
			
		||||
	symbol_coding::ACARSDecoder acars_decode { };
 | 
			
		||||
	/*PacketBuilder<BitPattern, NeverMatch, FixedLength> packet_builder {
 | 
			
		||||
		{ 0b011010000110100010000000, 24, 1 },	// SYN, SYN, SOH
 | 
			
		||||
		{ },
 | 
			
		||||
		{ 128 },
 | 
			
		||||
		[this](const baseband::Packet& packet) {
 | 
			
		||||
			this->payload_handler(packet);
 | 
			
		||||
		}
 | 
			
		||||
	};*/
 | 
			
		||||
	baseband::Packet packet { };
 | 
			
		||||
 | 
			
		||||
	void consume_symbol(const float symbol);
 | 
			
		||||
	void payload_handler(const baseband::Packet& packet);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__PROC_ACARS_H__*/
 | 
			
		||||
							
								
								
									
										167
									
								
								Software/portapack-mayhem/firmware/baseband/proc_adsbrx.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								Software/portapack-mayhem/firmware/baseband/proc_adsbrx.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,167 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2017 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_adsbrx.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
#include "sine_table_int8.hpp"
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
using namespace adsb;
 | 
			
		||||
	
 | 
			
		||||
void ADSBRXProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	int8_t re, im;
 | 
			
		||||
	uint32_t mag;
 | 
			
		||||
	uint32_t c;
 | 
			
		||||
	uint8_t bit, byte{};
 | 
			
		||||
	
 | 
			
		||||
	// This is called at 2M/2048 = 977Hz
 | 
			
		||||
	// One pulse = 500ns = 2 samples
 | 
			
		||||
	// One bit = 2 pulses = 1us = 4 samples
 | 
			
		||||
 | 
			
		||||
	if (!configured) return;
 | 
			
		||||
	
 | 
			
		||||
	for (size_t i = 0; i < buffer.count; i++) {
 | 
			
		||||
		
 | 
			
		||||
		// Compute sample's magnitude
 | 
			
		||||
		re = (int32_t)buffer.p[i].real(); // make re float and scale it
 | 
			
		||||
		im = (int32_t)buffer.p[i].imag(); // make re float and scale it
 | 
			
		||||
		mag = ((uint32_t)(re*re) + (uint32_t)(im*im));
 | 
			
		||||
 | 
			
		||||
		if (decoding) {
 | 
			
		||||
			// Decode
 | 
			
		||||
			
 | 
			
		||||
			// 1 bit lasts 2 samples
 | 
			
		||||
			if (sample_count & 1) {
 | 
			
		||||
				if (bit_count >= msgLen)
 | 
			
		||||
				{
 | 
			
		||||
					const ADSBFrameMessage message(frame, amp);
 | 
			
		||||
					shared_memory.application_queue.push(message);
 | 
			
		||||
					decoding = false;
 | 
			
		||||
					bit = (prev_mag > mag) ? 1 : 0;
 | 
			
		||||
				}
 | 
			
		||||
				else 
 | 
			
		||||
				{
 | 
			
		||||
					//confidence = true;
 | 
			
		||||
					bit = (prev_mag > mag) ? 1 : 0;
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				byte = bit | (byte << 1);
 | 
			
		||||
				bit_count++;
 | 
			
		||||
 | 
			
		||||
				// Perform checks at the end of the first byte
 | 
			
		||||
				if (!(bit_count & 7)) {
 | 
			
		||||
 | 
			
		||||
					// Store the byte
 | 
			
		||||
					frame.push_byte(byte);
 | 
			
		||||
 | 
			
		||||
					// Check at the end of the first byte of the message
 | 
			
		||||
					uint8_t df = (byte >> 3);
 | 
			
		||||
					if ( (bit_count == 8) && !(df & 0x10) ) {
 | 
			
		||||
						msgLen = 56; // DFs 16 or greater are long 112. DFs 15 or less are short 56.
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					// Abondon all frames that arent DF17 or DF18 extended squitters
 | 
			
		||||
					if ( (bit_count == 8) && !((df == 17)||(df == 18)) ) {
 | 
			
		||||
						decoding = false;
 | 
			
		||||
						bit = (prev_mag > mag) ? 1 : 0;
 | 
			
		||||
						frame.clear();
 | 
			
		||||
					}
 | 
			
		||||
				} // last bit of a byte
 | 
			
		||||
			} // Second sample of each bit
 | 
			
		||||
			sample_count++;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Continue looking for preamble even if in a packet
 | 
			
		||||
		// switch is new preamble id higher magnitude
 | 
			
		||||
			
 | 
			
		||||
		// Shift the preamble
 | 
			
		||||
		for (c = 0; c < (ADSB_PREAMBLE_LENGTH ); c++) { shifter[c] = shifter[c + 1]; }
 | 
			
		||||
		shifter[ADSB_PREAMBLE_LENGTH] = mag;
 | 
			
		||||
			
 | 
			
		||||
		// First check of relations between the first 10 samples
 | 
			
		||||
		// representing a valid preamble. We don't even investigate further
 | 
			
		||||
		// if this simple test is not passed
 | 
			
		||||
		if (shifter[0] < shifter[1] && 
 | 
			
		||||
			shifter[1] > shifter[2] &&
 | 
			
		||||
			shifter[2] < shifter[3] &&
 | 
			
		||||
			shifter[3] > shifter[4] &&
 | 
			
		||||
			shifter[4] < shifter[1] &&
 | 
			
		||||
			shifter[5] < shifter[1] &&
 | 
			
		||||
			shifter[6] < shifter[1] &&
 | 
			
		||||
			shifter[7] < shifter[1] &&
 | 
			
		||||
			shifter[8] > shifter[9] &&
 | 
			
		||||
			shifter[9] < shifter[10] &&
 | 
			
		||||
			shifter[10]> shifter[11] )
 | 
			
		||||
		{
 | 
			
		||||
			// The samples between the two spikes must be < than the average
 | 
			
		||||
			// of the high spikes level. We don't test bits too near to
 | 
			
		||||
			// the high levels as signals can be out of phase so part of the
 | 
			
		||||
			// energy can be in the near samples
 | 
			
		||||
			int32_t thisAmp = (shifter[1] + shifter[3] + shifter[8] + shifter[10]);
 | 
			
		||||
			uint32_t high = thisAmp / 9;
 | 
			
		||||
			if (
 | 
			
		||||
				shifter[5] < high &&
 | 
			
		||||
				shifter[6] < high &&
 | 
			
		||||
				// Similarly samples in the range 11-13 must be low, as it is the
 | 
			
		||||
				// space between the preamble and real data. Again we don't test
 | 
			
		||||
				// bits too near to high levels, see above
 | 
			
		||||
				shifter[12] < high &&
 | 
			
		||||
				shifter[13] < high &&
 | 
			
		||||
				shifter[14] < high )
 | 
			
		||||
			{
 | 
			
		||||
				if ((decoding == false) ||					   // New preamble
 | 
			
		||||
					((decoding == true) && (thisAmp > amp)))   // Higher power than existing packet
 | 
			
		||||
				{
 | 
			
		||||
					decoding = true;
 | 
			
		||||
					msgLen = 112;
 | 
			
		||||
					amp = thisAmp;
 | 
			
		||||
					sample_count = 0;
 | 
			
		||||
					bit_count = 0;
 | 
			
		||||
					frame.clear();
 | 
			
		||||
				}
 | 
			
		||||
			} // 4 & 5 low and 11-14 low
 | 
			
		||||
		} // Check for preamble pattern
 | 
			
		||||
 | 
			
		||||
		// Store mag for next time
 | 
			
		||||
		prev_mag = mag;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ADSBRXProcessor::on_message(const Message* const message) {
 | 
			
		||||
	if (message->id == Message::ID::ADSBConfigure) {
 | 
			
		||||
		bit_count = 0;
 | 
			
		||||
		sample_count = 0;
 | 
			
		||||
		decoding = false;
 | 
			
		||||
		configured = true;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<ADSBRXProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										63
									
								
								Software/portapack-mayhem/firmware/baseband/proc_adsbrx.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								Software/portapack-mayhem/firmware/baseband/proc_adsbrx.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2017 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_ADSBRX_H__
 | 
			
		||||
#define __PROC_ADSBRX_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "rssi_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#include "adsb_frame.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace adsb;
 | 
			
		||||
 | 
			
		||||
#define ADSB_PREAMBLE_LENGTH 16
 | 
			
		||||
 | 
			
		||||
class ADSBRXProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
	
 | 
			
		||||
	void on_message(const Message* const message) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr size_t baseband_fs = 2000000;
 | 
			
		||||
	
 | 
			
		||||
	BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
 | 
			
		||||
	RSSIThread rssi_thread { NORMALPRIO + 10 };
 | 
			
		||||
	
 | 
			
		||||
	ADSBFrame frame { };
 | 
			
		||||
	bool configured { false };
 | 
			
		||||
	uint32_t prev_mag { 0 };
 | 
			
		||||
	size_t bit_count { 0 }, sample_count { 0 };
 | 
			
		||||
	size_t msgLen{ 112 };
 | 
			
		||||
	uint32_t shifter[ADSB_PREAMBLE_LENGTH+1];
 | 
			
		||||
	bool decoding { };
 | 
			
		||||
	bool preamble { }, active { };
 | 
			
		||||
    uint16_t bit_pos { 0 };
 | 
			
		||||
    uint8_t cur_bit { 0 };
 | 
			
		||||
	uint32_t sample { 0 };
 | 
			
		||||
	int32_t re { }, im { };
 | 
			
		||||
	int32_t amp {0};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										73
									
								
								Software/portapack-mayhem/firmware/baseband/proc_adsbtx.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								Software/portapack-mayhem/firmware/baseband/proc_adsbtx.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_adsbtx.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
#include "sine_table_int8.hpp"
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
void ADSBTXProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	
 | 
			
		||||
	// This is called at 4M/2048 = 1953Hz
 | 
			
		||||
	// One pulse = 500ns = 2 samples
 | 
			
		||||
	// One bit = 2 pulses = 1us = 4 samples
 | 
			
		||||
	// Test this with ./dump1090 --freq 434000000 --gain 20
 | 
			
		||||
	// Or ./dump1090 --freq 434000000 --gain 20 --interactive --net --net-http-port 8080 --net-beast
 | 
			
		||||
	
 | 
			
		||||
	if (!configured) return;
 | 
			
		||||
 | 
			
		||||
	for (size_t i = 0; i < buffer.count; i++) {
 | 
			
		||||
		if (bit_pos >= (240 << 1)) {
 | 
			
		||||
			configured = false;
 | 
			
		||||
			cur_bit = 0;
 | 
			
		||||
		} else {
 | 
			
		||||
			cur_bit = shared_memory.bb_data.data[bit_pos >> 1];
 | 
			
		||||
			bit_pos++;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if (cur_bit) {
 | 
			
		||||
			// Crude AM
 | 
			
		||||
			buffer.p[i] = am_lut[phase & 3];
 | 
			
		||||
			phase++;
 | 
			
		||||
		} else {
 | 
			
		||||
			buffer.p[i] = { 0, 0 };
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ADSBTXProcessor::on_message(const Message* const p) {
 | 
			
		||||
	const auto message = *reinterpret_cast<const ADSBConfigureMessage*>(p);
 | 
			
		||||
	
 | 
			
		||||
	if (message.id == Message::ID::ADSBConfigure) {
 | 
			
		||||
		bit_pos = 0;
 | 
			
		||||
		phase = 0;
 | 
			
		||||
		configured = true;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<ADSBTXProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								Software/portapack-mayhem/firmware/baseband/proc_adsbtx.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								Software/portapack-mayhem/firmware/baseband/proc_adsbtx.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_ADSBTX_H__
 | 
			
		||||
#define __PROC_ADSBTX_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
 | 
			
		||||
class ADSBTXProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
	
 | 
			
		||||
	void on_message(const Message* const p) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	bool configured = false;
 | 
			
		||||
	
 | 
			
		||||
	BasebandThread baseband_thread { 4000000, this, NORMALPRIO + 20, baseband::Direction::Transmit };
 | 
			
		||||
	
 | 
			
		||||
	const complex8_t am_lut[4] = {
 | 
			
		||||
		{ 127, 0 },
 | 
			
		||||
		{ 0, 127 },
 | 
			
		||||
		{ -127, 0 },
 | 
			
		||||
		{ 0, -127 }		
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
    uint32_t bit_pos { 0 };
 | 
			
		||||
    uint32_t cur_bit { 0 };
 | 
			
		||||
	uint32_t phase { 0 };
 | 
			
		||||
	
 | 
			
		||||
	TXProgressMessage txprogress_message { };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										124
									
								
								Software/portapack-mayhem/firmware/baseband/proc_afsk.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								Software/portapack-mayhem/firmware/baseband/proc_afsk.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,124 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_afsk.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
#include "sine_table_int8.hpp"
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
void AFSKProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	
 | 
			
		||||
	// This is called at 2.28M/2048 = 1113Hz
 | 
			
		||||
	
 | 
			
		||||
	if (!configured) return;
 | 
			
		||||
	
 | 
			
		||||
	for (size_t i = 0; i<buffer.count; i++) {
 | 
			
		||||
 | 
			
		||||
		if (sample_count >= afsk_samples_per_bit) {
 | 
			
		||||
			if (configured) {
 | 
			
		||||
				cur_word = *word_ptr;
 | 
			
		||||
				
 | 
			
		||||
				if (!cur_word) {
 | 
			
		||||
					// End of data
 | 
			
		||||
					if (repeat_counter < afsk_repeat) {
 | 
			
		||||
						// Repeat
 | 
			
		||||
						bit_pos = 0;
 | 
			
		||||
						word_ptr = (uint16_t*)shared_memory.bb_data.data;
 | 
			
		||||
						cur_word = *word_ptr;
 | 
			
		||||
						txprogress_message.done = false;
 | 
			
		||||
						txprogress_message.progress = repeat_counter + 1;
 | 
			
		||||
						shared_memory.application_queue.push(txprogress_message);
 | 
			
		||||
						repeat_counter++;
 | 
			
		||||
					} else {
 | 
			
		||||
						// Stop
 | 
			
		||||
						cur_word = 0;
 | 
			
		||||
						txprogress_message.done = true;
 | 
			
		||||
						shared_memory.application_queue.push(txprogress_message);
 | 
			
		||||
						configured = false;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			cur_bit = (cur_word >> (symbol_count - bit_pos)) & 1;
 | 
			
		||||
 | 
			
		||||
			if (bit_pos >= symbol_count) {
 | 
			
		||||
				bit_pos = 0;
 | 
			
		||||
				word_ptr++;
 | 
			
		||||
			} else {
 | 
			
		||||
				bit_pos++;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			sample_count = 0;
 | 
			
		||||
		} else {
 | 
			
		||||
			sample_count++;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if (cur_bit)
 | 
			
		||||
			tone_phase += afsk_phase_inc_mark;
 | 
			
		||||
		else
 | 
			
		||||
			tone_phase += afsk_phase_inc_space;
 | 
			
		||||
 | 
			
		||||
		tone_sample = sine_table_i8[(tone_phase & 0xFF000000U) >> 24];
 | 
			
		||||
 | 
			
		||||
		delta = tone_sample * fm_delta;
 | 
			
		||||
		
 | 
			
		||||
		phase += delta;
 | 
			
		||||
		sphase = phase + (64 << 24);
 | 
			
		||||
 | 
			
		||||
		re = (sine_table_i8[(sphase & 0xFF000000U) >> 24]);
 | 
			
		||||
		im = (sine_table_i8[(phase & 0xFF000000U) >> 24]);
 | 
			
		||||
			
 | 
			
		||||
		buffer.p[i] = {re, im};
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AFSKProcessor::on_message(const Message* const msg) {
 | 
			
		||||
	const auto message = *reinterpret_cast<const AFSKTxConfigureMessage*>(msg);
 | 
			
		||||
	
 | 
			
		||||
	if (message.id == Message::ID::AFSKTxConfigure) {
 | 
			
		||||
		if (message.samples_per_bit) {
 | 
			
		||||
			afsk_samples_per_bit = message.samples_per_bit;
 | 
			
		||||
			afsk_phase_inc_mark = message.phase_inc_mark * AFSK_DELTA_COEF;
 | 
			
		||||
			afsk_phase_inc_space = message.phase_inc_space * AFSK_DELTA_COEF;
 | 
			
		||||
			afsk_repeat = message.repeat - 1;
 | 
			
		||||
			fm_delta = message.fm_delta * (0xFFFFFFULL / AFSK_SAMPLERATE);
 | 
			
		||||
			symbol_count = message.symbol_count - 1;
 | 
			
		||||
 | 
			
		||||
			sample_count = afsk_samples_per_bit;
 | 
			
		||||
			repeat_counter = 0;
 | 
			
		||||
			bit_pos = 0;
 | 
			
		||||
			word_ptr = (uint16_t*)shared_memory.bb_data.data;
 | 
			
		||||
			cur_word = 0;
 | 
			
		||||
			cur_bit = 0;
 | 
			
		||||
			configured = true;
 | 
			
		||||
		} else
 | 
			
		||||
			configured = false;		// Kill
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<AFSKProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										64
									
								
								Software/portapack-mayhem/firmware/baseband/proc_afsk.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								Software/portapack-mayhem/firmware/baseband/proc_afsk.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_AFSK_H__
 | 
			
		||||
#define __PROC_AFSK_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#define AFSK_SAMPLERATE 1536000
 | 
			
		||||
#define AFSK_DELTA_COEF ((1ULL << 32) / AFSK_SAMPLERATE)
 | 
			
		||||
 | 
			
		||||
class AFSKProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
	
 | 
			
		||||
	void on_message(const Message* const msg) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	bool configured = false;
 | 
			
		||||
	
 | 
			
		||||
	BasebandThread baseband_thread { AFSK_SAMPLERATE, this, NORMALPRIO + 20, baseband::Direction::Transmit };
 | 
			
		||||
	
 | 
			
		||||
	uint32_t afsk_samples_per_bit { 0 };
 | 
			
		||||
	uint32_t afsk_phase_inc_mark { 0 };
 | 
			
		||||
	uint32_t afsk_phase_inc_space { 0 };
 | 
			
		||||
	uint8_t afsk_repeat { 0 };
 | 
			
		||||
	uint32_t fm_delta { 0 };
 | 
			
		||||
	uint8_t symbol_count { 0 };
 | 
			
		||||
	
 | 
			
		||||
	uint8_t repeat_counter { 0 };
 | 
			
		||||
    uint8_t bit_pos { 0 };
 | 
			
		||||
    uint16_t * word_ptr { };
 | 
			
		||||
    uint16_t cur_word { 0 };
 | 
			
		||||
    uint8_t cur_bit { 0 };
 | 
			
		||||
    uint32_t sample_count { 0 };
 | 
			
		||||
	uint32_t tone_phase { 0 }, phase { 0 }, sphase { 0 };
 | 
			
		||||
	int32_t tone_sample { 0 }, delta { 0 };
 | 
			
		||||
	
 | 
			
		||||
	int8_t re { 0 }, im { 0 };
 | 
			
		||||
	
 | 
			
		||||
	TXProgressMessage txprogress_message { };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										191
									
								
								Software/portapack-mayhem/firmware/baseband/proc_afskrx.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								Software/portapack-mayhem/firmware/baseband/proc_afskrx.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,191 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_afskrx.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
void AFSKRxProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	// This is called at 3072000 / 2048 = 1500Hz
 | 
			
		||||
 | 
			
		||||
	if (!configured) return;
 | 
			
		||||
	
 | 
			
		||||
	// FM demodulation
 | 
			
		||||
	const auto decim_0_out = decim_0.execute(buffer, dst_buffer);				// 2048 / 8 = 256 (512 I/Q samples)
 | 
			
		||||
	const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer);			// 256 / 8 = 32 (64 I/Q samples)
 | 
			
		||||
	const auto channel_out = channel_filter.execute(decim_1_out, dst_buffer);	// 32 / 2 = 16 (32 I/Q samples)
 | 
			
		||||
 | 
			
		||||
	feed_channel_stats(channel_out);
 | 
			
		||||
	
 | 
			
		||||
	auto audio = demod.execute(channel_out, audio_buffer);
 | 
			
		||||
	
 | 
			
		||||
	audio_output.write(audio);
 | 
			
		||||
 | 
			
		||||
	// Audio signal processing
 | 
			
		||||
	for (size_t c = 0; c < audio.count; c++) {
 | 
			
		||||
 | 
			
		||||
		const int32_t sample_int = audio.p[c] * 32768.0f;
 | 
			
		||||
		int32_t current_sample = __SSAT(sample_int, 16);
 | 
			
		||||
		
 | 
			
		||||
		current_sample /= 128;
 | 
			
		||||
		
 | 
			
		||||
		// Delay line put
 | 
			
		||||
		delay_line[delay_line_index & 0x3F] = current_sample;
 | 
			
		||||
		
 | 
			
		||||
		// Delay line get, and LPF
 | 
			
		||||
		sample_mixed = (delay_line[(delay_line_index - (samples_per_bit/2)) & 0x3F] * current_sample) / 4;
 | 
			
		||||
		sample_filtered = prev_mixed + sample_mixed + (prev_filtered / 2);
 | 
			
		||||
		
 | 
			
		||||
		delay_line_index++;
 | 
			
		||||
		
 | 
			
		||||
		prev_filtered = sample_filtered;
 | 
			
		||||
		prev_mixed = sample_mixed;
 | 
			
		||||
		
 | 
			
		||||
		// Slice
 | 
			
		||||
		sample_bits <<= 1;
 | 
			
		||||
		sample_bits |= (sample_filtered < -20) ? 1 : 0;
 | 
			
		||||
		
 | 
			
		||||
		// Check for "clean" transition: either 0011 or 1100
 | 
			
		||||
		if ((((sample_bits >> 2) ^ sample_bits) & 3) == 3) {
 | 
			
		||||
			// Adjust phase
 | 
			
		||||
			if (phase < 0x8000)
 | 
			
		||||
				phase += 0x800;		// Is this a proper value ?
 | 
			
		||||
			else
 | 
			
		||||
				phase -= 0x800;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		phase += phase_inc;
 | 
			
		||||
		
 | 
			
		||||
		if (phase >= 0x10000) {
 | 
			
		||||
			phase &= 0xFFFF;
 | 
			
		||||
			
 | 
			
		||||
			if (trigger_word) {
 | 
			
		||||
				
 | 
			
		||||
				// Continuous-stream value-triggered mode (AX.25) - UNTESTED
 | 
			
		||||
				word_bits <<= 1;
 | 
			
		||||
				word_bits |= (sample_bits & 1);
 | 
			
		||||
				
 | 
			
		||||
				bit_counter++;
 | 
			
		||||
				
 | 
			
		||||
				if (triggered) {
 | 
			
		||||
					if (bit_counter == word_length) {
 | 
			
		||||
						bit_counter = 0;
 | 
			
		||||
						
 | 
			
		||||
						data_message.is_data = true;
 | 
			
		||||
						data_message.value = word_bits & word_mask;
 | 
			
		||||
						shared_memory.application_queue.push(data_message);
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					if ((word_bits & word_mask) == trigger_value) {
 | 
			
		||||
						triggered = !triggered;
 | 
			
		||||
						bit_counter = 0;
 | 
			
		||||
						
 | 
			
		||||
						data_message.is_data = true;
 | 
			
		||||
						data_message.value = trigger_value;
 | 
			
		||||
						shared_memory.application_queue.push(data_message);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
			} else {
 | 
			
		||||
				
 | 
			
		||||
				// RS232-like modem mode
 | 
			
		||||
				if (state == WAIT_START) {
 | 
			
		||||
					if (!(sample_bits & 1)) {
 | 
			
		||||
						// Got start bit
 | 
			
		||||
						state = RECEIVE;
 | 
			
		||||
						bit_counter = 0;
 | 
			
		||||
					}
 | 
			
		||||
				} else if (state == WAIT_STOP) {
 | 
			
		||||
					if (sample_bits & 1) {
 | 
			
		||||
						// Got stop bit
 | 
			
		||||
						state = WAIT_START;
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					word_bits <<= 1;
 | 
			
		||||
					word_bits |= (sample_bits & 1);
 | 
			
		||||
					
 | 
			
		||||
					bit_counter++;
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				if (bit_counter == word_length) {
 | 
			
		||||
					bit_counter = 0;
 | 
			
		||||
					state = WAIT_STOP;
 | 
			
		||||
					
 | 
			
		||||
					data_message.is_data = true;
 | 
			
		||||
					data_message.value = word_bits;
 | 
			
		||||
					shared_memory.application_queue.push(data_message);
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AFSKRxProcessor::on_message(const Message* const message) {
 | 
			
		||||
	if (message->id == Message::ID::AFSKRxConfigure)
 | 
			
		||||
		configure(*reinterpret_cast<const AFSKRxConfigureMessage*>(message));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AFSKRxProcessor::configure(const AFSKRxConfigureMessage& message) {
 | 
			
		||||
	/*constexpr size_t decim_0_input_fs = baseband_fs;
 | 
			
		||||
	constexpr size_t decim_0_output_fs = decim_0_input_fs / decim_0.decimation_factor;
 | 
			
		||||
 | 
			
		||||
	constexpr size_t decim_1_input_fs = decim_0_output_fs;
 | 
			
		||||
	constexpr size_t decim_1_output_fs = decim_1_input_fs / decim_1.decimation_factor;
 | 
			
		||||
	
 | 
			
		||||
	constexpr size_t channel_filter_input_fs = decim_1_output_fs;
 | 
			
		||||
	const size_t channel_filter_output_fs = channel_filter_input_fs / 2;
 | 
			
		||||
 | 
			
		||||
	const size_t demod_input_fs = channel_filter_output_fs;*/
 | 
			
		||||
	
 | 
			
		||||
	decim_0.configure(taps_11k0_decim_0.taps, 33554432);
 | 
			
		||||
	decim_1.configure(taps_11k0_decim_1.taps, 131072);
 | 
			
		||||
	channel_filter.configure(taps_11k0_channel.taps, 2);
 | 
			
		||||
	demod.configure(audio_fs, 5000);
 | 
			
		||||
 | 
			
		||||
	audio_output.configure(audio_24k_hpf_300hz_config, audio_24k_deemph_300_6_config, 0);
 | 
			
		||||
	
 | 
			
		||||
	samples_per_bit = audio_fs / message.baudrate;
 | 
			
		||||
	
 | 
			
		||||
	phase_inc = (0x10000 * message.baudrate) / audio_fs;
 | 
			
		||||
	phase = 0;
 | 
			
		||||
	
 | 
			
		||||
	trigger_word = message.trigger_word;
 | 
			
		||||
	word_length = message.word_length;
 | 
			
		||||
	trigger_value = message.trigger_value;
 | 
			
		||||
	word_mask = (1 << word_length) - 1;
 | 
			
		||||
	
 | 
			
		||||
	// Delay line
 | 
			
		||||
	delay_line_index = 0;
 | 
			
		||||
	
 | 
			
		||||
	triggered = false;
 | 
			
		||||
	state = WAIT_START;
 | 
			
		||||
	
 | 
			
		||||
	configured = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<AFSKRxProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										103
									
								
								Software/portapack-mayhem/firmware/baseband/proc_afskrx.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								Software/portapack-mayhem/firmware/baseband/proc_afskrx.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_AFSKRX_H__
 | 
			
		||||
#define __PROC_AFSKRX_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "rssi_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_decimate.hpp"
 | 
			
		||||
#include "dsp_demodulate.hpp"
 | 
			
		||||
 | 
			
		||||
#include "audio_output.hpp"
 | 
			
		||||
 | 
			
		||||
#include "fifo.hpp"
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
 | 
			
		||||
class AFSKRxProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
 | 
			
		||||
	void on_message(const Message* const message) override;
 | 
			
		||||
	
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr size_t baseband_fs = 3072000;
 | 
			
		||||
	static constexpr size_t audio_fs = baseband_fs / 8 / 8 / 2;
 | 
			
		||||
	
 | 
			
		||||
	size_t samples_per_bit { };
 | 
			
		||||
	
 | 
			
		||||
	enum State {
 | 
			
		||||
		WAIT_START = 0,
 | 
			
		||||
		WAIT_STOP,
 | 
			
		||||
		RECEIVE
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
 | 
			
		||||
	RSSIThread rssi_thread { NORMALPRIO + 10 };
 | 
			
		||||
	
 | 
			
		||||
	std::array<complex16_t, 512> dst { };
 | 
			
		||||
	const buffer_c16_t dst_buffer {
 | 
			
		||||
		dst.data(),
 | 
			
		||||
		dst.size()
 | 
			
		||||
	};
 | 
			
		||||
	std::array<float, 32> audio { };
 | 
			
		||||
	const buffer_f32_t audio_buffer {
 | 
			
		||||
		audio.data(),
 | 
			
		||||
		audio.size()
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	// Array size ok down to 375 bauds (24000 / 375)
 | 
			
		||||
	std::array<int32_t, 64> delay_line { 0 };
 | 
			
		||||
	
 | 
			
		||||
	dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { };
 | 
			
		||||
	dsp::decimate::FIRC16xR16x32Decim8 decim_1 { };
 | 
			
		||||
	dsp::decimate::FIRAndDecimateComplex channel_filter { };
 | 
			
		||||
	
 | 
			
		||||
	dsp::demodulate::FM demod { };
 | 
			
		||||
	
 | 
			
		||||
	AudioOutput audio_output { };
 | 
			
		||||
 | 
			
		||||
	State state { };
 | 
			
		||||
	size_t delay_line_index { };
 | 
			
		||||
	uint32_t bit_counter { 0 };
 | 
			
		||||
	uint32_t word_bits { 0 };
 | 
			
		||||
	uint32_t sample_bits { 0 };
 | 
			
		||||
	uint32_t phase { }, phase_inc { };
 | 
			
		||||
	int32_t sample_mixed { }, prev_mixed { }, sample_filtered { }, prev_filtered { };
 | 
			
		||||
	uint32_t word_length { };
 | 
			
		||||
	uint32_t word_mask { };
 | 
			
		||||
	uint32_t trigger_value { };
 | 
			
		||||
	
 | 
			
		||||
	bool configured { false };
 | 
			
		||||
	bool wait_start { };
 | 
			
		||||
	bool bit_value { };
 | 
			
		||||
	bool trigger_word { };
 | 
			
		||||
	bool triggered { };
 | 
			
		||||
	
 | 
			
		||||
	void configure(const AFSKRxConfigureMessage& message);
 | 
			
		||||
	
 | 
			
		||||
	AFSKDataMessage data_message { false, 0 };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__PROC_TPMS_H__*/
 | 
			
		||||
							
								
								
									
										72
									
								
								Software/portapack-mayhem/firmware/baseband/proc_ais.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								Software/portapack-mayhem/firmware/baseband/proc_ais.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_ais.hpp"
 | 
			
		||||
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_fir_taps.hpp"
 | 
			
		||||
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
AISProcessor::AISProcessor() {
 | 
			
		||||
	decim_0.configure(taps_11k0_decim_0.taps, 33554432);
 | 
			
		||||
	decim_1.configure(taps_11k0_decim_1.taps, 131072);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AISProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	/* 2.4576MHz, 2048 samples */
 | 
			
		||||
 | 
			
		||||
	const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
 | 
			
		||||
	const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer);
 | 
			
		||||
	const auto decimator_out = decim_1_out;
 | 
			
		||||
 | 
			
		||||
	/* 38.4kHz, 32 samples */
 | 
			
		||||
	feed_channel_stats(decimator_out);
 | 
			
		||||
 | 
			
		||||
	for(size_t i=0; i<decimator_out.count; i++) {
 | 
			
		||||
		if( mf.execute_once(decimator_out.p[i]) ) {
 | 
			
		||||
			clock_recovery(mf.get_output());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AISProcessor::consume_symbol(
 | 
			
		||||
	const float raw_symbol
 | 
			
		||||
) {
 | 
			
		||||
	const uint_fast8_t sliced_symbol = (raw_symbol >= 0.0f) ? 1 : 0;
 | 
			
		||||
	const auto decoded_symbol = nrzi_decode(sliced_symbol);
 | 
			
		||||
 | 
			
		||||
	packet_builder.execute(decoded_symbol);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AISProcessor::payload_handler(
 | 
			
		||||
	const baseband::Packet& packet
 | 
			
		||||
) {
 | 
			
		||||
	const AISPacketMessage message { packet };
 | 
			
		||||
	shared_memory.application_queue.push(message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<AISProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										85
									
								
								Software/portapack-mayhem/firmware/baseband/proc_ais.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								Software/portapack-mayhem/firmware/baseband/proc_ais.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_AIS_H__
 | 
			
		||||
#define __PROC_AIS_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "rssi_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#include "channel_decimator.hpp"
 | 
			
		||||
#include "matched_filter.hpp"
 | 
			
		||||
 | 
			
		||||
#include "clock_recovery.hpp"
 | 
			
		||||
#include "symbol_coding.hpp"
 | 
			
		||||
#include "packet_builder.hpp"
 | 
			
		||||
#include "baseband_packet.hpp"
 | 
			
		||||
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <bitset>
 | 
			
		||||
 | 
			
		||||
#include "ais_baseband.hpp"
 | 
			
		||||
 | 
			
		||||
class AISProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	AISProcessor();
 | 
			
		||||
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr size_t baseband_fs = 2457600;
 | 
			
		||||
 | 
			
		||||
	BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
 | 
			
		||||
	RSSIThread rssi_thread { NORMALPRIO + 10 };
 | 
			
		||||
 | 
			
		||||
	std::array<complex16_t, 512> dst { };
 | 
			
		||||
	const buffer_c16_t dst_buffer {
 | 
			
		||||
		dst.data(),
 | 
			
		||||
		dst.size()
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { };
 | 
			
		||||
	dsp::decimate::FIRC16xR16x32Decim8 decim_1 { };
 | 
			
		||||
	dsp::matched_filter::MatchedFilter mf { baseband::ais::square_taps_38k4_1t_p, 2 };
 | 
			
		||||
 | 
			
		||||
	clock_recovery::ClockRecovery<clock_recovery::FixedErrorFilter> clock_recovery {
 | 
			
		||||
		19200, 9600, { 0.0555f },
 | 
			
		||||
		[this](const float symbol) { this->consume_symbol(symbol); }
 | 
			
		||||
	};
 | 
			
		||||
	symbol_coding::NRZIDecoder nrzi_decode { };
 | 
			
		||||
	PacketBuilder<BitPattern, BitPattern, BitPattern> packet_builder {
 | 
			
		||||
		{ 0b0101010101111110, 16, 1 },
 | 
			
		||||
		{ 0b111110, 6 },
 | 
			
		||||
		{ 0b01111110, 8 },
 | 
			
		||||
		[this](const baseband::Packet& packet) {
 | 
			
		||||
			this->payload_handler(packet);
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	void consume_symbol(const float symbol);
 | 
			
		||||
	void payload_handler(const baseband::Packet& packet);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__PROC_AIS_H__*/
 | 
			
		||||
							
								
								
									
										118
									
								
								Software/portapack-mayhem/firmware/baseband/proc_am_audio.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								Software/portapack-mayhem/firmware/baseband/proc_am_audio.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_am_audio.hpp"
 | 
			
		||||
 | 
			
		||||
#include "audio_output.hpp"
 | 
			
		||||
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
void NarrowbandAMAudio::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	if( !configured ) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
 | 
			
		||||
	const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer);
 | 
			
		||||
 | 
			
		||||
	channel_spectrum.feed(decim_1_out, channel_filter_low_f, channel_filter_high_f, channel_filter_transition);
 | 
			
		||||
 | 
			
		||||
	const auto decim_2_out = decim_2.execute(decim_1_out, dst_buffer);
 | 
			
		||||
	const auto channel_out = channel_filter.execute(decim_2_out, dst_buffer);
 | 
			
		||||
 | 
			
		||||
	// TODO: Feed channel_stats post-decimation data?
 | 
			
		||||
	feed_channel_stats(channel_out);
 | 
			
		||||
 | 
			
		||||
	auto audio = demodulate(channel_out);
 | 
			
		||||
	audio_compressor.execute_in_place(audio);
 | 
			
		||||
	audio_output.write(audio);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buffer_f32_t NarrowbandAMAudio::demodulate(const buffer_c16_t& channel) {
 | 
			
		||||
	if( modulation_ssb ) {
 | 
			
		||||
		return demod_ssb.execute(channel, audio_buffer);
 | 
			
		||||
	} else {
 | 
			
		||||
		return demod_am.execute(channel, audio_buffer);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NarrowbandAMAudio::on_message(const Message* const message) {
 | 
			
		||||
	switch(message->id) {
 | 
			
		||||
	case Message::ID::UpdateSpectrum:
 | 
			
		||||
	case Message::ID::SpectrumStreamingConfig:
 | 
			
		||||
		channel_spectrum.on_message(message);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case Message::ID::AMConfigure:
 | 
			
		||||
		configure(*reinterpret_cast<const AMConfigureMessage*>(message));
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case Message::ID::CaptureConfig:
 | 
			
		||||
		capture_config(*reinterpret_cast<const CaptureConfigMessage*>(message));
 | 
			
		||||
		break;
 | 
			
		||||
		
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NarrowbandAMAudio::configure(const AMConfigureMessage& message) {
 | 
			
		||||
	constexpr size_t decim_0_input_fs = baseband_fs;
 | 
			
		||||
	constexpr size_t decim_0_output_fs = decim_0_input_fs / decim_0.decimation_factor;
 | 
			
		||||
 | 
			
		||||
	constexpr size_t decim_1_input_fs = decim_0_output_fs;
 | 
			
		||||
	constexpr size_t decim_1_output_fs = decim_1_input_fs / decim_1.decimation_factor;
 | 
			
		||||
 | 
			
		||||
	constexpr size_t decim_2_input_fs = decim_1_output_fs;
 | 
			
		||||
	constexpr size_t decim_2_output_fs = decim_2_input_fs / decim_2_decimation_factor;
 | 
			
		||||
 | 
			
		||||
	constexpr size_t channel_filter_input_fs = decim_2_output_fs;
 | 
			
		||||
	//const size_t channel_filter_output_fs = channel_filter_input_fs / channel_filter_decimation_factor;
 | 
			
		||||
 | 
			
		||||
	decim_0.configure(message.decim_0_filter.taps, 33554432);
 | 
			
		||||
	decim_1.configure(message.decim_1_filter.taps, 131072);
 | 
			
		||||
	decim_2.configure(message.decim_2_filter.taps, decim_2_decimation_factor);
 | 
			
		||||
	channel_filter.configure(message.channel_filter.taps, channel_filter_decimation_factor);
 | 
			
		||||
	channel_filter_low_f = message.channel_filter.low_frequency_normalized * channel_filter_input_fs;
 | 
			
		||||
	channel_filter_high_f = message.channel_filter.high_frequency_normalized * channel_filter_input_fs;
 | 
			
		||||
	channel_filter_transition = message.channel_filter.transition_normalized * channel_filter_input_fs;
 | 
			
		||||
	channel_spectrum.set_decimation_factor(1.0f);
 | 
			
		||||
	modulation_ssb = (message.modulation == AMConfigureMessage::Modulation::SSB);
 | 
			
		||||
	audio_output.configure(message.audio_hpf_config);
 | 
			
		||||
 | 
			
		||||
	configured = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NarrowbandAMAudio::capture_config(const CaptureConfigMessage& message) {
 | 
			
		||||
	if( message.config ) {
 | 
			
		||||
		audio_output.set_stream(std::make_unique<StreamInput>(message.config));
 | 
			
		||||
	} else {
 | 
			
		||||
		audio_output.set_stream(nullptr);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<NarrowbandAMAudio>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,86 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_AM_AUDIO_H__
 | 
			
		||||
#define __PROC_AM_AUDIO_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "rssi_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_decimate.hpp"
 | 
			
		||||
#include "dsp_demodulate.hpp"
 | 
			
		||||
#include "audio_compressor.hpp"
 | 
			
		||||
 | 
			
		||||
#include "audio_output.hpp"
 | 
			
		||||
#include "spectrum_collector.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
class NarrowbandAMAudio : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
	
 | 
			
		||||
	void on_message(const Message* const message) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr size_t baseband_fs = 3072000;
 | 
			
		||||
	static constexpr size_t decim_2_decimation_factor = 4;
 | 
			
		||||
	static constexpr size_t channel_filter_decimation_factor = 1;
 | 
			
		||||
 | 
			
		||||
	BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
 | 
			
		||||
	RSSIThread rssi_thread { NORMALPRIO + 10 };
 | 
			
		||||
 | 
			
		||||
	std::array<complex16_t, 512> dst { };
 | 
			
		||||
	const buffer_c16_t dst_buffer {
 | 
			
		||||
		dst.data(),
 | 
			
		||||
		dst.size()
 | 
			
		||||
	};
 | 
			
		||||
	std::array<float, 32> audio { };
 | 
			
		||||
	const buffer_f32_t audio_buffer {
 | 
			
		||||
		audio.data(),
 | 
			
		||||
		audio.size()
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { };
 | 
			
		||||
	dsp::decimate::FIRC16xR16x32Decim8 decim_1 { };
 | 
			
		||||
	dsp::decimate::FIRAndDecimateComplex decim_2 { };
 | 
			
		||||
	dsp::decimate::FIRAndDecimateComplex channel_filter { };
 | 
			
		||||
	int32_t channel_filter_low_f = 0;
 | 
			
		||||
	int32_t channel_filter_high_f = 0;
 | 
			
		||||
	int32_t channel_filter_transition = 0;
 | 
			
		||||
 | 
			
		||||
	bool modulation_ssb = false;
 | 
			
		||||
	dsp::demodulate::AM demod_am { };
 | 
			
		||||
	dsp::demodulate::SSB demod_ssb { };
 | 
			
		||||
	FeedForwardCompressor audio_compressor { };
 | 
			
		||||
	AudioOutput audio_output { };
 | 
			
		||||
 | 
			
		||||
	SpectrumCollector channel_spectrum { };
 | 
			
		||||
 | 
			
		||||
	bool configured { false };
 | 
			
		||||
	void configure(const AMConfigureMessage& message);
 | 
			
		||||
	void capture_config(const CaptureConfigMessage& message);
 | 
			
		||||
 | 
			
		||||
	buffer_f32_t demodulate(const buffer_c16_t& channel);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__PROC_AM_AUDIO_H__*/
 | 
			
		||||
							
								
								
									
										88
									
								
								Software/portapack-mayhem/firmware/baseband/proc_am_tv.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								Software/portapack-mayhem/firmware/baseband/proc_am_tv.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 * Copyright (C) 2020 Shao
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_am_tv.hpp"
 | 
			
		||||
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
#include "dsp_fft.hpp"
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
void WidebandFMAudio::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	if( !configured ) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	std::fill(spectrum.begin(), spectrum.end(), 0);
 | 
			
		||||
 | 
			
		||||
	for(size_t i=0; i<spectrum.size(); i++) {
 | 
			
		||||
		spectrum[i] += buffer.p[i];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const buffer_c16_t buffer_c16 {spectrum.data(),spectrum.size(),buffer.sampling_rate};
 | 
			
		||||
	channel_spectrum.feed(buffer_c16);
 | 
			
		||||
 | 
			
		||||
        int8_t re ;
 | 
			
		||||
	//int8_t im;  
 | 
			
		||||
	//int8_t mag;
 | 
			
		||||
 | 
			
		||||
        for (size_t i = 0; i < 128; i++) 
 | 
			
		||||
	{
 | 
			
		||||
		re = buffer.p[i].real();
 | 
			
		||||
		//im = buffer.p[i].imag();
 | 
			
		||||
		//mag = __builtin_sqrtf((re * re) + (im * im)) ;
 | 
			
		||||
		const unsigned int v =  re + 127.0f; //timescope
 | 
			
		||||
		audio_spectrum.db[i] = std::max(0U, std::min(255U, v));
 | 
			
		||||
	}
 | 
			
		||||
	AudioSpectrumMessage message { &audio_spectrum };
 | 
			
		||||
	shared_memory.application_queue.push(message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WidebandFMAudio::on_message(const Message* const message) {
 | 
			
		||||
	switch(message->id) {
 | 
			
		||||
	case Message::ID::UpdateSpectrum:
 | 
			
		||||
	case Message::ID::SpectrumStreamingConfig:
 | 
			
		||||
		channel_spectrum.on_message(message);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case Message::ID::WFMConfigure:
 | 
			
		||||
		configure(*reinterpret_cast<const WFMConfigureMessage*>(message));
 | 
			
		||||
		break;
 | 
			
		||||
		
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WidebandFMAudio::configure(const WFMConfigureMessage& message) {
 | 
			
		||||
	(void)message; // avoid warning
 | 
			
		||||
	configured = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<WidebandFMAudio>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										65
									
								
								Software/portapack-mayhem/firmware/baseband/proc_am_tv.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								Software/portapack-mayhem/firmware/baseband/proc_am_tv.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 * Copyright (C) 2020 Shao
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_AM_TV_H__
 | 
			
		||||
#define __PROC_AM_TV_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "rssi_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_types.hpp"
 | 
			
		||||
#include "dsp_decimate.hpp"
 | 
			
		||||
#include "dsp_demodulate.hpp"
 | 
			
		||||
#include "block_decimator.hpp"
 | 
			
		||||
 | 
			
		||||
#include "tv_collector.hpp"
 | 
			
		||||
 | 
			
		||||
class WidebandFMAudio : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
 | 
			
		||||
	void on_message(const Message* const message) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr size_t baseband_fs = 2000000;
 | 
			
		||||
 | 
			
		||||
	BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
 | 
			
		||||
	RSSIThread rssi_thread { NORMALPRIO + 10 };
 | 
			
		||||
 | 
			
		||||
	std::array<complex16_t, 512> dst { };
 | 
			
		||||
	const buffer_c16_t dst_buffer {
 | 
			
		||||
		dst.data(),
 | 
			
		||||
		dst.size()
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	AudioSpectrum audio_spectrum { };
 | 
			
		||||
	TvCollector channel_spectrum { };
 | 
			
		||||
        std::array<complex16_t, 256> spectrum { };
 | 
			
		||||
 | 
			
		||||
	bool configured { false };
 | 
			
		||||
	void configure(const WFMConfigureMessage& message);
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__PROC_AM_TV_H__*/
 | 
			
		||||
							
								
								
									
										257
									
								
								Software/portapack-mayhem/firmware/baseband/proc_aprsrx.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								Software/portapack-mayhem/firmware/baseband/proc_aprsrx.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,257 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_aprsrx.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include "stdio.h"
 | 
			
		||||
 | 
			
		||||
void APRSRxProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	// This is called at 3072000 / 2048 = 1500Hz
 | 
			
		||||
 | 
			
		||||
	if (!configured) return;
 | 
			
		||||
	
 | 
			
		||||
	// FM demodulation
 | 
			
		||||
	const auto decim_0_out = decim_0.execute(buffer, dst_buffer);				// 2048 / 8 = 256 (512 I/Q samples)
 | 
			
		||||
	const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer);			// 256 / 8 = 32 (64 I/Q samples)
 | 
			
		||||
	const auto channel_out = channel_filter.execute(decim_1_out, dst_buffer);	// 32 / 2 = 16 (32 I/Q samples)
 | 
			
		||||
 | 
			
		||||
	feed_channel_stats(channel_out);
 | 
			
		||||
	
 | 
			
		||||
	auto audio = demod.execute(channel_out, audio_buffer);
 | 
			
		||||
	
 | 
			
		||||
	audio_output.write(audio);
 | 
			
		||||
 | 
			
		||||
	// Audio signal processing
 | 
			
		||||
	for (size_t c = 0; c < audio.count; c++) {
 | 
			
		||||
 | 
			
		||||
		const int32_t sample_int = audio.p[c] * 32768.0f;
 | 
			
		||||
		int32_t current_sample = __SSAT(sample_int, 16);
 | 
			
		||||
		
 | 
			
		||||
		current_sample /= 128;
 | 
			
		||||
		
 | 
			
		||||
		// Delay line put
 | 
			
		||||
		delay_line[delay_line_index & 0x3F] = current_sample;
 | 
			
		||||
		
 | 
			
		||||
		// Delay line get, and LPF
 | 
			
		||||
		sample_mixed = (delay_line[(delay_line_index - (samples_per_bit/2)) & 0x3F] * current_sample) / 4; 
 | 
			
		||||
		sample_filtered = prev_mixed + sample_mixed + (prev_filtered / 2);
 | 
			
		||||
		
 | 
			
		||||
		delay_line_index++;
 | 
			
		||||
		
 | 
			
		||||
		prev_filtered = sample_filtered;
 | 
			
		||||
		prev_mixed = sample_mixed;		
 | 
			
		||||
 | 
			
		||||
		// Slice
 | 
			
		||||
		sample_bits <<= 1;
 | 
			
		||||
 | 
			
		||||
		uint8_t bit = (sample_filtered < -20) ? 1 : 0;
 | 
			
		||||
		sample_bits |= bit;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
		int16_t scaled = bit == 1 ? 32767 : -32767;
 | 
			
		||||
 | 
			
		||||
		if( stream ) {
 | 
			
		||||
			const size_t bytes_to_write = sizeof(scaled) * 1;
 | 
			
		||||
			const auto result = stream->write(&scaled, bytes_to_write);
 | 
			
		||||
		}
 | 
			
		||||
*/
 | 
			
		||||
		
 | 
			
		||||
		// Check for "clean" transition: either 0011 or 1100
 | 
			
		||||
		if ((((sample_bits >> 2) ^ sample_bits) & 3) == 3) {
 | 
			
		||||
			// Adjust phase
 | 
			
		||||
			if (phase < 0x8000)
 | 
			
		||||
				phase += 0x800;		// Is this a proper value ?
 | 
			
		||||
			else
 | 
			
		||||
				phase -= 0x800;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		phase += phase_inc;
 | 
			
		||||
		
 | 
			
		||||
		if (phase >= 0x10000) {
 | 
			
		||||
			phase &= 0xFFFF;
 | 
			
		||||
			
 | 
			
		||||
			if (true) {			
 | 
			
		||||
				uint8_t bit;					
 | 
			
		||||
				if(__builtin_popcount(sample_bits & 0xFF) >= 0x05){
 | 
			
		||||
					bit = 0x1;
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					bit = 0x0;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if(parse_bit(bit)){
 | 
			
		||||
					parse_packet();
 | 
			
		||||
				}						
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void APRSRxProcessor::parse_packet(){
 | 
			
		||||
	//validate crc	
 | 
			
		||||
	if(packet_buffer_size >= aprs::APRS_MIN_LENGTH){
 | 
			
		||||
		uint16_t crc = 0xFFFF;
 | 
			
		||||
 | 
			
		||||
		for(size_t i = 0; i < packet_buffer_size; i++){			
 | 
			
		||||
			uint8_t byte = packet_buffer[i];
 | 
			
		||||
			crc = ((crc >> 8) ^ crc_ccitt_tab[(crc ^ byte) & 0xFF]) & 0xFFFF;
 | 
			
		||||
		}	
 | 
			
		||||
 | 
			
		||||
		if(crc == 0xF0B8){		
 | 
			
		||||
			parse_ax25();
 | 
			
		||||
		}
 | 
			
		||||
	}	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void APRSRxProcessor::parse_ax25(){	
 | 
			
		||||
	aprs_packet.clear();
 | 
			
		||||
	aprs_packet.set_valid_checksum(true);
 | 
			
		||||
 | 
			
		||||
	for(size_t i = 0; i < packet_buffer_size; i++){
 | 
			
		||||
		aprs_packet.set(i, packet_buffer[i]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	APRSPacketMessage packet_message { aprs_packet };
 | 
			
		||||
	shared_memory.application_queue.push(packet_message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool APRSRxProcessor::parse_bit(const uint8_t current_bit){
 | 
			
		||||
	uint8_t decoded_bit = ~(current_bit ^ last_bit) & 0x1;
 | 
			
		||||
	last_bit = current_bit;
 | 
			
		||||
 | 
			
		||||
    //int16_t log = decoded_bit == 0 ? -32768 : 32767;
 | 
			
		||||
    //if(stream){
 | 
			
		||||
    //    const size_t bytes_to_write = sizeof(log) * 1;
 | 
			
		||||
    //    const auto result = stream->write(&log, bytes_to_write);
 | 
			
		||||
    //}
 | 
			
		||||
 | 
			
		||||
	if(decoded_bit & 0x1){
 | 
			
		||||
		if(ones_count < 8){
 | 
			
		||||
			ones_count++;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		if(ones_count > 6){ //not valid
 | 
			
		||||
			state = WAIT_FLAG;
 | 
			
		||||
			current_byte = 0;
 | 
			
		||||
			ones_count = 0;
 | 
			
		||||
			byte_index = 0;
 | 
			
		||||
			packet_buffer_size = 0;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		else if(ones_count == 6){ //flag
 | 
			
		||||
			bool done = false;
 | 
			
		||||
			if(state == IN_FRAME){				
 | 
			
		||||
				done = true;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				packet_buffer_size = 0;
 | 
			
		||||
			}
 | 
			
		||||
			state = WAIT_FRAME;
 | 
			
		||||
			current_byte = 0;
 | 
			
		||||
			ones_count = 0;
 | 
			
		||||
			byte_index = 0;			
 | 
			
		||||
 | 
			
		||||
			return done;
 | 
			
		||||
		}
 | 
			
		||||
		else if(ones_count == 5){ //bit stuff
 | 
			
		||||
			ones_count = 0;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			ones_count = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//store
 | 
			
		||||
	current_byte = current_byte >> 1;
 | 
			
		||||
	current_byte |= (decoded_bit == 0x1 ? 0x80 : 0x0);
 | 
			
		||||
	byte_index++;
 | 
			
		||||
 | 
			
		||||
	if(byte_index >= 8){
 | 
			
		||||
		byte_index = 0;
 | 
			
		||||
		if(state == WAIT_FRAME){
 | 
			
		||||
			state = IN_FRAME;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if(state == IN_FRAME){	
 | 
			
		||||
			if(packet_buffer_size + 1 >= 256){
 | 
			
		||||
				state = WAIT_FLAG;
 | 
			
		||||
				current_byte = 0;
 | 
			
		||||
				ones_count = 0;
 | 
			
		||||
				byte_index = 0;
 | 
			
		||||
				packet_buffer_size = 0;
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			packet_buffer[packet_buffer_size++] = current_byte;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void APRSRxProcessor::on_message(const Message* const message) {
 | 
			
		||||
	if (message->id == Message::ID::APRSRxConfigure)
 | 
			
		||||
		configure(*reinterpret_cast<const APRSRxConfigureMessage*>(message));
 | 
			
		||||
	if(message->id == Message::ID::CaptureConfig)
 | 
			
		||||
		capture_config(*reinterpret_cast<const CaptureConfigMessage*>(message));	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void APRSRxProcessor::capture_config(const CaptureConfigMessage& message) {
 | 
			
		||||
	if( message.config ) {
 | 
			
		||||
		//stream = std::make_unique<StreamInput>(message.config);
 | 
			
		||||
		audio_output.set_stream(std::make_unique<StreamInput>(message.config));
 | 
			
		||||
	} else {
 | 
			
		||||
		//stream.reset();
 | 
			
		||||
		audio_output.set_stream(nullptr);		
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void APRSRxProcessor::configure(const APRSRxConfigureMessage& message) {	
 | 
			
		||||
	decim_0.configure(taps_11k0_decim_0.taps, 33554432);
 | 
			
		||||
	decim_1.configure(taps_11k0_decim_1.taps, 131072);
 | 
			
		||||
	channel_filter.configure(taps_11k0_channel.taps, 2);
 | 
			
		||||
	demod.configure(audio_fs, 5000);
 | 
			
		||||
 | 
			
		||||
	audio_output.configure(audio_24k_hpf_300hz_config, audio_24k_deemph_300_6_config, 0);
 | 
			
		||||
	
 | 
			
		||||
	samples_per_bit = audio_fs / message.baudrate;
 | 
			
		||||
	
 | 
			
		||||
	phase_inc = (0x10000 * message.baudrate) / audio_fs;
 | 
			
		||||
	phase = 0;
 | 
			
		||||
	
 | 
			
		||||
	// Delay line
 | 
			
		||||
	delay_line_index = 0;
 | 
			
		||||
 | 
			
		||||
	state = WAIT_FLAG;
 | 
			
		||||
	
 | 
			
		||||
	configured = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<APRSRxProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										148
									
								
								Software/portapack-mayhem/firmware/baseband/proc_aprsrx.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								Software/portapack-mayhem/firmware/baseband/proc_aprsrx.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,148 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_APRSRX_H__
 | 
			
		||||
#define __PROC_APRSRX_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "rssi_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_decimate.hpp"
 | 
			
		||||
#include "dsp_demodulate.hpp"
 | 
			
		||||
#include "stream_input.hpp"
 | 
			
		||||
 | 
			
		||||
#include "audio_output.hpp"
 | 
			
		||||
 | 
			
		||||
#include "fifo.hpp"
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
 | 
			
		||||
#include  "aprs_packet.hpp"
 | 
			
		||||
 | 
			
		||||
static uint16_t crc_ccitt_tab[256] = {
 | 
			
		||||
    0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
 | 
			
		||||
	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
 | 
			
		||||
	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
 | 
			
		||||
	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
 | 
			
		||||
	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
 | 
			
		||||
	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
 | 
			
		||||
	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
 | 
			
		||||
	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
 | 
			
		||||
	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
 | 
			
		||||
	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
 | 
			
		||||
	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
 | 
			
		||||
	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
 | 
			
		||||
	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
 | 
			
		||||
	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
 | 
			
		||||
	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
 | 
			
		||||
	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
 | 
			
		||||
	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
 | 
			
		||||
	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
 | 
			
		||||
	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
 | 
			
		||||
	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
 | 
			
		||||
	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
 | 
			
		||||
	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
 | 
			
		||||
	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
 | 
			
		||||
	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
 | 
			
		||||
	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
 | 
			
		||||
	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
 | 
			
		||||
	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
 | 
			
		||||
	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
 | 
			
		||||
	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
 | 
			
		||||
	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
 | 
			
		||||
	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
 | 
			
		||||
	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class APRSRxProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
 | 
			
		||||
	void on_message(const Message* const message) override;
 | 
			
		||||
	
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr size_t baseband_fs = 3072000;
 | 
			
		||||
	static constexpr size_t audio_fs = baseband_fs / 8 / 8 / 2;
 | 
			
		||||
		
 | 
			
		||||
	size_t samples_per_bit { };
 | 
			
		||||
	
 | 
			
		||||
	enum State {
 | 
			
		||||
		WAIT_FLAG,
 | 
			
		||||
		WAIT_FRAME,
 | 
			
		||||
		IN_FRAME
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
 | 
			
		||||
	RSSIThread rssi_thread { NORMALPRIO + 10 };
 | 
			
		||||
	
 | 
			
		||||
	std::array<complex16_t, 512> dst { };
 | 
			
		||||
	const buffer_c16_t dst_buffer {
 | 
			
		||||
		dst.data(),
 | 
			
		||||
		dst.size()
 | 
			
		||||
	};
 | 
			
		||||
	std::array<float, 32> audio { };
 | 
			
		||||
	const buffer_f32_t audio_buffer {
 | 
			
		||||
		audio.data(),
 | 
			
		||||
		audio.size()
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	// Array size ok down to 375 bauds (24000 / 375)
 | 
			
		||||
	std::array<int32_t, 64> delay_line { 0 };
 | 
			
		||||
	
 | 
			
		||||
	dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { };
 | 
			
		||||
	dsp::decimate::FIRC16xR16x32Decim8 decim_1 { };
 | 
			
		||||
	dsp::decimate::FIRAndDecimateComplex channel_filter { };
 | 
			
		||||
	
 | 
			
		||||
	std::unique_ptr<StreamInput> stream { };
 | 
			
		||||
 | 
			
		||||
	dsp::demodulate::FM demod { };
 | 
			
		||||
	
 | 
			
		||||
	AudioOutput audio_output { };
 | 
			
		||||
 | 
			
		||||
	State state { };
 | 
			
		||||
	size_t delay_line_index { };	
 | 
			
		||||
	uint32_t bit_counter { 0 };
 | 
			
		||||
	uint32_t word_bits { 0 };
 | 
			
		||||
	uint32_t sample_bits { 0 };
 | 
			
		||||
	uint32_t phase { }, phase_inc { };
 | 
			
		||||
	int32_t sample_mixed { }, prev_mixed { }, sample_filtered { }, prev_filtered { };
 | 
			
		||||
	uint8_t last_bit = 0;
 | 
			
		||||
	uint8_t ones_count = 0 ;
 | 
			
		||||
	uint8_t current_byte = 0;
 | 
			
		||||
	uint8_t byte_index = 0;
 | 
			
		||||
	uint8_t packet_buffer[256];
 | 
			
		||||
	size_t packet_buffer_size = 0;
 | 
			
		||||
 | 
			
		||||
	bool configured { false };
 | 
			
		||||
	bool wait_start { 0 };
 | 
			
		||||
	bool bit_value { 0 };
 | 
			
		||||
 | 
			
		||||
	aprs::APRSPacket aprs_packet { };
 | 
			
		||||
 | 
			
		||||
	void configure(const APRSRxConfigureMessage& message);
 | 
			
		||||
	void capture_config(const CaptureConfigMessage& message);
 | 
			
		||||
	void parse_packet();
 | 
			
		||||
	bool parse_bit(const uint8_t bit);
 | 
			
		||||
	void parse_ax25();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__PROC_TPMS_H__*/
 | 
			
		||||
							
								
								
									
										121
									
								
								Software/portapack-mayhem/firmware/baseband/proc_audiotx.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								Software/portapack-mayhem/firmware/baseband/proc_audiotx.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,121 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 * 
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_audiotx.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
#include "sine_table_int8.hpp"
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
void AudioTXProcessor::execute(const buffer_c8_t& buffer){
 | 
			
		||||
	
 | 
			
		||||
	if (!configured) return;
 | 
			
		||||
	
 | 
			
		||||
	// Zero-order hold (poop)
 | 
			
		||||
	for (size_t i = 0; i < buffer.count; i++) {
 | 
			
		||||
		resample_acc += resample_inc;
 | 
			
		||||
		if (resample_acc >= 0x10000) {
 | 
			
		||||
			resample_acc -= 0x10000;
 | 
			
		||||
			if (stream) {
 | 
			
		||||
				stream->read(&audio_sample, 1);
 | 
			
		||||
				bytes_read++;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		sample = tone_gen.process(audio_sample - 0x80);
 | 
			
		||||
		
 | 
			
		||||
		// FM
 | 
			
		||||
		delta = sample * fm_delta;
 | 
			
		||||
		
 | 
			
		||||
		phase += delta;
 | 
			
		||||
		sphase = phase + (64 << 24);
 | 
			
		||||
		
 | 
			
		||||
		re = sine_table_i8[(sphase & 0xFF000000U) >> 24];
 | 
			
		||||
		im = sine_table_i8[(phase & 0xFF000000U) >> 24];
 | 
			
		||||
		
 | 
			
		||||
		buffer.p[i] = { (int8_t)re, (int8_t)im };
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	progress_samples += buffer.count;
 | 
			
		||||
	if (progress_samples >= progress_interval_samples) {
 | 
			
		||||
		progress_samples -= progress_interval_samples;
 | 
			
		||||
		
 | 
			
		||||
		txprogress_message.progress = bytes_read;	// Inform UI about progress
 | 
			
		||||
		txprogress_message.done = false;
 | 
			
		||||
		shared_memory.application_queue.push(txprogress_message);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTXProcessor::on_message(const Message* const message) {
 | 
			
		||||
	switch(message->id) {
 | 
			
		||||
		case Message::ID::AudioTXConfig:
 | 
			
		||||
			audio_config(*reinterpret_cast<const AudioTXConfigMessage*>(message));
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case Message::ID::ReplayConfig:
 | 
			
		||||
			configured = false;
 | 
			
		||||
			bytes_read = 0;
 | 
			
		||||
			replay_config(*reinterpret_cast<const ReplayConfigMessage*>(message));
 | 
			
		||||
			break;
 | 
			
		||||
		
 | 
			
		||||
		case Message::ID::SamplerateConfig:
 | 
			
		||||
			samplerate_config(*reinterpret_cast<const SamplerateConfigMessage*>(message));
 | 
			
		||||
			break;
 | 
			
		||||
		
 | 
			
		||||
		case Message::ID::FIFOData:
 | 
			
		||||
			configured = true;
 | 
			
		||||
			break;
 | 
			
		||||
		
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTXProcessor::audio_config(const AudioTXConfigMessage& message) {
 | 
			
		||||
	fm_delta = message.deviation_hz * (0xFFFFFFULL / baseband_fs);
 | 
			
		||||
	tone_gen.configure(message.tone_key_delta, message.tone_key_mix_weight);
 | 
			
		||||
	progress_interval_samples = message.divider;
 | 
			
		||||
	resample_acc = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTXProcessor::replay_config(const ReplayConfigMessage& message) {
 | 
			
		||||
	if( message.config ) {
 | 
			
		||||
		
 | 
			
		||||
		stream = std::make_unique<StreamOutput>(message.config);
 | 
			
		||||
		
 | 
			
		||||
		// Tell application that the buffers and FIFO pointers are ready, prefill
 | 
			
		||||
		shared_memory.application_queue.push(sig_message);
 | 
			
		||||
	} else {
 | 
			
		||||
		stream.reset();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTXProcessor::samplerate_config(const SamplerateConfigMessage& message) {
 | 
			
		||||
	resample_inc = (((uint64_t)message.sample_rate) << 16) / baseband_fs;	// 16.16 fixed point message.sample_rate
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<AudioTXProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								Software/portapack-mayhem/firmware/baseband/proc_audiotx.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								Software/portapack-mayhem/firmware/baseband/proc_audiotx.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 * 
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_AUDIOTX_H__
 | 
			
		||||
#define __PROC_AUDIOTX_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "tone_gen.hpp"
 | 
			
		||||
#include "stream_output.hpp"
 | 
			
		||||
 | 
			
		||||
class AudioTXProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
	
 | 
			
		||||
	void on_message(const Message* const msg) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr size_t baseband_fs = 1536000;
 | 
			
		||||
	
 | 
			
		||||
	BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Transmit };
 | 
			
		||||
	
 | 
			
		||||
	std::unique_ptr<StreamOutput> stream { };
 | 
			
		||||
	
 | 
			
		||||
	ToneGen tone_gen { };
 | 
			
		||||
	
 | 
			
		||||
	uint32_t resample_inc { }, resample_acc { };
 | 
			
		||||
	uint32_t fm_delta { 0 };
 | 
			
		||||
	uint32_t phase { 0 }, sphase { 0 };
 | 
			
		||||
	uint8_t audio_sample { };
 | 
			
		||||
	int32_t sample { 0 }, delta { };
 | 
			
		||||
	int8_t re { 0 }, im { 0 };
 | 
			
		||||
	
 | 
			
		||||
	size_t progress_interval_samples = 0 , progress_samples = 0;
 | 
			
		||||
	
 | 
			
		||||
	bool configured { false };
 | 
			
		||||
	uint32_t bytes_read { 0 };
 | 
			
		||||
	
 | 
			
		||||
	void samplerate_config(const SamplerateConfigMessage& message);
 | 
			
		||||
	void audio_config(const AudioTXConfigMessage& message);
 | 
			
		||||
	void replay_config(const ReplayConfigMessage& message);
 | 
			
		||||
	
 | 
			
		||||
	TXProgressMessage txprogress_message { };
 | 
			
		||||
	RequestSignalMessage sig_message { RequestSignalMessage::Signal::FillRequest };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										339
									
								
								Software/portapack-mayhem/firmware/baseband/proc_btlerx.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								Software/portapack-mayhem/firmware/baseband/proc_btlerx.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,339 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 * Copyright (C) 2020 Shao
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_btlerx.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
void BTLERxProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	if (!configured) return;
 | 
			
		||||
	
 | 
			
		||||
	// FM demodulation
 | 
			
		||||
 | 
			
		||||
	/*const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
 | 
			
		||||
	const auto channel = decim_1.execute(decim_0_out, dst_buffer);
 | 
			
		||||
 | 
			
		||||
	feed_channel_stats(channel);
 | 
			
		||||
	
 | 
			
		||||
	auto audio_oversampled = demod.execute(channel, work_audio_buffer);*/
 | 
			
		||||
 | 
			
		||||
	const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
 | 
			
		||||
	feed_channel_stats(decim_0_out);
 | 
			
		||||
	
 | 
			
		||||
	auto audio_oversampled = demod.execute(decim_0_out, work_audio_buffer);
 | 
			
		||||
 | 
			
		||||
	/*std::fill(spectrum.begin(), spectrum.end(), 0);
 | 
			
		||||
	for(size_t i=0; i<spectrum.size(); i++) {
 | 
			
		||||
		spectrum[i] += buffer.p[i];
 | 
			
		||||
	}
 | 
			
		||||
	const buffer_c16_t buffer_c16 {spectrum.data(),spectrum.size(),buffer.sampling_rate};
 | 
			
		||||
	feed_channel_stats(buffer_c16);
 | 
			
		||||
	
 | 
			
		||||
	auto audio_oversampled = demod.execute(buffer_c16, work_audio_buffer);*/
 | 
			
		||||
	// Audio signal processing
 | 
			
		||||
	for (size_t c = 0; c < audio_oversampled.count; c++) {
 | 
			
		||||
 | 
			
		||||
		/*const int32_t sample_int = audio_oversampled.p[c] * 32768.0f;
 | 
			
		||||
		int32_t current_sample = __SSAT(sample_int, 16);
 | 
			
		||||
		current_sample /= 128;*/
 | 
			
		||||
                
 | 
			
		||||
		int32_t current_sample = audio_oversampled.p[c]; //if I directly use this, some results can pass crc but not correct.
 | 
			
		||||
                rb_head++;
 | 
			
		||||
	        rb_head=(rb_head)%RB_SIZE;
 | 
			
		||||
 | 
			
		||||
                rb_buf[rb_head] = current_sample;
 | 
			
		||||
 | 
			
		||||
		skipSamples = skipSamples - 1;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		if (skipSamples<1)
 | 
			
		||||
		{
 | 
			
		||||
				
 | 
			
		||||
 | 
			
		||||
			int32_t threshold_tmp=0;
 | 
			
		||||
			for (int c=0;c<8;c++)
 | 
			
		||||
			{
 | 
			
		||||
				threshold_tmp = threshold_tmp + (int32_t)rb_buf[(rb_head+c)%RB_SIZE];
 | 
			
		||||
			}
 | 
			
		||||
			g_threshold = (int32_t)threshold_tmp/8;
 | 
			
		||||
 | 
			
		||||
				
 | 
			
		||||
			int transitions=0;
 | 
			
		||||
			if (rb_buf[(rb_head+9)%RB_SIZE] > g_threshold)
 | 
			
		||||
			{
 | 
			
		||||
				for (int c=0;c<8;c++)
 | 
			
		||||
				{
 | 
			
		||||
					if (rb_buf[(rb_head + c)%RB_SIZE] > rb_buf[(rb_head + c + 1)%RB_SIZE])
 | 
			
		||||
					transitions = transitions + 1;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				for (int c=0;c<8;c++)
 | 
			
		||||
				{
 | 
			
		||||
					if (rb_buf[(rb_head + c)%RB_SIZE] < rb_buf[(rb_head + c + 1)%RB_SIZE])
 | 
			
		||||
					transitions = transitions + 1;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			bool packet_detected=false;
 | 
			
		||||
			//if ( transitions==4 && abs(g_threshold)<15500)
 | 
			
		||||
			if ( transitions==4)
 | 
			
		||||
			{
 | 
			
		||||
 | 
			
		||||
				
 | 
			
		||||
				uint8_t packet_data[500];
 | 
			
		||||
				int packet_length;
 | 
			
		||||
				uint32_t packet_crc;
 | 
			
		||||
				//uint32_t calced_crc; // NOTE: restore when CRC is passing
 | 
			
		||||
				uint64_t packet_addr_l;
 | 
			
		||||
				//uint32_t result; // NOTE: restore when CRC is passing
 | 
			
		||||
				uint8_t crc[3];
 | 
			
		||||
				uint8_t packet_header_arr[2];
 | 
			
		||||
 | 
			
		||||
				packet_addr_l=0;
 | 
			
		||||
				for (int i=0;i<4;i++) 
 | 
			
		||||
				{                   
 | 
			
		||||
				    bool current_bit;
 | 
			
		||||
				    uint8_t byte=0;
 | 
			
		||||
				    for (int c=0;c<8;c++)
 | 
			
		||||
				    {
 | 
			
		||||
				        if (rb_buf[(rb_head + (i+1)*8 + c)%RB_SIZE] > g_threshold)
 | 
			
		||||
				            current_bit = true;
 | 
			
		||||
				        else
 | 
			
		||||
				            current_bit = false;
 | 
			
		||||
				        byte |= current_bit << (7-c);
 | 
			
		||||
				    }
 | 
			
		||||
				    uint8_t byte_temp = (uint8_t) (((byte * 0x0802LU & 0x22110LU) | (byte * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
 | 
			
		||||
				    packet_addr_l|=((uint64_t)byte_temp)<<(8*i);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				channel_number = 38;
 | 
			
		||||
 | 
			
		||||
				
 | 
			
		||||
				for (int t=0;t<2;t++)
 | 
			
		||||
				{
 | 
			
		||||
				    bool current_bit;
 | 
			
		||||
				    uint8_t byte=0;
 | 
			
		||||
				    for (int c=0;c<8;c++)
 | 
			
		||||
				    {
 | 
			
		||||
				        if (rb_buf[(rb_head + 5*8+t*8 + c)%RB_SIZE] > g_threshold)
 | 
			
		||||
				            current_bit = true;
 | 
			
		||||
				        else
 | 
			
		||||
				            current_bit = false;
 | 
			
		||||
				        byte |= current_bit << (7-c);
 | 
			
		||||
				    }
 | 
			
		||||
 | 
			
		||||
				    packet_header_arr[t] = byte;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				
 | 
			
		||||
 | 
			
		||||
				uint8_t byte_temp2 = (uint8_t) (((channel_number * 0x0802LU & 0x22110LU) | (channel_number * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
 | 
			
		||||
				uint8_t lfsr_1 = byte_temp2 | 2;
 | 
			
		||||
				int header_length = 2;
 | 
			
		||||
				int header_counter = 0;
 | 
			
		||||
				while(header_length--)
 | 
			
		||||
				{
 | 
			
		||||
				    for(uint8_t i = 0x80; i; i >>= 1)
 | 
			
		||||
				    {
 | 
			
		||||
				        if(lfsr_1 & 0x80)
 | 
			
		||||
				        {
 | 
			
		||||
				            lfsr_1 ^= 0x11;
 | 
			
		||||
				            (packet_header_arr[header_counter]) ^= i;
 | 
			
		||||
				        }
 | 
			
		||||
				        lfsr_1 <<= 1;
 | 
			
		||||
				    }
 | 
			
		||||
				    header_counter = header_counter + 1;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				
 | 
			
		||||
 | 
			
		||||
				if (packet_addr_l==0x8E89BED6)
 | 
			
		||||
				{  
 | 
			
		||||
 | 
			
		||||
				    uint8_t byte_temp3 = (uint8_t) (((packet_header_arr[1] * 0x0802LU & 0x22110LU) | (packet_header_arr[1] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
 | 
			
		||||
				    packet_length=byte_temp3&0x3F;
 | 
			
		||||
				
 | 
			
		||||
				} 
 | 
			
		||||
				else 
 | 
			
		||||
				{
 | 
			
		||||
				    packet_length=0;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				for (int t=0;t<packet_length+2+3;t++)
 | 
			
		||||
				{
 | 
			
		||||
				    bool current_bit;
 | 
			
		||||
				    uint8_t byte=0;
 | 
			
		||||
				    for (int c=0;c<8;c++)
 | 
			
		||||
				    {
 | 
			
		||||
				        if (rb_buf[(rb_head + 5*8+t*8 + c)%RB_SIZE] > g_threshold)
 | 
			
		||||
				            current_bit = true;
 | 
			
		||||
				        else
 | 
			
		||||
				            current_bit = false;
 | 
			
		||||
				        byte |= current_bit << (7-c);
 | 
			
		||||
				    }
 | 
			
		||||
 | 
			
		||||
				    packet_data[t] = byte;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				
 | 
			
		||||
 | 
			
		||||
				uint8_t byte_temp4 = (uint8_t) (((channel_number * 0x0802LU & 0x22110LU) | (channel_number * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
 | 
			
		||||
				uint8_t lfsr_2 = byte_temp4 | 2;
 | 
			
		||||
				int pdu_crc_length = packet_length+2+3;
 | 
			
		||||
				int pdu_crc_counter = 0;
 | 
			
		||||
				while(pdu_crc_length--)
 | 
			
		||||
				{
 | 
			
		||||
				    for(uint8_t i = 0x80; i; i >>= 1)
 | 
			
		||||
				    {
 | 
			
		||||
				        if(lfsr_2 & 0x80)
 | 
			
		||||
				        {
 | 
			
		||||
				            lfsr_2 ^= 0x11;
 | 
			
		||||
				            (packet_data[pdu_crc_counter]) ^= i;
 | 
			
		||||
				        }
 | 
			
		||||
				        lfsr_2 <<= 1;
 | 
			
		||||
				    }
 | 
			
		||||
				    pdu_crc_counter = pdu_crc_counter + 1;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				
 | 
			
		||||
 | 
			
		||||
				if (packet_addr_l==0x8E89BED6)
 | 
			
		||||
				{  
 | 
			
		||||
				    crc[0]=crc[1]=crc[2]=0x55;
 | 
			
		||||
				}
 | 
			
		||||
				else 
 | 
			
		||||
				{
 | 
			
		||||
				    crc[0]=crc[1]=crc[2]=0;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				uint8_t v, t, d, crc_length;
 | 
			
		||||
				uint32_t crc_result=0;
 | 
			
		||||
				crc_length = packet_length + 2;
 | 
			
		||||
				int counter = 0;
 | 
			
		||||
				while(crc_length--)
 | 
			
		||||
				{
 | 
			
		||||
				    uint8_t byte_temp5 = (uint8_t) (((packet_data[counter] * 0x0802LU & 0x22110LU) | (packet_data[counter] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
 | 
			
		||||
				    d = byte_temp5;
 | 
			
		||||
				    for(v = 0; v < 8; v++, d >>= 1)
 | 
			
		||||
				    {
 | 
			
		||||
				        t = crc[0] >> 7;
 | 
			
		||||
				        crc[0] <<= 1;
 | 
			
		||||
				        if(crc[1] & 0x80) crc[0] |= 1;
 | 
			
		||||
				        crc[1] <<= 1;
 | 
			
		||||
				        if(crc[2] & 0x80) crc[1] |= 1;
 | 
			
		||||
				        crc[2] <<= 1;
 | 
			
		||||
				        if(t != (d & 1))
 | 
			
		||||
				        {
 | 
			
		||||
				            crc[2] ^= 0x5B;
 | 
			
		||||
				            crc[1] ^= 0x06;
 | 
			
		||||
				        }
 | 
			
		||||
				    }
 | 
			
		||||
				    counter = counter + 1;
 | 
			
		||||
				}
 | 
			
		||||
				for (v=0;v<3;v++) crc_result=(crc_result<<8)|crc[v];
 | 
			
		||||
				//calced_crc = crc_result; // NOTE: restore when CRC is passing
 | 
			
		||||
 | 
			
		||||
				packet_crc=0;
 | 
			
		||||
				for (int c=0;c<3;c++) packet_crc=(packet_crc<<8)|packet_data[packet_length+2+c];
 | 
			
		||||
 | 
			
		||||
				if (packet_addr_l==0x8E89BED6)
 | 
			
		||||
				//if (packet_crc==calced_crc) // NOTE: restore when CRC is passing
 | 
			
		||||
				{
 | 
			
		||||
				    uint8_t mac_data[6];
 | 
			
		||||
				    int counter = 0;
 | 
			
		||||
				    for (int i = 7; i >= 2; i--) 
 | 
			
		||||
				    {
 | 
			
		||||
				        uint8_t byte_temp6 = (uint8_t) (((packet_data[i] * 0x0802LU & 0x22110LU) | (packet_data[i] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
 | 
			
		||||
					//result = byte_temp6; // NOTE: restore when CRC is passing
 | 
			
		||||
					mac_data[counter] = byte_temp6; 
 | 
			
		||||
					counter = counter + 1;
 | 
			
		||||
				    }
 | 
			
		||||
 | 
			
		||||
				    data_message.is_data = false;
 | 
			
		||||
			            data_message.value = 'A';
 | 
			
		||||
				    shared_memory.application_queue.push(data_message);
 | 
			
		||||
 | 
			
		||||
				    data_message.is_data = true;
 | 
			
		||||
			            data_message.value = mac_data[0];
 | 
			
		||||
				    shared_memory.application_queue.push(data_message);
 | 
			
		||||
 | 
			
		||||
				    data_message.is_data = true;
 | 
			
		||||
			            data_message.value = mac_data[1];
 | 
			
		||||
				    shared_memory.application_queue.push(data_message);
 | 
			
		||||
 | 
			
		||||
				    data_message.is_data = true;
 | 
			
		||||
			            data_message.value = mac_data[2];
 | 
			
		||||
				    shared_memory.application_queue.push(data_message);
 | 
			
		||||
 | 
			
		||||
				    data_message.is_data = true;
 | 
			
		||||
			            data_message.value = mac_data[3];
 | 
			
		||||
				    shared_memory.application_queue.push(data_message);
 | 
			
		||||
 | 
			
		||||
				    data_message.is_data = true;
 | 
			
		||||
			            data_message.value = mac_data[4];
 | 
			
		||||
				    shared_memory.application_queue.push(data_message);
 | 
			
		||||
 | 
			
		||||
				    data_message.is_data = true;
 | 
			
		||||
			            data_message.value = mac_data[5];
 | 
			
		||||
				    shared_memory.application_queue.push(data_message);
 | 
			
		||||
 | 
			
		||||
				    data_message.is_data = false;
 | 
			
		||||
			            data_message.value = 'B';
 | 
			
		||||
				    shared_memory.application_queue.push(data_message);
 | 
			
		||||
 | 
			
		||||
				    packet_detected = true;
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				    packet_detected = false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (packet_detected) 
 | 
			
		||||
			{
 | 
			
		||||
				skipSamples=20;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BTLERxProcessor::on_message(const Message* const message) {
 | 
			
		||||
	if (message->id == Message::ID::BTLERxConfigure)
 | 
			
		||||
		configure(*reinterpret_cast<const BTLERxConfigureMessage*>(message));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BTLERxProcessor::configure(const BTLERxConfigureMessage& message) {	
 | 
			
		||||
	(void)message; //avoid warning
 | 
			
		||||
	decim_0.configure(taps_200k_wfm_decim_0.taps, 33554432);
 | 
			
		||||
	decim_1.configure(taps_200k_wfm_decim_1.taps, 131072);
 | 
			
		||||
	demod.configure(audio_fs, 5000);
 | 
			
		||||
 | 
			
		||||
	configured = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<BTLERxProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										95
									
								
								Software/portapack-mayhem/firmware/baseband/proc_btlerx.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								Software/portapack-mayhem/firmware/baseband/proc_btlerx.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 * Copyright (C) 2020 Shao
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_BTLERX_H__
 | 
			
		||||
#define __PROC_BTLERX_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "rssi_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_decimate.hpp"
 | 
			
		||||
#include "dsp_demodulate.hpp"
 | 
			
		||||
 | 
			
		||||
#include "audio_output.hpp"
 | 
			
		||||
 | 
			
		||||
#include "fifo.hpp"
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
 | 
			
		||||
class BTLERxProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
 | 
			
		||||
	void on_message(const Message* const message) override;
 | 
			
		||||
	
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr size_t baseband_fs = 4000000;
 | 
			
		||||
	static constexpr size_t audio_fs = baseband_fs / 8 / 8 / 2;
 | 
			
		||||
	
 | 
			
		||||
	BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
 | 
			
		||||
	RSSIThread rssi_thread { NORMALPRIO + 10 };
 | 
			
		||||
	
 | 
			
		||||
	std::array<complex16_t, 512> dst { };
 | 
			
		||||
	const buffer_c16_t dst_buffer {
 | 
			
		||||
		dst.data(),
 | 
			
		||||
		dst.size()
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
        std::array<complex16_t, 512> spectrum { };
 | 
			
		||||
	const buffer_c16_t spectrum_buffer {
 | 
			
		||||
		spectrum.data(),
 | 
			
		||||
		spectrum.size()
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	const buffer_s16_t work_audio_buffer {
 | 
			
		||||
		(int16_t*)dst.data(),
 | 
			
		||||
		sizeof(dst) / sizeof(int16_t)
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	// Array size ok down to 375 bauds (24000 / 375)
 | 
			
		||||
	std::array<int32_t, 64> delay_line { 0 };
 | 
			
		||||
	std::array<int16_t, 1000> rb_buf { 0 };
 | 
			
		||||
 | 
			
		||||
	/*dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { };
 | 
			
		||||
	dsp::decimate::FIRC16xR16x32Decim8 decim_1 { };
 | 
			
		||||
	dsp::decimate::FIRAndDecimateComplex channel_filter { };*/
 | 
			
		||||
	dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0 { };
 | 
			
		||||
	dsp::decimate::FIRC16xR16x16Decim2 decim_1 { };
 | 
			
		||||
	
 | 
			
		||||
	dsp::demodulate::FM demod { };
 | 
			
		||||
	int rb_head {-1};
 | 
			
		||||
	int32_t g_threshold {0};  
 | 
			
		||||
	uint8_t channel_number {38};
 | 
			
		||||
	int skipSamples {1000};
 | 
			
		||||
	int RB_SIZE {1000};
 | 
			
		||||
 | 
			
		||||
	bool configured { false };
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	void configure(const BTLERxConfigureMessage& message);
 | 
			
		||||
	
 | 
			
		||||
	AFSKDataMessage data_message { false, 0 };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__PROC_BTLERX_H__*/
 | 
			
		||||
							
								
								
									
										112
									
								
								Software/portapack-mayhem/firmware/baseband/proc_capture.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								Software/portapack-mayhem/firmware/baseband/proc_capture.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2018 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_capture.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_fir_taps.hpp"
 | 
			
		||||
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
CaptureProcessor::CaptureProcessor() {
 | 
			
		||||
	decim_0.configure(taps_200k_decim_0.taps, 33554432);
 | 
			
		||||
	decim_1.configure(taps_200k_decim_1.taps, 131072);
 | 
			
		||||
	
 | 
			
		||||
	channel_spectrum.set_decimation_factor(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CaptureProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	/* 2.4576MHz, 2048 samples */
 | 
			
		||||
	const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
 | 
			
		||||
	const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer);
 | 
			
		||||
	const auto& decimator_out = decim_1_out;
 | 
			
		||||
	const auto& channel = decimator_out;
 | 
			
		||||
 | 
			
		||||
	if( stream ) {
 | 
			
		||||
		const size_t bytes_to_write = sizeof(*decimator_out.p) * decimator_out.count;
 | 
			
		||||
		const size_t written = stream->write(decimator_out.p, bytes_to_write);
 | 
			
		||||
		if( written != bytes_to_write )
 | 
			
		||||
		{
 | 
			
		||||
			//TODO eventually report error somewhere
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	feed_channel_stats(channel);
 | 
			
		||||
 | 
			
		||||
	spectrum_samples += channel.count;
 | 
			
		||||
	if( spectrum_samples >= spectrum_interval_samples ) {
 | 
			
		||||
		spectrum_samples -= spectrum_interval_samples;
 | 
			
		||||
		channel_spectrum.feed(channel, channel_filter_low_f, channel_filter_high_f, channel_filter_transition);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CaptureProcessor::on_message(const Message* const message) {
 | 
			
		||||
	switch(message->id) {
 | 
			
		||||
	case Message::ID::UpdateSpectrum:
 | 
			
		||||
	case Message::ID::SpectrumStreamingConfig:
 | 
			
		||||
		channel_spectrum.on_message(message);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case Message::ID::SamplerateConfig:
 | 
			
		||||
		samplerate_config(*reinterpret_cast<const SamplerateConfigMessage*>(message));
 | 
			
		||||
		break;
 | 
			
		||||
	
 | 
			
		||||
	case Message::ID::CaptureConfig:
 | 
			
		||||
		capture_config(*reinterpret_cast<const CaptureConfigMessage*>(message));
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CaptureProcessor::samplerate_config(const SamplerateConfigMessage& message) {
 | 
			
		||||
	baseband_fs = message.sample_rate;
 | 
			
		||||
	baseband_thread.set_sampling_rate(baseband_fs);
 | 
			
		||||
	
 | 
			
		||||
	size_t decim_0_output_fs = baseband_fs / decim_0.decimation_factor;
 | 
			
		||||
 | 
			
		||||
	size_t decim_1_input_fs = decim_0_output_fs;
 | 
			
		||||
	size_t decim_1_output_fs = decim_1_input_fs / decim_1.decimation_factor;
 | 
			
		||||
 | 
			
		||||
	channel_filter_low_f = taps_200k_decim_1.low_frequency_normalized * decim_1_input_fs;
 | 
			
		||||
	channel_filter_high_f = taps_200k_decim_1.high_frequency_normalized * decim_1_input_fs;
 | 
			
		||||
	channel_filter_transition = taps_200k_decim_1.transition_normalized * decim_1_input_fs;
 | 
			
		||||
 | 
			
		||||
	spectrum_interval_samples = decim_1_output_fs / spectrum_rate_hz;
 | 
			
		||||
	spectrum_samples = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CaptureProcessor::capture_config(const CaptureConfigMessage& message) {
 | 
			
		||||
	if( message.config ) {
 | 
			
		||||
		stream = std::make_unique<StreamInput>(message.config);
 | 
			
		||||
	} else {
 | 
			
		||||
		stream.reset();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<CaptureProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										77
									
								
								Software/portapack-mayhem/firmware/baseband/proc_capture.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								Software/portapack-mayhem/firmware/baseband/proc_capture.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2018 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_CAPTURE_HPP__
 | 
			
		||||
#define __PROC_CAPTURE_HPP__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "rssi_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_decimate.hpp"
 | 
			
		||||
 | 
			
		||||
#include "spectrum_collector.hpp"
 | 
			
		||||
 | 
			
		||||
#include "stream_input.hpp"
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
class CaptureProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	CaptureProcessor();
 | 
			
		||||
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
 | 
			
		||||
	void on_message(const Message* const message) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	// TODO: Repeated value needs to be transmitted from application side.
 | 
			
		||||
	size_t baseband_fs = 0;
 | 
			
		||||
	static constexpr auto spectrum_rate_hz = 50.0f;
 | 
			
		||||
 | 
			
		||||
	BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
 | 
			
		||||
	RSSIThread rssi_thread { NORMALPRIO + 10 };
 | 
			
		||||
 | 
			
		||||
	std::array<complex16_t, 512> dst { };
 | 
			
		||||
	const buffer_c16_t dst_buffer {
 | 
			
		||||
		dst.data(),
 | 
			
		||||
		dst.size()
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0 { };
 | 
			
		||||
	dsp::decimate::FIRC16xR16x16Decim2 decim_1 { };
 | 
			
		||||
	int32_t channel_filter_low_f = 0;
 | 
			
		||||
	int32_t channel_filter_high_f = 0;
 | 
			
		||||
	int32_t channel_filter_transition = 0;
 | 
			
		||||
 | 
			
		||||
	std::unique_ptr<StreamInput> stream { };
 | 
			
		||||
 | 
			
		||||
	SpectrumCollector channel_spectrum { };
 | 
			
		||||
	size_t spectrum_interval_samples = 0;
 | 
			
		||||
	size_t spectrum_samples = 0;
 | 
			
		||||
 | 
			
		||||
	void samplerate_config(const SamplerateConfigMessage& message);
 | 
			
		||||
	void capture_config(const CaptureConfigMessage& message);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__PROC_CAPTURE_HPP__*/
 | 
			
		||||
							
								
								
									
										111
									
								
								Software/portapack-mayhem/firmware/baseband/proc_ert.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								Software/portapack-mayhem/firmware/baseband/proc_ert.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,111 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_ert.hpp"
 | 
			
		||||
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
float ERTProcessor::abs(const complex8_t& v) {
 | 
			
		||||
	// const int16_t r = v.real() - offset_i;
 | 
			
		||||
	// const int16_t i = v.imag() - offset_q;
 | 
			
		||||
	// const uint32_t r2 = r * r;
 | 
			
		||||
	// const uint32_t i2 = i * i;
 | 
			
		||||
	// const uint32_t r2_i2 = r2 + i2;
 | 
			
		||||
	// return std::sqrt(static_cast<float>(r2_i2));
 | 
			
		||||
	const float r = static_cast<float>(v.real()) - offset_i;
 | 
			
		||||
	const float i = static_cast<float>(v.imag()) - offset_q;
 | 
			
		||||
	const float r2 = r * r;
 | 
			
		||||
	const float i2 = i * i;
 | 
			
		||||
	const float r2_i2 = r2 + i2;
 | 
			
		||||
	return std::sqrt(r2_i2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ERTProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	/* 4.194304MHz, 2048 samples */
 | 
			
		||||
 | 
			
		||||
	const complex8_t* src = &buffer.p[0];
 | 
			
		||||
	const complex8_t* const src_end = &buffer.p[buffer.count];
 | 
			
		||||
 | 
			
		||||
	average_i += src->real();
 | 
			
		||||
	average_q += src->imag();
 | 
			
		||||
	average_count++;
 | 
			
		||||
	if( average_count == average_window ) {
 | 
			
		||||
		offset_i = static_cast<float>(average_i) / average_window;
 | 
			
		||||
		offset_q = static_cast<float>(average_q) / average_window;
 | 
			
		||||
		average_i = 0;
 | 
			
		||||
		average_q = 0;
 | 
			
		||||
		average_count = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const float gain = 128 * samples_per_symbol;
 | 
			
		||||
	const float k = 1.0f / gain;
 | 
			
		||||
 | 
			
		||||
	while(src < src_end) {
 | 
			
		||||
		float sum = 0.0f;
 | 
			
		||||
		for(size_t i=0; i<(samples_per_symbol / 2); i++) {
 | 
			
		||||
			sum += abs(*(src++));
 | 
			
		||||
		}
 | 
			
		||||
		sum_half_period[1] = sum_half_period[0];
 | 
			
		||||
		sum_half_period[0] = sum;
 | 
			
		||||
 | 
			
		||||
		sum_period[2] = sum_period[1];
 | 
			
		||||
		sum_period[1] = sum_period[0];
 | 
			
		||||
		sum_period[0] = (sum_half_period[0] + sum_half_period[1]) * k;
 | 
			
		||||
 | 
			
		||||
		manchester[2] = manchester[1];
 | 
			
		||||
		manchester[1] = manchester[0];
 | 
			
		||||
		manchester[0] = sum_period[2] - sum_period[0];
 | 
			
		||||
 | 
			
		||||
		const auto data = manchester[0] - manchester[2];
 | 
			
		||||
 | 
			
		||||
		clock_recovery(data);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ERTProcessor::consume_symbol(
 | 
			
		||||
	const float raw_symbol
 | 
			
		||||
) {
 | 
			
		||||
	const uint_fast8_t sliced_symbol = (raw_symbol >= 0.0f) ? 1 : 0;
 | 
			
		||||
	scm_builder.execute(sliced_symbol);
 | 
			
		||||
	idm_builder.execute(sliced_symbol);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ERTProcessor::scm_handler(
 | 
			
		||||
	const baseband::Packet& packet
 | 
			
		||||
) {
 | 
			
		||||
	const ERTPacketMessage message { ert::Packet::Type::SCM, packet };
 | 
			
		||||
	shared_memory.application_queue.push(message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ERTProcessor::idm_handler(
 | 
			
		||||
	const baseband::Packet& packet
 | 
			
		||||
) {
 | 
			
		||||
	const ERTPacketMessage message { ert::Packet::Type::IDM, packet };
 | 
			
		||||
	shared_memory.application_queue.push(message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<ERTProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										110
									
								
								Software/portapack-mayhem/firmware/baseband/proc_ert.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								Software/portapack-mayhem/firmware/baseband/proc_ert.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_ERT_H__
 | 
			
		||||
#define __PROC_ERT_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "rssi_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#include "channel_decimator.hpp"
 | 
			
		||||
 | 
			
		||||
#include "clock_recovery.hpp"
 | 
			
		||||
#include "symbol_coding.hpp"
 | 
			
		||||
#include "packet_builder.hpp"
 | 
			
		||||
#include "baseband_packet.hpp"
 | 
			
		||||
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <bitset>
 | 
			
		||||
 | 
			
		||||
// ''.join(['%d%d' % (c, 1-c) for c in map(int, bin(0x1f2a60)[2:].zfill(21))])
 | 
			
		||||
constexpr uint64_t scm_preamble_and_sync_manchester { 0b101010101001011001100110010110100101010101 };
 | 
			
		||||
constexpr size_t scm_preamble_and_sync_length { 42 - 10 };
 | 
			
		||||
constexpr size_t scm_payload_length_max { 150 };
 | 
			
		||||
 | 
			
		||||
// ''.join(['%d%d' % (c, 1-c) for c in map(int, bin(0x555516a3)[2:].zfill(32))])
 | 
			
		||||
constexpr uint64_t idm_preamble_and_sync_manchester { 0b0110011001100110011001100110011001010110011010011001100101011010 };
 | 
			
		||||
constexpr size_t idm_preamble_and_sync_length { 64 - 16 };
 | 
			
		||||
 | 
			
		||||
constexpr size_t idm_payload_length_max { 1408 };
 | 
			
		||||
 | 
			
		||||
class ERTProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	const uint32_t baseband_sampling_rate = 4194304;
 | 
			
		||||
	const size_t decimation = 1;
 | 
			
		||||
	const float symbol_rate = 32768;
 | 
			
		||||
 | 
			
		||||
	const uint32_t channel_sampling_rate = baseband_sampling_rate / decimation;
 | 
			
		||||
	const size_t samples_per_symbol = channel_sampling_rate / symbol_rate;
 | 
			
		||||
	const float clock_recovery_rate = symbol_rate * 2;
 | 
			
		||||
 | 
			
		||||
	BasebandThread baseband_thread { baseband_sampling_rate, this, NORMALPRIO + 20, baseband::Direction::Receive };
 | 
			
		||||
	RSSIThread rssi_thread { NORMALPRIO + 10 };
 | 
			
		||||
 | 
			
		||||
	clock_recovery::ClockRecovery<clock_recovery::FixedErrorFilter> clock_recovery {
 | 
			
		||||
		clock_recovery_rate, symbol_rate, { 1.0f / 18.0f },
 | 
			
		||||
		[this](const float symbol) { this->consume_symbol(symbol); }
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	PacketBuilder<BitPattern, NeverMatch, FixedLength> scm_builder {
 | 
			
		||||
		{ scm_preamble_and_sync_manchester, scm_preamble_and_sync_length, 1 },
 | 
			
		||||
		{ },
 | 
			
		||||
		{ scm_payload_length_max },
 | 
			
		||||
		[this](const baseband::Packet& packet) {
 | 
			
		||||
			this->scm_handler(packet);
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	PacketBuilder<BitPattern, NeverMatch, FixedLength> idm_builder {
 | 
			
		||||
		{ idm_preamble_and_sync_manchester, idm_preamble_and_sync_length, 1 },
 | 
			
		||||
		{ },
 | 
			
		||||
		{ idm_payload_length_max },
 | 
			
		||||
		[this](const baseband::Packet& packet) {
 | 
			
		||||
			this->idm_handler(packet);
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	void consume_symbol(const float symbol);
 | 
			
		||||
	void scm_handler(const baseband::Packet& packet);
 | 
			
		||||
	void idm_handler(const baseband::Packet& packet);
 | 
			
		||||
 | 
			
		||||
	float sum_half_period[2];
 | 
			
		||||
	float sum_period[3];
 | 
			
		||||
	float manchester[3];
 | 
			
		||||
 | 
			
		||||
	const size_t average_window { 2048 };
 | 
			
		||||
	int32_t average_i { 0 };
 | 
			
		||||
	int32_t average_q { 0 };
 | 
			
		||||
	size_t average_count { 0 };
 | 
			
		||||
	float offset_i { 0.0f };
 | 
			
		||||
	float offset_q { 0.0f };
 | 
			
		||||
 | 
			
		||||
	float abs(const complex8_t& v);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__PROC_ERT_H__*/
 | 
			
		||||
							
								
								
									
										107
									
								
								Software/portapack-mayhem/firmware/baseband/proc_fsk.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								Software/portapack-mayhem/firmware/baseband/proc_fsk.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_fsk.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
#include "sine_table_int8.hpp"
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
void FSKProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	int8_t re, im;
 | 
			
		||||
	
 | 
			
		||||
	// This is called at 2.28M/2048 = 1113Hz
 | 
			
		||||
	
 | 
			
		||||
	for (size_t i = 0; i < buffer.count; i++) {
 | 
			
		||||
 | 
			
		||||
		if (configured) {
 | 
			
		||||
			if (sample_count >= samples_per_bit) {
 | 
			
		||||
				if (bit_pos > length) {
 | 
			
		||||
					// End of data
 | 
			
		||||
					cur_bit = 0;
 | 
			
		||||
					txprogress_message.done = true;
 | 
			
		||||
					shared_memory.application_queue.push(txprogress_message);
 | 
			
		||||
					configured = false;
 | 
			
		||||
				} else {
 | 
			
		||||
					cur_bit = (shared_memory.bb_data.data[bit_pos >> 3] << (bit_pos & 7)) & 0x80;
 | 
			
		||||
					bit_pos++;
 | 
			
		||||
					if (progress_count >= progress_notice) {
 | 
			
		||||
						progress_count = 0;
 | 
			
		||||
						txprogress_message.progress++;
 | 
			
		||||
						txprogress_message.done = false;
 | 
			
		||||
						shared_memory.application_queue.push(txprogress_message);
 | 
			
		||||
					} else {
 | 
			
		||||
						progress_count++;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				sample_count = 0;
 | 
			
		||||
			} else {
 | 
			
		||||
				sample_count++;
 | 
			
		||||
			}
 | 
			
		||||
		
 | 
			
		||||
			if (cur_bit)
 | 
			
		||||
				phase += shift_one;
 | 
			
		||||
			else
 | 
			
		||||
				phase += shift_zero;
 | 
			
		||||
			
 | 
			
		||||
			sphase = phase + (64 << 24);
 | 
			
		||||
 | 
			
		||||
			re = (sine_table_i8[(sphase & 0xFF000000) >> 24]);
 | 
			
		||||
			im = (sine_table_i8[(phase & 0xFF000000) >> 24]);
 | 
			
		||||
		} else {
 | 
			
		||||
			re = 0;
 | 
			
		||||
			im = 0;
 | 
			
		||||
		}
 | 
			
		||||
	
 | 
			
		||||
		buffer.p[i] = {re, im};
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FSKProcessor::on_message(const Message* const p) {
 | 
			
		||||
	const auto message = *reinterpret_cast<const FSKConfigureMessage*>(p);
 | 
			
		||||
	
 | 
			
		||||
	if (message.id == Message::ID::FSKConfigure) {
 | 
			
		||||
		samples_per_bit = message.samples_per_bit;
 | 
			
		||||
		length = message.stream_length + 32;			// Why ?!
 | 
			
		||||
		
 | 
			
		||||
		shift_one = message.shift * (0xFFFFFFFFULL / 2280000);
 | 
			
		||||
		shift_zero = -shift_one;
 | 
			
		||||
		
 | 
			
		||||
		progress_notice = message.progress_notice;
 | 
			
		||||
		
 | 
			
		||||
		sample_count = samples_per_bit;
 | 
			
		||||
		progress_count = 0;
 | 
			
		||||
		bit_pos = 0;
 | 
			
		||||
		cur_bit = 0;
 | 
			
		||||
		
 | 
			
		||||
		txprogress_message.progress = 0;
 | 
			
		||||
		txprogress_message.done = false;
 | 
			
		||||
		configured = true;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<FSKProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								Software/portapack-mayhem/firmware/baseband/proc_fsk.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								Software/portapack-mayhem/firmware/baseband/proc_fsk.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_FSK_H__
 | 
			
		||||
#define __PROC_FSK_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
 | 
			
		||||
class FSKProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
	
 | 
			
		||||
	void on_message(const Message* const p) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	bool configured = false;
 | 
			
		||||
	
 | 
			
		||||
	BasebandThread baseband_thread { 2280000, this, NORMALPRIO + 20, baseband::Direction::Transmit };
 | 
			
		||||
	
 | 
			
		||||
	uint32_t samples_per_bit { 0 };
 | 
			
		||||
	uint32_t length { 0 };
 | 
			
		||||
	
 | 
			
		||||
    uint32_t shift_zero { }, shift_one { };
 | 
			
		||||
    uint32_t bit_pos { 0 };
 | 
			
		||||
    uint32_t progress_notice { }, progress_count { 0 };
 | 
			
		||||
    uint8_t cur_bit { 0 };
 | 
			
		||||
    uint32_t sample_count { 0 };
 | 
			
		||||
	uint32_t phase { 0 }, sphase { 0 };
 | 
			
		||||
	
 | 
			
		||||
	TXProgressMessage txprogress_message { };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										128
									
								
								Software/portapack-mayhem/firmware/baseband/proc_gps_sim.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								Software/portapack-mayhem/firmware/baseband/proc_gps_sim.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 * Copyright (C) 2020 Shao
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_gps_sim.hpp"
 | 
			
		||||
#include "sine_table_int8.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include "utility.hpp"
 | 
			
		||||
 | 
			
		||||
ReplayProcessor::ReplayProcessor() {
 | 
			
		||||
	channel_filter_low_f = taps_200k_decim_1.low_frequency_normalized * 1000000;
 | 
			
		||||
	channel_filter_high_f = taps_200k_decim_1.high_frequency_normalized * 1000000;
 | 
			
		||||
	channel_filter_transition = taps_200k_decim_1.transition_normalized * 1000000;
 | 
			
		||||
	
 | 
			
		||||
	spectrum_samples = 0;
 | 
			
		||||
 | 
			
		||||
	channel_spectrum.set_decimation_factor(1);
 | 
			
		||||
	
 | 
			
		||||
	configured = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ReplayProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	/* 4MHz, 2048 samples */
 | 
			
		||||
	
 | 
			
		||||
	if (!configured) return;
 | 
			
		||||
	
 | 
			
		||||
	// File data is in C16 format, we need C8
 | 
			
		||||
	// File samplerate is 500kHz, we're at 4MHz
 | 
			
		||||
	// iq_buffer can only be 512 C16 samples (RAM limitation)
 | 
			
		||||
	// To fill up the 2048-sample C8 buffer, we need:
 | 
			
		||||
	// 2048 samples * 2 bytes per sample = 4096 bytes
 | 
			
		||||
	// Since we're oversampling by 4M/500k = 8, we only need 2048/8 = 256 samples from the file and duplicate them 8 times each
 | 
			
		||||
	// So 256 * 4 bytes per sample (C16) = 1024 bytes from the file
 | 
			
		||||
	if( stream ) {                             //sizeof(*buffer.p) = sizeof(C8) = 2*int8 = 2 bytes //buffer.count = 2048
 | 
			
		||||
		const size_t bytes_to_read = sizeof(*buffer.p) * 1 * (buffer.count );	// *2 (C16), /8 (oversampling) should be == 1024
 | 
			
		||||
		bytes_read += stream->read(iq_buffer.p, bytes_to_read);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// Fill and "stretch"
 | 
			
		||||
	for (size_t i = 0; i < buffer.count; i++) {               
 | 
			
		||||
        auto re_out = iq_buffer.p[i].real() ;
 | 
			
		||||
	    auto im_out = iq_buffer.p[i].imag() ;
 | 
			
		||||
		buffer.p[i] = { (int8_t)re_out, (int8_t)im_out };
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	spectrum_samples += buffer.count;
 | 
			
		||||
	if( spectrum_samples >= spectrum_interval_samples ) {
 | 
			
		||||
		spectrum_samples -= spectrum_interval_samples;
 | 
			
		||||
 | 
			
		||||
		txprogress_message.progress = bytes_read / 1024;	// Inform UI about progress
 | 
			
		||||
 | 
			
		||||
		txprogress_message.done = false;
 | 
			
		||||
		shared_memory.application_queue.push(txprogress_message);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ReplayProcessor::on_message(const Message* const message) {
 | 
			
		||||
	switch(message->id) {
 | 
			
		||||
	case Message::ID::UpdateSpectrum:
 | 
			
		||||
	case Message::ID::SpectrumStreamingConfig:
 | 
			
		||||
		channel_spectrum.on_message(message);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case Message::ID::SamplerateConfig:
 | 
			
		||||
		samplerate_config(*reinterpret_cast<const SamplerateConfigMessage*>(message));
 | 
			
		||||
		break;
 | 
			
		||||
	
 | 
			
		||||
	case Message::ID::ReplayConfig:
 | 
			
		||||
		configured = false;
 | 
			
		||||
		bytes_read = 0;
 | 
			
		||||
		replay_config(*reinterpret_cast<const ReplayConfigMessage*>(message));
 | 
			
		||||
		break;
 | 
			
		||||
		
 | 
			
		||||
	// App has prefilled the buffers, we're ready to go now
 | 
			
		||||
	case Message::ID::FIFOData:
 | 
			
		||||
		configured = true;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ReplayProcessor::samplerate_config(const SamplerateConfigMessage& message) {
 | 
			
		||||
	baseband_fs = message.sample_rate;
 | 
			
		||||
	baseband_thread.set_sampling_rate(baseband_fs);
 | 
			
		||||
	spectrum_interval_samples = baseband_fs / spectrum_rate_hz;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ReplayProcessor::replay_config(const ReplayConfigMessage& message) {
 | 
			
		||||
	if( message.config ) {
 | 
			
		||||
		
 | 
			
		||||
		stream = std::make_unique<StreamOutput>(message.config);
 | 
			
		||||
		
 | 
			
		||||
		// Tell application that the buffers and FIFO pointers are ready, prefill
 | 
			
		||||
		shared_memory.application_queue.push(sig_message);
 | 
			
		||||
	} else {
 | 
			
		||||
		stream.reset();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<ReplayProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										78
									
								
								Software/portapack-mayhem/firmware/baseband/proc_gps_sim.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								Software/portapack-mayhem/firmware/baseband/proc_gps_sim.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 * Copyright (C) 2020 Shao
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_GPS_SIM_HPP__
 | 
			
		||||
#define __PROC_GPS_SIM_HPP__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#include "spectrum_collector.hpp"
 | 
			
		||||
 | 
			
		||||
#include "stream_output.hpp"
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
class ReplayProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	ReplayProcessor();
 | 
			
		||||
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
 | 
			
		||||
	void on_message(const Message* const message) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	size_t baseband_fs = 0;
 | 
			
		||||
	static constexpr auto spectrum_rate_hz = 50.0f;
 | 
			
		||||
 | 
			
		||||
	BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Transmit };
 | 
			
		||||
 | 
			
		||||
	std::array<complex8_t, 2048> iq { };
 | 
			
		||||
	const buffer_c8_t iq_buffer {
 | 
			
		||||
		iq.data(),
 | 
			
		||||
		iq.size(),
 | 
			
		||||
		baseband_fs 
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	int32_t channel_filter_low_f = 0;
 | 
			
		||||
	int32_t channel_filter_high_f = 0;
 | 
			
		||||
	int32_t channel_filter_transition = 0;
 | 
			
		||||
 | 
			
		||||
	std::unique_ptr<StreamOutput> stream { };
 | 
			
		||||
 | 
			
		||||
	SpectrumCollector channel_spectrum { };
 | 
			
		||||
	size_t spectrum_interval_samples = 0;
 | 
			
		||||
	size_t spectrum_samples = 0;
 | 
			
		||||
	
 | 
			
		||||
	bool configured { false };
 | 
			
		||||
	uint32_t bytes_read { 0 };
 | 
			
		||||
 | 
			
		||||
	void samplerate_config(const SamplerateConfigMessage& message);
 | 
			
		||||
	void replay_config(const ReplayConfigMessage& message);
 | 
			
		||||
	
 | 
			
		||||
	TXProgressMessage txprogress_message { };
 | 
			
		||||
	RequestSignalMessage sig_message { RequestSignalMessage::Signal::FillRequest };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__PROC_GPS_SIM_HPP__*/
 | 
			
		||||
							
								
								
									
										115
									
								
								Software/portapack-mayhem/firmware/baseband/proc_jammer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								Software/portapack-mayhem/firmware/baseband/proc_jammer.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,115 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_jammer.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
#include "sine_table_int8.hpp"
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
void JammerProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	if (!configured) return;
 | 
			
		||||
	
 | 
			
		||||
	for (size_t i = 0; i < buffer.count; i++) {
 | 
			
		||||
 | 
			
		||||
		if (!jammer_duration) {
 | 
			
		||||
			// Find next enabled range
 | 
			
		||||
			do {
 | 
			
		||||
				current_range++;
 | 
			
		||||
				if (current_range == JAMMER_MAX_CH) current_range = 0;
 | 
			
		||||
			} while (!jammer_channels[current_range].enabled);
 | 
			
		||||
			
 | 
			
		||||
			jammer_duration = jammer_channels[current_range].duration;
 | 
			
		||||
			jammer_bw = jammer_channels[current_range].width / 2;		// TODO: Exact value
 | 
			
		||||
			
 | 
			
		||||
			// Ask for retune
 | 
			
		||||
			message.freq = jammer_channels[current_range].center;
 | 
			
		||||
			message.range = current_range;
 | 
			
		||||
			shared_memory.application_queue.push(message);
 | 
			
		||||
		} else {
 | 
			
		||||
			jammer_duration--;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// Phase noise
 | 
			
		||||
		if (!period_counter) {
 | 
			
		||||
			period_counter = noise_period;
 | 
			
		||||
			
 | 
			
		||||
			if (noise_type == JammerType::TYPE_FSK) {
 | 
			
		||||
				sample = (sample + lfsr) >> 1;
 | 
			
		||||
			} else if (noise_type == JammerType::TYPE_TONE) {
 | 
			
		||||
				tone_delta = 150000 + (lfsr >> 9);	// Approx 100Hz to 6kHz
 | 
			
		||||
			} else if (noise_type == JammerType::TYPE_SWEEP) {
 | 
			
		||||
				sample++;							// This is like saw wave FM
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			feedback = ((lfsr >> 31) ^ (lfsr >> 29) ^ (lfsr >> 15) ^ (lfsr >> 11)) & 1;
 | 
			
		||||
			lfsr = (lfsr << 1) | feedback;
 | 
			
		||||
			if (!lfsr) lfsr = 0x1337;				// Shouldn't do this :(
 | 
			
		||||
		} else {
 | 
			
		||||
			period_counter--;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if (noise_type == JammerType::TYPE_TONE) {
 | 
			
		||||
			aphase += tone_delta;
 | 
			
		||||
			sample = sine_table_i8[(aphase & 0xFF000000) >> 24];
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		delta = sample * jammer_bw;
 | 
			
		||||
		
 | 
			
		||||
		phase += delta;
 | 
			
		||||
		sphase = phase + (64 << 24);
 | 
			
		||||
 | 
			
		||||
		re = (sine_table_i8[(sphase & 0xFF000000) >> 24]);
 | 
			
		||||
		im = (sine_table_i8[(phase & 0xFF000000) >> 24]);
 | 
			
		||||
 | 
			
		||||
		buffer.p[i] = {re, im};
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void JammerProcessor::on_message(const Message* const msg) {
 | 
			
		||||
	if (msg->id == Message::ID::JammerConfigure) {
 | 
			
		||||
		const auto message = *reinterpret_cast<const JammerConfigureMessage*>(msg);
 | 
			
		||||
		
 | 
			
		||||
		if (message.run) {
 | 
			
		||||
			jammer_channels = (JammerChannel*)shared_memory.bb_data.data;
 | 
			
		||||
			noise_type = message.type;
 | 
			
		||||
			noise_period = 3072000 / message.speed;
 | 
			
		||||
			if (noise_type == JammerType::TYPE_SWEEP)
 | 
			
		||||
				noise_period >>= 8;
 | 
			
		||||
			period_counter = 0;
 | 
			
		||||
			jammer_duration = 0;
 | 
			
		||||
			current_range = 0;
 | 
			
		||||
			lfsr = 0xDEAD0012;
 | 
			
		||||
			
 | 
			
		||||
			configured = true;
 | 
			
		||||
		} else {
 | 
			
		||||
			configured = false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<JammerProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										59
									
								
								Software/portapack-mayhem/firmware/baseband/proc_jammer.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								Software/portapack-mayhem/firmware/baseband/proc_jammer.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_JAMMER_H__
 | 
			
		||||
#define __PROC_JAMMER_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
#include "jammer.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace jammer;
 | 
			
		||||
 | 
			
		||||
class JammerProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
	
 | 
			
		||||
	void on_message(const Message* const msg) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	bool configured { false };
 | 
			
		||||
	
 | 
			
		||||
	BasebandThread baseband_thread { 3072000, this, NORMALPRIO + 20, baseband::Direction::Transmit };
 | 
			
		||||
	
 | 
			
		||||
	JammerChannel * jammer_channels {  };
 | 
			
		||||
	
 | 
			
		||||
	JammerType noise_type { };
 | 
			
		||||
	uint32_t tone_delta { 0 }, lfsr { }, feedback { };
 | 
			
		||||
	uint32_t noise_period { 0 }, period_counter { 0 };
 | 
			
		||||
    uint32_t jammer_duration { 0 };
 | 
			
		||||
    uint32_t current_range { 0 };
 | 
			
		||||
	int64_t jammer_center { 0 }, jammer_bw { 0 };
 | 
			
		||||
    uint32_t sample_count { 0 };
 | 
			
		||||
	uint32_t aphase { 0 }, phase { 0 }, delta { 0 }, sphase { 0 };
 | 
			
		||||
	int8_t sample { 0 };
 | 
			
		||||
	int8_t re { 0 }, im { 0 };
 | 
			
		||||
	RetuneMessage message { };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										173
									
								
								Software/portapack-mayhem/firmware/baseband/proc_mictx.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								Software/portapack-mayhem/firmware/baseband/proc_mictx.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,173 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 * 
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_mictx.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
#include "sine_table_int8.hpp"
 | 
			
		||||
#include "tonesets.hpp"
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
void MicTXProcessor::execute(const buffer_c8_t& buffer){
 | 
			
		||||
 | 
			
		||||
	// This is called at 1536000/2048 = 750Hz
 | 
			
		||||
	
 | 
			
		||||
	if (!configured) return;
 | 
			
		||||
	
 | 
			
		||||
	audio_input.read_audio_buffer(audio_buffer);
 | 
			
		||||
	modulator->set_gain_vumeter_beep(audio_gain, play_beep ) ;	
 | 
			
		||||
	modulator->execute(audio_buffer, buffer, configured, beep_index, beep_timer, txprogress_message, level_message, power_acc_count, divider );	// Now "Key Tones & CTCSS" baseband additon inside FM mod. dsp_modulate.cpp"
 | 
			
		||||
    
 | 
			
		||||
   /* Original fw 1.3.1  good reference, beep and vu-meter
 | 
			
		||||
	for (size_t i = 0; i < buffer.count; i++) {
 | 
			
		||||
		
 | 
			
		||||
		if (!play_beep) {
 | 
			
		||||
			sample = audio_buffer.p[i >> 6] >> 8;			// 1536000 / 64 = 24000
 | 
			
		||||
			sample *= audio_gain;
 | 
			
		||||
			
 | 
			
		||||
			power_acc += (sample < 0) ? -sample : sample;	// Power average for UI vu-meter
 | 
			
		||||
			
 | 
			
		||||
			if (power_acc_count) {
 | 
			
		||||
				power_acc_count--;
 | 
			
		||||
			} else {
 | 
			
		||||
				power_acc_count = divider;
 | 
			
		||||
				level_message.value = power_acc / (divider / 4);	// Why ?
 | 
			
		||||
				shared_memory.application_queue.push(level_message);
 | 
			
		||||
				power_acc = 0;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if (beep_timer) {
 | 
			
		||||
				beep_timer--;
 | 
			
		||||
			} else {
 | 
			
		||||
				beep_timer = baseband_fs * 0.05;			// 50ms
 | 
			
		||||
				
 | 
			
		||||
				if (beep_index == BEEP_TONES_NB) {
 | 
			
		||||
					configured = false;
 | 
			
		||||
					shared_memory.application_queue.push(txprogress_message);
 | 
			
		||||
				} else {
 | 
			
		||||
					beep_gen.configure(beep_deltas[beep_index], 1.0);
 | 
			
		||||
					beep_index++;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			sample = beep_gen.process(0);    // TODO : Pending how to move inside modulate.cpp
 | 
			
		||||
		} 
 | 
			
		||||
	 */ 	
 | 
			
		||||
				
 | 
			
		||||
       /* Original fw 1.3.1  good reference FM moulation version, including "key tones CTCSS"  fw 1.3.1 
 | 
			
		||||
		sample = tone_gen.process(sample);
 | 
			
		||||
				
 | 
			
		||||
		// FM
 | 
			
		||||
		if (configured) {
 | 
			
		||||
			delta = sample * fm_delta;
 | 
			
		||||
			
 | 
			
		||||
			phase += delta;
 | 
			
		||||
			sphase = phase >> 24;
 | 
			
		||||
 | 
			
		||||
			re = (sine_table_i8[(sphase + 64) & 255]);
 | 
			
		||||
			im = (sine_table_i8[sphase]);
 | 
			
		||||
		} else {
 | 
			
		||||
			re = 0;
 | 
			
		||||
			im = 0;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		buffer.p[i] = { re, im };
 | 
			
		||||
		
 | 
			
		||||
	}  */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MicTXProcessor::on_message(const Message* const msg) {
 | 
			
		||||
	const AudioTXConfigMessage config_message = *reinterpret_cast<const AudioTXConfigMessage*>(msg);
 | 
			
		||||
	const RequestSignalMessage request_message = *reinterpret_cast<const RequestSignalMessage*>(msg);
 | 
			
		||||
	
 | 
			
		||||
	switch(msg->id) {
 | 
			
		||||
		case Message::ID::AudioTXConfig:
 | 
			
		||||
			if (fm_enabled) {
 | 
			
		||||
				 dsp::modulate::FM *fm = new dsp::modulate::FM();
 | 
			
		||||
 | 
			
		||||
				// Config fm_delta private var inside DSP modulate.cpp
 | 
			
		||||
				 fm->set_fm_delta(config_message.deviation_hz * (0xFFFFFFUL / baseband_fs));
 | 
			
		||||
 | 
			
		||||
				 // Config properly the private tone_gen function parameters inside DSP modulate.cpp  	
 | 
			
		||||
				 fm->set_tone_gen_configure(config_message.tone_key_delta, config_message.tone_key_mix_weight);		
 | 
			
		||||
				modulator = fm;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (usb_enabled) {
 | 
			
		||||
				modulator = new dsp::modulate::SSB();
 | 
			
		||||
				modulator->set_mode(dsp::modulate::Mode::USB);
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			if (lsb_enabled) {
 | 
			
		||||
				modulator = new dsp::modulate::SSB();
 | 
			
		||||
				modulator->set_mode(dsp::modulate::Mode::LSB);
 | 
			
		||||
			}
 | 
			
		||||
			if (am_enabled) {
 | 
			
		||||
				modulator = new dsp::modulate::AM();
 | 
			
		||||
				modulator->set_mode(dsp::modulate::Mode::AM);
 | 
			
		||||
			}
 | 
			
		||||
			if (dsb_enabled) {
 | 
			
		||||
				modulator = new dsp::modulate::AM();
 | 
			
		||||
				modulator->set_mode(dsp::modulate::Mode::DSB);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			modulator->set_over(baseband_fs / 24000); // Keep no change.
 | 
			
		||||
			
 | 
			
		||||
			am_enabled = config_message.am_enabled;
 | 
			
		||||
			usb_enabled = config_message.usb_enabled;
 | 
			
		||||
			lsb_enabled = config_message.lsb_enabled;
 | 
			
		||||
			dsb_enabled = config_message.dsb_enabled;
 | 
			
		||||
			if (!am_enabled || !usb_enabled || !lsb_enabled || !dsb_enabled) {
 | 
			
		||||
				fm_enabled = true;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			audio_gain = config_message.audio_gain;
 | 
			
		||||
			divider = config_message.divider;
 | 
			
		||||
			power_acc_count = 0;
 | 
			
		||||
 | 
			
		||||
			// now this config  moved, in the case Message::ID::AudioTXConfig , only FM case.
 | 
			
		||||
			// tone_gen.configure(config_message.tone_key_delta, config_message.tone_key_mix_weight);	
 | 
			
		||||
			
 | 
			
		||||
			txprogress_message.done = true;
 | 
			
		||||
 | 
			
		||||
			play_beep = false;
 | 
			
		||||
			configured = true;
 | 
			
		||||
			break;
 | 
			
		||||
		
 | 
			
		||||
		case Message::ID::RequestSignal:
 | 
			
		||||
			if (request_message.signal == RequestSignalMessage::Signal::BeepRequest) {
 | 
			
		||||
				beep_index = 0;
 | 
			
		||||
				beep_timer = 0;
 | 
			
		||||
				play_beep = true;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<MicTXProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										78
									
								
								Software/portapack-mayhem/firmware/baseband/proc_mictx.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								Software/portapack-mayhem/firmware/baseband/proc_mictx.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 * 
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_MICTX_H__
 | 
			
		||||
#define __PROC_MICTX_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "audio_input.hpp"
 | 
			
		||||
#include "tone_gen.hpp"
 | 
			
		||||
#include "dsp_modulate.hpp"
 | 
			
		||||
 | 
			
		||||
class MicTXProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
	
 | 
			
		||||
	void on_message(const Message* const msg) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr size_t baseband_fs = 1536000U;
 | 
			
		||||
	
 | 
			
		||||
	bool configured { false };
 | 
			
		||||
	
 | 
			
		||||
	BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Transmit };
 | 
			
		||||
	
 | 
			
		||||
	int16_t audio_data[64];
 | 
			
		||||
	buffer_s16_t audio_buffer {
 | 
			
		||||
		audio_data,
 | 
			
		||||
		sizeof(int16_t) * 64
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	AudioInput audio_input { };
 | 
			
		||||
	// ToneGen tone_gen { };   moved to  dsp_modulate.cpp
 | 
			
		||||
	// ToneGen beep_gen { };   moved to  dsp_modulate.cpp	
 | 
			
		||||
	dsp::modulate::Modulator *modulator = NULL ;
 | 
			
		||||
 | 
			
		||||
	bool am_enabled { false };
 | 
			
		||||
	bool fm_enabled { true };
 | 
			
		||||
	bool usb_enabled { false };
 | 
			
		||||
	bool lsb_enabled { false };
 | 
			
		||||
	bool dsb_enabled { false };
 | 
			
		||||
 | 
			
		||||
	uint32_t divider { };
 | 
			
		||||
	float audio_gain { };
 | 
			
		||||
	uint64_t power_acc { 0 };
 | 
			
		||||
	uint32_t power_acc_count { 0 };
 | 
			
		||||
	bool play_beep { false };
 | 
			
		||||
	uint32_t fm_delta { 0 };
 | 
			
		||||
	uint32_t phase { 0 }, sphase { 0 };
 | 
			
		||||
	int32_t sample { 0 }, delta { };
 | 
			
		||||
	uint32_t beep_index { }, beep_timer { };
 | 
			
		||||
	
 | 
			
		||||
	int8_t re { 0 }, im { 0 };
 | 
			
		||||
	
 | 
			
		||||
	AudioLevelReportMessage level_message { };
 | 
			
		||||
	TXProgressMessage txprogress_message { };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										177
									
								
								Software/portapack-mayhem/firmware/baseband/proc_nfm_audio.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								Software/portapack-mayhem/firmware/baseband/proc_nfm_audio.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,177 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_nfm_audio.hpp"
 | 
			
		||||
#include "sine_table_int8.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
void NarrowbandFMAudio::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	//bool new_state;
 | 
			
		||||
	
 | 
			
		||||
	if( !configured ) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
 | 
			
		||||
	const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer);
 | 
			
		||||
 | 
			
		||||
	channel_spectrum.feed(decim_1_out, channel_filter_low_f, channel_filter_high_f, channel_filter_transition);
 | 
			
		||||
 | 
			
		||||
	const auto channel_out = channel_filter.execute(decim_1_out, dst_buffer);
 | 
			
		||||
 | 
			
		||||
	feed_channel_stats(channel_out);
 | 
			
		||||
 | 
			
		||||
	if (!pitch_rssi_enabled) {
 | 
			
		||||
		// Normal mode, output demodulated audio
 | 
			
		||||
		auto audio = demod.execute(channel_out, audio_buffer);
 | 
			
		||||
		audio_output.write(audio);
 | 
			
		||||
		
 | 
			
		||||
		if (ctcss_detect_enabled) {
 | 
			
		||||
			/* 24kHz int16_t[16]
 | 
			
		||||
			 * -> FIR filter, <300Hz pass, >300Hz stop, gain of 1
 | 
			
		||||
			 * -> 12kHz int16_t[8] */
 | 
			
		||||
			auto audio_ctcss = ctcss_filter.execute(audio, work_audio_buffer);
 | 
			
		||||
			
 | 
			
		||||
			// s16 to f32 for hpf
 | 
			
		||||
			std::array<float, 8> audio_f;
 | 
			
		||||
			for (size_t i = 0; i < audio_ctcss.count; i++) {
 | 
			
		||||
				audio_f[i] = audio_ctcss.p[i] * ki;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			hpf.execute_in_place(buffer_f32_t {
 | 
			
		||||
				audio_f.data(),
 | 
			
		||||
				audio_ctcss.count,
 | 
			
		||||
				audio_ctcss.sampling_rate
 | 
			
		||||
				});
 | 
			
		||||
			
 | 
			
		||||
			// Zero-crossing detection
 | 
			
		||||
			for (size_t c = 0; c < audio_ctcss.count; c++) {
 | 
			
		||||
				cur_sample = audio_f[c];
 | 
			
		||||
				if (cur_sample * prev_sample < 0.0) {
 | 
			
		||||
					z_acc += z_timer;
 | 
			
		||||
					z_timer = 0;
 | 
			
		||||
					z_count++;
 | 
			
		||||
				} else
 | 
			
		||||
					z_timer++;
 | 
			
		||||
				prev_sample = cur_sample;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			if (z_count >= 30) {
 | 
			
		||||
				ctcss_message.value = (100 * 12000 / 2 * z_count) / z_acc;
 | 
			
		||||
				shared_memory.application_queue.push(ctcss_message);
 | 
			
		||||
				z_count = 0;
 | 
			
		||||
				z_acc = 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		// Direction-finding mode; output tone with pitch related to RSSI
 | 
			
		||||
		for (size_t c = 0; c < 16; c++) {
 | 
			
		||||
			tone_buffer.p[c] = (sine_table_i8[(tone_phase & 0xFF000000U) >> 24]) * 128;
 | 
			
		||||
			tone_phase += tone_delta;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		audio_output.write(tone_buffer);
 | 
			
		||||
		
 | 
			
		||||
		/*new_state = audio_output.is_squelched();
 | 
			
		||||
		
 | 
			
		||||
		if (new_state && !old_state)
 | 
			
		||||
			shared_memory.application_queue.push(sig_message);
 | 
			
		||||
		
 | 
			
		||||
		old_state = new_state;*/	
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NarrowbandFMAudio::on_message(const Message* const message) {
 | 
			
		||||
	switch(message->id) {
 | 
			
		||||
	case Message::ID::UpdateSpectrum:
 | 
			
		||||
	case Message::ID::SpectrumStreamingConfig:
 | 
			
		||||
		channel_spectrum.on_message(message);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case Message::ID::NBFMConfigure:
 | 
			
		||||
		configure(*reinterpret_cast<const NBFMConfigureMessage*>(message));
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case Message::ID::CaptureConfig:
 | 
			
		||||
		capture_config(*reinterpret_cast<const CaptureConfigMessage*>(message));
 | 
			
		||||
		break;
 | 
			
		||||
	
 | 
			
		||||
	case Message::ID::PitchRSSIConfigure:
 | 
			
		||||
		pitch_rssi_config(*reinterpret_cast<const PitchRSSIConfigureMessage*>(message));
 | 
			
		||||
		break;
 | 
			
		||||
		
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NarrowbandFMAudio::configure(const NBFMConfigureMessage& message) {
 | 
			
		||||
	constexpr size_t decim_0_input_fs = baseband_fs;
 | 
			
		||||
	constexpr size_t decim_0_output_fs = decim_0_input_fs / decim_0.decimation_factor;
 | 
			
		||||
 | 
			
		||||
	constexpr size_t decim_1_input_fs = decim_0_output_fs;
 | 
			
		||||
	constexpr size_t decim_1_output_fs = decim_1_input_fs / decim_1.decimation_factor;
 | 
			
		||||
 | 
			
		||||
	constexpr size_t channel_filter_input_fs = decim_1_output_fs;
 | 
			
		||||
	const size_t channel_filter_output_fs = channel_filter_input_fs / message.channel_decimation;
 | 
			
		||||
 | 
			
		||||
	const size_t demod_input_fs = channel_filter_output_fs;
 | 
			
		||||
 | 
			
		||||
	decim_0.configure(message.decim_0_filter.taps, 33554432);
 | 
			
		||||
	decim_1.configure(message.decim_1_filter.taps, 131072);
 | 
			
		||||
	channel_filter.configure(message.channel_filter.taps, message.channel_decimation);
 | 
			
		||||
	demod.configure(demod_input_fs, message.deviation);
 | 
			
		||||
	channel_filter_low_f = message.channel_filter.low_frequency_normalized * channel_filter_input_fs;
 | 
			
		||||
	channel_filter_high_f = message.channel_filter.high_frequency_normalized * channel_filter_input_fs;
 | 
			
		||||
	channel_filter_transition = message.channel_filter.transition_normalized * channel_filter_input_fs;
 | 
			
		||||
	channel_spectrum.set_decimation_factor(1.0f);
 | 
			
		||||
	audio_output.configure(message.audio_hpf_config, message.audio_deemph_config, (float)message.squelch_level / 100.0);
 | 
			
		||||
	
 | 
			
		||||
	hpf.configure(audio_24k_hpf_30hz_config);
 | 
			
		||||
	ctcss_filter.configure(taps_64_lp_025_025.taps);
 | 
			
		||||
 | 
			
		||||
	configured = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NarrowbandFMAudio::pitch_rssi_config(const PitchRSSIConfigureMessage& message) {
 | 
			
		||||
	pitch_rssi_enabled = message.enabled;
 | 
			
		||||
	tone_delta = (message.rssi + 1000) * ((1ULL << 32) / 24000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NarrowbandFMAudio::capture_config(const CaptureConfigMessage& message) {
 | 
			
		||||
	if( message.config ) {
 | 
			
		||||
		audio_output.set_stream(std::make_unique<StreamInput>(message.config));
 | 
			
		||||
	} else {
 | 
			
		||||
		audio_output.set_stream(nullptr);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<NarrowbandFMAudio>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										109
									
								
								Software/portapack-mayhem/firmware/baseband/proc_nfm_audio.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								Software/portapack-mayhem/firmware/baseband/proc_nfm_audio.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_NFM_AUDIO_H__
 | 
			
		||||
#define __PROC_NFM_AUDIO_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "rssi_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_decimate.hpp"
 | 
			
		||||
#include "dsp_demodulate.hpp"
 | 
			
		||||
#include "dsp_iir.hpp"
 | 
			
		||||
 | 
			
		||||
#include "audio_output.hpp"
 | 
			
		||||
#include "spectrum_collector.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
class NarrowbandFMAudio : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
 | 
			
		||||
	void on_message(const Message* const message) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr size_t baseband_fs = 3072000;
 | 
			
		||||
 | 
			
		||||
	BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
 | 
			
		||||
	RSSIThread rssi_thread { NORMALPRIO + 10 };
 | 
			
		||||
 | 
			
		||||
	std::array<complex16_t, 512> dst { };
 | 
			
		||||
	const buffer_c16_t dst_buffer {
 | 
			
		||||
		dst.data(),
 | 
			
		||||
		dst.size()
 | 
			
		||||
	};
 | 
			
		||||
	const buffer_s16_t work_audio_buffer {
 | 
			
		||||
		(int16_t*)dst.data(),
 | 
			
		||||
		sizeof(dst) / sizeof(int16_t)
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	std::array<int16_t, 16> audio { };
 | 
			
		||||
	const buffer_s16_t audio_buffer {
 | 
			
		||||
		(int16_t*)audio.data(),
 | 
			
		||||
		sizeof(audio) / sizeof(int16_t)
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	std::array<int16_t, 16> tone { };
 | 
			
		||||
	const buffer_s16_t tone_buffer {
 | 
			
		||||
		(int16_t*)tone.data(),
 | 
			
		||||
		sizeof(tone) / sizeof(int16_t)
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { };
 | 
			
		||||
	dsp::decimate::FIRC16xR16x32Decim8 decim_1 { };
 | 
			
		||||
	dsp::decimate::FIRAndDecimateComplex channel_filter { };
 | 
			
		||||
	int32_t channel_filter_low_f = 0;
 | 
			
		||||
	int32_t channel_filter_high_f = 0;
 | 
			
		||||
	int32_t channel_filter_transition = 0;
 | 
			
		||||
	
 | 
			
		||||
	// For CTCSS decoding
 | 
			
		||||
	dsp::decimate::FIR64AndDecimateBy2Real ctcss_filter { };
 | 
			
		||||
	IIRBiquadFilter hpf { };
 | 
			
		||||
 | 
			
		||||
	dsp::demodulate::FM demod { };
 | 
			
		||||
 | 
			
		||||
	AudioOutput audio_output { };
 | 
			
		||||
 | 
			
		||||
	SpectrumCollector channel_spectrum { };
 | 
			
		||||
	
 | 
			
		||||
	uint32_t tone_phase { 0 };
 | 
			
		||||
	uint32_t tone_delta { 0 };
 | 
			
		||||
	bool pitch_rssi_enabled { false };
 | 
			
		||||
	
 | 
			
		||||
	float cur_sample { }, prev_sample { };
 | 
			
		||||
	uint32_t z_acc { 0}, z_timer { 0 }, z_count { 0 };
 | 
			
		||||
	bool ctcss_detect_enabled { true };
 | 
			
		||||
	static constexpr float k = 32768.0f;
 | 
			
		||||
	static constexpr float ki = 1.0f / k;
 | 
			
		||||
 | 
			
		||||
	bool configured { false };
 | 
			
		||||
	void pitch_rssi_config(const PitchRSSIConfigureMessage& message);
 | 
			
		||||
	void configure(const NBFMConfigureMessage& message);
 | 
			
		||||
	void capture_config(const CaptureConfigMessage& message);
 | 
			
		||||
	
 | 
			
		||||
	//RequestSignalMessage sig_message { RequestSignalMessage::Signal::Squelched };
 | 
			
		||||
	CodedSquelchMessage ctcss_message { 0 };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__PROC_NFM_AUDIO_H__*/
 | 
			
		||||
							
								
								
									
										38
									
								
								Software/portapack-mayhem/firmware/baseband/proc_noop.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								Software/portapack-mayhem/firmware/baseband/proc_noop.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_noop.hpp"
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
void NOOPProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	for (size_t i = 0; i<buffer.count; i++) {
 | 
			
		||||
		buffer.p[i] = {0, 0};
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<NOOPProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								Software/portapack-mayhem/firmware/baseband/proc_noop.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								Software/portapack-mayhem/firmware/baseband/proc_noop.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_NOOP_H__
 | 
			
		||||
#define __PROC_NOOP_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
 | 
			
		||||
class NOOPProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	BasebandThread baseband_thread { 1536000, this, NORMALPRIO + 20, baseband::Direction::Transmit };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										283
									
								
								Software/portapack-mayhem/firmware/baseband/proc_nrfrx.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								Software/portapack-mayhem/firmware/baseband/proc_nrfrx.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,283 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 * Copyright (C) 2020 Shao
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_nrfrx.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
void NRFRxProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	if (!configured) return;
 | 
			
		||||
	
 | 
			
		||||
	// FM demodulation
 | 
			
		||||
 | 
			
		||||
	const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
 | 
			
		||||
	feed_channel_stats(decim_0_out);
 | 
			
		||||
	
 | 
			
		||||
	auto audio_oversampled = demod.execute(decim_0_out, work_audio_buffer);
 | 
			
		||||
	// Audio signal processing
 | 
			
		||||
	for (size_t c = 0; c < audio_oversampled.count; c++) {
 | 
			
		||||
                int g_srate = 4; //4 for 250KPS
 | 
			
		||||
		//int g_srate = 1; //1 for 1MPS, not working yet
 | 
			
		||||
		int32_t current_sample = audio_oversampled.p[c]; //if I directly use this, some results can pass crc but not correct.
 | 
			
		||||
                rb_head++;
 | 
			
		||||
	        rb_head=(rb_head)%RB_SIZE;
 | 
			
		||||
 | 
			
		||||
                rb_buf[rb_head] = current_sample;
 | 
			
		||||
 | 
			
		||||
		skipSamples = skipSamples - 1;
 | 
			
		||||
 | 
			
		||||
		if (skipSamples<1)
 | 
			
		||||
		{
 | 
			
		||||
			int32_t threshold_tmp=0;
 | 
			
		||||
			for (int c=0;c<8*g_srate;c++)
 | 
			
		||||
			{
 | 
			
		||||
				threshold_tmp = threshold_tmp + (int32_t)rb_buf[(rb_head+c)%RB_SIZE];
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			g_threshold = (int32_t)threshold_tmp/(8*g_srate);
 | 
			
		||||
	
 | 
			
		||||
			int transitions=0;
 | 
			
		||||
			if (rb_buf[(rb_head + 9*g_srate)%RB_SIZE] > g_threshold)
 | 
			
		||||
			{
 | 
			
		||||
				for (int c=0;c<8;c++)
 | 
			
		||||
				{
 | 
			
		||||
					if (rb_buf[(rb_head + c*g_srate)%RB_SIZE] > rb_buf[(rb_head + (c+1)*g_srate)%RB_SIZE])
 | 
			
		||||
						transitions = transitions + 1;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				for (int c=0;c<8;c++)
 | 
			
		||||
				{
 | 
			
		||||
					if (rb_buf[(rb_head + c*g_srate)%RB_SIZE] < rb_buf[(rb_head + (c+1)*g_srate)%RB_SIZE])
 | 
			
		||||
						transitions = transitions + 1;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			bool packet_detected=false;
 | 
			
		||||
			//if ( transitions==4 && abs(g_threshold)<15500)
 | 
			
		||||
			if ( transitions==4 && abs(g_threshold)<15500)
 | 
			
		||||
			{
 | 
			
		||||
				int packet_length = 0;
 | 
			
		||||
				uint8_t tmp_buf[10];
 | 
			
		||||
				uint8_t packet_data[500];
 | 
			
		||||
				uint8_t packet_packed[50];
 | 
			
		||||
				uint16_t pcf;
 | 
			
		||||
				uint32_t packet_crc;
 | 
			
		||||
				uint32_t calced_crc;
 | 
			
		||||
				uint64_t packet_addr_l;
 | 
			
		||||
 | 
			
		||||
				/* extract address */
 | 
			
		||||
				packet_addr_l=0;
 | 
			
		||||
 | 
			
		||||
				for (int t=0;t<5;t++)
 | 
			
		||||
				{
 | 
			
		||||
					bool current_bit;
 | 
			
		||||
					uint8_t byte=0;
 | 
			
		||||
					for (int c=0;c<8;c++) 
 | 
			
		||||
					{
 | 
			
		||||
						if (rb_buf[(rb_head+(1*8+t*8+c)*g_srate)%RB_SIZE] > g_threshold)
 | 
			
		||||
							current_bit = true;
 | 
			
		||||
						else
 | 
			
		||||
							current_bit = false;
 | 
			
		||||
						byte |= current_bit << (7-c);
 | 
			
		||||
					}
 | 
			
		||||
					tmp_buf[t]=byte;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				for (int t=0;t<5;t++) packet_addr_l|=((uint64_t)tmp_buf[t])<<(4-t)*8;
 | 
			
		||||
 | 
			
		||||
				//channel_number = 26;
 | 
			
		||||
 | 
			
		||||
				
 | 
			
		||||
				/* extract pcf */
 | 
			
		||||
				for (int t=0;t<2;t++)
 | 
			
		||||
				{
 | 
			
		||||
					bool current_bit;
 | 
			
		||||
					uint8_t byte=0;
 | 
			
		||||
					for (int c=0;c<8;c++) 
 | 
			
		||||
					{
 | 
			
		||||
						if (rb_buf[(rb_head+(6*8+t*8+c)*g_srate)%RB_SIZE] > g_threshold)
 | 
			
		||||
							current_bit = true;
 | 
			
		||||
						else
 | 
			
		||||
							current_bit = false;
 | 
			
		||||
						byte |= current_bit << (7-c);
 | 
			
		||||
					}
 | 
			
		||||
					tmp_buf[t]=byte;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				pcf = tmp_buf[0]<<8 | tmp_buf[1];
 | 
			
		||||
				pcf >>=7;
 | 
			
		||||
 | 
			
		||||
				/* extract packet length, avoid excessive length packets */
 | 
			
		||||
				if(packet_length == 0)
 | 
			
		||||
					packet_length=(int)pcf>>3;
 | 
			
		||||
				if (packet_length>32) 
 | 
			
		||||
					packet_detected = false;
 | 
			
		||||
 | 
			
		||||
				/* extract data */
 | 
			
		||||
				for (int t=0;t<packet_length;t++)
 | 
			
		||||
				{
 | 
			
		||||
					bool current_bit;
 | 
			
		||||
					uint8_t byte=0;
 | 
			
		||||
					for (int c=0;c<8;c++) 
 | 
			
		||||
					{
 | 
			
		||||
						if (rb_buf[(rb_head+(6*8+9+t*8+c)*g_srate)%RB_SIZE] > g_threshold)
 | 
			
		||||
							current_bit = true;
 | 
			
		||||
						else
 | 
			
		||||
							current_bit = false;
 | 
			
		||||
						byte |= current_bit << (7-c);
 | 
			
		||||
					}
 | 
			
		||||
					packet_data[t]=byte;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				/* Prepare packed bit stream for CRC calculation */
 | 
			
		||||
				uint64_t packet_header=packet_addr_l;
 | 
			
		||||
				packet_header<<=9;
 | 
			
		||||
				packet_header|=pcf;
 | 
			
		||||
				for (int c=0;c<7;c++){
 | 
			
		||||
					packet_packed[c]=(packet_header>>((6-c)*8))&0xFF;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				for (int c=0;c<packet_length;c++){
 | 
			
		||||
					packet_packed[c+7]=packet_data[c];
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				/* calculate packet crc */
 | 
			
		||||
				const uint8_t* data = packet_packed; 
 | 
			
		||||
				size_t data_len =  7+packet_length;
 | 
			
		||||
				bool bit;
 | 
			
		||||
				uint8_t cc;
 | 
			
		||||
				uint_fast16_t crc=0x3C18;
 | 
			
		||||
				while (data_len--) {
 | 
			
		||||
				cc = *data++;
 | 
			
		||||
				for (uint8_t i = 0x80; i > 0; i >>= 1) 
 | 
			
		||||
				{
 | 
			
		||||
					bit = crc & 0x8000;
 | 
			
		||||
					if (cc & i) 
 | 
			
		||||
					{
 | 
			
		||||
						bit = !bit;
 | 
			
		||||
					}
 | 
			
		||||
					crc <<= 1;
 | 
			
		||||
					if (bit) 
 | 
			
		||||
					{
 | 
			
		||||
						crc ^= 0x1021;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
					crc &= 0xffff;
 | 
			
		||||
				}
 | 
			
		||||
				calced_crc = (uint16_t)(crc & 0xffff);
 | 
			
		||||
 | 
			
		||||
				/* extract crc */
 | 
			
		||||
				for (int t=0;t<2;t++)
 | 
			
		||||
				{
 | 
			
		||||
					bool current_bit;
 | 
			
		||||
					uint8_t byte=0;
 | 
			
		||||
					for (int c=0;c<8;c++) 
 | 
			
		||||
					{
 | 
			
		||||
						if (rb_buf[(rb_head+((6+packet_length)*8+9+t*8+c)*g_srate)%RB_SIZE] > g_threshold)
 | 
			
		||||
							current_bit = true;
 | 
			
		||||
						else
 | 
			
		||||
							current_bit = false;
 | 
			
		||||
						byte |= current_bit << (7-c);
 | 
			
		||||
					}
 | 
			
		||||
					tmp_buf[t]=byte;
 | 
			
		||||
				}
 | 
			
		||||
				packet_crc = tmp_buf[0]<<8 | tmp_buf[1];
 | 
			
		||||
 | 
			
		||||
				/* NRF24L01+ packet found, dump information */
 | 
			
		||||
				//if (packet_addr_l==0xE7E7E7E7)
 | 
			
		||||
				if (packet_crc==calced_crc)
 | 
			
		||||
				{
 | 
			
		||||
					data_message.is_data = false;
 | 
			
		||||
					data_message.value = 'A';
 | 
			
		||||
					shared_memory.application_queue.push(data_message);
 | 
			
		||||
 | 
			
		||||
					data_message.is_data = true;
 | 
			
		||||
					data_message.value = packet_addr_l;
 | 
			
		||||
					shared_memory.application_queue.push(data_message);
 | 
			
		||||
 | 
			
		||||
					for (int c=0;c<7;c++)
 | 
			
		||||
					{
 | 
			
		||||
						data_message.is_data = true;
 | 
			
		||||
						data_message.value = packet_addr_l >> 8;
 | 
			
		||||
						shared_memory.application_queue.push(data_message);
 | 
			
		||||
					}
 | 
			
		||||
					/*data_message.is_data = true;
 | 
			
		||||
					data_message.value = packet_addr_l;
 | 
			
		||||
					shared_memory.application_queue.push(data_message);
 | 
			
		||||
 | 
			
		||||
					data_message.is_data = true;
 | 
			
		||||
					data_message.value = packet_addr_l >> 8;
 | 
			
		||||
					shared_memory.application_queue.push(data_message);*/
 | 
			
		||||
 | 
			
		||||
					data_message.is_data = false;
 | 
			
		||||
					data_message.value = 'B';
 | 
			
		||||
					shared_memory.application_queue.push(data_message);
 | 
			
		||||
 | 
			
		||||
					for (int c=0;c<packet_length;c++)
 | 
			
		||||
					{
 | 
			
		||||
						data_message.is_data = true;
 | 
			
		||||
						data_message.value = packet_data[c];
 | 
			
		||||
						shared_memory.application_queue.push(data_message);
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					data_message.is_data = false;
 | 
			
		||||
					data_message.value = 'C';
 | 
			
		||||
					shared_memory.application_queue.push(data_message);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
					packet_detected = true;
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
					packet_detected = false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (packet_detected) 
 | 
			
		||||
			{
 | 
			
		||||
				skipSamples=20;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NRFRxProcessor::on_message(const Message* const message) {
 | 
			
		||||
	if (message->id == Message::ID::NRFRxConfigure)
 | 
			
		||||
		configure(*reinterpret_cast<const NRFRxConfigureMessage*>(message));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NRFRxProcessor::configure(const NRFRxConfigureMessage& message) {	
 | 
			
		||||
	(void)message; //avoir unused warning
 | 
			
		||||
	decim_0.configure(taps_200k_wfm_decim_0.taps, 33554432);
 | 
			
		||||
	decim_1.configure(taps_200k_wfm_decim_1.taps, 131072);
 | 
			
		||||
	demod.configure(audio_fs, 5000);
 | 
			
		||||
 | 
			
		||||
	configured = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<NRFRxProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										96
									
								
								Software/portapack-mayhem/firmware/baseband/proc_nrfrx.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								Software/portapack-mayhem/firmware/baseband/proc_nrfrx.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 * Copyright (C) 2020 Shao
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_NRFRX_H__
 | 
			
		||||
#define __PROC_NRFRX_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
#include "rssi_thread.hpp"
 | 
			
		||||
 | 
			
		||||
#include "dsp_decimate.hpp"
 | 
			
		||||
#include "dsp_demodulate.hpp"
 | 
			
		||||
 | 
			
		||||
#include "audio_output.hpp"
 | 
			
		||||
 | 
			
		||||
#include "fifo.hpp"
 | 
			
		||||
#include "message.hpp"
 | 
			
		||||
 | 
			
		||||
class NRFRxProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
 | 
			
		||||
	void on_message(const Message* const message) override;
 | 
			
		||||
	
 | 
			
		||||
private:
 | 
			
		||||
	static constexpr size_t baseband_fs = 4000000;
 | 
			
		||||
	static constexpr size_t audio_fs = baseband_fs / 8 / 8 / 2;
 | 
			
		||||
	
 | 
			
		||||
	BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
 | 
			
		||||
	RSSIThread rssi_thread { NORMALPRIO + 10 };
 | 
			
		||||
	
 | 
			
		||||
	std::array<complex16_t, 512> dst { };
 | 
			
		||||
	const buffer_c16_t dst_buffer {
 | 
			
		||||
		dst.data(),
 | 
			
		||||
		dst.size()
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
        std::array<complex16_t, 512> spectrum { };
 | 
			
		||||
	const buffer_c16_t spectrum_buffer {
 | 
			
		||||
		spectrum.data(),
 | 
			
		||||
		spectrum.size()
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	const buffer_s16_t work_audio_buffer {
 | 
			
		||||
		(int16_t*)dst.data(),
 | 
			
		||||
		sizeof(dst) / sizeof(int16_t)
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	// Array size ok down to 375 bauds (24000 / 375)
 | 
			
		||||
	std::array<int32_t, 64> delay_line { 0 };
 | 
			
		||||
	std::array<int16_t, 1000> rb_buf { 0 };
 | 
			
		||||
 | 
			
		||||
	/*dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { };
 | 
			
		||||
	dsp::decimate::FIRC16xR16x32Decim8 decim_1 { };
 | 
			
		||||
	dsp::decimate::FIRAndDecimateComplex channel_filter { };*/
 | 
			
		||||
	dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0 { };
 | 
			
		||||
	dsp::decimate::FIRC16xR16x16Decim2 decim_1 { };
 | 
			
		||||
	
 | 
			
		||||
	dsp::demodulate::FM demod { };
 | 
			
		||||
	int rb_head {-1};
 | 
			
		||||
	int32_t g_threshold {0};  
 | 
			
		||||
	//uint8_t g_srate {8}; 
 | 
			
		||||
	uint8_t channel_number {38};
 | 
			
		||||
	int skipSamples {1000};
 | 
			
		||||
	int RB_SIZE {1000};
 | 
			
		||||
 | 
			
		||||
	bool configured { false };
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	void configure(const NRFRxConfigureMessage& message);
 | 
			
		||||
	
 | 
			
		||||
	AFSKDataMessage data_message { false, 0 };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif/*__PROC_NRFRX_H__*/
 | 
			
		||||
							
								
								
									
										123
									
								
								Software/portapack-mayhem/firmware/baseband/proc_ook.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								Software/portapack-mayhem/firmware/baseband/proc_ook.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,123 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_ook.hpp"
 | 
			
		||||
#include "portapack_shared_memory.hpp"
 | 
			
		||||
#include "sine_table_int8.hpp"
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
void OOKProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	int8_t re, im;
 | 
			
		||||
	
 | 
			
		||||
	// This is called at 2.28M/2048 = 1113Hz
 | 
			
		||||
	
 | 
			
		||||
	if (!configured) return;
 | 
			
		||||
	
 | 
			
		||||
	for (size_t i = 0; i < buffer.count; i++) {
 | 
			
		||||
		
 | 
			
		||||
		// Synthesis at 2.28M/10 = 228kHz
 | 
			
		||||
		if (!s) {
 | 
			
		||||
			s = 10 - 1;
 | 
			
		||||
			if (sample_count >= samples_per_bit) {
 | 
			
		||||
				if (configured) {
 | 
			
		||||
					if (bit_pos >= length) {
 | 
			
		||||
						// End of data
 | 
			
		||||
						if (pause_counter == 0) {
 | 
			
		||||
							pause_counter = pause;
 | 
			
		||||
							cur_bit = 0;
 | 
			
		||||
						} else if (pause_counter == 1) {
 | 
			
		||||
							if (repeat_counter < repeat) {
 | 
			
		||||
								// Repeat
 | 
			
		||||
								bit_pos = 0;
 | 
			
		||||
								cur_bit = shared_memory.bb_data.data[0] & 0x80;
 | 
			
		||||
								txprogress_message.progress = repeat_counter + 1;
 | 
			
		||||
								txprogress_message.done = false;
 | 
			
		||||
								shared_memory.application_queue.push(txprogress_message);
 | 
			
		||||
								repeat_counter++;
 | 
			
		||||
							} else {
 | 
			
		||||
								// Stop
 | 
			
		||||
								cur_bit = 0;
 | 
			
		||||
								txprogress_message.done = true;
 | 
			
		||||
								shared_memory.application_queue.push(txprogress_message);
 | 
			
		||||
								configured = false;
 | 
			
		||||
							}
 | 
			
		||||
							pause_counter = 0;
 | 
			
		||||
						} else {
 | 
			
		||||
							pause_counter--;
 | 
			
		||||
						}
 | 
			
		||||
					} else {
 | 
			
		||||
						cur_bit = (shared_memory.bb_data.data[bit_pos >> 3] << (bit_pos & 7)) & 0x80;
 | 
			
		||||
						bit_pos++;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				sample_count = 0;
 | 
			
		||||
			} else {
 | 
			
		||||
				sample_count++;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			s--;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if (cur_bit) {
 | 
			
		||||
			phase = (phase + 200);			// What ?
 | 
			
		||||
			sphase = phase + (64 << 18);
 | 
			
		||||
 | 
			
		||||
			re = (sine_table_i8[(sphase & 0x03FC0000) >> 18]);
 | 
			
		||||
			im = (sine_table_i8[(phase & 0x03FC0000) >> 18]);
 | 
			
		||||
		} else {
 | 
			
		||||
			re = 0;
 | 
			
		||||
			im = 0;
 | 
			
		||||
		}
 | 
			
		||||
	
 | 
			
		||||
		buffer.p[i] = {re, im};
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OOKProcessor::on_message(const Message* const p) {
 | 
			
		||||
	const auto message = *reinterpret_cast<const OOKConfigureMessage*>(p);
 | 
			
		||||
	
 | 
			
		||||
	if (message.id == Message::ID::OOKConfigure) {
 | 
			
		||||
		samples_per_bit = message.samples_per_bit / 10;
 | 
			
		||||
		repeat = message.repeat - 1;
 | 
			
		||||
		length = message.stream_length;
 | 
			
		||||
		pause = message.pause_symbols + 1;
 | 
			
		||||
	
 | 
			
		||||
		pause_counter = 0;
 | 
			
		||||
		s = 0;
 | 
			
		||||
		sample_count = samples_per_bit;
 | 
			
		||||
		repeat_counter = 0;
 | 
			
		||||
		bit_pos = 0;
 | 
			
		||||
		cur_bit = 0;
 | 
			
		||||
		txprogress_message.progress = 0;
 | 
			
		||||
		txprogress_message.done = false;
 | 
			
		||||
		configured = true;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<OOKProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								Software/portapack-mayhem/firmware/baseband/proc_ook.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								Software/portapack-mayhem/firmware/baseband/proc_ook.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PROC_OOK_H__
 | 
			
		||||
#define __PROC_OOK_H__
 | 
			
		||||
 | 
			
		||||
#include "baseband_processor.hpp"
 | 
			
		||||
#include "baseband_thread.hpp"
 | 
			
		||||
 | 
			
		||||
class OOKProcessor : public BasebandProcessor {
 | 
			
		||||
public:
 | 
			
		||||
	void execute(const buffer_c8_t& buffer) override;
 | 
			
		||||
	
 | 
			
		||||
	void on_message(const Message* const p) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	bool configured = false;
 | 
			
		||||
	
 | 
			
		||||
	BasebandThread baseband_thread { 2280000, this, NORMALPRIO + 20, baseband::Direction::Transmit };
 | 
			
		||||
	
 | 
			
		||||
	uint32_t samples_per_bit { 0 };
 | 
			
		||||
	uint8_t repeat { 0 };
 | 
			
		||||
	uint32_t length { 0 };
 | 
			
		||||
	uint32_t pause { 0 };
 | 
			
		||||
	
 | 
			
		||||
	uint32_t pause_counter { 0 };
 | 
			
		||||
	uint8_t repeat_counter { 0 };
 | 
			
		||||
	uint8_t s { 0 };
 | 
			
		||||
    uint16_t bit_pos { 0 };
 | 
			
		||||
    uint8_t cur_bit { 0 };
 | 
			
		||||
    uint32_t sample_count { 0 };
 | 
			
		||||
	uint32_t tone_phase { 0 }, phase { 0 }, sphase { 0 };
 | 
			
		||||
	int32_t tone_sample { 0 }, sig { 0 }, frq { 0 };
 | 
			
		||||
	
 | 
			
		||||
	TXProgressMessage txprogress_message { };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										539
									
								
								Software/portapack-mayhem/firmware/baseband/proc_pocsag.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										539
									
								
								Software/portapack-mayhem/firmware/baseband/proc_pocsag.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,539 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu)
 | 
			
		||||
 * Copyright (C) 2012-2014 Elias Oenal (multimon-ng@eliasoenal.com)
 | 
			
		||||
 * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
 | 
			
		||||
 * Copyright (C) 2016 Furrtek
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "proc_pocsag.hpp"
 | 
			
		||||
 | 
			
		||||
#include "event_m4.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <algorithm>    // std::max
 | 
			
		||||
#include <cmath>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void POCSAGProcessor::execute(const buffer_c8_t& buffer) {
 | 
			
		||||
	// This is called at 1500Hz
 | 
			
		||||
	
 | 
			
		||||
	if (!configured) return;
 | 
			
		||||
	
 | 
			
		||||
	// Get 24kHz audio
 | 
			
		||||
	const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
 | 
			
		||||
	const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer);
 | 
			
		||||
	const auto channel_out = channel_filter.execute(decim_1_out, dst_buffer);
 | 
			
		||||
	auto audio = demod.execute(channel_out, audio_buffer);
 | 
			
		||||
	smooth.Process(audio.p, audio.count); // Smooth the data to  make decoding more accurate
 | 
			
		||||
	audio_output.write(audio);
 | 
			
		||||
	
 | 
			
		||||
	processDemodulatedSamples(audio.p, 16);
 | 
			
		||||
	extractFrames();
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ====================================================================
 | 
			
		||||
//
 | 
			
		||||
// ====================================================================
 | 
			
		||||
int POCSAGProcessor::OnDataWord(uint32_t word, int pos)
 | 
			
		||||
{
 | 
			
		||||
	packet.set(pos, word);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ====================================================================
 | 
			
		||||
//
 | 
			
		||||
// ====================================================================
 | 
			
		||||
int POCSAGProcessor::OnDataFrame(int len, int baud)
 | 
			
		||||
{
 | 
			
		||||
	if (len > 0)
 | 
			
		||||
	{
 | 
			
		||||
		packet.set_bitrate(baud);
 | 
			
		||||
		packet.set_flag(pocsag::PacketFlag::NORMAL);
 | 
			
		||||
		packet.set_timestamp(Timestamp::now());
 | 
			
		||||
		const POCSAGPacketMessage message(packet);
 | 
			
		||||
		shared_memory.application_queue.push(message);
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void POCSAGProcessor::on_message(const Message* const message) {
 | 
			
		||||
	if (message->id == Message::ID::POCSAGConfigure)
 | 
			
		||||
		configure();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void POCSAGProcessor::configure() {
 | 
			
		||||
	constexpr size_t decim_0_input_fs = baseband_fs;
 | 
			
		||||
	constexpr size_t decim_0_output_fs = decim_0_input_fs / decim_0.decimation_factor;
 | 
			
		||||
 | 
			
		||||
	constexpr size_t decim_1_input_fs = decim_0_output_fs;
 | 
			
		||||
	constexpr size_t decim_1_output_fs = decim_1_input_fs / decim_1.decimation_factor;
 | 
			
		||||
	
 | 
			
		||||
	constexpr size_t channel_filter_input_fs = decim_1_output_fs;
 | 
			
		||||
	const size_t channel_filter_output_fs = channel_filter_input_fs / 2;
 | 
			
		||||
 | 
			
		||||
	const size_t demod_input_fs = channel_filter_output_fs;
 | 
			
		||||
 | 
			
		||||
	decim_0.configure(taps_11k0_decim_0.taps, 33554432);
 | 
			
		||||
	decim_1.configure(taps_11k0_decim_1.taps, 131072);
 | 
			
		||||
	channel_filter.configure(taps_11k0_channel.taps, 2);
 | 
			
		||||
	demod.configure(demod_input_fs, 4500);
 | 
			
		||||
	// Smoothing should be roughly sample rate over max baud
 | 
			
		||||
	// 24k / 3.2k is 7.5
 | 
			
		||||
	smooth.SetSize(8);
 | 
			
		||||
	audio_output.configure(false);
 | 
			
		||||
 | 
			
		||||
	// Set up the frame extraction, limits of baud
 | 
			
		||||
	setFrameExtractParams(demod_input_fs, 4000, 300, 32);
 | 
			
		||||
 | 
			
		||||
	// Mark the class as ready to accept data
 | 
			
		||||
	configured = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// -----------------------------
 | 
			
		||||
// Frame extractraction methods
 | 
			
		||||
// -----------------------------
 | 
			
		||||
#define BAUD_STABLE (104)
 | 
			
		||||
#define MAX_CONSEC_SAME (32)
 | 
			
		||||
#define MAX_WITHOUT_SINGLE (64)
 | 
			
		||||
#define MAX_BAD_TRANS (10)
 | 
			
		||||
 | 
			
		||||
#define M_SYNC				(0x7cd215d8)
 | 
			
		||||
#define M_NOTSYNC			(0x832dea27)
 | 
			
		||||
 | 
			
		||||
#define M_IDLE				(0x7a89c197)
 | 
			
		||||
 | 
			
		||||
// ====================================================================
 | 
			
		||||
//
 | 
			
		||||
// ====================================================================
 | 
			
		||||
inline int bitsDiff(unsigned long left, unsigned long right)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long xord = left ^ right;
 | 
			
		||||
	int count = 0;
 | 
			
		||||
	for (int i = 0; i < 32; i++)
 | 
			
		||||
	{
 | 
			
		||||
		if ((xord & 0x01) != 0) ++count;
 | 
			
		||||
		xord = xord >> 1;
 | 
			
		||||
	}
 | 
			
		||||
	return(count);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// ====================================================================
 | 
			
		||||
//
 | 
			
		||||
// ====================================================================
 | 
			
		||||
void POCSAGProcessor::initFrameExtraction()
 | 
			
		||||
{
 | 
			
		||||
	m_averageSymbolLen_1024 = m_maxSymSamples_1024;
 | 
			
		||||
	m_lastStableSymbolLen_1024 = m_minSymSamples_1024;
 | 
			
		||||
 | 
			
		||||
	m_badTransitions = 0;
 | 
			
		||||
	m_bitsStart = 0;
 | 
			
		||||
	m_bitsEnd = 0;
 | 
			
		||||
	m_inverted = false;
 | 
			
		||||
 | 
			
		||||
	resetVals();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ====================================================================
 | 
			
		||||
//
 | 
			
		||||
// ====================================================================
 | 
			
		||||
void POCSAGProcessor::resetVals()
 | 
			
		||||
{
 | 
			
		||||
	// Reset the parameters
 | 
			
		||||
	// --------------------
 | 
			
		||||
	m_goodTransitions = 0;
 | 
			
		||||
	m_badTransitions = 0;
 | 
			
		||||
	m_averageSymbolLen_1024 = m_maxSymSamples_1024;
 | 
			
		||||
	m_shortestGoodTrans_1024 = m_maxSymSamples_1024;
 | 
			
		||||
	m_valMid = 0;
 | 
			
		||||
 | 
			
		||||
	// And reset the counts
 | 
			
		||||
	// --------------------
 | 
			
		||||
	m_lastTransPos_1024 = 0;
 | 
			
		||||
	m_lastBitPos_1024 = 0;
 | 
			
		||||
	m_lastSample = 0;
 | 
			
		||||
	m_sampleNo = 0;
 | 
			
		||||
	m_nextBitPos_1024 = m_maxSymSamples_1024;
 | 
			
		||||
	m_nextBitPosInt = (long)m_nextBitPos_1024;
 | 
			
		||||
 | 
			
		||||
	// Extraction
 | 
			
		||||
	m_fifo.numBits = 0;
 | 
			
		||||
	m_gotSync = false;
 | 
			
		||||
	m_numCode = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ====================================================================
 | 
			
		||||
//
 | 
			
		||||
// ====================================================================
 | 
			
		||||
void POCSAGProcessor::setFrameExtractParams(long a_samplesPerSec, long a_maxBaud, long a_minBaud, long maxRunOfSameValue)
 | 
			
		||||
{
 | 
			
		||||
	m_samplesPerSec = a_samplesPerSec;
 | 
			
		||||
	m_minSymSamples_1024 = (uint32_t)(1024.0f * (float)a_samplesPerSec / (float)a_maxBaud);
 | 
			
		||||
	m_maxSymSamples_1024 = (uint32_t)(1024.0f*(float)a_samplesPerSec / (float)a_minBaud);
 | 
			
		||||
	m_maxRunOfSameValue = maxRunOfSameValue;
 | 
			
		||||
 | 
			
		||||
	m_shortestGoodTrans_1024 = m_maxSymSamples_1024;
 | 
			
		||||
	m_averageSymbolLen_1024 = m_maxSymSamples_1024;
 | 
			
		||||
	m_lastStableSymbolLen_1024 = m_minSymSamples_1024;
 | 
			
		||||
 | 
			
		||||
	m_nextBitPos_1024 = m_averageSymbolLen_1024 / 2;
 | 
			
		||||
	m_nextBitPosInt = m_nextBitPos_1024 >> 10;
 | 
			
		||||
 | 
			
		||||
	initFrameExtraction();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ====================================================================
 | 
			
		||||
//
 | 
			
		||||
// ====================================================================
 | 
			
		||||
int POCSAGProcessor::processDemodulatedSamples(float * sampleBuff, int noOfSamples)
 | 
			
		||||
{
 | 
			
		||||
	bool transition = false;
 | 
			
		||||
	uint32_t samplePos_1024 = 0;
 | 
			
		||||
	uint32_t len_1024 = 0;
 | 
			
		||||
 | 
			
		||||
	// Loop through the block of data
 | 
			
		||||
	// ------------------------------
 | 
			
		||||
	for (int pos = 0; pos < noOfSamples; ++pos)
 | 
			
		||||
	{
 | 
			
		||||
		m_sample = sampleBuff[pos];
 | 
			
		||||
		m_valMid += (m_sample - m_valMid) / 1024.0f;
 | 
			
		||||
 | 
			
		||||
		++m_sampleNo;
 | 
			
		||||
 | 
			
		||||
		// Detect Transition
 | 
			
		||||
		// -----------------
 | 
			
		||||
		transition = ! ((m_lastSample < m_valMid) ^ (m_sample >= m_valMid)); // use XOR for speed
 | 
			
		||||
 | 
			
		||||
		// If this is a transition
 | 
			
		||||
		// -----------------------
 | 
			
		||||
		if (transition)
 | 
			
		||||
		{
 | 
			
		||||
			// Calculate samples since last trans
 | 
			
		||||
			// ----------------------------------
 | 
			
		||||
			int32_t fractional_1024 = (int32_t)(((m_sample - m_valMid)*1024) / (m_sample - m_lastSample));
 | 
			
		||||
			if (fractional_1024 < 0) { fractional_1024 = -fractional_1024; }
 | 
			
		||||
 | 
			
		||||
			samplePos_1024 = (m_sampleNo<<10)-fractional_1024;
 | 
			
		||||
			len_1024 = samplePos_1024 - m_lastTransPos_1024;
 | 
			
		||||
			m_lastTransPos_1024 = samplePos_1024;
 | 
			
		||||
 | 
			
		||||
			// If symbol is large enough to be valid
 | 
			
		||||
			// -------------------------------------
 | 
			
		||||
			if (len_1024 > m_minSymSamples_1024)
 | 
			
		||||
			{
 | 
			
		||||
				// Check for shortest good transition
 | 
			
		||||
				// ----------------------------------
 | 
			
		||||
				if ((len_1024 < m_shortestGoodTrans_1024) &&
 | 
			
		||||
					(m_goodTransitions < BAUD_STABLE))	// detect change of symbol size
 | 
			
		||||
				{
 | 
			
		||||
					int32_t fractionOfShortest_1024 = (len_1024<<10) / m_shortestGoodTrans_1024;
 | 
			
		||||
 | 
			
		||||
					// If currently at half the baud rate
 | 
			
		||||
					// ----------------------------------
 | 
			
		||||
					if ((fractionOfShortest_1024 > 410) && (fractionOfShortest_1024 < 614)) // 0.4 and 0.6
 | 
			
		||||
					{
 | 
			
		||||
						m_averageSymbolLen_1024 /= 2;
 | 
			
		||||
						m_shortestGoodTrans_1024 = len_1024;
 | 
			
		||||
					}
 | 
			
		||||
					// If currently at the wrong baud rate
 | 
			
		||||
					// -----------------------------------
 | 
			
		||||
					else if (fractionOfShortest_1024 < 768) // 0.75
 | 
			
		||||
					{
 | 
			
		||||
						m_averageSymbolLen_1024 = len_1024;
 | 
			
		||||
						m_shortestGoodTrans_1024 = len_1024;
 | 
			
		||||
						m_goodTransitions = 0;
 | 
			
		||||
						m_lastSingleBitPos_1024 = samplePos_1024 - len_1024;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Calc the number of bits since events
 | 
			
		||||
				// ------------------------------------
 | 
			
		||||
				int32_t halfSymbol_1024 = m_averageSymbolLen_1024 / 2;
 | 
			
		||||
				int bitsSinceLastTrans = max((uint32_t)1, (len_1024+halfSymbol_1024) / m_averageSymbolLen_1024 );
 | 
			
		||||
				int bitsSinceLastSingle = (((m_sampleNo<<10)-m_lastSingleBitPos_1024) + halfSymbol_1024) / m_averageSymbolLen_1024;
 | 
			
		||||
 | 
			
		||||
				// Check for single bit
 | 
			
		||||
				// --------------------
 | 
			
		||||
				if (bitsSinceLastTrans == 1)
 | 
			
		||||
				{
 | 
			
		||||
					m_lastSingleBitPos_1024 = samplePos_1024;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// If too long since last transition
 | 
			
		||||
				// ---------------------------------
 | 
			
		||||
				if (bitsSinceLastTrans > MAX_CONSEC_SAME)
 | 
			
		||||
				{
 | 
			
		||||
					resetVals();
 | 
			
		||||
				}
 | 
			
		||||
				// If too long sice last single bit
 | 
			
		||||
				// --------------------------------
 | 
			
		||||
				else if (bitsSinceLastSingle > MAX_WITHOUT_SINGLE)
 | 
			
		||||
				{
 | 
			
		||||
					resetVals();
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					// If this is a good transition
 | 
			
		||||
					// ----------------------------
 | 
			
		||||
					int32_t offsetFromExtectedTransition_1024 = len_1024 - (bitsSinceLastTrans*m_averageSymbolLen_1024);
 | 
			
		||||
					if (offsetFromExtectedTransition_1024 < 0) { offsetFromExtectedTransition_1024 = -offsetFromExtectedTransition_1024; }
 | 
			
		||||
					if (offsetFromExtectedTransition_1024 < ((int32_t)m_averageSymbolLen_1024 / 4)) // Has to be within 1/4 of symbol to be good
 | 
			
		||||
					{
 | 
			
		||||
						++m_goodTransitions;
 | 
			
		||||
						uint32_t bitsCount = min((uint32_t)BAUD_STABLE, m_goodTransitions);
 | 
			
		||||
 | 
			
		||||
						uint32_t propFromPrevious = m_averageSymbolLen_1024*bitsCount;
 | 
			
		||||
						uint32_t propFromCurrent = (len_1024 / bitsSinceLastTrans);
 | 
			
		||||
						m_averageSymbolLen_1024 = (propFromPrevious + propFromCurrent) / (bitsCount + 1);
 | 
			
		||||
						m_badTransitions = 0;
 | 
			
		||||
						//if ( len < m_shortestGoodTrans ){m_shortestGoodTrans = len;}
 | 
			
		||||
						// Store the old symbol size
 | 
			
		||||
						if (m_goodTransitions >= BAUD_STABLE) 
 | 
			
		||||
						{ 
 | 
			
		||||
							m_lastStableSymbolLen_1024 = m_averageSymbolLen_1024; 
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Set the point of the last bit if not yet stable
 | 
			
		||||
				// -----------------------------------------------
 | 
			
		||||
				if ((m_goodTransitions < BAUD_STABLE) || (m_badTransitions > 0))
 | 
			
		||||
				{
 | 
			
		||||
					m_lastBitPos_1024 = samplePos_1024 - (m_averageSymbolLen_1024 / 2);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Calculate the exact positiom of the next bit
 | 
			
		||||
				// --------------------------------------------
 | 
			
		||||
				int32_t thisPlusHalfsymbol_1024 = samplePos_1024 + (m_averageSymbolLen_1024/2);
 | 
			
		||||
				int32_t lastPlusSymbol = m_lastBitPos_1024 + m_averageSymbolLen_1024;
 | 
			
		||||
				m_nextBitPos_1024 = lastPlusSymbol + ((thisPlusHalfsymbol_1024 - lastPlusSymbol) / 16);
 | 
			
		||||
 | 
			
		||||
				// Check for bad pos error
 | 
			
		||||
				// -----------------------
 | 
			
		||||
				if (m_nextBitPos_1024 < samplePos_1024) m_nextBitPos_1024 += m_averageSymbolLen_1024;
 | 
			
		||||
 | 
			
		||||
				// Calculate integer sample after next bit
 | 
			
		||||
				// ---------------------------------------
 | 
			
		||||
				m_nextBitPosInt = (m_nextBitPos_1024>>10) + 1;
 | 
			
		||||
 | 
			
		||||
			} // symbol is large enough to be valid
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				// Bad transition, so reset the counts
 | 
			
		||||
				// -----------------------------------
 | 
			
		||||
				++m_badTransitions;
 | 
			
		||||
				if (m_badTransitions > MAX_BAD_TRANS)
 | 
			
		||||
				{
 | 
			
		||||
					resetVals();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}  // end of if transition
 | 
			
		||||
 | 
			
		||||
		// Reached the point of the next bit
 | 
			
		||||
		// ---------------------------------
 | 
			
		||||
		if (m_sampleNo >= m_nextBitPosInt)
 | 
			
		||||
		{
 | 
			
		||||
			// Everything is good so extract a bit
 | 
			
		||||
			// -----------------------------------
 | 
			
		||||
			if (m_goodTransitions > 20)
 | 
			
		||||
			{
 | 
			
		||||
				// Store value at the center of bit
 | 
			
		||||
				// --------------------------------
 | 
			
		||||
				storeBit();
 | 
			
		||||
			}
 | 
			
		||||
			// Check for long 1 or zero
 | 
			
		||||
			// ------------------------
 | 
			
		||||
			uint32_t bitsSinceLastTrans = ((m_sampleNo<<10) - m_lastTransPos_1024) / m_averageSymbolLen_1024;
 | 
			
		||||
			if (bitsSinceLastTrans > m_maxRunOfSameValue) 
 | 
			
		||||
			{ 
 | 
			
		||||
				resetVals(); 
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Store the point of the last bit
 | 
			
		||||
			// -------------------------------
 | 
			
		||||
			m_lastBitPos_1024 = m_nextBitPos_1024;
 | 
			
		||||
 | 
			
		||||
			// Calculate the exact point of the next bit
 | 
			
		||||
			// -----------------------------------------
 | 
			
		||||
			m_nextBitPos_1024 += m_averageSymbolLen_1024;
 | 
			
		||||
 | 
			
		||||
			// Look for the bit after the next bit pos
 | 
			
		||||
			// ---------------------------------------
 | 
			
		||||
			m_nextBitPosInt = (m_nextBitPos_1024>>10) + 1;
 | 
			
		||||
 | 
			
		||||
		} // Reached the point of the next bit
 | 
			
		||||
 | 
			
		||||
		m_lastSample = m_sample;
 | 
			
		||||
 | 
			
		||||
	} // Loop through the block of data
 | 
			
		||||
 | 
			
		||||
	return getNoOfBits();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ====================================================================
 | 
			
		||||
//
 | 
			
		||||
// ====================================================================
 | 
			
		||||
void POCSAGProcessor::storeBit()
 | 
			
		||||
{
 | 
			
		||||
	if (++m_bitsStart >= BIT_BUF_SIZE) { m_bitsStart = 0; }
 | 
			
		||||
 | 
			
		||||
	// Calculate the bit value
 | 
			
		||||
	float sample = (m_sample + m_lastSample) / 2;
 | 
			
		||||
	//int32_t sample_1024 = m_sample_1024;
 | 
			
		||||
	bool bit = sample > m_valMid;
 | 
			
		||||
 | 
			
		||||
	// If buffer not full
 | 
			
		||||
	if (m_bitsStart != m_bitsEnd)
 | 
			
		||||
	{
 | 
			
		||||
		// Decide on output val
 | 
			
		||||
		if (bit)
 | 
			
		||||
		{
 | 
			
		||||
			m_bits[m_bitsStart] = 0;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			m_bits[m_bitsStart] = 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// Throw away bits if the buffer is full
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		if (--m_bitsStart <= -1) 
 | 
			
		||||
		{ 
 | 
			
		||||
			m_bitsStart = BIT_BUF_SIZE - 1; 
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ====================================================================
 | 
			
		||||
//
 | 
			
		||||
// ====================================================================
 | 
			
		||||
int POCSAGProcessor::extractFrames()
 | 
			
		||||
{
 | 
			
		||||
	int msgCnt = 0;
 | 
			
		||||
	// While there is unread data in the bits buffer
 | 
			
		||||
	//----------------------------------------------
 | 
			
		||||
	while (getNoOfBits() > 0)
 | 
			
		||||
	{
 | 
			
		||||
		m_fifo.codeword = (m_fifo.codeword << 1) + getBit();
 | 
			
		||||
		m_fifo.numBits++;
 | 
			
		||||
 | 
			
		||||
		// If number of bits in fifo equals 32
 | 
			
		||||
		//------------------------------------
 | 
			
		||||
		if (m_fifo.numBits >= 32)
 | 
			
		||||
		{
 | 
			
		||||
			// Not got sync
 | 
			
		||||
			// ------------
 | 
			
		||||
			if (!m_gotSync)
 | 
			
		||||
			{
 | 
			
		||||
				if (bitsDiff(m_fifo.codeword, M_SYNC) <= 2)
 | 
			
		||||
				{
 | 
			
		||||
					m_inverted = false;
 | 
			
		||||
					m_gotSync = true;
 | 
			
		||||
					m_numCode = -1;
 | 
			
		||||
					m_fifo.numBits = 0;
 | 
			
		||||
				}
 | 
			
		||||
				else if (bitsDiff(m_fifo.codeword, M_NOTSYNC) <= 2)
 | 
			
		||||
				{
 | 
			
		||||
					m_inverted = true;
 | 
			
		||||
					m_gotSync = true;
 | 
			
		||||
					m_numCode = -1;
 | 
			
		||||
					m_fifo.numBits = 0;
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					// Cause it to load one more bit
 | 
			
		||||
					m_fifo.numBits = 31;
 | 
			
		||||
				}
 | 
			
		||||
			} // Not got sync
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				// Increment the word count
 | 
			
		||||
				// ------------------------
 | 
			
		||||
				++m_numCode; // It got set to -1 when a sync was found, now count the 16 words
 | 
			
		||||
				uint32_t val = m_inverted ? ~m_fifo.codeword : m_fifo.codeword;
 | 
			
		||||
				OnDataWord(val, m_numCode);
 | 
			
		||||
 | 
			
		||||
				// If at the end of a 16 word block
 | 
			
		||||
				// --------------------------------
 | 
			
		||||
				if (m_numCode >= 15)
 | 
			
		||||
				{
 | 
			
		||||
					msgCnt += OnDataFrame(m_numCode+1, (m_samplesPerSec<<10) / m_lastStableSymbolLen_1024);
 | 
			
		||||
					m_gotSync = false;
 | 
			
		||||
					m_numCode = -1;
 | 
			
		||||
				}
 | 
			
		||||
				m_fifo.numBits = 0;
 | 
			
		||||
			}
 | 
			
		||||
		} // If number of bits in fifo equals 32
 | 
			
		||||
	} // While there is unread data in the bits buffer
 | 
			
		||||
	return msgCnt;
 | 
			
		||||
} // extractFrames
 | 
			
		||||
 | 
			
		||||
// ====================================================================
 | 
			
		||||
//
 | 
			
		||||
// ====================================================================
 | 
			
		||||
short POCSAGProcessor::getBit()
 | 
			
		||||
{
 | 
			
		||||
	if (m_bitsEnd != m_bitsStart)
 | 
			
		||||
	{
 | 
			
		||||
		if (++m_bitsEnd >= BIT_BUF_SIZE) 
 | 
			
		||||
		{ 
 | 
			
		||||
			m_bitsEnd = 0; 
 | 
			
		||||
		}
 | 
			
		||||
		return m_bits[m_bitsEnd];
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ====================================================================
 | 
			
		||||
//
 | 
			
		||||
// ====================================================================
 | 
			
		||||
int POCSAGProcessor::getNoOfBits()
 | 
			
		||||
{
 | 
			
		||||
	int bits = m_bitsEnd - m_bitsStart;
 | 
			
		||||
	if (bits < 0) { bits += BIT_BUF_SIZE; }
 | 
			
		||||
	return bits;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ====================================================================
 | 
			
		||||
//
 | 
			
		||||
// ====================================================================
 | 
			
		||||
uint32_t POCSAGProcessor::getRate()
 | 
			
		||||
{
 | 
			
		||||
	return ((m_samplesPerSec<<10)+512) / m_lastStableSymbolLen_1024;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// ====================================================================
 | 
			
		||||
//
 | 
			
		||||
// ====================================================================
 | 
			
		||||
int main() {
 | 
			
		||||
	EventDispatcher event_dispatcher { std::make_unique<POCSAGProcessor>() };
 | 
			
		||||
	event_dispatcher.run();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user