kopia lustrzana https://github.com/DL7AD/pecanpico10
Copy in PKT code base. Temp changes to config system. Other updates.
rodzic
54c03be7b2
commit
cd6a2962b4
|
@ -14,7 +14,7 @@
|
|||
</extensions>
|
||||
</storageModule>
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
<configuration buildProperties="" description="" id="cdt.managedbuild.toolchain.gnu.cross.base.1712694318" name="Default" parent="org.eclipse.cdt.build.core.emptycfg">
|
||||
<configuration artifactName="${ProjName}" buildProperties="" description="" id="cdt.managedbuild.toolchain.gnu.cross.base.1712694318" name="Default" parent="org.eclipse.cdt.build.core.emptycfg">
|
||||
<folderInfo id="cdt.managedbuild.toolchain.gnu.cross.base.1712694318.64830061" name="/" resourcePath="">
|
||||
<toolChain id="cdt.managedbuild.toolchain.gnu.cross.base.1747856722" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.base">
|
||||
<option id="cdt.managedbuild.option.gnu.cross.prefix.797583309" name="Prefix" superClass="cdt.managedbuild.option.gnu.cross.prefix"/>
|
||||
|
@ -59,4 +59,5 @@
|
|||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
</scannerConfigBuildInfo>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||
</cproject>
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
/debug/
|
||||
/Copy of config.c
|
||||
/pkt-saved/
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser"/>
|
||||
<provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="461136237790816521" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
<provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="138446027592133826" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
||||
</provider>
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
|
|
@ -60,13 +60,13 @@ endif
|
|||
# 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 = 0x2000
|
||||
USE_PROCESS_STACKSIZE = 0x1000
|
||||
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 = 0x2000
|
||||
USE_EXCEPTIONS_STACKSIZE = 0x1000
|
||||
endif
|
||||
|
||||
# Enables the use of FPU (no, softfp, hard).
|
||||
|
@ -140,7 +140,7 @@ CSRC = $(STARTUPSRC) \
|
|||
drivers/wrapper/padc.c \
|
||||
drivers/wrapper/ptime.c \
|
||||
drivers/ublox.c \
|
||||
drivers/si446x.c \
|
||||
pkt/devices/si446x.c \
|
||||
drivers/bme280.c \
|
||||
drivers/pac1720.c \
|
||||
drivers/ov5640.c \
|
||||
|
@ -160,16 +160,18 @@ CSRC = $(STARTUPSRC) \
|
|||
regex/crx.c \
|
||||
\
|
||||
portab.c \
|
||||
io/protocols/crc_calc.c \
|
||||
io/managers/rxafsk.c \
|
||||
io/channels/rxpwm.c \
|
||||
io/filters/dsp.c \
|
||||
io/filters/firfilter_q31.c \
|
||||
io/decoders/corr_q31.c \
|
||||
io/protocols/rxhdlc.c \
|
||||
io/channels/rxpacket.c \
|
||||
io/devices/dbguart.c \
|
||||
sys/ihex_out.c \
|
||||
pkt/protocols/crc_calc.c \
|
||||
pkt/managers/rxafsk.c \
|
||||
pkt/managers/pktradio.c \
|
||||
pkt/channels/rxpwm.c \
|
||||
pkt/filters/dsp.c \
|
||||
pkt/filters/firfilter_q31.c \
|
||||
pkt/decoders/corr_q31.c \
|
||||
pkt/protocols/rxhdlc.c \
|
||||
pkt/channels/pktservice.c \
|
||||
pkt/devices/dbguart.c \
|
||||
pkt/sys/ihex_out.c \
|
||||
pkt/diagnostics/ax25_dump.c \
|
||||
\
|
||||
main.c \
|
||||
|
||||
|
@ -255,7 +257,7 @@ CPPWARN = -Wall -Wextra -Wundef
|
|||
#
|
||||
|
||||
# List all user C define here, like -D_DEBUG=1
|
||||
UDEFS = -D_GNU_SOURCE -DARM_MATH_CM4
|
||||
UDEFS = -D_GNU_SOURCE -DARM_MATH_CM4 -DSHELL_CMD_TEST_ENABLED=0
|
||||
|
||||
# Define ASM defines here
|
||||
UADEFS =
|
||||
|
@ -264,8 +266,9 @@ UADEFS =
|
|||
UINCDIR = threads/ drivers/ drivers/wrapper/ protocols/aprs2 \
|
||||
protocols/ssdv protocols/morse math/ drivers/flash/ \
|
||||
fatfs/src/ threads/radio/ \
|
||||
sys io/channels io/managers io/devices io/protocols \
|
||||
io/filters io/decoders CMSIS/include regex/
|
||||
pkt pkt/channels pkt/managers pkt/devices pkt/protocols \
|
||||
pkt/diagnostics pkt/filters pkt/decoders pkt/sys CMSIS/include \
|
||||
regex/
|
||||
|
||||
# List the user directory to look for the libraries here
|
||||
ULIBDIR = CMSIS/Lib/GCC
|
||||
|
|
|
@ -372,7 +372,7 @@
|
|||
*
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#define CH_DBG_STATISTICS FALSE
|
||||
#define CH_DBG_STATISTICS TRUE
|
||||
|
||||
/**
|
||||
* @brief Debug option, system state check.
|
||||
|
@ -400,7 +400,7 @@
|
|||
*
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#define CH_DBG_ENABLE_ASSERTS FALSE
|
||||
#define CH_DBG_ENABLE_ASSERTS TRUE
|
||||
|
||||
/**
|
||||
* @brief Debug option, trace buffer.
|
||||
|
@ -408,7 +408,7 @@
|
|||
*
|
||||
* @note The default is @p CH_DBG_TRACE_MASK_DISABLED.
|
||||
*/
|
||||
#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_DISABLED
|
||||
#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_ALL
|
||||
|
||||
/**
|
||||
* @brief Trace buffer entries.
|
||||
|
@ -427,7 +427,7 @@
|
|||
* @note The default failure mode is to halt the system with the global
|
||||
* @p panic_msg variable set to @p NULL.
|
||||
*/
|
||||
#define CH_DBG_ENABLE_STACK_CHECK FALSE
|
||||
#define CH_DBG_ENABLE_STACK_CHECK TRUE
|
||||
|
||||
/**
|
||||
* @brief Debug option, stacks initialization.
|
||||
|
@ -437,7 +437,7 @@
|
|||
*
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#define CH_DBG_FILL_THREADS FALSE
|
||||
#define CH_DBG_FILL_THREADS TRUE
|
||||
|
||||
/**
|
||||
* @brief Debug option, threads profiling.
|
||||
|
@ -448,7 +448,7 @@
|
|||
* @note This debug option is not currently compatible with the
|
||||
* tickless mode.
|
||||
*/
|
||||
#define CH_DBG_THREADS_PROFILING FALSE
|
||||
#define CH_DBG_THREADS_PROFILING TRUE
|
||||
|
||||
/** @} */
|
||||
|
||||
|
|
|
@ -118,19 +118,19 @@ const conf_t conf_flash_default = {
|
|||
},
|
||||
.radio_conf = {
|
||||
.pwr = 0x7F,
|
||||
.freq = FREQ_APRS_DYNAMIC,
|
||||
.freq = 145175000,
|
||||
.mod = MOD_AFSK,
|
||||
.preamble = 200
|
||||
},
|
||||
|
||||
.call = "DL7AD-13",
|
||||
.path = "WIDE1-1",
|
||||
.call = "VK2GJ-15",
|
||||
.path = "WIDE2-1",
|
||||
.symbol = SYM_DIGIPEATER
|
||||
},
|
||||
|
||||
.rssi = 0x3F,
|
||||
.rssi = 0x4F,
|
||||
|
||||
.dig_active = false,
|
||||
.dig_active = true,
|
||||
|
||||
.keep_cam_switched_on = false,
|
||||
|
||||
|
|
|
@ -1,300 +0,0 @@
|
|||
/*
|
||||
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"
|
||||
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
packet_rx_t RPKTD1;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Initializes all packet handlers.
|
||||
* @note The option to manage multiple handlers is not yet implemented.
|
||||
*
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void pktInitReceiveChannels() {
|
||||
RPKTD1.state = PACKET_IDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Opens a packet channel.
|
||||
* @post A reference to the packet handler is returned.
|
||||
* @post The packet channel is initialized and ready to be started.
|
||||
*
|
||||
* @param[in] type the encoding type (currently only AFSK).
|
||||
* @param[in] radio_config pointer to a radio configuration.
|
||||
*
|
||||
* @return The reference to the packet handler object.
|
||||
* @retval NULL if resources are not available to open the channel.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
packet_rx_t *pktOpenReceiveChannel(encoding_type_t type,
|
||||
radio_config_t *radio_config) {
|
||||
/* TODO: Define radio config struct.
|
||||
* Function should return a status like MSG_OK, etc.
|
||||
*/
|
||||
packet_rx_t *handler = &RPKTD1;
|
||||
|
||||
chDbgCheck(handler->state == PACKET_IDLE);
|
||||
|
||||
if(handler->state != PACKET_IDLE)
|
||||
return NULL;
|
||||
|
||||
/* Set link encoding type. */
|
||||
handler->link_type = type;
|
||||
|
||||
/* Create the dynamic objects FIFO for the packet data queue. */
|
||||
dyn_objects_fifo_t *dyn_fifo = chFactoryCreateObjectsFIFO("pkt_fifo",
|
||||
sizeof(pkt_data_fifo_t),
|
||||
NUMBER_PKT_FIFOS, sizeof(msg_t));
|
||||
|
||||
chDbgAssert(dyn_fifo != NULL, "failed to create PKT objects FIFO");
|
||||
|
||||
if(dyn_fifo == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Initialize the counting semaphore for free buffers. */
|
||||
chSemObjectInit(&handler->packet_sem, NUMBER_PKT_FIFOS);
|
||||
|
||||
/* Save the factory FIFO. */
|
||||
handler->the_packet_fifo = dyn_fifo;
|
||||
|
||||
/* Get the objects FIFO . */
|
||||
handler->packet_fifo_pool = chFactoryGetObjectsFIFO(dyn_fifo);
|
||||
|
||||
chDbgAssert(handler->packet_fifo_pool != NULL, "no packet FIFO pool");
|
||||
|
||||
if(handler->packet_fifo_pool == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Indicate no active packet buffer. */
|
||||
handler->active_packet_object = NULL;
|
||||
|
||||
/* TODO: Should statistics be kept in main (user thread)? */
|
||||
handler->packet_count = 0;
|
||||
handler->frame_count = 0;
|
||||
handler->valid_count = 0;
|
||||
|
||||
switch(type) {
|
||||
case DECODE_AFSK: {
|
||||
/*
|
||||
* Create the AFSK channel.
|
||||
* This also handles ICU init and creates the radio PWM FIFO.
|
||||
* The PWM FIFO is the communication channel between ICU and decoder.
|
||||
* Their may be sequential radio packets queued during decoding.
|
||||
*/
|
||||
AFSKDemodDriver *driver = pktCreateAFSKDecoder(handler,
|
||||
radio_config->radio_id);
|
||||
|
||||
chDbgCheck(driver != NULL);
|
||||
|
||||
if(driver == NULL) {
|
||||
chFactoryReleaseObjectsFIFO(dyn_fifo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
handler->link_controller = driver;
|
||||
|
||||
/*
|
||||
* TODO: Configure the radio parameters, frequency, etc.
|
||||
*/
|
||||
|
||||
break;
|
||||
} /* End case. */
|
||||
|
||||
case DECODE_FSK: {
|
||||
chFactoryReleaseObjectsFIFO(dyn_fifo);
|
||||
return NULL;
|
||||
}
|
||||
} /* End switch. */
|
||||
|
||||
/*
|
||||
* Initialize the packet common event object.
|
||||
*/
|
||||
chEvtObjectInit(pktGetEventSource(handler));
|
||||
|
||||
/* Setup offboard red LED. */
|
||||
//palSetLineMode(LINE_RED_LED, PAL_MODE_OUTPUT_PUSHPULL);
|
||||
//palClearLine(LINE_RED_LED);
|
||||
handler->state = PACKET_OPEN;
|
||||
return handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts a packet channel.
|
||||
* @pre The packet channel must have been opened.
|
||||
* @post The packet channel is running if it was stopped.
|
||||
*
|
||||
* @param[in] handler pointer to a @p packet handler object.
|
||||
*
|
||||
* @return Status of the operation.
|
||||
* @retval MSG_OK if the channel was started.
|
||||
* @retval MSG_RESET if the channel was not in the correct state.
|
||||
* @retval MSG_TIMEOUT if the channel could not be started or is invalid.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
msg_t pktStartDataReception(packet_rx_t *handler) {
|
||||
|
||||
if(!(handler->state == PACKET_OPEN || handler->state == PACKET_STOP))
|
||||
return MSG_RESET;
|
||||
switch(handler->link_type) {
|
||||
case DECODE_AFSK: {
|
||||
thread_t *the_decoder =
|
||||
((AFSKDemodDriver *)handler->link_controller)->decoder_thd;
|
||||
chEvtSignal(the_decoder, EVT_DECODER_START);
|
||||
handler->state = PACKET_RUN;
|
||||
return MSG_OK;
|
||||
} /* End case. */
|
||||
|
||||
case DECODE_FSK: {
|
||||
break;
|
||||
}
|
||||
} /* End switch. */
|
||||
return MSG_TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop reception.
|
||||
* @notes Decoding is stopped.
|
||||
* @notes Any packets out for processing remain in effect.
|
||||
* @pre The packet channel must have been started.
|
||||
* @post The packet channel is stopped.
|
||||
*
|
||||
* @param[in] handler pointer to a @p packet handler object.
|
||||
*
|
||||
* @return Status of the operation.
|
||||
* @retval MSG_OK if the channel was stopped.
|
||||
* @retval MSG_RESET if the channel was not in the correct state.
|
||||
* @retval MSG_TIMEOUT if the channel could not be stopped or is invalid.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
msg_t pktStopDataReception(packet_rx_t *handler) {
|
||||
if(handler->state != PACKET_RUN)
|
||||
return MSG_RESET;
|
||||
switch(handler->link_type) {
|
||||
case DECODE_AFSK: {
|
||||
thread_t *the_decoder =
|
||||
((AFSKDemodDriver *)handler->link_controller)->decoder_thd;
|
||||
chEvtSignal(the_decoder, EVT_DECODER_STOP);
|
||||
handler->state = PACKET_STOP;
|
||||
return MSG_OK;
|
||||
} /* End case. */
|
||||
|
||||
case DECODE_FSK: {
|
||||
break;
|
||||
}
|
||||
} /* End switch. */
|
||||
return MSG_TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Closes a packet channel.
|
||||
* @pre The packet channel must have been stopped.
|
||||
* @post The packet channel is closed.
|
||||
* @post Memory used by the decoder thread is released.
|
||||
*
|
||||
* @param[in] handler pointer to a @p packet handler object.
|
||||
*
|
||||
* @return Status of the operation.
|
||||
* @retval MSG_OK if the channel was closed.
|
||||
* @retval MSG_RESET if the channel was not in the correct state.
|
||||
* @retval MSG_TIMEOUT if the channel could not be closed.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
msg_t pktCloseReceiveChannel(packet_rx_t *handler) {
|
||||
|
||||
if(handler->state != PACKET_STOP)
|
||||
return MSG_RESET;
|
||||
handler->state = PACKET_CLOSE;
|
||||
switch(handler->link_type) {
|
||||
case DECODE_AFSK: {
|
||||
thread_t *decoder =
|
||||
((AFSKDemodDriver *)(handler->link_controller))->decoder_thd;
|
||||
chEvtSignal(decoder, EVT_PKT_CHANNEL_CLOSE);
|
||||
/* Wait for AFSK thread to terminate. */
|
||||
msg_t msg = chThdWait(decoder);
|
||||
|
||||
/* Wait for all buffers to be released. */
|
||||
chSemWait(&handler->packet_sem);
|
||||
|
||||
/* Destroy the dynamic objects FIFO for the packet data queue. */
|
||||
chFactoryReleaseObjectsFIFO(handler->the_packet_fifo);
|
||||
|
||||
handler->the_packet_fifo = NULL;
|
||||
handler->packet_fifo_pool = NULL;
|
||||
|
||||
handler->state = PACKET_IDLE;
|
||||
|
||||
/*
|
||||
* TODO: Shut down the radio.
|
||||
*/
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
case DECODE_FSK: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return MSG_TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stores data in a packet channel buffer.
|
||||
* @notes If the data is an HDLC value it will be escape encoded.
|
||||
* @post The character is stored and the internal buffer index is updated.
|
||||
*
|
||||
* @param[in] pkt_buffer pointer to a @p packet buffer object.
|
||||
* @param[in] data the character to be stored
|
||||
*
|
||||
* @return Status of the operation.
|
||||
* @retval true The data was stored.
|
||||
* @retval false The data could not be stored (buffer full).
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
bool pktStoreBufferData(pkt_data_fifo_t *pkt_buffer, ax25char_t data) {
|
||||
if((pkt_buffer->packet_size + 1U) > pkt_buffer->buffer_size) {
|
||||
/* Buffer full. */
|
||||
return false;
|
||||
}
|
||||
/* Buffer space available. */
|
||||
pkt_buffer->buffer[pkt_buffer->packet_size++] = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -1,339 +0,0 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef IO_CHANNELS_RXPACKET_H_
|
||||
#define IO_CHANNELS_RXPACKET_H_
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* Main thread events. */
|
||||
#define EVT_DIAG_OUT_END EVENT_MASK(0)
|
||||
#define EVT_PKT_OUT_END EVENT_MASK(1)
|
||||
|
||||
#define PKT_BUFFER_SIZE PKT_MAX_PACKET_LEN
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* Packet handler states. */
|
||||
typedef enum packetHandlerStates {
|
||||
PACKET_IDLE = 0,
|
||||
PACKET_OPEN,
|
||||
PACKET_RUN,
|
||||
PACKET_STOP,
|
||||
PACKET_CLOSE
|
||||
} packet_state_t;
|
||||
|
||||
/* HDLC frame states. */
|
||||
typedef enum HDLCFrameStates{
|
||||
FRAME_SEARCH,
|
||||
FRAME_OPEN,
|
||||
FRAME_DATA,
|
||||
FRAME_CLOSE,
|
||||
FRAME_RESET
|
||||
} frame_state_t;
|
||||
|
||||
/* Link level encoding type. */
|
||||
typedef enum streamEncodingTypes{
|
||||
DECODE_AFSK,
|
||||
DECODE_FSK
|
||||
} encoding_type_t;
|
||||
|
||||
|
||||
typedef struct packetBuffer {
|
||||
struct pool_header link; /* For safety keep clear - where pool stores its free link. */
|
||||
volatile eventflags_t status;
|
||||
size_t buffer_size;
|
||||
size_t packet_size;
|
||||
ax25char_t buffer[PKT_BUFFER_SIZE];
|
||||
#if USE_AFSK_PHASE_STATISTICS == TRUE
|
||||
dsp_phase_t correction;
|
||||
dsp_phase_t drift;
|
||||
#endif
|
||||
} pkt_data_fifo_t;
|
||||
|
||||
typedef struct packetHandlerData {
|
||||
packet_state_t state;
|
||||
/**
|
||||
* @brief User thread (for events posted to user).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Pointer to link level protocol data.
|
||||
*/
|
||||
void *link_controller;
|
||||
|
||||
/**
|
||||
* @brief Link level protocol type.
|
||||
*/
|
||||
encoding_type_t link_type;
|
||||
|
||||
/**
|
||||
* @brief AX25 packet guarded FIFO.
|
||||
*/
|
||||
dyn_objects_fifo_t *the_packet_fifo;
|
||||
|
||||
/**
|
||||
* @brief AX25 packet FIFO pool.
|
||||
*/
|
||||
objects_fifo_t *packet_fifo_pool;
|
||||
|
||||
/**
|
||||
* @brief Current active packet fifo object.
|
||||
*/
|
||||
pkt_data_fifo_t *active_packet_object;
|
||||
|
||||
/**
|
||||
* @brief Semaphore for buffer counting.
|
||||
*/
|
||||
semaphore_t packet_sem;
|
||||
|
||||
/**
|
||||
* @brief Event source object.
|
||||
*/
|
||||
event_source_t event;
|
||||
|
||||
/**
|
||||
* @brief Event flags.
|
||||
*/
|
||||
//eventflags_t status;
|
||||
|
||||
/**
|
||||
* @brief Packet count.
|
||||
*/
|
||||
uint16_t packet_count;
|
||||
|
||||
/**
|
||||
* @brief Total frame count.
|
||||
*/
|
||||
uint16_t frame_count;
|
||||
|
||||
/**
|
||||
* @brief Good (CRC) frame count.
|
||||
*/
|
||||
uint16_t valid_count;
|
||||
|
||||
/**
|
||||
* @brief Opening HDLC flag sequence found.
|
||||
*/
|
||||
} packet_rx_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void pktInitReceiveChannels(void);
|
||||
packet_rx_t *pktOpenReceiveChannel(encoding_type_t type,
|
||||
radio_config_t *radio_config);
|
||||
msg_t pktStartDataReception(packet_rx_t *handler);
|
||||
msg_t pktStopDataReception(packet_rx_t *handler);
|
||||
msg_t pktCloseReceiveChannel(packet_rx_t *handler);
|
||||
bool pktStoreBufferData(pkt_data_fifo_t *buffer, ax25char_t data);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Macro Functions (packet demod drivers)
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Returns the I/O condition event source.
|
||||
* @details The event source is broadcast when an I/O condition happens.
|
||||
*
|
||||
* @param[in] ip pointer to a @p packet demod driver
|
||||
*
|
||||
* @return A pointer to an @p EventSource object.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define pktGetEventSource(ip) (&((ip)->event))
|
||||
|
||||
/**
|
||||
* @brief Adds status flags to the listeners's flags mask.
|
||||
* @details This function is can be called from the thread level (locked) or
|
||||
* I/O ISRs in order to notify I/O conditions such as
|
||||
* data events, errors, signal changes etc.
|
||||
*
|
||||
* @param[in] ip pointer to a @p packet handler object
|
||||
*
|
||||
* @param[in] flags condition flags to be added to the listener flags mask
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define pktAddEventFlagsI(ip, flags) { \
|
||||
osalEventBroadcastFlagsI(&(ip)->event, flags); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds status flags to the listeners's flags mask.
|
||||
* @details This function is an alias for pktAddsFlagsI for convenience
|
||||
*
|
||||
* @param[in] ip pointer to a @p packet handler object
|
||||
*
|
||||
* @param[in] flags condition flags to be added to the listener flags mask
|
||||
*
|
||||
* @sclass
|
||||
*/
|
||||
#define pktAddEventFlagsS(ip, flags) pktAddEventFlagsI(ip, flags)
|
||||
|
||||
/**
|
||||
* @brief Adds status flags to the listeners's flags mask.
|
||||
* @details This function is can be called from the thread level
|
||||
* in order to notify I/O conditions such as
|
||||
* data events, errors, signal changes etc.
|
||||
*
|
||||
* @param[in] ip pointer to a @p packet handler object
|
||||
*
|
||||
* @param[in] flags condition flags to be added to the listener flags mask
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define pktAddEventFlags(ip, flags) { \
|
||||
osalEventBroadcastFlags(&(ip)->event, flags); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fetches a buffer from the packet buffer free pool.
|
||||
* @details This function is called from thread level to obtain a buffer
|
||||
* to write AX25 data into.
|
||||
*
|
||||
* @param[in] fifo pointer to a @p objects FIFO
|
||||
*
|
||||
* @return pointer to buffer object.
|
||||
* @retval NULL if no buffer object available.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline pkt_data_fifo_t *pktTakeDataBuffer(objects_fifo_t *fifo) {
|
||||
return (pkt_data_fifo_t *)chFifoTakeObjectTimeout(fifo, TIME_IMMEDIATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fetches a buffer from the packet buffer free pool.
|
||||
* @details This function is called from locked thread level to an AX25 buffer.
|
||||
*
|
||||
* @param[in] fifo pointer to a @p objects FIFO
|
||||
*
|
||||
* @return pointer to packet buffer.
|
||||
* @retval NULL if no buffer available.
|
||||
*
|
||||
* @sclass
|
||||
*/
|
||||
static inline pkt_data_fifo_t *pktTakeDataBufferS(objects_fifo_t *fifo) {
|
||||
return (pkt_data_fifo_t *)chFifoTakeObjectI(fifo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a buffer to the packet buffer free pool.
|
||||
* @details This function is called from locked thread level to free a buffer.
|
||||
*
|
||||
* @param[in] fifo pointer to a @p objects FIFO.
|
||||
* @param[in] object pointer to the @p object to return.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline void pktReturnDataBufferS(objects_fifo_t *fifo,
|
||||
pkt_data_fifo_t *object) {
|
||||
chFifoReturnObjectI(fifo, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a buffer to the packet buffer free pool.
|
||||
* @details This function is called from thread level to free a buffer.
|
||||
*
|
||||
* @param[in] handler pointer to a @p packet handler object.
|
||||
* @param[in] object pointer to a @p buffer object.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline void pktReleaseDataBuffer(packet_rx_t *handler,
|
||||
pkt_data_fifo_t *object) {
|
||||
chSysLock();
|
||||
pktReturnDataBufferS(handler->packet_fifo_pool, object);
|
||||
|
||||
/* Indicate that the packet consumer has released the buffer. */
|
||||
chSemSignalI(&handler->packet_sem);
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets the buffer index of a packet buffer.
|
||||
* @details This function is called from thread level to reset the buffer.
|
||||
*
|
||||
* @param[in] object pointer to the @p buffer to reset.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline void pktResetDataBuffer(pkt_data_fifo_t *object) {
|
||||
object->packet_size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits for a buffer to be posted to the FIFO and gets it.
|
||||
* @details This function is called from thread level to get a posted buffer.
|
||||
*
|
||||
* @param[in] handler pointer to a @p packet handler object.
|
||||
* @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 A pointer to the received object.
|
||||
* @retval MSG_TIMEOUT if the specified time expired.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline pkt_data_fifo_t *pktReceiveDataBufferTimeout(packet_rx_t *handler,
|
||||
sysinterval_t timeout) {
|
||||
|
||||
objects_fifo_t *fifo = handler->packet_fifo_pool;
|
||||
pkt_data_fifo_t *object;
|
||||
msg_t fifo_msg = chFifoReceiveObjectTimeout(fifo,
|
||||
(void *)&object, timeout);
|
||||
return (fifo_msg == MSG_OK ? object : NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a buffer meets minimum AX25 validity.
|
||||
* @note Validity relates to minimum size only.
|
||||
* @note The frame may have a good or bad CRC.
|
||||
* @details This function is called from thread level.
|
||||
*
|
||||
* @param[in] object pointer to a @p objects FIFO.
|
||||
*
|
||||
* @return Status.
|
||||
* @retval MSG_OK if the buffer meets minimum requirement for AX25 frame.
|
||||
* @retval MSG_TIMEOUT if the minimum requirements are not met.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline msg_t pktIsBufferValidAX25Frame(pkt_data_fifo_t *object) {
|
||||
chDbgAssert(object != NULL, "no pointer to packet object buffer");
|
||||
uint16_t frame_size = object->packet_size;
|
||||
if((object->status & EVT_AFSK_DECODE_DONE)
|
||||
&& frame_size >= PKT_MIN_FRAME) {
|
||||
return MSG_OK;
|
||||
}
|
||||
return MSG_RESET;
|
||||
}
|
||||
|
||||
#endif /* IO_CHANNELS_RXPACKET_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file rxax25.h
|
||||
* @brief Definitions for AX25 protocol for packet receiver.
|
||||
*
|
||||
* @addtogroup protocols
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
#ifndef IO_PROTOCOLS_RXAX25_H_
|
||||
#define IO_PROTOCOLS_RXAX25_H_
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Type of characters in AX25 packet.
|
||||
*
|
||||
* @note Only used in buffers.
|
||||
*/
|
||||
typedef uint8_t ax25char_t;
|
||||
typedef int16_t ax25size_t;
|
||||
|
||||
/* AX25 definitions for packet data useage. */
|
||||
#define PKT_MAX_REPEATERS 8
|
||||
/* Destination & Source. */
|
||||
#define PKT_MIN_ADDRS 2
|
||||
/*
|
||||
* Destination & Source + 8 digipeater addresses.
|
||||
* A destination address may specify a generic APRS digipeater path.
|
||||
* In such case the digipeater address fields are overridden by that path.
|
||||
*/
|
||||
#define PKT_MAX_ADDRS 10
|
||||
/* Address positions in frame. */
|
||||
#define PKT_DESTINATION 0
|
||||
#define PKT_SOURCE 1
|
||||
#define PKT_REPEATER_1 2
|
||||
#define PKT_REPEATER_2 3
|
||||
#define PKT_REPEATER_3 4
|
||||
#define PKT_REPEATER_4 5
|
||||
#define PKT_REPEATER_5 6
|
||||
#define PKT_REPEATER_6 7
|
||||
#define PKT_REPEATER_7 8
|
||||
#define PKT_REPEATER_8 9
|
||||
|
||||
/*
|
||||
* The maximum address length should be 6 letters, dash, 2 digits and null.
|
||||
* Making a total of 10.
|
||||
* However, object labels can be 10 characters.
|
||||
* So add 2 extra margin bytes.
|
||||
*/
|
||||
#define PKT_DS_ADDRESS_LEN 7
|
||||
#define PKT_MAX_ADDR_LEN 12
|
||||
#define PKT_CONTROL_LEN 1
|
||||
#define PKT_PROTOCOL_LEN 1
|
||||
#define PKT_CRC_LEN 2
|
||||
#define PKT_FLAG_LEN 1
|
||||
#define PKT_MIN_INFO_LEN 0
|
||||
|
||||
|
||||
/* An AX.25 packet can have a control byte and no protocol. */
|
||||
#define PKT_MIN_PACKET_LEN (PKT_MIN_ADDRS * PKT_DS_ADDRESS_LEN \
|
||||
+ PKT_CONTROL_LEN)
|
||||
|
||||
/*
|
||||
* Maximum size for APRS.
|
||||
* The payload excluding CRC.
|
||||
*/
|
||||
#define PKT_MAX_INFO_LEN 2048
|
||||
|
||||
/* An AX.25 packet maximum - closing flag is not included. */
|
||||
#define PKT_MAX_PACKET_LEN (PKT_MAX_ADDRS * PKT_DS_ADDRESS_LEN \
|
||||
+ PKT_CONTROL_LEN \
|
||||
+ PKT_PROTOCOL_LEN \
|
||||
+ PKT_MAX_INFO_LEN \
|
||||
+ PKT_CRC_LEN)
|
||||
|
||||
#define PKT_MIN_FRAME ((PKT_MIN_PACKET_LEN) + PKT_CRC_LEN)
|
||||
#define PKT_MAX_FRAME ((PKT_MAX_PACKET_LEN) + PKT_CRC_LEN)
|
||||
|
||||
#endif /* IO_PROTOCOLS_RXAX25_H_ */
|
||||
|
||||
/** @} */
|
|
@ -47,13 +47,13 @@ int main(void) {
|
|||
#endif
|
||||
|
||||
// Startup threads
|
||||
start_essential_threads(); // Startup required modules (tracking managemer, watchdog)
|
||||
start_essential_threads(); // Startup required modules (tracking manager, watchdog)
|
||||
start_user_threads(); // Startup optional modules (eg. POSITION, LOG, ...)
|
||||
|
||||
while(true) {
|
||||
#if ACTIVATE_USB
|
||||
if(SDU1.config->usbp->state == USB_ACTIVE) {
|
||||
thread_t *shelltp = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(512), "shell", NORMALPRIO+1, shellThread, (void*)&shell_cfg);
|
||||
thread_t *shelltp = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(512), "shell", NORMALPRIO - 50, shellThread, (void*)&shell_cfg);
|
||||
chThdWait(shelltp);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -185,6 +185,7 @@
|
|||
#define STM32_SERIAL_USE_USART1 FALSE
|
||||
#define STM32_SERIAL_USE_USART2 FALSE
|
||||
#define STM32_SERIAL_USE_USART3 TRUE
|
||||
#define STM32_SERIAL_USE_UART4 FALSE
|
||||
#define STM32_SERIAL_USE_UART5 FALSE
|
||||
#define STM32_SERIAL_USE_USART6 FALSE
|
||||
#define STM32_SERIAL_USART1_PRIORITY 12
|
||||
|
|
|
@ -0,0 +1,684 @@
|
|||
/*
|
||||
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"
|
||||
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
packet_svc_t RPKTD1;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Initializes packet handlers and starts the radio manager.
|
||||
* @note The option to manage multiple radios is not yet implemented.
|
||||
*
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void pktServiceCreate() {
|
||||
|
||||
/* TODO: This should create the top level object for each radio (RPKTDx). */
|
||||
packet_svc_t *handler = &RPKTD1;
|
||||
|
||||
/*
|
||||
* Initialize the packet common event object.
|
||||
*/
|
||||
chEvtObjectInit(pktGetEventSource(handler));
|
||||
|
||||
memset(&handler->radio_config, 0, sizeof(radio_task_object_t));
|
||||
|
||||
/* Set parameters and send request. */
|
||||
handler->radio_config.radio_id = PKT_RADIO_1;
|
||||
|
||||
/* Set service semaphore to idle state. */
|
||||
chBSemObjectInit(&handler->close_sem, false);
|
||||
|
||||
pktRadioManagerCreate(handler);
|
||||
handler->state = PACKET_IDLE;
|
||||
}
|
||||
|
||||
void pktServiceRelease() {
|
||||
|
||||
/* TODO: This should release top level resources for each radio (RPKTDx). */
|
||||
packet_svc_t *handler = &RPKTD1;
|
||||
|
||||
pktRadioManagerRelease(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Opens a packet service.
|
||||
* @post A reference to the packet handler is returned.
|
||||
* @post The packet service is initialized and ready to be started.
|
||||
*
|
||||
* @param[in] radio radio unit identifier.
|
||||
* @param[in] encoding radio link level encoding.
|
||||
* @param[in] frequency operating frequency (in Hz).
|
||||
* @param[in] ch_step frequency step per channel (in Hz).
|
||||
*
|
||||
* @return the reference to the packet handler object.
|
||||
* @retval MSG_OK if the open request was processed.
|
||||
* @retval MSG_TIMEOUT if the open request timed out waiting for resources.
|
||||
* @retval MSG_RESET if state is invalid or bad parameter is submitted.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
msg_t pktOpenRadioService(radio_unit_t radio,
|
||||
encoding_type_t encoding,
|
||||
radio_freq_t frequency,
|
||||
channel_hz_t ch_step,
|
||||
packet_svc_t **ph) {
|
||||
|
||||
/* TODO: implement mapping from radio config to packet handler object.
|
||||
* TODO: implement channel step size in Hz in radio driver.
|
||||
*/
|
||||
(void)radio;
|
||||
packet_svc_t *handler = &RPKTD1;
|
||||
|
||||
chDbgCheck(handler->state == PACKET_IDLE);
|
||||
|
||||
if(handler->state != PACKET_IDLE)
|
||||
return MSG_RESET;
|
||||
|
||||
/* Wait for any prior session to complete closing. */
|
||||
chBSemWait(&handler->close_sem);
|
||||
|
||||
/* Save radio configuration. */
|
||||
handler->radio_config.type = encoding;
|
||||
handler->radio_config.base_frequency = frequency;
|
||||
handler->radio_config.step_hz = ch_step;
|
||||
|
||||
/* Reset the statistics collection variables. */
|
||||
handler->sync_count = 0;
|
||||
handler->frame_count = 0;
|
||||
handler->valid_count = 0;
|
||||
handler->good_count = 0;
|
||||
|
||||
radio_task_object_t rt = handler->radio_config;
|
||||
|
||||
/* Set parameters for radio command. */
|
||||
rt.command = PKT_RADIO_OPEN;
|
||||
|
||||
/*
|
||||
* Open (init) the radio (via submit radio task).
|
||||
*/
|
||||
msg_t msg = pktSendRadioCommand(handler, &rt);
|
||||
|
||||
if(msg != MSG_OK)
|
||||
return msg;
|
||||
|
||||
handler->state = PACKET_OPEN;
|
||||
pktAddEventFlags(handler, EVT_PKT_CHANNEL_OPEN);
|
||||
|
||||
/* Set the pointer. */
|
||||
*ph = handler;
|
||||
return MSG_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts packet reception.
|
||||
* @pre The packet service must have been opened.
|
||||
* @post The radio is tuned to the specified channel.
|
||||
* @post The packet reception is running if it was stopped.
|
||||
*
|
||||
* @param[in] handler pointer to a @p packet handler object.
|
||||
* @param[in] channel radio channel number to select
|
||||
* @param[in] cb callback function called on receipt of packet.
|
||||
*
|
||||
* @return Status of the operation.
|
||||
* @retval MSG_OK if the service was started.
|
||||
* @retval MSG_RESET parameter error or service not in correct state.
|
||||
* @retval MSG_TIMEOUT if the service could not be started.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
msg_t pktStartDataReception(packet_svc_t *handler,
|
||||
radio_ch_t channel,
|
||||
radio_squelch_t sq,
|
||||
pkt_buffer_cb_t cb) {
|
||||
|
||||
chDbgAssert(handler != NULL, "invalid handler reference");
|
||||
|
||||
if(!(handler->state == PACKET_OPEN || handler->state == PACKET_STOP))
|
||||
return MSG_RESET;
|
||||
|
||||
handler->usr_callback = cb;
|
||||
|
||||
handler->radio_config.channel = channel;
|
||||
handler->radio_config.squelch = sq;
|
||||
|
||||
radio_task_object_t rt = handler->radio_config;
|
||||
|
||||
rt.command = PKT_RADIO_RX;
|
||||
|
||||
msg_t msg = pktSendRadioCommand(handler, &rt);
|
||||
if(msg != MSG_OK)
|
||||
return MSG_TIMEOUT;
|
||||
|
||||
handler->state = PACKET_RUN;
|
||||
pktAddEventFlags(handler, EVT_PKT_DECODER_START);
|
||||
return MSG_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts a packet decoder.
|
||||
* @pre The packet channel must have been opened.
|
||||
* @post The packet decoder is running.
|
||||
*
|
||||
* @param[in] handler pointer to a @p packet handler object.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void pktStartDecoder(packet_svc_t *handler) {
|
||||
|
||||
//chDbgAssert(handler->state == PACKET_RUN, "invalid handler state");
|
||||
|
||||
event_listener_t el;
|
||||
event_source_t *esp;
|
||||
|
||||
switch(handler->radio_config.type) {
|
||||
case DECODE_AFSK: {
|
||||
|
||||
esp = pktGetEventSource((AFSKDemodDriver *)handler->link_controller);
|
||||
|
||||
pktRegisterEventListener(esp, &el, USR_COMMAND_ACK, DEC_START_EXEC);
|
||||
|
||||
thread_t *the_decoder =
|
||||
((AFSKDemodDriver *)handler->link_controller)->decoder_thd;
|
||||
chEvtSignal(the_decoder, DEC_COMMAND_START);
|
||||
break;
|
||||
} /* End case. */
|
||||
|
||||
case DECODE_FSK: {
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
return;
|
||||
} /* End switch. */
|
||||
|
||||
/* Wait for the decoder to start. */
|
||||
eventflags_t evt;
|
||||
do {
|
||||
/* In reality this is redundant as the only masked event is START. */
|
||||
chEvtWaitAny(USR_COMMAND_ACK);
|
||||
|
||||
/* Wait for correct event at source.
|
||||
*/
|
||||
evt = chEvtGetAndClearFlags(&el);
|
||||
} while (evt != DEC_START_EXEC);
|
||||
pktUnregisterEventListener(esp, &el);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop reception.
|
||||
* @notes Decoding is stopped.
|
||||
* @notes Any packets out for processing remain in effect.
|
||||
* @pre The packet channel must be running.
|
||||
* @post The packet channel is stopped.
|
||||
*
|
||||
* @param[in] handler pointer to a @p packet handler object.
|
||||
*
|
||||
* @return Status of the operation.
|
||||
* @retval MSG_OK if the channel was stopped.
|
||||
* @retval MSG_RESET if the channel was not in the correct state.
|
||||
* @retval MSG_TIMEOUT if the channel could not be stopped or is invalid.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
msg_t pktStopDataReception(packet_svc_t *handler) {
|
||||
if(handler->state != PACKET_RUN)
|
||||
return MSG_RESET;
|
||||
|
||||
/* Stop the radio processing. */
|
||||
|
||||
radio_task_object_t rt = handler->radio_config;
|
||||
|
||||
rt.command = PKT_RADIO_RX_STOP;
|
||||
|
||||
msg_t msg = pktSendRadioCommand(handler, &rt);
|
||||
if(msg != MSG_OK)
|
||||
return msg;
|
||||
|
||||
handler->state = PACKET_STOP;
|
||||
pktAddEventFlags(handler, EVT_PKT_CHANNEL_STOP);
|
||||
return MSG_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops a packet decoder.
|
||||
* @pre The packet channel must be running.
|
||||
* @post The packet decoder is stopped.
|
||||
*
|
||||
* @param[in] handler pointer to a @p packet handler object.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void pktStopDecoder(packet_svc_t *handler) {
|
||||
|
||||
//chDbgAssert(handler->state == PACKET_STOP, "invalid handler state");
|
||||
|
||||
event_listener_t el;
|
||||
event_source_t *esp;
|
||||
|
||||
switch(handler->radio_config.type) {
|
||||
case DECODE_AFSK: {
|
||||
esp = pktGetEventSource((AFSKDemodDriver *)handler->link_controller);
|
||||
|
||||
pktRegisterEventListener(esp, &el, USR_COMMAND_ACK, DEC_STOP_EXEC);
|
||||
|
||||
thread_t *the_decoder =
|
||||
((AFSKDemodDriver *)handler->link_controller)->decoder_thd;
|
||||
chEvtSignal(the_decoder, DEC_COMMAND_STOP);
|
||||
break;
|
||||
} /* End case. */
|
||||
|
||||
case DECODE_FSK: {
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
return;
|
||||
} /* End switch. */
|
||||
|
||||
/* Wait for the decoder to stop. */
|
||||
eventflags_t evt;
|
||||
do {
|
||||
chEvtWaitAny(USR_COMMAND_ACK);
|
||||
|
||||
/* Wait for correct event at source.
|
||||
*/
|
||||
evt = chEvtGetAndClearFlags(&el);
|
||||
} while (evt != DEC_STOP_EXEC);
|
||||
pktUnregisterEventListener(esp, &el);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Closes a packet service.
|
||||
* @pre The packet service must have been stopped.
|
||||
* @post The packet service is closed.
|
||||
* @post Memory used by the decoder thread is released.
|
||||
*
|
||||
* @param[in] handler pointer to a @p packet handler object.
|
||||
*
|
||||
* @return Status of the operation.
|
||||
* @retval MSG_OK if the service was closed successfully.
|
||||
* @retval MSG_RESET service not in the correct state or invalid parameter.
|
||||
* @retval MSG_TIMEOUT if the service could not be closed.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
msg_t pktCloseRadioService(packet_svc_t *handler) {
|
||||
|
||||
if(handler->state != PACKET_STOP)
|
||||
return MSG_RESET;
|
||||
|
||||
handler->state = PACKET_CLOSE;
|
||||
|
||||
/* Set parameters for radio. */;
|
||||
|
||||
radio_task_object_t rt = handler->radio_config;
|
||||
|
||||
rt.command = PKT_RADIO_CLOSE;
|
||||
|
||||
/* Submit command. A timeout can occur waiting for a command queue object. */
|
||||
msg_t msg = pktSendRadioCommand(handler, &rt);
|
||||
if(msg != MSG_OK)
|
||||
return msg;
|
||||
|
||||
handler->state = PACKET_IDLE;
|
||||
pktAddEventFlags(handler, EVT_PKT_CHANNEL_CLOSE);
|
||||
return MSG_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stores data in a packet channel buffer.
|
||||
* @notes If the data is an HDLC value it will be escape encoded.
|
||||
* @post The character is stored and the internal buffer index is updated.
|
||||
*
|
||||
* @param[in] pkt_buffer pointer to a @p packet buffer object.
|
||||
* @param[in] data the character to be stored
|
||||
*
|
||||
* @return Status of the operation.
|
||||
* @retval true The data was stored.
|
||||
* @retval false The data could not be stored (buffer full).
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
bool pktStoreBufferData(pkt_data_object_t *pkt_buffer, ax25char_t data) {
|
||||
if((pkt_buffer->packet_size + 1U) > pkt_buffer->buffer_size) {
|
||||
/* Buffer full. */
|
||||
return false;
|
||||
}
|
||||
/* Buffer space available. */
|
||||
pkt_buffer->buffer[pkt_buffer->packet_size++] = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dispatch a received buffer object.
|
||||
* @notes The buffer is checked to determine validity and CRC.
|
||||
* @post The buffer status is updated in the packet FIFO.
|
||||
* @post Packet quality statistics are updated.
|
||||
* @post Where no callback is used the buffer is posted to the FIFO mailbox.
|
||||
* @post Where a callback is used a thread is created to execute the callback.
|
||||
*
|
||||
* @param[in] pkt_buffer pointer to a @p packet buffer object.
|
||||
*
|
||||
* @return Status flags added after packet validity check.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
eventflags_t pktDispatchReceivedBuffer(pkt_data_object_t *pkt_buffer) {
|
||||
|
||||
chDbgAssert(pkt_buffer != NULL, "no packet buffer");
|
||||
|
||||
packet_svc_t *handler = pkt_buffer->handler;
|
||||
|
||||
chDbgAssert(handler != NULL, "invalid handler");
|
||||
|
||||
eventflags_t flags = EVT_NONE;
|
||||
handler->frame_count++;
|
||||
if(pktIsBufferValidAX25Frame(pkt_buffer)) {
|
||||
handler->valid_count++;
|
||||
uint16_t magicCRC =
|
||||
calc_crc16(pkt_buffer->buffer, 0,
|
||||
pkt_buffer->packet_size);
|
||||
if(magicCRC == CRC_INCLUSIVE_CONSTANT)
|
||||
handler->good_count++;
|
||||
flags |= (magicCRC == CRC_INCLUSIVE_CONSTANT)
|
||||
? EVT_AX25_FRAME_RDY
|
||||
: EVT_AX25_CRC_ERROR;
|
||||
} else {
|
||||
flags |= EVT_AFSK_INVALID_FRAME;
|
||||
}
|
||||
|
||||
/* Update status in packet buffer object. */
|
||||
pkt_buffer->status |= flags;
|
||||
|
||||
if(pkt_buffer->cb_func == NULL) {
|
||||
objects_fifo_t *pkt_fifo = chFactoryGetObjectsFIFO(pkt_buffer->pkt_factory);
|
||||
|
||||
chDbgAssert(pkt_fifo != NULL, "no packet FIFO");
|
||||
|
||||
/* Send the packet buffer to the FIFO queue. */
|
||||
chFifoSendObject(pkt_fifo, pkt_buffer);
|
||||
} else {
|
||||
/* Schedule a callback. */
|
||||
thread_t *cb_thd = pktCreateBufferCallback(pkt_buffer);
|
||||
|
||||
chDbgAssert(cb_thd != NULL, "failed to create callback thread");
|
||||
|
||||
/* Increase outstanding callback count. */
|
||||
handler->cb_count++;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a callback processing thread.
|
||||
* @notes Packet callbacks are processed by individual threads.
|
||||
* @notes Thus packet callbacks are non-blocking to the decoder thread.
|
||||
* @notes After callback completes the thread it is scheduled for release.
|
||||
* @notes Release is initiated by posting the packet buffer to the queue.
|
||||
*
|
||||
* @post Call back has been executed (for however long it takes).
|
||||
* @post Callback thread release is completed in the terminator thread.
|
||||
*
|
||||
* @param[in] pkt_data_object_t pointer to a @p packet buffer object.
|
||||
*
|
||||
* @return The callback thread.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
thread_t *pktCreateBufferCallback(pkt_data_object_t *pkt_buffer) {
|
||||
|
||||
chDbgAssert(pkt_buffer != NULL, "invalid packet buffer");
|
||||
|
||||
/* Create a callback thread name which is the address of the buffer. */
|
||||
chsnprintf(pkt_buffer->cb_thd_name, sizeof(pkt_buffer->cb_thd_name),
|
||||
"%x", pkt_buffer);
|
||||
|
||||
/* Start a callback dispatcher thread. */
|
||||
thread_t *cb_thd = chThdCreateFromHeap(NULL,
|
||||
THD_WORKING_AREA_SIZE(PKT_CALLBACK_WA_SIZE),
|
||||
pkt_buffer->cb_thd_name,
|
||||
NORMALPRIO - 20,
|
||||
pktCallback,
|
||||
pkt_buffer);
|
||||
|
||||
return cb_thd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Run a callback processing thread.
|
||||
* @notes Packet callbacks are processed by individual threads.
|
||||
* @notes Thus packet callbacks are non-blocking to the decoder thread.
|
||||
* @notes After callback completes the thread it is scheduled for release.
|
||||
* @notes Release is initiated by posting the packet buffer to the queue.
|
||||
*
|
||||
* @post Call back has been executed (for however long it takes).
|
||||
* @post Callback thread release is completed in the terminator thread.
|
||||
*
|
||||
* @param[in] arg pointer to a @p packet buffer object.
|
||||
*
|
||||
* @return status (MSG_OK).
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
THD_FUNCTION(pktCallback, arg) {
|
||||
|
||||
chDbgAssert(arg != NULL, "invalid buffer reference");
|
||||
|
||||
pkt_data_object_t *pkt_buffer = arg;
|
||||
|
||||
chDbgAssert(pkt_buffer->cb_func != NULL, "no callback set");
|
||||
|
||||
dyn_objects_fifo_t *pkt_factory = pkt_buffer->pkt_factory;
|
||||
chDbgAssert(pkt_factory != NULL, "invalid packet factory reference");
|
||||
|
||||
objects_fifo_t *pkt_fifo = chFactoryGetObjectsFIFO(pkt_factory);
|
||||
chDbgAssert(pkt_fifo != NULL, "no packet FIFO");
|
||||
|
||||
/* Save thread pointer for use later in terminator. */
|
||||
pkt_buffer->cb_thread = chThdGetSelfX();
|
||||
|
||||
/* Perform the callback. */
|
||||
pkt_buffer->cb_func(pkt_buffer);
|
||||
|
||||
/*
|
||||
* Upon return buffer is queued for release.
|
||||
* Thread is scheduled for destruction in pktReleaseDataBuffer(...).
|
||||
* .i.e pktReleaseDataBuffer does not return for callback.
|
||||
*/
|
||||
pktReleaseDataBuffer(pkt_buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Process releasae of completed callbacks.
|
||||
* @notes Release is initiated by posting the packet buffer to the queue.
|
||||
*
|
||||
* @post Call back thread has been released.
|
||||
* @post Packet buffer object is returned to free pool.
|
||||
* @post Packet object is released (for this instance).
|
||||
* @post If the FIFO is now unused it will be released.
|
||||
*
|
||||
* @param[in] arg pointer to a @p packet service object.
|
||||
*
|
||||
* @return status (MSG_OK).
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
THD_FUNCTION(pktCompletion, arg) {
|
||||
packet_svc_t *handler = arg;
|
||||
#define PKT_COMPLETION_THREAD_TIMER 100 /* 100 mS. */
|
||||
chDbgAssert(arg != NULL, "invalid handler reference");
|
||||
|
||||
dyn_objects_fifo_t *pkt_factory = handler->the_packet_fifo;
|
||||
objects_fifo_t *pkt_queue = chFactoryGetObjectsFIFO(pkt_factory);
|
||||
chDbgAssert(pkt_queue != NULL, "no packet fifo list");
|
||||
|
||||
/* TODO: Implement thread events to control start/stop. */
|
||||
while(true) {
|
||||
|
||||
/*
|
||||
* Wait for a callback to be outstanding.
|
||||
* If no callbacks outstanding check for termination request.
|
||||
*/
|
||||
if(handler->cb_count == 0) {
|
||||
if(chThdShouldTerminateX())
|
||||
chThdExit(MSG_OK);
|
||||
chThdSleep(TIME_MS2I(PKT_COMPLETION_THREAD_TIMER));
|
||||
continue;
|
||||
}
|
||||
/* Wait for a buffer to be released. */
|
||||
pkt_data_object_t *pkt_object;
|
||||
|
||||
msg_t fmsg = chFifoReceiveObjectTimeout(pkt_queue,
|
||||
(void *)&pkt_object,
|
||||
TIME_MS2I(PKT_COMPLETION_THREAD_TIMER));
|
||||
if(fmsg == MSG_TIMEOUT)
|
||||
continue;
|
||||
|
||||
/* Release the callback thread and recover heap. */
|
||||
chThdRelease(pkt_object->cb_thread);
|
||||
|
||||
/* Return packet buffer object to free list. */
|
||||
chFifoReturnObject(pkt_queue, (pkt_data_object_t *)pkt_object);
|
||||
|
||||
/*
|
||||
* Decrease FIFO reference counter (increased by decoder).
|
||||
* FIFO will be destroyed if all references now released.
|
||||
*/
|
||||
chFactoryReleaseObjectsFIFO(pkt_factory);
|
||||
|
||||
/* Decrease count of outstanding callbacks. */
|
||||
--handler->cb_count;
|
||||
}
|
||||
chThdExit(MSG_OK);
|
||||
}
|
||||
|
||||
void pktCallbackManagerOpen(packet_svc_t *handler) {
|
||||
|
||||
radio_unit_t rid = handler->radio_config.radio_id;
|
||||
|
||||
/* Create the callback handler thread name. */
|
||||
chsnprintf(handler->cbend_name, sizeof(handler->cbend_name),
|
||||
"%s%02i", PKT_CALLBACK_TERMINATOR_PREFIX, rid);
|
||||
|
||||
/* Start the callback thread terminator. */
|
||||
thread_t *cbh = chThdCreateFromHeap(NULL,
|
||||
THD_WORKING_AREA_SIZE(PKT_TERMINATOR_WA_SIZE),
|
||||
handler->cbend_name,
|
||||
NORMALPRIO - 30,
|
||||
pktCompletion,
|
||||
handler);
|
||||
|
||||
chDbgAssert(cbh != NULL, "failed to create callback terminator thread");
|
||||
handler->cb_terminator = cbh;
|
||||
}
|
||||
|
||||
dyn_objects_fifo_t *pktBufferManagerCreate(packet_svc_t *handler) {
|
||||
/* The radio associated with this AFSK driver. */
|
||||
radio_unit_t rid = handler->radio_config.radio_id;
|
||||
|
||||
/* Create the packet buffer name for this radio. */
|
||||
chsnprintf(handler->pbuff_name, sizeof(handler->pbuff_name),
|
||||
"%s%02i", PKT_FRAME_QUEUE_PREFIX, rid);
|
||||
|
||||
/* Check if the packet buffer factory is still in existence.
|
||||
* If so we get a pointer to it.
|
||||
*/
|
||||
dyn_objects_fifo_t *dyn_fifo =
|
||||
chFactoryFindObjectsFIFO(handler->pbuff_name);
|
||||
|
||||
if(dyn_fifo == NULL) {
|
||||
/* Create the dynamic objects FIFO for the packet data queue. */
|
||||
dyn_fifo = chFactoryCreateObjectsFIFO(handler->pbuff_name,
|
||||
sizeof(pkt_data_object_t),
|
||||
NUMBER_PKT_FIFOS, sizeof(msg_t));
|
||||
|
||||
chDbgAssert(dyn_fifo != NULL, "failed to create PKT objects FIFO");
|
||||
|
||||
if(dyn_fifo == NULL) {
|
||||
/* TODO: Close decoder on fail. */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Save the factory FIFO. */
|
||||
handler->the_packet_fifo = dyn_fifo;
|
||||
|
||||
/* Initialize packet buffer pointer. */
|
||||
handler->active_packet_object = NULL;
|
||||
return dyn_fifo;
|
||||
}
|
||||
|
||||
|
||||
void pktCallbackManagerCreate(packet_svc_t *handler) {
|
||||
radio_unit_t rid = handler->radio_config.radio_id;
|
||||
|
||||
/* Create the callback termination thread name. */
|
||||
chsnprintf(handler->cbend_name, sizeof(handler->cbend_name),
|
||||
"%s%02i", PKT_CALLBACK_TERMINATOR_PREFIX, rid);
|
||||
|
||||
/*
|
||||
* Initialize the outstanding callback count.
|
||||
*/
|
||||
handler->cb_count = 0;
|
||||
|
||||
/* Start the callback thread terminator. */
|
||||
thread_t *cbh = chThdCreateFromHeap(NULL,
|
||||
THD_WORKING_AREA_SIZE(PKT_TERMINATOR_WA_SIZE),
|
||||
handler->cbend_name,
|
||||
NORMALPRIO - 30,
|
||||
pktCompletion,
|
||||
handler);
|
||||
|
||||
chDbgAssert(cbh != NULL, "failed to create callback terminator thread");
|
||||
handler->cb_terminator = cbh;
|
||||
}
|
||||
|
||||
void pktBufferManagerRelease(packet_svc_t *handler) {
|
||||
|
||||
/* Release the dynamic objects FIFO for the packet data queue. */
|
||||
chFactoryReleaseObjectsFIFO(handler->the_packet_fifo);
|
||||
handler->the_packet_fifo = NULL;
|
||||
}
|
||||
|
||||
void pktCallbackManagerRelease(packet_svc_t *handler) {
|
||||
|
||||
/* Tell the callback terminator it should exit. */
|
||||
chThdTerminate(handler->cb_terminator);
|
||||
|
||||
/* Wait for it to terminate and release. */
|
||||
chThdWait(handler->cb_terminator);
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -0,0 +1,470 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef PKT_CHANNELS_PKTSERVICE_H_
|
||||
#define PKT_CHANNELS_PKTSERVICE_H_
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* Main thread events. */
|
||||
#define EVT_DIAG_OUT_END EVENT_MASK(0)
|
||||
#define EVT_PKT_OUT_END EVENT_MASK(1)
|
||||
|
||||
#define PKT_BUFFER_SIZE PKT_MAX_PACKET_LEN
|
||||
|
||||
#define PKT_FRAME_QUEUE_PREFIX "pktx_"
|
||||
#define PKT_CALLBACK_TERMINATOR_PREFIX "cbtx_"
|
||||
|
||||
#define PKT_CALLBACK_WA_SIZE 4096
|
||||
#define PKT_TERMINATOR_WA_SIZE 1024
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* Packet handler states. */
|
||||
typedef enum packetHandlerStates {
|
||||
PACKET_IDLE = 0,
|
||||
PACKET_OPEN,
|
||||
PACKET_RUN,
|
||||
PACKET_STOP,
|
||||
PACKET_CLOSE
|
||||
} packet_state_t;
|
||||
|
||||
/* HDLC frame states. */
|
||||
typedef enum HDLCFrameStates {
|
||||
FRAME_SEARCH,
|
||||
FRAME_OPEN,
|
||||
FRAME_DATA,
|
||||
FRAME_CLOSE,
|
||||
FRAME_RESET
|
||||
} frame_state_t;
|
||||
|
||||
/* Link level encoding type. */
|
||||
typedef enum {
|
||||
DECODE_NOT_SET,
|
||||
DECODE_AFSK,
|
||||
DECODE_FSK
|
||||
} encoding_type_t;
|
||||
|
||||
#ifdef PKT_USE_PROJECT_DEFINITIONS
|
||||
/* Modulation type. */
|
||||
typedef enum {
|
||||
MOD_AFSK,
|
||||
MOD_2FSK
|
||||
} mod_t;
|
||||
|
||||
#endif
|
||||
|
||||
#include "pktradio.h"
|
||||
|
||||
typedef struct packetBuffer pkt_data_object_t;
|
||||
typedef void (*pkt_buffer_cb_t)(pkt_data_object_t *pkt_buffer);
|
||||
|
||||
typedef struct packetBuffer {
|
||||
struct pool_header link; /* For safety keep clear - where pool stores its free link. */
|
||||
packet_svc_t *handler;
|
||||
dyn_objects_fifo_t *pkt_factory;
|
||||
thread_t *cb_thread;
|
||||
char cb_thd_name[sizeof(size_t) + 1];
|
||||
pkt_buffer_cb_t cb_func;
|
||||
volatile eventflags_t status;
|
||||
size_t buffer_size;
|
||||
size_t packet_size;
|
||||
ax25char_t buffer[PKT_BUFFER_SIZE];
|
||||
} pkt_data_object_t;
|
||||
|
||||
|
||||
typedef struct packetHandlerData {
|
||||
/**
|
||||
* @brief State of the packet handler.
|
||||
*/
|
||||
packet_state_t state;
|
||||
|
||||
/**
|
||||
* @brief Radio operating parameters.
|
||||
*/
|
||||
radio_task_object_t radio_config;
|
||||
|
||||
/**
|
||||
* @brief Pointer to link level protocol data.
|
||||
*/
|
||||
void *link_controller;
|
||||
|
||||
/**
|
||||
* @brief Link level protocol type.
|
||||
*/
|
||||
//encoding_type_t link_type;
|
||||
|
||||
/**
|
||||
* @brief names for the factory FIFOs.
|
||||
* @notes packet buffer & radio task and callback
|
||||
*/
|
||||
char pbuff_name[CH_CFG_FACTORY_MAX_NAMES_LENGTH];
|
||||
char rtask_name[CH_CFG_FACTORY_MAX_NAMES_LENGTH];
|
||||
char cbend_name[CH_CFG_FACTORY_MAX_NAMES_LENGTH];
|
||||
|
||||
/**
|
||||
* @brief Packet system service threads.
|
||||
*/
|
||||
thread_t *radio_manager;
|
||||
thread_t *cb_terminator;
|
||||
|
||||
/**
|
||||
* @brief Radio task guarded FIFO.
|
||||
*/
|
||||
dyn_objects_fifo_t *the_radio_fifo;
|
||||
|
||||
/**
|
||||
* @brief AX25 packet guarded FIFO.
|
||||
*/
|
||||
dyn_objects_fifo_t *the_packet_fifo;
|
||||
|
||||
/**
|
||||
* @brief Packet buffer cb_func.
|
||||
*/
|
||||
pkt_buffer_cb_t usr_callback;
|
||||
|
||||
/**
|
||||
* @brief Current active packet fifo object.
|
||||
*/
|
||||
pkt_data_object_t *active_packet_object;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Counter for active callback threads.
|
||||
* TODO: type should be of a generic counter?
|
||||
*/
|
||||
uint8_t cb_count;
|
||||
|
||||
/**
|
||||
* @brief Event source object.
|
||||
*/
|
||||
binary_semaphore_t close_sem;
|
||||
|
||||
/**
|
||||
* @brief Event source object.
|
||||
*/
|
||||
event_source_t event;
|
||||
|
||||
/**
|
||||
* @brief Packet count.
|
||||
*/
|
||||
uint16_t sync_count;
|
||||
|
||||
/**
|
||||
* @brief Statistics counters.
|
||||
*/
|
||||
uint16_t frame_count;
|
||||
uint16_t good_count;
|
||||
uint16_t valid_count;
|
||||
} packet_svc_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#include "pktradio.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void pktServiceCreate(void);
|
||||
void pktServiceRelease(void);
|
||||
msg_t pktOpenRadioService(radio_unit_t radio,
|
||||
encoding_type_t encoding,
|
||||
radio_freq_t frequency,
|
||||
channel_hz_t ch_step,
|
||||
packet_svc_t **handler);
|
||||
msg_t pktStartDataReception(packet_svc_t *handler,
|
||||
radio_ch_t channel,
|
||||
radio_squelch_t sq,
|
||||
pkt_buffer_cb_t cb);
|
||||
void pktStartDecoder(packet_svc_t *handler);
|
||||
msg_t pktStopDataReception(packet_svc_t *handler);
|
||||
void pktStopDecoder(packet_svc_t *handler);
|
||||
msg_t pktCloseRadioService(packet_svc_t *handler);
|
||||
bool pktStoreBufferData(pkt_data_object_t *buffer, ax25char_t data);
|
||||
eventflags_t pktDispatchReceivedBuffer(pkt_data_object_t *pkt_buffer);
|
||||
thread_t *pktCreateBufferCallback(pkt_data_object_t *pkt_buffer);
|
||||
void pktCallback(void *arg);
|
||||
void pktCallbackManagerOpen(packet_svc_t *handler);
|
||||
void pktCompletion(void *arg);
|
||||
dyn_objects_fifo_t *pktBufferManagerCreate(packet_svc_t *handler);
|
||||
void pktCallbackManagerCreate(packet_svc_t *handler);
|
||||
void pktBufferManagerRelease(packet_svc_t *handler);
|
||||
void pktCallbackManagerRelease(packet_svc_t *handler);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Macro Functions (packet system drivers)
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Returns the I/O condition event source.
|
||||
* @details The event source is broadcast when an I/O condition happens.
|
||||
*
|
||||
* @param[in] ip pointer to a @p packet system event source
|
||||
* @return A pointer to an @p EventSource object.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define pktGetEventSource(ip) (&((ip)->event))
|
||||
|
||||
/**
|
||||
* @brief Adds status flags to the listeners's flags mask.
|
||||
* @details This function is called from the thread level (locked) or
|
||||
* I/O ISRs in order to notify I/O conditions such as
|
||||
* data events, errors, signal changes etc.
|
||||
*
|
||||
* @param[in] ip pointer to a @p packet system event source
|
||||
* @param[in] flags condition flags to be added to the listener flags mask
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define pktAddEventFlagsI(ip, flags) { \
|
||||
chEvtBroadcastFlagsI(&(ip)->event, flags); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds status flags to the listeners's flags mask.
|
||||
* @details This function is an alias for pktAddsFlagsI for convenience
|
||||
*
|
||||
* @param[in] ip pointer to a @p packet system event source
|
||||
* @param[in] flags condition flags to be added to the listener flags mask
|
||||
*
|
||||
* @sclass
|
||||
*/
|
||||
#define pktAddEventFlagsS(ip, flags) pktAddEventFlagsI(ip, flags)
|
||||
|
||||
/**
|
||||
* @brief Adds status flags to the listeners's flags mask.
|
||||
* @details This function is called from the thread level
|
||||
* in order to notify I/O conditions such as
|
||||
* data events, errors, signal changes etc.
|
||||
*
|
||||
* @param[in] ip pointer to a @p packet system event source
|
||||
* @param[in] flags condition flags to be added to the listener flags mask
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define pktAddEventFlags(ip, flags) { \
|
||||
chEvtBroadcastFlags(&(ip)->event, flags); \
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Registers a listener on the specified event source.
|
||||
* @details This function can be called from the thread level
|
||||
* to register a listener for I/O conditions such as
|
||||
* data events, errors, signal changes etc.
|
||||
*
|
||||
* @param[in] ip pointer to a @p packet system event source
|
||||
* @param[in] listener pointer to event listener object
|
||||
* @param[in] events the events of interest at the event source
|
||||
* @param[in] flags the flags to be added to the listener flags mask
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define pktRegisterEventListener(ip, listener, events, flags) { \
|
||||
chEvtRegisterMaskWithFlags(ip, listener, events, flags); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unregisters an Event Listener from a packet handler.
|
||||
* @note If the event listener is not registered on the specified packet
|
||||
* handler then the function does nothing.
|
||||
*
|
||||
* @param[in] ip pointer to a @p packet system event source
|
||||
* @param[in] listener pointer to the event listener object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define pktUnregisterEventListener(ip, listener) { \
|
||||
chEvtUnregister(ip, listener); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fetches a buffer from the packet buffer free pool.
|
||||
* @details This function is called from locked thread level to an AX25 buffer.
|
||||
*
|
||||
* @param[in] fifo pointer to a @p objects FIFO
|
||||
*
|
||||
* @return pointer to packet buffer.
|
||||
* @retval NULL if no buffer available.
|
||||
*
|
||||
* @sclass
|
||||
*/
|
||||
static inline pkt_data_object_t *pktTakeDataBufferS(packet_svc_t *handler,
|
||||
objects_fifo_t *fifo) {
|
||||
pkt_data_object_t *pkt_buffer = chFifoTakeObjectI(fifo);
|
||||
if(pkt_buffer != NULL) {
|
||||
|
||||
/*
|
||||
* Packet buffer available.
|
||||
* Save the object pointer.
|
||||
*/
|
||||
handler->active_packet_object = pkt_buffer;
|
||||
|
||||
/* Initialize the buffer fields. */
|
||||
pkt_buffer->handler = handler;
|
||||
pkt_buffer->status = EVT_STATUS_CLEAR;
|
||||
pkt_buffer->packet_size = 0;
|
||||
pkt_buffer->buffer_size = PKT_BUFFER_SIZE;
|
||||
pkt_buffer->cb_func = handler->usr_callback;
|
||||
|
||||
/* Save the pointer to the packet factory for use when releasing buffer. */
|
||||
pkt_buffer->pkt_factory = handler->the_packet_fifo;
|
||||
}
|
||||
return pkt_buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fetches a buffer from the packet buffer free pool.
|
||||
* @details This function is called from thread level to obtain a buffer
|
||||
* to write AX25 data into.
|
||||
*
|
||||
* @param[in] fifo pointer to a @p objects FIFO
|
||||
*
|
||||
* @return pointer to buffer object.
|
||||
* @retval NULL if no buffer object available.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline pkt_data_object_t *pktTakeDataBuffer(packet_svc_t *handler,
|
||||
objects_fifo_t *fifo) {
|
||||
chSysLock();
|
||||
pkt_data_object_t *pkt_buffer = pktTakeDataBufferS(handler, fifo);
|
||||
chSysUnlock();
|
||||
return pkt_buffer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns a buffer to the packet buffer free pool.
|
||||
* @details This function is called from thread level to free a buffer.
|
||||
* @post The buffer is released back to the free pool.
|
||||
* @post The semaphore for used/free buffer counting is updated.
|
||||
* @post Or...
|
||||
* @post The factory object is released.
|
||||
* @post If the factory reference count reaches zero it will be destroyed.
|
||||
* @post i.e. when the decoder is closed and the last outstanding buffer is released.
|
||||
*
|
||||
* @param[in] object pointer to a @p buffer object.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline void pktReleaseDataBuffer(pkt_data_object_t *object) {
|
||||
|
||||
dyn_objects_fifo_t *pkt_factory = object->pkt_factory;
|
||||
chDbgAssert(pkt_factory != NULL, "no packet factory");
|
||||
|
||||
objects_fifo_t *pkt_fifo = chFactoryGetObjectsFIFO(pkt_factory);
|
||||
chDbgAssert(pkt_fifo != NULL, "no packet FIFO");
|
||||
|
||||
|
||||
/* Is this a callback release? */
|
||||
/* TODO: Might be better if this is handled independent of this function? */
|
||||
if(object->cb_func != NULL) {
|
||||
/*
|
||||
* For callback mode send the packet buffer to the FIFO queue.
|
||||
* It will be released in the collector thread.
|
||||
* The callback thread memory will be recovered.
|
||||
* The semaphore will be signalled.
|
||||
*/
|
||||
chSysLock();
|
||||
chFifoSendObjectI(pkt_fifo, object);
|
||||
chThdExitS(MSG_OK);
|
||||
/* We don't get to here. */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Free the object.
|
||||
* Decrease the factory reference count.
|
||||
* If the service is closed and all buffers freed then the FIFO is destroyed.
|
||||
*/
|
||||
chFifoReturnObject(pkt_fifo, object);
|
||||
chFactoryReleaseObjectsFIFO(pkt_factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets the buffer index of a packet buffer.
|
||||
* @details This macro resets the buffer count to zero.
|
||||
*
|
||||
* @param[in] object pointer to the @p buffer to reset.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline void pktResetDataCount(pkt_data_object_t *object) {
|
||||
object->packet_size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits for a buffer to be posted to the FIFO and gets it.
|
||||
* @details This function is called from thread level to get a posted buffer.
|
||||
*
|
||||
* @param[in] handler pointer to a @p packet handler object.
|
||||
* @param[in] object pointer to the fetched object reference.
|
||||
* @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 The operation status.
|
||||
* @retval MSG_OK if an object has been correctly fetched.
|
||||
* @retval MSG_TIMEOUT if the operation has timed out.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline msg_t pktReceiveDataBufferTimeout(packet_svc_t *handler,
|
||||
pkt_data_object_t **object,
|
||||
sysinterval_t timeout) {
|
||||
|
||||
objects_fifo_t *pkt_fifo = chFactoryGetObjectsFIFO(handler->the_packet_fifo);
|
||||
|
||||
chDbgAssert(pkt_fifo != NULL, "no packet FIFO");
|
||||
|
||||
msg_t fifo_msg = chFifoReceiveObjectTimeout(pkt_fifo,
|
||||
(void *)object, timeout);
|
||||
return fifo_msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a buffer meets minimum AX25 validity.
|
||||
* @note Validity relates to minimum size and AFSK decoding being complete.
|
||||
* @note The frame may have a good or bad CRC.
|
||||
* @details This function is called from thread level.
|
||||
*
|
||||
* @param[in] object pointer to a @p objects FIFO.
|
||||
*
|
||||
* @return The operation status.
|
||||
* @retval true if the buffer meets minimum requirement for AX25 frame.
|
||||
* @retval false if the minimum requirements are not met.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline msg_t pktIsBufferValidAX25Frame(pkt_data_object_t *object) {
|
||||
chDbgAssert(object != NULL, "no pointer to packet object buffer");
|
||||
uint16_t frame_size = object->packet_size;
|
||||
return ((object->status & EVT_AFSK_DECODE_DONE)
|
||||
&& (frame_size >= PKT_MIN_FRAME));
|
||||
}
|
||||
|
||||
#endif /* PKT_CHANNELS_PKTSERVICE_H_ */
|
||||
|
||||
/** @} */
|
|
@ -194,7 +194,7 @@ void pktDisablePWM(AFSKDemodDriver *myDriver) {
|
|||
chSysLock();
|
||||
|
||||
/* Close the PWM stream. */
|
||||
pktClosePWMChannelI(myDriver->icudriver, 0);
|
||||
pktClosePWMChannelI(myDriver->icudriver, 0, PWM_TERM_DECODE_STOP);
|
||||
|
||||
/* Stop ICU capture. */
|
||||
icuStopCaptureI(myDriver->icudriver);
|
||||
|
@ -502,23 +502,29 @@ void pktResetAFSKDecoder(AFSKDemodDriver *myDriver) {
|
|||
*
|
||||
* @api
|
||||
*/
|
||||
AFSKDemodDriver *pktCreateAFSKDecoder(packet_rx_t *pktHandler,
|
||||
radio_unit_t radio) {
|
||||
AFSKDemodDriver *pktCreateAFSKDecoder(packet_svc_t *pktHandler) {
|
||||
|
||||
chDbgAssert(pktHandler != NULL, "no packet handler");
|
||||
|
||||
AFSKDemodDriver *myDriver = &AFSKD1;
|
||||
|
||||
/*
|
||||
* Initialize the decoder event object.
|
||||
*/
|
||||
chEvtObjectInit(pktGetEventSource(myDriver));
|
||||
|
||||
/* Set the link from demod driver to the packet driver. */
|
||||
myDriver->packet_handler = pktHandler;
|
||||
|
||||
myDriver->radio_id = radio;
|
||||
/* The radio associated with this AFSK driver. */
|
||||
radio_unit_t rid = myDriver->packet_handler->radio_config.radio_id;
|
||||
|
||||
/* Set the user (caller) thread in the demod driver structure. */
|
||||
myDriver->initiating_thd = chThdGetSelfX();
|
||||
/* Create a PWM FIFO name for this radio. */
|
||||
chsnprintf(myDriver->pwm_fifo_name, sizeof(myDriver->pwm_fifo_name),
|
||||
"%s%02i", PKT_PWM_QUEUE_PREFIX, rid);
|
||||
|
||||
/* Create the dynamic objects FIFO for the PWM data queue. */
|
||||
myDriver->the_pwm_fifo = chFactoryCreateObjectsFIFO("pwm_fifo",
|
||||
myDriver->the_pwm_fifo = chFactoryCreateObjectsFIFO(myDriver->pwm_fifo_name,
|
||||
sizeof(radio_cca_fifo_t),
|
||||
NUMBER_PWM_FIFOS, sizeof(msg_t));
|
||||
|
||||
|
@ -536,15 +542,19 @@ AFSKDemodDriver *pktCreateAFSKDecoder(packet_rx_t *pktHandler,
|
|||
myDriver->active_demod_object = NULL;
|
||||
|
||||
/* Attach and initialize the ICU PWM system. */
|
||||
myDriver->icudriver = pktAttachICU(radio);
|
||||
myDriver->icudriver = pktAttachICU(pktHandler->radio_config.radio_id);
|
||||
|
||||
/* Set the link from ICU driver to AFSK demod driver. */
|
||||
myDriver->icudriver->link = myDriver;
|
||||
myDriver->icustate = PKT_PWM_READY;
|
||||
|
||||
/* Create the packet buffer name. */
|
||||
chsnprintf(myDriver->decoder_name, sizeof(myDriver->decoder_name),
|
||||
"%s%02i", PKT_AFSK_THREAD_NAME_PREFIX, rid);
|
||||
|
||||
myDriver->decoder_thd = chThdCreateFromHeap(NULL,
|
||||
THD_WORKING_AREA_SIZE(PKT_AFSK_DECODER_WA_SIZE),
|
||||
"afskdecoder",
|
||||
myDriver->decoder_name,
|
||||
NORMALPRIO - 10,
|
||||
pktAFSKDecoder,
|
||||
myDriver);
|
||||
|
@ -582,16 +592,16 @@ AFSKDemodDriver *pktCreateAFSKDecoder(packet_rx_t *pktHandler,
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Destroys AFSK channel and frees resources.
|
||||
* @brief Release AFSK resources.
|
||||
*
|
||||
* @post The ICU is stopped.
|
||||
* @post The dynamic object FIFO is released.
|
||||
* @post The dynamic object FIFO for PWM is released.
|
||||
*
|
||||
* @param[in] myDriver pointer to a @p AFSKDemodDriver structure
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void pktDestroyAFSKDecoder(AFSKDemodDriver *myDriver) {
|
||||
void pktReleaseAFSKDecoder(AFSKDemodDriver *myDriver) {
|
||||
chDbgAssert(myDriver != NULL, "no AFSK driver");
|
||||
chDbgAssert(myDriver->the_pwm_fifo != NULL, "no CCA FIFO");
|
||||
chDbgAssert(myDriver->icudriver != NULL, "no ICU driver");
|
||||
|
@ -618,7 +628,7 @@ THD_FUNCTION(pktAFSKDecoder, arg) {
|
|||
* Setup pointers to control structure and resources.
|
||||
*/
|
||||
AFSKDemodDriver *myDriver = arg;
|
||||
packet_rx_t *myHandler = myDriver->packet_handler;
|
||||
packet_svc_t *myHandler = myDriver->packet_handler;
|
||||
|
||||
/* No active packet object. */
|
||||
myHandler->active_packet_object = NULL;
|
||||
|
@ -628,8 +638,8 @@ THD_FUNCTION(pktAFSKDecoder, arg) {
|
|||
|
||||
#define DECODER_WAIT_TIME 200U /* 200mS. */
|
||||
#define DECODER_IDLE_TIME 2000U /* 2000uS. */
|
||||
#define DECODER_POLL_TIME 10U /* 10mS. */
|
||||
#define DECODER_LED_RATE_POLL 100U /* 1000mS. */
|
||||
#define DECODER_POLL_TIME 10U /* 10mS. */
|
||||
#define DECODER_LED_RATE_POLL 100U /* 1000uS. */
|
||||
#define DECODER_ACTIVE_TIMEOUT 5U /* 5mS. */
|
||||
#define DECODER_SUSPEND_TIME 2000U /* 2000uS. */
|
||||
#define DECODER_LED_RATE_SUSPEND 250U /* Blink at 250mS during suspend. */
|
||||
|
@ -649,28 +659,30 @@ THD_FUNCTION(pktAFSKDecoder, arg) {
|
|||
|
||||
pktWriteDecoderLED(PAL_HIGH);
|
||||
|
||||
/* Wait for start or close of decoder. */
|
||||
/* Acknowledge open then wait for start or close of decoder. */
|
||||
pktAddEventFlags(myDriver, DEC_OPEN_EXEC);
|
||||
myDriver->decoder_state = DECODER_WAIT;
|
||||
while(true) {
|
||||
switch(myDriver->decoder_state) {
|
||||
|
||||
case DECODER_WAIT: {
|
||||
/*
|
||||
* Wait for start event.
|
||||
* Wait for start or close event.
|
||||
*/
|
||||
eventmask_t evt = chEvtWaitAnyTimeout(EVT_DECODER_START,
|
||||
eventmask_t evt = chEvtWaitAnyTimeout(DEC_COMMAND_START,
|
||||
TIME_MS2I(DECODER_WAIT_TIME));
|
||||
if(evt) {
|
||||
pktEnablePWM(myDriver);
|
||||
myDriver->decoder_state = DECODER_RESET;
|
||||
pktAddEventFlags(myHandler, EVT_DECODER_ACK);
|
||||
pktAddEventFlags(myDriver, DEC_START_EXEC);
|
||||
break;
|
||||
}
|
||||
evt = chEvtGetAndClearEvents(EVT_PKT_CHANNEL_CLOSE);
|
||||
evt = chEvtGetAndClearEvents(DEC_COMMAND_CLOSE);
|
||||
if(evt) {
|
||||
pktAddEventFlags(myHandler, EVT_DECODER_ACK);
|
||||
pktDestroyAFSKDecoder(myDriver);
|
||||
pktAddEventFlags(myDriver, DEC_CLOSE_EXEC);
|
||||
pktReleaseAFSKDecoder(myDriver);
|
||||
myDriver->decoder_state = DECODER_TERMINATED;
|
||||
pktWriteDecoderLED(PAL_LOW);
|
||||
chThdExit(MSG_OK);
|
||||
/* Something went wrong if we arrive here. */
|
||||
chSysHalt("ThdExit");
|
||||
|
@ -687,11 +699,11 @@ THD_FUNCTION(pktAFSKDecoder, arg) {
|
|||
/*
|
||||
* Check for stop event.
|
||||
*/
|
||||
eventmask_t evt = chEvtGetAndClearEvents(EVT_DECODER_STOP);
|
||||
eventmask_t evt = chEvtGetAndClearEvents(DEC_COMMAND_STOP);
|
||||
if(evt) {
|
||||
pktDisablePWM(myDriver);
|
||||
myDriver->decoder_state = DECODER_WAIT;
|
||||
pktAddEventFlags(myHandler, EVT_DECODER_ACK);
|
||||
pktAddEventFlags(myDriver, DEC_STOP_EXEC);
|
||||
break;
|
||||
}
|
||||
myDriver->decoder_state = DECODER_POLL;
|
||||
|
@ -710,56 +722,47 @@ THD_FUNCTION(pktAFSKDecoder, arg) {
|
|||
pktWriteDecoderLED(PAL_TOGGLE);
|
||||
led_count = 0;
|
||||
}
|
||||
/* No FIFO posted so loop again. */
|
||||
/* No FIFO object posted so loop again. */
|
||||
myDriver->decoder_state = DECODER_IDLE;
|
||||
break;
|
||||
}
|
||||
/* Check if FIFO released in RESET state. */
|
||||
/* Check if PWM queue object released in RESET state. */
|
||||
chDbgCheck(myDriver->active_demod_object == NULL);
|
||||
|
||||
/* Set current demod FIFO. */
|
||||
/* Set current PWM queue object. */
|
||||
myDriver->active_demod_object = myRadioFIFO;
|
||||
|
||||
/* Check if prior packet buffer released. */
|
||||
chDbgCheck(myHandler->active_packet_object == NULL);
|
||||
|
||||
/* Get a packet buffer. */
|
||||
chSysLock();
|
||||
pkt_data_fifo_t *myPktFIFO =
|
||||
pktTakeDataBufferS(myHandler->packet_fifo_pool);
|
||||
dyn_objects_fifo_t *pkt_fifo =
|
||||
chFactoryFindObjectsFIFO(myHandler->pbuff_name);
|
||||
chDbgAssert(pkt_fifo != NULL, "unable to find packet fifo");
|
||||
|
||||
if(myPktFIFO == NULL) {
|
||||
/* The factory reference count is increased. */
|
||||
objects_fifo_t *pkt_buffer_pool = chFactoryGetObjectsFIFO(pkt_fifo);
|
||||
chDbgAssert(pkt_buffer_pool != NULL, "no packet fifo list");
|
||||
|
||||
chSysLock();
|
||||
/* TODO: Does this really need to be locked? */
|
||||
/* Get a buffer and have it initialized ready for use. */
|
||||
pkt_data_object_t *myPktBuffer = pktTakeDataBufferS(myHandler,
|
||||
pkt_buffer_pool);
|
||||
|
||||
if(myPktBuffer == NULL) {
|
||||
chSysUnlock();
|
||||
pktAddEventFlags(myHandler, EVT_AX25_NO_BUFFER);
|
||||
myDriver->active_demod_object->status |= EVT_AX25_NO_BUFFER;
|
||||
myDriver->decoder_state = DECODER_ERROR;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Packet buffer available.
|
||||
* Save the object pointer.
|
||||
*/
|
||||
myHandler->active_packet_object = myPktFIFO;
|
||||
|
||||
/*
|
||||
* Decrease sempahore count.
|
||||
* Will become zero if all buffers are in use by consumers.
|
||||
* Should never go negative.
|
||||
*/
|
||||
(void)chSemWaitS(&myHandler->packet_sem);
|
||||
|
||||
chSysUnlock();
|
||||
|
||||
/* Initialize the buffer. */
|
||||
myPktFIFO->status = EVT_STATUS_CLEAR;
|
||||
myPktFIFO->packet_size = 0;
|
||||
myPktFIFO->buffer_size = PKT_BUFFER_SIZE;
|
||||
|
||||
/*
|
||||
* Fill it with a pattern for debug.
|
||||
* TODO: Make this a diagnostic conditional.
|
||||
*/
|
||||
memset(myPktFIFO->buffer, 0x55, myPktFIFO->buffer_size);
|
||||
//memset(myPktBuffer->buffer, 0x55, myPktBuffer->buffer_size);
|
||||
|
||||
myDriver->decoder_state = DECODER_ACTIVE;
|
||||
|
||||
|
@ -805,26 +808,30 @@ THD_FUNCTION(pktAFSKDecoder, arg) {
|
|||
/* look for "in band" signal in radio data. */
|
||||
if(radio.pwm.impulse == 0) {
|
||||
switch(radio.pwm.valley) {
|
||||
case 0: {
|
||||
/* End of data flag from PWM. */
|
||||
myDriver->decoder_state = DECODER_CLOSE;
|
||||
continue; /* From this case. */
|
||||
} /* End case 0. */
|
||||
case PWM_TERM_DECODE_ENDED:
|
||||
case PWM_TERM_DECODE_STOP:
|
||||
case PWM_TERM_CCA_CLOSE: {
|
||||
/* End of data flag from PWM. */
|
||||
myDriver->decoder_state = DECODER_CLOSE;
|
||||
continue; /* From this case. */
|
||||
} /* End case 0. */
|
||||
|
||||
case 1: {
|
||||
/* Buffer overrun flag from PWM.
|
||||
* PWM side has already set an event for this.
|
||||
*/
|
||||
myDriver->decoder_state = DECODER_ERROR;
|
||||
continue; /* From this case. */
|
||||
} /* End case 1. */
|
||||
case PWM_TERM_ICU_OVERFLOW:
|
||||
case PWM_TERM_NO_RESOURCE:
|
||||
case PWM_TERM_QUEUE_FULL: {
|
||||
/* Buffer overrun flag from PWM.
|
||||
* PWM side has set the global event for this.
|
||||
*/
|
||||
myDriver->decoder_state = DECODER_ERROR;
|
||||
continue; /* From this case. */
|
||||
} /* End case 1. */
|
||||
|
||||
default: {
|
||||
/* Unknown flag from PWM. */
|
||||
pktAddEventFlags(myHandler, EVT_PWM_UNKNOWN_INBAND);
|
||||
myDriver->active_demod_object->status |= EVT_PWM_UNKNOWN_INBAND;
|
||||
myDriver->decoder_state = DECODER_ERROR;
|
||||
continue; /* From this case. */
|
||||
default: {
|
||||
/* Unknown flag from PWM. */
|
||||
pktAddEventFlags(myHandler, EVT_PWM_UNKNOWN_INBAND);
|
||||
myDriver->active_demod_object->status |= EVT_PWM_UNKNOWN_INBAND;
|
||||
myDriver->decoder_state = DECODER_ERROR;
|
||||
continue; /* From this case. */
|
||||
} /* End case default. */
|
||||
} /* End switch. */
|
||||
} /* End if in-band. */
|
||||
|
@ -850,7 +857,6 @@ THD_FUNCTION(pktAFSKDecoder, arg) {
|
|||
pktWriteDecoderLED(PAL_HIGH);
|
||||
continue;
|
||||
case FRAME_RESET:
|
||||
continue;
|
||||
case FRAME_CLOSE: {
|
||||
myDriver->decoder_state = DECODER_CLOSE;
|
||||
continue; /* From this case. */
|
||||
|
@ -884,78 +890,82 @@ THD_FUNCTION(pktAFSKDecoder, arg) {
|
|||
|
||||
case DECODER_RESET: {
|
||||
/*
|
||||
* Return FIFO to pool if there is one active.
|
||||
* Return PWM FIFO to pool if there is one active.
|
||||
*/
|
||||
chSysLock();
|
||||
radio_cca_fifo_t *myFIFO = myDriver->active_demod_object;
|
||||
if(myFIFO != NULL) {
|
||||
|
||||
/* Wait for queue object to be released by PWM. */
|
||||
(void)chSemWait(&myFIFO->sem);
|
||||
chSysLock();
|
||||
(void)chBSemWaitS(&myFIFO->sem);
|
||||
|
||||
myDriver->active_demod_object = NULL;
|
||||
chFifoReturnObjectI(myDriver->pwm_fifo_pool, myFIFO);
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the correlation decoder and its filters.
|
||||
*/
|
||||
}
|
||||
chSysUnlock();
|
||||
/* Reset the correlation decoder and its filters. */
|
||||
pktResetAFSKDecoder(myDriver);
|
||||
|
||||
/*
|
||||
* Turn off blue LED and reset time interval
|
||||
*/
|
||||
/* Turn off blue LED and reset time interval. */
|
||||
pktWriteDecoderLED(PAL_LOW);
|
||||
|
||||
/* Clear the LED blink scaler. */
|
||||
led_count = 0;
|
||||
|
||||
(void)chThdSetPriority(decoder_idle_priority);
|
||||
|
||||
/* Set decoder back to idle. */
|
||||
|
||||
myDriver->decoder_state = DECODER_IDLE;
|
||||
break;
|
||||
} /* End case DECODER_RESET. */
|
||||
|
||||
case DECODER_SUSPEND: {
|
||||
if(myHandler->active_packet_object != NULL) {
|
||||
/* Lock the FIFO against further writes. */
|
||||
pktAddEventFlags(myHandler, EVT_AFSK_DECODE_DONE | EVT_PWM_FIFO_LOCK);
|
||||
myDriver->active_demod_object->status |=
|
||||
(EVT_AFSK_DECODE_DONE | EVT_PWM_FIFO_LOCK);
|
||||
#if USE_AFSK_PHASE_STATISTICS == TRUE
|
||||
qcorr_stats_t *statistics = get_qcorr_statistics(myDriver);
|
||||
myHandler->active_packet_object->correction =
|
||||
statistics->correction;
|
||||
myHandler->active_packet_object->drift =
|
||||
statistics->drift_max;
|
||||
#endif
|
||||
uint16_t magicCRC =
|
||||
calc_crc16(myHandler->active_packet_object->buffer, 0,
|
||||
myHandler->active_packet_object->packet_size);
|
||||
#if AFSK_DEBUG_TYPE == AFSK_PWM_DATA_CAPTURE_DEBUG
|
||||
char buf[80];
|
||||
int out = chsnprintf(buf, sizeof(buf),
|
||||
"\r\n======= END %s =========\r\n",
|
||||
(magicCRC == CRC_INCLUSIVE_CONSTANT) ? "(good)" : "(bad)");
|
||||
chnWrite(pkt_out, (uint8_t *)buf, out);
|
||||
#endif
|
||||
/* Close packet and send event. */
|
||||
eventflags_t evt = (magicCRC == CRC_INCLUSIVE_CONSTANT)
|
||||
? EVT_AX25_FRAME_RDY
|
||||
: EVT_AX25_CRC_ERROR;
|
||||
pktAddEventFlags(myHandler, evt);
|
||||
myDriver->active_demod_object->status |= evt;
|
||||
|
||||
/* Copy status into packet buffer object. */
|
||||
/*
|
||||
* Indicate AFSK decode done & lock the PWM queue.
|
||||
*/
|
||||
eventflags_t evtf = EVT_AFSK_DECODE_DONE | EVT_PWM_QUEUE_LOCK;
|
||||
myDriver->active_demod_object->status |= evtf;
|
||||
|
||||
/* Copy latest status into packet buffer object. */
|
||||
myHandler->active_packet_object->status =
|
||||
myDriver->active_demod_object->status;
|
||||
|
||||
/* Send the packet buffer to the consumer. */
|
||||
chFifoSendObject(myHandler->packet_fifo_pool,
|
||||
myHandler->active_packet_object);
|
||||
/* Dispatch the packet buffer object and get AX25 events. */
|
||||
evtf |= pktDispatchReceivedBuffer(myHandler->active_packet_object);
|
||||
|
||||
/* Forget the packet object. */
|
||||
myHandler->active_packet_object = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send events then update PWM/demod object status.
|
||||
* (the PWM input side doesn't care about AX25 events actually...)
|
||||
*/
|
||||
pktAddEventFlags(myHandler, evtf);
|
||||
myDriver->active_demod_object->status |= evtf;
|
||||
|
||||
#if AFSK_DEBUG_TYPE == AFSK_PWM_DATA_CAPTURE_DEBUG
|
||||
event_listener_t p_listener;
|
||||
chEvtRegisterMaskWithFlags(
|
||||
chnGetEventSource ((SerialDriver *)pkt_out),
|
||||
&p_listener, DEC_DIAG_OUT_END,
|
||||
CHN_TRANSMISSION_END);
|
||||
char buf[80];
|
||||
int out = chsnprintf(buf, sizeof(buf),
|
||||
"\r\n======= END (%s) =========\r\n",
|
||||
(myDriver->active_demod_object->status & EVT_AFSK_INVALID_FRAME)
|
||||
? "invalid frame"
|
||||
: (myDriver->active_demod_object->status & EVT_AX25_FRAME_RDY)
|
||||
? "good CRC" : "bad CRC");
|
||||
chnWrite(pkt_out, (uint8_t *)buf, out);
|
||||
eventflags_t clear;
|
||||
do {
|
||||
clear = chEvtWaitAnyTimeout(DEC_DIAG_OUT_END, TIME_MS2I(100));
|
||||
} while(clear != 0);
|
||||
chEvtUnregister(chnGetEventSource ((SerialDriver *)pkt_out),
|
||||
&p_listener);
|
||||
#endif
|
||||
} /* Active packet object != NULL. */
|
||||
#if SUSPEND_HANDLING == NO_SUSPEND
|
||||
myDriver->decoder_state = DECODER_RESET;
|
||||
break;
|
||||
|
@ -963,16 +973,15 @@ THD_FUNCTION(pktAFSKDecoder, arg) {
|
|||
/*
|
||||
* Only exit suspend on posted event.
|
||||
*/
|
||||
eventmask_t evt = chEvtWaitAnyTimeout(EVT_SUSPEND_EXIT,
|
||||
eventmask_t evtf;
|
||||
do {
|
||||
evtf = chEvtWaitAnyTimeout(DEC_SUSPEND_EXIT,
|
||||
TIME_US2I(DECODER_SUSPEND_TIME));
|
||||
if(evt == 0) {
|
||||
if(++led_count >= DECODER_LED_RATE_SUSPEND) {
|
||||
pktWriteDecoderLED(PAL_TOGGLE);
|
||||
led_count = 0;
|
||||
}
|
||||
/* No event so loop again. */
|
||||
break;
|
||||
}
|
||||
} while(evtf == 0);
|
||||
/*
|
||||
* Post processing done.
|
||||
* Reset the decoder and get ready for next packet.
|
||||
|
@ -983,4 +992,5 @@ THD_FUNCTION(pktAFSKDecoder, arg) {
|
|||
} /* End switch on decoder state. */
|
||||
} /* End thread while(true). */
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -68,7 +68,7 @@
|
|||
#define MAG_FILTER_GEN_COEFF TRUE
|
||||
#define MAG_FILTER_HIGH 1400
|
||||
|
||||
#define PRE_FILTER_NUM_TAPS 55U //311U
|
||||
#define PRE_FILTER_NUM_TAPS 55U
|
||||
#define PRE_FILTER_BLOCK_SIZE 1U
|
||||
#if PRE_FILTER_BLOCK_SIZE != 1
|
||||
#error "Filter block size must be 1"
|
||||
|
@ -90,7 +90,7 @@
|
|||
* Coefficients created dynamically are calculated at run-time.
|
||||
* Coefficients generated externally in Matlab/Octave need to be re-done.
|
||||
*/
|
||||
#define SYMBOL_DECIMATION (24U)
|
||||
#define SYMBOL_DECIMATION (12U)
|
||||
/* Sample rate in Hz. */
|
||||
#define FILTER_SAMPLE_RATE (SYMBOL_DECIMATION * AFSK_BAUD_RATE)
|
||||
#define DECODE_FILTER_LENGTH (2U * SYMBOL_DECIMATION)
|
||||
|
@ -108,10 +108,10 @@
|
|||
#define DECODE_FILTER_LENGTH (2U * SYMBOL_DECIMATION)
|
||||
#endif
|
||||
|
||||
/* Statistic analysis enabling. */
|
||||
#define USE_AFSK_PHASE_STATISTICS FALSE
|
||||
|
||||
#define AFSK_COLLISION_RESTART TRUE
|
||||
#define PKT_PWM_QUEUE_PREFIX "pwmx_"
|
||||
|
||||
#define PKT_AFSK_THREAD_NAME_PREFIX "afsk_"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
|
@ -154,25 +154,23 @@ typedef float32_t pwm_accum_t;
|
|||
typedef int16_t dsp_phase_t;
|
||||
|
||||
#include "rxpwm.h"
|
||||
#include "rxpacket.h"
|
||||
#include "pktservice.h"
|
||||
/**
|
||||
* @brief Structure representing an AFSK demod driver.
|
||||
*/
|
||||
typedef struct AFSK_data {
|
||||
/**
|
||||
* @brief radio identifier.
|
||||
*/
|
||||
radio_unit_t radio_id;
|
||||
|
||||
char decoder_name[CH_CFG_FACTORY_MAX_NAMES_LENGTH];
|
||||
|
||||
/**
|
||||
* @brief pointer to the packet handler.
|
||||
*/
|
||||
packet_rx_t *packet_handler;
|
||||
packet_svc_t *packet_handler;
|
||||
|
||||
/**
|
||||
* @brief User thread (for events posted to user).
|
||||
* @brief Event source object.
|
||||
*/
|
||||
thread_t *initiating_thd;
|
||||
event_source_t event;
|
||||
|
||||
/**
|
||||
* @brief Decoder thread (for events posted to decoder).
|
||||
|
@ -214,6 +212,8 @@ typedef struct AFSK_data {
|
|||
*/
|
||||
rx_icu_state_t icustate;
|
||||
|
||||
char pwm_fifo_name[CH_CFG_FACTORY_MAX_NAMES_LENGTH];
|
||||
|
||||
/**
|
||||
* @brief ICU guarded FIFO.
|
||||
*/
|
||||
|
@ -266,8 +266,8 @@ typedef struct AFSK_data {
|
|||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
static inline void pktRestartAFSKDecoder(AFSKDemodDriver *myDriver) {
|
||||
packet_rx_t *myHandler = myDriver->packet_handler;
|
||||
static inline void pktResyncAFSKDecoder(AFSKDemodDriver *myDriver) {
|
||||
packet_svc_t *myHandler = myDriver->packet_handler;
|
||||
myDriver->frame_state = FRAME_OPEN;
|
||||
myHandler->active_packet_object->packet_size = 0;
|
||||
}
|
||||
|
@ -287,11 +287,10 @@ extern "C" {
|
|||
bool pktDecodeAFSKSymbol(AFSKDemodDriver *myDriver);
|
||||
bool pktExtractHDLCfromAFSK(AFSKDemodDriver *myDriver);
|
||||
bool pktProcessAFSK(AFSKDemodDriver *myDriver, min_pwmcnt_t current_tone[]);
|
||||
AFSKDemodDriver *pktCreateAFSKDecoder(packet_rx_t *pktDriver,
|
||||
radio_unit_t radio_id);
|
||||
AFSKDemodDriver *pktCreateAFSKDecoder(packet_svc_t *pktDriver);
|
||||
bool pktCheckAFSKSymbolTime(AFSKDemodDriver *myDriver);
|
||||
void pktUpdateAFSKSymbolPLL(AFSKDemodDriver *myDriver);
|
||||
void pktDestroyAFSKDecoder(AFSKDemodDriver *myDriver);
|
||||
void pktReleaseAFSKDecoder(AFSKDemodDriver *myDriver);
|
||||
void pktResetAFSKDecoder(AFSKDemodDriver *myDriver);
|
||||
void pktDisablePWM(AFSKDemodDriver *myDriver);
|
||||
void pktAFSKDecoder(void *arg);
|
|
@ -128,6 +128,10 @@ ICUDriver *pktAttachICU(radio_unit_t radio_id) {
|
|||
pktSetLineModeOverflowLED();
|
||||
pktWriteOverflowLED(PAL_LOW);
|
||||
|
||||
/* Setup the no FIFO LED. */
|
||||
pktSetLineModeNoFIFOLED();
|
||||
pktWriteNoFIFOLED(PAL_LOW);
|
||||
|
||||
return myICU;
|
||||
}
|
||||
|
||||
|
@ -155,6 +159,9 @@ void pktDetachICU(ICUDriver *myICU) {
|
|||
/* Disable overflow LED. */
|
||||
pktUnsetLineModeOverflowLED();
|
||||
|
||||
/* Disable no FIFO LED. */
|
||||
pktUnsetLineModeNoFIFOLED();
|
||||
|
||||
/* If using PWM mirror disable diagnostic port. */
|
||||
pktUnsetLineModePWMMirror();
|
||||
}
|
||||
|
@ -174,18 +181,18 @@ void pktICUStart(ICUDriver *myICU) {
|
|||
/**
|
||||
* @brief Terminates the PWM stream from the ICU.
|
||||
* @post The ICU notification (callback) is stopped.
|
||||
* @post An end of data (EOD) in-band flag is written to the PWM queue.
|
||||
* @post If the queue is full the yellow LED is lit.
|
||||
* @post An in-band reason code flag is written to the PWM queue.
|
||||
* @post If the queue is full the optional LED is lit.
|
||||
*
|
||||
* @param[in] myICU pointer to a @p ICUDriver structure
|
||||
* @param[in] event flags to be set as to why the channel is closed.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void pktClosePWMChannelI(ICUDriver *myICU, eventflags_t evt) {
|
||||
void pktClosePWMChannelI(ICUDriver *myICU, eventflags_t evt, pwm_code_t reason) {
|
||||
/* Stop posting data and write end marker. */
|
||||
AFSKDemodDriver *myDemod = myICU->link;
|
||||
packet_rx_t *myHandler = myDemod->packet_handler;
|
||||
packet_svc_t *myHandler = myDemod->packet_handler;
|
||||
chDbgAssert(myDemod != NULL, "no demod linked");
|
||||
chVTResetI(&myICU->pwm_timer);
|
||||
|
||||
|
@ -197,11 +204,15 @@ void pktClosePWMChannelI(ICUDriver *myICU, eventflags_t evt) {
|
|||
/* Stop the ICU notification (callback). */
|
||||
icuDisableNotificationsI(myICU);
|
||||
if(myDemod->active_radio_object != NULL) {
|
||||
myDemod->active_radio_object->status |= (EVT_PWM_FIFO_LOCK | evt);
|
||||
pktAddEventFlagsI(myHandler, (EVT_PWM_FIFO_LOCK | evt));
|
||||
myDemod->active_radio_object->status |= (EVT_PWM_QUEUE_LOCK | evt);
|
||||
pktAddEventFlagsI(myHandler, (EVT_PWM_QUEUE_LOCK | evt));
|
||||
input_queue_t *myQueue = &myDemod->active_radio_object->radio_pwm_queue;
|
||||
/* End of data flag. */
|
||||
byte_packed_pwm_t pack = {{0, 0, 0}};
|
||||
#if USE_12_BIT_PWM == TRUE
|
||||
byte_packed_pwm_t pack = {{0, reason, 0}};
|
||||
#else
|
||||
byte_packed_pwm_t pack = {{0, reason}};
|
||||
#endif
|
||||
msg_t qs = pktWritePWMQueue(myQueue, pack);
|
||||
if(qs != MSG_OK) {
|
||||
pktWriteOverflowLED(PAL_HIGH);
|
||||
|
@ -209,7 +220,7 @@ void pktClosePWMChannelI(ICUDriver *myICU, eventflags_t evt) {
|
|||
pktAddEventFlagsI(myHandler, EVT_PWM_QUEUE_FULL);
|
||||
}
|
||||
/* Release the decoder thread if waiting. */
|
||||
chSemSignalI(&myDemod->active_radio_object->sem);
|
||||
chBSemSignalI(&myDemod->active_radio_object->sem);
|
||||
/* Remove object reference. */
|
||||
myDemod->active_radio_object = NULL;
|
||||
} else {
|
||||
|
@ -234,20 +245,20 @@ void pktClosePWMChannelI(ICUDriver *myICU, eventflags_t evt) {
|
|||
*/
|
||||
void pktOpenPWMChannelI(ICUDriver *myICU, eventflags_t evt) {
|
||||
AFSKDemodDriver *myDemod = myICU->link;
|
||||
packet_rx_t *myHandler = myDemod->packet_handler;
|
||||
packet_svc_t *myHandler = myDemod->packet_handler;
|
||||
|
||||
/* Turn on the squelch LED. */
|
||||
pktWriteSquelchLED(PAL_HIGH);
|
||||
|
||||
/* Turn off the overflow LED. */
|
||||
pktWriteOverflowLED(PAL_LOW);
|
||||
//pktWriteOverflowLED(PAL_LOW);
|
||||
|
||||
if(myDemod->active_radio_object != NULL) {
|
||||
/* TODO: Work out correct handling.
|
||||
* Shouldn't happen unless CCA has not triggered an EXTI trailing edge.
|
||||
* For now just flag that an error condition happened.
|
||||
*/
|
||||
pktClosePWMChannelI(myICU, EVT_RADIO_CCA_FIFO_ERR);
|
||||
pktClosePWMChannelI(myICU, EVT_RADIO_CCA_FIFO_ERR, PWM_TERM_NO_RESOURCE);
|
||||
return;
|
||||
}
|
||||
/* Normal CCA handling. */
|
||||
|
@ -260,6 +271,9 @@ void pktOpenPWMChannelI(ICUDriver *myICU, eventflags_t evt) {
|
|||
*/
|
||||
pktAddEventFlagsI(myHandler, EVT_PWM_FIFO_EMPTY);
|
||||
icuDisableNotificationsI(myICU);
|
||||
|
||||
/* Turn on the FIFO out LED. */
|
||||
pktWriteNoFIFOLED(PAL_HIGH);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -272,7 +286,7 @@ void pktOpenPWMChannelI(ICUDriver *myICU, eventflags_t evt) {
|
|||
* Initialize FIFO release control semaphore.
|
||||
* The decoder thread waits on the semaphore before releasing to pool.
|
||||
*/
|
||||
chSemObjectInit(&myFIFO->sem, 0);
|
||||
chBSemObjectInit(&myFIFO->sem, true);
|
||||
|
||||
/* Each FIFO entry has an embedded input queue with data buffer. */
|
||||
(void)iqObjectInit(&myFIFO->radio_pwm_queue,
|
||||
|
@ -340,7 +354,7 @@ void pktICUInactivityTimeout(ICUDriver *myICU) {
|
|||
*/
|
||||
chSysLockFromISR();
|
||||
AFSKDemodDriver *myDemod = myICU->link;
|
||||
packet_rx_t *myHandler = myDemod->packet_handler;
|
||||
packet_svc_t *myHandler = myDemod->packet_handler;
|
||||
if(myDemod->active_radio_object == NULL) {
|
||||
pktSleepICUI(myICU);
|
||||
pktAddEventFlagsI(myHandler, EVT_ICU_SLEEP_TIMEOUT);
|
||||
|
@ -375,7 +389,7 @@ void pktPWMInactivityTimeout(ICUDriver *myICU) {
|
|||
chSysLockFromISR();
|
||||
AFSKDemodDriver *myDemod = myICU->link;
|
||||
if(myDemod->active_radio_object != NULL) {
|
||||
pktClosePWMChannelI(myICU, EVT_PWM_NO_DATA);
|
||||
pktClosePWMChannelI(myICU, EVT_PWM_NO_DATA, PWM_TERM_ICU_OVERFLOW);
|
||||
}
|
||||
chSysUnlockFromISR();
|
||||
}
|
||||
|
@ -390,15 +404,15 @@ void pktPWMInactivityTimeout(ICUDriver *myICU) {
|
|||
*/
|
||||
void pktRadioCCALeadTimer(ICUDriver *myICU) {
|
||||
chSysLockFromISR();
|
||||
//AFSKDemodDriver *myDemod = myICU->link;
|
||||
//packet_rx_t *myHandler = myDemod->packet_handler;
|
||||
AFSKDemodDriver *myDemod = myICU->link;
|
||||
packet_svc_t *myHandler = myDemod->packet_handler;
|
||||
/* CCA de-glitch timer expired. */
|
||||
switch(palReadLine(LINE_CCA)) {
|
||||
case PAL_LOW: {
|
||||
/*
|
||||
* We shouldn't arrive here unless EXTI failed to assert interrupt.
|
||||
* In that case the trailing edge callback didn't happen.
|
||||
* CAA has dropped so it is a spike.
|
||||
*/
|
||||
pktAddEventFlagsI(myHandler, EVT_RADIO_CCA_SPIKE);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -422,8 +436,8 @@ void pktRadioCCALeadTimer(ICUDriver *myICU) {
|
|||
*/
|
||||
void pktRadioCCATrailTimer(ICUDriver *myICU) {
|
||||
chSysLockFromISR();
|
||||
//AFSKDemodDriver *myDemod = myICU->link;
|
||||
|
||||
AFSKDemodDriver *myDemod = myICU->link;
|
||||
packet_svc_t *myHandler = myDemod->packet_handler;
|
||||
/* CCA de-glitch timer for trailing edge expired. */
|
||||
switch(palReadLine(LINE_CCA)) {
|
||||
case PAL_LOW: {
|
||||
|
@ -432,12 +446,13 @@ void pktRadioCCATrailTimer(ICUDriver *myICU) {
|
|||
* When the decoder ends it returns its FIFO object to the pool.
|
||||
* Closing PWM sets the FIFO management semaphore.
|
||||
*/
|
||||
pktClosePWMChannelI(myICU, EVT_RADIO_CCA_CLOSE);
|
||||
pktClosePWMChannelI(myICU, EVT_RADIO_CCA_CLOSE, PWM_TERM_CCA_CLOSE);
|
||||
break;
|
||||
}
|
||||
|
||||
case PAL_HIGH: {
|
||||
/* CCA is active again so leave PWM open. */
|
||||
pktAddEventFlagsI(myHandler, EVT_RADIO_CCA_GLITCH);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -554,15 +569,16 @@ void pktRadioICUPeriod(ICUDriver *myICU) {
|
|||
*
|
||||
*/
|
||||
if((myDemod->active_radio_object->status & EVT_AFSK_DECODE_DONE) != 0) {
|
||||
pktClosePWMChannelI(myICU, EVT_PWM_STREAM_CLOSED);
|
||||
pktClosePWMChannelI(myICU, EVT_PWM_STREAM_CLOSED, PWM_TERM_DECODE_ENDED);
|
||||
chSysUnlockFromISR();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check and write ICU values if OK. */
|
||||
msg_t qs = pktQueuePWMDataI(myICU);
|
||||
if(qs != MSG_OK) {
|
||||
pktWriteOverflowLED(PAL_HIGH);
|
||||
pktClosePWMChannelI(myICU, EVT_PWM_QUEUE_FULL);
|
||||
pktClosePWMChannelI(myICU, EVT_PWM_QUEUE_FULL, PWM_TERM_QUEUE_FULL);
|
||||
}
|
||||
chSysUnlockFromISR();
|
||||
return;
|
||||
|
@ -580,10 +596,10 @@ void pktRadioICUPeriod(ICUDriver *myICU) {
|
|||
void PktRadioICUOverflow(ICUDriver *myICU) {
|
||||
chSysLockFromISR();
|
||||
AFSKDemodDriver *myDemod = myICU->link;
|
||||
packet_rx_t *myHandler = myDemod->packet_handler;
|
||||
packet_svc_t *myHandler = myDemod->packet_handler;
|
||||
pktAddEventFlagsI(myHandler, EVT_ICU_OVERFLOW);
|
||||
if(myDemod->active_radio_object != NULL) {
|
||||
pktClosePWMChannelI(myICU, EVT_ICU_OVERFLOW);
|
||||
pktClosePWMChannelI(myICU, EVT_ICU_OVERFLOW, PWM_TERM_ICU_OVERFLOW);
|
||||
} else {
|
||||
/* Just stop the ICU notification. */
|
||||
icuDisableNotificationsI(myICU);
|
|
@ -14,8 +14,8 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
#ifndef IO_CHANNELS_RXPWM_H_
|
||||
#define IO_CHANNELS_RXPWM_H_
|
||||
#ifndef PKT_CHANNELS_RXPWM_H_
|
||||
#define PKT_CHANNELS_RXPWM_H_
|
||||
|
||||
#include "pktconf.h"
|
||||
|
||||
|
@ -23,25 +23,31 @@
|
|||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* ICU related definitions.
|
||||
*/
|
||||
|
||||
/* ICU counter frequency (2.88MHz). */
|
||||
/*
|
||||
* TODO: This should be calculated using SYSTEM CLOCK.
|
||||
* ICU has to run at an integer divide from SYSTEM CLOCK.
|
||||
*/
|
||||
#define ICU_COUNT_FREQUENCY 4000000U
|
||||
|
||||
/* Limit of ICU and PWM count for packed format. */
|
||||
#define ICU_MAX_COUNT 0xFFFFFF
|
||||
|
||||
#if USE_12_BIT_PWM == TRUE
|
||||
#define PWM_MAX_COUNT 0xFFF
|
||||
#define MAX_PWM_BITS 12
|
||||
#else
|
||||
#define PWM_MAX_COUNT 0xFFFF
|
||||
#define MAX_PWM_BITS 16
|
||||
#endif
|
||||
|
||||
/* PWM stream terminate reason codes. */
|
||||
#define PWM_TERM_CCA_CLOSE 0
|
||||
#define PWM_TERM_QUEUE_FULL 1
|
||||
#define PWM_TERM_ICU_OVERFLOW 2
|
||||
#define PWM_TERM_NO_RESOURCE 3
|
||||
#define PWM_TERM_DECODE_ENDED 4
|
||||
#define PWM_TERM_DECODE_STOP 5
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
typedef uint8_t pwm_code_t;
|
||||
|
||||
typedef enum ICUStates {
|
||||
PKT_PWM_INIT = 0,
|
||||
PKT_PWM_READY,
|
||||
|
@ -54,6 +60,7 @@ typedef uint16_t min_icucnt_t;
|
|||
typedef uint16_t min_pwmcnt_t;
|
||||
|
||||
typedef uint8_t packed_pwm_data_t;
|
||||
#if USE_12_BIT_PWM == TRUE
|
||||
typedef packed_pwm_data_t packed_pwmcnt_t;
|
||||
typedef packed_pwm_data_t packed_pwmxtn_t;
|
||||
|
||||
|
@ -64,6 +71,16 @@ typedef struct {
|
|||
packed_pwmxtn_t xtn;
|
||||
} packed_pwm_counts_t;
|
||||
|
||||
#else
|
||||
typedef min_pwmcnt_t packed_pwmcnt_t;
|
||||
|
||||
/* Structure containing packed PWM results. */
|
||||
typedef struct {
|
||||
packed_pwmcnt_t impulse;
|
||||
packed_pwmcnt_t valley;
|
||||
} packed_pwm_counts_t;
|
||||
#endif
|
||||
|
||||
/* Union of packed PWM results and byte array representation. */
|
||||
typedef union {
|
||||
packed_pwm_counts_t pwm;
|
||||
|
@ -79,21 +96,24 @@ typedef struct {
|
|||
/* Union of PWM results and byte array representation. */
|
||||
typedef union {
|
||||
min_pwm_counts_t pwm;
|
||||
min_pwmcnt_t array[sizeof(min_pwm_counts_t) / sizeof(min_pwmcnt_t)];
|
||||
min_pwmcnt_t array[sizeof(min_pwm_counts_t)
|
||||
/ sizeof(min_pwmcnt_t)];
|
||||
} array_min_pwm_counts_t;
|
||||
|
||||
/* Union of packed PWM data buffer and byte array representation. */
|
||||
typedef union {
|
||||
byte_packed_pwm_t pwm_buffer[PWM_BUFFER_SLOTS];
|
||||
packed_pwm_data_t pwm_bytes[sizeof(byte_packed_pwm_t) * PWM_BUFFER_SLOTS];
|
||||
packed_pwm_data_t pwm_bytes[sizeof(byte_packed_pwm_t)
|
||||
* PWM_BUFFER_SLOTS];
|
||||
} radio_pwm_buffer_t;
|
||||
|
||||
/* PWM FIFO object with embedded queue shared between ICU and decoder. */
|
||||
typedef struct {
|
||||
struct pool_header link; /* For safety keep clear - where pool stores its free link. */
|
||||
/* For safety keep clear - where pool stores its free link. */
|
||||
struct pool_header link;
|
||||
radio_pwm_buffer_t packed_buffer;
|
||||
input_queue_t radio_pwm_queue;
|
||||
semaphore_t sem;
|
||||
binary_semaphore_t sem;
|
||||
volatile eventflags_t status;
|
||||
} radio_cca_fifo_t;
|
||||
|
||||
|
@ -110,9 +130,11 @@ typedef struct {
|
|||
*
|
||||
* @api
|
||||
*/
|
||||
static inline void pktConvertICUtoPWM(ICUDriver *icup, byte_packed_pwm_t *dest) {
|
||||
static inline void pktConvertICUtoPWM(ICUDriver *icup,
|
||||
byte_packed_pwm_t *dest) {
|
||||
icucnt_t impulse = icuGetWidthX(icup);
|
||||
icucnt_t valley = icuGetPeriodX(icup) - impulse;
|
||||
#if USE_12_BIT_PWM == TRUE
|
||||
dest->pwm.impulse = (packed_pwmcnt_t)impulse & 0xFFU;
|
||||
dest->pwm.valley = (packed_pwmcnt_t)valley & 0xFFU;
|
||||
/*
|
||||
|
@ -123,6 +145,10 @@ static inline void pktConvertICUtoPWM(ICUDriver *icup, byte_packed_pwm_t *dest)
|
|||
impulse >>= 8;
|
||||
dest->pwm.xtn = ((packed_pwmxtn_t)(impulse) & 0x000FU);
|
||||
dest->pwm.xtn |= ((packed_pwmxtn_t)(valley) & 0x00F0U);
|
||||
#else
|
||||
dest->pwm.impulse = (packed_pwmcnt_t)impulse & 0xFFFFU;
|
||||
dest->pwm.valley = (packed_pwmcnt_t)valley & 0xFFFFU;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,13 +160,21 @@ static inline void pktConvertICUtoPWM(ICUDriver *icup, byte_packed_pwm_t *dest)
|
|||
*
|
||||
* @api
|
||||
*/
|
||||
static inline void pktUnpackPWMData(byte_packed_pwm_t src, array_min_pwm_counts_t *dest) {
|
||||
static inline void pktUnpackPWMData(byte_packed_pwm_t src,
|
||||
array_min_pwm_counts_t *dest) {
|
||||
#if USE_12_BIT_PWM == TRUE
|
||||
min_icucnt_t duration = src.pwm.impulse;
|
||||
duration |= ((min_icucnt_t)(src.pwm.xtn & 0x0FU) << 8);
|
||||
dest->pwm.impulse = duration;
|
||||
duration = src.pwm.valley;
|
||||
duration |= ((min_icucnt_t)(src.pwm.xtn & 0xF0U) << 4);
|
||||
dest->pwm.valley = duration;
|
||||
#else
|
||||
min_icucnt_t duration = src.pwm.impulse;
|
||||
dest->pwm.impulse = duration;
|
||||
duration = src.pwm.valley;
|
||||
dest->pwm.valley = duration;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -167,13 +201,23 @@ static inline msg_t pktWritePWMQueue(input_queue_t *queue,
|
|||
}
|
||||
msg_t ret_val = MSG_OK;
|
||||
if(iqGetEmptyI(queue) == qsz) {
|
||||
|
||||
/* TODO: Define in band data flags 0 & 1. */
|
||||
#if USE_12_BIT_PWM == TRUE
|
||||
if((pack.pwm.impulse + pack.pwm.valley + pack.pwm.xtn) != 0) {
|
||||
byte_packed_pwm_t eob = {{0, 1, 0}}; /* OVF flag. */
|
||||
pack = eob;
|
||||
ret_val = MSG_RESET;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if((pack.pwm.impulse + pack.pwm.valley) != 0) {
|
||||
byte_packed_pwm_t eob = {{0, 1}}; /* OVF flag. */
|
||||
pack = eob;
|
||||
ret_val = MSG_RESET;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
uint8_t b;
|
||||
for(b = 0; b < sizeof(pack.bytes); b++) {
|
||||
msg_t result = iqPutI(queue, pack.bytes[b]);
|
||||
|
@ -200,13 +244,14 @@ extern "C" {
|
|||
void pktStopAllICUTimersS(ICUDriver *myICU);
|
||||
void pktSleepICUI(ICUDriver *myICU);
|
||||
msg_t pktQueuePWMDataI(ICUDriver *myICU);
|
||||
void pktClosePWMChannelI(ICUDriver *myICU, eventflags_t evt);
|
||||
void pktClosePWMChannelI(ICUDriver *myICU, eventflags_t evt,
|
||||
pwm_code_t reason);
|
||||
void pktICUInactivityTimeout(ICUDriver *myICU);
|
||||
void pktPWMInactivityTimeout(ICUDriver *myICU);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* IO_CHANNELS_RXPWM_H_ */
|
||||
#endif /* PKT_CHANNELS_RXPWM_H_ */
|
||||
|
||||
/** @} */
|
|
@ -208,7 +208,7 @@ q31_t push_qcorr_sample(AFSKDemodDriver *myDriver, bit_t sample) {
|
|||
#if AFSK_DEBUG_TYPE == AFSK_QCORR_FIR_DEBUG
|
||||
char buf[80];
|
||||
int out = chsnprintf(buf, sizeof(buf), "%X\r\n", scaledOut);
|
||||
chnWrite(diag_out, (uint8_t *)buf, out);
|
||||
chnWrite(pkt_out, (uint8_t *)buf, out);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -262,7 +262,7 @@ bool process_qcorr_output(AFSKDemodDriver *myDriver) {
|
|||
int out = chsnprintf(buf, sizeof(buf), "%i, %i\r\n",
|
||||
myBin->cos_out, myBin->sin_out);
|
||||
}
|
||||
chnWrite(diag_out, (uint8_t *)buf, out);
|
||||
chnWrite(pkt_out, (uint8_t *)buf, out);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -292,7 +292,7 @@ bool process_qcorr_output(AFSKDemodDriver *myDriver) {
|
|||
i, decoder->filter_bins[i].mag,
|
||||
decoder->current_n,
|
||||
decoder->current_n % decoder->decode_length);
|
||||
chnWrite(diag_out, (uint8_t *)buf, out);
|
||||
chnWrite(pkt_out, (uint8_t *)buf, out);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -496,7 +496,7 @@ void calc_qcorr_magnitude(AFSKDemodDriver *myDriver) {
|
|||
int out = chsnprintf(buf, sizeof(buf), \
|
||||
"MAG SQRT failed bin %i, cosQ %X, sinQ %X, cos %f, sin %f, mag2 %f, mag %X, index %i\r\n", \
|
||||
i, myBin->cos_out, myBin->sin_out, cos, sin, mag2, raw_mag, decoder->current_n);
|
||||
chnWrite(diag_out, (uint8_t *)buf, out);
|
||||
chnWrite(pkt_out, (uint8_t *)buf, out);
|
||||
#endif /* AFSK_ERROR_TYPE == AFSK_SQRT_ERROR */
|
||||
|
||||
#else
|
||||
|
@ -516,7 +516,7 @@ void calc_qcorr_magnitude(AFSKDemodDriver *myDriver) {
|
|||
"mag2 %X, mag %X, index %i\r\n",
|
||||
i, myBin->cos_out, myBin->sin_out, cos, sin, mag2,
|
||||
decoder->filter_bins[i].raw_mag, decoder->current_n);
|
||||
chnWrite(diag_out, (uint8_t *)buf, out);
|
||||
chnWrite(pkt_out, (uint8_t *)buf, out);
|
||||
#endif /* AFSK_ERROR_TYPE == AFSK_SQRT_ERROR */
|
||||
#endif /* QCORR_MAG_USE_FLOAT */
|
||||
}
|
||||
|
@ -528,7 +528,7 @@ void calc_qcorr_magnitude(AFSKDemodDriver *myDriver) {
|
|||
} else {
|
||||
out = chsnprintf(buf, sizeof(buf), "%i\r\n", raw_mag);
|
||||
}
|
||||
chnWrite(diag_out, (uint8_t *)buf, out);
|
||||
chnWrite(pkt_out, (uint8_t *)buf, out);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -564,7 +564,7 @@ void filter_qcorr_magnitude(AFSKDemodDriver *myDriver) {
|
|||
decoder->filter_bins[i].raw_mag,
|
||||
decoder->filter_bins[i].filtered_mag);
|
||||
}
|
||||
chnWrite(diag_out, (uint8_t *)buf, out);
|
||||
chnWrite(pkt_out, (uint8_t *)buf, out);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -604,7 +604,7 @@ void evaluate_qcorr_tone(AFSKDemodDriver *myDriver) {
|
|||
char buf[200];
|
||||
int out = chsnprintf(buf, sizeof(buf), "%i, %i\r\n",
|
||||
mark, space);
|
||||
chnWrite(diag_out, (uint8_t *)buf, out);
|
||||
chnWrite(pkt_out, (uint8_t *)buf, out);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -645,7 +645,7 @@ static void setup_qcorr_prefilter(qcorr_decoder_t *decoder) {
|
|||
char buf[80];
|
||||
int out = chsnprintf(buf, sizeof(buf),
|
||||
"PRE FILTER COEFF %f %x\r\n", coeff_total_f32, coeff_total_q31);
|
||||
chnWrite(diag_out, (uint8_t *)buf, out);
|
||||
chnWrite(pkt_out, (uint8_t *)buf, out);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -776,7 +776,7 @@ static void setup_qcorr_magfilter(qcorr_decoder_t *decoder) {
|
|||
char buf[80];
|
||||
int out = chsnprintf(buf, sizeof(buf),
|
||||
"MAG FILTER COEFF %f %x\r\n", bin_coeff_total_f32, bin_coeff_total_q31);
|
||||
chnWrite(diag_out, (uint8_t *)buf, out);
|
||||
chnWrite(pkt_out, (uint8_t *)buf, out);
|
||||
#endif
|
||||
}
|
||||
#endif
|
|
@ -57,16 +57,6 @@
|
|||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Correlation diagnostics statistics.
|
||||
*
|
||||
*/
|
||||
typedef struct qStats {
|
||||
dsp_phase_t correction;
|
||||
dsp_phase_t drift_max;
|
||||
dsp_phase_t drift_min;
|
||||
} qcorr_stats_t;
|
||||
|
||||
/**
|
||||
* @brief Correlation decoder bin (tone) structure.
|
||||
*
|
||||
|
@ -110,9 +100,7 @@ typedef struct qCorrFilter {
|
|||
int32_t symbol_pll;
|
||||
int32_t prior_pll;
|
||||
#endif
|
||||
#if USE_AFSK_PHASE_STATISTICS == TRUE
|
||||
qcorr_stats_t statistics;
|
||||
#endif
|
||||
|
||||
} qcorr_decoder_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
|
@ -139,13 +127,6 @@ extern "C" {
|
|||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if USE_AFSK_PHASE_STATISTICS
|
||||
static inline qcorr_stats_t *get_qcorr_statistics(AFSKDemodDriver *myDriver) {
|
||||
qcorr_decoder_t *decoder = (qcorr_decoder_t *)myDriver->tone_decoder;
|
||||
qcorr_stats_t *statistics = &decoder->statistics;
|
||||
return statistics;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* IO_DECODERS_QCORR_H_ */
|
||||
|
|
@ -20,24 +20,6 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
#if PKT_CFG_USE_SERIAL == TRUE
|
||||
const SerialConfig debug_config = {
|
||||
115200,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
/* Declare UART aliases. */
|
||||
BaseSequentialStream* diag_out = (BaseSequentialStream*) &SD3;
|
||||
BaseSequentialStream* pkt_out = (BaseSequentialStream*) &SD4;
|
||||
|
||||
void pktSerialStart() {
|
||||
pktConfigSerialDiag();
|
||||
pktConfigSerialPkt();
|
||||
sdStart(&SD4, &debug_config);
|
||||
sdStart(&SD3, &debug_config);
|
||||
}
|
||||
#endif /* PKT_CFG_USE_SERIAL */
|
||||
|
||||
/** @} */
|
|
@ -17,19 +17,21 @@
|
|||
#ifndef DEVICES_DBGUART_H_
|
||||
#define DEVICES_DBGUART_H_
|
||||
|
||||
#include "portab.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
extern BaseSequentialStream* diag_out;
|
||||
extern BaseSequentialStream* pkt_out;
|
||||
|
||||
extern const SerialConfig debug_config;
|
||||
#define DBG_ERROR 1
|
||||
#define DBG_WARN 2
|
||||
#define DBG_INFO 3
|
||||
#define DBG_DEBUG 4
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void pktSerialStart(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -1,17 +1,19 @@
|
|||
/**
|
||||
* Si446x driver specialized for APRS transmissions. The driver supports APRS
|
||||
* transmission and receiption.
|
||||
* transmission and reception.
|
||||
* There can be either used the SLabs Si4463 or Si4464.
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
//#include "ch.h"
|
||||
//#include "hal.h"
|
||||
|
||||
#include "si446x.h"
|
||||
#include "debug.h"
|
||||
//#include "si446x.h"
|
||||
//#include "debug.h"
|
||||
#include "pktconf.h"
|
||||
|
||||
#define LINE_LENGTH 40U
|
||||
#ifdef PKT_USE_PROJECT_DEFINITIONS
|
||||
void ax25_delete(packet_t pp);
|
||||
#endif
|
||||
|
||||
// Mutex
|
||||
static mutex_t radio_mtx; // Radio mutex
|
||||
|
@ -34,12 +36,13 @@ static bool radioInitialized;
|
|||
// Receiver thread variables
|
||||
static uint32_t rx_frequency;
|
||||
static uint8_t rx_rssi;
|
||||
static uint8_t rx_chan;
|
||||
static mod_t rx_mod;
|
||||
static void (*rx_cb)(uint8_t*,uint32_t);
|
||||
static void (*rx_cb)(uint8_t*, uint32_t);
|
||||
|
||||
static thread_t* si446x_rx_thd = NULL;
|
||||
static THD_WORKING_AREA(si446x_rx_wa, 8192);
|
||||
static packet_rx_t *packetHandler;
|
||||
//static thread_t* si446x_rx_thd = NULL;
|
||||
//static THD_WORKING_AREA(si446x_rx_wa, 8192);
|
||||
static packet_svc_t *packetHandler;
|
||||
|
||||
static int16_t Si446x_getTemperature(void);
|
||||
|
||||
|
@ -53,15 +56,16 @@ static const SPIConfig ls_spicfg = {
|
|||
|
||||
static void Si446x_write(const uint8_t* txData, uint32_t len) {
|
||||
// Transmit data by SPI
|
||||
/* TODO: Add radio unit ID and get SPI accordingly. */
|
||||
uint8_t rxData[len];
|
||||
|
||||
// SPI transfer
|
||||
spiAcquireBus(&SPID3);
|
||||
spiStart(&SPID3, &ls_spicfg);
|
||||
spiAcquireBus(PKT_RADIO_SPI);
|
||||
spiStart(PKT_RADIO_SPI, &ls_spicfg);
|
||||
|
||||
spiSelect(&SPID3);
|
||||
spiExchange(&SPID3, len, txData, rxData);
|
||||
spiUnselect(&SPID3);
|
||||
spiSelect(PKT_RADIO_SPI);
|
||||
spiExchange(PKT_RADIO_SPI, len, txData, rxData);
|
||||
spiUnselect(PKT_RADIO_SPI);
|
||||
|
||||
// Reqest ACK by Si446x
|
||||
rxData[1] = 0x00;
|
||||
|
@ -71,12 +75,12 @@ static void Si446x_write(const uint8_t* txData, uint32_t len) {
|
|||
uint8_t rx_ready[] = {0x44};
|
||||
|
||||
// SPI transfer
|
||||
spiSelect(&SPID3);
|
||||
spiExchange(&SPID3, 3, rx_ready, rxData);
|
||||
spiUnselect(&SPID3);
|
||||
spiSelect(PKT_RADIO_SPI);
|
||||
spiExchange(PKT_RADIO_SPI, 3, rx_ready, rxData);
|
||||
spiUnselect(PKT_RADIO_SPI);
|
||||
}
|
||||
spiStop(&SPID3);
|
||||
spiReleaseBus(&SPID3);
|
||||
spiStop(PKT_RADIO_SPI);
|
||||
spiReleaseBus(PKT_RADIO_SPI);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,14 +88,15 @@ static void Si446x_write(const uint8_t* txData, uint32_t len) {
|
|||
*/
|
||||
static void Si446x_read(const uint8_t* txData, uint32_t txlen, uint8_t* rxData, uint32_t rxlen) {
|
||||
// Transmit data by SPI
|
||||
/* TODO: Add radio unit ID and get SPI accordingly. */
|
||||
uint8_t null_spi[txlen];
|
||||
// SPI transfer
|
||||
spiAcquireBus(&SPID3);
|
||||
spiStart(&SPID3, &ls_spicfg);
|
||||
spiAcquireBus(PKT_RADIO_SPI);
|
||||
spiStart(PKT_RADIO_SPI, &ls_spicfg);
|
||||
|
||||
spiSelect(&SPID3);
|
||||
spiExchange(&SPID3, txlen, txData, null_spi);
|
||||
spiUnselect(&SPID3);
|
||||
spiSelect(PKT_RADIO_SPI);
|
||||
spiExchange(PKT_RADIO_SPI, txlen, txData, null_spi);
|
||||
spiUnselect(PKT_RADIO_SPI);
|
||||
|
||||
// Reqest ACK by Si446x
|
||||
rxData[1] = 0x00;
|
||||
|
@ -102,12 +107,12 @@ static void Si446x_read(const uint8_t* txData, uint32_t txlen, uint8_t* rxData,
|
|||
rx_ready[0] = 0x44;
|
||||
|
||||
// SPI transfer
|
||||
spiSelect(&SPID3);
|
||||
spiExchange(&SPID3, rxlen, rx_ready, rxData);
|
||||
spiUnselect(&SPID3);
|
||||
spiSelect(PKT_RADIO_SPI);
|
||||
spiExchange(PKT_RADIO_SPI, rxlen, rx_ready, rxData);
|
||||
spiUnselect(PKT_RADIO_SPI);
|
||||
}
|
||||
spiStop(&SPID3);
|
||||
spiReleaseBus(&SPID3);
|
||||
spiStop(PKT_RADIO_SPI);
|
||||
spiReleaseBus(PKT_RADIO_SPI);
|
||||
}
|
||||
|
||||
static void Si446x_setProperty8(uint16_t reg, uint8_t val) {
|
||||
|
@ -130,35 +135,15 @@ static void Si446x_setProperty32(uint16_t reg, uint8_t val1, uint8_t val2, uint8
|
|||
Si446x_write(msg, 8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Initializes Si446x transceiver chip. Adjustes the frequency which is shifted by variable
|
||||
* Initializes Si446x transceiver chip. Adjusts the frequency which is shifted by variable
|
||||
* oscillator voltage.
|
||||
* @param mv Oscillator voltage in mv
|
||||
*/
|
||||
static void Si446x_init(void) {
|
||||
TRACE_INFO("SI > Init radio");
|
||||
dbgPrintf(DBG_INFO, "SI > Init radio\r\n");
|
||||
|
||||
// Configure Radio pins
|
||||
palSetLineMode(LINE_SPI_SCK, PAL_MODE_ALTERNATE(6) | PAL_STM32_OSPEED_HIGHEST); // SCK
|
||||
palSetLineMode(LINE_SPI_MISO, PAL_MODE_ALTERNATE(6) | PAL_STM32_OSPEED_HIGHEST); // MISO
|
||||
palSetLineMode(LINE_SPI_MOSI, PAL_MODE_ALTERNATE(6) | PAL_STM32_OSPEED_HIGHEST); // MOSI
|
||||
palSetLineMode(LINE_RADIO_CS, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); // RADIO CS
|
||||
palSetLineMode(LINE_RADIO_SDN, PAL_MODE_OUTPUT_PUSHPULL); // RADIO SDN
|
||||
|
||||
// Pull CS HIGH
|
||||
palSetLine(LINE_RADIO_CS);
|
||||
|
||||
// Reset radio
|
||||
palSetLine(LINE_RADIO_SDN);
|
||||
chThdSleep(TIME_MS2I(10));
|
||||
|
||||
// Power up transceiver
|
||||
palClearLine(LINE_RADIO_SDN); // Radio SDN low (power up transceiver)
|
||||
chThdSleep(TIME_MS2I(10)); // Wait for transceiver to power up
|
||||
pktConfigureRadioGPIO();
|
||||
|
||||
// Power up (send oscillator type)
|
||||
const uint8_t x3 = (Si446x_CCLK >> 24) & 0x0FF;
|
||||
|
@ -201,10 +186,12 @@ static void Si446x_init(void) {
|
|||
Si446x_write(unreset_fifo, 2);
|
||||
|
||||
/*
|
||||
* TODO: Move the TX and RX settings out into the relevant functions.
|
||||
* Leave only common setup and init in here.
|
||||
* TODO: Move the TX and RX settings out into the respective functions.
|
||||
* This would split up into AFSK and FSK for RX & TX.
|
||||
* Leave only common setup and init in here for selected base band frequency.
|
||||
*/
|
||||
Si446x_setProperty8(Si446x_PREAMBLE_TX_LENGTH, 0x00);
|
||||
/* TODO: Use PREAMBLE_CONFIG_NSTD, etc. to send flags? */
|
||||
Si446x_setProperty8(Si446x_SYNC_CONFIG, 0x80);
|
||||
|
||||
Si446x_setProperty8(Si446x_GLOBAL_CLK_CFG, 0x00);
|
||||
|
@ -258,12 +245,16 @@ static void Si446x_init(void) {
|
|||
|
||||
// Temperature readout
|
||||
lastTemp = Si446x_getTemperature();
|
||||
TRACE_INFO("SI > Transmitter temperature %d degC", lastTemp/100);
|
||||
dbgPrintf(DBG_INFO, "SI > Transmitter temperature %d degC\r\n", lastTemp/100);
|
||||
|
||||
radioInitialized = true;
|
||||
}
|
||||
|
||||
|
||||
void Si446x_conditional_init() {
|
||||
// Initialize radio
|
||||
if(!radioInitialized)
|
||||
Si446x_init();
|
||||
}
|
||||
|
||||
/*void init144_800(void) {
|
||||
// Configure Radio pins
|
||||
|
@ -554,7 +545,7 @@ static void Si446x_setModemAFSK_RX(void)
|
|||
Si446x_setProperty8(Si446x_MODEM_CHFLT_RX1_CHFLT_COEM2, 0x00);
|
||||
Si446x_setProperty8(Si446x_MODEM_CHFLT_RX1_CHFLT_COEM3, 0x00);
|
||||
|
||||
Si446x_setProperty8(Si446x_MODEM_CHFLT_RX2_CHFLT_COE13_7_0, 0xFF);
|
||||
/* Si446x_setProperty8(Si446x_MODEM_CHFLT_RX2_CHFLT_COE13_7_0, 0xFF);
|
||||
Si446x_setProperty8(Si446x_MODEM_CHFLT_RX2_CHFLT_COE12_7_0, 0xC4);
|
||||
Si446x_setProperty8(Si446x_MODEM_CHFLT_RX2_CHFLT_COE11_7_0, 0x30);
|
||||
Si446x_setProperty8(Si446x_MODEM_CHFLT_RX2_CHFLT_COE10_7_0, 0x7F);
|
||||
|
@ -571,7 +562,7 @@ static void Si446x_setModemAFSK_RX(void)
|
|||
Si446x_setProperty8(Si446x_MODEM_CHFLT_RX2_CHFLT_COEM0, 0x15);
|
||||
Si446x_setProperty8(Si446x_MODEM_CHFLT_RX2_CHFLT_COEM1, 0xFF);
|
||||
Si446x_setProperty8(Si446x_MODEM_CHFLT_RX2_CHFLT_COEM2, 0x00);
|
||||
Si446x_setProperty8(Si446x_MODEM_CHFLT_RX2_CHFLT_COEM3, 0x00);
|
||||
Si446x_setProperty8(Si446x_MODEM_CHFLT_RX2_CHFLT_COEM3, 0x00);*/
|
||||
}
|
||||
|
||||
static void Si446x_setModem2FSK(uint32_t speed)
|
||||
|
@ -643,20 +634,15 @@ static void Si446x_shutdown(void)
|
|||
|
||||
if(!nextTransmissionWaiting) { // No thread is waiting for radio, so shutdown radio
|
||||
|
||||
TRACE_INFO("SI > Shutdown radio");
|
||||
|
||||
palSetLineMode(LINE_SPI_SCK, PAL_MODE_INPUT_PULLDOWN); // SCK
|
||||
palSetLineMode(LINE_SPI_MISO, PAL_MODE_INPUT_PULLDOWN); // MISO
|
||||
palSetLineMode(LINE_SPI_MOSI, PAL_MODE_INPUT_PULLDOWN); // MOSI
|
||||
palSetLineMode(LINE_RADIO_CS, PAL_MODE_INPUT_PULLDOWN); // RADIO CS
|
||||
palSetLineMode(LINE_RADIO_SDN, PAL_MODE_INPUT_PULLDOWN); // RADIO SDN
|
||||
//TRACE_INFO("SI > Shutdown radio");
|
||||
pktDeconfigureRadioGPIO();
|
||||
|
||||
radioInitialized = false;
|
||||
|
||||
} else {
|
||||
|
||||
TRACE_INFO("RAD > Transmission finished");
|
||||
TRACE_INFO("RAD > Keep radio switched on");
|
||||
//TRACE_INFO("RAD > Transmission finished");
|
||||
//TRACE_INFO("RAD > Keep radio switched on");
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -707,51 +693,59 @@ static bool Si446x_getLatchedCCA(uint8_t ms)
|
|||
cca += Si446x_getCCA();
|
||||
chThdSleep(TIME_US2I(100));
|
||||
}
|
||||
TRACE_DEBUG("SI > CCA=%03d RX=%d", cca, cca > ms/10);
|
||||
//TRACE_DEBUG("SI > CCA=%03d RX=%d", cca, cca > ms/10);
|
||||
dbgPrintf(DBG_ERROR, "SI > CCA=%03d RX=%d\r\n", cca, cca > ms/10);
|
||||
return cca > ms; // Max. 1 spike per ms
|
||||
}
|
||||
|
||||
static bool Si446x_transmit(uint32_t frequency, int8_t power, uint16_t size, uint8_t rssi, sysinterval_t sql_timeout)
|
||||
{
|
||||
if(!Si446x_inRadioBand(frequency)) {
|
||||
TRACE_ERROR("SI > Frequency out of range");
|
||||
TRACE_ERROR("SI > abort transmission");
|
||||
//TRACE_ERROR("SI > Frequency out of range");
|
||||
dbgPrintf(DBG_ERROR, "SI > Frequency out of range\r\n");
|
||||
//TRACE_ERROR("SI > abort transmission");
|
||||
dbgPrintf(DBG_ERROR, "SI > abort transmission\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Switch to ready state
|
||||
if(Si446x_getState() == Si446x_STATE_RX) {
|
||||
TRACE_INFO("SI > Switch Si446x to ready state");
|
||||
//TRACE_INFO("SI > Switch Si446x to ready state");
|
||||
dbgPrintf(DBG_INFO, "SI > Switch Si446x to ready state\r\n");
|
||||
Si446x_setReadyState();
|
||||
}
|
||||
|
||||
Si446x_setProperty8(Si446x_MODEM_RSSI_THRESH, rssi);
|
||||
Si446x_setFrequency(frequency); // Set frequency
|
||||
Si446x_setPowerLevel(power); // Set power level
|
||||
Si446x_setRXState();
|
||||
|
||||
// Wait until nobody is transmitting (until timeout)
|
||||
sysinterval_t t0 = chVTGetSystemTime();
|
||||
if(Si446x_getState() != Si446x_STATE_RX || Si446x_getLatchedCCA(50)) {
|
||||
TRACE_DEBUG("SI > Wait for CCA to drop");
|
||||
//TRACE_DEBUG("SI > Wait for CCA to drop");
|
||||
dbgPrintf(DBG_INFO, "SI > Wait for CCA to drop\r\n");
|
||||
while((Si446x_getState() != Si446x_STATE_RX || Si446x_getLatchedCCA(50)) && chVTGetSystemTime()-t0 < sql_timeout)
|
||||
chThdSleep(TIME_US2I(100));
|
||||
}
|
||||
|
||||
// Transmit
|
||||
TRACE_INFO("SI > Tune Si446x (TX)");
|
||||
//TRACE_INFO("SI > Tune Si446x (TX)");
|
||||
dbgPrintf(DBG_INFO, "SI > Tune Si446x (TX)\r\n");
|
||||
Si446x_setPowerLevel(power); // Set power level
|
||||
Si446x_setReadyState();
|
||||
Si446x_setTXState(size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Si446x_receive_noLock(uint32_t frequency, uint8_t rssi, mod_t mod)
|
||||
/*static*/ bool Si446x_receive_noLock(uint32_t frequency, uint8_t rssi, mod_t mod)
|
||||
{
|
||||
if(!Si446x_inRadioBand(frequency)) {
|
||||
TRACE_ERROR("SI > Frequency out of range");
|
||||
TRACE_ERROR("SI > abort reception");
|
||||
return false;
|
||||
//TRACE_ERROR("SI > Frequency out of range");
|
||||
dbgPrintf(DBG_ERROR, "SI > Frequency out of range\r\n");
|
||||
//TRACE_ERROR("SI > abort reception");
|
||||
dbgPrintf(DBG_ERROR, "SI > abort reception\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize radio
|
||||
|
@ -768,17 +762,21 @@ static bool Si446x_receive_noLock(uint32_t frequency, uint8_t rssi, mod_t mod)
|
|||
Si446x_setModemAFSK_RX();
|
||||
} else {
|
||||
Si446x_shutdown();
|
||||
TRACE_ERROR("SI > Modulation not supported");
|
||||
TRACE_ERROR("SI > abort reception");
|
||||
//TRACE_ERROR("SI > Modulation not supported");
|
||||
dbgPrintf(DBG_ERROR, "SI > Unknown modulation\r\n");
|
||||
//TRACE_ERROR("SI > abort reception");
|
||||
dbgPrintf(DBG_ERROR, "SI > abort reception\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Preserve settings in case transceiver changes to TX state
|
||||
rx_frequency = frequency;
|
||||
rx_rssi = rssi;
|
||||
rx_chan = 0;
|
||||
rx_mod = mod;
|
||||
|
||||
TRACE_INFO("SI > Tune Si446x (RX)");
|
||||
//TRACE_INFO("SI > Tune Si446x (RX)");
|
||||
dbgPrintf(DBG_INFO, "SI > Tune Si446x (RX)\r\n");
|
||||
Si446x_setProperty8(Si446x_MODEM_RSSI_THRESH, rssi);
|
||||
Si446x_setFrequency(frequency); // Set frequency
|
||||
Si446x_setRXState();
|
||||
|
@ -803,8 +801,11 @@ static bool Si4464_restoreRX(void)
|
|||
bool ret = Si446x_receive_noLock(rx_frequency, rx_rssi, rx_mod);
|
||||
|
||||
if(packetHandler) {
|
||||
TRACE_DEBUG("SI > Start packet handler")
|
||||
pktStartDataReception(packetHandler); // Start packet handler again
|
||||
//TRACE_DEBUG("Start packet handler");
|
||||
dbgPrintf(DBG_INFO, "SI > Start packet handler\r\n");
|
||||
/* TODO: This should be handled from radio manager thread. */
|
||||
pktResumeDecoder(packetHandler);
|
||||
//pktStartDataReception(packetHandler, 0, 0x3f, NULL); // Start packet handler again
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -850,7 +851,8 @@ static uint32_t pack(uint8_t *inbuf, uint32_t inlen, uint8_t* buf, uint32_t buf_
|
|||
for(uint8_t j=0; j<8; j++) {
|
||||
|
||||
if(blen >> 3 >= buf_len) { // Buffer overflow
|
||||
TRACE_ERROR("Packet too long");
|
||||
//TRACE_ERROR("Packet too long");
|
||||
dbgPrintf(DBG_ERROR, "SI > Packet too long\r\n");
|
||||
return blen;
|
||||
}
|
||||
|
||||
|
@ -870,7 +872,8 @@ static uint32_t pack(uint8_t *inbuf, uint32_t inlen, uint8_t* buf, uint32_t buf_
|
|||
while(pos < inlen*8)
|
||||
{
|
||||
if(blen >> 3 >= buf_len) { // Buffer overflow
|
||||
TRACE_ERROR("Packet too long");
|
||||
//TRACE_ERROR("Packet too long");
|
||||
dbgPrintf(DBG_ERROR, "SI > Packet too long\r\n");
|
||||
return blen;
|
||||
}
|
||||
|
||||
|
@ -904,7 +907,8 @@ static uint32_t pack(uint8_t *inbuf, uint32_t inlen, uint8_t* buf, uint32_t buf_
|
|||
for(uint8_t j=0; j<8; j++) {
|
||||
|
||||
if(blen >> 3 >= buf_len) { // Buffer overflow
|
||||
TRACE_ERROR("Packet too long");
|
||||
//TRACE_ERROR("Packet too long");
|
||||
dbgPrintf(DBG_ERROR, "SI > Packet too long\r\n");
|
||||
return blen;
|
||||
}
|
||||
|
||||
|
@ -975,7 +979,7 @@ THD_FUNCTION(si_fifo_feeder_afsk, arg)
|
|||
// Start transmission
|
||||
Si446x_transmit(radio_freq, radio_pwr, all, 0x4F, TIME_S2I(10));
|
||||
|
||||
while(c < all && Si446x_getState() == Si446x_STATE_TX) { // Do while bytes not written into FIFO completely
|
||||
while(c < all) { // Do while bytes not written into FIFO completely
|
||||
// Determine free memory in Si446x-FIFO
|
||||
uint8_t more = Si446x_freeFIFO();
|
||||
if(more > all-c) {
|
||||
|
@ -991,13 +995,9 @@ THD_FUNCTION(si_fifo_feeder_afsk, arg)
|
|||
chThdSleep(TIME_MS2I(15));
|
||||
}
|
||||
|
||||
if(c < all) {
|
||||
TRACE_ERROR("SI > Packet was not sent completly");
|
||||
}
|
||||
|
||||
/*
|
||||
* Shutdown radio if receiption has been interrupted. If receiption was interrupted rx_frequency is set.
|
||||
* If receiption has not been interrupted rx_frequency is set 0.
|
||||
* Shutdown radio if reception has been interrupted. If reception was interrupted rx_frequency is set.
|
||||
* If reception has not been interrupted rx_frequency is set 0.
|
||||
*/
|
||||
if(!rx_frequency) {
|
||||
Si446x_shutdown();
|
||||
|
@ -1007,7 +1007,6 @@ THD_FUNCTION(si_fifo_feeder_afsk, arg)
|
|||
|
||||
// Free packet object memory
|
||||
ax25_delete(pp);
|
||||
|
||||
chThdExit(MSG_OK);
|
||||
}
|
||||
|
||||
|
@ -1016,8 +1015,10 @@ void Si446x_sendAFSK(/*uint8_t *frame, uint32_t len*/packet_t pp, uint32_t freq,
|
|||
|
||||
// Stop packet handler (if started)
|
||||
if(packetHandler) {
|
||||
TRACE_DEBUG("SI > Stop packet handler")
|
||||
pktStopDataReception(packetHandler);
|
||||
//TRACE_DEBUG("Stop packet handler");
|
||||
dbgPrintf(DBG_INFO, "SI > Stop packet handler\r\n");
|
||||
pktPauseDecoder(packetHandler);
|
||||
//pktStopDataReception(packetHandler);
|
||||
}
|
||||
|
||||
// Initialize radio
|
||||
|
@ -1052,186 +1053,41 @@ void Si446x_sendAFSK(/*uint8_t *frame, uint32_t len*/packet_t pp, uint32_t freq,
|
|||
|
||||
/* ===================================================================== AFSK Receiver ====================================================================== */
|
||||
|
||||
THD_FUNCTION(si_receiver, arg)
|
||||
{
|
||||
(void)arg;
|
||||
void Si446x_mapCallback(pkt_data_object_t *pkt_buff) {
|
||||
/* Packet buffer. */
|
||||
ax25char_t *frame_buffer = pkt_buff->buffer;
|
||||
uint16_t frame_size = pkt_buff->packet_size;
|
||||
|
||||
chRegSetThreadName("radio_receiver");
|
||||
|
||||
/* Buffer and size params for serial terminal output. */
|
||||
char serial_buf[512];
|
||||
int serial_out;
|
||||
|
||||
/*
|
||||
* Setup the parameters for the AFSK decoder thread.
|
||||
* TODO: Radio configuration to be implemented in pktOpenReceiveChannel().
|
||||
*/
|
||||
|
||||
radio_config_t afsk_radio = { PKT_RADIO_1 };
|
||||
char frameCounter = 'A';
|
||||
|
||||
/* set packet instance assignment(s). */
|
||||
pktInitReceiveChannels();
|
||||
|
||||
packetHandler = pktOpenReceiveChannel(DECODE_AFSK, &afsk_radio);
|
||||
chDbgAssert(packetHandler != NULL, "invalid packet type");
|
||||
|
||||
thread_t *the_decoder = ((AFSKDemodDriver *)packetHandler->link_controller)->decoder_thd;
|
||||
chDbgAssert(the_decoder != NULL, "no decoder assigned");
|
||||
|
||||
event_source_t *events = pktGetEventSource(packetHandler);
|
||||
|
||||
/* Start the decoder. */
|
||||
msg_t pstart = pktStartDataReception(packetHandler);
|
||||
|
||||
TRACE_DEBUG("RX > Starting decoder: start status %i, event source @ %x", pstart, events);
|
||||
|
||||
/* Main loop. */
|
||||
while (true) {
|
||||
frameCounter = ((frameCounter+1-'A') % 26) + 'A';
|
||||
|
||||
pkt_data_fifo_t *myPktFIFO = pktReceiveDataBufferTimeout(packetHandler, TIME_MS2I(1000));
|
||||
if(myPktFIFO == NULL) {
|
||||
continue;
|
||||
}
|
||||
/* Packet buffer sent via FIFO. */
|
||||
ax25char_t *frame_buffer = myPktFIFO->buffer;
|
||||
uint16_t frame_size = myPktFIFO->packet_size;
|
||||
eventmask_t the_events;
|
||||
packetHandler->frame_count++;
|
||||
if(pktIsBufferValidAX25Frame(myPktFIFO) == MSG_OK) {
|
||||
the_events = EVT_DIAG_OUT_END | EVT_PKT_OUT_END;
|
||||
uint16_t actualCRC = frame_buffer[frame_size - 2] | (frame_buffer[frame_size - 1] << 8);
|
||||
uint16_t computeCRC = calc_crc16(frame_buffer, 0, frame_size - 2);
|
||||
uint16_t magicCRC = calc_crc16(frame_buffer, 0, frame_size);
|
||||
if(magicCRC == CRC_INCLUSIVE_CONSTANT)
|
||||
packetHandler->valid_count++;
|
||||
float32_t good = (float32_t)packetHandler->valid_count / (float32_t)packetHandler->packet_count;
|
||||
/* Write out the buffer data.
|
||||
* TODO: Have a define to put diagnostic data into AX25 buffer object.
|
||||
*/
|
||||
TRACE_DEBUG(
|
||||
"RX %c > AFSK capture: status 0x%08x"
|
||||
", packet count %u frame count %u valid frames %u (%.2f%%) bytes %u"
|
||||
", CRCr %04x, CRCc %04x (%s), CRCm %04x",
|
||||
frameCounter,
|
||||
myPktFIFO->status,
|
||||
packetHandler->packet_count,
|
||||
packetHandler->frame_count,
|
||||
packetHandler->valid_count,
|
||||
(good * 100),
|
||||
frame_size,
|
||||
actualCRC,
|
||||
computeCRC,
|
||||
(actualCRC == computeCRC ? "good" : "bad"),
|
||||
magicCRC
|
||||
);
|
||||
|
||||
uint16_t bufpos;
|
||||
uint16_t bufpos_a = 0;
|
||||
serial_out = 0;
|
||||
/* Write out a buffer line as hex first. */
|
||||
for(bufpos = 0; bufpos < frame_size; bufpos++) {
|
||||
if((bufpos + 1) % LINE_LENGTH == 0) {
|
||||
serial_out += chsnprintf(&serial_buf[serial_out], sizeof(serial_buf)-serial_out, "%02x", frame_buffer[bufpos]);
|
||||
TRACE_DEBUG("RX %c > %s", frameCounter, serial_buf);
|
||||
serial_out = 0;
|
||||
/* Write out full line of converted ASCII under hex.*/
|
||||
bufpos_a = (bufpos + 1) - LINE_LENGTH;
|
||||
do {
|
||||
char asciichar = frame_buffer[bufpos_a];
|
||||
if(asciichar == 0x7e) {
|
||||
asciichar = '^';
|
||||
} else {
|
||||
asciichar >>= 1;
|
||||
if(!((asciichar >= 0x70 && asciichar < 0x7a) || (asciichar > 0x2f && asciichar < 0x3a) || (asciichar > 0x40 && asciichar < 0x5b))) {
|
||||
asciichar = 0x20;
|
||||
} else if(asciichar >= 0x70 && asciichar < 0x7a) {
|
||||
asciichar &= 0x3f;
|
||||
}
|
||||
}
|
||||
if((bufpos_a + 1) % LINE_LENGTH == 0) {
|
||||
serial_out += chsnprintf(&serial_buf[serial_out], sizeof(serial_buf)-serial_out, " %c", asciichar);
|
||||
TRACE_DEBUG("RX %c > %s", frameCounter, serial_buf);
|
||||
serial_out = 0;
|
||||
} else {
|
||||
serial_out += chsnprintf(&serial_buf[serial_out], sizeof(serial_buf)-serial_out, " %c ", asciichar);
|
||||
}
|
||||
} while(bufpos_a++ < bufpos);
|
||||
} else {
|
||||
serial_out += chsnprintf(&serial_buf[serial_out], sizeof(serial_buf)-serial_out, "%02x ", frame_buffer[bufpos]);
|
||||
}
|
||||
} /* End for(bufpos = 0; bufpos < frame_size; bufpos++). */
|
||||
|
||||
TRACE_DEBUG("RX %c > %s", frameCounter, serial_buf);
|
||||
serial_out = 0;
|
||||
/* Write out remaining partial line of converted ASCII under hex. */
|
||||
|
||||
do {
|
||||
char asciichar = frame_buffer[bufpos_a];
|
||||
if(asciichar == 0x7e) {
|
||||
asciichar = '^';
|
||||
} else {
|
||||
asciichar >>= 1;
|
||||
if(!((asciichar >= 0x70 && asciichar < 0x7a) || (asciichar > 0x2f && asciichar < 0x3a) || (asciichar > 0x40 && asciichar < 0x5b))) {
|
||||
asciichar = 0x20;
|
||||
} else if(asciichar >= 0x70 && asciichar < 0x7a) {
|
||||
asciichar &= 0x3f;
|
||||
}
|
||||
}
|
||||
serial_out += chsnprintf(&serial_buf[serial_out], sizeof(serial_buf)-serial_out, " %c ", asciichar);
|
||||
} while(++bufpos_a < bufpos);
|
||||
TRACE_DEBUG("RX %c > %s", frameCounter, serial_buf);
|
||||
|
||||
|
||||
if(actualCRC == computeCRC) {
|
||||
rx_cb(frame_buffer, frame_size);
|
||||
}
|
||||
|
||||
} else {/* End if valid frame. */
|
||||
the_events = EVT_DIAG_OUT_END;
|
||||
TRACE_DEBUG("RX %c > Invalid frame, status 0x%08x, bytes %u", frameCounter, myPktFIFO->status, myPktFIFO->packet_size);
|
||||
}
|
||||
|
||||
#if SUSPEND_HANDLING == RELEASE_ON_OUTPUT
|
||||
/*
|
||||
* Wait for end of transmission on diagnostic channel.
|
||||
*/
|
||||
eventmask_t evt = chEvtWaitAllTimeout(the_events, TIME_S2I(10));
|
||||
if (!evt) {
|
||||
TRACE_ERROR("RX > FAIL: Timeout waiting for EOT from serial channels");
|
||||
}
|
||||
chEvtSignal(the_decoder, EVT_SUSPEND_EXIT);
|
||||
#else
|
||||
(void)the_events;
|
||||
/* TODO: This is a quick diagnostic implementation only. */
|
||||
#if DUMP_PACKET_TO_SERIAL == TRUE
|
||||
pktDiagnosticOutput(pkt_buff->handler, pkt_buff);
|
||||
#endif
|
||||
pktReleaseDataBuffer(packetHandler, myPktFIFO);
|
||||
if(packetHandler->packet_count % 100 == 0 && packetHandler->packet_count != 0) {
|
||||
/* Stop the decoder. */
|
||||
msg_t pmsg = pktStopDataReception(packetHandler);
|
||||
TRACE_DEBUG("RX > Decoder STOP %i", pmsg);
|
||||
if(packetHandler->packet_count % 1000 == 0 && packetHandler->packet_count != 0) {
|
||||
chThdSleep(TIME_S2I(5));
|
||||
pmsg = pktCloseReceiveChannel(packetHandler);
|
||||
TRACE_DEBUG("RX > Decoder CLOSE %i\r\n", pmsg);
|
||||
chThdSleep(TIME_S2I(5));
|
||||
packetHandler = pktOpenReceiveChannel(DECODE_AFSK, &afsk_radio);
|
||||
TRACE_DEBUG("RX > Decoder OPEN %x", packetHandler);
|
||||
}
|
||||
chThdSleep(TIME_S2I(5));
|
||||
pmsg = pktStartDataReception(packetHandler);
|
||||
TRACE_DEBUG("RX > Decoder START %i", pmsg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform the callback. */
|
||||
rx_cb(frame_buffer, frame_size);
|
||||
}
|
||||
|
||||
void Si446x_startDecoder(void* cb) {
|
||||
void Si446x_startDecoder(radio_freq_t freq, radio_squelch_t sq, void* cb) {
|
||||
|
||||
rx_cb = cb;
|
||||
|
||||
// Start receiver thread
|
||||
if(si446x_rx_thd == NULL)
|
||||
si446x_rx_thd = chThdCreateStatic(si446x_rx_wa, sizeof(si446x_rx_wa),
|
||||
NORMALPRIO, si_receiver, NULL);
|
||||
/* Start serial channels. */
|
||||
pktSerialStart();
|
||||
|
||||
pktServiceCreate();
|
||||
|
||||
/* Open packet radio service. */
|
||||
pktOpenRadioService(PKT_RADIO_1,
|
||||
DECODE_AFSK,
|
||||
freq,
|
||||
PKT_RADIO_CHANNEL_STEPPING_NONE,
|
||||
&packetHandler);
|
||||
|
||||
/* Start the decoder. */
|
||||
pktStartDataReception(packetHandler,
|
||||
94,
|
||||
sq,
|
||||
Si446x_mapCallback);
|
||||
}
|
||||
|
||||
void Si446x_stopDecoder(void) {
|
||||
|
@ -1270,8 +1126,8 @@ THD_FUNCTION(si_fifo_feeder_fsk, arg)
|
|||
}*/
|
||||
|
||||
/*
|
||||
* Shutdown radio if receiption has been interrupted. If receiption was interrupted rx_frequency is set.
|
||||
* If receiption has not been interrupted rx_frequency is set 0.
|
||||
* Shutdown radio if reception has been interrupted. If reception was interrupted rx_frequency is set.
|
||||
* If reception has not been interrupted rx_frequency is set 0.
|
||||
*/
|
||||
if(!rx_frequency) {
|
||||
Si446x_shutdown();
|
||||
|
@ -1291,7 +1147,8 @@ void Si446x_send2FSK(/*uint8_t *frame, uint32_t len*/packet_t pp, uint32_t freq,
|
|||
|
||||
// Stop packet handler (if started)
|
||||
if(packetHandler)
|
||||
pktStopDataReception(packetHandler);
|
||||
//pktStopDataReception(packetHandler);
|
||||
pktPauseDecoder(packetHandler);
|
||||
|
||||
// Initialize radio
|
||||
if(!radioInitialized)
|
||||
|
@ -1337,3 +1194,4 @@ int16_t Si446x_getLastTemperature(void) {
|
|||
return lastTemp;
|
||||
}
|
||||
|
||||
//#endif
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef __si446x__H__
|
||||
#define __si446x__H__
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "types.h"
|
||||
//#include "ch.h"
|
||||
//#include "hal.h"
|
||||
//#include "types.h"
|
||||
|
||||
#ifndef Si446x_CLK
|
||||
#error Si446x_CLK is not defined which is needed for Si446x.
|
||||
|
@ -156,6 +156,11 @@
|
|||
#define Si446x_FREQ_CONTROL_W_SIZE 0x4006
|
||||
#define Si446x_FREQ_CONTROL_VCOCNT_RX_ADJ 0x4007
|
||||
|
||||
#define RADIO_TASK_QUEUE_MAX 3
|
||||
|
||||
#define PKT_SI446X_APRS_CHANNEL 94
|
||||
#define PKT_SI446X_SQUELCH_LEVEL 0x4F
|
||||
|
||||
// Public methods
|
||||
|
||||
int16_t Si446x_getLastTemperature(void);
|
||||
|
@ -164,11 +169,11 @@ void Si446x_sendAFSK(/*uint8_t *frame, uint32_t len*/packet_t pp, uint32_t freq,
|
|||
void Si446x_send2FSK(/*uint8_t *frame, uint32_t len*/packet_t pp, uint32_t freq, uint8_t pwr, uint32_t speed);
|
||||
|
||||
bool Si446x_receive(uint32_t frequency, uint8_t rssi, mod_t mod);
|
||||
void Si446x_startDecoder(void* cb);
|
||||
void Si446x_startDecoder(uint32_t freq, uint8_t sq, void* cb);
|
||||
void Si446x_stopDecoder(void);
|
||||
|
||||
bool Si446x_receive_noLock(uint32_t frequency, uint8_t rssi, mod_t mod);
|
||||
void unlockRadio(void);
|
||||
void lockRadioByCamera(void);
|
||||
|
||||
void Si446x_conditional_init(void);
|
||||
#endif
|
||||
|
|
@ -20,6 +20,9 @@
|
|||
char serial_buf[1024];
|
||||
int serial_out;
|
||||
|
||||
/* Access control semaphore. */
|
||||
extern binary_semaphore_t callback_sem;
|
||||
|
||||
void pktDumpAX25Frame(ax25char_t *frame_buffer,
|
||||
ax25size_t frame_size, ax25_select_t which) {
|
||||
if(which == AX25_DUMP_ALL || which == AX25_DUMP_RAW) {
|
||||
|
@ -30,7 +33,7 @@ void pktDumpAX25Frame(ax25char_t *frame_buffer,
|
|||
if((bufpos + 1) % DUMP_LINE_LENGTH == 0) {
|
||||
serial_out = chsnprintf(serial_buf, sizeof(serial_buf),
|
||||
"%02x\r\n", frame_buffer[bufpos]);
|
||||
chnWrite(diag_out, (uint8_t *)serial_buf, serial_out);
|
||||
pktWrite((uint8_t *)serial_buf, serial_out);
|
||||
/* Write out full line of converted ASCII under hex.*/
|
||||
bufpos_a = (bufpos + 1) - DUMP_LINE_LENGTH;
|
||||
do {
|
||||
|
@ -47,7 +50,7 @@ void pktDumpAX25Frame(ax25char_t *frame_buffer,
|
|||
asciichar &= 0x3f;
|
||||
}
|
||||
}
|
||||
if((bufpos_a + 1) % LINE_LENGTH == 0) {
|
||||
if((bufpos_a + 1) % DUMP_LINE_LENGTH == 0) {
|
||||
serial_out = chsnprintf(serial_buf,
|
||||
sizeof(serial_buf),
|
||||
" %c\r\n", asciichar);
|
||||
|
@ -56,16 +59,16 @@ void pktDumpAX25Frame(ax25char_t *frame_buffer,
|
|||
sizeof(serial_buf),
|
||||
" %c ", asciichar);
|
||||
}
|
||||
chnWrite(diag_out, (uint8_t *)serial_buf, serial_out);
|
||||
pktWrite((uint8_t *)serial_buf, serial_out);
|
||||
} while(bufpos_a++ < bufpos);
|
||||
} else {
|
||||
serial_out = chsnprintf(serial_buf, sizeof(serial_buf),
|
||||
"%02x ", frame_buffer[bufpos]);
|
||||
chnWrite(diag_out, (uint8_t *)serial_buf, serial_out);
|
||||
pktWrite((uint8_t *)serial_buf, serial_out);
|
||||
}
|
||||
} /* End for(bufpos = 0; bufpos < frame_size; bufpos++). */
|
||||
serial_out = chsnprintf(serial_buf, sizeof(serial_buf), "\r\n");
|
||||
chnWrite(diag_out, (uint8_t *)serial_buf, serial_out);
|
||||
pktWrite((uint8_t *)serial_buf, serial_out);
|
||||
/* Write out remaining partial line of converted ASCII under hex. */
|
||||
do {
|
||||
char asciichar = frame_buffer[bufpos_a];
|
||||
|
@ -83,53 +86,76 @@ void pktDumpAX25Frame(ax25char_t *frame_buffer,
|
|||
}
|
||||
serial_out = chsnprintf(serial_buf, sizeof(serial_buf),
|
||||
" %c ", asciichar);
|
||||
chnWrite(diag_out, (uint8_t *)serial_buf, serial_out);
|
||||
pktWrite((uint8_t *)serial_buf, serial_out);
|
||||
} while(++bufpos_a < bufpos);
|
||||
serial_out = chsnprintf(serial_buf, sizeof(serial_buf), "\r\n");
|
||||
chnWrite(diag_out, (uint8_t *)serial_buf, serial_out);
|
||||
pktWrite((uint8_t *)serial_buf, serial_out);
|
||||
} /* End raw dump. */
|
||||
|
||||
if(which == AX25_DUMP_ALL || which == AX25_DUMP_APRS) {
|
||||
uint16_t magicCRC = calc_crc16(frame_buffer, 0, frame_size);
|
||||
if(magicCRC == CRC_INCLUSIVE_CONSTANT) {
|
||||
/* CRC is good => decode APRS packet */
|
||||
packet_t pp = ax25_from_frame(frame_buffer, frame_size - 2);
|
||||
if(pp != NULL) {
|
||||
char rec[1024];
|
||||
unsigned char *pinfo;
|
||||
ax25_format_addrs(pp, rec);
|
||||
ax25_get_info(pp, &pinfo);
|
||||
serial_out = chsnprintf(serial_buf, sizeof(serial_buf),
|
||||
"%s", rec);
|
||||
chnWrite(diag_out, (uint8_t *)serial_buf, serial_out);
|
||||
for(uint32_t i=0; pinfo[i]; i++) {
|
||||
if(pinfo[i] < 32 || pinfo[i] > 126) {
|
||||
/* Printable char */
|
||||
serial_out = chsnprintf(serial_buf,
|
||||
sizeof(serial_buf),
|
||||
"<0x%02x>", pinfo[i]);
|
||||
} else {
|
||||
serial_out = chsnprintf(serial_buf,
|
||||
sizeof(serial_buf),
|
||||
"%c", pinfo[i]);
|
||||
}
|
||||
chnWrite(diag_out, (uint8_t *)serial_buf, serial_out);
|
||||
}
|
||||
serial_out = chsnprintf(serial_buf, sizeof(serial_buf),
|
||||
"\r\n");
|
||||
chnWrite(diag_out, (uint8_t *)serial_buf, serial_out);
|
||||
ax25_delete(pp);
|
||||
} else {
|
||||
serial_out = chsnprintf(serial_buf, sizeof(serial_buf),
|
||||
"APRS: Error in packet\r\n");
|
||||
chnWrite(diag_out, (uint8_t *)serial_buf, serial_out);
|
||||
}
|
||||
} else {
|
||||
serial_out = chsnprintf(serial_buf, sizeof(serial_buf),
|
||||
"APRS: Bad CRC\r\n");
|
||||
chnWrite(diag_out, (uint8_t *)serial_buf, serial_out);
|
||||
} /* End CRC check. */
|
||||
} /* End APRS dump. */
|
||||
}
|
||||
|
||||
|
||||
void pktDiagnosticOutput(packet_svc_t *packetHandler,
|
||||
pkt_data_object_t *myPktFIFO) {
|
||||
chBSemWait(&callback_sem);
|
||||
/* Buffer and size params for serial terminal output. */
|
||||
char serial_buf[1024];
|
||||
int serial_out;
|
||||
|
||||
/* Packet buffer. */
|
||||
ax25char_t *frame_buffer = myPktFIFO->buffer;
|
||||
uint16_t frame_size = myPktFIFO->packet_size;
|
||||
eventmask_t the_events;
|
||||
|
||||
if(pktIsBufferValidAX25Frame(myPktFIFO)) {
|
||||
the_events = EVT_DIAG_OUT_END | EVT_PKT_OUT_END;
|
||||
uint16_t magicCRC = calc_crc16(frame_buffer, 0, frame_size);
|
||||
|
||||
float32_t good = (float32_t)packetHandler->good_count
|
||||
/ (float32_t)packetHandler->valid_count;
|
||||
serial_out = chsnprintf(serial_buf, sizeof(serial_buf),
|
||||
"AFSK... mode: %s, factory: %s, status: %x"
|
||||
", packet count: %u sync count: %u"
|
||||
" valid frames: %u"
|
||||
" good frames: %u (%.2f%%), bytes: %u"
|
||||
", CRCm: %04x\r\n",
|
||||
((packetHandler->usr_callback == NULL) ? "polling" : "callback"),
|
||||
packetHandler->pbuff_name,
|
||||
myPktFIFO->status,
|
||||
packetHandler->sync_count,
|
||||
packetHandler->frame_count,
|
||||
packetHandler->valid_count,
|
||||
packetHandler->good_count,
|
||||
(good * 100),
|
||||
frame_size,
|
||||
magicCRC
|
||||
);
|
||||
dbgWrite(DBG_INFO, (uint8_t *)serial_buf, serial_out);
|
||||
/* Dump the frame contents out. */
|
||||
pktDumpAX25Frame(frame_buffer, frame_size, AX25_DUMP_RAW);
|
||||
} else { /* End if valid frame. */
|
||||
the_events = EVT_DIAG_OUT_END;
|
||||
serial_out = chsnprintf(serial_buf, sizeof(serial_buf),
|
||||
"Invalid frame, status %x, bytes %u\r\n",
|
||||
myPktFIFO->status, myPktFIFO->packet_size);
|
||||
dbgWrite(DBG_INFO, (uint8_t *)serial_buf, serial_out);
|
||||
}
|
||||
|
||||
#if SUSPEND_HANDLING == RELEASE_ON_OUTPUT
|
||||
/*
|
||||
* Wait for end of transmission on diagnostic channel.
|
||||
*/
|
||||
eventmask_t evt = chEvtWaitAllTimeout(the_events, TIME_S2I(10));
|
||||
if (!evt) {
|
||||
serial_out = chsnprintf(serial_buf, sizeof(serial_buf),
|
||||
"FAIL: Timeout waiting for EOT from serial channels\r\n");
|
||||
dbgWrite(DBG_INFO, (uint8_t *)serial_buf, serial_out);
|
||||
}
|
||||
chEvtSignal(the_decoder, DEC_SUSPEND_EXIT);
|
||||
#else
|
||||
(void)the_events;
|
||||
#endif
|
||||
chBSemSignal(&callback_sem);
|
||||
}
|
||||
|
||||
|
||||
/** @} */
|
|
@ -15,8 +15,8 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
#ifndef IO_PROTOCOLS_AX25_DUMP_H_
|
||||
#define IO_PROTOCOLS_AX25_DUMP_H_
|
||||
#ifndef PKT_PROTOCOLS_AX25_DUMP_H_
|
||||
#define PKT_PROTOCOLS_AX25_DUMP_H_
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
|
@ -52,6 +52,8 @@ extern "C" {
|
|||
#endif
|
||||
void pktDumpAX25Frame(ax25char_t *frame_buffer, ax25size_t frame_size,
|
||||
ax25_select_t which);
|
||||
void pktDiagnosticOutput(packet_svc_t *packetHandler,
|
||||
pkt_data_object_t *pkt_buffer);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -61,6 +63,6 @@ extern "C" {
|
|||
/*===========================================================================*/
|
||||
|
||||
|
||||
#endif /* IO_PROTOCOLS_AX25_DUMP_H_ */
|
||||
#endif /* PKT_PROTOCOLS_AX25_DUMP_H_ */
|
||||
|
||||
/** @} */
|
|
@ -14,8 +14,8 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
#ifndef IO_FILTERS_DSP_H_
|
||||
#define IO_FILTERS_DSP_H_
|
||||
#ifndef PKT_FILTERS_DSP_H_
|
||||
#define PKT_FILTERS_DSP_H_
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
|
@ -79,6 +79,6 @@ typedef enum fd_window_e {
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif /* IO_FILTERS_DSP_H_ */
|
||||
#endif /* PKT_FILTERS_DSP_H_ */
|
||||
|
||||
/** @} */
|
|
@ -0,0 +1,286 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file pktradio.c
|
||||
* @brief Radio manager.
|
||||
*
|
||||
* @addtogroup managers
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "pktconf.h"
|
||||
|
||||
/*
|
||||
* The radio manager thread.
|
||||
*/
|
||||
THD_FUNCTION(pktRadioManager, arg) {
|
||||
dyn_objects_fifo_t *the_radio_fifo = arg;
|
||||
|
||||
chDbgCheck(arg != NULL);
|
||||
|
||||
bool rx_active = false;
|
||||
|
||||
objects_fifo_t *radio_queue = chFactoryGetObjectsFIFO(the_radio_fifo);
|
||||
|
||||
chDbgAssert(radio_queue != NULL, "no queue in radio manager FIFO");
|
||||
|
||||
while(!chThdShouldTerminateX()) {
|
||||
/* Check for task requests. */
|
||||
radio_task_object_t *task_object;
|
||||
msg_t fifo_msg = chFifoReceiveObjectTimeout(radio_queue,
|
||||
(void *)&task_object,
|
||||
TIME_MS2I(100));
|
||||
if(fifo_msg == MSG_TIMEOUT)
|
||||
continue;
|
||||
|
||||
/* Something to do. object pointer is in fifo_msg. */
|
||||
|
||||
packet_svc_t *handler = task_object->handler;
|
||||
|
||||
/* TODO: Use radio ID to determine handling... later. */
|
||||
switch(task_object->command) {
|
||||
case PKT_RADIO_OPEN: {
|
||||
/* Create the packet management services. */
|
||||
pktBufferManagerCreate(handler);
|
||||
pktCallbackManagerCreate(handler);
|
||||
switch(task_object->type) {
|
||||
case DECODE_AFSK: {
|
||||
/*
|
||||
* Create the AFSK decoder (includes PWM, filters, etc.).
|
||||
*/
|
||||
AFSKDemodDriver *driver = pktCreateAFSKDecoder(handler);
|
||||
handler->link_controller = driver;
|
||||
chDbgCheck(driver != NULL);
|
||||
/* TODO: Implement thread events or callback for results. */
|
||||
if(driver == NULL) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
} /* End case. */
|
||||
|
||||
case DECODE_NOT_SET:
|
||||
case DECODE_FSK: {
|
||||
break;
|
||||
}
|
||||
} /* End switch. */
|
||||
Si446x_conditional_init();
|
||||
break;
|
||||
}
|
||||
|
||||
/* TODO: Switch on encoding. Tune radio to channel. */
|
||||
case PKT_RADIO_RX: {
|
||||
pktStartDecoder(handler);
|
||||
radio_squelch_t sq = task_object->squelch;
|
||||
radio_freq_t freq = task_object->base_frequency;
|
||||
Si446x_receive_noLock(freq, sq, MOD_AFSK);
|
||||
rx_active = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PKT_RADIO_RX_STOP: {
|
||||
pktStopDecoder(handler);
|
||||
rx_active = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case PKT_RADIO_TX: {
|
||||
/* TODO: Switch on encoding. */
|
||||
if(rx_active)
|
||||
pktPauseDecoder(handler);
|
||||
|
||||
/* Transmit here... */
|
||||
|
||||
if(rx_active)
|
||||
pktResumeDecoder(handler);
|
||||
break;
|
||||
}
|
||||
|
||||
case PKT_RADIO_CLOSE: {
|
||||
event_listener_t el;
|
||||
event_source_t *esp;
|
||||
thread_t *decoder = NULL;
|
||||
switch(task_object->type) {
|
||||
case DECODE_AFSK: {
|
||||
esp = pktGetEventSource((AFSKDemodDriver *)handler->link_controller);
|
||||
|
||||
pktRegisterEventListener(esp, &el, USR_COMMAND_ACK, DEC_CLOSE_EXEC);
|
||||
|
||||
decoder = ((AFSKDemodDriver *)(handler->link_controller))->decoder_thd;
|
||||
|
||||
/* Send event to release AFSK resources and terminate thread. */
|
||||
chEvtSignal(decoder, DEC_COMMAND_CLOSE);
|
||||
|
||||
/* Then release common services and thread heap. */
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODE_NOT_SET:
|
||||
case DECODE_FSK: {
|
||||
break;
|
||||
} /* End case DECODE_FSK. */
|
||||
} /* End switch on link_type. */
|
||||
if(decoder == NULL)
|
||||
/* No decoder processed. */
|
||||
break;
|
||||
|
||||
/* Wait for the decoder to stop. */
|
||||
eventflags_t evt;
|
||||
do {
|
||||
chEvtWaitAny(USR_COMMAND_ACK);
|
||||
|
||||
/* Wait for correct event at source.
|
||||
*/
|
||||
evt = chEvtGetAndClearFlags(&el);
|
||||
} while (evt != DEC_CLOSE_EXEC);
|
||||
|
||||
pktUnregisterEventListener(esp, &el);
|
||||
|
||||
/*
|
||||
* Release decoder thread heap when it terminates.
|
||||
*/
|
||||
chThdWait(decoder);
|
||||
|
||||
/* Release packet services. */
|
||||
pktBufferManagerRelease(handler);
|
||||
pktCallbackManagerRelease(handler);
|
||||
chBSemSignal(&handler->close_sem);
|
||||
break;
|
||||
} /*end case close. */
|
||||
} /* End switch on command. */
|
||||
|
||||
if(task_object->callback != NULL)
|
||||
/* Perform the callback. */
|
||||
task_object->callback(handler);
|
||||
/* Return task object to free list. */
|
||||
chFifoReturnObject(radio_queue, (radio_task_object_t *)task_object);
|
||||
}
|
||||
chThdExit(MSG_OK);
|
||||
}
|
||||
|
||||
|
||||
void pktRadioManagerCreate(packet_svc_t *handler) {
|
||||
|
||||
/* The radio associated with this packet handler. */
|
||||
radio_unit_t rid = handler->radio_config.radio_id;
|
||||
|
||||
/* Create the radio manager name. */
|
||||
chsnprintf(handler->rtask_name, sizeof(handler->rtask_name),
|
||||
"%s%02i", PKT_RADIO_TASK_QUEUE_PREFIX, rid);
|
||||
|
||||
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");
|
||||
|
||||
handler->the_radio_fifo = the_radio_fifo;
|
||||
|
||||
dbgPrintf(DBG_INFO, "PKT > radio manager thread created. FIFO @ 0x%x\r\n",
|
||||
the_radio_fifo);
|
||||
|
||||
/* Start the task dispatcher thread. */
|
||||
handler->radio_manager = chThdCreateFromHeap(NULL,
|
||||
THD_WORKING_AREA_SIZE(PKT_RADIO_MANAGER_WA_SIZE),
|
||||
handler->rtask_name,
|
||||
NORMALPRIO - 10,
|
||||
pktRadioManager,
|
||||
the_radio_fifo);
|
||||
|
||||
chDbgAssert(handler->radio_manager != NULL,
|
||||
"unable to create radio task thread");
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: This needs review. Is it robust enough?
|
||||
*/
|
||||
void pktRadioManagerRelease(packet_svc_t *handler) {
|
||||
chThdTerminate(handler->radio_manager);
|
||||
chThdWait(handler->radio_manager);
|
||||
chFactoryReleaseObjectsFIFO(handler->the_radio_fifo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a radio command task object.
|
||||
* @post A task object is returned ready for filling and submission.
|
||||
*
|
||||
* @param[in] handler pointer to packet handler object.
|
||||
* @param[in] timeout maximum time to wait for a task to be submitted.
|
||||
* @param[in] rt pointer to a task object pointer.
|
||||
*
|
||||
* @return Status of the operation.
|
||||
* @retval MSG_TIMEOUT an object could not be obtained within the timeout.
|
||||
* @retval MSG_OK an object has been fetched.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
msg_t pktGetRadioTaskObject(packet_svc_t *handler,
|
||||
sysinterval_t timeout,
|
||||
radio_task_object_t **rt) {
|
||||
dyn_objects_fifo_t *task_fifo =
|
||||
chFactoryFindObjectsFIFO(handler->rtask_name);
|
||||
chDbgAssert(task_fifo != NULL, "unable to find radio task fifo");
|
||||
|
||||
objects_fifo_t *task_queue = chFactoryGetObjectsFIFO(task_fifo);
|
||||
chDbgAssert(task_queue != NULL, "no objects fifo list");
|
||||
|
||||
*rt = chFifoTakeObjectTimeout(task_queue, TIME_MS2I(timeout));
|
||||
|
||||
if(*rt == NULL) {
|
||||
/* Timeout waiting for object. */
|
||||
/* Release find reference to the FIFO (decrease reference count). */
|
||||
chFactoryReleaseObjectsFIFO(task_fifo);
|
||||
return MSG_TIMEOUT;
|
||||
}
|
||||
(*rt)->handler = handler;
|
||||
return MSG_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Submit a radio command to the task manager.
|
||||
* @post A task object is created and submitted to the radio manager.
|
||||
*
|
||||
* @param[in] handler pointer to packet handler object.
|
||||
* @param[in] object radio task object to be submitted.
|
||||
* @param[in] cb function to call with result (can be NULL).
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void pktSubmitRadioTask(packet_svc_t *handler,
|
||||
radio_task_object_t *object,
|
||||
radio_task_cb_t cb) {
|
||||
|
||||
dyn_objects_fifo_t *task_fifo =
|
||||
chFactoryFindObjectsFIFO(handler->rtask_name);
|
||||
chDbgAssert(task_fifo != NULL, "unable to find radio task fifo");
|
||||
|
||||
objects_fifo_t *task_queue = chFactoryGetObjectsFIFO(task_fifo);
|
||||
chDbgAssert(task_queue != NULL, "no objects fifo list");
|
||||
|
||||
/* Populate the object with information from request. */
|
||||
|
||||
/* TODO: Put command information into queue object.
|
||||
* Have to do this so that commands are not overwritten in handler.
|
||||
*/
|
||||
object->handler = handler;
|
||||
object->callback = cb;
|
||||
// etc.
|
||||
/*
|
||||
* Submit the task to the queue.
|
||||
* The task thread will process the request.
|
||||
* The task object is returned to the free list.
|
||||
* If a callback is specified it is called after the task object is freed.
|
||||
*/
|
||||
chFifoSendObject(task_queue, object);
|
||||
|
||||
/* Release reference to the FIFO acquired earlier by find. */
|
||||
chFactoryReleaseObjectsFIFO(task_fifo);
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file pktradio.h
|
||||
* @brief Generic radio definitions.
|
||||
*
|
||||
* @addtogroup managers
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef PKT_MANAGERS_PKTRADIO_H_
|
||||
#define PKT_MANAGERS_PKTRADIO_H_
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* Thread working area size. */
|
||||
#define PKT_RADIO_MANAGER_WA_SIZE 1024
|
||||
|
||||
#define PKT_RADIO_TASK_QUEUE_PREFIX "radx_"
|
||||
|
||||
#define BAND_START_2M 144000000
|
||||
#define AU_APRS_2M_FREQUENCY 145175000
|
||||
|
||||
#define PKT_RADIO_CHANNEL_STEPPING_NONE 0
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Radio manager control commands.
|
||||
* @details Radio task requests execute these commands.
|
||||
*/
|
||||
typedef enum radioCommand {
|
||||
PKT_RADIO_OPEN,
|
||||
PKT_RADIO_RX,
|
||||
PKT_RADIO_RX_STOP,
|
||||
PKT_RADIO_TX,
|
||||
PKT_RADIO_CLOSE
|
||||
} radio_command_t;
|
||||
|
||||
/**
|
||||
* @brief Definition of radio unit ID.
|
||||
* @details Defines the radio unit used in configuring and enabling a radio.
|
||||
*
|
||||
*/
|
||||
typedef enum radioUnit {
|
||||
PKT_RADIO_1
|
||||
} radio_unit_t;
|
||||
|
||||
/* Radio frequency in Hz. */
|
||||
typedef uint32_t radio_freq_t;
|
||||
|
||||
/* Channel step in Hz. */
|
||||
typedef uint16_t channel_hz_t;
|
||||
|
||||
/* Channel selector for radio frequency. */
|
||||
typedef uint8_t radio_ch_t;
|
||||
|
||||
/* Radio squelch setting. */
|
||||
typedef uint8_t radio_squelch_t;
|
||||
|
||||
/**
|
||||
* Forward declare structure types.
|
||||
*/
|
||||
typedef struct radioTask radio_task_object_t;
|
||||
typedef struct packetHandlerData packet_svc_t;
|
||||
|
||||
/**
|
||||
* @brief Radio task notification callback type.
|
||||
*
|
||||
* @param[in] rcob pointer to a @p radio task object
|
||||
*/
|
||||
typedef void (*radio_task_cb_t)(packet_svc_t *handler);
|
||||
|
||||
/**
|
||||
* @brief Radio request object.
|
||||
*/
|
||||
/*typedef struct radioRequest {
|
||||
radio_unit_t radio;
|
||||
radio_command_t command;
|
||||
encoding_type_t type;
|
||||
radio_freq_t base_frequency;
|
||||
radio_ch_t channel;
|
||||
radio_task_cb_t callback;
|
||||
} radio_request_t;*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Radio task object.
|
||||
* @details object submitted by FIFO to manager for radio task requests.
|
||||
*/
|
||||
struct radioTask {
|
||||
/* For safety keep clear - where pool stores its free link. */
|
||||
struct pool_header link;
|
||||
radio_unit_t radio_id;
|
||||
radio_command_t command;
|
||||
encoding_type_t type;
|
||||
radio_freq_t base_frequency;
|
||||
channel_hz_t step_hz;
|
||||
radio_ch_t channel;
|
||||
radio_squelch_t squelch;
|
||||
radio_task_cb_t callback;
|
||||
packet_svc_t *handler;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void pktRadioManagerCreate(packet_svc_t *handler);
|
||||
void pktRadioManagerRelease(packet_svc_t *handler);
|
||||
void pktRadioManager(void *arg);
|
||||
msg_t pktGetRadioTaskObject(packet_svc_t *handler,
|
||||
sysinterval_t timeout,
|
||||
radio_task_object_t **rt);
|
||||
void pktSubmitRadioTask(packet_svc_t *handler,
|
||||
radio_task_object_t *object,
|
||||
radio_task_cb_t cb);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Alias for convenience of pktStopDecoder.
|
||||
*
|
||||
* @param[in] ip pointer to a @p packet handler object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define pktPauseDecoder(handler) pktStopDecoder(handler)
|
||||
|
||||
/**
|
||||
* @brief Alias for convenience of pktStartDecoder.
|
||||
*
|
||||
* @param[in] ip pointer to a @p packet handler object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define pktResumeDecoder(handler) pktStartDecoder(handler)
|
||||
|
||||
#endif /* PKT_MANAGERS_PKTRADIO_H_ */
|
||||
|
||||
/** @} */
|
|
@ -39,10 +39,22 @@
|
|||
*/
|
||||
#include "arm_math.h"
|
||||
|
||||
/* Decoder system events. */
|
||||
/*===========================================================================*/
|
||||
/* Aerospace decoder system function includes. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#include "bit_array.h"
|
||||
|
||||
|
||||
/* General event definitions. */
|
||||
#define EVT_NONE 0
|
||||
#define EVT_PRIORITY_BASE 0
|
||||
|
||||
/*
|
||||
* Decoder global system events.
|
||||
* The packet channel object holds the global events.
|
||||
* Events are broadcast to any listeners.
|
||||
*/
|
||||
#define EVT_AX25_FRAME_RDY EVENT_MASK(EVT_PRIORITY_BASE + 0)
|
||||
#define EVT_RADIO_CCA_GLITCH EVENT_MASK(EVT_PRIORITY_BASE + 1)
|
||||
#define EVT_RADIO_CCA_CLOSE EVENT_MASK(EVT_PRIORITY_BASE + 2)
|
||||
|
@ -51,7 +63,7 @@
|
|||
#define EVT_AFSK_TERMINATED EVENT_MASK(EVT_PRIORITY_BASE + 4)
|
||||
#define EVT_PWM_UNKNOWN_INBAND EVENT_MASK(EVT_PRIORITY_BASE + 5)
|
||||
#define EVT_ICU_OVERFLOW EVENT_MASK(EVT_PRIORITY_BASE + 6)
|
||||
#define EVT_SUSPEND_EXIT EVENT_MASK(EVT_PRIORITY_BASE + 7)
|
||||
//#define EVT_SUSPEND_EXIT EVENT_MASK(EVT_PRIORITY_BASE + 7)
|
||||
|
||||
#define EVT_PWM_NO_DATA EVENT_MASK(EVT_PRIORITY_BASE + 8)
|
||||
#define EVT_PWM_FIFO_SENT EVENT_MASK(EVT_PRIORITY_BASE + 9)
|
||||
|
@ -60,13 +72,13 @@
|
|||
|
||||
#define EVT_PWM_FIFO_EMPTY EVENT_MASK(EVT_PRIORITY_BASE + 12)
|
||||
#define EVT_PWM_STREAM_TIMEOUT EVENT_MASK(EVT_PRIORITY_BASE + 13)
|
||||
#define EVT_PWM_FIFO_LOCK EVENT_MASK(EVT_PRIORITY_BASE + 14)
|
||||
#define EVT_DECODER_START EVENT_MASK(EVT_PRIORITY_BASE + 15)
|
||||
#define EVT_PWM_QUEUE_LOCK EVENT_MASK(EVT_PRIORITY_BASE + 14)
|
||||
#define EVT_PKT_DECODER_START EVENT_MASK(EVT_PRIORITY_BASE + 15)
|
||||
|
||||
#define EVT_DECODER_STOP EVENT_MASK(EVT_PRIORITY_BASE + 16)
|
||||
#define EVT_PKT_CHANNEL_STOP EVENT_MASK(EVT_PRIORITY_BASE + 16)
|
||||
#define EVT_RADIO_CCA_FIFO_ERR EVENT_MASK(EVT_PRIORITY_BASE + 17)
|
||||
#define EVT_AX25_BUFFER_FULL EVENT_MASK(EVT_PRIORITY_BASE + 18)
|
||||
//#define EVT_AFSK_DATA_TIMEOUT EVENT_MASK(EVT_PRIORITY_BASE + 19)
|
||||
#define EVT_AFSK_INVALID_FRAME EVENT_MASK(EVT_PRIORITY_BASE + 19)
|
||||
|
||||
#define EVT_AX25_CRC_ERROR EVENT_MASK(EVT_PRIORITY_BASE + 20)
|
||||
#define EVT_HDLC_RESET_RCVD EVENT_MASK(EVT_PRIORITY_BASE + 21)
|
||||
|
@ -75,10 +87,29 @@
|
|||
|
||||
#define EVT_PWM_STREAM_CLOSED EVENT_MASK(EVT_PRIORITY_BASE + 24)
|
||||
#define EVT_PKT_CHANNEL_CLOSE EVENT_MASK(EVT_PRIORITY_BASE + 25)
|
||||
#define EVT_DECODER_ACK EVENT_MASK(EVT_PRIORITY_BASE + 26)
|
||||
#define EVT_PKT_CHANNEL_OPEN EVENT_MASK(EVT_PRIORITY_BASE + 26)
|
||||
#define EVT_AFSK_DECODE_DONE EVENT_MASK(EVT_PRIORITY_BASE + 27)
|
||||
|
||||
#define EVT_RADIO_CCA_SPIKE EVENT_MASK(EVT_PRIORITY_BASE + 28)
|
||||
//#define EVT_SERIAL_PKT_OUT_END EVENT_MASK(EVT_PRIORITY_BASE + 29)
|
||||
#define EVT_ICU_OUT_OF_RANGE EVENT_MASK(EVT_PRIORITY_BASE + 30)
|
||||
|
||||
/* Initiator thread events (from decoder to initiator). */
|
||||
#define DEC_OPEN_EXEC EVENT_MASK(EVT_PRIORITY_BASE + 0)
|
||||
#define DEC_START_EXEC EVENT_MASK(EVT_PRIORITY_BASE + 1)
|
||||
#define DEC_STOP_EXEC EVENT_MASK(EVT_PRIORITY_BASE + 2)
|
||||
#define DEC_CLOSE_EXEC EVENT_MASK(EVT_PRIORITY_BASE + 2)
|
||||
|
||||
/* Decoder thread events (from initiator to decoder). */
|
||||
|
||||
#define DEC_COMMAND_START EVENT_MASK(EVT_PRIORITY_BASE + 0)
|
||||
#define DEC_COMMAND_STOP EVENT_MASK(EVT_PRIORITY_BASE + 1)
|
||||
#define DEC_COMMAND_CLOSE EVENT_MASK(EVT_PRIORITY_BASE + 2)
|
||||
#define DEC_DIAG_OUT_END EVENT_MASK(EVT_PRIORITY_BASE + 3)
|
||||
#define DEC_SUSPEND_EXIT EVENT_MASK(EVT_PRIORITY_BASE + 4)
|
||||
|
||||
/* Reserved system thread events (in user threads). */
|
||||
#define USR_COMMAND_ACK EVENT_MASK(EVT_PRIORITY_BASE + 0)
|
||||
|
||||
#define EVT_STATUS_CLEAR EVT_NONE
|
||||
|
||||
|
@ -95,66 +126,30 @@
|
|||
/* Extra GPIO value. */
|
||||
#define PAL_TOGGLE 2U
|
||||
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @name Subsystems configuration
|
||||
* @{
|
||||
*/
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Enables and sets the device parameters.
|
||||
* @details Some devices may be optional.
|
||||
*
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#define PKT_CFG_USE_SERIAL FALSE
|
||||
|
||||
/**
|
||||
* @brief Temporary definition of radio unit ID.
|
||||
* @details Defines the radio unit used in configuring and enabling a radio.
|
||||
*
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
typedef enum radioUnit {
|
||||
PKT_RADIO_1
|
||||
} radio_unit_t;
|
||||
|
||||
typedef struct radioConfig {
|
||||
radio_unit_t radio_id;
|
||||
/* Other stuff like frequency goes here. */
|
||||
} radio_config_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Aerospace decoder system function includes. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#include "bit_array.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Aerospace decoder subsystem includes. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#include "portab.h"
|
||||
#include "rxax25.h"
|
||||
#include "pktservice.h"
|
||||
#include "pktradio.h"
|
||||
#include "dbguart.h"
|
||||
#include "dsp.h"
|
||||
#include "rxax25.h"
|
||||
#include "crc_calc.h"
|
||||
#include "rxafsk.h"
|
||||
#include "rxpwm.h"
|
||||
#include "firfilter_q31.h"
|
||||
#include "rxafsk.h"
|
||||
#include "corr_q31.h"
|
||||
#include "rxhdlc.h"
|
||||
#include "rxpacket.h"
|
||||
#include "ihex_out.h"
|
||||
#include "ax25_pad.h"
|
||||
#include "ax25_dump.h"
|
||||
#include "si446x.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -170,6 +165,7 @@ static inline void pktSetLineModeCCA(void) {
|
|||
palSetLineMode(LINE_CCA, PAL_MODE_INPUT_PULLUP);
|
||||
}
|
||||
|
||||
/* Decoder blinker LED. */
|
||||
static inline void pktSetLineModeDecoderLED(void) {
|
||||
#if defined(LINE_DECODER_LED)
|
||||
palSetLineMode(LINE_DECODER_LED, PAL_MODE_OUTPUT_PUSHPULL);
|
||||
|
@ -193,6 +189,7 @@ static inline void pktWriteDecoderLED(uint8_t state) {
|
|||
#endif
|
||||
}
|
||||
|
||||
/* Squelch (CCA) indicator. */
|
||||
static inline void pktSetLineModeSquelchLED(void) {
|
||||
#if defined(LINE_SQUELCH_LED)
|
||||
palSetLineMode(LINE_SQUELCH_LED, PAL_MODE_OUTPUT_PUSHPULL);
|
||||
|
@ -216,6 +213,7 @@ static inline void pktUnsetLineModeSquelchLED(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
/* Overflow in FIFO queue space. */
|
||||
static inline void pktSetLineModeOverflowLED(void) {
|
||||
#if defined(LINE_OVERFLOW_LED)
|
||||
palSetLineMode(LINE_OVERFLOW_LED, PAL_MODE_OUTPUT_PUSHPULL);
|
||||
|
@ -239,6 +237,31 @@ static inline void pktUnsetLineModeOverflowLED(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
/* LED for FIFO out at PWM/ICU side. */
|
||||
static inline void pktSetLineModeNoFIFOLED(void) {
|
||||
#if defined(LINE_NO_FIFO_LED)
|
||||
palSetLineMode(LINE_NO_FIFO_LED, PAL_MODE_OUTPUT_PUSHPULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void pktWriteNoFIFOLED(uint8_t state) {
|
||||
#if defined(LINE_NO_FIFO_LED)
|
||||
if(state != PAL_TOGGLE)
|
||||
palWriteLine(LINE_NO_FIFO_LED, state);
|
||||
else
|
||||
palToggleLine(LINE_NO_FIFO_LED);
|
||||
#else
|
||||
(void)state;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void pktUnsetLineModeNoFIFOLED(void) {
|
||||
#if defined(LINE_NO_FIFO_LED)
|
||||
palSetLineMode(LINE_NO_FIFO_LED, PAL_MODE_UNCONNECTED);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* PWM mirroring to a GPIO for diagnostics. */
|
||||
static inline void pktSetLineModePWMMirror(void) {
|
||||
#if defined(LINE_PWM_MIRROR)
|
||||
palSetLineMode(LINE_PWM_MIRROR, PAL_MODE_OUTPUT_PUSHPULL);
|
||||
|
@ -262,9 +285,63 @@ static inline void pktWritePWMMirror(uint8_t state) {
|
|||
#endif
|
||||
}
|
||||
|
||||
/* Radio configuration for SPI connected radio. */
|
||||
/*static inline msg_t pktOpenRadio(packet_svc_t *handler) {
|
||||
#if USE_SPI_ATTACHED_RADIO == TRUE
|
||||
msg_t msg = pktSubmitRadioTask(handler, TIME_S2I(10), NULL);
|
||||
return msg;
|
||||
#else
|
||||
(void)handler;
|
||||
return MSG_OK;
|
||||
#endif
|
||||
}*/
|
||||
|
||||
/*static inline msg_t pktStartRadio(packet_svc_t *handler) {
|
||||
#if USE_SPI_ATTACHED_RADIO == TRUE
|
||||
msg_t msg = pktSubmitRadioTask(handler, TIME_MS2I(100), NULL);
|
||||
return msg;
|
||||
#else
|
||||
(void)handler;
|
||||
return MSG_OK;
|
||||
#endif
|
||||
}*/
|
||||
|
||||
/*static inline void pktStopRadio(packet_svc_t *handler) {
|
||||
#if USE_SPI_ATTACHED_RADIO == TRUE
|
||||
(void)handler;
|
||||
#else
|
||||
(void)handler;
|
||||
#endif
|
||||
}*/
|
||||
|
||||
/*static inline msg_t pktCloseRadio(packet_svc_t *handler) {
|
||||
#if USE_SPI_ATTACHED_RADIO == TRUE
|
||||
(void)handler;
|
||||
//Si446x_shutdown();
|
||||
#else
|
||||
(void)handler;
|
||||
#endif
|
||||
return MSG_OK;
|
||||
}*/
|
||||
|
||||
|
||||
static inline msg_t pktSendRadioCommand(packet_svc_t *handler,
|
||||
radio_task_object_t *task) {
|
||||
#if USE_SPI_ATTACHED_RADIO == TRUE
|
||||
radio_task_object_t *rt = NULL;
|
||||
msg_t msg = pktGetRadioTaskObject(handler, TIME_MS2I(3000), &rt);
|
||||
if(msg != MSG_OK)
|
||||
return MSG_TIMEOUT;
|
||||
*rt = *task;
|
||||
pktSubmitRadioTask(handler, rt, NULL);
|
||||
return msg;
|
||||
#else
|
||||
(void)task;
|
||||
(void)handler;
|
||||
return MSG_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* _PKTCONF_H_ */
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file rxax25.h
|
||||
* @brief Definitions for AX25 protocol for packet receiver.
|
||||
*
|
||||
* @addtogroup protocols
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PKT_PROTOCOLS_RXAX25_H_
|
||||
#define PKT_PROTOCOLS_RXAX25_H_
|
||||
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* AX25 definitions for packet data useage. */
|
||||
#define PKT_MAX_REPEATERS 8
|
||||
/* Destination & Source. */
|
||||
#define PKT_MIN_ADDRS 2
|
||||
/*
|
||||
* Destination & Source + 8 digipeater addresses.
|
||||
* A destination address may specify a generic APRS digipeater path.
|
||||
* In such case the digipeater address fields are overridden by that path.
|
||||
*/
|
||||
#define PKT_MAX_ADDRS 10
|
||||
/* Address positions in frame. */
|
||||
#define PKT_DESTINATION 0
|
||||
#define PKT_SOURCE 1
|
||||
#define PKT_REPEATER_1 2
|
||||
#define PKT_REPEATER_2 3
|
||||
#define PKT_REPEATER_3 4
|
||||
#define PKT_REPEATER_4 5
|
||||
#define PKT_REPEATER_5 6
|
||||
#define PKT_REPEATER_6 7
|
||||
#define PKT_REPEATER_7 8
|
||||
#define PKT_REPEATER_8 9
|
||||
|
||||
/*
|
||||
* The maximum address length should be 6 letters, dash, 2 digits and null.
|
||||
* Making a total of 10.
|
||||
* However, object labels can be 10 characters.
|
||||
* So add 2 extra margin bytes.
|
||||
*/
|
||||
#define PKT_DS_ADDRESS_LEN 7
|
||||
#define PKT_MAX_ADDR_LEN 12
|
||||
#define PKT_CONTROL_LEN 1
|
||||
#define PKT_PROTOCOL_LEN 1
|
||||
#define PKT_CRC_LEN 2
|
||||
#define PKT_FLAG_LEN 1
|
||||
#define PKT_MIN_INFO_LEN 0
|
||||
|
||||
|
||||
/* An AX.25 packet can have a control byte and no protocol. */
|
||||
#define PKT_MIN_PACKET_LEN (PKT_MIN_ADDRS * PKT_DS_ADDRESS_LEN \
|
||||
+ PKT_CONTROL_LEN)
|
||||
|
||||
/*
|
||||
* Maximum size for APRS.
|
||||
* The payload excluding CRC.
|
||||
*/
|
||||
#define PKT_MAX_INFO_LEN 2048
|
||||
|
||||
/* An AX.25 packet maximum - closing flag is not included. */
|
||||
#define PKT_MAX_PACKET_LEN (PKT_MAX_ADDRS * PKT_DS_ADDRESS_LEN \
|
||||
+ PKT_CONTROL_LEN \
|
||||
+ PKT_PROTOCOL_LEN \
|
||||
+ PKT_MAX_INFO_LEN \
|
||||
+ PKT_CRC_LEN)
|
||||
|
||||
#define PKT_MIN_FRAME ((PKT_MIN_PACKET_LEN) + PKT_CRC_LEN)
|
||||
#define PKT_MAX_FRAME ((PKT_MAX_PACKET_LEN) + PKT_CRC_LEN)
|
||||
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Type of characters in AX25 packet.
|
||||
*
|
||||
* @note Only used in buffers.
|
||||
*/
|
||||
typedef uint8_t ax25char_t;
|
||||
typedef int16_t ax25size_t;
|
||||
|
||||
#ifdef PKT_USE_PROJECT_DEFINITIONS
|
||||
/* TODO: Create a chFactory FIFO to manage these objects. */
|
||||
struct packet_s {
|
||||
|
||||
int magic1; /* for error checking. */
|
||||
|
||||
int seq; /* unique sequence number for debugging. */
|
||||
|
||||
double release_time; /* Time stamp in format returned by dtime_now(). */
|
||||
/* When to release from the SATgate mode delay queue. */
|
||||
|
||||
#define MAGIC 0x41583235
|
||||
|
||||
struct packet_s *nextp; /* Pointer to next in queue. */
|
||||
|
||||
int num_addr; /* Number of addresses in frame. */
|
||||
/* Range of AX25_MIN_ADDRS .. AX25_MAX_ADDRS for AX.25. */
|
||||
/* It will be 0 if it doesn't look like AX.25. */
|
||||
/* -1 is used temporarily at allocation to mean */
|
||||
/* not determined yet. */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* The 7th octet of each address contains:
|
||||
*
|
||||
* Bits: H R R SSID 0
|
||||
*
|
||||
* H for digipeaters set to 0 intially.
|
||||
* Changed to 1 when position has been used.
|
||||
*
|
||||
* for source & destination it is called
|
||||
* command/response. Normally both 1 for APRS.
|
||||
* They should be opposites for connected mode.
|
||||
*
|
||||
* R R Reserved. Normally set to 1 1.
|
||||
*
|
||||
* SSID Substation ID. Range of 0 - 15.
|
||||
*
|
||||
* 0 Usually 0 but 1 for last address.
|
||||
*/
|
||||
|
||||
|
||||
#define SSID_H_MASK 0x80
|
||||
#define SSID_H_SHIFT 7
|
||||
|
||||
#define SSID_RR_MASK 0x60
|
||||
#define SSID_RR_SHIFT 5
|
||||
|
||||
#define SSID_SSID_MASK 0x1e
|
||||
#define SSID_SSID_SHIFT 1
|
||||
|
||||
#define SSID_LAST_MASK 0x01
|
||||
|
||||
|
||||
int frame_len; /* Frame length without CRC. */
|
||||
|
||||
int modulo; /* I & S frames have sequence numbers of either 3 bits (modulo 8) */
|
||||
/* or 7 bits (modulo 128). This is conveyed by either 1 or 2 */
|
||||
/* control bytes. Unfortunately, we can't determine this by looking */
|
||||
/* at an isolated frame. We need to know about the context. If we */
|
||||
/* are part of the conversation, we would know. But if we are */
|
||||
/* just listening to others, this would be more difficult to determine. */
|
||||
|
||||
/* For U frames: set to 0 - not applicable */
|
||||
/* For I & S frames: 8 or 128 if known. 0 if unknown. */
|
||||
|
||||
unsigned char frame_data[PKT_MAX_PACKET_LEN + 1];
|
||||
/* Raw frame contents, without the CRC. */
|
||||
|
||||
|
||||
int magic2; /* Will get stomped on if above overflows. */
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct packet_s *packet_t;
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* PKT_PROTOCOLS_RXAX25_H_ */
|
||||
|
||||
/** @} */
|
|
@ -11,6 +11,11 @@
|
|||
/**
|
||||
* @brief Extract HDLC from AFSK.
|
||||
* @post The HDLC state will be updated.
|
||||
* @notes In the case of an HDLC_RESET HDLC sync can be restarted.
|
||||
* @notes This is done where the AX25 payload is below minimum size.
|
||||
* @notes If the payload is above minimum size state HDLC_RESET is set.
|
||||
* @notes In that case it is left to the decoder to determine an action.
|
||||
*
|
||||
* @param[in] myDriver pointer to an @p AFSKDemodDriver structure.
|
||||
*
|
||||
* @return status of operation
|
||||
|
@ -21,7 +26,7 @@
|
|||
*/
|
||||
bool pktExtractHDLCfromAFSK(AFSKDemodDriver *myDriver) {
|
||||
|
||||
packet_rx_t *myHandler = myDriver->packet_handler;
|
||||
packet_svc_t *myHandler = myDriver->packet_handler;
|
||||
|
||||
/* Shift prior HDLC bits up before adding new bit. */
|
||||
myDriver->hdlc_bits <<= 1;
|
||||
|
@ -50,8 +55,7 @@ bool pktExtractHDLCfromAFSK(AFSKDemodDriver *myDriver) {
|
|||
* Dump any bits already put into the AX25 byte.
|
||||
*/
|
||||
myDriver->bit_index = 0;
|
||||
myHandler->packet_count++;
|
||||
/* Inform thread loop of end of frame. */
|
||||
/* Inform decoder thread of end of frame. */
|
||||
myDriver->frame_state = FRAME_CLOSE;
|
||||
return true;
|
||||
} /* End AX25 frame size check. */
|
||||
|
@ -61,7 +65,7 @@ bool pktExtractHDLCfromAFSK(AFSKDemodDriver *myDriver) {
|
|||
* HDLC sync still in progress.
|
||||
* Reset AX25 counts and wait for next HDLC bit.
|
||||
*/
|
||||
pktResetDataBuffer(myHandler->active_packet_object);
|
||||
pktResetDataCount(myHandler->active_packet_object);
|
||||
myDriver->bit_index = 0;
|
||||
return true;
|
||||
} /* End case. */
|
||||
|
@ -75,11 +79,14 @@ bool pktExtractHDLCfromAFSK(AFSKDemodDriver *myDriver) {
|
|||
|
||||
myDriver->active_demod_object->status |= EVT_HDLC_RESET_RCVD;
|
||||
pktAddEventFlags(myHandler, EVT_HDLC_RESET_RCVD);
|
||||
if(myHandler->active_packet_object->packet_size == 0) {
|
||||
/* No data stored yet so go back to sync search. */
|
||||
if(myHandler->active_packet_object->packet_size < PKT_MIN_FRAME) {
|
||||
/* No data payload stored yet so go back to sync search. */
|
||||
myHandler->active_packet_object->packet_size = 0;
|
||||
myDriver->frame_state = FRAME_SEARCH;
|
||||
myHandler->sync_count--;
|
||||
break;
|
||||
}
|
||||
/* Else let the decoder determine what to do. */
|
||||
myDriver->frame_state = FRAME_RESET;
|
||||
return true;
|
||||
} /* End case. */
|
||||
|
@ -132,7 +139,7 @@ bool pktExtractHDLCfromAFSK(AFSKDemodDriver *myDriver) {
|
|||
) {
|
||||
|
||||
myDriver->frame_state = FRAME_OPEN;
|
||||
|
||||
myHandler->sync_count++;
|
||||
/* Reset AX25 data indexes. */
|
||||
myHandler->active_packet_object->packet_size = 0;
|
||||
myDriver->bit_index = 0;
|
|
@ -6,16 +6,16 @@
|
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#ifndef IO_PROTOCOLS_RXHDLC_H_
|
||||
#define IO_PROTOCOLS_RXHDLC_H_
|
||||
#ifndef PKT_PROTOCOLS_RXHDLC_H_
|
||||
#define PKT_PROTOCOLS_RXHDLC_H_
|
||||
|
||||
/* HDLC bit pattern definitions. */
|
||||
#define HDLC_CODE_MASK 0xFFU
|
||||
#define HDLC_FLAG 0x7EU
|
||||
#define HDLC_ZERO 0x00U
|
||||
#define HDLC_FRAME_MASK_A 0x000000FFU
|
||||
#define HDLC_FRAME_MASK_A 0x00FFFFFFU
|
||||
#define HDLC_FRAME_OPEN_A 0x7E7E7E7EU
|
||||
#define HDLC_FRAME_MASK_B 0x0000FFFFU
|
||||
#define HDLC_FRAME_MASK_B 0x00FFFFFFU
|
||||
#define HDLC_FRAME_OPEN_B 0x0000007EU
|
||||
|
||||
#define HDLC_FRAME_CLOSE HDLC_FLAG
|
||||
|
@ -36,4 +36,4 @@
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif /* IO_PROTOCOLS_RXHDLC_H_ */
|
||||
#endif /* PKT_PROTOCOLS_RXHDLC_H_ */
|
|
@ -16,7 +16,9 @@
|
|||
*/
|
||||
|
||||
#include "hal.h"
|
||||
#include "chprintf.h"
|
||||
#include "portab.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local definitions. */
|
||||
|
@ -26,6 +28,8 @@
|
|||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
binary_semaphore_t callback_sem;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
@ -34,6 +38,7 @@
|
|||
/* Module local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
@ -42,22 +47,89 @@
|
|||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
const SerialConfig debug_config = {
|
||||
115200,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
void pktConfigSerialDiag(void) {
|
||||
/* USART3 TX. */
|
||||
//palSetLineMode(LINE_USART3_TX, PAL_MODE_OUTPUT_PUSHPULL | PAL_MODE_ALTERNATE(3));
|
||||
palSetLineMode(LINE_USART3_TX, PAL_MODE_ALTERNATE(7));
|
||||
/* USART3 RX. */
|
||||
//palSetLineMode(LINE_USART3_RX, PAL_MODE_ALTERNATE(3));
|
||||
palSetLineMode(LINE_USART3_RX, PAL_MODE_ALTERNATE(7));
|
||||
}
|
||||
|
||||
void pktConfigSerialPkt(void) {
|
||||
/* UART4 TX. */
|
||||
palSetLineMode(LINE_UART4_TX, PAL_MODE_OUTPUT_PUSHPULL | PAL_MODE_ALTERNATE(11));
|
||||
/* UART4 RX. */
|
||||
palSetLineMode(LINE_UART4_RX, PAL_MODE_INPUT | PAL_MODE_ALTERNATE(11));
|
||||
|
||||
}
|
||||
|
||||
void pktSetLineModeICU(void) {
|
||||
palSetLineMode(LINE_ICU, PAL_MODE_INPUT | PAL_MODE_ALTERNATE(2));
|
||||
}
|
||||
|
||||
void pktSerialStart(void) {
|
||||
pktConfigSerialDiag();
|
||||
pktConfigSerialPkt();
|
||||
sdStart(SERIAL_CFG_DEBUG_DRIVER, &debug_config);
|
||||
//sdStart(SERIAL_CFG_PACKET_DRIVER, &debug_config);
|
||||
|
||||
/* Setup diagnostic resource access semaphore. */
|
||||
chBSemObjectInit(&callback_sem, false);
|
||||
}
|
||||
|
||||
void dbgWrite(uint8_t level, uint8_t *buf, uint32_t len) {
|
||||
(void)level;
|
||||
chnWrite((BaseSequentialStream*)SERIAL_CFG_DEBUG_DRIVER, buf, len);
|
||||
}
|
||||
|
||||
int dbgPrintf(uint8_t level, const char *format, ...) {
|
||||
(void)level;
|
||||
|
||||
va_list arg;
|
||||
int done;
|
||||
|
||||
va_start(arg, format);
|
||||
done = chprintf((BaseSequentialStream*)SERIAL_CFG_DEBUG_DRIVER, format, arg);
|
||||
va_end(arg);
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
void pktWrite(uint8_t *buf, uint32_t len) {
|
||||
chnWrite((BaseSequentialStream*)SERIAL_CFG_DEBUG_DRIVER, buf, len);
|
||||
}
|
||||
|
||||
void pktConfigureRadioGPIO() {
|
||||
// Configure Radio pins
|
||||
palSetLineMode(LINE_SPI_SCK, PAL_MODE_ALTERNATE(6) | PAL_STM32_OSPEED_HIGHEST); // SCK
|
||||
palSetLineMode(LINE_SPI_MISO, PAL_MODE_ALTERNATE(6) | PAL_STM32_OSPEED_HIGHEST); // MISO
|
||||
palSetLineMode(LINE_SPI_MOSI, PAL_MODE_ALTERNATE(6) | PAL_STM32_OSPEED_HIGHEST); // MOSI
|
||||
palSetLineMode(LINE_RADIO_CS, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); // RADIO CS
|
||||
palSetLineMode(LINE_RADIO_SDN, PAL_MODE_OUTPUT_PUSHPULL); // RADIO SDN
|
||||
|
||||
// Pull CS HIGH
|
||||
palSetLine(LINE_RADIO_CS);
|
||||
|
||||
// Reset radio
|
||||
palSetLine(LINE_RADIO_SDN);
|
||||
chThdSleep(TIME_MS2I(10));
|
||||
|
||||
// Power up transceiver
|
||||
palClearLine(LINE_RADIO_SDN); // Radio SDN low (power up transceiver)
|
||||
chThdSleep(TIME_MS2I(10)); // Wait for transceiver to power up
|
||||
}
|
||||
|
||||
void pktDeconfigureRadioGPIO() {
|
||||
|
||||
palSetLineMode(LINE_SPI_SCK, PAL_MODE_INPUT_PULLDOWN); // SCK
|
||||
palSetLineMode(LINE_SPI_MISO, PAL_MODE_INPUT_PULLDOWN); // MISO
|
||||
palSetLineMode(LINE_SPI_MOSI, PAL_MODE_INPUT_PULLDOWN); // MOSI
|
||||
palSetLineMode(LINE_RADIO_CS, PAL_MODE_INPUT_PULLDOWN); // RADIO CS
|
||||
palSetLineMode(LINE_RADIO_SDN, PAL_MODE_INPUT_PULLDOWN); // RADIO SDN
|
||||
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
|
|
|
@ -13,27 +13,81 @@
|
|||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
//#define LINE_OVERFLOW_LED LINE_LED3
|
||||
#define LINE_DECODER_LED LINE_IO_BLUE
|
||||
//#define LINE_SQUELCH_LED LINE_IO_BLUE
|
||||
/*
|
||||
* Serial port definitions
|
||||
*/
|
||||
#define SERIAL_CFG_DEBUG_DRIVER &SD3
|
||||
//#define SERIAL_CFG_PACKET_DRIVER &SD4
|
||||
|
||||
#define LINE_CCA PAL_LINE(GPIOD, 2U)
|
||||
#define LINE_ICU PAL_LINE(GPIOB, 6U)
|
||||
|
||||
#define LINE_UART4_TX PAL_LINE(GPIOA, 12U)
|
||||
#define LINE_UART4_RX PAL_LINE(GPIOA, 11U)
|
||||
#define USE_SPI_ATTACHED_RADIO TRUE
|
||||
#define DUMP_PACKET_TO_SERIAL TRUE
|
||||
|
||||
//#define LINE_PWM_MIRROR PAL_LINE(GPIOA, 8U)
|
||||
/*
|
||||
* TODO: Need to use radio unit ID to set assigned GPIO & SPI.
|
||||
* Only if there is a multi radio board...
|
||||
*/
|
||||
|
||||
#define PWM_ICU ICUD4
|
||||
#define PWM_TIMER_CHANNEL 0
|
||||
/*
|
||||
* Radio SPI definitions.
|
||||
*/
|
||||
#define PKT_RADIO_SPI &SPID3
|
||||
|
||||
/*
|
||||
* Radio GPIO definitions.
|
||||
*/
|
||||
#define LINE_RADIO_CS PAL_LINE(GPIOC, 12U)
|
||||
#define LINE_RADIO_SDN PAL_LINE(GPIOC, 10U)
|
||||
#define LINE_RADIO_IRQ PAL_LINE(GPIOD, 2U)
|
||||
#define LINE_RADIO_GPIO0 PAL_LINE(GPIOB, 7U)
|
||||
#define LINE_RADIO_GPIO1 PAL_LINE(GPIOB, 6U)
|
||||
#define LINE_SPI_SCK PAL_LINE(GPIOB, 3U)
|
||||
#define LINE_SPI_MISO PAL_LINE(GPIOB, 4U)
|
||||
#define LINE_SPI_MOSI PAL_LINE(GPIOB, 5U)
|
||||
|
||||
#define Si446x_MIN_FREQ 144000000 /* Minimum allowed frequency in Hz */
|
||||
#define Si446x_MAX_FREQ 148000000 /* Maximum allowed frequency in Hz */
|
||||
#define Si446x_CLK STM32_HSECLK /* Oscillator frequency in Hz */
|
||||
#define Si446x_CLK_OFFSET 22 /* Oscillator frequency drift in ppm */
|
||||
#define Si446x_CLK_TCXO_EN true /* Set this true, if a TCXO is used, false for XTAL */
|
||||
|
||||
//#define LINE_OVERFLOW_LED LINE_LED3
|
||||
#define LINE_DECODER_LED LINE_IO_BLUE
|
||||
//#define LINE_SQUELCH_LED LINE_IO_GREEN
|
||||
|
||||
#define LINE_CCA LINE_RADIO_IRQ
|
||||
#define LINE_ICU LINE_RADIO_GPIO1
|
||||
|
||||
//#define LINE_UART4_TX PAL_LINE(GPIOA, 12U)
|
||||
//#define LINE_UART4_RX PAL_LINE(GPIOA, 11U)
|
||||
|
||||
#define LINE_USART3_TX LINE_IO_TXD
|
||||
#define LINE_USART3_RX LINE_IO_RXD
|
||||
|
||||
#define LINE_PWM_MIRROR PAL_LINE(GPIOA, 8U)
|
||||
|
||||
/**
|
||||
* ICU related definitions.
|
||||
*/
|
||||
#define PWM_ICU ICUD4
|
||||
#define PWM_TIMER_CHANNEL 0
|
||||
|
||||
/* ICU counter frequency (2.88MHz). */
|
||||
/*
|
||||
* TODO: This should be calculated using SYSTEM CLOCK.
|
||||
* ICU has to run at an integer divide from SYSTEM CLOCK.
|
||||
*/
|
||||
|
||||
#define ICU_COUNT_FREQUENCY 6000000U
|
||||
|
||||
#define USE_12_BIT_PWM FALSE
|
||||
|
||||
/* Definitions for ICU FIFO implemented using chfactory. */
|
||||
#define NUMBER_PWM_FIFOS 4
|
||||
#define PWM_BUFFER_SLOTS 6000
|
||||
#define NUMBER_PWM_FIFOS 4U
|
||||
#define PWM_BUFFER_SLOTS 6000
|
||||
|
||||
/* Number of AX25 output buffers. */
|
||||
#define NUMBER_PKT_FIFOS 2U
|
||||
/* Number of frame output buffers. */
|
||||
#define NUMBER_PKT_FIFOS 2U
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
|
@ -61,6 +115,12 @@ extern "C" {
|
|||
void pktConfigSerialDiag(void);
|
||||
void pktConfigSerialPkt(void);
|
||||
void pktSetLineModeICU(void);
|
||||
void pktSerialStart(void);
|
||||
void dbgWrite(uint8_t level, uint8_t *buf, uint32_t len);
|
||||
int dbgPrintf(uint8_t level, const char *format, ...);
|
||||
void pktWrite(uint8_t *buf, uint32_t len);
|
||||
void pktConfigureRadioGPIO(void);
|
||||
void pktDeconfigureRadioGPIO(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -30,17 +30,12 @@ static void handlePacket(uint8_t *buf, uint32_t len) {
|
|||
}
|
||||
|
||||
void start_rx_thread(uint32_t freq, uint8_t rssi) {
|
||||
uint32_t f;
|
||||
if(freq == FREQ_APRS_DYNAMIC)
|
||||
f = getAPRSRegionFrequency(); // Get transmission frequency by geofencing
|
||||
else
|
||||
f = freq;
|
||||
|
||||
// Start transceiver
|
||||
Si446x_receive(f, rssi, MOD_AFSK);
|
||||
if(freq == FREQ_APRS_DYNAMIC)
|
||||
freq = getAPRSRegionFrequency(); // Get transmission frequency by geofencing
|
||||
|
||||
// Start decoder
|
||||
Si446x_startDecoder(handlePacket);
|
||||
Si446x_startDecoder(freq, rssi, handlePacket);
|
||||
}
|
||||
|
||||
bool transmitOnRadio(packet_t pp, uint32_t freq, uint8_t pwr, mod_t mod)
|
||||
|
|
|
@ -34,7 +34,8 @@ void start_user_threads(void)
|
|||
}
|
||||
|
||||
// Copy
|
||||
memcpy(&conf_sram, conf_flash, sizeof(conf_t));
|
||||
//memcpy(&conf_sram, conf_flash, sizeof(conf_t));
|
||||
memcpy(&conf_sram, &conf_flash_default, sizeof(conf_t));
|
||||
|
||||
if(conf_sram.pos_pri.thread_conf.active) start_position_thread(&conf_sram.pos_pri);
|
||||
if(conf_sram.pos_sec.thread_conf.active) start_position_thread(&conf_sram.pos_sec);
|
||||
|
|
Ładowanie…
Reference in New Issue