The functions are just simulations of the real driver functions, so their behaviour will not always be the same as that of the real CI functions. I have tried to point out all differences that I know, but more may exist.
global items used by the functions:
local variables of the implementation file:
CNodeIdList
listOfInitializedNetworks: Stores all network IDs, for which ci_init()
has been called.
simulated functions:
INT32
ci_buf_size (INT16 size): Returns the number of bytes that have to
be allocated if a buffer size of size is requested in ci_get_tbuf().
It is the least multiple of sizeof(bufx) that is >= size.
Note: this is *no* CI function! You have to declare it before you
can use it. It is only needed to make the computation of the number of
bufx structures that are needed easier and less error prone. Since
both ci_get_tbuf() and SMsg need to
do such a computation, this function is provided for it.
int
ci_dispatcher (int functionID, ciparam *param): The dispatcher checks
the function code functionID, extracts the parameters from param,
calls the appropriate function and returns its value. If the function is
not known or not supported (only functions listed below are supported),
INVALID_COMMAND is returned. If param is NULL, INVALID_POINTER
is returned.
int
ci_get_tbuf (INT16 size, bufx **buf, int if_num, int area): Allocates
a buffer structure of at least size bytes. The function first
checks if area is less than MAXASICS (ci.h). If it is not, INVALID_IF_NUMBER
is returned. Then, if_num is searched in the list of initialized
networks, and if it is not found, INVALID_IF_NUMBER is returned. If buf
is NULL, INVALID_POINTER is returned. Last, the size is checked:
if it is 0, *buf is set to NULL and 0 (success) is returned. Ifsize
is positive, ci_buf_size() is called and the return value is used
to allocate the buffer array which is stored in *buf. If the memory
allocation fails, NO_BUF_FREE is returned, else the function was successful
and 0 is returned.
Note: the buffer is allocated as an array of unsigned char, which
is cast to bufx*.
Note: the real CI function has a limited number of buffers per network
and area. So it may happen that NO_BUF_FREE occurs in hardware-based simulation,
although it has never occurred in pure simulation.
int
ci_get_tenv (int mode, tenvx **tenv, int if_num, int area): The function
first checks area and if_num as described for function
ci_get_tbuf() and returns INVALID_IF_NUMBER if one of them is
not valid. If tenv is NULL, INVALID_POINTER is returned. Otherwise,
a new object of type tenvx is allocated. If the allocation fails,
NO_ENV_FREE is returned, otherwise, tenv is modified to point
to the object and 0 (success) is returned.
Note: in pure simulation, the mode is copied into tenvx::length_field
to tell the network if it should timestamp the message belonging to this
envelope or not.
Note: again, the real CI function has a limited number of envelopes
per network and area. Therefore it may happen that NO_ENV_FREE occurs in
hardware-based simulation, although it has never occurred in pure simulation.
int
ci_init (int if_num, ci_fn ci_announce_add, ci_efn ci_announce_error_add):
Must be called for every network that is to be used. The function searches
listOfNetworks for the networkID if_num.
If the network is found, the networkID is put into the internal list of
initialized networks and 0 is returned. If the network was not found, INVALID_IF_NUMBER
(error.h) is returned. If either the announce or the announce error function
pointer is NULL, INVALID_POINTER is returned.
int
ci_ret_tbuf (bufx *buf): If buf is NULL, the function returns
INVALID_BUF_ADDRESS, else the buffer memory is deleted.
Note: it is assumed that the buffer has been allocated using function
ci_get_tbuf(), so buf is taken to be an array of unsigned
char.
Note: the real CI functions make a difference between rbuf
and tbuf buffers: tbuf buffers (and tenvx envelopes)
are used for sending messages, rbuf (and renvx) are used
for receiving messages. Since my application does not return the structures
(I leave that to the CI functions) anyway, I do not check the type of buffer
returned with ci_ret_tbuf().
int
ci_ret_tenv (tenvx *tenv): If tenv is NULL, the function
returns INVALID_ENV_ADDRESS, else the envelope memory is deleted.
int
ci_send (int mode, tenvx *tenv, bufx *buf, INT16 size, int if_num, int
area): The function first checks area and if_num
as described for function ci_get_tbuf() and returns INVALID_IF_NUMBER
if one of them is not valid. If tenv is NULL, NO_ENVELOPE_ATTACHED
is returned. If not, the network with networkID if_num is searched
in the listOfNetworks and if it is not found
(which may happen if the network has been deleted after ci_init()
was called), INVALID_IF_NUMBER is returned. If the network was found, the
message is sent. Then, mode is checked: if the flag RET_PKB_IMM
(ci.h) is set, buf and tenv are immediately returned
calling ci_ret_tbuf() or ci_ret_tenv(). In any case,
if the message is sent to the network, the function was successful and
returns 0. If the function is not successful, RET_PKB_IMM is ignored and
the envelope and buffer are not freed.
Note: I do not know what the real function would do if the network
were physically removed. Probably crash.
Note: the real function does not send the message to the network
at once, but stores it in a queue until it can be sent. If for some reason
the message cannot be sent, function ci_announce_error() would
be called to notify the sender of the failure. In pure simulation, this
part of the CI interface is not implemented, so if the message cannot be
sent, it is lost.
not needed and therefore not implemented are the following functions:
void ci_announce_up (renvx *renv, bufx *buf, INT16 size, int if_num)
void ci_announce_error_up (tenvx *env, bufx *buf, INT16 size, int if_num,
int area)
int ci_mcon()
int ci_ret_rbuf (bufx *rbuf)
int ci_ret_renv (renvx *renv)
the following functions are only needed in hardware based simulation:
int ci_announce (renvx *renv, bufx *buf, INT16 size, int if_num):
The function is called by the CI to distribute an incoming messages to
all Lances. The Lance modules of the node can be obtained by iterating
through the listOfSupervisors and getting a
pointer to the their Lance modules via CSupervisor::GetLance().
First, you should asure that the data buffer is contiguous. Next, for each
Lance you should obtain local buffers through the functions CLance::GetReceiveBuffer()
and CLance::GetReceiveEnvelope(), copy the CI
buf and renv structures into the local ones, and call
CLance::Announce(). At last, you should return
the CI constant IMMEDIATE_RELEASE to let the CI return its buffer
and envelope.
void ci_announce_error (tenvx *env,bufx *buf,INT16 size,int if_num,int area): Just release the buffers and call the global ReportError() function to report that the CI has announced an error and that the message was discarded.