TEST

Dependencies:   max32630fthr Adafruit_FeatherOLED USBDevice

Revision:
1:f60eafbf009a
Child:
3:2fe2ff1ca0dc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Utilities/queue.cpp	Wed Apr 10 14:56:25 2019 +0300
@@ -0,0 +1,691 @@
+/*******************************************************************************
+* Author: Ismail Kose, Ismail.Kose@maximintegrated.com
+* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included
+* in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+* OTHER DEALINGS IN THE SOFTWARE.
+*
+* Except as contained in this notice, the name of Maxim Integrated
+* Products, Inc. shall not be used except as stated in the Maxim Integrated
+* Products, Inc. Branding Policy.
+*
+* The mere transfer of this software does not imply any licenses
+* of trade secrets, proprietary technology, copyrights, patents,
+* trademarks, maskwork rights, or any other form of intellectual
+* property whatsoever. Maxim Integrated Products, Inc. retains all
+* ownership rights.
+*******************************************************************************
+*/
+
+/*
+ * TODO:
+ * Add a function to enqueue data block instead of one by one.
+ * Write function definitions in the header file as doxygen format
+ * Init function will also allocate memory for queue buffer, providing the buffer will not necessary
+ *
+ * */
+
+#include "queue.h"
+#include "mbed.h"
+#include "Peripherals.h"
+
+int queue_reset(struct queue_t *q)
+{
+	if (!q)
+		return -EINVAL;
+
+	q->wr = q->base;
+	q->rd = q->base;
+	q->num_item = 0;
+	q->ovf_item = 0;
+#ifdef QUEUE_USAGE_STATS
+	q->pop_cnt = 0;
+	q->push_cnt = 0;
+	q->stats_period_cnt = 100; // Default
+#endif
+	return 0;
+}
+
+int queue_update_items_size(struct queue_t *q, int item_size)
+{
+	if (!q)
+		return -EINVAL;
+
+	queue_reset(q);
+	q->item_size = item_size;
+	q->buffer_size = q->max_buffer_size - (q->max_buffer_size % item_size);
+	return 0;
+}
+
+int queue_len(struct queue_t *q)
+{
+	int num_elements;
+
+	if (!q)
+		return -EINVAL;
+
+	num_elements = q->num_item;
+	return num_elements;
+}
+
+
+int queue_init(struct queue_t *q, void *buf, int item_size, int buffer_size)
+{
+	if (!q || !buf)
+		return -EINVAL;
+
+	if (buffer_size % item_size != 0)
+		return -EINVAL; // Padding problem
+
+	q->num_item = 0;
+	q->ovf_item = 0;
+	q->base = (char *)buf;
+	q->wr =  (char *)buf;
+	q->rd =  (char *)buf;
+	q->item_size = item_size;
+	q->buffer_size = buffer_size;
+	q->max_buffer_size = buffer_size;
+	q->name = NULL;
+
+#ifdef QUEUE_USAGE_STATS
+	q->pop_cnt = 0;
+	q->push_cnt = 0;
+	q->stats_period_cnt = 100; // Default
+#endif
+
+	return 0;
+}
+
+int queue_init_by_name(struct queue_t *q, void *buf, int item_size, int buffer_size, const char *name)
+{
+	int ret = queue_init(q, buf, item_size, buffer_size);
+
+	if (ret < 0)
+		return ret;
+
+	q->name = (char *)name;
+	return 0;
+}
+
+
+void queue_destroy(struct queue_t *q)
+{
+/* TODO: This is placeholder function, double check the implementation */
+	free((void *)q->base);
+	free((void *)q);
+}
+
+int enqueue(struct queue_t *q, void *data)
+{
+	int ret = 0;
+
+	if (!q || !data)
+		return -EINVAL; // Invalid pointer
+
+	if (q->wr == q->rd)
+		ret = (q->num_item != 0) ? -2 : 0; // Is FIFO Full or Empty?
+
+	if (q->wr >= (q->base + q->buffer_size))
+		q->wr = q->base;
+
+	memcpy((void *)q->wr, data, q->item_size);
+	q->wr = q->wr + q->item_size;
+	q->num_item++;
+	int fifo_size = q->buffer_size / q->item_size;
+	if (q->num_item > fifo_size)
+		q->ovf_item = q->num_item - fifo_size;
+	else
+		q->ovf_item = 0;
+	return ret;
+}
+
+int enqueue_test(struct queue_t *q, void *data)
+{
+	if (!q || !data)
+		return -EINVAL; // Invalid pointer
+
+	q->num_item++;
+	return 0;
+}
+
+
+int dequeue_test(struct queue_t *q, void *data)
+{
+	if (!q || !data)
+		return -EINVAL;
+
+	if (q->num_item > 0)
+		q->num_item--;
+	else
+		return -2;
+	return 0;
+}
+
+int dequeue(struct queue_t *q, void *data)
+{
+	int fifo_size = q->buffer_size / q->item_size;
+
+	if (!q || !data)
+		return -EINVAL;
+
+	if (q->num_item <= 0) {
+		return -2;
+	}
+
+	if (q->num_item > fifo_size) {
+		uint32_t curr_rd_off = ((uint32_t)(q->rd - q->base) + q->num_item * q->item_size);
+		q->rd = (q->base + (curr_rd_off % q->buffer_size));
+		q->num_item = fifo_size; // OVF number samples are already gone.
+
+#ifdef QUEUE_USAGE_STATS
+		q->pop_cnt++;
+
+		if ((q->pop_cnt % q->stats_period_cnt) == 0) {
+			if (q->name) {
+				pr_info("%s:%d (%s) - %d samples lost, avail:%d \n",__func__, __LINE__, q->name, q->ovf_item, q->num_item);
+			} else {
+				pr_info("%s:%d - %d samples lost, avail:%d \n",	__func__, __LINE__, q->ovf_item, q->num_item);
+			}
+		}
+#endif
+	}
+
+	if (q->rd >= (q->base + q->buffer_size))
+		q->rd = q->base;
+
+	memcpy(data, (void *)q->rd, q->item_size);
+	q->rd = q->rd + q->item_size;
+	q->num_item--;
+	if (q->num_item <= fifo_size)
+		q->ovf_item = 0;
+
+#if defined(QUEUE_DEBUG)
+	do {
+		static int cnt;
+
+		if (cnt++ % 100 == 0) {
+			if (q->name) {
+				pr_debug("%s - $ Fifo size: %d, usage: %d\n", q->name, fifo_size, q->num_item);
+			} else {
+				pr_debug("$ Fifo size: %d, usage: %d\n", fifo_size, q->num_item);
+			}
+		}
+	} while(0);
+#endif
+
+	return 0;
+}
+
+bool queue_is_full(struct queue_t *q)
+{
+	if (!q)
+		return -EINVAL;
+
+	int num_items = q->buffer_size / q->item_size;
+
+
+	if (num_items > q->num_item)
+		return false;
+	return true;
+}
+
+int queue_usage(struct queue_t *q, int *total, int *nm_item)
+{
+	if (!q)
+		return -EINVAL;
+
+	*total = q->buffer_size / q->item_size;
+	*nm_item = q->num_item;
+
+	return 0;
+}
+
+int queue_pop(struct queue_t *q)
+{
+	int fifo_size = q->buffer_size / q->item_size;
+
+	if (!q)
+		return -EINVAL;
+
+	if (q->num_item <= 0) {
+		return -2;
+	}
+
+	if (q->num_item > fifo_size) {
+		uint32_t curr_rd_off = ((uint32_t)(q->rd - q->base) + q->num_item * q->item_size);
+		q->ovf_item = q->num_item - fifo_size;
+		q->rd = q->base + (curr_rd_off % q->buffer_size);
+		q->num_item = fifo_size; // OVF number samples are already gone.
+
+#ifdef QUEUE_USAGE_STATS
+		q->push_cnt++;
+
+		if ((q->push_cnt % q->stats_period_cnt) == 0) {
+			if (q->name) {
+				pr_info("%s:%d (%s) - %d samples lost, avail:%d \n",__func__, __LINE__, q->name, q->ovf_item, q->num_item);
+			} else {
+				pr_info("%s:%d - %d samples lost, avail:%d \n",	__func__, __LINE__, q->ovf_item, q->num_item);
+			}
+		}
+#endif
+	} else
+		q->ovf_item = 0;
+
+	if (q->rd >= (q->base + q->buffer_size))
+		q->rd = q->base;
+
+	q->rd = q->rd + q->item_size;
+	q->num_item--;
+
+#if defined(QUEUE_DEBUG)
+	do {
+		static int cnt;
+
+		if (cnt++ % 100 == 0) {
+			if (q->name)
+				pr_debug("%s - $ Fifo size: %d, usage: %d\n", q->name, fifo_size, q->num_item);
+			else
+				pr_debug("$ Fifo size: %d, usage: %d\n", fifo_size, q->num_item);
+		}
+	} while(0);
+#endif
+
+	return 0;
+}
+
+int queue_pop_n(struct queue_t *q, int n)
+{
+	int fifo_size = q->buffer_size / q->item_size;
+
+	if (!q || n < 1)
+		return -EINVAL;
+
+	if (q->num_item < n) {
+		return -2;
+	}
+
+	if (q->num_item > fifo_size) {
+		if (q->name) {
+			pr_info("%s:%d ( %s ) - %d samples lost, avail:%d \n",
+				__func__, __LINE__, q->name, q->num_item - fifo_size, fifo_size);
+		} else {
+			pr_info("%s:%d - %d samples lost, avail:%d \n",
+				__func__, __LINE__, q->num_item - fifo_size, fifo_size);
+		}
+		q->num_item = fifo_size; // OVF number samples are already gone.
+		n = fifo_size;
+		uint32_t curr_rd_off = (uint32_t)(q->rd - q->base) + q->num_item * q->item_size;
+		q->ovf_item = q->num_item - fifo_size;
+		q->rd = q->base + curr_rd_off % q->buffer_size;
+	} else {
+		q->ovf_item = 0;
+	}
+
+	if (q->rd >= (q->base + q->buffer_size))
+		q->rd = q->base;
+
+
+	uint32_t rd_sz = q->item_size * n;
+	uint32_t to_end = (uint32_t)(q->base + q->buffer_size - q->rd);
+	if (to_end < rd_sz) {
+		rd_sz -= to_end;
+		q->rd = q->base;
+	}
+
+	q->rd = q->rd + rd_sz;
+	q->num_item -= n;
+
+	return 0;
+}
+
+int queue_front(struct queue_t *q, void *data)
+{
+#if 0
+	return queue_front_n(q, data, 1);
+#endif
+
+	int fifo_size = q->buffer_size / q->item_size;
+	void *rd = 0;
+
+	if (!q || !data)
+		return -EINVAL;
+
+	if (q->num_item <= 0) {
+		return -2;
+	}
+
+	if (q->num_item > fifo_size) {
+		uint32_t curr_rd_off = (uint32_t)(q->rd - q->base) + q->num_item * q->item_size;
+		rd = q->base + (curr_rd_off % q->buffer_size);
+		if (q->name) {
+			pr_info("%s:%d ( %s )- %d samples lost, avail:%d cap:%d \n",
+				__func__, __LINE__, q->name, q->ovf_item, q->num_item, fifo_size);
+		} else {
+			pr_info("%s:%d - %d samples lost, avail:%d cap:%d \n",
+				__func__, __LINE__, q->ovf_item, q->num_item, fifo_size);
+		}
+	} else {
+		q->ovf_item = 0;
+		rd = q->rd;
+	}
+
+	if (q->rd >= (q->base + q->buffer_size))
+		rd = q->base;
+
+	memcpy(data, (void *)rd, q->item_size);
+	return 0;
+}
+
+int queue_front_n(struct queue_t *q, void *data, int n, int buf_sz)
+{
+	int fifo_size = q->buffer_size / q->item_size;
+	char *rd = 0;
+	char *wr = (char *)data;
+
+	if (!q || !data || n < 1)
+		return -EINVAL;
+
+	if (q->num_item < n) {
+		return -2;
+	}
+
+	if (q->num_item > fifo_size) {
+		if (q->name) {
+			pr_info("\n%s:%d ( %s ) - %d samples lost, avail:%d \n",
+					__func__, __LINE__, q->name, q->num_item - fifo_size, fifo_size);
+		} else {
+			pr_info("\n%s:%d - %d samples lost, avail:%d \n",
+				__func__, __LINE__, q->num_item - fifo_size, fifo_size);
+		}
+		q->num_item = fifo_size;
+		n = fifo_size;
+		uint32_t curr_rd_off = (uint32_t)(q->rd - q->base) + q->num_item * q->item_size;
+		rd = q->base + (curr_rd_off % q->buffer_size);
+	} else {
+		q->ovf_item = 0;
+		rd = q->rd;
+	}
+
+	if (q->rd >= (q->base + q->buffer_size))
+		rd = q->base;
+
+	uint32_t rd_sz = q->item_size * n;
+
+	if (buf_sz < rd_sz) {
+		if (q->name) {
+			pr_info("\n%s:%d ( %s ) - Insufficient buffer size: %d\n",
+					__func__, __LINE__, q->name, buf_sz);
+		} else {
+			pr_info("\n%s:%d - Insufficient buffer size: %d\n",
+				__func__, __LINE__, buf_sz);
+		}
+		return -EINVAL;
+	}
+
+	uint32_t to_end = (uint32_t)(q->base + q->buffer_size - q->rd);
+	if (to_end < rd_sz) {
+		memcpy(wr, rd, to_end);
+		rd_sz -= to_end;
+		rd = q->base;
+		wr += to_end;
+		memcpy(wr, rd, rd_sz);
+
+	} else {
+		memcpy(wr, rd, rd_sz);
+	}
+
+	return 0;
+}
+
+int enqueue_string(struct queue_t *q, char *data, int sz)
+{
+	int ret = 0;
+	int buf_index;
+	char *wr_ptr;
+
+	if (!q || !data || sz <= 0)
+		return -EFAULT; // Invalid parameters
+
+	if (q->wr == q->rd)
+		ret = (q->num_item != 0) ? -2 : 0; // Is FIFO Full or Empty?
+
+	if (q->wr >= (q->base + q->buffer_size))
+		q->wr = q->base;
+
+	if ((q->num_item + sz) > q->buffer_size) {
+#if defined(QUEUE_DEBUG)
+		{
+			char buf[128];
+			int len;
+
+			if (q->name)
+				len = sprintf(buf, "\r\n**** %s - ( %s ) - Fifo is full. num_item: %d, sz: %d, buffer size: %d\r\n",
+						__func__, q->name, q->num_item, sz, q->buffer_size);
+			else
+				len = sprintf(buf, "\r\n**** %s - Fifo is full. num_item: %d, sz: %d, buffer size: %d\r\n",
+						__func__, q->num_item, sz, q->buffer_size);
+
+			UART_Write(UART_PORT, (uint8_t*)buf, len);
+		}
+#endif
+		return -ENOMEM;
+	}
+
+	buf_index = (uint32_t)(q->wr - q->base);
+	wr_ptr = q->base;
+	q->num_item += sz;
+	while(sz--)
+		wr_ptr[buf_index++ % q->buffer_size] = *data++;
+
+	q->wr = q->base + buf_index % q->buffer_size;
+	return ret;
+}
+
+int dequeue_string(struct queue_t *q, char *buf, int buffer_size)
+{
+	char *rd_ptr;
+	int buf_index;
+	int len;
+
+	if (!q || !buf || buffer_size <= 0)
+		return -EFAULT;
+
+	if (q->num_item <= 0) {
+		return -EPERM;
+	}
+
+	rd_ptr = (char *)q->base;
+	buf_index = (uint32_t)(q->rd - q->base);
+	len = q->num_item;
+
+	while (buffer_size-- && q->num_item--) {
+		char tmp = rd_ptr[buf_index % q->buffer_size];
+		rd_ptr[buf_index % q->buffer_size] = 0; // Remove this later on
+		buf_index++;
+		*buf++ = tmp;
+		if (tmp == '\0')
+			break;
+	}
+
+	if (q->num_item < 0) {
+		/* Data corruption in FIFO */
+		q->num_item = 0;
+	} else
+		len -= q->num_item;
+
+	q->rd = q->base + buf_index % q->buffer_size;
+
+	return len;
+}
+
+int queue_str_len(struct queue_t *q)
+{
+	char *rd_ptr;
+	int buf_index;
+	int len, i;
+
+	if (!q)
+		return -EFAULT;
+
+	if (q->num_item <= 0) {
+		return 0;
+	}
+
+	rd_ptr = q->base;
+	buf_index = (uint32_t)(q->rd - q->base);
+	i = q->num_item;
+	len = 0;
+
+	while (i--) {
+		char tmp = rd_ptr[buf_index % q->buffer_size];
+		buf_index++;
+		if (tmp == '\0')
+			break;
+		len++;
+	}
+
+	return len;
+}
+
+#if 0
+void queue_test(void)
+{
+	int ret;
+	ppg_data_t ppg_test = { 0, };
+	ppg_data_t ppg_test_out = { 0, };
+	int i, j, ii, jj;
+	static ppg_data_t ppg_data[10];
+	static queue_t queue;
+
+	srand((unsigned)time(NULL));
+	ret = queue_init(&queue, &ppg_data, sizeof(ppg_data_t), sizeof(ppg_data));
+	while (1) {
+		ii = rand() % 20;
+		for (i = 0; i < ii; i++) {
+			/* Test data */
+			ppg_test.timestamp++;
+			ppg_test.ir++;
+			ppg_test.red++;
+			ppg_test.green++;
+			/* Test functions */
+			ret = enqueue(&queue, &ppg_test);
+		}
+		jj = rand() % 20;
+		for (j = 0; j < jj; j++) {
+			ret = dequeue(&queue, &ppg_test_out);
+		}
+	}
+}
+#endif
+void queue_n_test(void)
+{
+	struct queue_t q;
+	uint8_t buf[5];
+	uint8_t peek_buf[5];
+	int error;
+	int i;
+	error = queue_init(&q, &buf[0], 1, sizeof(buf));
+	if (error)
+		printf("queue_init error :(\r\n");
+
+	uint8_t val = 0;
+	enqueue(&q, &val);
+	val = 1;
+	enqueue(&q, &val);
+	val = 2;
+	enqueue(&q, &val);
+	val = 3;
+	enqueue(&q, &val);
+	val = 4;
+	enqueue(&q, &val);
+
+	printf("enqueued 0,1,2,3,4\r\n");
+
+	error = queue_front_n(&q, &peek_buf, 5, sizeof(peek_buf));
+	if (error) {
+		printf("queue_front_n n=5 error :(\r\n");
+	} else {
+		printf("queue_front_n n=5: ");
+		for (i = 0; i < 5; i++) {
+			printf("%d ", peek_buf[i]);
+		}
+		printf("\r\n");
+	}
+
+	error = queue_front_n(&q, &peek_buf, 6, sizeof(peek_buf));
+	if (error)
+		printf("queue_front_n n=6 error :)\r\n");
+	else
+		printf("queue_front_n n=6 succeeded :(\r\n");
+
+	error = queue_pop_n(&q, 2);
+	if (error)
+		printf("queue_pop_n n=2 error :(\r\n");
+	else
+		printf("queue_pop_n n=2 succeeded :)\r\n");
+
+	error = queue_front_n(&q, &peek_buf, 5, sizeof(peek_buf));
+	if (error)
+		printf("queue_front_n n=5 error :)\r\n");
+
+	error = queue_front_n(&q, &peek_buf, 3, sizeof(peek_buf));
+	if (error) {
+		printf("queue_front_n n=3 error :(\r\n");
+	} else {
+		printf("queue_front_n n=3: ");
+		for (i = 0; i < 3; i++) {
+			printf("%d ", peek_buf[i]);
+		}
+		printf("\r\n");
+	}
+
+	val = 0;
+	enqueue(&q, &val);
+	val = 1;
+	enqueue(&q, &val);
+
+	printf("enqueued 0,1\r\n");
+
+	error = queue_front_n(&q, &peek_buf, 5, sizeof(peek_buf));
+	if (error) {
+		printf("queue_front_n n=5 error :(\r\n");
+	} else {
+		printf("queue_front_n n=5: ");
+		for (i = 0; i < 5; i++) {
+			printf("%d ", peek_buf[i]);
+		}
+		printf("\r\n");
+	}
+
+	error = queue_pop_n(&q, 4);
+	if (error)
+		printf("queue_pop_n n=4 error :(\r\n");
+	else
+		printf("queue_pop_n n=4 succeeded :)\r\n");
+
+	error = queue_front_n(&q, &peek_buf, 1, sizeof(peek_buf));
+	if (error) {
+		printf("queue_front_n n=1 error :(\r\n");
+	} else {
+		printf("queue_front_n n=1: ");
+		for (i = 0; i < 1; i++) {
+			printf("%d ", peek_buf[i]);
+		}
+		printf("\r\n");
+	}
+}