Copy in PKT code base. Temp changes to config system. Other updates.

pull/1/head
CInsights 2018-03-02 00:34:09 +11:00
rodzic 54c03be7b2
commit cd6a2962b4
47 zmienionych plików z 2619 dodań i 1425 usunięć

Wyświetl plik

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

Wyświetl plik

@ -1,2 +1,3 @@
/debug/
/Copy of config.c
/pkt-saved/

Wyświetl plik

@ -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 &quot;${INPUTS}&quot;" 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 &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>

Wyświetl plik

@ -0,0 +1,2 @@
eclipse.preferences.version=1
org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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