2018-03-01 13:34:09 +00:00
|
|
|
/*
|
|
|
|
|
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. */
|
|
|
|
|
/*===========================================================================*/
|
|
|
|
|
|
|
|
|
|
/*===========================================================================*/
|
|
|
|
|
/* 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.
|
2018-03-29 04:52:09 +00:00
|
|
|
* @note Once initialized the transmit service is available.
|
|
|
|
|
* @note To activate receive requires an open to be made.
|
2018-03-01 13:34:09 +00:00
|
|
|
*
|
2018-03-13 14:53:37 +00:00
|
|
|
* @param[in] radio unit ID.
|
2018-03-13 05:17:37 +00:00
|
|
|
*
|
2018-03-08 06:06:35 +00:00
|
|
|
*@return result of operation.
|
|
|
|
|
*@retval true service was created.
|
|
|
|
|
*@retval false service creation failed or state was not idle.
|
2018-03-01 13:34:09 +00:00
|
|
|
*
|
|
|
|
|
* @api
|
|
|
|
|
*/
|
2018-03-13 14:53:37 +00:00
|
|
|
bool pktServiceCreate(radio_unit_t radio) {
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-03-13 14:53:37 +00:00
|
|
|
/*
|
2018-03-29 12:23:12 +00:00
|
|
|
* Get service object maps radio IDs to service objects
|
2018-03-08 06:06:35 +00:00
|
|
|
*/
|
2018-03-29 04:52:09 +00:00
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
if(handler == NULL)
|
2018-03-13 14:53:37 +00:00
|
|
|
return false;
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-03-08 06:06:35 +00:00
|
|
|
if(handler->state != PACKET_IDLE)
|
|
|
|
|
return false;
|
2018-03-01 13:34:09 +00:00
|
|
|
/*
|
|
|
|
|
* Initialize the packet common event object.
|
|
|
|
|
*/
|
|
|
|
|
chEvtObjectInit(pktGetEventSource(handler));
|
|
|
|
|
|
2018-03-08 04:34:41 +00:00
|
|
|
memset(&handler->radio_rx_config, 0, sizeof(radio_task_object_t));
|
|
|
|
|
memset(&handler->radio_tx_config, 0, sizeof(radio_task_object_t));
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-03-29 12:23:12 +00:00
|
|
|
/* Set flags and radio ID. */
|
2018-03-29 04:52:09 +00:00
|
|
|
handler->rx_active = false;
|
2018-03-29 12:23:12 +00:00
|
|
|
handler->radio_init = false;
|
2018-03-29 04:52:09 +00:00
|
|
|
handler->radio = radio;
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
/* Set service semaphore to idle state. */
|
|
|
|
|
chBSemObjectInit(&handler->close_sem, false);
|
|
|
|
|
|
2018-03-29 04:52:09 +00:00
|
|
|
/* Set radio semaphore to free state. */
|
|
|
|
|
chBSemObjectInit(&handler->radio_sem, false);
|
|
|
|
|
|
2018-04-01 15:36:47 +00:00
|
|
|
/*
|
|
|
|
|
* Create outgoing pool if it does not already exist.
|
|
|
|
|
* If it does exist the ref count is increased.
|
|
|
|
|
*/
|
|
|
|
|
/* if(pktOutgoingBufferPoolCreate(radio) == NULL)
|
|
|
|
|
return false;*/
|
|
|
|
|
|
2018-04-03 13:14:31 +00:00
|
|
|
#if USE_NEW_PKT_TX_ALLOC == TRUE
|
2018-04-01 15:36:47 +00:00
|
|
|
/*
|
|
|
|
|
* Create outgoing buffer sempahore if it does not already exist.
|
|
|
|
|
* If it does exist the ref count is increased.
|
|
|
|
|
* If we can't create it get false else true.
|
|
|
|
|
*/
|
2018-04-06 09:54:08 +00:00
|
|
|
if(pktCommonBufferSemaphoreCreate(radio) == NULL)
|
2018-04-01 15:36:47 +00:00
|
|
|
return false;
|
2018-04-03 13:14:31 +00:00
|
|
|
#endif
|
2018-03-08 06:06:35 +00:00
|
|
|
/* Send request to create radio manager. */
|
2018-03-29 04:52:09 +00:00
|
|
|
if (pktRadioManagerCreate(radio) == NULL)
|
2018-03-08 06:06:35 +00:00
|
|
|
return false;
|
|
|
|
|
handler->state = PACKET_READY;
|
|
|
|
|
return true;
|
2018-03-01 13:34:09 +00:00
|
|
|
}
|
|
|
|
|
|
2018-03-08 06:06:35 +00:00
|
|
|
/**
|
|
|
|
|
* @brief Releases packet service.
|
|
|
|
|
* @note The option to manage multiple radios is not yet implemented.
|
2018-03-29 04:52:09 +00:00
|
|
|
* @post The packet service is no longer available for transmit or receive.
|
2018-03-08 06:06:35 +00:00
|
|
|
*
|
2018-03-13 14:53:37 +00:00
|
|
|
* @param[in] radio unit ID
|
|
|
|
|
*
|
2018-03-08 06:06:35 +00:00
|
|
|
*@return result of operation.
|
|
|
|
|
*@retval true service was released.
|
2018-03-29 12:23:12 +00:00
|
|
|
*@retval false service state is incorrect or invalid radio ID.
|
2018-03-08 06:06:35 +00:00
|
|
|
*
|
|
|
|
|
* @api
|
|
|
|
|
*/
|
2018-03-13 14:53:37 +00:00
|
|
|
bool pktServiceRelease(radio_unit_t radio) {
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-03-13 14:53:37 +00:00
|
|
|
/*
|
2018-03-29 04:52:09 +00:00
|
|
|
* Lookup radio and assign handler (RPKTDx).
|
2018-03-13 14:53:37 +00:00
|
|
|
*/
|
2018-03-29 04:52:09 +00:00
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
if(handler == NULL)
|
2018-03-13 14:53:37 +00:00
|
|
|
return false;
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-03-08 06:06:35 +00:00
|
|
|
if(handler->state != PACKET_READY)
|
|
|
|
|
return false;
|
2018-04-03 13:14:31 +00:00
|
|
|
#if USE_NEW_PKT_TX_ALLOC == TRUE
|
2018-04-05 16:18:31 +00:00
|
|
|
pktBufferSemaphoreRelease(radio);
|
2018-04-03 13:14:31 +00:00
|
|
|
#endif
|
2018-03-29 04:52:09 +00:00
|
|
|
pktRadioManagerRelease(radio);
|
2018-03-08 06:06:35 +00:00
|
|
|
handler->state = PACKET_IDLE;
|
|
|
|
|
return true;
|
2018-03-01 13:34:09 +00:00
|
|
|
}
|
|
|
|
|
|
2018-03-29 16:57:34 +00:00
|
|
|
/**
|
|
|
|
|
* @brief Initializes packet handlers and starts the radio manager.
|
|
|
|
|
* @note The option to manage multiple radios is not yet implemented.
|
|
|
|
|
* @note Once initialized the transmit service is available.
|
|
|
|
|
* @note To activate receive requires an open to be made.
|
|
|
|
|
*
|
|
|
|
|
* @param[in] radio unit ID.
|
|
|
|
|
*
|
|
|
|
|
*@return result of operation.
|
|
|
|
|
*@retval true service was created.
|
|
|
|
|
*@retval false service creation failed or state was not idle.
|
|
|
|
|
*
|
|
|
|
|
* @api
|
|
|
|
|
*/
|
|
|
|
|
bool pktServiceHibernate(radio_unit_t radio) {
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get service object maps radio IDs to service objects
|
|
|
|
|
*/
|
|
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
if(handler == NULL)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if(handler->state != PACKET_IDLE)
|
|
|
|
|
return false;
|
|
|
|
|
/*
|
|
|
|
|
* Initialize the packet common event object.
|
|
|
|
|
*/
|
|
|
|
|
chEvtObjectInit(pktGetEventSource(handler));
|
|
|
|
|
|
|
|
|
|
memset(&handler->radio_rx_config, 0, sizeof(radio_task_object_t));
|
|
|
|
|
memset(&handler->radio_tx_config, 0, sizeof(radio_task_object_t));
|
|
|
|
|
|
|
|
|
|
/* Set flags and radio ID. */
|
|
|
|
|
handler->rx_active = false;
|
|
|
|
|
handler->radio_init = false;
|
|
|
|
|
handler->radio = radio;
|
|
|
|
|
|
|
|
|
|
/* Set service semaphore to idle state. */
|
|
|
|
|
chBSemObjectInit(&handler->close_sem, false);
|
|
|
|
|
|
|
|
|
|
/* Set radio semaphore to free state. */
|
|
|
|
|
chBSemObjectInit(&handler->radio_sem, false);
|
|
|
|
|
|
|
|
|
|
/* Send request to create radio manager. */
|
|
|
|
|
if (pktRadioManagerCreate(radio) == NULL)
|
|
|
|
|
return false;
|
|
|
|
|
handler->state = PACKET_READY;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Releases packet service.
|
|
|
|
|
* @note The option to manage multiple radios is not yet implemented.
|
|
|
|
|
* @post The packet service is no longer available for transmit or receive.
|
|
|
|
|
*
|
|
|
|
|
* @param[in] radio unit ID
|
|
|
|
|
*
|
|
|
|
|
*@return result of operation.
|
|
|
|
|
*@retval true service was released.
|
|
|
|
|
*@retval false service state is incorrect or invalid radio ID.
|
|
|
|
|
*
|
|
|
|
|
* @api
|
|
|
|
|
*/
|
|
|
|
|
bool pktServiceWakeup(radio_unit_t radio) {
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Lookup radio and assign handler (RPKTDx).
|
|
|
|
|
*/
|
|
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
if(handler == NULL)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if(handler->state != PACKET_READY)
|
|
|
|
|
return false;
|
|
|
|
|
pktRadioManagerRelease(radio);
|
|
|
|
|
handler->state = PACKET_IDLE;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-01 13:34:09 +00:00
|
|
|
/**
|
2018-03-29 04:52:09 +00:00
|
|
|
* @brief Opens a packet receive service.
|
2018-03-01 13:34:09 +00:00
|
|
|
* @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).
|
|
|
|
|
*
|
2018-03-29 04:52:09 +00:00
|
|
|
* @return status of operation.
|
2018-03-01 13:34:09 +00:00
|
|
|
* @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
|
|
|
|
|
*/
|
2018-03-29 04:52:09 +00:00
|
|
|
msg_t pktOpenRadioReceive(radio_unit_t radio,
|
2018-03-01 13:34:09 +00:00
|
|
|
encoding_type_t encoding,
|
|
|
|
|
radio_freq_t frequency,
|
2018-03-29 04:52:09 +00:00
|
|
|
channel_hz_t ch_step) {
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-03-29 04:52:09 +00:00
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
if(handler == NULL)
|
2018-03-13 14:53:37 +00:00
|
|
|
return MSG_RESET;
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-03-08 06:06:35 +00:00
|
|
|
chDbgCheck(handler->state == PACKET_READY);
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-03-08 06:06:35 +00:00
|
|
|
if(handler->state != PACKET_READY)
|
2018-03-01 13:34:09 +00:00
|
|
|
return MSG_RESET;
|
|
|
|
|
|
|
|
|
|
/* Wait for any prior session to complete closing. */
|
|
|
|
|
chBSemWait(&handler->close_sem);
|
|
|
|
|
|
|
|
|
|
/* Save radio configuration. */
|
2018-03-08 04:34:41 +00:00
|
|
|
handler->radio_rx_config.type = encoding;
|
|
|
|
|
handler->radio_rx_config.base_frequency = frequency;
|
|
|
|
|
handler->radio_rx_config.step_hz = ch_step;
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
/* Reset the statistics collection variables. */
|
|
|
|
|
handler->sync_count = 0;
|
|
|
|
|
handler->frame_count = 0;
|
|
|
|
|
handler->valid_count = 0;
|
|
|
|
|
handler->good_count = 0;
|
|
|
|
|
|
2018-03-08 04:34:41 +00:00
|
|
|
radio_task_object_t rt = handler->radio_rx_config;
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
/* Set parameters for radio command. */
|
2018-03-08 04:34:41 +00:00
|
|
|
rt.command = PKT_RADIO_RX_OPEN;
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Open (init) the radio (via submit radio task).
|
|
|
|
|
*/
|
2018-04-06 09:54:08 +00:00
|
|
|
msg_t msg = pktSendRadioCommand(radio, &rt, NULL);
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
if(msg != MSG_OK)
|
|
|
|
|
return msg;
|
|
|
|
|
|
|
|
|
|
handler->state = PACKET_OPEN;
|
|
|
|
|
pktAddEventFlags(handler, EVT_PKT_CHANNEL_OPEN);
|
|
|
|
|
|
|
|
|
|
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
|
2018-03-06 03:58:03 +00:00
|
|
|
* @param[in] sq the RSSI setting to be used.
|
2018-03-01 13:34:09 +00:00
|
|
|
* @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
|
|
|
|
|
*/
|
2018-03-13 14:53:37 +00:00
|
|
|
msg_t pktStartDataReception(radio_unit_t radio,
|
2018-03-01 13:34:09 +00:00
|
|
|
radio_ch_t channel,
|
|
|
|
|
radio_squelch_t sq,
|
|
|
|
|
pkt_buffer_cb_t cb) {
|
|
|
|
|
|
2018-03-29 04:52:09 +00:00
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
if(handler == NULL)
|
2018-03-13 14:53:37 +00:00
|
|
|
return MSG_RESET;
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
if(!(handler->state == PACKET_OPEN || handler->state == PACKET_STOP))
|
|
|
|
|
return MSG_RESET;
|
|
|
|
|
|
|
|
|
|
handler->usr_callback = cb;
|
|
|
|
|
|
2018-03-08 04:34:41 +00:00
|
|
|
handler->radio_rx_config.channel = channel;
|
|
|
|
|
handler->radio_rx_config.squelch = sq;
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-03-08 04:34:41 +00:00
|
|
|
radio_task_object_t rt = handler->radio_rx_config;
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-03-08 04:34:41 +00:00
|
|
|
rt.command = PKT_RADIO_RX_START;
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-04-06 09:54:08 +00:00
|
|
|
msg_t msg = pktSendRadioCommand(radio, &rt, NULL);
|
2018-03-01 13:34:09 +00:00
|
|
|
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.
|
|
|
|
|
*
|
2018-03-13 14:53:37 +00:00
|
|
|
* @param[in] radio unit ID.
|
2018-03-01 13:34:09 +00:00
|
|
|
*
|
|
|
|
|
* @api
|
|
|
|
|
*/
|
2018-03-13 14:53:37 +00:00
|
|
|
void pktStartDecoder(radio_unit_t radio) {
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-03-29 04:52:09 +00:00
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
|
|
|
|
|
chDbgAssert(handler != NULL, "invalid radio ID");
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
event_listener_t el;
|
|
|
|
|
event_source_t *esp;
|
|
|
|
|
|
2018-03-08 04:34:41 +00:00
|
|
|
switch(handler->radio_rx_config.type) {
|
2018-03-08 00:56:52 +00:00
|
|
|
case MOD_AFSK: {
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
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. */
|
|
|
|
|
|
2018-03-08 00:56:52 +00:00
|
|
|
case MOD_2FSK: {
|
2018-03-01 13:34:09 +00:00
|
|
|
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.
|
|
|
|
|
*
|
2018-03-13 14:53:37 +00:00
|
|
|
* @param[in] radio radio unit ID..
|
2018-03-01 13:34:09 +00:00
|
|
|
*
|
|
|
|
|
* @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
|
|
|
|
|
*/
|
2018-03-13 14:53:37 +00:00
|
|
|
msg_t pktStopDataReception(radio_unit_t radio) {
|
|
|
|
|
|
2018-03-29 04:52:09 +00:00
|
|
|
|
|
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
|
|
|
|
|
if(handler == NULL)
|
2018-03-13 14:53:37 +00:00
|
|
|
return MSG_RESET;
|
|
|
|
|
|
2018-03-01 13:34:09 +00:00
|
|
|
if(handler->state != PACKET_RUN)
|
|
|
|
|
return MSG_RESET;
|
|
|
|
|
|
|
|
|
|
/* Stop the radio processing. */
|
|
|
|
|
|
2018-03-08 04:34:41 +00:00
|
|
|
radio_task_object_t rt = handler->radio_rx_config;
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
rt.command = PKT_RADIO_RX_STOP;
|
|
|
|
|
|
2018-04-06 09:54:08 +00:00
|
|
|
msg_t msg = pktSendRadioCommand(radio, &rt, NULL);
|
2018-03-01 13:34:09 +00:00
|
|
|
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.
|
|
|
|
|
*
|
2018-03-13 14:53:37 +00:00
|
|
|
* @param[in] radio unit ID.
|
2018-03-01 13:34:09 +00:00
|
|
|
*
|
|
|
|
|
* @api
|
|
|
|
|
*/
|
2018-03-13 14:53:37 +00:00
|
|
|
void pktStopDecoder(radio_unit_t radio) {
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-03-29 04:52:09 +00:00
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
|
|
|
|
|
if(handler == NULL)
|
2018-03-13 14:53:37 +00:00
|
|
|
chDbgAssert(false, "invalid radio ID");
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
event_listener_t el;
|
|
|
|
|
event_source_t *esp;
|
|
|
|
|
|
2018-03-08 04:34:41 +00:00
|
|
|
switch(handler->radio_rx_config.type) {
|
2018-03-08 00:56:52 +00:00
|
|
|
case MOD_AFSK: {
|
2018-03-01 13:34:09 +00:00
|
|
|
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. */
|
|
|
|
|
|
2018-03-08 00:56:52 +00:00
|
|
|
case MOD_2FSK: {
|
2018-03-01 13:34:09 +00:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2018-03-29 04:52:09 +00:00
|
|
|
* @brief Closes a packet receive service.
|
2018-03-01 13:34:09 +00:00
|
|
|
* @pre The packet service must have been stopped.
|
2018-03-13 14:53:37 +00:00
|
|
|
* @post The packet service is closed and returned to ready state.
|
2018-03-01 13:34:09 +00:00
|
|
|
* @post Memory used by the decoder thread is released.
|
|
|
|
|
*
|
2018-03-13 14:53:37 +00:00
|
|
|
* @param[in] radio radio unit ID.
|
2018-03-01 13:34:09 +00:00
|
|
|
*
|
|
|
|
|
* @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
|
|
|
|
|
*/
|
2018-03-29 04:52:09 +00:00
|
|
|
msg_t pktCloseRadioReceive(radio_unit_t radio) {
|
2018-03-13 14:53:37 +00:00
|
|
|
|
2018-03-29 04:52:09 +00:00
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
if(handler == NULL)
|
2018-03-13 14:53:37 +00:00
|
|
|
return MSG_RESET;
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-03-13 14:53:37 +00:00
|
|
|
if(!(handler->state == PACKET_STOP || handler->state == PACKET_CLOSE))
|
2018-03-01 13:34:09 +00:00
|
|
|
return MSG_RESET;
|
|
|
|
|
|
|
|
|
|
handler->state = PACKET_CLOSE;
|
|
|
|
|
|
|
|
|
|
/* Set parameters for radio. */;
|
|
|
|
|
|
2018-03-08 04:34:41 +00:00
|
|
|
radio_task_object_t rt = handler->radio_rx_config;
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-03-08 04:34:41 +00:00
|
|
|
rt.command = PKT_RADIO_RX_CLOSE;
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
/* Submit command. A timeout can occur waiting for a command queue object. */
|
2018-04-06 09:54:08 +00:00
|
|
|
msg_t msg = pktSendRadioCommand(radio, &rt, NULL);
|
2018-03-01 13:34:09 +00:00
|
|
|
if(msg != MSG_OK)
|
|
|
|
|
return msg;
|
|
|
|
|
|
|
|
|
|
pktAddEventFlags(handler, EVT_PKT_CHANNEL_CLOSE);
|
2018-03-08 06:06:35 +00:00
|
|
|
handler->state = PACKET_READY;
|
2018-03-01 13:34:09 +00:00
|
|
|
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 {
|
2018-03-11 15:10:24 +00:00
|
|
|
flags |= EVT_PKT_INVALID_FRAME;
|
2018-03-01 13:34:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Update status in packet buffer object. */
|
|
|
|
|
pkt_buffer->status |= flags;
|
|
|
|
|
|
2018-03-11 15:10:24 +00:00
|
|
|
objects_fifo_t *pkt_fifo = chFactoryGetObjectsFIFO(pkt_buffer->pkt_factory);
|
|
|
|
|
|
|
|
|
|
chDbgAssert(pkt_fifo != NULL, "no packet FIFO");
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-03-11 15:10:24 +00:00
|
|
|
if(pkt_buffer->cb_func == NULL) {
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
/* 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");
|
|
|
|
|
|
2018-03-11 15:10:24 +00:00
|
|
|
if(cb_thd == NULL) {
|
|
|
|
|
/* Failed to create CB thread. Release buffer. Flag event. */
|
|
|
|
|
chFifoReturnObject(pkt_fifo, pkt_buffer);
|
|
|
|
|
flags |= EVT_PKT_FAILED_CB_THD;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
/* Increase outstanding callback count. */
|
|
|
|
|
handler->cb_count++;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-01 13:34:09 +00:00
|
|
|
}
|
|
|
|
|
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. */
|
2018-03-29 04:52:09 +00:00
|
|
|
/* TODO: Create a more meaningful but still unique thread name. */
|
2018-03-01 13:34:09 +00:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2018-03-05 07:35:39 +00:00
|
|
|
* @brief Process release of completed callbacks.
|
2018-03-01 13:34:09 +00:00
|
|
|
* @notes Release is initiated by posting the packet buffer to the queue.
|
2018-03-05 07:35:39 +00:00
|
|
|
* @notes The queue is used as a completion mechanism in callback mode.
|
|
|
|
|
* @notes In poll mode the received packet is posted to the consumer
|
2018-03-01 13:34:09 +00:00
|
|
|
*
|
|
|
|
|
* @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.
|
|
|
|
|
*
|
2018-03-29 04:52:09 +00:00
|
|
|
* @param[in] arg radio unit ID.
|
2018-03-01 13:34:09 +00:00
|
|
|
*
|
2018-03-05 07:35:39 +00:00
|
|
|
* @return status (MSG_OK) on exit.
|
2018-03-01 13:34:09 +00:00
|
|
|
*
|
|
|
|
|
* @notapi
|
|
|
|
|
*/
|
2018-03-29 04:52:09 +00:00
|
|
|
|
2018-04-01 15:36:47 +00:00
|
|
|
/* TODO: Deprecate and use radio manager thread for callback release? */
|
2018-03-01 13:34:09 +00:00
|
|
|
THD_FUNCTION(pktCompletion, arg) {
|
|
|
|
|
packet_svc_t *handler = arg;
|
|
|
|
|
#define PKT_COMPLETION_THREAD_TIMER 100 /* 100 mS. */
|
2018-03-29 04:52:09 +00:00
|
|
|
|
|
|
|
|
chDbgAssert(handler != NULL, "invalid handler reference");
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-01 15:36:47 +00:00
|
|
|
/**
|
|
|
|
|
* @brief Create receive callback thread terminator.
|
|
|
|
|
*
|
|
|
|
|
* @param[in] arg radio unit ID.
|
|
|
|
|
*
|
|
|
|
|
* @notapi
|
|
|
|
|
*/
|
2018-03-29 04:52:09 +00:00
|
|
|
void pktCallbackManagerOpen(radio_unit_t radio) {
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-03-29 04:52:09 +00:00
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
|
|
|
|
|
chDbgAssert(handler != NULL, "invalid radio ID");
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
/* Create the callback handler thread name. */
|
|
|
|
|
chsnprintf(handler->cbend_name, sizeof(handler->cbend_name),
|
2018-03-29 04:52:09 +00:00
|
|
|
"%s%02i", PKT_CALLBACK_TERMINATOR_PREFIX, radio);
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-29 04:52:09 +00:00
|
|
|
/*
|
|
|
|
|
*
|
|
|
|
|
*/
|
2018-04-01 15:36:47 +00:00
|
|
|
dyn_objects_fifo_t *pktIncomingBufferPoolCreate(radio_unit_t radio) {
|
2018-03-29 04:52:09 +00:00
|
|
|
|
|
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
|
|
|
|
|
chDbgAssert(handler != NULL, "invalid radio ID");
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
/* Create the packet buffer name for this radio. */
|
|
|
|
|
chsnprintf(handler->pbuff_name, sizeof(handler->pbuff_name),
|
2018-03-29 04:52:09 +00:00
|
|
|
"%s%02i", PKT_FRAME_QUEUE_PREFIX, radio);
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
/* 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),
|
2018-04-01 15:36:47 +00:00
|
|
|
NUMBER_RX_PKT_BUFFERS, sizeof(msg_t));
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-04-01 15:36:47 +00:00
|
|
|
chDbgAssert(dyn_fifo != NULL, "failed to create receive PKT objects FIFO");
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
if(dyn_fifo == NULL) {
|
|
|
|
|
/* TODO: Close decoder on fail. */
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-01 15:36:47 +00:00
|
|
|
/* Save the factory FIFO reference. */
|
2018-03-01 13:34:09 +00:00
|
|
|
handler->the_packet_fifo = dyn_fifo;
|
|
|
|
|
|
|
|
|
|
/* Initialize packet buffer pointer. */
|
|
|
|
|
handler->active_packet_object = NULL;
|
|
|
|
|
return dyn_fifo;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-01 15:36:47 +00:00
|
|
|
/*
|
|
|
|
|
* Send shares a common pool of buffers.
|
|
|
|
|
*/
|
2018-04-06 09:54:08 +00:00
|
|
|
dyn_objects_fifo_t *pktCommonBufferPoolCreate(radio_unit_t radio) {
|
2018-04-01 15:36:47 +00:00
|
|
|
|
|
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
|
|
|
|
|
chDbgAssert(handler != NULL, "invalid radio ID");
|
|
|
|
|
|
|
|
|
|
/* Check if the transmit packet buffer factory already exists.
|
|
|
|
|
* If so we get a pointer to it and just return that.
|
|
|
|
|
* Otherwise create the FIFO and return result.
|
|
|
|
|
*/
|
|
|
|
|
dyn_objects_fifo_t *dyn_fifo =
|
|
|
|
|
chFactoryFindObjectsFIFO(PKT_SEND_BUFFER_NAME);
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-04-01 15:36:47 +00:00
|
|
|
if(dyn_fifo == NULL) {
|
|
|
|
|
/* Create the dynamic objects FIFO for the packet data queue. */
|
|
|
|
|
dyn_fifo = chFactoryCreateObjectsFIFO(PKT_SEND_BUFFER_NAME,
|
|
|
|
|
sizeof(packet_tx_t),
|
2018-04-06 09:54:08 +00:00
|
|
|
NUMBER_COMMON_PKT_BUFFERS, sizeof(msg_t));
|
2018-04-01 15:36:47 +00:00
|
|
|
|
|
|
|
|
chDbgAssert(dyn_fifo != NULL, "failed to create send PKT objects FIFO");
|
|
|
|
|
}
|
|
|
|
|
/* Save the factory FIFO reference. */
|
|
|
|
|
handler->tx_packet_fifo = dyn_fifo;
|
|
|
|
|
return dyn_fifo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Send shares a common pool of buffers.
|
|
|
|
|
*/
|
2018-04-06 09:54:08 +00:00
|
|
|
void pktCommonBufferPoolRelease(radio_unit_t radio) {
|
2018-04-01 15:36:47 +00:00
|
|
|
|
|
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
|
|
|
|
|
chDbgAssert(handler != NULL, "invalid radio ID");
|
|
|
|
|
chDbgAssert(handler->tx_packet_fifo != NULL, "no outgoing FIFO assigned");
|
|
|
|
|
/* Release FIFO. If this is the last radio using it the FIFO is released. */
|
|
|
|
|
chFactoryReleaseObjectsFIFO(handler->tx_packet_fifo);
|
|
|
|
|
handler->tx_packet_fifo = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Send shares a common pool of buffers.
|
|
|
|
|
*/
|
2018-04-06 09:54:08 +00:00
|
|
|
dyn_semaphore_t *pktCommonBufferSemaphoreCreate(radio_unit_t radio) {
|
2018-04-01 15:36:47 +00:00
|
|
|
|
|
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
|
|
|
|
|
chDbgAssert(handler != NULL, "invalid radio ID");
|
|
|
|
|
|
|
|
|
|
/* Check if the transmit packet buffer semaphore already exists.
|
|
|
|
|
* If so we get a pointer to it and just return that.
|
|
|
|
|
* Otherwise create the semaphore and return result.
|
|
|
|
|
*/
|
|
|
|
|
dyn_semaphore_t *dyn_sem =
|
|
|
|
|
chFactoryFindSemaphore(PKT_SEND_BUFFER_SEM_NAME);
|
|
|
|
|
|
|
|
|
|
if(dyn_sem == NULL) {
|
|
|
|
|
/* Create the dynamic objects FIFO for the packet data queue. */
|
|
|
|
|
dyn_sem = chFactoryCreateSemaphore(PKT_SEND_BUFFER_SEM_NAME,
|
2018-04-06 09:54:08 +00:00
|
|
|
NUMBER_COMMON_PKT_BUFFERS);
|
2018-04-01 15:36:47 +00:00
|
|
|
|
|
|
|
|
chDbgAssert(dyn_sem != NULL, "failed to create send PKT semaphore");
|
|
|
|
|
} else {
|
|
|
|
|
/* Increase buffer number by adjusting semaphore.
|
|
|
|
|
* TODO: Once bumped up the count can't be decreased if a radio is closed. */
|
|
|
|
|
/* chSysLock();
|
|
|
|
|
chSemAddCounterI(chFactoryGetSemaphore(dyn_sem), NUMBER_TX_PKT_BUFFERS);
|
|
|
|
|
chSchRescheduleS();
|
|
|
|
|
chSysUnlock();*/
|
|
|
|
|
}
|
|
|
|
|
handler->tx_packet_sem = dyn_sem;
|
|
|
|
|
return dyn_sem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Send shares a common pool of buffers.
|
|
|
|
|
* @retval MSG_RESET if the semaphore has been reset using @p chSemReset().
|
|
|
|
|
* @retval MSG_TIMEOUT if the semaphore has not been signaled or reset within
|
|
|
|
|
* the specified timeout.
|
|
|
|
|
*/
|
2018-04-05 16:18:31 +00:00
|
|
|
msg_t pktGetPacketBuffer(packet_t *pp, sysinterval_t timeout) {
|
2018-04-01 15:36:47 +00:00
|
|
|
|
|
|
|
|
/* Check if the transmit packet buffer semaphore already exists.
|
|
|
|
|
* If so we get a pointer to it and just return that.
|
|
|
|
|
* Otherwise create the semaphore and return result.
|
|
|
|
|
*/
|
|
|
|
|
dyn_semaphore_t *dyn_sem =
|
|
|
|
|
chFactoryFindSemaphore(PKT_SEND_BUFFER_SEM_NAME);
|
|
|
|
|
|
|
|
|
|
chDbgAssert(dyn_sem != NULL, "no send PKT semaphore");
|
|
|
|
|
|
|
|
|
|
*pp = NULL;
|
|
|
|
|
|
|
|
|
|
if(dyn_sem == NULL)
|
|
|
|
|
return MSG_TIMEOUT;
|
|
|
|
|
|
|
|
|
|
/* Decrease ref count. */
|
|
|
|
|
chFactoryReleaseSemaphore(dyn_sem);
|
|
|
|
|
|
|
|
|
|
/* Wait in queue for permission to allocate a buffer. */
|
|
|
|
|
msg_t msg = chSemWaitTimeout(chFactoryGetSemaphore(dyn_sem), timeout);
|
|
|
|
|
if(msg != MSG_OK)
|
|
|
|
|
/* This can be MSG_TIMEOUT or MSG_RESET. */
|
|
|
|
|
return msg;
|
|
|
|
|
|
|
|
|
|
/* Allocate buffer.
|
|
|
|
|
* If this returns null then all heap is consumed.
|
|
|
|
|
*/
|
|
|
|
|
*pp = ax25_new();
|
|
|
|
|
if(pp == NULL)
|
|
|
|
|
return MSG_TIMEOUT;
|
|
|
|
|
return MSG_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2018-04-05 16:18:31 +00:00
|
|
|
* A common pool of AX25 buffers.
|
2018-04-01 15:36:47 +00:00
|
|
|
*/
|
2018-04-05 16:18:31 +00:00
|
|
|
void pktReleasePacketBuffer(packet_t pp) {
|
2018-04-01 15:36:47 +00:00
|
|
|
|
2018-04-05 16:18:31 +00:00
|
|
|
/* Check if the packet buffer semaphore exists.
|
|
|
|
|
* If not this is a system error.
|
2018-04-01 15:36:47 +00:00
|
|
|
*/
|
|
|
|
|
dyn_semaphore_t *dyn_sem =
|
|
|
|
|
chFactoryFindSemaphore(PKT_SEND_BUFFER_SEM_NAME);
|
|
|
|
|
|
2018-04-05 16:18:31 +00:00
|
|
|
chDbgAssert(dyn_sem != NULL, "no general packet buffer semaphore");
|
2018-04-01 15:36:47 +00:00
|
|
|
|
|
|
|
|
/* Free buffer memory. */
|
|
|
|
|
ax25_delete(pp);
|
|
|
|
|
|
|
|
|
|
/* Relinquish the buffer creation permission. */
|
|
|
|
|
chSemSignal(chFactoryGetSemaphore(dyn_sem));
|
|
|
|
|
|
|
|
|
|
/* Decrease factory ref count. */
|
|
|
|
|
chFactoryReleaseSemaphore(dyn_sem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Send shares a common pool of buffers.
|
|
|
|
|
*/
|
2018-04-05 16:18:31 +00:00
|
|
|
void pktBufferSemaphoreRelease(radio_unit_t radio) {
|
2018-04-01 15:36:47 +00:00
|
|
|
|
|
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
|
|
|
|
|
chDbgAssert(handler != NULL, "invalid radio ID");
|
|
|
|
|
chDbgAssert(handler->tx_packet_fifo != NULL, "no outgoing FIFO assigned");
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Release Semaphore.
|
|
|
|
|
* If this is the last radio using the semaphore it is released.
|
|
|
|
|
*/
|
|
|
|
|
chFactoryReleaseSemaphore(handler->tx_packet_sem);
|
|
|
|
|
handler->tx_packet_sem = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*
|
|
|
|
|
*/
|
2018-03-29 04:52:09 +00:00
|
|
|
thread_t *pktCallbackManagerCreate(radio_unit_t radio) {
|
|
|
|
|
|
|
|
|
|
packet_svc_t *handler = pktGetServiceObject(radio);
|
|
|
|
|
|
|
|
|
|
chDbgAssert(handler != NULL, "invalid radio ID");
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
/* Create the callback termination thread name. */
|
|
|
|
|
chsnprintf(handler->cbend_name, sizeof(handler->cbend_name),
|
2018-03-29 04:52:09 +00:00
|
|
|
"%s%02i", PKT_CALLBACK_TERMINATOR_PREFIX, radio);
|
2018-03-01 13:34:09 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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;
|
2018-03-26 08:22:17 +00:00
|
|
|
return cbh;
|
2018-03-01 13:34:09 +00:00
|
|
|
}
|
|
|
|
|
|
2018-04-01 15:36:47 +00:00
|
|
|
void pktIncomingBufferPoolRelease(packet_svc_t *handler) {
|
2018-03-01 13:34:09 +00:00
|
|
|
|
2018-04-01 15:36:47 +00:00
|
|
|
/* Release the dynamic objects FIFO for the incoming packet data queue. */
|
2018-03-01 13:34:09 +00:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-29 04:52:09 +00:00
|
|
|
/*void pktScheduleThreadRelease(thread_t *thread) {
|
2018-03-26 08:22:17 +00:00
|
|
|
(void)thread;
|
2018-03-29 04:52:09 +00:00
|
|
|
}*/
|
2018-03-26 08:22:17 +00:00
|
|
|
|
2018-03-01 13:34:09 +00:00
|
|
|
/** @} */
|