msousa@0: /* msousa@0: * Copyright (c) 2002,2016 Mario de Sousa (msousa@fe.up.pt) msousa@0: * msousa@0: * This file is part of the Modbus library for Beremiz and matiec. msousa@0: * msousa@0: * This Modbus library is free software: you can redistribute it and/or modify msousa@0: * it under the terms of the GNU Lesser General Public License as published by msousa@0: * the Free Software Foundation, either version 3 of the License, or msousa@0: * (at your option) any later version. msousa@0: * msousa@0: * This program is distributed in the hope that it will be useful, but msousa@0: * WITHOUT ANY WARRANTY; without even the implied warranty of msousa@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser msousa@0: * General Public License for more details. msousa@0: * msousa@0: * You should have received a copy of the GNU Lesser General Public License msousa@0: * along with this Modbus library. If not, see . msousa@0: * msousa@0: * This code is made available on the understanding that it will not be msousa@0: * used in safety-critical situations without a full and competent review. msousa@0: */ msousa@0: msousa@0: msousa@0: msousa@0: /* Data structures used by the modbus protocols... */ msousa@0: msousa@0: msousa@0: #ifndef __MODBUS_DS_UTIL_H msousa@0: #define __MODBUS_DS_UTIL_H msousa@0: msousa@0: msousa@0: #include "mb_types.h" /* get the data types */ msousa@0: msousa@0: /**************************************/ msousa@0: /** **/ msousa@0: /** A data structure - linear buffer **/ msousa@0: /** **/ msousa@0: /**************************************/ msousa@0: msousa@0: /* An unbounded FIFO data structure. msousa@0: * msousa@0: * The user/caller writes and reads directly from the data structure's buffer, msousa@0: * which eliminates slow copying of bytes between the user's and the structure's msousa@0: * local memory. msousa@0: * msousa@0: * The data structure stores the current data linearly in a single memory array, msousa@0: * i.e. the current data is stored from start to finish from a low address msousa@0: * to a high address, and does *not* circle back to the bottom of the address msousa@0: * space as is usual in a circular buffer. This allows the user/caller to msousa@0: * pass the structure's own byte array on to other functions such as msousa@0: * read() and write() for file operations. msousa@0: * msousa@0: * The FIFO is implemented by allocating more memory than the maximum number msousa@0: * of bytes it will ever hold, and using the extra bytes at the top of the msousa@0: * array as the bottom data bytes are released. When we run out of extra bytes, msousa@0: * (actually, when the number of un-used bytes at the beginning is larger than msousa@0: * a configured maximum), the whole data is moved down, freeing once again the msousa@0: * extra bytes at the top of the array. msousa@0: * msousa@0: * Remember that we can optimize the data structure so that whenever it becomes msousa@0: * empty, we can reset it to start off at the bottom of the byte array, i.e. we msousa@0: * can set the start = end = 0; instead of simply setting the start = end, which msousa@0: * may point to any position in the array. msousa@0: * msousa@0: * Taking the above into consideration, it would probably be a little more efficient msousa@0: * to implement it as a circular buffer with an additional linearize() function msousa@0: * the user could call whenever (s)he required the data to be stored linearly. msousa@0: * Nevertheless, since it has already been implemented as a linear buffer, and since msousa@0: * under normal circumstances the start and end pointers will be reset to 0 quite msousa@0: * often (and therefore we get no additional benefit under normal circumstances), msousa@0: * we will leave it as it is for the time being... msousa@0: * msousa@0: * msousa@0: * The user is expected to call msousa@0: * lb_init() -> to initialize the structure msousa@0: * lb_done() -> to free the data structure's memory msousa@0: * msousa@0: * The user can store data starting off from... msousa@0: * lb_free() -> pointer to address of free memory msousa@0: * lb_free_count() -> number of free bytes available msousa@0: * and then call msousa@0: * lb_data_add() msousa@0: * to add the data to the data structure msousa@0: * msousa@0: * Likewise, the user can read the data directly from msousa@0: * lb_data() -> pointer to address of data location msousa@0: * lb_free_count() -> number of data bytes available msousa@0: * and free the data using msousa@0: * lb_data_purge() msousa@0: * to remove the data from the data structure msousa@0: */ msousa@0: msousa@0: msousa@0: typedef struct { msousa@0: u8 *data; msousa@0: int data_size; /* size of the *data buffer */ msousa@0: int data_start; /* offset within *data were valid data starts */ msousa@0: int data_end; /* offset within *data were valid data ends */ msousa@0: int max_data_start; /* optimization parameter! When should it be normalised? */ msousa@0: } lb_buf_t; msousa@0: msousa@0: /* NOTE: lb = Linear Buffer */ msousa@0: msousa@0: static inline u8 *lb_init(lb_buf_t *buf, int size, int max_data_start) { msousa@0: if (size <= 0) msousa@0: return NULL; msousa@0: msousa@0: if (max_data_start >= size) msousa@0: max_data_start = size - 1; msousa@0: msousa@0: buf->data_size = size; msousa@0: buf->data_start = 0; msousa@0: buf->data_end = 0; msousa@0: buf->max_data_start = max_data_start; msousa@0: buf->data = (u8 *)malloc(size); msousa@0: return buf->data; msousa@0: } msousa@0: msousa@0: static inline void lb_done(lb_buf_t *buf) { msousa@0: free(buf->data); msousa@0: buf->data = NULL; msousa@0: } msousa@0: msousa@0: static inline u8 *lb_normalize(lb_buf_t *buf) { msousa@0: return (u8 *)memmove(buf->data, msousa@0: buf->data + buf->data_start, msousa@0: buf->data_end - buf->data_start); msousa@0: } msousa@0: msousa@0: static inline u8 *lb_data(lb_buf_t *buf) { msousa@0: return buf->data + buf->data_start; msousa@0: } msousa@0: msousa@0: static inline int lb_data_count(lb_buf_t *buf) { msousa@0: return buf->data_end - buf->data_start; msousa@0: } msousa@0: msousa@0: static inline void lb_data_add(lb_buf_t *buf, int count) { msousa@0: if ((buf->data_end += count) >= buf->data_size) msousa@0: buf->data_end = buf->data_size - 1; msousa@0: } msousa@0: msousa@0: static inline u8 *lb_data_purge(lb_buf_t *buf, int count) { msousa@0: buf->data_start += count; msousa@0: if (buf->data_start > buf->data_end) msousa@0: buf->data_start = buf->data_end; msousa@0: msousa@0: if ((buf->data_end == buf->data_size) || (buf->data_start >= buf->max_data_start)) msousa@0: return lb_normalize(buf); msousa@0: msousa@0: return buf->data + buf->data_start; msousa@0: } msousa@0: msousa@0: static inline void lb_data_purge_all(lb_buf_t *buf) { msousa@0: buf->data_start = buf->data_end = 0; msousa@0: } msousa@0: msousa@0: static inline u8 *lb_free(lb_buf_t *buf) { msousa@0: return buf->data + buf->data_end; msousa@0: } msousa@0: msousa@0: static inline int lb_free_count(lb_buf_t *buf) { msousa@0: return buf->data_size - buf->data_end; msousa@0: } msousa@0: msousa@0: msousa@0: msousa@0: msousa@0: #endif /* __MODBUS_DS_UTIL_H */