// -*- mode: C; tab-width: 2 ; indent-tabs-mode: nil -*- // // Unified Keyboard Project // ASDF keyboard firmware // // asdf_buffer.c // // This is a circular buffer module that can be used by any part of the code // that requires buffering. Buffering provides an interface between the // generation of keycodes and the hardware-level keycode transmission, which may // occur at different rates. // // Copyright 2019 David Fenyes // // This program is free software: you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software // Foundation, either version 3 of the License, or (at your option) any later // version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more // details. // // You should have received a copy of the GNU General Public License along with // this program. If not, see . #include #include #include "asdf.h" #include "asdf_buffer.h" // Implementation Notes: // // 1) Note that this implementation does not support dynamic allocation and // freeing of buffers. Each buffer is allocated at startup and is stable forever // afterwards. // // 2) Buffer handles are indices into an array of buffer-tracking structures. // Using indices rather than pointers incurs a small performance penalty for the // extra level of indirection, but affords the advantage of testing the buffer // handle for validity. // Define the low-level details for each buffer. typedef struct { asdf_keycode_t *buf; int16_t size; uint8_t head; uint8_t tail; uint8_t count; } asdf_buffer_t; // This is the pool of codes available for buffering. This pool is divided among // the allocated buffers. static asdf_keycode_t buffer_pool[ASDF_BUFFER_POOL_SIZE]; // This array stores the buffering details for each allocated buffer. The number // of available buffers is defined in the header file. static asdf_buffer_t buffers[ASDF_BUFFER_NUM_HANDLES]; // Index of the beginning of unallocated part of the buffer pool. static int16_t buffer_pool_next_available; // Index of the next available buffer handle static asdf_buffer_handle_t next_handle; // PROCEDURE: asdf_buffer_init // INPUTS: none // OUTPUTS: none // // DESCRIPTION: Initialize the buffer pool and handles // // SIDE EFFECTS: See description // // NOTES: // // SCOPE: public // // COMPLEXITY: 1 // void asdf_buffer_init(void) { buffer_pool_next_available = 0; next_handle = 0; } // PROCEDURE: buffer_handle_valid // INPUTS: (uint8_t) handle - handle to be checked // OUTPUTS: returns TRUE if the handle is a valid allocated handle. // // DESCRIPTION: Returns TRUE if the handle is one that has been allocated. // // SIDE EFFECTS: none // // NOTES: // // SCOPE: private // // COMPLEXITY: 1 // uint8_t buffer_handle_valid(asdf_buffer_handle_t handle) { return ((handle >= 0) && (handle < next_handle)); } // PROCEDURE: asdf_buffer_new // INPUTS: (uint16_t) size: size of the buffer to allocate. // // OUTPUTS: returns a uint8_t handle to identify the buffer allocated from the // pool. // // DESCRIPTION: Receives a request to allocate a fixed-size buffer from the // pool. If there is enough room in the buffer pool, and if a buffer handle is // available, then allocate space from the pool, initialize the next available // buffer struct, and return the handle. // // SIDE EFFECTS: see above // // SCOPE: public // // COMPLEXITY: 3 // asdf_buffer_handle_t asdf_buffer_new(int16_t size) { asdf_buffer_handle_t handle = ASDF_BUFFER_INVALID; if (next_handle < ASDF_BUFFER_NUM_HANDLES) { if (size <= (ASDF_BUFFER_POOL_SIZE - buffer_pool_next_available)) { handle = next_handle++; buffers[handle].size = size; buffers[handle].buf = &buffer_pool[buffer_pool_next_available]; buffers[handle].head = 0; buffers[handle].tail = 0; buffers[handle].count = 0; buffer_pool_next_available += size; } } return handle; } // PROCEDURE: asdf_buffer_put // // INPUTS:(asdf_buffer_t) buffer_handle: pointer to the buffer struct. // (asdf_keycode_t) code: code to be added to the queue. // // OUTPUTS: None // // DESCRIPTION: Add the keycode to the head of the output buffer. If the buffer // is full, quietly drop the keycode. // // SIDE EFFECTS: See DESCRIPTION // // NOTES: // // COMPLEXITY: 3 // // SCOPE: public // void asdf_buffer_put(asdf_buffer_handle_t handle, asdf_keycode_t code) { if (buffer_handle_valid(handle)) { if (buffers[handle].count < buffers[handle].size) { buffers[handle].buf[buffers[handle].head] = code; buffers[handle].head = (buffers[handle].head + 1) % buffers[handle].size; buffers[handle].count++; } } } // PROCEDURE: asdf_buffer_get // // INPUTS: None // // OUTPUTS: returns next code in the buffer. // // DESCRIPTION: Gets the next queued code in the output buffer and return the // value. // // SIDE EFFECTS: Removes a code from the queue. // // NOTES: If the buffer is empty, the code ASDF_INVALID_CODE is returned. // // COMPLEXITY: 2 // // SCOPE: Public // asdf_keycode_t asdf_buffer_get(asdf_buffer_handle_t handle) { asdf_keycode_t code = ASDF_INVALID_CODE; if (buffer_handle_valid(handle) && buffers[handle].count) { code = buffers[handle].buf[buffers[handle].tail]; buffers[handle].tail = (buffers[handle].tail + 1) % buffers[handle].size; buffers[handle].count--; } return code; } //-------|---------|---------+---------+---------+---------+---------+---------+ // Above line is 80 columns, and should display completely in the editor.