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.
279 lines
6.8 KiB
C++
279 lines
6.8 KiB
C++
/* ----------------------------------------------------------------------
|
|
* Project: CMSIS DSP Library
|
|
* Title: RingBuffer.cpp
|
|
* Description: Implementation of the Ring buffer.
|
|
*
|
|
* $Date: 30 July 2021
|
|
* $Revision: V1.10.0
|
|
*
|
|
* Target Processor: Cortex-M and Cortex-A cores
|
|
* -------------------------------------------------------------------- */
|
|
/*
|
|
* Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the License); you may
|
|
* not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* 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.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/*
|
|
|
|
RTOS dependent definitions must be in RingPrivate.h.
|
|
Without a RingPrivate.h, this code cannot work.
|
|
|
|
*/
|
|
#include "RingPrivate.h"
|
|
#include "RingBuffer.h"
|
|
|
|
/*
|
|
|
|
RTOS Integration
|
|
|
|
*/
|
|
#ifndef RING_BEGINCRITICALSECTION
|
|
#define RING_BEGINCRITICALSECTION()
|
|
#endif
|
|
|
|
#ifndef RING_ENDCRITICALSECTION
|
|
#define RING_ENDCRITICALSECTION()
|
|
#endif
|
|
|
|
#ifndef RING_WAIT_BUFFER
|
|
#define RING_WAIT_BUFFER(ID) 0
|
|
#endif
|
|
|
|
#ifndef RING_RELEASE_BUFFER
|
|
#define RING_RELEASE_BUFFER(THREADID)
|
|
#endif
|
|
|
|
#ifndef RING_HASWAITERROR
|
|
#define RING_HASWAITERROR(ERR) 0
|
|
#endif
|
|
|
|
/*
|
|
|
|
Debug integration
|
|
|
|
*/
|
|
|
|
#ifndef RING_DBG_USER_RESERVE_BUFFER
|
|
#define RING_DBG_USER_RESERVE_BUFFER(ID,CONF)
|
|
#endif
|
|
|
|
#ifndef RING_DBG_USER_RELEASE_BUFFER
|
|
#define RING_DBG_USER_RELEASE_BUFFER(ID,CONF)
|
|
#endif
|
|
|
|
#ifndef RING_DBG_USER_WAIT_BUFFER
|
|
#define RING_DBG_USER_WAIT_BUFFER(ID,CONF)
|
|
#endif
|
|
|
|
#ifndef RING_DBG_USER_BUFFER_RELEASED
|
|
#define RING_DBG_USER_BUFFER_RELEASED(ID,CONF)
|
|
#endif
|
|
|
|
#ifndef RING_DBG_USER_STATUS
|
|
#define RING_DBG_USER_STATUS(SA,SB,CONF)
|
|
#endif
|
|
|
|
#ifndef RING_DBG_INT_RESERVE_BUFFER
|
|
#define RING_DBG_INT_RESERVE_BUFFER(ID,CONF)
|
|
#endif
|
|
|
|
#ifndef RING_DBG_INT_RELEASE_BUFFER
|
|
#define RING_DBG_INT_RELEASE_BUFFER(ID,CONF)
|
|
#endif
|
|
|
|
#ifndef RING_DBG_INT_RELEASE_USER
|
|
#define RING_DBG_INT_RELEASE_USER(CONF)
|
|
#endif
|
|
|
|
#ifndef RING_DBG_INT_STATUS
|
|
#define RING_DBG_INT_STATUS(SA,SB,CONF)
|
|
#endif
|
|
|
|
#ifndef RING_DBG_ERROR
|
|
#define RING_DBG_ERROR(ERROR,CONF)
|
|
#endif
|
|
|
|
/*
|
|
|
|
Implementation
|
|
|
|
*/
|
|
|
|
#define RING_SET(FIELD,BIT) (config->FIELD) |= (1 << (config->BIT))
|
|
#define RING_CLEAR(FIELD,BIT) (config->FIELD) &= ~(1 << (config->BIT))
|
|
#define RING_TEST(FIELD,BIT) (((config->FIELD) & (1 << (config->BIT))) != 0)
|
|
|
|
#define RING_INC(ID) \
|
|
config->ID++; \
|
|
if (config->ID == config->nbBuffers)\
|
|
{ \
|
|
config->ID=0; \
|
|
}
|
|
|
|
#define RING_BUSY(ID) \
|
|
(RING_TEST(userBufferStatus,ID) || RING_TEST(intBufferStatus,ID))
|
|
|
|
|
|
void ringInit(ring_config_t *config,
|
|
uint32_t nbBuffers,
|
|
uint32_t bufferSize,
|
|
uint8_t *buffer,
|
|
int interruptID,
|
|
int timeout)
|
|
{
|
|
|
|
config->buffer=buffer;
|
|
config->nbBuffers = nbBuffers;
|
|
config->bufferSize = bufferSize;
|
|
config->interruptBufferIDStart = 0;
|
|
config->interruptBufferIDStop = 0;
|
|
config->userBufferIDStart = 0;
|
|
config->userBufferIDStop = 0;
|
|
config->error=kNoError;
|
|
config->waiting=0;
|
|
config->timeout=timeout;
|
|
|
|
config->interruptID = interruptID;
|
|
config->userBufferStatus = 0;
|
|
config->intBufferStatus = 0;
|
|
|
|
}
|
|
|
|
void ringClean(ring_config_t *config)
|
|
{
|
|
}
|
|
|
|
uint8_t *ringGetBufferAddress(ring_config_t *config,int id)
|
|
{
|
|
if (id < 0)
|
|
{
|
|
return(NULL);
|
|
}
|
|
else
|
|
{
|
|
return(&config->buffer[id*config->bufferSize]);
|
|
}
|
|
}
|
|
|
|
int ringInterruptReserveBuffer(ring_config_t *config)
|
|
{
|
|
RING_DBG_INT_STATUS(userBufferStatus,intBufferStatus,config);
|
|
if (config->error)
|
|
{
|
|
return(-1);
|
|
}
|
|
|
|
/* Try to reserve a buffer */
|
|
if (RING_BUSY(interruptBufferIDStop))
|
|
{
|
|
/* If buffer is already used then kErrorOverflowUnderflow*/
|
|
config->error=kErrorOverflowUnderflow;
|
|
RING_DBG_ERROR(config->error,config);
|
|
return(-1);
|
|
}
|
|
else
|
|
{
|
|
RING_DBG_INT_RESERVE_BUFFER(config->interruptBufferIDStop,config);
|
|
RING_SET(intBufferStatus,interruptBufferIDStop);
|
|
RING_DBG_INT_STATUS(userBufferStatus,intBufferStatus,config);
|
|
int id=config->interruptBufferIDStop;
|
|
RING_INC(interruptBufferIDStop);
|
|
return(id);
|
|
}
|
|
}
|
|
|
|
void ringInterruptReleaseBuffer(ring_config_t *config,void *threadId)
|
|
{
|
|
RING_DBG_INT_STATUS(userBufferStatus,intBufferStatus,config);
|
|
if (config->error)
|
|
{
|
|
return;
|
|
}
|
|
if (config->interruptBufferIDStart != config->interruptBufferIDStop)
|
|
{
|
|
RING_DBG_INT_RELEASE_BUFFER(config->interruptBufferIDStart,config);
|
|
RING_CLEAR(intBufferStatus,interruptBufferIDStart);
|
|
/* Send release message in case the thread may be waiting */
|
|
if (config->interruptBufferIDStart == config->userBufferIDStop)
|
|
{
|
|
if (config->waiting)
|
|
{
|
|
RING_DBG_INT_RELEASE_USER(config);
|
|
RING_RELEASE_BUFFER(threadId);
|
|
}
|
|
}
|
|
RING_INC(interruptBufferIDStart);
|
|
}
|
|
}
|
|
|
|
int ringUserReserveBuffer(ring_config_t *config)
|
|
{
|
|
RING_BEGINCRITICALSECTION();
|
|
RING_DBG_USER_STATUS(userBufferStatus,intBufferStatus,config);
|
|
if (config->error)
|
|
{
|
|
RING_ENDCRITICALSECTION();
|
|
return(-1);
|
|
}
|
|
/* If buffer is busy we wait*/
|
|
if (RING_BUSY(userBufferIDStop))
|
|
{
|
|
config->waiting=1;
|
|
RING_DBG_USER_WAIT_BUFFER(config->userBufferIDStop,config);
|
|
RING_ENDCRITICALSECTION();
|
|
|
|
int err = RING_WAIT_BUFFER(config->timeout);
|
|
|
|
RING_BEGINCRITICALSECTION();
|
|
RING_DBG_USER_BUFFER_RELEASED(config->userBufferIDStop,config);
|
|
if (RING_HASWAITERROR(err))
|
|
{
|
|
RING_DBG_ERROR(err,config);
|
|
config->error=kTimeout;
|
|
return(-1);
|
|
}
|
|
|
|
}
|
|
|
|
RING_DBG_USER_RESERVE_BUFFER(config->userBufferIDStop,config);
|
|
RING_SET(userBufferStatus,userBufferIDStop);
|
|
int id=config->userBufferIDStop;
|
|
RING_INC(userBufferIDStop);
|
|
|
|
RING_ENDCRITICALSECTION();
|
|
|
|
return(id);
|
|
}
|
|
|
|
void ringUserReleaseBuffer(ring_config_t *config)
|
|
{
|
|
RING_BEGINCRITICALSECTION();
|
|
RING_DBG_USER_STATUS(userBufferStatus,intBufferStatus,config);
|
|
if (config->error)
|
|
{
|
|
RING_ENDCRITICALSECTION();
|
|
return;
|
|
}
|
|
if (config->userBufferIDStart != config->userBufferIDStop)
|
|
{
|
|
RING_DBG_USER_RELEASE_BUFFER(config->userBufferIDStart,config);
|
|
RING_CLEAR(userBufferStatus,userBufferIDStart);
|
|
RING_INC(userBufferIDStart);
|
|
}
|
|
|
|
RING_ENDCRITICALSECTION();
|
|
}
|