Commit 0c2a3a4e authored by Pedro Henrique Kopper's avatar Pedro Henrique Kopper

Add barebones SCPI handling

parent 9440a974
# List of all the board related files. # List of all the board related files.
BOARDSRC = $(ROOT)/board/board.c BOARDSRC = ./board/board.c
# Required include directories # Required include directories
BOARDINC = $(ROOT)/board BOARDINC = ./board
# Shared variables # Shared variables
ALLCSRC += $(BOARDSRC) ALLCSRC += $(BOARDSRC)
......
BSD 2-Clause License
Copyright (c) 2012-2018, Jan Breuer
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/*-
* BSD 2-Clause License
*
* Copyright (c) 2012-2018, Jan Breuer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file scpi_error.c
* @date Thu Nov 15 10:58:45 UTC 2012
*
* @brief Error handling and storing routines
*
*
*/
#include <stdint.h>
#include "scpi/parser.h"
#include "scpi/ieee488.h"
#include "scpi/error.h"
#include "fifo_private.h"
#include "scpi/constants.h"
#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
#define SCPI_ERROR_SETVAL(e, c, i) do { (e)->error_code = (c); (e)->device_dependent_info = (i); } while(0)
#else
#define SCPI_ERROR_SETVAL(e, c, i) do { (e)->error_code = (c); (void)(i);} while(0)
#endif
/**
* Initialize error queue
* @param context - scpi context
*/
void SCPI_ErrorInit(scpi_t * context, scpi_error_t * data, int16_t size) {
fifo_init(&context->error_queue, data, size);
}
/**
* Emit no error
* @param context scpi context
*/
static void SCPI_ErrorEmitEmpty(scpi_t * context) {
if ((SCPI_ErrorCount(context) == 0) && (SCPI_RegGet(context, SCPI_REG_STB) & STB_QMA)) {
SCPI_RegClearBits(context, SCPI_REG_STB, STB_QMA);
if (context->interface && context->interface->error) {
context->interface->error(context, 0);
}
}
}
/**
* Emit error
* @param context scpi context
* @param err Error to emit
*/
static void SCPI_ErrorEmit(scpi_t * context, int16_t err) {
SCPI_RegSetBits(context, SCPI_REG_STB, STB_QMA);
if (context->interface && context->interface->error) {
context->interface->error(context, err);
}
}
/**
* Clear error queue
* @param context - scpi context
*/
void SCPI_ErrorClear(scpi_t * context) {
#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
scpi_error_t error;
while (fifo_remove(&context->error_queue, &error)) {
SCPIDEFINE_free(&context->error_info_heap, error.device_dependent_info, false);
}
#endif
fifo_clear(&context->error_queue);
SCPI_ErrorEmitEmpty(context);
}
/**
* Pop error from queue
* @param context - scpi context
* @param error
* @return
*/
scpi_bool_t SCPI_ErrorPop(scpi_t * context, scpi_error_t * error) {
if (!error || !context) return FALSE;
SCPI_ERROR_SETVAL(error, 0, NULL);
fifo_remove(&context->error_queue, error);
SCPI_ErrorEmitEmpty(context);
return TRUE;
}
/**
* Return number of errors/events in the queue
* @param context
* @return
*/
int32_t SCPI_ErrorCount(scpi_t * context) {
int16_t result = 0;
fifo_count(&context->error_queue, &result);
return result;
}
static scpi_bool_t SCPI_ErrorAddInternal(scpi_t * context, int16_t err, char * info, size_t info_len) {
scpi_error_t error_value;
/* SCPIDEFINE_strndup is sometimes a dumy that does not reference it's arguments.
Since info_len is not referenced elsewhere caoing to void prevents unusd argument warnings */
(void) info_len;
char * info_ptr = info ? SCPIDEFINE_strndup(&context->error_info_heap, info, info_len) : NULL;
SCPI_ERROR_SETVAL(&error_value, err, info_ptr);
if (!fifo_add(&context->error_queue, &error_value)) {
SCPIDEFINE_free(&context->error_info_heap, error_value.device_dependent_info, true);
fifo_remove_last(&context->error_queue, &error_value);
SCPIDEFINE_free(&context->error_info_heap, error_value.device_dependent_info, true);
SCPI_ERROR_SETVAL(&error_value, SCPI_ERROR_QUEUE_OVERFLOW, NULL);
fifo_add(&context->error_queue, &error_value);
return FALSE;
}
return TRUE;
}
struct error_reg {
int16_t from;
int16_t to;
scpi_reg_val_t esrBit;
};
#define ERROR_DEFS_N 9
static const struct error_reg errs[ERROR_DEFS_N] = {
{-100, -199, ESR_CER}, /* Command error (e.g. syntax error) ch 21.8.9 */
{-200, -299, ESR_EER}, /* Execution Error (e.g. range error) ch 21.8.10 */
{-300, -399, ESR_DER}, /* Device specific error -300, -399 ch 21.8.11 */
{ 1, 32767, ESR_DER}, /* Device designer provided specific error 1, 32767 ch 21.8.11 */
{-400, -499, ESR_QER}, /* Query error -400, -499 ch 21.8.12 */
{-500, -599, ESR_PON}, /* Power on event -500, -599 ch 21.8.13 */
{-600, -699, ESR_URQ}, /* User Request Event -600, -699 ch 21.8.14 */
{-700, -799, ESR_REQ}, /* Request Control Event -700, -799 ch 21.8.15 */
{-800, -899, ESR_OPC}, /* Operation Complete Event -800, -899 ch 21.8.16 */
};
/**
* Push error to queue
* @param context
* @param err - error number
* @param info - additional text information or NULL for no text
* @param info_len - length of text or 0 for automatic length
*/
void SCPI_ErrorPushEx(scpi_t * context, int16_t err, char * info, size_t info_len) {
int i;
/* automatic calculation of length */
if (info && info_len == 0) {
info_len = SCPIDEFINE_strnlen(info, SCPI_STD_ERROR_DESC_MAX_STRING_LENGTH);
}
scpi_bool_t queue_overflow = !SCPI_ErrorAddInternal(context, err, info, info_len);
for (i = 0; i < ERROR_DEFS_N; i++) {
if ((err <= errs[i].from) && (err >= errs[i].to)) {
SCPI_RegSetBits(context, SCPI_REG_ESR, errs[i].esrBit);
}
}
SCPI_ErrorEmit(context, err);
if (queue_overflow) {
SCPI_ErrorEmit(context, SCPI_ERROR_QUEUE_OVERFLOW);
}
if (context) {
context->cmd_error = TRUE;
}
}
/**
* Push error to queue
* @param context - scpi context
* @param err - error number
*/
void SCPI_ErrorPush(scpi_t * context, int16_t err) {
SCPI_ErrorPushEx(context, err, NULL, 0);
return;
}
/**
* Translate error number to string
* @param err - error number
* @return Error string representation
*/
const char * SCPI_ErrorTranslate(int16_t err) {
switch (err) {
#define X(def, val, str) case def: return str;
#if USE_FULL_ERROR_LIST
#define XE X
#else
#define XE(def, val, str)
#endif
LIST_OF_ERRORS
#if USE_USER_ERROR_LIST
LIST_OF_USER_ERRORS
#endif
#undef X
#undef XE
default: return "Unknown error";
}
}
/*-
* BSD 2-Clause License
*
* Copyright (c) 2012-2018, Jan Breuer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file expression.c
*
* @brief Expressions handling
*
*
*/
#include "scpi/expression.h"
#include "scpi/error.h"
#include "scpi/parser.h"
#include "lexer_private.h"
/**
* Parse one range or single value
* @param state lexer state
* @param isRange return true if parsed expression is range
* @param valueFrom return parsed value from
* @param valueTo return parsed value to
* @return SCPI_EXPR_OK - parsing was succesful
* SCPI_EXPR_ERROR - parser error
* SCPI_EXPR_NO_MORE - no more data
*/
static scpi_expr_result_t numericRange(lex_state_t * state, scpi_bool_t * isRange, scpi_token_t * valueFrom, scpi_token_t * valueTo) {
if (scpiLex_DecimalNumericProgramData(state, valueFrom)) {
if (scpiLex_Colon(state, valueTo)) {
*isRange = TRUE;
if (scpiLex_DecimalNumericProgramData(state, valueTo)) {
return SCPI_EXPR_OK;
} else {
return SCPI_EXPR_ERROR;
}
} else {
*isRange = FALSE;
return SCPI_EXPR_OK;
}
}
return SCPI_EXPR_NO_MORE;
}
/**
* Parse entry on specified position
* @param context scpi context
* @param param input parameter
* @param index index of position (start from 0)
* @param isRange return true if expression at index was range
* @param valueFrom return value from
* @param valueTo return value to
* @return SCPI_EXPR_OK - parsing was succesful
* SCPI_EXPR_ERROR - parser error
* SCPI_EXPR_NO_MORE - no more data
* @see SCPI_ExprNumericListEntryInt, SCPI_ExprNumericListEntryDouble
*/
scpi_expr_result_t SCPI_ExprNumericListEntry(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, scpi_parameter_t * valueFrom, scpi_parameter_t * valueTo) {
lex_state_t lex;
int i;
scpi_expr_result_t res = SCPI_EXPR_OK;
if (!isRange || !valueFrom || !valueTo || !param) {
SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
return SCPI_EXPR_ERROR;
}
if (param->type != SCPI_TOKEN_PROGRAM_EXPRESSION) {
SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
return SCPI_EXPR_ERROR;
}
lex.buffer = param->ptr + 1;
lex.pos = lex.buffer;
lex.len = param->len - 2;
for (i = 0; i <= index; i++) {
res = numericRange(&lex, isRange, valueFrom, valueTo);
if (res != SCPI_EXPR_OK) {
break;
}
if (i != index) {
if (!scpiLex_Comma(&lex, valueFrom)) {
res = scpiLex_IsEos(&lex) ? SCPI_EXPR_NO_MORE : SCPI_EXPR_ERROR;
break;
}
}
}
if (res == SCPI_EXPR_ERROR) {
SCPI_ErrorPush(context, SCPI_ERROR_EXPRESSION_PARSING_ERROR);
}
return res;
}
/**
* Parse entry on specified position and convert result to int32_t
* @param context scpi context
* @param param input parameter
* @param index index of position (start from 0)
* @param isRange return true if expression at index was range
* @param valueFrom return value from
* @param valueTo return value to
* @return SCPI_EXPR_OK - parsing was succesful
* SCPI_EXPR_ERROR - parser error
* SCPI_EXPR_NO_MORE - no more data
* @see SCPI_ExprNumericListEntry, SCPI_ExprNumericListEntryDouble
*/
scpi_expr_result_t SCPI_ExprNumericListEntryInt(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, int32_t * valueFrom, int32_t * valueTo) {
scpi_expr_result_t res;
scpi_bool_t range = FALSE;
scpi_parameter_t paramFrom;
scpi_parameter_t paramTo;
res = SCPI_ExprNumericListEntry(context, param, index, &range, &paramFrom, &paramTo);
if (res == SCPI_EXPR_OK) {
*isRange = range;
SCPI_ParamToInt32(context, &paramFrom, valueFrom);
if (range) {
SCPI_ParamToInt32(context, &paramTo, valueTo);
}
}
return res;
}
/**
* Parse entry on specified position and convert result to double
* @param context scpi context
* @param param input parameter
* @param index index of position (start from 0)
* @param isRange return true if expression at index was range
* @param valueFrom return value from
* @param valueTo return value to
* @return SCPI_EXPR_OK - parsing was succesful
* SCPI_EXPR_ERROR - parser error
* SCPI_EXPR_NO_MORE - no more data
* @see SCPI_ExprNumericListEntry, SCPI_ExprNumericListEntryInt
*/
scpi_expr_result_t SCPI_ExprNumericListEntryDouble(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, double * valueFrom, double * valueTo) {
scpi_expr_result_t res;
scpi_bool_t range = FALSE;
scpi_parameter_t paramFrom;
scpi_parameter_t paramTo;
res = SCPI_ExprNumericListEntry(context, param, index, &range, &paramFrom, &paramTo);
if (res == SCPI_EXPR_OK) {
*isRange = range;
SCPI_ParamToDouble(context, &paramFrom, valueFrom);
if (range) {
SCPI_ParamToDouble(context, &paramTo, valueTo);
}
}
return res;
}
/**
* Parse one channel_spec e.g. "1!5!8"
* @param context
* @param state lexer state
* @param values range values
* @param length length of values array
* @param dimensions real number of dimensions
*/
static scpi_expr_result_t channelSpec(scpi_t * context, lex_state_t * state, int32_t * values, size_t length, size_t * dimensions) {
scpi_parameter_t param;
size_t i = 0;
while (scpiLex_DecimalNumericProgramData(state, &param)) {
if (i < length) {
SCPI_ParamToInt32(context, &param, &values[i]);
}
if (scpiLex_SpecificCharacter(state, &param, '!')) {
i++;
} else {
*dimensions = i + 1;
return SCPI_EXPR_OK;
}
}
if (i == 0) {
return SCPI_EXPR_NO_MORE;
} else {
/* there was at least one number followed by !, but after ! was not another number */
return SCPI_EXPR_ERROR;
}
}
/**
* Parse channel_range e.g. "1!2:5!6"
* @param context
* @param state lexer state
* @param isRange return true if it is range
* @param valuesFrom return array of values from
* @param valuesTo return array of values to
* @param length length of values arrays
* @param dimensions real number of dimensions
*/
static scpi_expr_result_t channelRange(scpi_t * context, lex_state_t * state, scpi_bool_t * isRange, int32_t * valuesFrom, int32_t * valuesTo, size_t length, size_t * dimensions) {
scpi_token_t token;
scpi_expr_result_t err;
size_t fromDimensions;
size_t toDimensions;
err = channelSpec(context, state, valuesFrom, length, &fromDimensions);
if (err == SCPI_EXPR_OK) {
if (scpiLex_Colon(state, &token)) {
*isRange = TRUE;
err = channelSpec(context, state, valuesTo, length, &toDimensions);
if (err != SCPI_EXPR_OK) {
return SCPI_EXPR_ERROR;
}
if (fromDimensions != toDimensions) {
return SCPI_EXPR_ERROR;
}
*dimensions = fromDimensions;
} else {
*isRange = FALSE;
*dimensions = fromDimensions;
return SCPI_EXPR_OK;
}
} else if (err == SCPI_EXPR_NO_MORE) {
err = SCPI_EXPR_ERROR;
}
return err;
}
/**
* Parse one list entry at specific position e.g. "1!2:5!6"
* @param context
* @param param
* @param index
* @param isRange return true if it is range
* @param valuesFrom return array of values from
* @param valuesTo return array of values to
* @param length length of values arrays
* @param dimensions real number of dimensions
*/
scpi_expr_result_t SCPI_ExprChannelListEntry(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, int32_t * valuesFrom, int32_t * valuesTo, size_t length, size_t * dimensions) {
lex_state_t lex;
int i;
scpi_expr_result_t res = SCPI_EXPR_OK;
scpi_token_t token;
if (!isRange || !param || !dimensions || (length && (!valuesFrom || !valuesTo))) {
SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
return SCPI_EXPR_ERROR;
}
if (param->type != SCPI_TOKEN_PROGRAM_EXPRESSION) {
SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
return SCPI_EXPR_ERROR;
}
lex.buffer = param->ptr + 1;
lex.pos = lex.buffer;
lex.len = param->len - 2;
/* detect channel list expression */
if (!scpiLex_SpecificCharacter(&lex, &token, '@')) {
SCPI_ErrorPush(context, SCPI_ERROR_EXPRESSION_PARSING_ERROR);
return SCPI_EXPR_ERROR;
}
for (i = 0; i <= index; i++) {
res = channelRange(context, &lex, isRange, valuesFrom, valuesTo, (i == index) ? length : 0, dimensions);
if (res != SCPI_EXPR_OK) {
break;
}
if (i != index) {
if (!scpiLex_Comma(&lex, &token)) {
res = scpiLex_IsEos(&lex) ? SCPI_EXPR_NO_MORE : SCPI_EXPR_ERROR;
break;
}
}
}
if (res == SCPI_EXPR_ERROR) {
SCPI_ErrorPush(context, SCPI_ERROR_EXPRESSION_PARSING_ERROR);
}
if (res == SCPI_EXPR_NO_MORE) {
if (!scpiLex_IsEos(&lex)) {
res = SCPI_EXPR_ERROR;
SCPI_ErrorPush(context, SCPI_ERROR_EXPRESSION_PARSING_ERROR);
}
}
return res;
}
/*-
* BSD 2-Clause License
*
* Copyright (c) 2012-2018, Jan Breuer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fifo_private.h"
/**
* Initialize fifo
* @param fifo
*/
void fifo_init(scpi_fifo_t * fifo, scpi_error_t * data, int16_t size) {
fifo->wr = 0;
fifo->rd = 0;
fifo->count = 0;
fifo->data = data;
fifo->size = size;
}
/**
* Empty fifo
* @param fifo
*/
void fifo_clear(scpi_fifo_t * fifo) {
fifo->wr = 0;
fifo->rd = 0;
fifo->count = 0;
}
/**
* Test if fifo is empty
* @param fifo
* @return
*/
scpi_bool_t fifo_is_empty(scpi_fifo_t * fifo) {
return fifo->count == 0;
}
/**
* Test if fifo is full
* @param fifo
* @return
*/
scpi_bool_t fifo_is_full(scpi_fifo_t * fifo) {
return fifo->count == fifo->size;
}
/**
* Add element to fifo. If fifo is full, return FALSE.
* @param fifo
* @param err
* @param info
* @return
*/
scpi_bool_t fifo_add(scpi_fifo_t * fifo, const scpi_error_t * value) {
/* FIFO full? */
if (fifo_is_full(fifo)) {
return FALSE;
}
if (!value) {
return FALSE;
}
fifo->data[fifo->wr] = *value;
fifo->wr = (fifo->wr + 1) % (fifo->size);
fifo->count += 1;
return TRUE;
}
/**
* Remove element form fifo
* @param fifo
* @param value
* @return FALSE - fifo is empty
*/
scpi_bool_t fifo_remove(scpi_fifo_t * fifo, scpi_error_t * value) {
/* FIFO empty? */
if (fifo_is_empty(fifo)) {
return FALSE;
}
if (value) {
*value = fifo->data[fifo->rd];
}
fifo->rd = (fifo->rd + 1) % (fifo->size);
fifo->count -= 1;
return TRUE;
}
/**
* Remove last element from fifo
* @param fifo
* @param value
* @return FALSE - fifo is empty
*/
scpi_bool_t fifo_remove_last(scpi_fifo_t * fifo, scpi_error_t * value) {
/* FIFO empty? */
if (fifo_is_empty(fifo)) {
return FALSE;
}
fifo->wr = (fifo->wr + fifo->size - 1) % (fifo->size);
if (value) {
*value = fifo->data[fifo->wr];
}
fifo->count -= 1;
return TRUE;
}
/**
* Retrive number of elements in fifo
* @param fifo
* @param value
* @return
*/
scpi_bool_t fifo_count(scpi_fifo_t * fifo, int16_t * value) {
*value = fifo->count;
return TRUE;
}
/*-
* BSD 2-Clause License
*
* Copyright (c) 2012-2018, Jan Breuer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.