|
|
1.1 root 1: /* $Id: serial.c,v 1.4 2003/05/05 23:14:34 fredette Exp $ */
2:
3: /* generic/serial.c - generic serial implementation support: */
4:
5: /*
6: * Copyright (c) 2003 Matt Fredette
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by Matt Fredette.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33: * POSSIBILITY OF SUCH DAMAGE.
34: */
35:
36: #include <tme/common.h>
37: _TME_RCSID("$Id: serial.c,v 1.4 2003/05/05 23:14:34 fredette Exp $");
38:
39: /* includes: */
40: #include <tme/generic/serial.h>
41:
42: /* this initializes a serial buffer: */
43: int
44: tme_serial_buffer_init(struct tme_serial_buffer *buffer, unsigned int size)
45: {
46:
47: /* round the buffer size up to a power of two: */
48: if (size & (size - 1)) {
49: do {
50: size &= (size - 1);
51: } while (size & (size - 1));
52: size <<= 1;
53: }
54:
55: /* set the buffer size: */
56: buffer->tme_serial_buffer_size = size;
57:
58: /* set the head and tail pointers: */
59: buffer->tme_serial_buffer_head = 0;
60: buffer->tme_serial_buffer_tail = 0;
61:
62: /* allocate the buffer data and flags: */
63: buffer->tme_serial_buffer_data =
64: tme_new(tme_uint8_t, size);
65: buffer->tme_serial_buffer_data_flags =
66: tme_new(tme_serial_data_flags_t, size);
67:
68: /* done: */
69: return (TME_OK);
70: }
71:
72: /* this copies data into a serial buffer: */
73: unsigned int
74: tme_serial_buffer_copyin(struct tme_serial_buffer *buffer,
75: const tme_uint8_t *data,
76: unsigned int count,
77: tme_serial_data_flags_t data_flags,
78: int copy_flags)
79: {
80: unsigned int resid;
81: unsigned int buffer_head, buffer_tail, buffer_size_mask;
82: unsigned int buffer_size;
83:
84: /* get the head, tail, and size mask: */
85: buffer_head = buffer->tme_serial_buffer_head;
86: buffer_tail = buffer->tme_serial_buffer_tail;
87: buffer_size_mask = buffer->tme_serial_buffer_size - 1;
88:
89: /* while we have more data to copy in: */
90: for (resid = count; resid > 0; ) {
91:
92: /* if the buffer is full: */
93: if (((buffer_head + 1) & buffer_size_mask)
94: == buffer_tail) {
95:
96: /* if a full buffer means an overrun, mark it: */
97: if (copy_flags & TME_SERIAL_COPY_FULL_IS_OVERRUN) {
98: buffer->tme_serial_buffer_data_flags[buffer_head] |= TME_SERIAL_DATA_OVERRUN;
99: }
100:
101: /* we're done copying in: */
102: break;
103: }
104:
105: /* otherwise, the buffer is not full, meaning there is always some
106: space starting at the buffer head. if the buffer head >= the
107: buffer tail, there is space from the buffer head up to the end
108: of the buffer, otherwise there is space from the buffer head up
109: to one before the buffer tail: */
110: buffer_size = ((buffer_head >= buffer_tail)
111: ? (buffer_size_mask - buffer_head) + 1
112: : (buffer_tail - buffer_head) - 1);
113:
114: /* don't copy in more data than is available: */
115: buffer_size = TME_MIN(buffer_size, resid);
116: assert(buffer_size > 0);
117:
118: /* copy in this data: */
119: memcpy(buffer->tme_serial_buffer_data + buffer_head,
120: data,
121: buffer_size);
122: memset(buffer->tme_serial_buffer_data_flags + buffer_head,
123: data_flags,
124: buffer_size);
125:
126: /* update and loop: */
127: buffer_head = (buffer_head + buffer_size) & buffer_size_mask;
128: data += buffer_size;
129: resid -= buffer_size;
130: }
131:
132: /* store our new head pointer: */
133: buffer->tme_serial_buffer_head = buffer_head;
134:
135: /* done: */
136: return (count - resid);
137: }
138:
139: /* this copies data out of a buffer: */
140: unsigned int
141: tme_serial_buffer_copyout(struct tme_serial_buffer *buffer,
142: tme_uint8_t *data,
143: unsigned int count,
144: tme_serial_data_flags_t *_data_flags,
145: int copy_flags)
146: {
147: unsigned int resid;
148: unsigned int buffer_head, buffer_tail, buffer_size_mask;
149: unsigned int buffer_size;
150: tme_serial_data_flags_t data_flags, *scan_flags;
151: unsigned int scan_resid;
152:
153: /* get the head, tail, and size mask: */
154: buffer_head = buffer->tme_serial_buffer_head;
155: buffer_tail = buffer->tme_serial_buffer_tail;
156: buffer_size_mask = buffer->tme_serial_buffer_size - 1;
157:
158: /* we can only return data with the same data flags: */
159: data_flags = buffer->tme_serial_buffer_data_flags[buffer_tail];
160:
161: /* while we have more data to copy out: */
162: for (resid = count; resid > 0; ) {
163:
164: /* if the buffer is empty: */
165: if (buffer_tail == buffer_head) {
166:
167: /* we're done copying out: */
168: break;
169: }
170:
171: /* otherwise, the buffer is not empty, meaning there is always some
172: data starting at the buffer tail. if the buffer tail > the
173: buffer head, there is space from the buffer tail up to the end
174: of the buffer, otherwise there is space from the buffer tail up
175: to the buffer head: */
176: buffer_size = ((buffer_tail > buffer_head)
177: ? (buffer_size_mask - buffer_tail) + 1
178: : (buffer_head - buffer_tail));
179:
180: /* don't copy out more data than there is space available: */
181: buffer_size = TME_MIN(buffer_size, resid);
182: assert(buffer_size > 0);
183:
184: /* only copy out data with the same buffer flags. if we just
185: wrapped in the buffer, we may find that no new data has the
186: same buffer flags as data we already copied out: */
187: scan_flags = buffer->tme_serial_buffer_data_flags + buffer_tail;
188: scan_resid = buffer_size;
189: for (; (*(scan_flags++) == data_flags
190: && --scan_resid > 0); );
191: buffer_size -= scan_resid;
192: if (buffer_size == 0) {
193: break;
194: }
195:
196: /* copy out this data: */
197: if (data != NULL) {
198: memcpy(data,
199: buffer->tme_serial_buffer_data + buffer_tail,
200: buffer_size);
201: data += buffer_size;
202: }
203:
204: /* update and loop: */
205: buffer_tail = (buffer_tail + buffer_size) & buffer_size_mask;
206: resid -= buffer_size;
207: }
208:
209: /* store our new tail pointer: */
210: if (!(copy_flags & TME_SERIAL_COPY_PEEK)) {
211: buffer->tme_serial_buffer_tail = buffer_tail;
212: }
213:
214: /* done: */
215: if (_data_flags != NULL) {
216: *_data_flags = data_flags;
217: }
218: return (count - resid);
219: }
220:
221: /* this returns the amount of busy space in the buffer: */
222: unsigned int
223: tme_serial_buffer_space_busy(const struct tme_serial_buffer *buffer)
224: {
225: unsigned int buffer_head, buffer_tail, buffer_size;
226:
227: /* get the head, tail, and size: */
228: buffer_head = buffer->tme_serial_buffer_head;
229: buffer_tail = buffer->tme_serial_buffer_tail;
230: buffer_size = buffer->tme_serial_buffer_size;
231:
232: if (buffer_head >= buffer_tail) {
233: return (buffer_head - buffer_tail);
234: }
235: else {
236: return (buffer_size - (buffer_tail - buffer_head));
237: }
238: }
239:
240: /* this returns the amount of free space in the buffer: */
241: unsigned int
242: tme_serial_buffer_space_free(const struct tme_serial_buffer *buffer)
243: {
244: /* you can't completely fill the buffer: */
245: return ((buffer->tme_serial_buffer_size - 1)
246: - tme_serial_buffer_space_busy(buffer));
247: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.