TEST
Dependencies: max32630fthr Adafruit_FeatherOLED USBDevice
Utilities/queue.cpp
- Committer:
- Emre.Eken@IST-LT-36262.maxim-ic.internal
- Date:
- 2019-07-29
- Revision:
- 3:2fe2ff1ca0dc
- Parent:
- 1:f60eafbf009a
File content as of revision 3:2fe2ff1ca0dc:
/******************************************************************************* * Copyright (C) Maxim Integrated Products, Inc., All rights Reserved. * * This software is protected by copyright laws of the United States and * of foreign countries. This material may also be protected by patent laws * and technology transfer regulations of the United States and of foreign * countries. This software is furnished under a license agreement and/or a * nondisclosure agreement and may only be used or reproduced in accordance * with the terms of those agreements. Dissemination of this information to * any party or parties not specified in the license agreement and/or * nondisclosure agreement is expressly prohibited. * * 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"); } }