|
|
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.