You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
543 lines
19 KiB
C
543 lines
19 KiB
C
/***************************************************************************//**
|
|
* @file
|
|
* @brief RAILtest transmit and receive events
|
|
*******************************************************************************
|
|
* # License
|
|
* <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
|
|
*******************************************************************************
|
|
*
|
|
* SPDX-License-Identifier: Zlib
|
|
*
|
|
* The licensor of this software is Silicon Laboratories Inc.
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
* arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "rail.h"
|
|
#include "rail_types.h"
|
|
|
|
#include "buffer_pool_allocator.h"
|
|
#include "circular_queue.h"
|
|
|
|
#include "app_common.h"
|
|
#include "app_trx.h"
|
|
#include "rail_ble.h"
|
|
#include "rail_ieee802154.h"
|
|
/******************************************************************************
|
|
* Variables
|
|
*****************************************************************************/
|
|
RAIL_TxPacketDetails_t previousTxAppendedInfo = { .isAck = false, };
|
|
RAIL_TxPacketDetails_t previousTxAckAppendedInfo = { .isAck = true, };
|
|
|
|
static uint16_t dataLeft = 0;
|
|
static uint8_t *dataLeftPtr = NULL;
|
|
|
|
// Variables to keep track of the receive packet
|
|
static uint16_t rxLengthTarget;
|
|
static uint16_t rxLengthCount;
|
|
static void *rxFifoPacketHandle = 0;
|
|
static RailAppEvent_t *rxFifoPacketData;
|
|
static uint8_t *currentRxFifoPacketPtr;
|
|
|
|
uint32_t abortRxDelay = 0;
|
|
|
|
// Used for wakeup from sleep
|
|
volatile bool rxPacketEvent = false;
|
|
|
|
// fifo mode test variables
|
|
/*
|
|
* This test bit is used to prevent RAILtest from automatically loading packet
|
|
* data into transmit fifo
|
|
*/
|
|
bool txFifoManual = false;
|
|
/*
|
|
* This test bit is used to prevent RAILtest from automatically reading out the
|
|
* packet from the fifo
|
|
*/
|
|
bool rxFifoManual = false;
|
|
|
|
// To enable power manager sleep from the main loop.
|
|
extern volatile bool allowPowerManagerSleep;
|
|
|
|
/******************************************************************************
|
|
* Static
|
|
*****************************************************************************/
|
|
static void packetMode_RxPacketAborted(RAIL_Handle_t railHandle)
|
|
{
|
|
if (!printRxErrorPackets) {
|
|
return;
|
|
}
|
|
RAIL_RxPacketInfo_t packetInfo;
|
|
RAIL_RxPacketHandle_t packetHandle
|
|
= RAIL_GetRxPacketInfo(railHandle, RAIL_RX_PACKET_HANDLE_NEWEST,
|
|
&packetInfo);
|
|
// assert(packetHandle != NULL);
|
|
// assert(packetInfo.packetBytes == 0);
|
|
// Get a memory buffer for the received packet details
|
|
void *rxPacketMemoryHandle = memoryAllocate(sizeof(RailAppEvent_t));
|
|
RailAppEvent_t *rxPacket = (RailAppEvent_t *)memoryPtrFromHandle(rxPacketMemoryHandle);
|
|
if (rxPacket != NULL) {
|
|
rxPacket->type = RX_PACKET;
|
|
rxPacket->rxPacket.dataPtr = NULL;
|
|
rxPacket->rxPacket.packetStatus = packetInfo.packetStatus;
|
|
rxPacket->rxPacket.dataLength = 0U;
|
|
rxPacket->rxPacket.freqOffset = getRxFreqOffset();
|
|
rxPacket->rxPacket.filterMask = 0U;
|
|
// Read what packet details are available into our packet structure
|
|
if (RAIL_GetRxPacketDetailsAlt(railHandle, packetHandle,
|
|
&rxPacket->rxPacket.appendedInfo)
|
|
!= RAIL_STATUS_NO_ERROR) {
|
|
// assert(false);
|
|
memset(&rxPacket->rxPacket.appendedInfo, 0, sizeof(rxPacket->rxPacket.appendedInfo));
|
|
}
|
|
if (logLevel & ASYNC_RESPONSE) {
|
|
// Take an extra reference to this rx packet pointer so it's not released
|
|
memoryTakeReference(rxPacketMemoryHandle);
|
|
// Copy this received packet into our circular queue
|
|
queueAdd(&railAppEventQueue, rxPacketMemoryHandle);
|
|
}
|
|
// Do not include Rx Error packets in PER's RSSI stats:
|
|
// updateStats(rxPacket->appendedInfo.rssi, &counters.rssi);
|
|
} else {
|
|
counters.noRxBuffer++;
|
|
eventsMissed++;
|
|
}
|
|
// Free the allocated memory now that we're done with it
|
|
memoryFree(rxPacketMemoryHandle);
|
|
}
|
|
|
|
static void packetMode_RxPacketReceived(RAIL_Handle_t railHandle)
|
|
{
|
|
if ((rxSuccessTransition == RAIL_RF_STATE_TX)
|
|
|| (RAIL_IsAutoAckEnabled(railHandle) && afterRxUseTxBufferForAck)) {
|
|
// Load packet for either the non-AutoACK RXSUCCESS => TX transition,
|
|
// or for the ACK transition when we intend to use the TX buffer
|
|
// We don't do this in other circumstances in case of an RX2TX
|
|
// transition to send a packet that's already been loaded,
|
|
// which could cause TX underflow if we were to disturb it.
|
|
RAIL_WriteTxFifo(railHandle, txData, txDataLen, true);
|
|
}
|
|
|
|
if (rxHeld) {
|
|
(void)RAIL_HoldRxPacket(railHandle);
|
|
packetsHeld++;
|
|
} else {
|
|
(void)processRxPacket(railHandle, RAIL_RX_PACKET_HANDLE_NEWEST);
|
|
}
|
|
}
|
|
|
|
RAIL_RxPacketHandle_t processRxPacket(RAIL_Handle_t railHandle,
|
|
RAIL_RxPacketHandle_t packetHandle)
|
|
{
|
|
RAIL_RxPacketInfo_t packetInfo;
|
|
packetHandle = RAIL_GetRxPacketInfo(railHandle, packetHandle, &packetInfo);
|
|
if (packetHandle == RAIL_RX_PACKET_HANDLE_INVALID) {
|
|
return packetHandle;
|
|
}
|
|
uint16_t length = packetInfo.packetBytes;
|
|
void *rxPacketMemoryHandle = memoryAllocate(sizeof(RailAppEvent_t) + length);
|
|
RailAppEvent_t *rxPacket = (RailAppEvent_t *)memoryPtrFromHandle(rxPacketMemoryHandle);
|
|
uint8_t *rxPacketData = (uint8_t *)&rxPacket[1];
|
|
|
|
// Count packets that we received but had no memory to store
|
|
if (rxPacket == NULL) {
|
|
counters.noRxBuffer++;
|
|
} else {
|
|
RAIL_Status_t status;
|
|
rxPacket->type = RX_PACKET;
|
|
rxPacket->rxPacket.dataPtr = rxPacketData;
|
|
rxPacket->rxPacket.packetStatus = packetInfo.packetStatus;
|
|
// Read packet data into our packet structure
|
|
RAIL_CopyRxPacket(rxPacketData, &packetInfo);
|
|
rxPacket->rxPacket.filterMask = packetInfo.filterMask;
|
|
rxPacket->rxPacket.dataLength = length;
|
|
rxPacket->rxPacket.freqOffset = getRxFreqOffset();
|
|
|
|
// Read the appended info into our packet structure
|
|
status = RAIL_GetRxPacketDetailsAlt(railHandle, packetHandle,
|
|
&rxPacket->rxPacket.appendedInfo);
|
|
if (status == RAIL_STATUS_NO_ERROR) {
|
|
// Note that this does not take into account CRC bytes unless
|
|
// RAIL_RX_OPTION_STORE_CRC is used
|
|
rxPacket->rxPacket.appendedInfo.timeReceived.totalPacketBytes = length;
|
|
(void) (*rxTimePosition)(railHandle, &rxPacket->rxPacket.appendedInfo);
|
|
}
|
|
if (status != RAIL_STATUS_NO_ERROR) {
|
|
memset(&rxPacket->rxPacket.appendedInfo, 0, sizeof(rxPacket->rxPacket.appendedInfo));
|
|
}
|
|
|
|
// If we have just received an ACK, don't respond with an ACK
|
|
if (rxPacketData[2] == 0xF1) {
|
|
RAIL_CancelAutoAck(railHandle);
|
|
}
|
|
|
|
// Cancel ack if user requested
|
|
if (afterRxCancelAck) {
|
|
afterRxCancelAck = false;
|
|
RAIL_CancelAutoAck(railHandle);
|
|
}
|
|
|
|
// Use Tx Buffer for Ack if user requested
|
|
if (afterRxUseTxBufferForAck) {
|
|
afterRxUseTxBufferForAck = false;
|
|
RAIL_UseTxFifoForAutoAck(railHandle);
|
|
}
|
|
|
|
if (currentAppMode() == SCHTX_AFTER_RX) {
|
|
// Schedule the next transmit after this receive
|
|
RAIL_ScheduleTxConfig_t scheduledTxOptions = {
|
|
//TODO: packetTime depends on rxTimePosition;
|
|
// this code assumes default position (SYNC_END).
|
|
.when = rxPacket->rxPacket.appendedInfo.timeReceived.packetTime
|
|
+ txAfterRxDelay,
|
|
.mode = RAIL_TIME_ABSOLUTE,
|
|
.txDuringRx = RAIL_SCHEDULED_TX_DURING_RX_POSTPONE_TX
|
|
};
|
|
|
|
setNextPacketTime(&scheduledTxOptions);
|
|
|
|
txCount = 1;
|
|
pendPacketTx();
|
|
}
|
|
|
|
if (phySwitchToRx.enable) {
|
|
//TODO: packetTime depends on rxTimePosition;
|
|
// this code assumes default position (SYNC_END).
|
|
uint32_t syncTime = rxPacket->rxPacket.appendedInfo.timeReceived.packetTime;
|
|
(void) RAIL_BLE_PhySwitchToRx(railHandle,
|
|
phySwitchToRx.phy,
|
|
phySwitchToRx.physicalChannel,
|
|
phySwitchToRx.timeDelta + syncTime,
|
|
phySwitchToRx.crcInit,
|
|
phySwitchToRx.accessAddress,
|
|
phySwitchToRx.logicalChannel,
|
|
phySwitchToRx.disableWhitening);
|
|
}
|
|
|
|
if (logLevel & ASYNC_RESPONSE) {
|
|
updateGraphics();
|
|
|
|
// Take an extra reference to this rx packet pointer so it's not released
|
|
memoryTakeReference(rxPacketMemoryHandle);
|
|
|
|
// Copy this received packet into our circular queue
|
|
queueAdd(&railAppEventQueue, rxPacketMemoryHandle);
|
|
}
|
|
|
|
updateStats(rxPacket->rxPacket.appendedInfo.rssi, &counters.rssi);
|
|
}
|
|
|
|
// Track the state of scheduled Rx to figure out when it ends
|
|
if (inAppMode(RX_SCHEDULED, NULL) && schRxStopOnRxEvent) {
|
|
enableAppMode(RX_SCHEDULED, false, NULL);
|
|
}
|
|
|
|
// In Rx overflow test mode hang in this ISR to prevent processing new
|
|
// packets to force an overflow
|
|
if ((currentAppMode() == RX_OVERFLOW)) {
|
|
enableAppMode(RX_OVERFLOW, false, NULL); // Switch back after the overflow
|
|
changeAppModeIfPending();
|
|
// Trigger an overflow by waiting in the interrupt handler
|
|
usDelay(rxOverflowDelay);
|
|
}
|
|
|
|
// Free the allocated memory now that we're done with it
|
|
memoryFree(rxPacketMemoryHandle);
|
|
return packetHandle;
|
|
}
|
|
|
|
// Only support fixed length
|
|
static void fifoMode_RxPacketReceived(void)
|
|
{
|
|
uint16_t bytesRead;
|
|
// Discard incoming data stream in BER mode.
|
|
if (currentAppMode() == BER) {
|
|
RAIL_ResetFifo(railHandle, true, true);
|
|
} else {
|
|
// Note the packet's status
|
|
RAIL_RxPacketInfo_t packetInfo;
|
|
RAIL_RxPacketHandle_t packetHandle
|
|
= RAIL_GetRxPacketInfo(railHandle, RAIL_RX_PACKET_HANDLE_OLDEST,
|
|
&packetInfo);
|
|
// assert(packetHandle != NULL);
|
|
if ((rxLengthCount > 0)
|
|
&& (printRxErrorPackets
|
|
|| (packetInfo.packetStatus == RAIL_RX_PACKET_READY_CRC_ERROR)
|
|
|| (packetInfo.packetStatus == RAIL_RX_PACKET_READY_SUCCESS))) {
|
|
// Keep and display this frame
|
|
rxFifoPacketData->rxPacket.packetStatus = packetInfo.packetStatus;
|
|
rxFifoPacketData->rxPacket.filterMask = packetInfo.filterMask;
|
|
|
|
// Read the rest of the bytes out of the fifo
|
|
bytesRead = RAIL_ReadRxFifo(railHandle, currentRxFifoPacketPtr, rxLengthCount);
|
|
rxLengthCount -= bytesRead;
|
|
currentRxFifoPacketPtr += bytesRead;
|
|
|
|
// Configure how many bytes were received
|
|
rxFifoPacketData->rxPacket.dataLength = rxLengthTarget;
|
|
|
|
// Get the appended info details
|
|
if (RAIL_GetRxPacketDetailsAlt(railHandle, packetHandle,
|
|
&rxFifoPacketData->rxPacket.appendedInfo)
|
|
!= RAIL_STATUS_NO_ERROR) {
|
|
// assert(false);
|
|
memset(&rxFifoPacketData->rxPacket.appendedInfo, 0, sizeof(rxFifoPacketData->rxPacket.appendedInfo));
|
|
}
|
|
// Note that this does not take into account CRC bytes unless
|
|
// RAIL_RX_OPTION_STORE_CRC is used
|
|
rxFifoPacketData->rxPacket.appendedInfo.timeReceived.totalPacketBytes = rxLengthTarget;
|
|
RAIL_GetRxTimeSyncWordEndAlt(railHandle, &rxFifoPacketData->rxPacket.appendedInfo);
|
|
queueAdd(&railAppEventQueue, rxFifoPacketHandle);
|
|
} else {
|
|
// Toss this frame and any of its data accumlated so far
|
|
memoryFree(rxFifoPacketHandle);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* In Fifo mode, prepare for the upcoming rx
|
|
*
|
|
* Grab a buffer to store rx data
|
|
* Keep track of writing data to this buffer
|
|
*/
|
|
void rxFifoPrep(void)
|
|
{
|
|
// Don't allocate memory to save incoming data in BER mode.
|
|
if ((railDataConfig.rxMethod == FIFO_MODE)
|
|
&& (currentAppMode() != BER)
|
|
&& !rxFifoManual) {
|
|
rxFifoPacketHandle = memoryAllocate(sizeof(RailAppEvent_t) + rxLengthTarget);
|
|
rxFifoPacketData = (RailAppEvent_t *)memoryPtrFromHandle(rxFifoPacketHandle);
|
|
if (rxFifoPacketData == NULL) {
|
|
rxLengthCount = 0;
|
|
counters.noRxBuffer++;
|
|
} else {
|
|
rxLengthCount = rxLengthTarget;
|
|
uint8_t *rxPacketData = (uint8_t *)&rxFifoPacketData[1];
|
|
rxFifoPacketData->type = RX_PACKET;
|
|
rxFifoPacketData->rxPacket.dataPtr = rxPacketData;
|
|
rxFifoPacketData->rxPacket.freqOffset = getRxFreqOffset();
|
|
rxFifoPacketData->rxPacket.filterMask = 0U;
|
|
currentRxFifoPacketPtr = rxPacketData;
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Public
|
|
*****************************************************************************/
|
|
void loadTxData(uint8_t *data, uint16_t dataLen)
|
|
{
|
|
uint16_t dataWritten;
|
|
|
|
if (railDataConfig.txMethod == PACKET_MODE) {
|
|
RAIL_WriteTxFifo(railHandle, data, dataLen, true);
|
|
} else {
|
|
dataWritten = RAIL_WriteTxFifo(railHandle, data, dataLen, false);
|
|
dataLeft = dataLen - dataWritten;
|
|
dataLeftPtr = data + dataWritten;
|
|
}
|
|
}
|
|
|
|
void configRxLengthSetting(uint16_t rxLength)
|
|
{
|
|
if (railDataConfig.rxMethod == FIFO_MODE) {
|
|
rxLengthTarget = rxLength;
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* RAIL Callback Implementation
|
|
*****************************************************************************/
|
|
void RAILCb_TxPacketSent(RAIL_Handle_t railHandle, bool isAck)
|
|
{
|
|
LedToggle(1);
|
|
updateGraphics();
|
|
|
|
// Store the previous tx time for printing later
|
|
if (isAck) {
|
|
sentAckPackets++;
|
|
// previousTxAckAppendedInfo.isAck already initialized true
|
|
previousTxAckAppendedInfo.timeSent.totalPacketBytes
|
|
= RAIL_IEEE802154_IsEnabled(railHandle) ? 4U : ackDataLen;
|
|
(void) RAIL_GetTxPacketDetailsAlt2(railHandle, &previousTxAckAppendedInfo);
|
|
(void) (*txTimePosition)(railHandle, &previousTxAckAppendedInfo);
|
|
pendFinishTxAckSequence();
|
|
} else {
|
|
internalTransmitCounter++;
|
|
// previousTxAppendedInfo.isAck already initialized false
|
|
previousTxAppendedInfo.timeSent.totalPacketBytes = txDataLen;
|
|
(void) RAIL_GetTxPacketDetailsAlt2(railHandle, &previousTxAppendedInfo);
|
|
(void) (*txTimePosition)(railHandle, &previousTxAppendedInfo);
|
|
scheduleNextTx();
|
|
}
|
|
}
|
|
|
|
void RAILCb_RxPacketAborted(RAIL_Handle_t railHandle)
|
|
{
|
|
if (railDataConfig.rxMethod == PACKET_MODE) {
|
|
packetMode_RxPacketAborted(railHandle);
|
|
} else if (!rxFifoManual) {
|
|
fifoMode_RxPacketReceived();
|
|
}
|
|
}
|
|
|
|
void RAILCb_RxPacketReceived(RAIL_Handle_t railHandle)
|
|
{
|
|
counters.receive++;
|
|
LedToggle(0);
|
|
rxPacketEvent = true;
|
|
|
|
if (railDataConfig.rxMethod == PACKET_MODE) {
|
|
packetMode_RxPacketReceived(railHandle);
|
|
} else if (!rxFifoManual) {
|
|
fifoMode_RxPacketReceived();
|
|
}
|
|
}
|
|
|
|
void RAILCb_RxChannelHoppingComplete(RAIL_Handle_t railHandle)
|
|
{
|
|
RAIL_Time_t periodicWakeupUs = 0U;
|
|
|
|
// Only schedule the next wakeup if:
|
|
// 1. RX Duty Cycle Schedule Wakeup is enabled
|
|
// 2. Sleep duration > 0
|
|
// 3. Sleep has not been interrupted via a serial wakeup.
|
|
if ((getRxDutyCycleSchedWakeupEnable(&periodicWakeupUs))
|
|
&& (periodicWakeupUs > 0U) && (!serEvent)) {
|
|
// Configure the next scheduled RX
|
|
RAIL_ScheduleRxConfig_t rxCfg = {
|
|
.start = periodicWakeupUs,
|
|
.startMode = RAIL_TIME_DELAY,
|
|
.end = 0U,
|
|
.endMode = RAIL_TIME_DISABLED,
|
|
.rxTransitionEndSchedule = 0U,
|
|
.hardWindowEnd = 0U
|
|
};
|
|
|
|
RAIL_Idle(railHandle, RAIL_IDLE_ABORT, true);
|
|
RAIL_ScheduleRx(railHandle, channel, &rxCfg, NULL);
|
|
allowPowerManagerSleep = true;
|
|
}
|
|
}
|
|
|
|
void RAILCb_TxFifoAlmostEmpty(RAIL_Handle_t railHandle)
|
|
{
|
|
uint16_t dataWritten;
|
|
counters.txFifoAlmostEmpty++;
|
|
|
|
if (dataLeft) {
|
|
dataWritten = RAIL_WriteTxFifo(railHandle, dataLeftPtr, dataLeft, false);
|
|
dataLeft -= dataWritten;
|
|
dataLeftPtr += dataWritten;
|
|
}
|
|
}
|
|
|
|
// count number of 1s in a byte without a loop
|
|
static uint8_t countBits(uint8_t num)
|
|
{
|
|
uint8_t count = 0;
|
|
static const uint8_t nibblebits[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
|
|
count += nibblebits[num & 0x0F];
|
|
count += nibblebits[num >> 4];
|
|
return count;
|
|
}
|
|
|
|
static void berSource_RxFifoAlmostFull(uint16_t bytesAvailable)
|
|
{
|
|
(void)bytesAvailable;
|
|
// All incoming bytes are received and validated here.
|
|
uint16_t numBytes;
|
|
bool stopBerRx = false;
|
|
|
|
// If rxOfEvent is > 0, then we're overflowing the incoming RX buffer
|
|
// probably because the BER test isn't processing incoming bits fast
|
|
// enough. The test will automatically try to re-synchronize and read in bits
|
|
// from the stream, but the bits under test will not be continuous. Abort
|
|
// testing and notify the user if this is the case.
|
|
if (counters.rxOfEvent) {
|
|
stopBerRx = true;
|
|
}
|
|
|
|
while ((RAIL_GetRxFifoBytesAvailable(railHandle) > RAIL_GetRxFifoThreshold(railHandle))
|
|
&& !stopBerRx) {
|
|
// Read multiple bytes in if they're available.
|
|
// Reuse the txData[SL_RAIL_TEST_MAX_PACKET_LENGTH] array since we won't be
|
|
// transmitting in BER Test mode anyway.
|
|
numBytes = RAIL_ReadRxFifo(railHandle, txData, SL_RAIL_TEST_MAX_PACKET_LENGTH);
|
|
|
|
for (uint16_t x = 0; x < numBytes && !stopBerRx; x++) {
|
|
// Update BER statistics
|
|
if (berStats.bytesTested < berStats.bytesTotal) {
|
|
// Counters will not overflow since bytesTotal max value is capped.
|
|
berStats.bitErrors += countBits(txData[x]);
|
|
berStats.bytesTested++;
|
|
} else {
|
|
stopBerRx = true; // statistics are all gathered - stop now
|
|
}
|
|
}
|
|
}
|
|
// disregard decimal point
|
|
berStats.rssi = (int8_t)(RAIL_GetRssiAlt(railHandle, RAIL_GET_RSSI_WAIT_WITHOUT_TIMEOUT) / 4);
|
|
|
|
// stop RXing when enough bits are acquired or an error (i.e. RX overflow)
|
|
if (stopBerRx) {
|
|
RAIL_Idle(railHandle, RAIL_IDLE_FORCE_SHUTDOWN, true);
|
|
RAIL_ResetFifo(railHandle, true, true);
|
|
berTestModeEnabled = false;
|
|
}
|
|
}
|
|
|
|
// @TODO It would be better if we could 'register' callback contents
|
|
static void packetSource_RxFifoAlmostFull(uint16_t bytesAvailable)
|
|
{
|
|
uint16_t bytesRead;
|
|
if (rxLengthCount > 0) {
|
|
// Amount to read is either bytes avilable or number of bytes remaining in packet
|
|
bytesRead = (rxLengthCount > bytesAvailable) ? bytesAvailable : rxLengthCount;
|
|
bytesRead = RAIL_ReadRxFifo(railHandle, currentRxFifoPacketPtr, bytesRead);
|
|
rxLengthCount -= bytesRead;
|
|
currentRxFifoPacketPtr += bytesRead;
|
|
}
|
|
}
|
|
|
|
void RAILCb_RxFifoAlmostFull(RAIL_Handle_t railHandle)
|
|
{
|
|
uint16_t bytesAvailable = RAIL_GetRxFifoBytesAvailable(railHandle);
|
|
counters.rxFifoAlmostFull++;
|
|
|
|
if (berTestModeEnabled) {
|
|
berSource_RxFifoAlmostFull(bytesAvailable);
|
|
} else if (RAIL_BLE_IsEnabled(railHandle)) {
|
|
RAIL_ConfigEvents(railHandle, RAIL_EVENT_RX_FIFO_ALMOST_FULL,
|
|
RAIL_EVENTS_NONE); // Disable this event
|
|
} else {
|
|
packetSource_RxFifoAlmostFull(bytesAvailable);
|
|
}
|
|
}
|
|
|
|
void setNextPacketTime(RAIL_ScheduleTxConfig_t *scheduledTxOptions)
|
|
{
|
|
memcpy(&nextPacketTxTime, scheduledTxOptions, sizeof(RAIL_ScheduleTxConfig_t));
|
|
}
|