|
pipe.c |
|
|---|---|
|
|
/*
* pipe.c
*
* ------------------------------------------------------------
* A Kla2 Module
* Copyright (c) 2003, David Clifton
* All Rights Reserved
* http://www.codelode.com
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice, website reference, this permission
* notice, and the disclaimer of warranty below shall be included
* in all copies, derivatives, 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 THE AUTHORS OR COPYRIGHT
* HOLDERS 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.
* -------------------------------------------------------------
*
* data & methods for pipe object
*
* NOTES:
*
* 1) It is a useful practice to put each individual pipe object
* into its own source file, which contains a pointer to its allocated
* PIPE structure, the contiguous buffer area, and wrapper functions
* (which eliminate the need to pass the PIPE * pointer) for each
* of the Pipe methods used by the application.
*
* 2) It is up to the user to determine what action to take if
* the pipe fills up. This action may be to simply discard
* the input data, or to abort the program, or to wait for
* the pipe to be read (only works if the receiver is at a
* higher priority which is usually not the case). Pipe overflow
* can be a useful tool to determine whether the system
* has enough processing power to meet its obligations.
*
* 3) Buffers are retrieved from the pipe in the order in
* which they were put, not necessarily the order in which
* they were allocated.
*/
#include "types.h"
#include "sizes.h"
#include "err.h"
#include "intrpt.h"
#include "pfcn.h"
#include "pipe.h"
/*
* buffer node struct
*/
struct bufnode {
u8 *bufptr;
s16 bnnext;
};
/*
* BUFNODE type
*/
typedef struct bufnode BUFNODE;
/*
* private method declarations
*/
PIPE *firstFreePipe(void);
s16 firstFreeBnode(void);
void *moveFreeToAllocd(PIPE *pipeptr);
void moveAllocdToFilled(PIPE *pipeptr,void *bufptr);
void *moveFirstFilledToRecvd(PIPE *pipeptr);
void moveRecvdToFree(PIPE *pipeptr,void *bufptr);
/* ---------------------------------------------------------------
* Pipe object data
* --------------------------------------------------------------- */
/*
* A pointer to the dummy buffer is returned if a user
* calls Pipe_bufalloc() with a NULL (PIPE *) argument.
* This fact can be used to permit the pipe supplier
* to put data to a pipe before the pipe has been
* allocated by its receiver. Such data will not
* take up a pipe buffer, or be transmitted to the
* receiver.
*/
u8 dummyBuffer[SYSMAX_PIPEBUF_SIZE];
/*
* initialized pipe code constant
*/
const s16 initPipeCode= 0xBEAD;
/*
* table of pipe structs
*/
PIPE pipeTable[SYSMAX_PIPES];
/*
* table of pipe buffer nodes (contains pointers to buffers)
*/
BUFNODE pbufTable[SYSMAX_PIPEBUFS];
/*
* first Free buffer node
*/
s16 firstFreeBufnode=NIL;
/*----------------------------------------------------------------
* Public method definitions
* --------------------------------------------------------------- */
/*
* Pipe_init
* Initialize the pipe table and the pipe buffer table
*/
void Pipe_init(void)
{
s16 j;
/*
* initialize all the pipe table entries
*/
for(j=0;j<SYSMAX_PIPES;j++) {
pipeTable[j].ipcode=initPipeCode; // flag memory as a pipe struct
pipeTable[j].bnum=0;
pipeTable[j].bsiz=0;
pipeTable[j].freeList=NIL;
pipeTable[j].allocdList=NIL;
pipeTable[j].filledListFirst=NIL;
pipeTable[j].filledListLast=NIL;
pipeTable[j].recvdList=NIL;
pipeTable[j].recvPfcn=NIL;
}
/*
* initialize all the pipe buffer nodes
* and put them into the pipe buffer node
* free chain
*/
firstFreeBufnode=0;
for(j=0;j<SYSMAX_PIPEBUFS;j++) {
pbufTable[j].bufptr=NULL;
if((j+1)==SYSMAX_PIPEBUFS) {
pbufTable[j].bnnext=NIL;
} else {
pbufTable[j].bnnext=j+1;
}
}
}
/*
* Pipe_new
*
* Allocate a new PIPE struct.
*
* Initialize the struct with the number and size of pipe
* buffers, the location of a contiguous block of memory
* large enough to contain all the pipe buffers, and the
* pfcn index of a registered prioritized function
* to use as a buffer receive function.
*
* If the receive function index is NIL, nobody will be notified
* when a buffer is placed into the pipe. Such a pipe must
* be polled by using the Pipe_dataAvailable() method.
*
* Returns a pointer to the PIPE struct allocated.
*
* Does an error shutdown if there are no PIPE structs
* left to allocate.
*
* NOTE:
* If interrupt latency is an important issue, do all
* of the pipe allocations before the main processes are
* started.
* Notice that there is no method for de-allocating
* a pipe. Dynamic Pipe allocation after initialization
* is discouraged.
*/
PIPE *Pipe_new(s16 bufno,s16 bufsiz,void *bufptr,s16 rcvpfcn)
{
PIPE *dapipe;
u8 *baddr; // address of next buffer
s16 bndex,bprev,numbufs; // pointers to buffer nodes
bool intsav;
intsav=Intrpt_disable();
dapipe=firstFreePipe();
if(dapipe==NULL) {
Err_shutdown(NO_MORE_PIPES);
} else {
if(bufno<1) {
Err_shutdown(NEED_ATLEAST_ONE_PIPEBUF);
} else {
dapipe->bnum=bufno;
}
if(bufsiz>SYSMAX_PIPEBUF_SIZE) {
Err_shutdown(BAD_PIPE_BUFSIZE);
} else {
dapipe->bsiz=bufsiz;
}
if(bufptr==NULL) {
Err_shutdown(NO_PIPE_BUFFER_SPACE);
} else {
dapipe->bptr=(u8 *)bufptr;
}
dapipe->recvPfcn=rcvpfcn;
/*
* build the pipe's free chain of buffer nodes
* with pointers to associated buffers in
* the space provided
*/
bprev=NIL;
bndex=firstFreeBnode();
if(bndex==NIL) {
Err_shutdown(NO_MORE_PIPE_BUFNODES);
} else {
baddr=dapipe->bptr;
numbufs=0;
do {
if(bprev==NIL) {
dapipe->freeList=bndex;
} else {
pbufTable[bprev].bnnext=bndex;
}
pbufTable[bndex].bufptr=baddr;
bprev=bndex;
bndex=firstFreeBnode();
if(bndex==NIL) {
Err_shutdown(NO_MORE_PIPE_BUFNODES);
} else {
numbufs++;
baddr=baddr+dapipe->bsiz;
}
} while ( numbufs
|