- 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 ups
Development
bob 2019-02-13 23:30:49 +11:00
rodzic f0446e1fd9
commit da2bbbc5cf
23 zmienionych plików z 2080 dodań i 1549 usunięć

Wyświetl plik

@ -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. */

Wyświetl plik

@ -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

Wyświetl plik

@ -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.
};

Wyświetl plik

@ -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,

Wyświetl plik

@ -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__ */

Wyświetl plik

@ -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);

Wyświetl plik

@ -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);

Wyświetl plik

@ -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) {

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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. */
/*===========================================================================*/

Wyświetl plik

@ -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
}

Wyświetl plik

@ -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;
}
/** @} */

Wyświetl plik

@ -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
}

Wyświetl plik

@ -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:

Wyświetl plik

@ -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. */
/*===========================================================================*/

Wyświetl plik

@ -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. */

Wyświetl plik

@ -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"

Wyświetl plik

@ -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. */
/** @} */

Wyświetl plik

@ -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,

Wyświetl plik

@ -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)");