kopia lustrzana https://github.com/DL7AD/pecanpico10
WIP:
- Improved interrupt handling in 446x - Fix incorrect state handling in pktradio.c - Relocate misplaced PWM function into rxpwm.c - Working on issue with GPS I2C killing PAC1720 - Various other tidy upsDevelopment
rodzic
f0446e1fd9
commit
da2bbbc5cf
|
@ -70,7 +70,7 @@ const si446x_mcucfg_t radio1_cfg = {
|
|||
},
|
||||
.nirq = {
|
||||
.line = &radio1_cfg.nirq,
|
||||
.mode = (PAL_MODE_INPUT_PULLUP)
|
||||
.mode = PAL_MODE_INPUT_PULLUP
|
||||
},
|
||||
},
|
||||
.rcca = { /**< CCA carrier sense radio GPIO settings. */
|
||||
|
|
|
@ -1,247 +1,247 @@
|
|||
##############################################################################
|
||||
# Build global options
|
||||
# NOTE: Can be overridden externally.
|
||||
#
|
||||
|
||||
# Compiler options here.
|
||||
ifeq ($(USE_OPT),)
|
||||
USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16
|
||||
endif
|
||||
|
||||
# C specific options here (added to USE_OPT).
|
||||
ifeq ($(USE_COPT),)
|
||||
USE_COPT = -std=c11
|
||||
endif
|
||||
|
||||
# C++ specific options here (added to USE_OPT).
|
||||
ifeq ($(USE_CPPOPT),)
|
||||
USE_CPPOPT = -fno-rtti
|
||||
endif
|
||||
|
||||
# Enable this if you want the linker to remove unused code and data
|
||||
ifeq ($(USE_LINK_GC),)
|
||||
USE_LINK_GC = yes
|
||||
endif
|
||||
|
||||
# Linker extra moptions here.
|
||||
ifeq ($(USE_LDOPT),)
|
||||
USE_LDOPT =
|
||||
endif
|
||||
|
||||
# Enable this if you want link time optimizations (LTO)
|
||||
ifeq ($(USE_LTO),)
|
||||
USE_LTO = yes
|
||||
endif
|
||||
|
||||
# If enabled, this option allows to compile the application in THUMB mode.
|
||||
ifeq ($(USE_THUMB),)
|
||||
USE_THUMB = yes
|
||||
endif
|
||||
|
||||
# Enable this if you want to see the full log while compiling.
|
||||
ifeq ($(USE_VERBOSE_COMPILE),)
|
||||
USE_VERBOSE_COMPILE = no
|
||||
endif
|
||||
|
||||
# If enabled, this option makes the build process faster by not compiling
|
||||
# modules not used in the current configuration.
|
||||
ifeq ($(USE_SMART_BUILD),)
|
||||
USE_SMART_BUILD = yes
|
||||
endif
|
||||
|
||||
#
|
||||
# Build global options
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Architecture or project specific options
|
||||
#
|
||||
|
||||
# Stack size to be allocated to the Cortex-M process stack. This stack is
|
||||
# the stack used by the main() thread.
|
||||
ifeq ($(USE_PROCESS_STACKSIZE),)
|
||||
USE_PROCESS_STACKSIZE = 0x1400
|
||||
endif
|
||||
|
||||
# Stack size to the allocated to the Cortex-M main/exceptions stack. This
|
||||
# stack is used for processing interrupts and exceptions.
|
||||
ifeq ($(USE_EXCEPTIONS_STACKSIZE),)
|
||||
USE_EXCEPTIONS_STACKSIZE = 0x4800
|
||||
endif
|
||||
|
||||
# Enables the use of FPU (no, softfp, hard).
|
||||
ifeq ($(USE_FPU),)
|
||||
USE_FPU = hard
|
||||
USE_FPU_OPT = -mfloat-abi=$(USE_FPU) \
|
||||
-mfpu=fpv4-sp-d16 -fsingle-precision-constant
|
||||
endif
|
||||
|
||||
#
|
||||
# Architecture or project specific options
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Project, sources and paths
|
||||
#
|
||||
|
||||
# Define project name here
|
||||
PROJECT = pp10b
|
||||
|
||||
# Imported source files and paths
|
||||
CHIBIOS = ChibiOS
|
||||
CONFDIR := ${CURDIR}/cfg/$(PROJECT)
|
||||
BUILDDIR := ${CURDIR}/build/$(PROJECT)
|
||||
DEPDIR := ${CURDIR}/.dep/$(PROJECT)
|
||||
CMSISINC = ${CURDIR}/CMSIS/include
|
||||
CMSISLIB = ${CURDIR}/CMSIS/Lib/GCC
|
||||
ifeq ($(USE_FPU), hard)
|
||||
CMSISFILE = libarm_cortexM4lf_math.a
|
||||
else
|
||||
CMSISFILE = libarm_cortexM4l_math.a
|
||||
endif
|
||||
|
||||
# ChibiOS versions of system calls
|
||||
ALLCSRC := $(CHIBIOS)/os/various/syscalls.c
|
||||
|
||||
# Licensing files.
|
||||
include $(CHIBIOS)/os/license/license.mk
|
||||
# Startup files.
|
||||
include $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk
|
||||
# HAL-OSAL files (optional).
|
||||
include $(CHIBIOS)/os/hal/hal.mk
|
||||
include $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/platform.mk
|
||||
include $(CHIBIOS)/os/hal/osal/rt/osal.mk
|
||||
# BOARD files.
|
||||
include $(CONFDIR)/board/board.mk
|
||||
# PORTAB files.
|
||||
include $(CONFDIR)/portab.mk
|
||||
# RTOS files (optional).
|
||||
include $(CHIBIOS)/os/rt/rt.mk
|
||||
include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk
|
||||
# Auto-build files in AUTOBUILD_ROOT recursively.
|
||||
include $(CHIBIOS)/tools/mk/autobuild.mk
|
||||
# Other files (optional).
|
||||
include $(CHIBIOS)/test/lib/test.mk
|
||||
include $(CHIBIOS)/test/rt/rt_test.mk
|
||||
include $(CHIBIOS)/test/oslib/oslib_test.mk
|
||||
include $(CHIBIOS)/os/hal/lib/streams/streams.mk
|
||||
include $(CHIBIOS)/os/various/shell/shell.mk
|
||||
include $(CHIBIOS)/os/various/fatfs_bindings/fatfs.mk
|
||||
|
||||
# Define linker script file here
|
||||
LDSCRIPT= $(CONFDIR)/STM32F413xH.ld
|
||||
|
||||
#$(info $$ALLCSRC is [${ALLCSRC}])
|
||||
#$(info $$CONFDIR is [${CONFDIR}])
|
||||
#$(info $$ALLINC is [${ALLINC}])
|
||||
|
||||
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
||||
# setting.
|
||||
CSRC = $(ALLCSRC) \
|
||||
$(TESTSRC)
|
||||
|
||||
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
||||
# setting.
|
||||
CPPSRC = $(ALLCPPSRC)
|
||||
|
||||
# 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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
TCPPSRC =
|
||||
|
||||
# List ASM source files here
|
||||
ASMSRC = $(ALLASMSRC)
|
||||
ASMXSRC = $(ALLXASMSRC)
|
||||
|
||||
INCDIR = $(ALLINC) $(TESTINC)
|
||||
#$(info $$INCDIR is [${INCDIR}])
|
||||
#
|
||||
# Project, sources and paths
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Compiler settings
|
||||
#
|
||||
|
||||
MCU = cortex-m4
|
||||
|
||||
#TRGT = arm-elf-
|
||||
TRGT = arm-none-eabi-
|
||||
CC = $(TRGT)gcc
|
||||
CPPC = $(TRGT)g++
|
||||
# Enable loading with g++ only if you need C++ runtime support.
|
||||
# NOTE: You can use C++ even without C++ support if you are careful. C++
|
||||
# runtime support makes code size explode.
|
||||
LD = $(TRGT)gcc
|
||||
#LD = $(TRGT)g++
|
||||
CP = $(TRGT)objcopy
|
||||
AS = $(TRGT)gcc -x assembler-with-cpp
|
||||
AR = $(TRGT)ar
|
||||
OD = $(TRGT)objdump
|
||||
SZ = $(TRGT)size
|
||||
HEX = $(CP) -O ihex
|
||||
BIN = $(CP) -O binary
|
||||
|
||||
# ARM-specific options here
|
||||
AOPT =
|
||||
|
||||
# THUMB-specific options here
|
||||
TOPT = -mthumb -DTHUMB
|
||||
|
||||
# Define C warning options here
|
||||
CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes
|
||||
|
||||
# Define C++ warning options here
|
||||
CPPWARN = -Wall -Wextra -Wundef
|
||||
|
||||
#
|
||||
# Compiler settings
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Start of user section
|
||||
#
|
||||
|
||||
# List all user C define here, like -D_DEBUG=1
|
||||
UDEFS = -D_GNU_SOURCE -DARM_MATH_CM4 -DSHELL_CMD_TEST_ENABLED=0 \
|
||||
-DSHELL_CMD_EXIT_ENABLED=1 -DSET_TRACE_LEVEL=5 -DPDCMI_USE_DMA_DBM=1 \
|
||||
-DSHELL_CMD_MEM_ENABLED=0 -DTRACE_SHOW_THREAD=1 \
|
||||
-DDISABLE_HW_WATCHDOG=0 -DUSE_UART_FOR_CONSOLE=1
|
||||
|
||||
# Define ASM defines here
|
||||
UADEFS =
|
||||
|
||||
# List all user directories here
|
||||
UINCDIR = $(CMSISINC)
|
||||
|
||||
# List the user directory to look for the libraries here
|
||||
ULIBDIR = $(CMSISLIB)
|
||||
|
||||
# List all user libraries here
|
||||
ULIBS = -lm $(CMSISLIB)/$(CMSISFILE)
|
||||
|
||||
#
|
||||
# End of user defines
|
||||
##############################################################################
|
||||
|
||||
RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC
|
||||
include $(RULESPATH)/rules.mk
|
||||
|
||||
burn-$(PROJECT):
|
||||
st-flash write build/$(PROJECT)/$(PROJECT).bin 0x08000000
|
||||
##############################################################################
|
||||
# Build global options
|
||||
# NOTE: Can be overridden externally.
|
||||
#
|
||||
|
||||
# Compiler options here.
|
||||
ifeq ($(USE_OPT),)
|
||||
USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16
|
||||
endif
|
||||
|
||||
# C specific options here (added to USE_OPT).
|
||||
ifeq ($(USE_COPT),)
|
||||
USE_COPT = -std=c11
|
||||
endif
|
||||
|
||||
# C++ specific options here (added to USE_OPT).
|
||||
ifeq ($(USE_CPPOPT),)
|
||||
USE_CPPOPT = -fno-rtti
|
||||
endif
|
||||
|
||||
# Enable this if you want the linker to remove unused code and data
|
||||
ifeq ($(USE_LINK_GC),)
|
||||
USE_LINK_GC = yes
|
||||
endif
|
||||
|
||||
# Linker extra moptions here.
|
||||
ifeq ($(USE_LDOPT),)
|
||||
USE_LDOPT =
|
||||
endif
|
||||
|
||||
# Enable this if you want link time optimizations (LTO)
|
||||
ifeq ($(USE_LTO),)
|
||||
USE_LTO = yes
|
||||
endif
|
||||
|
||||
# If enabled, this option allows to compile the application in THUMB mode.
|
||||
ifeq ($(USE_THUMB),)
|
||||
USE_THUMB = yes
|
||||
endif
|
||||
|
||||
# Enable this if you want to see the full log while compiling.
|
||||
ifeq ($(USE_VERBOSE_COMPILE),)
|
||||
USE_VERBOSE_COMPILE = no
|
||||
endif
|
||||
|
||||
# If enabled, this option makes the build process faster by not compiling
|
||||
# modules not used in the current configuration.
|
||||
ifeq ($(USE_SMART_BUILD),)
|
||||
USE_SMART_BUILD = yes
|
||||
endif
|
||||
|
||||
#
|
||||
# Build global options
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Architecture or project specific options
|
||||
#
|
||||
|
||||
# Stack size to be allocated to the Cortex-M process stack. This stack is
|
||||
# the stack used by the main() thread.
|
||||
ifeq ($(USE_PROCESS_STACKSIZE),)
|
||||
USE_PROCESS_STACKSIZE = 0x1400
|
||||
endif
|
||||
|
||||
# Stack size to the allocated to the Cortex-M main/exceptions stack. This
|
||||
# stack is used for processing interrupts and exceptions.
|
||||
ifeq ($(USE_EXCEPTIONS_STACKSIZE),)
|
||||
USE_EXCEPTIONS_STACKSIZE = 0x4800
|
||||
endif
|
||||
|
||||
# Enables the use of FPU (no, softfp, hard).
|
||||
ifeq ($(USE_FPU),)
|
||||
USE_FPU = hard
|
||||
USE_FPU_OPT = -mfloat-abi=$(USE_FPU) \
|
||||
-mfpu=fpv4-sp-d16 -fsingle-precision-constant
|
||||
endif
|
||||
|
||||
#
|
||||
# Architecture or project specific options
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Project, sources and paths
|
||||
#
|
||||
|
||||
# Define project name here
|
||||
PROJECT = pp10b
|
||||
|
||||
# Imported source files and paths
|
||||
CHIBIOS = ChibiOS
|
||||
CONFDIR := ${CURDIR}/cfg/$(PROJECT)
|
||||
BUILDDIR := ${CURDIR}/build/$(PROJECT)
|
||||
DEPDIR := ${CURDIR}/.dep/$(PROJECT)
|
||||
CMSISINC = ${CURDIR}/CMSIS/include
|
||||
CMSISLIB = ${CURDIR}/CMSIS/Lib/GCC
|
||||
ifeq ($(USE_FPU), hard)
|
||||
CMSISFILE = libarm_cortexM4lf_math.a
|
||||
else
|
||||
CMSISFILE = libarm_cortexM4l_math.a
|
||||
endif
|
||||
|
||||
# ChibiOS versions of system calls
|
||||
ALLCSRC := $(CHIBIOS)/os/various/syscalls.c
|
||||
|
||||
# Licensing files.
|
||||
include $(CHIBIOS)/os/license/license.mk
|
||||
# Startup files.
|
||||
include $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk
|
||||
# HAL-OSAL files (optional).
|
||||
include $(CHIBIOS)/os/hal/hal.mk
|
||||
include $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/platform.mk
|
||||
include $(CHIBIOS)/os/hal/osal/rt/osal.mk
|
||||
# BOARD files.
|
||||
include $(CONFDIR)/board/board.mk
|
||||
# PORTAB files.
|
||||
include $(CONFDIR)/portab.mk
|
||||
# RTOS files (optional).
|
||||
include $(CHIBIOS)/os/rt/rt.mk
|
||||
include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk
|
||||
# Auto-build files in AUTOBUILD_ROOT recursively.
|
||||
include $(CHIBIOS)/tools/mk/autobuild.mk
|
||||
# Other files (optional).
|
||||
include $(CHIBIOS)/test/lib/test.mk
|
||||
include $(CHIBIOS)/test/rt/rt_test.mk
|
||||
include $(CHIBIOS)/test/oslib/oslib_test.mk
|
||||
include $(CHIBIOS)/os/hal/lib/streams/streams.mk
|
||||
include $(CHIBIOS)/os/various/shell/shell.mk
|
||||
include $(CHIBIOS)/os/various/fatfs_bindings/fatfs.mk
|
||||
|
||||
# Define linker script file here
|
||||
LDSCRIPT= $(CONFDIR)/STM32F413xH.ld
|
||||
|
||||
#$(info $$ALLCSRC is [${ALLCSRC}])
|
||||
#$(info $$CONFDIR is [${CONFDIR}])
|
||||
#$(info $$ALLINC is [${ALLINC}])
|
||||
|
||||
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
||||
# setting.
|
||||
CSRC = $(ALLCSRC) \
|
||||
$(TESTSRC)
|
||||
|
||||
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
||||
# setting.
|
||||
CPPSRC = $(ALLCPPSRC)
|
||||
|
||||
# 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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
TCPPSRC =
|
||||
|
||||
# List ASM source files here
|
||||
ASMSRC = $(ALLASMSRC)
|
||||
ASMXSRC = $(ALLXASMSRC)
|
||||
|
||||
INCDIR = $(ALLINC) $(TESTINC)
|
||||
#$(info $$INCDIR is [${INCDIR}])
|
||||
#
|
||||
# Project, sources and paths
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Compiler settings
|
||||
#
|
||||
|
||||
MCU = cortex-m4
|
||||
|
||||
#TRGT = arm-elf-
|
||||
TRGT = arm-none-eabi-
|
||||
CC = $(TRGT)gcc
|
||||
CPPC = $(TRGT)g++
|
||||
# Enable loading with g++ only if you need C++ runtime support.
|
||||
# NOTE: You can use C++ even without C++ support if you are careful. C++
|
||||
# runtime support makes code size explode.
|
||||
LD = $(TRGT)gcc
|
||||
#LD = $(TRGT)g++
|
||||
CP = $(TRGT)objcopy
|
||||
AS = $(TRGT)gcc -x assembler-with-cpp
|
||||
AR = $(TRGT)ar
|
||||
OD = $(TRGT)objdump
|
||||
SZ = $(TRGT)size
|
||||
HEX = $(CP) -O ihex
|
||||
BIN = $(CP) -O binary
|
||||
|
||||
# ARM-specific options here
|
||||
AOPT =
|
||||
|
||||
# THUMB-specific options here
|
||||
TOPT = -mthumb -DTHUMB
|
||||
|
||||
# Define C warning options here
|
||||
CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes
|
||||
|
||||
# Define C++ warning options here
|
||||
CPPWARN = -Wall -Wextra -Wundef
|
||||
|
||||
#
|
||||
# Compiler settings
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Start of user section
|
||||
#
|
||||
|
||||
# List all user C define here, like -D_DEBUG=1
|
||||
UDEFS = -D_GNU_SOURCE -DARM_MATH_CM4 -DSHELL_CMD_TEST_ENABLED=0 \
|
||||
-DSHELL_CMD_EXIT_ENABLED=1 -DSET_TRACE_LEVEL=5 -DPDCMI_USE_DMA_DBM=1 \
|
||||
-DSHELL_CMD_MEM_ENABLED=0 -DTRACE_SHOW_THREAD=1 \
|
||||
-DDISABLE_HW_WATCHDOG=1 -DUSE_UART_FOR_CONSOLE=1
|
||||
|
||||
# Define ASM defines here
|
||||
UADEFS =
|
||||
|
||||
# List all user directories here
|
||||
UINCDIR = $(CMSISINC)
|
||||
|
||||
# List the user directory to look for the libraries here
|
||||
ULIBDIR = $(CMSISLIB)
|
||||
|
||||
# List all user libraries here
|
||||
ULIBS = -lm $(CMSISLIB)/$(CMSISFILE)
|
||||
|
||||
#
|
||||
# End of user defines
|
||||
##############################################################################
|
||||
|
||||
RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC
|
||||
include $(RULESPATH)/rules.mk
|
||||
|
||||
burn-$(PROJECT):
|
||||
st-flash write build/$(PROJECT)/$(PROJECT).bin 0x08000000
|
||||
|
||||
|
|
|
@ -1,205 +1,209 @@
|
|||
/**
|
||||
* Put your configuration settings here. See description of all fields in types.h
|
||||
*/
|
||||
|
||||
|
||||
#include "config.h"
|
||||
#include "aprs.h"
|
||||
#include "geofence.h"
|
||||
#include "pktconf.h"
|
||||
|
||||
conf_t conf_sram useCCM;
|
||||
|
||||
const conf_t conf_flash_default = {
|
||||
// Primary position app
|
||||
.pos_pri = {
|
||||
.beacon = {
|
||||
.active = true,
|
||||
.cycle = TIME_S2I(60),
|
||||
.init_delay = TIME_S2I(5),
|
||||
.fixed = false
|
||||
},
|
||||
.radio_conf = {
|
||||
.pwr = 0x7F,
|
||||
.freq = FREQ_APRS_AUSTRALIA,
|
||||
.mod = MOD_AFSK,
|
||||
.cca = 0x5F,
|
||||
},
|
||||
// App identity
|
||||
.call = "VK2GJ-11",
|
||||
.path = "WIDE2-1",
|
||||
.symbol = SYM_BALLOON,
|
||||
.aprs_msg = true, // Enable APRS message reception on this app
|
||||
},
|
||||
|
||||
// Secondary position app
|
||||
.pos_sec = {
|
||||
.beacon = {
|
||||
.active = true,
|
||||
.cycle = TIME_S2I(15), // Beacon interval
|
||||
.init_delay = TIME_S2I(60 * 150),
|
||||
.fixed = false
|
||||
},
|
||||
.radio_conf = {
|
||||
.pwr = 0x7F,
|
||||
.freq = FREQ_APRS_AUSTRALIA,
|
||||
.mod = MOD_AFSK,
|
||||
.cca = 0x4F
|
||||
},
|
||||
// App identity
|
||||
.call = "VK2GJ-12",
|
||||
.path = "",
|
||||
.symbol = SYM_ANTENNA,
|
||||
.aprs_msg = true, // Enable APRS message reception on this app
|
||||
},
|
||||
|
||||
// Primary image app
|
||||
.img_pri = {
|
||||
.svc_conf = {
|
||||
.active = false,
|
||||
.cycle = TIME_S2I(60 * 10),
|
||||
.init_delay = TIME_S2I(60),
|
||||
.send_spacing = TIME_S2I(3)
|
||||
},
|
||||
.radio_conf = {
|
||||
.pwr = 0x1F,
|
||||
.freq = FREQ_GEOFENCE,
|
||||
.mod = MOD_AFSK,
|
||||
.cca = 0x5F
|
||||
|
||||
},
|
||||
// App identity
|
||||
.call = "VK2GJ-5",
|
||||
.path = "",
|
||||
|
||||
// Image settings
|
||||
.res = RES_QVGA,
|
||||
.quality = 4,
|
||||
.buf_size = 15 * 1024,
|
||||
.redundantTx = true
|
||||
},
|
||||
|
||||
// Secondary image app
|
||||
.img_sec = {
|
||||
.svc_conf = {
|
||||
.active = false,
|
||||
.cycle = TIME_S2I(60 * 1),
|
||||
.init_delay = TIME_S2I(10),
|
||||
.send_spacing = TIME_S2I(0)
|
||||
},
|
||||
.radio_conf = {
|
||||
.pwr = 0x7F,
|
||||
.freq = 144800000,
|
||||
.mod = MOD_2FSK_9k6,
|
||||
.cca = 0x5F
|
||||
},
|
||||
// App identity
|
||||
.call = "VK2GJ-2",
|
||||
.path = "",
|
||||
|
||||
// Image settings
|
||||
.res = RES_QVGA,
|
||||
.quality = 4,
|
||||
.buf_size = 20 * 1024,
|
||||
.redundantTx = false,
|
||||
.no_burst = true
|
||||
},
|
||||
|
||||
// Log app
|
||||
.log = {
|
||||
.svc_conf = {
|
||||
.active = false,
|
||||
.cycle = TIME_S2I(10),
|
||||
.init_delay = TIME_S2I(5)
|
||||
},
|
||||
.radio_conf = {
|
||||
.pwr = 0x7F,
|
||||
.freq = FREQ_GEOFENCE,
|
||||
.mod = MOD_AFSK,
|
||||
.cca = 0x4F
|
||||
},
|
||||
// Node identity
|
||||
.call = "VK2GJ-13",
|
||||
.path = "WIDE1-1",
|
||||
.density = 10
|
||||
},
|
||||
|
||||
// APRS app
|
||||
.aprs = {
|
||||
// The receive identity for APRS
|
||||
.rx = {
|
||||
.svc_conf = {
|
||||
// The packet receive service is enabled if true
|
||||
// Receive is paused and resumed by transmission on that radio
|
||||
// Receive can have a schedule set by cycle and interval
|
||||
// An interval will run receive for the specified time period
|
||||
// If interval is TIME_IMMEDIATE the radio turns off then on immediately
|
||||
// If interval is TIME_INFINITE then the radio stays on and cycle is ignored
|
||||
// Cycle is checked after the interval has expired
|
||||
// Cycle timing less than interval means the cycle will run immediately after interval
|
||||
// If cycle is CYCLE_CONTINUOUSLY the radio turns off and on at each interval
|
||||
.active = true,
|
||||
.init_delay = TIME_S2I(20),
|
||||
.cycle = TIME_S2I(60),
|
||||
.interval = TIME_INFINITE
|
||||
},
|
||||
// Receive radio configuration
|
||||
.radio_conf = {
|
||||
.freq = FREQ_APRS_AUSTRALIA,
|
||||
.mod = MOD_AFSK,
|
||||
.rssi = 0x4F
|
||||
},
|
||||
// APRS identity used in message responses if digipeat is not enabled
|
||||
.call = "VK2GJ-4",
|
||||
.symbol = SYM_ANTENNA
|
||||
},
|
||||
.aprs_msg = true, // Set true to enable messages to be accepted on RX call sign
|
||||
.digi = false,
|
||||
.tx = {
|
||||
// Transmit radio configuration
|
||||
.radio_conf = {
|
||||
.freq = FREQ_RX_APRS,
|
||||
.pwr = 0x7F,
|
||||
.mod = MOD_AFSK,
|
||||
.cca = 0x5F
|
||||
},
|
||||
// Digipeat transmission identity
|
||||
.call = "VK2GJ-5",
|
||||
.path = "WIDE2-1",
|
||||
.symbol = SYM_DIGIPEATER,
|
||||
// A digipeater beacon can be added using one of the POS apps
|
||||
// Set the POS identity the same as the dipipeater TX identity
|
||||
// Alternatively the digipeater can have its own .beacon entry here
|
||||
},
|
||||
},
|
||||
|
||||
// Global controls
|
||||
|
||||
// Power control
|
||||
.keep_cam_switched_on = false,
|
||||
.gps_on_vbat = 3300, // mV
|
||||
.gps_off_vbat = 3000, // mV
|
||||
.gps_onper_vbat = 3500, // mV
|
||||
|
||||
// GPS altitude model control (air pressure controlled using on-board BME280)
|
||||
.gps_pressure = 90000, // Air pressure (Pa) threshold for alt model switch
|
||||
.gps_low_alt = GPS_STATIONARY,
|
||||
.gps_high_alt = GPS_AIRBORNE_1G,
|
||||
|
||||
// APRS
|
||||
// How often to send telemetry config (global for beacons)
|
||||
.tel_enc_cycle = TIME_S2I(60 * 60),
|
||||
|
||||
// The default APRS frequency when geofence is not resolved
|
||||
.freq = FREQ_APRS_AUSTRALIA,
|
||||
|
||||
// The base station identity.
|
||||
.base = {
|
||||
// If enabled tracker initiated APRS messages are addressed to this call sign
|
||||
.enabled = true,
|
||||
.call = "VK2GJ-7",
|
||||
.path = "WIDE2-1",
|
||||
},
|
||||
|
||||
.magic = CONFIG_MAGIC_DEFAULT // Do not remove. This is the activation bit.
|
||||
};
|
||||
/**
|
||||
* Put your configuration settings here. See description of all fields in types.h
|
||||
*/
|
||||
|
||||
|
||||
#include "config.h"
|
||||
#include "aprs.h"
|
||||
#include "geofence.h"
|
||||
#include "pktconf.h"
|
||||
|
||||
conf_t conf_sram useCCM;
|
||||
|
||||
const conf_t conf_flash_default = {
|
||||
// Primary position app
|
||||
.pos_pri = {
|
||||
.beacon = {
|
||||
.active = true,
|
||||
.cycle = TIME_S2I(60),
|
||||
.init_delay = TIME_S2I(5),
|
||||
.fixed = false
|
||||
},
|
||||
.radio_conf = {
|
||||
.pwr = 0x7F,
|
||||
.freq = FREQ_APRS_AUSTRALIA,
|
||||
.mod = MOD_AFSK,
|
||||
.cca = 0x5F,
|
||||
},
|
||||
// App identity
|
||||
.call = "VK2GJ-11",
|
||||
.path = "WIDE2-1",
|
||||
.symbol = SYM_BALLOON,
|
||||
.aprs_msg = true, // Enable APRS message reception on this app
|
||||
},
|
||||
|
||||
// Secondary position app
|
||||
.pos_sec = {
|
||||
.beacon = {
|
||||
.active = true,
|
||||
.cycle = TIME_S2I(10), // Beacon interval
|
||||
.init_delay = TIME_S2I(30),
|
||||
.fixed = false
|
||||
},
|
||||
/* Altitude controlled settings. */
|
||||
.arm_alt = 20000
|
||||
.run_alt = 15000,
|
||||
/* Radio configuration. */
|
||||
.radio_conf = {
|
||||
.pwr = 0x7F,
|
||||
.freq = FREQ_APRS_AUSTRALIA,
|
||||
.mod = MOD_AFSK,
|
||||
.cca = 0x4F
|
||||
},
|
||||
// App identity
|
||||
.call = "VK2GJ-12",
|
||||
.path = "WIDE2-1",
|
||||
.symbol = SYM_BALLOON,
|
||||
.aprs_msg = true, // Enable APRS message reception on this app
|
||||
},
|
||||
|
||||
// Primary image app
|
||||
.img_pri = {
|
||||
.svc_conf = {
|
||||
.active = false,
|
||||
.cycle = TIME_S2I(60 * 10),
|
||||
.init_delay = TIME_S2I(60),
|
||||
.send_spacing = TIME_S2I(3)
|
||||
},
|
||||
.radio_conf = {
|
||||
.pwr = 0x1F,
|
||||
.freq = FREQ_GEOFENCE,
|
||||
.mod = MOD_AFSK,
|
||||
.cca = 0x5F
|
||||
|
||||
},
|
||||
// App identity
|
||||
.call = "VK2GJ-5",
|
||||
.path = "",
|
||||
|
||||
// Image settings
|
||||
.res = RES_QVGA,
|
||||
.quality = 4,
|
||||
.buf_size = 15 * 1024,
|
||||
.redundantTx = true
|
||||
},
|
||||
|
||||
// Secondary image app
|
||||
.img_sec = {
|
||||
.svc_conf = {
|
||||
.active = false,
|
||||
.cycle = TIME_S2I(60 * 1),
|
||||
.init_delay = TIME_S2I(10),
|
||||
.send_spacing = TIME_S2I(0)
|
||||
},
|
||||
.radio_conf = {
|
||||
.pwr = 0x7F,
|
||||
.freq = 144800000,
|
||||
.mod = MOD_2FSK_9k6,
|
||||
.cca = 0x5F
|
||||
},
|
||||
// App identity
|
||||
.call = "VK2GJ-2",
|
||||
.path = "",
|
||||
|
||||
// Image settings
|
||||
.res = RES_QVGA,
|
||||
.quality = 4,
|
||||
.buf_size = 20 * 1024,
|
||||
.redundantTx = false,
|
||||
.no_burst = true
|
||||
},
|
||||
|
||||
// Log app
|
||||
.log = {
|
||||
.svc_conf = {
|
||||
.active = false,
|
||||
.cycle = TIME_S2I(10),
|
||||
.init_delay = TIME_S2I(5)
|
||||
},
|
||||
.radio_conf = {
|
||||
.pwr = 0x7F,
|
||||
.freq = FREQ_GEOFENCE,
|
||||
.mod = MOD_AFSK,
|
||||
.cca = 0x4F
|
||||
},
|
||||
// Node identity
|
||||
.call = "VK2GJ-13",
|
||||
.path = "WIDE1-1",
|
||||
.density = 10
|
||||
},
|
||||
|
||||
// APRS app
|
||||
.aprs = {
|
||||
// The receive identity for APRS
|
||||
.rx = {
|
||||
.svc_conf = {
|
||||
// The packet receive service is enabled if true
|
||||
// Receive is paused and resumed by transmission on that radio
|
||||
// Receive can have a schedule set by cycle and interval
|
||||
// An interval will run receive for the specified time period
|
||||
// If interval is TIME_IMMEDIATE the radio turns off then on immediately
|
||||
// If interval is TIME_INFINITE then the radio stays on and cycle is ignored
|
||||
// Cycle is checked after the interval has expired
|
||||
// Cycle timing less than interval means the cycle will run immediately after interval
|
||||
// If cycle is CYCLE_CONTINUOUSLY the radio turns off and on at each interval
|
||||
.active = true,
|
||||
.init_delay = TIME_S2I(20),
|
||||
.cycle = TIME_S2I(60),
|
||||
.interval = TIME_INFINITE
|
||||
},
|
||||
// Receive radio configuration
|
||||
.radio_conf = {
|
||||
.freq = FREQ_APRS_AUSTRALIA,
|
||||
.mod = MOD_AFSK,
|
||||
.rssi = 0x4F
|
||||
},
|
||||
// APRS identity used in message responses if digipeat is not enabled
|
||||
.call = "VK2GJ-4",
|
||||
.symbol = SYM_ANTENNA
|
||||
},
|
||||
.aprs_msg = true, // Set true to enable messages to be accepted on RX call sign
|
||||
.digi = false,
|
||||
.tx = {
|
||||
// Transmit radio configuration
|
||||
.radio_conf = {
|
||||
.freq = FREQ_RX_APRS,
|
||||
.pwr = 0x7F,
|
||||
.mod = MOD_AFSK,
|
||||
.cca = 0x5F
|
||||
},
|
||||
// Digipeat transmission identity
|
||||
.call = "VK2GJ-5",
|
||||
.path = "WIDE2-1",
|
||||
.symbol = SYM_DIGIPEATER,
|
||||
// A digipeater beacon can be added using one of the POS apps
|
||||
// Set the POS identity the same as the dipipeater TX identity
|
||||
// Alternatively the digipeater can have its own .beacon entry here
|
||||
},
|
||||
},
|
||||
|
||||
// Global controls
|
||||
|
||||
// Power control
|
||||
.keep_cam_switched_on = false,
|
||||
.gps_on_vbat = 3300, // mV
|
||||
.gps_off_vbat = 3000, // mV
|
||||
.gps_onper_vbat = 3500, // mV
|
||||
|
||||
// GPS altitude model control (air pressure controlled using on-board BME280)
|
||||
.gps_pressure = 90000, // Air pressure (Pa) threshold for alt model switch
|
||||
.gps_low_alt = GPS_STATIONARY,
|
||||
.gps_high_alt = GPS_AIRBORNE_1G,
|
||||
|
||||
// APRS
|
||||
// How often to send telemetry config (global for beacons)
|
||||
.tel_enc_cycle = TIME_S2I(60 * 60),
|
||||
|
||||
// The default APRS frequency when geofence is not resolved
|
||||
.freq = FREQ_APRS_AUSTRALIA,
|
||||
|
||||
// The base station identity.
|
||||
.base = {
|
||||
// If enabled tracker initiated APRS messages are addressed to this call sign
|
||||
.enabled = true,
|
||||
.call = "VK2GJ-7",
|
||||
.path = "WIDE2-1",
|
||||
},
|
||||
|
||||
.magic = CONFIG_MAGIC_DEFAULT // Do not remove. This is the activation bit.
|
||||
};
|
||||
|
|
|
@ -39,10 +39,13 @@ const conf_t conf_flash_default = {
|
|||
.pos_sec = {
|
||||
.beacon = {
|
||||
.active = true,
|
||||
.cycle = TIME_S2I(30), // Beacon interval
|
||||
.cycle = TIME_S2I(60), // Beacon interval
|
||||
.init_delay = TIME_S2I(10),
|
||||
.fixed = false
|
||||
},
|
||||
/* Altitude controlled settings. */
|
||||
.run_alt = 100,
|
||||
/* Radio configuration. */
|
||||
.radio_conf = {
|
||||
.pwr = 0x1F,
|
||||
.freq = 144800000,
|
||||
|
|
|
@ -1,244 +1,247 @@
|
|||
#ifndef __TYPES_H__
|
||||
#define __TYPES_H__
|
||||
|
||||
#include "ch.h"
|
||||
#include "ax25_pad.h"
|
||||
#include "ublox.h"
|
||||
|
||||
#define IS_AFSK(m) ((m) == MOD_AFSK)
|
||||
#define IS_2FSK(m) ((m) == MOD_2FSK_300 || (m) == MOD_2FSK_9k6 \
|
||||
|| (m) == MOD_2FSK_19k2 || (m) == MOD_2FSK_38k4 \
|
||||
|| (m) == MOD_2FSK_57k6 || (m) == MOD_2FSK_76k8 \
|
||||
|| (m) == MOD_2FSK_96k || (m) == MOD_2FSK_115k2)
|
||||
#define IS_FAST_2FSK(m) ((m) == MOD_2FSK_9k6 \
|
||||
|| (m) == MOD_2FSK_19k2 || (m) == MOD_2FSK_38k4 \
|
||||
|| (m) == MOD_2FSK_57k6 || (m) == MOD_2FSK_76k8 \
|
||||
|| (m) == MOD_2FSK_96k || (m) == MOD_2FSK_115k2)
|
||||
|
||||
typedef enum {
|
||||
FREQ_INVALID = 0,
|
||||
FREQ_APRS_GEOFENCE, /* Geofencing frequency (144.8 default). */
|
||||
FREQ_SCAN, /* Frequency last found in RX scan. - TBI */
|
||||
FREQ_RX_APRS, /* Active RX frequency - fall back to DYNAMIC. */
|
||||
FREQ_RX_CMDC, /* Frequency used for command and control. TBI */
|
||||
FREQ_DEFAULT, /* Default frequency specified in configuration */
|
||||
FREQ_CODES_END
|
||||
} freq_codes_t;
|
||||
|
||||
#define FREQ_INVALID 0
|
||||
#define FREQ_GEOFENCE 1 /* Geofencing frequency (144.8 default). */
|
||||
#define FREQ_SCAN 2 /* Frequency based on band base + channel scan. */
|
||||
#define FREQ_RX_APRS 3 /* Active RX frequency - fall back to DYNAMIC. */
|
||||
#define FREQ_RX_CMDC 4 /* Frequency used for command and control. TBI */
|
||||
#define FREQ_DEFAULT 5 /* Default frequency specified in configuration */
|
||||
#define FREQ_CODES_END 6
|
||||
|
||||
#define CYCLE_CONTINUOUSLY 0
|
||||
|
||||
#define TYPE_NULL 0
|
||||
#define TYPE_INT 1
|
||||
#define TYPE_TIME 2
|
||||
#define TYPE_STR 3
|
||||
|
||||
typedef enum {
|
||||
SLEEP_DISABLED = 0,
|
||||
SLEEP_WHEN_VBAT_BELOW_THRES,
|
||||
SLEEP_WHEN_VSOL_BELOW_THRES,
|
||||
SLEEP_WHEN_VBAT_ABOVE_THRES,
|
||||
SLEEP_WHEN_VSOL_ABOVE_THRES,
|
||||
SLEEP_WHEN_DISCHARGING,
|
||||
SLEEP_WHEN_CHARGING
|
||||
} sleep_type_t;
|
||||
|
||||
typedef struct {
|
||||
sleep_type_t type;
|
||||
volt_level_t vbat_thres;
|
||||
volt_level_t vsol_thres;
|
||||
} sleep_conf_t;
|
||||
|
||||
typedef enum { // Modulation type
|
||||
MOD_NONE,
|
||||
MOD_CW,
|
||||
MOD_AFSK,
|
||||
MOD_2FSK_300,
|
||||
MOD_2FSK_9k6,
|
||||
MOD_2FSK_19k2,
|
||||
MOD_2FSK_38k4,
|
||||
MOD_2FSK_57k6,
|
||||
MOD_2FSK_76k8,
|
||||
MOD_2FSK_96k,
|
||||
MOD_2FSK_115k2
|
||||
} radio_mod_t;
|
||||
|
||||
typedef enum {
|
||||
RES_NONE = 0,
|
||||
RES_QQVGA,
|
||||
RES_QVGA,
|
||||
RES_VGA,
|
||||
RES_VGA_ZOOM2,
|
||||
RES_VGA_ZOOM4,
|
||||
RES_XGA,
|
||||
RES_UXGA,
|
||||
RES_MAX
|
||||
} resolution_t;
|
||||
|
||||
typedef struct {
|
||||
radio_pwr_t pwr;
|
||||
radio_freq_hz_t freq;
|
||||
radio_mod_t mod;
|
||||
union {
|
||||
radio_squelch_t cca;
|
||||
radio_squelch_t rssi;
|
||||
};
|
||||
} radio_conf_t;
|
||||
|
||||
typedef struct {
|
||||
radio_pwr_t pwr;
|
||||
radio_freq_hz_t freq;
|
||||
radio_mod_t mod;
|
||||
link_speed_t speed;
|
||||
radio_squelch_t cca;
|
||||
sysinterval_t rx_wait; // TODO: implement into in progress RX wait.
|
||||
sysinterval_t cca_wait;
|
||||
} radio_tx_conf_t; // Radio / Modulation
|
||||
|
||||
typedef struct {
|
||||
radio_freq_hz_t freq;
|
||||
radio_mod_t mod;
|
||||
link_speed_t speed;
|
||||
radio_squelch_t rssi;
|
||||
} radio_rx_conf_t; // Radio / Modulation
|
||||
|
||||
typedef struct {
|
||||
bool active;
|
||||
sysinterval_t init_delay;
|
||||
sysinterval_t send_spacing;
|
||||
sleep_conf_t sleep_conf;
|
||||
sysinterval_t cycle; // Cycle time (0: continuously)
|
||||
sysinterval_t interval;
|
||||
} thread_conf_t; // Thread
|
||||
|
||||
typedef struct {
|
||||
bool active;
|
||||
sysinterval_t init_delay;
|
||||
//sysinterval_t send_spacing;
|
||||
sleep_conf_t sleep_conf;
|
||||
sysinterval_t cycle; // Cycle time (0: continuously)
|
||||
sysinterval_t duration;
|
||||
sysinterval_t gps_wait; // Maximum time to wait for a fix
|
||||
// Default lat, lon and alt when fixed is enabled
|
||||
bool fixed;
|
||||
gps_coord_t lat;
|
||||
gps_coord_t lon;
|
||||
gps_alt_t alt;
|
||||
} telem_svc_conf_t; // Thread
|
||||
|
||||
typedef struct {
|
||||
telem_svc_conf_t beacon;
|
||||
radio_tx_conf_t radio_conf;
|
||||
// Protocol
|
||||
char call[AX25_MAX_ADDR_LEN];
|
||||
char path[16];
|
||||
aprs_sym_t symbol;
|
||||
bool aprs_msg;
|
||||
bool run_once;
|
||||
sysinterval_t gps_wait;
|
||||
} bcn_app_conf_t;
|
||||
|
||||
typedef struct {
|
||||
thread_conf_t svc_conf;
|
||||
radio_tx_conf_t radio_conf;
|
||||
bool redundantTx;
|
||||
//sysinterval_t send_spacing;
|
||||
// Protocol
|
||||
char call[AX25_MAX_ADDR_LEN];
|
||||
char path[16];
|
||||
resolution_t res; // Picture resolution
|
||||
uint8_t quality; // SSDV Quality ranging from 0-7
|
||||
bool flip; // 180 image rotation
|
||||
bool no_burst; // Disable burst send
|
||||
uint32_t buf_size; // SRAM buffer size for the picture
|
||||
} img_app_conf_t;
|
||||
|
||||
typedef struct {
|
||||
thread_conf_t svc_conf;
|
||||
radio_tx_conf_t radio_conf;
|
||||
// Protocol
|
||||
char call[AX25_MAX_ADDR_LEN];
|
||||
char path[16];
|
||||
uint8_t density; // Density of log points being sent out in 1/x (value 10 => 10%)
|
||||
} log_app_conf_t;
|
||||
|
||||
typedef struct {
|
||||
thread_conf_t svc_conf;
|
||||
radio_rx_conf_t radio_conf;
|
||||
aprs_sym_t symbol;
|
||||
// Protocol
|
||||
char call[AX25_MAX_ADDR_LEN];
|
||||
} thd_rx_conf_t;
|
||||
|
||||
typedef struct {
|
||||
radio_tx_conf_t radio_conf;
|
||||
// Protocol
|
||||
char call[AX25_MAX_ADDR_LEN];
|
||||
char path[16];
|
||||
aprs_sym_t symbol;
|
||||
} thd_tx_conf_t;
|
||||
|
||||
typedef struct {
|
||||
radio_tx_conf_t radio_conf;
|
||||
// Protocol
|
||||
char call[AX25_MAX_ADDR_LEN];
|
||||
char path[16];
|
||||
aprs_sym_t symbol;
|
||||
bool enabled;
|
||||
} thd_base_conf_t;
|
||||
|
||||
/* APRS configuration. */
|
||||
typedef struct {
|
||||
thd_rx_conf_t rx;
|
||||
bool aprs_msg;
|
||||
bool digi;
|
||||
bcn_app_conf_t tx;
|
||||
} thd_aprs_conf_t;
|
||||
|
||||
typedef struct {
|
||||
bcn_app_conf_t pos_pri; // Primary position thread configuration
|
||||
bcn_app_conf_t pos_sec; // Secondary position thread configuration
|
||||
|
||||
img_app_conf_t img_pri; // Primary image thread configuration
|
||||
img_app_conf_t img_sec; // Secondary image thread configuration
|
||||
|
||||
log_app_conf_t log; // Log transmission configuration
|
||||
thd_aprs_conf_t aprs;
|
||||
|
||||
bool keep_cam_switched_on; // Keep camera switched on and initialized, this makes image capturing faster but takes a lot of power over long time
|
||||
|
||||
volt_level_t gps_on_vbat; // Battery voltage threshold at which GPS is switched on
|
||||
volt_level_t gps_off_vbat; // Battery voltage threshold at which GPS is switched off
|
||||
volt_level_t gps_onper_vbat; // Battery voltage threshold at which GPS is kept switched on all time. This value must be larger
|
||||
// When gps_on_vbat and gps_off_vbat otherwise this value has no effect. Value 0 disables this feature
|
||||
uint32_t gps_pressure; // Air pressure below which GPS is switched to airborne mode
|
||||
gps_hp_model_t gps_low_alt; // Model to use when air pressure is above gps_pa_threshold
|
||||
gps_lp_model_t gps_high_alt; // Model to use when air pressure is below gps_pa_threshold
|
||||
|
||||
//APRS global
|
||||
sysinterval_t tel_enc_cycle; // Cycle for sending of telemetry config headers
|
||||
radio_freq_hz_t freq; // Default APRS frequency if geolocation not available
|
||||
// Base station call sign for receipt of tracker initiated sends
|
||||
// These are sends by the tracker which are not in response to a query.
|
||||
thd_base_conf_t base;
|
||||
|
||||
uint32_t magic; // Key that indicates if the flash is loaded or has been updated
|
||||
uint16_t crc; // CRC to verify content
|
||||
} conf_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
char name[64];
|
||||
size_t size;
|
||||
void *ptr;
|
||||
} conf_command_t;
|
||||
|
||||
#endif /* __TYPES_H__ */
|
||||
|
||||
#ifndef __TYPES_H__
|
||||
#define __TYPES_H__
|
||||
|
||||
#include "ch.h"
|
||||
#include "ax25_pad.h"
|
||||
#include "ublox.h"
|
||||
|
||||
#define IS_AFSK(m) ((m) == MOD_AFSK)
|
||||
#define IS_2FSK(m) ((m) == MOD_2FSK_300 || (m) == MOD_2FSK_9k6 \
|
||||
|| (m) == MOD_2FSK_19k2 || (m) == MOD_2FSK_38k4 \
|
||||
|| (m) == MOD_2FSK_57k6 || (m) == MOD_2FSK_76k8 \
|
||||
|| (m) == MOD_2FSK_96k || (m) == MOD_2FSK_115k2)
|
||||
#define IS_FAST_2FSK(m) ((m) == MOD_2FSK_9k6 \
|
||||
|| (m) == MOD_2FSK_19k2 || (m) == MOD_2FSK_38k4 \
|
||||
|| (m) == MOD_2FSK_57k6 || (m) == MOD_2FSK_76k8 \
|
||||
|| (m) == MOD_2FSK_96k || (m) == MOD_2FSK_115k2)
|
||||
|
||||
typedef enum {
|
||||
FREQ_INVALID = 0,
|
||||
FREQ_APRS_GEOFENCE, /* Geofencing frequency (144.8 default). */
|
||||
FREQ_SCAN, /* Frequency last found in RX scan. - TBI */
|
||||
FREQ_RX_APRS, /* Active RX frequency - fall back to DYNAMIC. */
|
||||
FREQ_RX_CMDC, /* Frequency used for command and control. TBI */
|
||||
FREQ_DEFAULT, /* Default frequency specified in configuration */
|
||||
FREQ_CODES_END
|
||||
} freq_codes_t;
|
||||
|
||||
#define FREQ_INVALID 0
|
||||
#define FREQ_GEOFENCE 1 /* Geofencing frequency (144.8 default). */
|
||||
#define FREQ_SCAN 2 /* Frequency based on band base + channel scan. */
|
||||
#define FREQ_RX_APRS 3 /* Active RX frequency - fall back to DYNAMIC. */
|
||||
#define FREQ_RX_CMDC 4 /* Frequency used for command and control. TBI */
|
||||
#define FREQ_DEFAULT 5 /* Default frequency specified in configuration */
|
||||
#define FREQ_CODES_END 6
|
||||
|
||||
#define CYCLE_CONTINUOUSLY 0
|
||||
|
||||
#define TYPE_NULL 0
|
||||
#define TYPE_INT 1
|
||||
#define TYPE_TIME 2
|
||||
#define TYPE_STR 3
|
||||
|
||||
typedef enum {
|
||||
SLEEP_DISABLED = 0,
|
||||
SLEEP_WHEN_VBAT_BELOW_THRES,
|
||||
SLEEP_WHEN_VSOL_BELOW_THRES,
|
||||
SLEEP_WHEN_VBAT_ABOVE_THRES,
|
||||
SLEEP_WHEN_VSOL_ABOVE_THRES,
|
||||
SLEEP_WHEN_DISCHARGING,
|
||||
SLEEP_WHEN_CHARGING
|
||||
} sleep_type_t;
|
||||
|
||||
typedef struct {
|
||||
sleep_type_t type;
|
||||
volt_level_t vbat_thres;
|
||||
volt_level_t vsol_thres;
|
||||
} sleep_conf_t;
|
||||
|
||||
typedef enum { // Modulation type
|
||||
MOD_NONE,
|
||||
MOD_CW,
|
||||
MOD_AFSK,
|
||||
MOD_2FSK_300,
|
||||
MOD_2FSK_9k6,
|
||||
MOD_2FSK_19k2,
|
||||
MOD_2FSK_38k4,
|
||||
MOD_2FSK_57k6,
|
||||
MOD_2FSK_76k8,
|
||||
MOD_2FSK_96k,
|
||||
MOD_2FSK_115k2
|
||||
} radio_mod_t;
|
||||
|
||||
typedef enum {
|
||||
RES_NONE = 0,
|
||||
RES_QQVGA,
|
||||
RES_QVGA,
|
||||
RES_VGA,
|
||||
RES_VGA_ZOOM2,
|
||||
RES_VGA_ZOOM4,
|
||||
RES_XGA,
|
||||
RES_UXGA,
|
||||
RES_MAX
|
||||
} resolution_t;
|
||||
|
||||
typedef struct {
|
||||
radio_pwr_t pwr;
|
||||
radio_freq_hz_t freq;
|
||||
radio_mod_t mod;
|
||||
union {
|
||||
radio_squelch_t cca;
|
||||
radio_squelch_t rssi;
|
||||
};
|
||||
} radio_conf_t;
|
||||
|
||||
typedef struct {
|
||||
radio_pwr_t pwr;
|
||||
radio_freq_hz_t freq;
|
||||
radio_mod_t mod;
|
||||
link_speed_t speed;
|
||||
radio_squelch_t cca;
|
||||
sysinterval_t rx_wait; // TODO: implement into in progress RX wait.
|
||||
sysinterval_t cca_wait;
|
||||
} radio_tx_conf_t; // Radio / Modulation
|
||||
|
||||
typedef struct {
|
||||
radio_freq_hz_t freq;
|
||||
radio_mod_t mod;
|
||||
link_speed_t speed;
|
||||
radio_squelch_t rssi;
|
||||
} radio_rx_conf_t; // Radio / Modulation
|
||||
|
||||
typedef struct {
|
||||
bool active;
|
||||
sysinterval_t init_delay;
|
||||
sysinterval_t send_spacing;
|
||||
sleep_conf_t sleep_conf;
|
||||
sysinterval_t cycle; // Cycle time (0: continuously)
|
||||
sysinterval_t interval;
|
||||
} thread_conf_t; // Thread
|
||||
|
||||
typedef struct {
|
||||
bool active;
|
||||
sysinterval_t init_delay;
|
||||
sleep_conf_t sleep_conf;
|
||||
sysinterval_t cycle; // Cycle time (0: continuously)
|
||||
sysinterval_t duration;
|
||||
sysinterval_t gps_wait; // Maximum time to wait for a fix
|
||||
// Default lat, lon and alt when fixed is enabled
|
||||
bool fixed;
|
||||
gps_coord_t lat;
|
||||
gps_coord_t lon;
|
||||
gps_alt_t alt;
|
||||
} bcn_svc_conf_t; // Thread
|
||||
|
||||
typedef struct {
|
||||
bcn_svc_conf_t beacon;
|
||||
radio_tx_conf_t radio_conf;
|
||||
// Protocol
|
||||
char call[AX25_MAX_ADDR_LEN];
|
||||
char path[16];
|
||||
aprs_sym_t symbol;
|
||||
bool aprs_msg;
|
||||
bool run_once;
|
||||
int32_t arm_alt;
|
||||
int32_t run_alt;
|
||||
ioline_t arm_line;
|
||||
ioline_t run_line;
|
||||
sysinterval_t gps_wait;
|
||||
} bcn_app_conf_t;
|
||||
|
||||
typedef struct {
|
||||
thread_conf_t svc_conf;
|
||||
radio_tx_conf_t radio_conf;
|
||||
bool redundantTx;
|
||||
//sysinterval_t send_spacing;
|
||||
// Protocol
|
||||
char call[AX25_MAX_ADDR_LEN];
|
||||
char path[16];
|
||||
resolution_t res; // Picture resolution
|
||||
uint8_t quality; // SSDV Quality ranging from 0-7
|
||||
bool flip; // 180 image rotation
|
||||
bool no_burst; // Disable burst send
|
||||
uint32_t buf_size; // SRAM buffer size for the picture
|
||||
} img_app_conf_t;
|
||||
|
||||
typedef struct {
|
||||
thread_conf_t svc_conf;
|
||||
radio_tx_conf_t radio_conf;
|
||||
// Protocol
|
||||
char call[AX25_MAX_ADDR_LEN];
|
||||
char path[16];
|
||||
uint8_t density; // Density of log points being sent out in 1/x (value 10 => 10%)
|
||||
} log_app_conf_t;
|
||||
|
||||
typedef struct {
|
||||
thread_conf_t svc_conf;
|
||||
radio_rx_conf_t radio_conf;
|
||||
aprs_sym_t symbol;
|
||||
// Protocol
|
||||
char call[AX25_MAX_ADDR_LEN];
|
||||
} thd_rx_conf_t;
|
||||
|
||||
typedef struct {
|
||||
radio_tx_conf_t radio_conf;
|
||||
// Protocol
|
||||
char call[AX25_MAX_ADDR_LEN];
|
||||
char path[16];
|
||||
aprs_sym_t symbol;
|
||||
} thd_tx_conf_t;
|
||||
|
||||
typedef struct {
|
||||
radio_tx_conf_t radio_conf;
|
||||
// Protocol
|
||||
char call[AX25_MAX_ADDR_LEN];
|
||||
char path[16];
|
||||
aprs_sym_t symbol;
|
||||
bool enabled;
|
||||
} thd_base_conf_t;
|
||||
|
||||
/* APRS configuration. */
|
||||
typedef struct {
|
||||
thd_rx_conf_t rx;
|
||||
bool aprs_msg;
|
||||
bool digi;
|
||||
bcn_app_conf_t tx;
|
||||
} thd_aprs_conf_t;
|
||||
|
||||
typedef struct {
|
||||
bcn_app_conf_t pos_pri; // Primary position thread configuration
|
||||
bcn_app_conf_t pos_sec; // Secondary position thread configuration
|
||||
|
||||
img_app_conf_t img_pri; // Primary image thread configuration
|
||||
img_app_conf_t img_sec; // Secondary image thread configuration
|
||||
|
||||
log_app_conf_t log; // Log transmission configuration
|
||||
thd_aprs_conf_t aprs;
|
||||
|
||||
bool keep_cam_switched_on; // Keep camera switched on and initialized, this makes image capturing faster but takes a lot of power over long time
|
||||
|
||||
volt_level_t gps_on_vbat; // Battery voltage threshold at which GPS is switched on
|
||||
volt_level_t gps_off_vbat; // Battery voltage threshold at which GPS is switched off
|
||||
volt_level_t gps_onper_vbat; // Battery voltage threshold at which GPS is kept switched on all time. This value must be larger
|
||||
// When gps_on_vbat and gps_off_vbat otherwise this value has no effect. Value 0 disables this feature
|
||||
uint32_t gps_pressure; // Air pressure below which GPS is switched to airborne mode
|
||||
gps_hp_model_t gps_low_alt; // Model to use when air pressure is above gps_pa_threshold
|
||||
gps_lp_model_t gps_high_alt; // Model to use when air pressure is below gps_pa_threshold
|
||||
|
||||
//APRS global
|
||||
sysinterval_t tel_enc_cycle; // Cycle for sending of telemetry config headers
|
||||
radio_freq_hz_t freq; // Default APRS frequency if geolocation not available
|
||||
// Base station call sign for receipt of tracker initiated sends
|
||||
// These are sends by the tracker which are not in response to a query.
|
||||
thd_base_conf_t base;
|
||||
|
||||
uint32_t magic; // Key that indicates if the flash is loaded or has been updated
|
||||
uint16_t crc; // CRC to verify content
|
||||
} conf_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
char name[64];
|
||||
size_t size;
|
||||
void *ptr;
|
||||
} conf_command_t;
|
||||
|
||||
#endif /* __TYPES_H__ */
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ void usb_cmd_ccm_heap(BaseSequentialStream *chp, int argc, char *argv[]) {
|
|||
extern uint8_t __ram4_free__[];
|
||||
extern uint8_t __ram4_end__[];
|
||||
|
||||
chprintf(chp, SHELL_NEWLINE_STR"CCM heap : size %x starts at : %x"SHELL_NEWLINE_STR,
|
||||
chprintf(chp, SHELL_NEWLINE_STR"CCM heap : size %d (0x%x) starts at : 0x%x"SHELL_NEWLINE_STR,
|
||||
(__ram4_end__ - __ram4_free__), __ram4_free__);
|
||||
n = chHeapStatus(ccm_heap, &total, &largest);
|
||||
chprintf(chp, SHELL_NEWLINE_STR"CCM Heap"SHELL_NEWLINE_STR);
|
||||
|
|
Plik diff jest za duży
Load Diff
|
@ -19,8 +19,18 @@
|
|||
#define Si446x_USE_AFSK_LCM_DATA_RATE FALSE
|
||||
#define Si446x_USE_NB_RECEIVE_FILTER TRUE
|
||||
#define Si446x_USE_TRANSMIT_TIMEOUT FALSE
|
||||
#define Si446x_USE_SEMAPHORE_INTERRUPT_SYNC TRUE
|
||||
#define Si446x_USE_PACKET_END_INTERRUPT TRUE
|
||||
#define Si446x_USE_FIFO_THRESHOLD_INTERRUPT TRUE
|
||||
#define Si446x_USE_STATE_CHANGE_INTERRUPT TRUE
|
||||
#define Si446x_USE_COMMON_TX_THREAD TRUE
|
||||
#if Si446x_USE_PACKET_END_INTERRUPT == TRUE \
|
||||
|| Si446x_USE_FIFO_THRESHOLD_INTERRUPT == TRUE \
|
||||
|| Si446x_USE_STATE_CHANGE_INTERRUPT == TRUE
|
||||
#define Si446x_USE_INTERRUPTS TRUE
|
||||
#else
|
||||
#define Si446x_USE_INTERRUPTS FALSE
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
|
@ -299,7 +309,7 @@ typedef uint8_t si446x_reply_t;
|
|||
typedef uint8_t si446x_args_t;
|
||||
|
||||
/* AFSK encoder/up-sampler control object. */
|
||||
typedef struct {
|
||||
typedef struct reSampler {
|
||||
uint32_t phase_delta; // 1200/2200 for standard AX.25
|
||||
uint32_t phase; // Fixed point 9.7 (2PI = TABLE_SIZE)
|
||||
uint32_t packet_pos; // Index of next bit to be sent out
|
||||
|
@ -417,8 +427,15 @@ typedef struct Si446x_DAT {
|
|||
radio_patch_t radio_patch;
|
||||
radio_temp_t lastTemp;
|
||||
radio_clock_t radio_clock;
|
||||
#if Si446x_USE_INTERRUPTS
|
||||
bool nirq_active;
|
||||
#if Si446x_USE_SEMAPHORE_INTERRUPT_SYNC == TRUE
|
||||
binary_semaphore_t wait_sem;
|
||||
#else
|
||||
thread_t *irq_dispatch;
|
||||
thread_reference_t wait_thread;
|
||||
#endif
|
||||
#endif /* Si446x_USE_INTERRUPTS */
|
||||
radio_isr_cb_t cb;
|
||||
si446x_int_status_t int_status;
|
||||
} si446x_data_t;
|
||||
|
@ -460,7 +477,7 @@ extern "C" {
|
|||
void Si446x_unlockRadio(const radio_mode_t mode);
|
||||
//void Si446x_lockRadioByCamera(void);
|
||||
//void Si446x_unlockRadioByCamera(void);
|
||||
bool Si446x_conditional_init(radio_unit_t radio);
|
||||
bool Si446x_driverInit(radio_unit_t radio);
|
||||
radio_signal_t Si446x_getCurrentRSSI(const radio_unit_t radio);
|
||||
ICUDriver *Si446x_attachPWM(const radio_unit_t radio);
|
||||
void Si446x_detachPWM(const radio_unit_t radio);
|
||||
|
|
|
@ -181,7 +181,7 @@ THD_FUNCTION(tcxo_thd, arg) {
|
|||
&result,
|
||||
NULL);
|
||||
if (msg != MSG_OK) {
|
||||
TRACE_ERROR("TCXO > Could not post TCXO update to radio %d",
|
||||
TRACE_ERROR("TCXO > Could not queue TCXO update for radio %d",
|
||||
radio);
|
||||
}
|
||||
if (result != MSG_OK) {
|
||||
|
|
|
@ -44,7 +44,7 @@ const char *gps_get_model_name(uint8_t index) {
|
|||
void gps_transmit_string(uint8_t *cmd, uint8_t length) {
|
||||
gps_calc_ubx_csum(cmd, length);
|
||||
#if UBLOX_USE_I2C == TRUE
|
||||
I2C_writeN(PKT_GPS_I2C, UBLOX_MAX_ADDRESS, cmd, length);
|
||||
I2C_writeN(&PKT_GPS_I2C, UBLOX_MAX_ADDRESS, cmd, length);
|
||||
#elif defined(UBLOX_UART_CONNECTED)
|
||||
sdWrite(&PKT_GPS_UART, cmd, length);
|
||||
#endif
|
||||
|
@ -57,10 +57,10 @@ void gps_transmit_string(uint8_t *cmd, uint8_t length) {
|
|||
bool gps_receive_byte(uint8_t *data) {
|
||||
#if UBLOX_USE_I2C == TRUE
|
||||
uint16_t len;
|
||||
I2C_read16(PKT_GPS_I2C, UBLOX_MAX_ADDRESS, 0xFD, &len);
|
||||
I2C_read16(&PKT_GPS_I2C, UBLOX_MAX_ADDRESS, 0xFD, &len);
|
||||
if(len) {
|
||||
I2C_read8(PKT_GPS_I2C, UBLOX_MAX_ADDRESS, 0xFF, data);
|
||||
return true;
|
||||
I2C_read8(&PKT_GPS_I2C, UBLOX_MAX_ADDRESS, 0xFF, data);
|
||||
return true;
|
||||
}
|
||||
#elif defined(UBLOX_UART_CONNECTED)
|
||||
return sdReadTimeout(&PKT_GPS_UART, data, 1, TIME_IMMEDIATE);
|
||||
|
@ -631,9 +631,8 @@ bool gps_set_model(bool dynamic) {
|
|||
bool GPS_Init() {
|
||||
// Initialize pins
|
||||
TRACE_DEBUG("GPS > Init GPS pins");
|
||||
palSetLineMode(LINE_GPS_EN, PAL_MODE_OUTPUT_PUSHPULL); // GPS off
|
||||
palSetLineMode(LINE_GPS_RESET, PAL_MODE_OUTPUT_PUSHPULL); // GPS reset
|
||||
palSetLineMode(LINE_GPS_EN, PAL_MODE_OUTPUT_PUSHPULL); // GPS off
|
||||
|
||||
|
||||
#if defined(UBLOX_UART_CONNECTED) && UBLOX_USE_I2C == FALSE
|
||||
// Init and start UART
|
||||
|
@ -643,12 +642,17 @@ bool GPS_Init() {
|
|||
palSetLineMode(LINE_GPS_TXD, PAL_MODE_ALTERNATE(11)); // UART TXD
|
||||
sdStart(&PKT_GPS_UART, &gps_config);
|
||||
#endif
|
||||
|
||||
#if defined(UBLOX_UART_CONNECTED)
|
||||
/* Always lock I2C during init. The UBLOX will look on address 0xA0 for
|
||||
an EEPROM. */
|
||||
I2C_Lock(&PKT_GPS_I2C);
|
||||
#endif
|
||||
// Switch MOSFET
|
||||
TRACE_DEBUG("GPS > Power up GPS");
|
||||
palSetLine(LINE_GPS_RESET); // Pull up GPS reset
|
||||
palSetLine(LINE_GPS_EN); // Switch on GPS
|
||||
|
||||
palSetLine(LINE_GPS_RESET); // Pull up GPS reset
|
||||
chThdSleep(TIME_MS2I(10));
|
||||
palSetLine(LINE_GPS_EN); // Switch on GPS
|
||||
|
||||
// Wait for GPS startup
|
||||
chThdSleep(TIME_S2I(1));
|
||||
|
||||
|
@ -663,6 +667,9 @@ bool GPS_Init() {
|
|||
TRACE_DEBUG("GPS > ... Disable NMEA output OK");
|
||||
} else {
|
||||
TRACE_ERROR("GPS > Communication Error [disable NMEA]");
|
||||
#if defined(UBLOX_UART_CONNECTED)
|
||||
I2C_Unlock(&PKT_GPS_I2C);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
cntr = 3;
|
||||
|
@ -671,8 +678,14 @@ bool GPS_Init() {
|
|||
TRACE_DEBUG("GPS > ... Set power options OK");
|
||||
} else {
|
||||
TRACE_ERROR("GPS > Communication Error [power options]");
|
||||
#if defined(UBLOX_UART_CONNECTED)
|
||||
I2C_Unlock(&PKT_GPS_I2C);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
#if defined(UBLOX_UART_CONNECTED)
|
||||
I2C_Unlock(&PKT_GPS_I2C);
|
||||
#endif
|
||||
gps_enabled = true;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ typedef enum {
|
|||
|
||||
#define isGPSLocked(pos) ((pos)->type == 3 && (pos)->num_svs >= 4 && (pos)->fixOK == true)
|
||||
|
||||
/* UBLOX reply messages. */
|
||||
typedef struct {
|
||||
uint8_t chn; // Channel number
|
||||
uint8_t svid; // Satellite ID
|
||||
|
@ -71,7 +72,7 @@ typedef struct {
|
|||
int8_t elev; // Elevation in integer degrees
|
||||
int16_t azim; // Azimuth in integer degrees
|
||||
int32_t prRes; // Pseudo range residual in centimetres
|
||||
} gps_svchn_t;
|
||||
} __attribute__((packed)) gps_svchn_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t iTOW; // Time ms
|
||||
|
@ -79,8 +80,7 @@ typedef struct {
|
|||
uint8_t globalFlags; // chip hardware generation
|
||||
uint16_t reserved2; // reserved
|
||||
gps_svchn_t svinfo[GPS_MAX_SV_CHANNELS];
|
||||
} gps_svinfo_t;
|
||||
|
||||
} __attribute__((packed)) gps_svinfo_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t iTOW; // Time ms
|
||||
|
@ -90,7 +90,7 @@ typedef struct {
|
|||
uint8_t flags2; // further navigation information
|
||||
uint32_t ttff; // time to first fix
|
||||
uint32_t msss; // milliseconds since startup
|
||||
} gps_navinfo_t;
|
||||
} __attribute__((packed)) gps_navinfo_t;
|
||||
|
||||
typedef uint8_t tpidx_t;
|
||||
|
||||
|
@ -106,15 +106,16 @@ typedef struct {
|
|||
uint32_t pulseLenRatioLock; // Pulse length or duty cycle when locked
|
||||
int32_t userConfigDelay; // User configurable time pulse delay
|
||||
uint32_t flags; // Configuration flags
|
||||
} gps_tp5_t;
|
||||
} __attribute__((packed)) gps_tp5_t;
|
||||
|
||||
/* Combination object (not a UBLOX reply). */
|
||||
typedef struct {
|
||||
ptime_t time; // Time
|
||||
uint8_t type; // type of fix (validity)
|
||||
uint8_t num_svs; // number of satellites used for solution, range 0 .. 19
|
||||
int32_t lat; // latitude in deg * 10^7, range -90 .. +90 * 10^7
|
||||
int32_t lon; // longitude in deg * 10^7, range -180 .. +180 * 10^7
|
||||
int32_t alt; // altitude in m, range 0m, up to ~40000m, clamped
|
||||
int32_t alt; // altitude in m, range 0m, up to 50000m, clamped
|
||||
bool fixOK; // Flag that is set to true, when DOP is with the limits
|
||||
uint16_t pdop; // Position DOP
|
||||
uint8_t model; // Dynamic model
|
||||
|
|
|
@ -1,109 +1,120 @@
|
|||
/**
|
||||
* I2C wrapper for ChibiOS due to a bug: I2C blocking when I2C transfer suffered timeout
|
||||
* @see https://github.com/psas/stm32/commit/32ec8c97a1e5bf605bd5d41a89fc60b60e136af2
|
||||
*/
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "pi2c.h"
|
||||
|
||||
//#define I2C_DRIVER (&I2CD1)
|
||||
|
||||
static uint8_t error;
|
||||
|
||||
const I2CConfig _i2cfg = {
|
||||
OPMODE_I2C,
|
||||
50000,
|
||||
STD_DUTY_CYCLE,
|
||||
};
|
||||
|
||||
void I2C_Lock(I2CDriver *bus) {
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
i2cAcquireBus(bus);
|
||||
#else
|
||||
(void)bus;
|
||||
#endif
|
||||
}
|
||||
|
||||
void I2C_Unlock(I2CDriver *bus) {
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
i2cReleaseBus(bus);
|
||||
#else
|
||||
(void)bus;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool I2C_transmit(I2CDriver *bus, uint8_t addr, uint8_t *txbuf, uint32_t txbytes, uint8_t *rxbuf, uint32_t rxbytes, sysinterval_t timeout) {
|
||||
i2cAcquireBus(bus);
|
||||
i2cStart(bus, &_i2cfg);
|
||||
msg_t i2c_status = i2cMasterTransmitTimeout(bus, addr, txbuf, txbytes, rxbuf, rxbytes, timeout);
|
||||
i2cStop(bus);
|
||||
i2cReleaseBus(bus);
|
||||
|
||||
if(i2c_status == MSG_TIMEOUT) { // Restart I2C at timeout
|
||||
TRACE_ERROR("I2C > TIMEOUT (ADDR 0x%02x)", addr);
|
||||
error = 0x1;
|
||||
} else if(i2c_status == MSG_RESET) {
|
||||
TRACE_ERROR("I2C > RESET (ADDR 0x%02x)", addr);
|
||||
error = 0x0;
|
||||
} else {
|
||||
error = 0x0;
|
||||
}
|
||||
return i2c_status == MSG_OK;
|
||||
}
|
||||
|
||||
bool I2C_write8(I2CDriver *bus, uint8_t address, uint8_t reg, uint8_t value)
|
||||
{
|
||||
uint8_t txbuf[] = {reg, value};
|
||||
return I2C_transmit(bus, address, txbuf, 2, NULL, 0, TIME_MS2I(100));
|
||||
}
|
||||
|
||||
bool I2C_writeN(I2CDriver *bus, uint8_t address, uint8_t *txbuf, uint32_t length)
|
||||
{
|
||||
return I2C_transmit(bus, address, txbuf, length, NULL, 0, TIME_MS2I(100));
|
||||
}
|
||||
|
||||
bool I2C_read8(I2CDriver *bus, uint8_t address, uint8_t reg, uint8_t *val)
|
||||
{
|
||||
uint8_t txbuf[] = {reg};
|
||||
uint8_t rxbuf[1];
|
||||
bool ret = I2C_transmit(bus, address, txbuf, 1, rxbuf, 1, TIME_MS2I(100));
|
||||
*val = rxbuf[0];
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool I2C_read16(I2CDriver *bus, uint8_t address, uint8_t reg, uint16_t *val)
|
||||
{
|
||||
uint8_t txbuf[] = {reg};
|
||||
uint8_t rxbuf[2];
|
||||
bool ret = I2C_transmit(bus, address, txbuf, 1, rxbuf, 2, TIME_MS2I(100));
|
||||
*val = (rxbuf[0] << 8) | rxbuf[1];
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool I2C_read16_LE(I2CDriver *bus, uint8_t address, uint8_t reg, uint16_t *val) {
|
||||
bool ret = I2C_read16(bus, address, reg, val);
|
||||
*val = (*val >> 8) | (*val << 8);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool I2C_read8_16bitreg(I2CDriver *bus, uint8_t address, uint16_t reg, uint8_t *val) // 16bit register (for OV5640)
|
||||
{
|
||||
uint8_t txbuf[] = {reg >> 8, reg & 0xFF};
|
||||
uint8_t rxbuf[1];
|
||||
bool ret = I2C_transmit(bus, address, txbuf, 2, rxbuf, 1, TIME_MS2I(100));
|
||||
*val = rxbuf[0];
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool I2C_write8_16bitreg(I2CDriver *bus, uint8_t address, uint16_t reg, uint8_t value) // 16bit register (for OV5640)
|
||||
{
|
||||
uint8_t txbuf[] = {reg >> 8, reg & 0xFF, value};
|
||||
return I2C_transmit(bus, address, txbuf, 3, NULL, 0, TIME_MS2I(100));
|
||||
}
|
||||
|
||||
uint8_t I2C_hasError(void)
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* I2C wrapper for ChibiOS due to a bug: I2C blocking when I2C transfer suffered timeout
|
||||
* @see https://github.com/psas/stm32/commit/32ec8c97a1e5bf605bd5d41a89fc60b60e136af2
|
||||
*/
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "pi2c.h"
|
||||
|
||||
//#define I2C_DRIVER (&I2CD1)
|
||||
|
||||
static uint8_t error;
|
||||
|
||||
const I2CConfig _i2cfg = {
|
||||
OPMODE_I2C,
|
||||
50000,
|
||||
STD_DUTY_CYCLE,
|
||||
};
|
||||
|
||||
void I2C_Lock(I2CDriver *bus) {
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
i2cAcquireBus(bus);
|
||||
#else
|
||||
(void)bus;
|
||||
#endif
|
||||
}
|
||||
|
||||
void I2C_Unlock(I2CDriver *bus) {
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
i2cReleaseBus(bus);
|
||||
#else
|
||||
(void)bus;
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* @note Error codes from i2cGetErrors()
|
||||
*
|
||||
* 0x01 I2C_BUS_ERROR
|
||||
* 0x02 I2C_ARBITRATION_LOST
|
||||
* 0x04 I2C_ACK_FAILURE
|
||||
* 0x08 I2C_OVERRUN
|
||||
* 0x10 I2C_PEC_ERROR
|
||||
* 0x20 I2C_TIMEOUT
|
||||
* 0x40 I2C_SMB_ALERT
|
||||
*/
|
||||
static bool I2C_transmit(I2CDriver *bus, uint8_t addr, uint8_t *txbuf, uint32_t txbytes, uint8_t *rxbuf, uint32_t rxbytes, sysinterval_t timeout) {
|
||||
i2cAcquireBus(bus);
|
||||
i2cStart(bus, &_i2cfg);
|
||||
msg_t i2c_status = i2cMasterTransmitTimeout(bus, addr, txbuf, txbytes, rxbuf, rxbytes, timeout);
|
||||
i2cStop(bus);
|
||||
i2cReleaseBus(bus);
|
||||
|
||||
if(i2c_status == MSG_TIMEOUT) { // Restart I2C at timeout
|
||||
TRACE_ERROR("I2C > TIMEOUT (ADDR 0x%02x)", addr);
|
||||
error = 0x1;
|
||||
} else if(i2c_status == MSG_RESET) {
|
||||
TRACE_ERROR("I2C > RESET (ADDR 0x%02x) with errors %x", addr,
|
||||
i2cGetErrors(bus));
|
||||
error = 0x1;
|
||||
} else {
|
||||
error = 0x0;
|
||||
}
|
||||
return i2c_status == MSG_OK;
|
||||
}
|
||||
|
||||
bool I2C_write8(I2CDriver *bus, uint8_t address, uint8_t reg, uint8_t value)
|
||||
{
|
||||
uint8_t txbuf[] = {reg, value};
|
||||
return I2C_transmit(bus, address, txbuf, 2, NULL, 0, TIME_MS2I(100));
|
||||
}
|
||||
|
||||
bool I2C_writeN(I2CDriver *bus, uint8_t address, uint8_t *txbuf, uint32_t length)
|
||||
{
|
||||
return I2C_transmit(bus, address, txbuf, length, NULL, 0, TIME_MS2I(100));
|
||||
}
|
||||
|
||||
bool I2C_read8(I2CDriver *bus, uint8_t address, uint8_t reg, uint8_t *val)
|
||||
{
|
||||
uint8_t txbuf[] = {reg};
|
||||
uint8_t rxbuf[1];
|
||||
bool ret = I2C_transmit(bus, address, txbuf, 1, rxbuf, 1, TIME_MS2I(100));
|
||||
*val = rxbuf[0];
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool I2C_read16(I2CDriver *bus, uint8_t address, uint8_t reg, uint16_t *val)
|
||||
{
|
||||
uint8_t txbuf[] = {reg};
|
||||
uint8_t rxbuf[2];
|
||||
bool ret = I2C_transmit(bus, address, txbuf, 1, rxbuf, 2, TIME_MS2I(100));
|
||||
*val = (rxbuf[0] << 8) | rxbuf[1];
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool I2C_read16_LE(I2CDriver *bus, uint8_t address, uint8_t reg, uint16_t *val) {
|
||||
bool ret = I2C_read16(bus, address, reg, val);
|
||||
*val = (*val >> 8) | (*val << 8);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool I2C_read8_16bitreg(I2CDriver *bus, uint8_t address, uint16_t reg, uint8_t *val) // 16bit register (for OV5640)
|
||||
{
|
||||
uint8_t txbuf[] = {reg >> 8, reg & 0xFF};
|
||||
uint8_t rxbuf[1];
|
||||
bool ret = I2C_transmit(bus, address, txbuf, 2, rxbuf, 1, TIME_MS2I(100));
|
||||
*val = rxbuf[0];
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool I2C_write8_16bitreg(I2CDriver *bus, uint8_t address, uint16_t reg, uint8_t value) // 16bit register (for OV5640)
|
||||
{
|
||||
uint8_t txbuf[] = {reg >> 8, reg & 0xFF, value};
|
||||
return I2C_transmit(bus, address, txbuf, 3, NULL, 0, TIME_MS2I(100));
|
||||
}
|
||||
|
||||
uint8_t I2C_hasError(void)
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
@ -630,6 +630,16 @@ uint8_t pktReleasePWMbuffers(AFSKDemodDriver *myDriver) {
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
bool pktIsAFSKReceiveActive(packet_svc_t *handler) {
|
||||
AFSKDemodDriver *myDemod = handler->rx_link_control;
|
||||
chDbgAssert(myDemod != NULL, "no demod driver");
|
||||
return myDemod->icustate == PKT_PWM_ACTIVE
|
||||
|| myDemod->icustate == PKT_PWM_WAITING;
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* AFSK Decoder thread. */
|
||||
/*===========================================================================*/
|
||||
|
|
|
@ -318,6 +318,7 @@ extern "C" {
|
|||
#endif
|
||||
AFSKDemodDriver *pktCreateAFSKDecoder(radio_unit_t radio);
|
||||
void pktReleaseAFSKDecoder(AFSKDemodDriver *myDriver);
|
||||
bool pktIsAFSKReceiveActive(packet_svc_t *handler);
|
||||
void pktAFSKDecoder(void *arg);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -511,11 +511,7 @@ void pktEnableRadioStreamProcessing(const radio_unit_t radio) {
|
|||
switch(myDemod->icustate) {
|
||||
/* The PWM handling is currently stopped. */
|
||||
case PKT_PWM_STOP: {
|
||||
/*
|
||||
* Enable CCA callback from GPIO.
|
||||
* TODO: Enable RSSI interrupt in radio.
|
||||
* - either in the following function or a separate function.
|
||||
*/
|
||||
/* Enable CCA callback from GPIO. */
|
||||
pktLLDradioCCAEnable(radio, mod, (palcallback_t)pktRadioCCAInput);
|
||||
|
||||
/* Start ICU capture. The ICU will sync to the next edge. Notifications
|
||||
|
@ -600,7 +596,6 @@ void pktDisableRadioStreamProcessing(const radio_unit_t radio) {
|
|||
case PKT_PWM_ACTIVE: {
|
||||
/* PWM incoming active. */
|
||||
|
||||
|
||||
/* Disable CCA line event. */
|
||||
pktLLDradioCCADisableI(radio, mod);
|
||||
|
||||
|
@ -621,11 +616,12 @@ void pktDisableRadioStreamProcessing(const radio_unit_t radio) {
|
|||
|
||||
myDemod->icustate = PKT_PWM_STOP;
|
||||
|
||||
/* Reschedule to avoid a "priority order violation". */
|
||||
/* Reschedule to avoid a "priority order violation" Closing stream
|
||||
can be lengthy. */
|
||||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
|
||||
/* Putting radio in standby stops all output from radio. */
|
||||
/* Putting radio in standby stops all output from device. */
|
||||
pktLLDradioStandby(radio);
|
||||
return;
|
||||
} /* End case PKT_PWM_WAITING or PKT_PWM_ACTIVE */
|
||||
|
@ -693,6 +689,55 @@ void pktDisableRadioStreamProcessing(const radio_unit_t radio) {
|
|||
} /* End switch on link type. */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait for PWM receive inactive.
|
||||
* @pre The radio must be locked before calling this function.
|
||||
* @notes Will wait a timeout for any PWM stream currently open.
|
||||
*
|
||||
* @param[in] radio Radio unit ID.
|
||||
* @param[in] timeout the number of ticks before the operation times out.
|
||||
* the following special values are allowed:
|
||||
* - @a TIME_IMMEDIATE immediate timeout.
|
||||
* - @a TIME_INFINITE no timeout.
|
||||
*
|
||||
* @return status of request
|
||||
* @retval MSG_OK stream is not active.
|
||||
* @retval MSG_TIMEOUT stream closed during allowed timeout.
|
||||
* @retval MSG_RESET stream was stopped as it did not cease within t/o.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
msg_t pktWaitPWMStreamClose(radio_unit_t radio, sysinterval_t timeout) {
|
||||
msg_t msg = MSG_OK;
|
||||
if (pktRadioGetInProgress(radio)) {
|
||||
/* If PWM receive is in progress wait. */
|
||||
packet_svc_t *handler = pktGetServiceObject(radio);
|
||||
msg = MSG_RESET;
|
||||
if (timeout != TIME_IMMEDIATE) {
|
||||
event_source_t *esp = pktGetEventSource((packet_svc_t *)handler);
|
||||
/* Register for EVT_RAD_STREAM_CLOSE event which is posted by the PWM
|
||||
ISR front end when a stream is closed. */
|
||||
event_listener_t el;
|
||||
pktRegisterEventListener(esp, &el, GTE_RECEIVE_INACTIVE,
|
||||
EVT_RAD_STREAM_CLOSE);
|
||||
systime_t start = chVTGetSystemTime();
|
||||
if (chEvtWaitAnyTimeout(GTE_RECEIVE_INACTIVE, timeout) == 0) {
|
||||
msg = MSG_RESET;
|
||||
TRACE_DEBUG("RAD > Timed out in %d ms waiting for in progress receive",
|
||||
chTimeI2MS(timeout));
|
||||
} else {
|
||||
/* Capture the elapsed time. */
|
||||
systime_t wait = chVTTimeElapsedSinceX(start);
|
||||
TRACE_DEBUG("RAD > Waited %d ms for in progress receive",
|
||||
chTimeI2MS(wait));
|
||||
msg = MSG_TIMEOUT;
|
||||
}
|
||||
pktUnregisterEventListener(esp, &el);
|
||||
} /* End test on timeout. */
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop all ICU associated timers.
|
||||
* @notes Will be called when a packet stream is closed.
|
||||
|
@ -1329,4 +1374,5 @@ msg_t pktWritePWMQueueI(input_queue_t *queue, byte_packed_pwm_t pack) {
|
|||
}
|
||||
return MSG_OK;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -190,7 +190,6 @@ typedef struct {
|
|||
/* Module macro definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
@ -208,7 +207,7 @@ extern "C" {
|
|||
void pktRadioCCAInput(ICUDriver *myICU);
|
||||
void pktStopAllICUtimersI(ICUDriver *myICU);
|
||||
void pktSleepICUI(ICUDriver *myICU);
|
||||
//void pktPWMInactivityTimeout(ICUDriver *myICU);
|
||||
msg_t pktWaitPWMStreamClose(radio_unit_t radio, sysinterval_t timeout);
|
||||
msg_t pktWritePWMQueueI(input_queue_t *queue, byte_packed_pwm_t pack);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ const radio_band_t band_70cm = {
|
|||
static bool pktLLDradioInit(const radio_unit_t radio) {
|
||||
/* TODO: Implement hardware mapping to different radio types. */
|
||||
|
||||
return Si446x_conditional_init(radio);
|
||||
return Si446x_driverInit(radio);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -132,9 +132,6 @@ static bool pktLLDradioSendPacket(radio_task_object_t *const rto) {
|
|||
static bool pktLLDradioStartReceiver(const radio_unit_t radio) {
|
||||
packet_svc_t *handler = pktGetServiceObject(radio);
|
||||
|
||||
if (handler == NULL)
|
||||
return false;
|
||||
|
||||
if (!Si4464_enableReceive(radio,
|
||||
handler->radio_rx_config.base_frequency,
|
||||
handler->radio_rx_config.step_hz,
|
||||
|
@ -574,16 +571,18 @@ static msg_t pktStartRadioReceive(const radio_unit_t radio,
|
|||
return msg;
|
||||
}
|
||||
|
||||
if (handler->rx_state != PACKET_RX_OPEN) {
|
||||
chDbgAssert(false, "wrong state");
|
||||
pktUnlockRadio(radio);
|
||||
return MSG_ERROR;
|
||||
}
|
||||
|
||||
/* Set ENABLED now so pktSetReceiveStreamActive() sees correct state. */
|
||||
handler->rx_state = PACKET_RX_ENABLED;
|
||||
msg = pktSetReceiveStreamActive(radio);
|
||||
switch (msg) {
|
||||
case MSG_OK:
|
||||
#if PKT_RADIO_LOCK_IN_RECEIVE == TRUE
|
||||
return msg;
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
|
||||
case MSG_IDLE:
|
||||
case MSG_ERROR:
|
||||
|
@ -596,7 +595,7 @@ static msg_t pktStartRadioReceive(const radio_unit_t radio,
|
|||
|
||||
/**
|
||||
* @brief Stop radio receive.
|
||||
* @pre The packet service is open and with receive chain active.
|
||||
* @pre The packet service is open with receive chain active.
|
||||
*
|
||||
* @param[in] radio radio unit ID.
|
||||
* @param[in] lock_to the number of ticks before the radio lock times out
|
||||
|
@ -620,25 +619,21 @@ static msg_t pktStopRadioReceive(const radio_unit_t radio,
|
|||
|
||||
packet_svc_t *handler = pktGetServiceObject(radio);
|
||||
|
||||
#if PKT_RADIO_LOCK_IN_RECEIVE == FALSE
|
||||
/*
|
||||
* Lock radio to hold any transmit requests.
|
||||
*/
|
||||
msg_t msg = pktLockRadio(radio, RADIO_RX, lock_to);
|
||||
if (msg != MSG_OK)
|
||||
return msg;
|
||||
#endif
|
||||
msg = pktSetReceiveStreamInactive(radio, decode_to);
|
||||
/* Set state back to open versus active. */
|
||||
handler->rx_state = PACKET_RX_OPEN;
|
||||
if (msg == MSG_OK) {
|
||||
;
|
||||
msg = pktSetReceiveStreamInactive(radio, decode_to);
|
||||
if (msg == MSG_OK) {
|
||||
/* Set state back to open versus active. */
|
||||
handler->rx_state = PACKET_RX_OPEN;
|
||||
}
|
||||
pktUnlockRadio(radio);
|
||||
}
|
||||
pktUnlockRadio(radio);
|
||||
return MSG_OK;
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set receive data stream capability active.
|
||||
* @pre Radio must be locked prior to calling this function.
|
||||
|
@ -709,23 +704,53 @@ msg_t pktSetReceiveStreamActive(const radio_unit_t radio) {
|
|||
THD_FUNCTION(pktRadioManager, arg) {
|
||||
|
||||
packet_svc_t *handler = arg;
|
||||
chDbgAssert(handler != NULL, "no handler object");
|
||||
const radio_unit_t radio = handler->radio;
|
||||
|
||||
/* Setup for initialisation handshake. */
|
||||
thread_t *initiator = chMsgWait();
|
||||
(void)chMsgGet(initiator);
|
||||
#if PKT_RADIO_MANAGER_INIT
|
||||
/* Create the radio manager name. */
|
||||
chsnprintf(handler->rtask_name, sizeof(handler->rtask_name),
|
||||
"%s%02i", PKT_RADIO_TASK_QUEUE_PREFIX, radio);
|
||||
|
||||
/*
|
||||
* Create the radio task object FIFO.
|
||||
* TODO: Move into thread init.
|
||||
*/
|
||||
dyn_objects_fifo_t *the_radio_fifo =
|
||||
chFactoryCreateObjectsFIFO(handler->rtask_name,
|
||||
sizeof(radio_task_object_t),
|
||||
RADIO_TASK_QUEUE_MAX, sizeof(msg_t));
|
||||
|
||||
chDbgAssert(the_radio_fifo != NULL, "unable to create radio task queue");
|
||||
|
||||
if (the_radio_fifo == NULL) {
|
||||
/* Failed to create FIFO. */
|
||||
chMsgRelease(initiator, MSG_ERROR);
|
||||
chThdExit(MSG_OK);
|
||||
}
|
||||
handler->the_radio_fifo = the_radio_fifo;
|
||||
#else
|
||||
dyn_objects_fifo_t *the_radio_fifo = handler->the_radio_fifo;
|
||||
|
||||
chDbgCheck(arg != NULL);
|
||||
|
||||
#endif
|
||||
objects_fifo_t *radio_queue = chFactoryGetObjectsFIFO(the_radio_fifo);
|
||||
|
||||
chDbgAssert(radio_queue != NULL, "no queue in radio manager FIFO");
|
||||
|
||||
const radio_unit_t radio = handler->radio;
|
||||
|
||||
thread_t *initiator = chMsgWait();
|
||||
/* TODO: Initiator should send radio ID in message then we check it. */
|
||||
(void)chMsgGet(initiator);
|
||||
/* Create an incoming AX25 packet buffer pool for this radio. */
|
||||
handler->packet_heap = pktIncomingBufferPoolCreate(radio);
|
||||
if (handler->packet_heap == NULL) {
|
||||
/* TODO: Release RTO FIFO. */
|
||||
#if PKT_RADIO_MANAGER_INIT
|
||||
chFactoryReleaseObjectsFIFO(the_radio_fifo);
|
||||
|
||||
/* Forget the references. */
|
||||
handler->radio_manager = NULL;
|
||||
#endif
|
||||
/* Failed to initialise/get buffer pool. */
|
||||
chMsgRelease(initiator, MSG_ERROR);
|
||||
chThdExit(MSG_OK);
|
||||
|
@ -736,6 +761,13 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
/* Take radio out of shutdown and initialize base registers. */
|
||||
if (pktLLDradioInit(radio)) {
|
||||
/* Failed to initialise radio. */
|
||||
#if PKT_RADIO_MANAGER_INIT
|
||||
/* Release the FIFO. */
|
||||
chFactoryReleaseObjectsFIFO(the_radio_fifo);
|
||||
|
||||
/* Forget the references. */
|
||||
handler->radio_manager = NULL;
|
||||
#endif
|
||||
pktIncomingBufferPoolRelease(handler);
|
||||
chMsgRelease(initiator, MSG_ERROR);
|
||||
chThdExit(MSG_OK);
|
||||
|
@ -764,13 +796,15 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
|
||||
case PKT_RADIO_TCXO_UPDATE: {
|
||||
|
||||
#if 0 /* The TCXO service checks for out of bounds measurements. */
|
||||
if (!pktPPMcheckTCXO(handler->xtal)) {
|
||||
TRACE_ERROR("RAD > TCXO update for radio %d is out of PPM bounds",
|
||||
radio);
|
||||
task_object->result = MSG_ERROR;
|
||||
break;
|
||||
}
|
||||
/* The TCXO manager has measure an updated TCXO frequency and
|
||||
#endif
|
||||
/* The TCXO manager has measured an updated TCXO frequency and
|
||||
posted a command to notify the RM. */
|
||||
msg_t msg = pktLockRadio(radio, RADIO_RX, TIME_MS2I(10));
|
||||
if (msg == MSG_TIMEOUT) {
|
||||
|
@ -786,7 +820,7 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
/* Radio lock semaphore has been reset. Can't execute update. */
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0 /* TODO: Implement PLL update in radio driver for current RX session. */
|
||||
/*
|
||||
* Set stream inactive.
|
||||
* RX state is left as enabled.
|
||||
|
@ -805,10 +839,11 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
* Apply the TCXO update.
|
||||
* Reactivate stream if it was stopped.
|
||||
*/
|
||||
#endif
|
||||
TRACE_DEBUG("RAD > Sending new TCXO %d Hz to radio %d",
|
||||
handler->xtal, radio);
|
||||
(void)pktLLDradioOscUpdate(radio, handler->xtal);
|
||||
|
||||
bool update = pktLLDradioOscUpdate(radio, handler->xtal);
|
||||
#if 0
|
||||
/* Radio receive not enabled if MSG_IDLE, resumed if MSG_OK. */
|
||||
msg = pktSetReceiveStreamActive(radio);
|
||||
/* Resume of receive failed. */
|
||||
|
@ -817,9 +852,11 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
TRACE_ERROR("RAD > Error when reactivating receive "
|
||||
"after TCXO update on radio %d", radio);
|
||||
}
|
||||
|
||||
#endif
|
||||
task_object->result = msg;
|
||||
pktUnlockRadio(radio);
|
||||
TRACE_DEBUG("RAD > Radio %d %s TCXO update", radio,
|
||||
update ? "accepted" : "ignored");
|
||||
break;
|
||||
} /* End case PKT_RADIO_TCXO_UPDATE */
|
||||
|
||||
|
@ -919,10 +956,11 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
|
||||
/*
|
||||
* Service now has receive open state.
|
||||
* Next start receive.
|
||||
* Radio is unlocked.
|
||||
* Next start receive as next queued task.
|
||||
*/
|
||||
task_object->command = PKT_RADIO_RX_START;
|
||||
pktSubmitRadioTask(radio, task_object, NULL);
|
||||
pktSubmitPriorityRadioTask(radio, task_object, NULL);
|
||||
continue;
|
||||
} /* End case PKT_RADIO_RX_OPEN. */
|
||||
|
||||
|
@ -941,7 +979,8 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
|
||||
/*
|
||||
* Time out waiting to lock radio.
|
||||
* Repost task, let the FIFO be processed and check again.
|
||||
* Repost task as normal priority.
|
||||
* Let the FIFO be processed and check again.
|
||||
*/
|
||||
pktSubmitRadioTask(radio, task_object, NULL);
|
||||
continue;
|
||||
|
@ -1089,11 +1128,6 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
*
|
||||
*/
|
||||
case PKT_RADIO_TX_DONE: {
|
||||
/* TX thread has completed. */
|
||||
if (--handler->txrto_ref_count > 0)
|
||||
/* More TX tasks outstanding. Just process call backs and release RTO. */
|
||||
break;
|
||||
/* No transmissions pending. Resume RX if enabled. */
|
||||
msg_t msg = pktLockRadio(radio, RADIO_RX, TIME_MS2I(10));
|
||||
if (msg == MSG_TIMEOUT) {
|
||||
/*
|
||||
|
@ -1101,16 +1135,22 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
* Repost task, let the FIFO be processed and check again.
|
||||
*/
|
||||
pktSubmitRadioTask(radio, task_object, NULL);
|
||||
/* Restore count for next loop. */
|
||||
++handler->txrto_ref_count;
|
||||
continue;
|
||||
}
|
||||
if (msg == MSG_RESET) {
|
||||
/* Radio semaphore has been reset by another thread. */
|
||||
/* Mark TX thread has completed. */
|
||||
--handler->txrto_ref_count;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Resume receive if enabled. */
|
||||
/* Radio is locked. Decrease TX ref count. */
|
||||
if (--handler->txrto_ref_count > 0) {
|
||||
/* More TX tasks outstanding. Unlock radio. Process call backs
|
||||
and release RTO. */
|
||||
pktUnlockRadio(radio);
|
||||
break;
|
||||
}
|
||||
/* No transmissions pending. Resume RX if enabled. */
|
||||
msg = pktSetReceiveStreamActive(radio);
|
||||
switch (msg) {
|
||||
case MSG_ERROR: /* Parameter error. */
|
||||
|
@ -1119,7 +1159,7 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
case MSG_OK: /* Receive now active. */
|
||||
case MSG_IDLE: /* Receive not enabled. */
|
||||
break;
|
||||
}
|
||||
} /* End switch. */
|
||||
|
||||
/* Release radio. */
|
||||
pktUnlockRadio(radio);
|
||||
|
@ -1190,7 +1230,7 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
thread_t *pktRadioManagerCreate(const radio_unit_t radio) {
|
||||
|
||||
packet_svc_t *handler = pktGetServiceObject(radio);
|
||||
|
||||
#if PKT_RADIO_MANAGER_INIT != TRUE
|
||||
/* Create the radio manager name. */
|
||||
chsnprintf(handler->rtask_name, sizeof(handler->rtask_name),
|
||||
"%s%02i", PKT_RADIO_TASK_QUEUE_PREFIX, radio);
|
||||
|
@ -1210,10 +1250,7 @@ thread_t *pktRadioManagerCreate(const radio_unit_t radio) {
|
|||
return NULL;
|
||||
|
||||
handler->the_radio_fifo = the_radio_fifo;
|
||||
|
||||
TRACE_INFO("PKT > radio manager thread created. FIFO @ 0x%x",
|
||||
the_radio_fifo);
|
||||
|
||||
#endif
|
||||
/* Start the radio manager thread. */
|
||||
handler->radio_manager = chThdCreateFromHeap(NULL,
|
||||
THD_WORKING_AREA_SIZE(PKT_RADIO_MANAGER_WA_SIZE),
|
||||
|
@ -1225,25 +1262,27 @@ thread_t *pktRadioManagerCreate(const radio_unit_t radio) {
|
|||
chDbgAssert(handler->radio_manager != NULL,
|
||||
"unable to create radio task thread");
|
||||
|
||||
if (handler->radio_manager == NULL) {
|
||||
if (handler->radio_manager == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TRACE_INFO("PKT > radio manager thread created for radio %d", radio);
|
||||
|
||||
msg_t init = chMsgSend(handler->radio_manager, MSG_OK);
|
||||
if (init == MSG_OK)
|
||||
return handler->radio_manager;
|
||||
|
||||
/* Radio init failed so clean up. */
|
||||
chThdTerminate(handler->radio_manager);
|
||||
//chThdTerminate(handler->radio_manager);
|
||||
|
||||
/* Wait for the radio manager thread to terminate. */
|
||||
chThdWait(handler->radio_manager);
|
||||
|
||||
#if PKT_RADIO_MANAGER_INIT != TRUE
|
||||
/*
|
||||
* Release the RM FIFO.
|
||||
* TODO: Moves when FIFO creation is in thread init.
|
||||
*/
|
||||
chFactoryReleaseObjectsFIFO(the_radio_fifo);
|
||||
|
||||
#endif
|
||||
/* Forget the references. */
|
||||
handler->radio_manager = NULL;
|
||||
return NULL;
|
||||
|
@ -1369,7 +1408,6 @@ void pktSubmitPriorityRadioTaskI(const radio_unit_t radio,
|
|||
|
||||
/**
|
||||
* @brief Get a radio command task object.
|
||||
* @post A task object is returned ready for filling and submission.
|
||||
* @note The radio manager will lock all objects when closing.
|
||||
*
|
||||
* @param[in] radio radio unit ID.
|
||||
|
@ -1894,6 +1932,9 @@ msg_t pktSetReceiveStreamInactive(const radio_unit_t radio,
|
|||
*/
|
||||
switch(handler->rx_link_type) {
|
||||
case MOD_AFSK: {
|
||||
#if 1
|
||||
msg = pktWaitPWMStreamClose(radio, timeout);
|
||||
#else
|
||||
if (pktRadioGetInProgress(radio)) {
|
||||
/* If PWM receive is in progress wait. */
|
||||
msg = MSG_RESET;
|
||||
|
@ -1918,14 +1959,15 @@ msg_t pktSetReceiveStreamInactive(const radio_unit_t radio,
|
|||
pktUnregisterEventListener(esp, &el);
|
||||
} /* End test on timeout. */
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* The radio must be locked prior to disabling the stream.
|
||||
* Actions:
|
||||
* 1. Stop transport layer stream data.
|
||||
* 2. Write an in-stream stop message to an open stream.
|
||||
* 3. The physical radio is put into standby state.
|
||||
* 3. The radio device is put into standby state.
|
||||
*
|
||||
* The decoder can/will process any currently buffered PWM data.
|
||||
* The AFSK decoder can/will process any currently buffered PWM data.
|
||||
* - If the frame is incomplete the decoder will see an in-stream stop message.
|
||||
* - In such case the packet is dropped and the decoder resets.
|
||||
* - Where an in-stream stop message is after the HDLC frame close it is never seen.
|
||||
|
@ -2033,7 +2075,8 @@ void pktRadioSendComplete(radio_task_object_t *const rto) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Check if a packet is being received by the radio.
|
||||
* Check if a packet is in process of being received by the radio.
|
||||
* True if yes, false if no.
|
||||
*
|
||||
*/
|
||||
bool pktRadioGetInProgress(const radio_unit_t radio) {
|
||||
|
@ -2054,12 +2097,16 @@ bool pktRadioGetInProgress(const radio_unit_t radio) {
|
|||
return false;
|
||||
|
||||
case MOD_AFSK: {
|
||||
/* TODO: Put a macro in rxpwm.c */
|
||||
#if 1
|
||||
return pktIsAFSKReceiveActive(handler);
|
||||
#else
|
||||
/* TODO: Put a macro in rxpwm.h */
|
||||
AFSKDemodDriver *myDemod = handler->rx_link_control;
|
||||
chDbgAssert(myDemod != NULL, "no demod driver");
|
||||
|
||||
return myDemod->icustate == PKT_PWM_ACTIVE
|
||||
|| myDemod->icustate == PKT_PWM_WAITING;
|
||||
#endif
|
||||
}
|
||||
|
||||
case MOD_CW:
|
||||
|
|
|
@ -17,6 +17,12 @@
|
|||
#ifndef PKTRADIO_H
|
||||
#define PKTRADIO_H
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#define PKT_RADIO_MANAGER_INIT TRUE
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
@ -30,12 +36,6 @@
|
|||
#define RADIO_TASK_QUEUE_MAX 10
|
||||
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#define PKT_RADIO_LOCK_IN_RECEIVE FALSE
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
|
|
@ -220,6 +220,7 @@ bool pktServiceCreate(const radio_unit_t radio) {
|
|||
*/
|
||||
chEvtObjectInit(pktGetEventSource(handler));
|
||||
|
||||
/* Reset the radio parameters. */
|
||||
memset(&handler->radio_rx_config, 0, sizeof(radio_task_object_t));
|
||||
memset(&handler->radio_tx_config, 0, sizeof(radio_task_object_t));
|
||||
|
||||
|
@ -407,7 +408,7 @@ msg_t pktOpenReceiveService(const radio_unit_t radio,
|
|||
*/
|
||||
case PACKET_RX_ENABLED:
|
||||
case PACKET_RX_CLOSE:
|
||||
case PACKET_RX_INVALID:
|
||||
case PACKET_RX_ERROR:
|
||||
|
||||
break;
|
||||
} /* End switch. */
|
||||
|
|
|
@ -47,7 +47,7 @@ typedef enum handlerRxStates {
|
|||
PACKET_RX_OPEN,
|
||||
PACKET_RX_ENABLED,
|
||||
PACKET_RX_CLOSE,
|
||||
PACKET_RX_INVALID
|
||||
PACKET_RX_ERROR
|
||||
} pkt_rx_state_t;
|
||||
|
||||
#include "types.h"
|
||||
|
|
|
@ -1,319 +1,322 @@
|
|||
/*
|
||||
Aerospace Decoder - Copyright (C) 2018 Bob Anderson (VK2GJ)
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "pktconf.h"
|
||||
|
||||
/**
|
||||
* @brief Initialize an NRZI stream iterator.
|
||||
* @post The iterator is ready for use.
|
||||
*
|
||||
* @param[in] iterator pointer to an @p iterator object.
|
||||
* @param[in] pp packet object reference pointer.
|
||||
* @param[in] pre length of HDLC (flags) preamble
|
||||
* @param[in] post length of HDLC (flags) closing
|
||||
* @param[in] tail length of HDLC (0 data) tail flags
|
||||
* @param[in] scramble determines if scrambling (whitening) is applied.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void pktStreamIteratorInit(tx_iterator_t *iterator,
|
||||
packet_t pp,
|
||||
uint8_t pre,
|
||||
uint8_t post,
|
||||
uint8_t tail,
|
||||
bool scramble) {
|
||||
memset(iterator, 0, sizeof(tx_iterator_t));
|
||||
iterator->hdlc_code = HDLC_FLAG;
|
||||
iterator->hdlc_count = pre;
|
||||
iterator->hdlc_post = post;
|
||||
iterator->hdlc_tail = tail;
|
||||
iterator->scramble = scramble;
|
||||
iterator->data_buff = pp->frame_data;
|
||||
iterator->data_size = pp->frame_len;
|
||||
uint16_t crc = calc_crc16(pp->frame_data, 0, pp->frame_len);
|
||||
iterator->crc[0] = crc & 0xFF;
|
||||
iterator->crc[1] = crc >> 8;
|
||||
iterator->no_write = false;
|
||||
iterator->state = ITERATE_PREAMBLE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write NRZI stream data to buffer.
|
||||
* @post NRZI encoded bits are written to the stream.
|
||||
* @notes If counting only is active data is not written but simply counted.
|
||||
*
|
||||
* @param[in] iterator pointer to an @p iterator object.
|
||||
* @param[in] bit the bit to be written.
|
||||
*
|
||||
* @return status.
|
||||
* @retval true indicates the requested quantity of bytes has been reached.
|
||||
* @retval false indicates the requested quantity of bytes not reached.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static bool pktIteratorWriteStreamBit(tx_iterator_t *iterator, uint8_t bit) {
|
||||
/* If new output buffer byte clear it first if write is enabled. */
|
||||
if((iterator->out_index % 8 == 0) && (iterator->no_write == false))
|
||||
iterator->out_buff[iterator->out_index >> 3] = 0;
|
||||
|
||||
/* Mask to bit 0 only. */
|
||||
bit &= 1;
|
||||
|
||||
/* Keep track of HDLC for RLL detection. */
|
||||
iterator->hdlc_hist <<= 1;
|
||||
iterator->hdlc_hist |= bit;
|
||||
|
||||
if(iterator->scramble) {
|
||||
iterator->lfsr <<= 1;
|
||||
/* Scramble is ^16 and ^11 but we shifted up one. */
|
||||
iterator->lfsr |= (bit ^ (iterator->lfsr >> 17)
|
||||
^ (iterator->lfsr >> 12)) & 0x1;
|
||||
bit = iterator->lfsr & 0x1;
|
||||
}
|
||||
|
||||
/* NRZI encode bit. */
|
||||
iterator->nrzi_hist ^= (bit == 0) ? 0x1 : 0x0;
|
||||
|
||||
/* Write NRZI bit to current byte. */
|
||||
if(iterator->no_write == false)
|
||||
iterator->out_buff[iterator->out_index >> 3] |=
|
||||
(iterator->nrzi_hist & 0x1) << (iterator->out_index % 8);
|
||||
|
||||
/* If byte was filled then check quantity status. */
|
||||
if((++iterator->out_index % 8) == 0) {
|
||||
if((++iterator->out_count) == iterator->qty)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encode frame HDLC byte.
|
||||
* @pre Iterator object initialized and buffer pointer set.
|
||||
* @post HDLC octet is written to the stream unless counting only is active.
|
||||
*
|
||||
* @param[in] iterator pointer to an @p iterator object.
|
||||
*
|
||||
* @return status.
|
||||
* @retval true indicates the requested quantity of bytes has been reached.
|
||||
* @retval false indicates the requested quantity of bytes not reached.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static bool pktEncodeFrameHDLC(tx_iterator_t *iterator) {
|
||||
do {
|
||||
uint8_t bit = (iterator->hdlc_code >> (iterator->inp_index++ % 8)) & 0x1;
|
||||
if((iterator->inp_index % 8) == 0)
|
||||
iterator->hdlc_count--;
|
||||
if(pktIteratorWriteStreamBit(iterator, bit))
|
||||
return true;
|
||||
} while((iterator->inp_index % 8) != 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encode frame data byte.
|
||||
* @pre Iterator object initialized and buffer pointer set.
|
||||
* @post Data is written to the stream unless counting only is active.
|
||||
* @notes Data size may expand due to RLL encoding.
|
||||
* @notes The required quantity may be reached on a RLL inserted bit.
|
||||
*
|
||||
* @param[in] iterator pointer to an @p iterator object.
|
||||
*
|
||||
* @return status.
|
||||
* @retval true indicates the requested quantity of bytes has been reached.
|
||||
* @retval false indicates the requested quantity of bytes not reached.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static bool pktEncodeFrameData(tx_iterator_t *iterator) {
|
||||
do {
|
||||
/* Next apply RLL encoding for the packet data pay load. */
|
||||
if((iterator->hdlc_hist & HDLC_RLL_SEQUENCE) == HDLC_RLL_SEQUENCE) {
|
||||
iterator->rll_count++;
|
||||
/* Insert RLL 0 to output stream. */
|
||||
if(pktIteratorWriteStreamBit(iterator, 0))
|
||||
return true;
|
||||
}
|
||||
/* Get data bit and advance index. */
|
||||
uint8_t byte = iterator->data_buff[iterator->inp_index >> 3];
|
||||
uint8_t bit = (byte >> (iterator->inp_index++ % 8)) & 0x1;
|
||||
if((iterator->inp_index % 8) == 0)
|
||||
iterator->data_size--;
|
||||
/* Write data bit to stream. */
|
||||
if(pktIteratorWriteStreamBit(iterator, bit))
|
||||
return true;
|
||||
} while((iterator->inp_index % 8) != 0);
|
||||
/* End of input byte. */
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encode frame stream for transmission.
|
||||
* @pre The iterator has to be initialized before use.
|
||||
* @post When the stream is complete the iterator may be re-used.
|
||||
* @notes The iterator allows a frame to be encoded in chunks.
|
||||
* @notes The calling function may request chunk sizes from 1 byte up.
|
||||
* @notes A quantity of 0 will return the number of bytes pending only.
|
||||
* @notes In this case no data is actually written to the stream.
|
||||
*
|
||||
* @param[in] iterator pointer to an @p iterator object.
|
||||
* @param[in] stream pointer to buffer to write stream data.
|
||||
* @param[in] qty the requested quantity of stream bytes.
|
||||
* requesting 0 will return the stream bytes remaining.
|
||||
*
|
||||
* @return number of bytes encoded or remaining to be encoded.
|
||||
* @retval zero indicates the iterator is not initialized or is finished.
|
||||
* @retval requested size is returned while encoding continues.
|
||||
* @retval less than requested size is returned when encoding is ending.
|
||||
* Or...
|
||||
* @retval number of bytes remaining to be encoded for quantity zero request.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
uint16_t pktStreamEncodingIterator(tx_iterator_t *iterator,
|
||||
uint8_t *stream, uint16_t qty) {
|
||||
|
||||
if(qty == 0) {
|
||||
tx_iterator_t saved;
|
||||
|
||||
/* Save state. */
|
||||
saved = *iterator;
|
||||
iterator->no_write = true;
|
||||
|
||||
/* Count the number of bytes remaining to output to the stream. */
|
||||
uint16_t remain = pktStreamEncodingIterator(iterator, NULL,
|
||||
ITERATOR_MAX_QTY);
|
||||
|
||||
/* Restore state. */
|
||||
*iterator = saved;
|
||||
return remain;
|
||||
}
|
||||
|
||||
/*
|
||||
* Each call specifies a quantity and stream buffer.
|
||||
* The stream data is written from index 0 of the buffer.
|
||||
*/
|
||||
iterator->out_count = 0;
|
||||
iterator->qty = qty;
|
||||
iterator->out_index = 0;
|
||||
|
||||
chDbgAssert((stream != NULL) || (iterator->no_write == true),
|
||||
"no stream buffer allocated");
|
||||
|
||||
iterator->out_buff = stream;
|
||||
|
||||
while(true) {
|
||||
switch(iterator->state) {
|
||||
case ITERATE_INIT:
|
||||
return 0;
|
||||
|
||||
case ITERATE_END:
|
||||
return 0;
|
||||
|
||||
case ITERATE_PREAMBLE: {
|
||||
/*
|
||||
* Output preamble bytes of specified quantity in requested chunk size.
|
||||
* RLL encoding is not used as these are HDLC flags.
|
||||
*/
|
||||
while(iterator->hdlc_count > 0) {
|
||||
if(pktEncodeFrameHDLC(iterator))
|
||||
/* True means the requested count has been reached. */
|
||||
return iterator->qty;
|
||||
} /* End while. */
|
||||
iterator->inp_index = 0;
|
||||
iterator->state = ITERATE_FRAME;
|
||||
continue;
|
||||
} /* End case ITERATE_PREAMBLE. */
|
||||
|
||||
case ITERATE_FRAME: {
|
||||
/*
|
||||
* Output frame data bytes in requested chunk size.
|
||||
*/
|
||||
while(iterator->data_size > 0) {
|
||||
/* Consume bytes until count reached. */
|
||||
if(pktEncodeFrameData(iterator))
|
||||
/* True means the requested count has been reached. */
|
||||
return iterator->qty;
|
||||
}
|
||||
/* All frame data input consumed. Switch to CRC fields. */
|
||||
iterator->state = ITERATE_CRC;
|
||||
iterator->data_buff = iterator->crc;
|
||||
iterator->data_size = sizeof(iterator->crc);
|
||||
iterator->inp_index = 0;
|
||||
continue;
|
||||
} /* End case ITERATE_FRAME. */
|
||||
|
||||
case ITERATE_CRC: {
|
||||
/*
|
||||
* Output frame CRC bytes in requested chunk size.
|
||||
*/
|
||||
while(iterator->data_size > 0) {
|
||||
/* Consume bytes until count reached. */
|
||||
if(pktEncodeFrameData(iterator))
|
||||
/* True means the requested count has been reached. */
|
||||
return iterator->qty;
|
||||
}
|
||||
/* Frame CRC consumed. */
|
||||
iterator->state = ITERATE_CLOSE;
|
||||
iterator->hdlc_count = iterator->hdlc_post;
|
||||
iterator->hdlc_code = HDLC_FLAG;
|
||||
iterator->inp_index = 0;
|
||||
continue;
|
||||
} /* End case ITERATE_CRC. */
|
||||
|
||||
case ITERATE_CLOSE: {
|
||||
/*
|
||||
* Output closing flags.
|
||||
* RLL encoding is not used as these are HDLC flags.
|
||||
*/
|
||||
while(iterator->hdlc_count > 0) {
|
||||
if(pktEncodeFrameHDLC(iterator))
|
||||
/* True means the requested count has been reached. */
|
||||
return iterator->qty;
|
||||
} /* End while. */
|
||||
iterator->state = ITERATE_TAIL;
|
||||
/* Tail length. */
|
||||
iterator->hdlc_count = iterator->hdlc_tail;
|
||||
iterator->hdlc_code = HDLC_ZERO;
|
||||
iterator->inp_index = 0;
|
||||
continue;
|
||||
} /* End case ITERATE_CLOSE. */
|
||||
|
||||
case ITERATE_TAIL: {
|
||||
/*
|
||||
* Output tail.
|
||||
* RLL encoding is not used as these are idle flags.
|
||||
* This keeps the data tail clean for the receiver.
|
||||
*/
|
||||
while(iterator->hdlc_count > 0) {
|
||||
if(pktEncodeFrameHDLC(iterator))
|
||||
/* True means the requested count has been reached. */
|
||||
return iterator->qty;
|
||||
} /* End while. */
|
||||
/* Account for RLL inserted bits. */
|
||||
iterator->hdlc_count = ((iterator->rll_count + 7) / 8);
|
||||
iterator->state = ITERATE_FINAL;
|
||||
continue;
|
||||
} /* End case ITERATE_TAIL. */
|
||||
|
||||
case ITERATE_FINAL: {
|
||||
if(iterator->hdlc_count <= iterator->qty) {
|
||||
iterator->state = ITERATE_END;
|
||||
return (iterator->out_count + iterator->hdlc_count);
|
||||
} else {
|
||||
iterator->hdlc_count -= iterator->qty;
|
||||
return iterator->qty;
|
||||
}
|
||||
} /* End case ITERATE_FINAL. */
|
||||
} /* End switch on state. */
|
||||
} /* End while. */
|
||||
} /* End function. */
|
||||
|
||||
/** @} */
|
||||
/*
|
||||
Aerospace Decoder - Copyright (C) 2018 Bob Anderson (VK2GJ)
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "pktconf.h"
|
||||
|
||||
/**
|
||||
* @brief Initialize an NRZI stream iterator.
|
||||
* @post The iterator is ready for use.
|
||||
*
|
||||
* @param[in] iterator pointer to an @p iterator object.
|
||||
* @param[in] packet packet buffer reference pointer.
|
||||
* @param[in] len packet length.
|
||||
* @param[in] pre length of HDLC (flags) preamble
|
||||
* @param[in] post length of HDLC (flags) closing
|
||||
* @param[in] tail length of HDLC (0 data) tail flags
|
||||
* @param[in] scramble determines if scrambling (whitening) is applied.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void pktStreamIteratorInit(tx_iterator_t *iterator,
|
||||
ax25char_t* pkt,
|
||||
size_t len,
|
||||
uint8_t pre,
|
||||
uint8_t post,
|
||||
uint8_t tail,
|
||||
bool scramble) {
|
||||
memset(iterator, 0, sizeof(tx_iterator_t));
|
||||
iterator->hdlc_code = HDLC_FLAG;
|
||||
iterator->hdlc_count = pre;
|
||||
iterator->hdlc_post = post;
|
||||
iterator->hdlc_tail = tail;
|
||||
iterator->scramble = scramble;
|
||||
iterator->data_buff = pkt;
|
||||
iterator->data_size = len;
|
||||
uint16_t crc = calc_crc16(pkt, 0, len);
|
||||
iterator->crc[0] = crc & 0xFF;
|
||||
iterator->crc[1] = crc >> 8;
|
||||
iterator->no_write = false;
|
||||
iterator->state = ITERATE_PREAMBLE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write NRZI stream data to buffer.
|
||||
* @post NRZI encoded bits are written to the stream.
|
||||
* @notes If counting only is active data is not written but simply counted.
|
||||
*
|
||||
* @param[in] iterator pointer to an @p iterator object.
|
||||
* @param[in] bit the bit to be written.
|
||||
*
|
||||
* @return status.
|
||||
* @retval true indicates the requested quantity of output bytes was reached.
|
||||
* @retval false indicates the requested quantity of output bytes not yet reached.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static bool pktIteratorWriteStreamBit(tx_iterator_t *iterator, uint8_t bit) {
|
||||
/* If new output buffer byte clear it first if write is enabled. */
|
||||
if ((iterator->out_index % 8 == 0) && (iterator->no_write == false))
|
||||
iterator->out_buff[iterator->out_index >> 3] = 0;
|
||||
|
||||
/* Mask to bit 0 only. */
|
||||
bit &= 1;
|
||||
|
||||
/* Keep track of HDLC for RLL detection. */
|
||||
iterator->hdlc_hist <<= 1;
|
||||
iterator->hdlc_hist |= bit;
|
||||
|
||||
if (iterator->scramble) {
|
||||
iterator->lfsr <<= 1;
|
||||
/* Scramble is ^16 and ^11 but we shifted up one. */
|
||||
iterator->lfsr |= (bit ^ (iterator->lfsr >> 17)
|
||||
^ (iterator->lfsr >> 12)) & 0x1;
|
||||
bit = iterator->lfsr & 0x1;
|
||||
}
|
||||
|
||||
/* NRZI encode bit. */
|
||||
iterator->nrzi_hist ^= (bit == 0) ? 0x1 : 0x0;
|
||||
|
||||
/* Write NRZI bit to current byte. */
|
||||
if (iterator->no_write == false)
|
||||
iterator->out_buff[iterator->out_index >> 3] |=
|
||||
(iterator->nrzi_hist & 0x1) << (iterator->out_index % 8);
|
||||
|
||||
/* If byte was filled then check quantity status. */
|
||||
if ((++iterator->out_index % 8) == 0) {
|
||||
if ((++iterator->out_count) == iterator->qty)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encode frame HDLC byte.
|
||||
* @pre Iterator object initialized and buffer pointer set.
|
||||
* @post HDLC octet is written to the stream unless counting only is active.
|
||||
*
|
||||
* @param[in] iterator pointer to an @p iterator object.
|
||||
*
|
||||
* @return status.
|
||||
* @retval true indicates the requested quantity of bytes has been reached.
|
||||
* @retval false indicates the requested quantity of bytes not reached.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static bool pktEncodeFrameHDLC(tx_iterator_t *iterator) {
|
||||
do {
|
||||
uint8_t bit = (iterator->hdlc_code >> (iterator->inp_index++ % 8)) & 0x1;
|
||||
if ((iterator->inp_index % 8) == 0)
|
||||
iterator->hdlc_count--;
|
||||
if (pktIteratorWriteStreamBit(iterator, bit))
|
||||
return true;
|
||||
} while ((iterator->inp_index % 8) != 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encode frame data byte.
|
||||
* @pre Iterator object initialized and buffer pointer set.
|
||||
* @post Data out is written to the stream unless counting only is active.
|
||||
* @notes Data out size may expand due to RLL encoding.
|
||||
* @notes The required output quantity may be reached on an RLL inserted bit.
|
||||
*
|
||||
* @param[in] iterator pointer to an @p iterator object.
|
||||
*
|
||||
* @return status.
|
||||
* @retval true indicates the requested quantity of bytes has been reached.
|
||||
* @retval false indicates the requested quantity of bytes not reached.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static bool pktEncodeFrameData(tx_iterator_t *iterator) {
|
||||
do {
|
||||
/* Next apply RLL encoding for the packet data pay load. */
|
||||
if ((iterator->hdlc_hist & HDLC_RLL_SEQUENCE) == HDLC_RLL_SEQUENCE) {
|
||||
iterator->rll_count++;
|
||||
/* Insert RLL 0 to output stream. */
|
||||
if (pktIteratorWriteStreamBit(iterator, 0))
|
||||
return true;
|
||||
}
|
||||
/* Get data bit and advance index. */
|
||||
uint8_t byte = iterator->data_buff[iterator->inp_index >> 3];
|
||||
uint8_t bit = (byte >> (iterator->inp_index++ % 8)) & 0x1;
|
||||
if ((iterator->inp_index % 8) == 0)
|
||||
iterator->data_size--;
|
||||
/* Write data bit to stream. */
|
||||
if (pktIteratorWriteStreamBit(iterator, bit))
|
||||
return true;
|
||||
} while ((iterator->inp_index % 8) != 0);
|
||||
/* End of input byte. */
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encode frame stream for transmission.
|
||||
* @pre The iterator has to be initialized before use.
|
||||
* @post When the stream is complete the iterator may be re-used.
|
||||
* @notes The iterator allows a frame to be encoded in chunks.
|
||||
* @notes The calling function may request output chunk sizes from 1 byte up.
|
||||
* @notes A quantity of 0 will return the number of bytes pending only.
|
||||
* @notes In this case no data is actually written to the stream.
|
||||
*
|
||||
* @param[in] iterator pointer to an @p iterator object.
|
||||
* @param[in] stream pointer to buffer to write stream data.
|
||||
* @param[in] qty the requested quantity of stream out bytes.
|
||||
* requesting 0 will return the stream
|
||||
* output pending size.
|
||||
*
|
||||
* @return number of bytes encoded or remaining to be encoded.
|
||||
* @retval zero indicates the iterator is not initialized or is finished.
|
||||
* @retval requested size is returned while encoding continues.
|
||||
* @retval less than requested size is returned when encoding is ending.
|
||||
* Or...
|
||||
* @retval number of bytes remaining to be encoded for quantity zero request.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
uint16_t pktStreamEncodingIterator(tx_iterator_t *iterator,
|
||||
uint8_t *stream, uint16_t qty) {
|
||||
|
||||
if (qty == 0) {
|
||||
tx_iterator_t saved;
|
||||
|
||||
/* Save state. */
|
||||
saved = *iterator;
|
||||
iterator->no_write = true;
|
||||
|
||||
/* Count the number of bytes remaining to output to the stream. */
|
||||
uint16_t remain = pktStreamEncodingIterator(iterator, NULL,
|
||||
ITERATOR_MAX_QTY);
|
||||
|
||||
/* Restore state. */
|
||||
*iterator = saved;
|
||||
return remain;
|
||||
}
|
||||
|
||||
/*
|
||||
* Each call specifies a quantity and stream buffer.
|
||||
* The stream data is written from index 0 of the buffer.
|
||||
*/
|
||||
iterator->out_count = 0;
|
||||
iterator->qty = qty;
|
||||
iterator->out_index = 0;
|
||||
|
||||
chDbgAssert((stream != NULL) || (iterator->no_write == true),
|
||||
"no stream buffer allocated");
|
||||
|
||||
iterator->out_buff = stream;
|
||||
|
||||
while (true) {
|
||||
switch(iterator->state) {
|
||||
case ITERATE_INIT:
|
||||
return 0;
|
||||
|
||||
case ITERATE_END:
|
||||
return 0;
|
||||
|
||||
case ITERATE_PREAMBLE: {
|
||||
/*
|
||||
* Output preamble bytes of specified quantity in requested chunk size.
|
||||
* RLL encoding is not used as these are HDLC flags.
|
||||
*/
|
||||
while (iterator->hdlc_count > 0) {
|
||||
if (pktEncodeFrameHDLC(iterator))
|
||||
/* True means the requested count has been reached. */
|
||||
return iterator->qty;
|
||||
} /* End while. */
|
||||
iterator->inp_index = 0;
|
||||
iterator->state = ITERATE_FRAME;
|
||||
continue;
|
||||
} /* End case ITERATE_PREAMBLE. */
|
||||
|
||||
case ITERATE_FRAME: {
|
||||
/*
|
||||
* Output frame data bytes in requested chunk size.
|
||||
*/
|
||||
while (iterator->data_size > 0) {
|
||||
/* Consume input bytes until count reached. */
|
||||
if (pktEncodeFrameData(iterator))
|
||||
/* True means the requested output count has been reached. */
|
||||
return iterator->qty;
|
||||
}
|
||||
/* All frame data input consumed. Switch to CRC fields. */
|
||||
iterator->state = ITERATE_CRC;
|
||||
iterator->data_buff = iterator->crc;
|
||||
iterator->data_size = sizeof(iterator->crc);
|
||||
iterator->inp_index = 0;
|
||||
continue;
|
||||
} /* End case ITERATE_FRAME. */
|
||||
|
||||
case ITERATE_CRC: {
|
||||
/*
|
||||
* Output frame CRC bytes in requested chunk size.
|
||||
*/
|
||||
while (iterator->data_size > 0) {
|
||||
/* Consume bytes until count reached. */
|
||||
if (pktEncodeFrameData(iterator))
|
||||
/* True means the requested count has been reached. */
|
||||
return iterator->qty;
|
||||
}
|
||||
/* Frame CRC consumed. */
|
||||
iterator->state = ITERATE_CLOSE;
|
||||
iterator->hdlc_count = iterator->hdlc_post;
|
||||
iterator->hdlc_code = HDLC_FLAG;
|
||||
iterator->inp_index = 0;
|
||||
continue;
|
||||
} /* End case ITERATE_CRC. */
|
||||
|
||||
case ITERATE_CLOSE: {
|
||||
/*
|
||||
* Output closing flags.
|
||||
* RLL encoding is not used as these are HDLC flags.
|
||||
*/
|
||||
while (iterator->hdlc_count > 0) {
|
||||
if (pktEncodeFrameHDLC(iterator))
|
||||
/* True means the requested count has been reached. */
|
||||
return iterator->qty;
|
||||
} /* End while. */
|
||||
iterator->state = ITERATE_TAIL;
|
||||
/* Tail length. */
|
||||
iterator->hdlc_count = iterator->hdlc_tail;
|
||||
iterator->hdlc_code = HDLC_ZERO;
|
||||
iterator->inp_index = 0;
|
||||
continue;
|
||||
} /* End case ITERATE_CLOSE. */
|
||||
|
||||
case ITERATE_TAIL: {
|
||||
/*
|
||||
* Output tail.
|
||||
* RLL encoding is not used as these are idle flags.
|
||||
* This keeps the data tail clean for the receiver.
|
||||
*/
|
||||
while (iterator->hdlc_count > 0) {
|
||||
if (pktEncodeFrameHDLC(iterator))
|
||||
/* True means the requested count has been reached. */
|
||||
return iterator->qty;
|
||||
} /* End while. */
|
||||
/* Account for RLL inserted bits. */
|
||||
iterator->hdlc_count = ((iterator->rll_count + 7) / 8);
|
||||
iterator->state = ITERATE_FINAL;
|
||||
continue;
|
||||
} /* End case ITERATE_TAIL. */
|
||||
|
||||
case ITERATE_FINAL: {
|
||||
if (iterator->hdlc_count <= iterator->qty) {
|
||||
iterator->state = ITERATE_END;
|
||||
return (iterator->out_count + iterator->hdlc_count);
|
||||
} else {
|
||||
iterator->hdlc_count -= iterator->qty;
|
||||
return iterator->qty;
|
||||
}
|
||||
} /* End case ITERATE_FINAL. */
|
||||
} /* End switch on state. */
|
||||
} /* End while. */
|
||||
} /* End function. */
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -41,26 +41,26 @@ typedef enum {
|
|||
ITERATE_END
|
||||
} txit_state_t;
|
||||
|
||||
typedef struct {
|
||||
typedef struct txIterator {
|
||||
txit_state_t state;
|
||||
bool no_write;
|
||||
uint16_t qty;
|
||||
uint16_t out_count;
|
||||
uint8_t hdlc_count;
|
||||
uint8_t hdlc_post;
|
||||
uint8_t hdlc_tail;
|
||||
uint8_t *data_buff;
|
||||
uint16_t data_size;
|
||||
uint8_t *out_buff;
|
||||
uint8_t hdlc_code;
|
||||
uint8_t crc[sizeof(uint16_t)];
|
||||
uint8_t nrzi_hist;
|
||||
uint8_t hdlc_hist;
|
||||
uint32_t inp_index;
|
||||
uint32_t out_index;
|
||||
uint8_t rll_count;
|
||||
bool scramble;
|
||||
uint32_t lfsr;
|
||||
bool no_write;
|
||||
uint16_t qty;
|
||||
uint16_t out_count;
|
||||
uint8_t hdlc_count;
|
||||
uint8_t hdlc_post;
|
||||
uint8_t hdlc_tail;
|
||||
ax25char_t* data_buff;
|
||||
uint16_t data_size;
|
||||
hdlc_octet_t* out_buff;
|
||||
uint8_t hdlc_code;
|
||||
uint8_t crc[sizeof(uint16_t)];
|
||||
uint8_t nrzi_hist;
|
||||
uint8_t hdlc_hist;
|
||||
uint32_t inp_index;
|
||||
uint32_t out_index;
|
||||
uint8_t rll_count;
|
||||
bool scramble;
|
||||
uint32_t lfsr;
|
||||
} tx_iterator_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
|
@ -70,10 +70,12 @@ typedef struct {
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
uint16_t pktStreamEncodingIterator(tx_iterator_t *iterator,
|
||||
uint16_t pktStreamEncodingIterator(tx_iterator_t *iterator,
|
||||
uint8_t *stream, uint16_t qty);
|
||||
void pktStreamIteratorInit(tx_iterator_t *iterator,
|
||||
packet_t pp,
|
||||
void pktStreamIteratorInit(tx_iterator_t *iterator,
|
||||
ax25char_t* pkt,
|
||||
size_t len,
|
||||
//packet_t pp,
|
||||
uint8_t pre,
|
||||
uint8_t post,
|
||||
uint8_t tail,
|
||||
|
|
|
@ -45,6 +45,75 @@ THD_FUNCTION(bcnThread, arg) {
|
|||
*/
|
||||
systime_t next_conf_transmission = 0;
|
||||
|
||||
/**
|
||||
* Altitude controlled beaconing.
|
||||
*
|
||||
* This feature is primarily for short latex based flights.
|
||||
* In such case high rate beaconing is preferable on descent to improve
|
||||
* the chances of beacon reception and location accuracy for recovery.
|
||||
* A second beacon should be assigned for such purpose.
|
||||
*
|
||||
* Ascent based beaconing is also implemented for completeness.
|
||||
*
|
||||
* Altitude control is done with an ARM and RUN field in config.
|
||||
* If not explicitly set in config these values will both be zero and
|
||||
* normal beacon operation takes place.
|
||||
*
|
||||
* There are two altitude controlled cases.
|
||||
* In both cases an ARM altitude must be reached to enable a beacon.
|
||||
* The altitude control commences after the normal startup delay has expired.
|
||||
* 1. Ascending activated
|
||||
* If RUN >= ARM then the beacon is of ascending type.
|
||||
* i.e. the beacon runs after first being enabled and then exceeding the
|
||||
* activate altitude.
|
||||
*
|
||||
* 2. Descending activated
|
||||
* If RUN < ARM then the beacon is of descending type.
|
||||
* i.e. the beacon will run after first being enabled and then falling
|
||||
* below the RUN altitude level.
|
||||
*
|
||||
* Once activated an altitude controlled beacon runs on the cycle time
|
||||
* and ignores the ARM and RUN settings from then on.
|
||||
*
|
||||
* Normally ARM would be zero in the case of an ascending beacon
|
||||
* although it need not be if an altitude delayed start is required.
|
||||
*/
|
||||
|
||||
if (conf.run_alt != 0) {
|
||||
/* This is an altitude controlled beacon.
|
||||
Wait for enable altitude. */
|
||||
msg_t dpmsg;
|
||||
dataPoint_t *dataPoint;
|
||||
TRACE_DEBUG("POS > Altitude controlled beacon waiting for enable at %dM",
|
||||
conf.arm_alt);
|
||||
do {
|
||||
dpmsg = chMsgSend(collector_thd, (msg_t)&conf);
|
||||
dataPoint = (dataPoint_t *)dpmsg;
|
||||
} while (!hasGPSacquiredLock(dataPoint)
|
||||
|| dataPoint->gps_alt < conf.arm_alt);
|
||||
TRACE_DEBUG("POS > Altitude controlled %dM beacon enabled at %dM",
|
||||
conf.arm_alt, dataPoint->gps_alt);
|
||||
if (conf.run_alt >= conf.arm_alt) {
|
||||
/* This is an ascending beacon. */
|
||||
do {
|
||||
dpmsg = chMsgSend(collector_thd, (msg_t)&conf);
|
||||
dataPoint = (dataPoint_t *)dpmsg;
|
||||
} while (!hasGPSacquiredLock(dataPoint)
|
||||
|| dataPoint->gps_alt < conf.run_alt);
|
||||
TRACE_DEBUG("POS > Ascending %dM beacon activated at %dM",
|
||||
conf.run_alt, dataPoint->gps_alt);
|
||||
} else {
|
||||
/* This is a descending beacon. */
|
||||
do {
|
||||
dpmsg = chMsgSend(collector_thd, (msg_t)&conf);
|
||||
dataPoint = (dataPoint_t *)dpmsg;
|
||||
} while (!hasGPSacquiredLock(dataPoint)
|
||||
|| dataPoint->gps_alt > conf.run_alt);
|
||||
TRACE_DEBUG("POS > Descending %dM beacon activated at %dM",
|
||||
conf.run_alt, dataPoint->gps_alt);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Force fast timeout on first attempt from normal BCN app.
|
||||
* ?APRSP command can set its own interval to override the timing.
|
||||
|
@ -60,38 +129,7 @@ THD_FUNCTION(bcnThread, arg) {
|
|||
char code_s[100];
|
||||
pktDisplayFrequencyCode(conf.radio_conf.freq, code_s, sizeof(code_s));
|
||||
TRACE_DEBUG("POS > Do module BEACON cycle for %s on %s%s",
|
||||
conf.call, code_s, conf.run_once ? " (?aprsp response)" : "");
|
||||
|
||||
/* TODO: Implement altitude controlled beaconing.
|
||||
*
|
||||
* This feature is primarily for short latex based flights.
|
||||
* In such case high rate beaconing is preferable on descent to improve
|
||||
* the chances of beacon reception and location accuracy.
|
||||
* A complementary ascent base beaconing is also included for completeness.
|
||||
*
|
||||
* Altitude control is done with an ENABLE and ACTIVATE field in config.
|
||||
* If not explicitly set in config these values will both be zero and
|
||||
* normal beacon operation takes place.
|
||||
*
|
||||
* There are two altitude controlled cases.
|
||||
* In both cases an ENABLE altitude must be reached to enable a beacon.
|
||||
* 1. Ascending activated
|
||||
* If ACTIVATE >= ENABLE then the beacon is of ascending type.
|
||||
* i.e. the beacon runs after first being enabled and then exceeding the
|
||||
* activate altitude.
|
||||
*
|
||||
* 2. Descending activated
|
||||
* If ACTIVATE < ENABLE then the beacon is of descending type.
|
||||
* i.e. the beacon will run after first being enabled and then falling
|
||||
* below the ACTIVATE altitude level.
|
||||
*
|
||||
* Once activated an altitude controlled beacon runs on the cycle time
|
||||
* and ignores the ARM and ACTIVATE settings from then on.
|
||||
*
|
||||
* Normally ENABLE would be zero in the case of an ascending beacon
|
||||
* although it need not be if an altitude delayed start is required.
|
||||
*/
|
||||
|
||||
conf.call, code_s, conf.run_once ? " (?aprsp response)" : "");
|
||||
|
||||
/* Pass pointer to beacon config to the collector thread. */
|
||||
msg_t dpmsg = chMsgSend(collector_thd, (msg_t)&conf);
|
||||
|
@ -117,12 +155,12 @@ THD_FUNCTION(bcnThread, arg) {
|
|||
" telemetry config transmission %d", type);
|
||||
} else {
|
||||
if(!pktTransmitOnRadio(packet,
|
||||
conf.radio_conf.freq,
|
||||
0,
|
||||
0,
|
||||
conf.radio_conf.pwr,
|
||||
conf.radio_conf.mod,
|
||||
conf.radio_conf.cca)) {
|
||||
conf.radio_conf.freq,
|
||||
0,
|
||||
0,
|
||||
conf.radio_conf.pwr,
|
||||
conf.radio_conf.mod,
|
||||
conf.radio_conf.cca)) {
|
||||
/* Packet is released in transmitOnRadio. */
|
||||
TRACE_ERROR("BCN > Failed to transmit telemetry config");
|
||||
}
|
||||
|
@ -145,12 +183,12 @@ THD_FUNCTION(bcnThread, arg) {
|
|||
" for position transmission");
|
||||
} else {
|
||||
if(!pktTransmitOnRadio(packet,
|
||||
conf.radio_conf.freq,
|
||||
0,
|
||||
0,
|
||||
conf.radio_conf.pwr,
|
||||
conf.radio_conf.mod,
|
||||
conf.radio_conf.cca)) {
|
||||
conf.radio_conf.freq,
|
||||
0,
|
||||
0,
|
||||
conf.radio_conf.pwr,
|
||||
conf.radio_conf.mod,
|
||||
conf.radio_conf.cca)) {
|
||||
TRACE_ERROR("BCN > failed to transmit beacon data");
|
||||
}
|
||||
}
|
||||
|
@ -185,12 +223,12 @@ THD_FUNCTION(bcnThread, arg) {
|
|||
"or badly formed APRSD message");
|
||||
} else {
|
||||
if(!pktTransmitOnRadio(packet,
|
||||
conf.radio_conf.freq,
|
||||
0,
|
||||
0,
|
||||
conf.radio_conf.pwr,
|
||||
conf.radio_conf.mod,
|
||||
conf.radio_conf.cca
|
||||
conf.radio_conf.freq,
|
||||
0,
|
||||
0,
|
||||
conf.radio_conf.pwr,
|
||||
conf.radio_conf.mod,
|
||||
conf.radio_conf.cca
|
||||
)) {
|
||||
TRACE_ERROR("BCN > Failed to transmit APRSD data");
|
||||
}
|
||||
|
@ -209,8 +247,8 @@ THD_FUNCTION(bcnThread, arg) {
|
|||
thread_t * start_beacon_thread(bcn_app_conf_t *conf, const char *name) {
|
||||
//extern memory_heap_t *ccm_heap;
|
||||
thread_t *th = chThdCreateFromHeap(ccm_heap,
|
||||
THD_WORKING_AREA_SIZE(PKT_APRS_BEACON_WA_SIZE),
|
||||
name, LOWPRIO, bcnThread, conf);
|
||||
THD_WORKING_AREA_SIZE(PKT_APRS_BEACON_WA_SIZE),
|
||||
name, LOWPRIO, bcnThread, conf);
|
||||
if(!th) {
|
||||
// Print startup error, do not start watchdog for this thread
|
||||
TRACE_ERROR("BCN > Could not start thread (insufficient memory)");
|
||||
|
|
Ładowanie…
Reference in New Issue