file name: lance.hpp, lance.cpp
classification: simulation
contents: class CLance
derived from: CApplControlledObject,
CCrashingModule
and CNeedInterrupt
use: provides an interface to the clock interface (CI) of the
network driver (ci.hpp)
global items used:
local items used:
const addr
broadcastAddress: the address used to specify a broadcast message.
const int
AddedBufferLength: the size of additional buffer that the Lance needs
for sending own information. Whenever GetBuffer() is called, the
Lance allocates AddedBufferLength bytes more, but returns a pointer
to the first byte after this additional portion. Thus, for the caller,
the function behaves as expected, but internally there is an additional
buffer allocated at the front.
Note: currently, the size is set to four bytes, because the
Lance adds the message ID.
local (static) functions of the implementation file:
bufx *BufToBufx
(char *buf): If buf is NULL, then the function returns NULL.
Otherwise, it assumes that buf is part of a bufx buffer
allocated by GetBuffer() and that AddedBufferLength bytes
before buf belong to bufx as well. The function returns
a pointer to the address bufx-AddedBufferLength, which is cast
to type bufx*.
char *BufxToBuf
(bufx *buf): If buf is NULL, then the function returns NULL.
Otherwise, it casts buf to type char* and returns a pointer
to the address of byte AddedBufferLength.
void ExtractMessage
(bufx *buf, INT16 size, SINT32 nodeID, int if_num, STimeData *time, char
**message, INT16 *msgsize): extracts the original message from the
message buffer announced by the Lance. The data that was automatically
inserted into the buffer (the clock value and area of the sender) is stored
in time. The rest of the message is put into message
(an array of characters is allocated for it) and the size of that array
is stored in msgsize. If one of the pointers is NULL, an assert
fails.
The function asserts that all added items have sizes between zero and
four byte. In addition, the accuracy may only have a size of zero,
two or four bytes. And if the size of the macrostamp is greater
than zero, the timestamp must have a size of four bytes.
If an item has a size less than four bytes, it is assumed that the
following part of the original four byte value was transmitted:
void CI_GetBuffer
(INT16 size, bufx **buf, int if_num, int area):
void CI_GetEnvelope
(int mode, tenvx **tenv, int if_num, int area):
void CI_RetBuffer
(bufx *buf):
void CI_RetEnvelope
(tenvx *tenv):
void CI_Send
(int mode, tenvx *tenv, bufx **buf, INT16 size, int if_num, int area):
Same as the CI functions. The functions are just wrappers to hide the
use of the CI dispatcher.
member variables:
int area_:
the area of the application.
default: parameter area of the ctor
CClockInterface
*clock_: a pointer to the associated clock.
default: NULL
CClockSync
*clockSync_: a pointer to the associated clock synchronization module.
If it is set to NULL, incoming messages are ignored.
default: NULL
SRandomData
distDataRecv_: distribution data used for choosing the delay of outgoing
messages.
default and reset value: dist=Uniform, all other members are
0
SRandomData
distDataSend_: distribution data used for choosing the delay of outgoing
messages.
default and reset value: dist=Uniform, all other members are
0
CDelayList
listOfDelayedMessages_: the list of all currently delayed messages.
default and reset value: empty list
SDelayMcb
msg_: the delayed message that is handled (sent or delivered) next.
default and reset value: NULL
INT32 msgID_:
the number of the next message that is sent.
default and reset value: 0
double
pRecvDuplicate_: the probability that an incoming message is duplicated.
default and reset value: 0
double
pSendDuplicate_: the probability that an outgoing message is duplicated.
default and reset value: 0
double
pRecvScramble_: the probability that an incoming message is scrambled.
default and reset value: 0
double
pSendScramble_: the probability that an outgoing message is scrambled.
default and reset value: 0
CRandom
random_: the random class used to obtain the delay of a message.
EBool suspended_:
is set to True if the Lance is currently suspended (in this case, incoming
messages are ignored). If Send() is called, the variable is set
to False.
default and reset value: True
member functions:
CLance (CControllingObject
*ctrl, int area): Calls Init() to set all members to their
default values, installs the ISR for duty timer B5 using SetISR().
Interrupts are turned off using DisableInterrupts()
before the call to SetISR() and turned on using
EnableInterrupts()
afterwards.
~CLance
(): If member clock is not NULL, the duty timer B5 interrupt
and timer itself are disabled via the functions DisableInterrupt()
and DisableDutyTimer() of CClockInterface. The ISR is
removed from the vector table through a call to RemoveISR(),
which is again placed within a call to DisableInterrupts()
and EnableInterrupts(). Then, Dispose()
is called to delete the dynamic members.
void Announce
(renvx *renv, bufx *buf, INT16 size, int if_num): The function calls
ModifyCrashStatus(),
then checks if the module is crashed or suspended. If it is, ReportMessageEvent()
is called with DiscardRecvMessage and renv
and buf are returned using RetReceiveEnvelope() and RetReceiveBuffer().
If the module is not crashed, DelayMessage() is called to delay
the message. If the message should be duplicated, then renv and
buf
are copied into freshly allocated structures and DelayMessage()
is called a second time for the duplicated message. In this case, ReportMessageEvent()
is called with DuplicateRecvMessage to report
the duplication.
Note: the function assumes that renv and buf
are local and were allocated using the member functions GetReceiveBuffer()
and GetReceiveEnvelope().
void AnnounceNow
(renvx *renv, bufx *buf, INT16 size, int if_num): The function is
called by the isr() and delivers the message to the ClockSync
module.
The function first checks if a ClockSync module is attached (that is,
member clockSync is not NULL). If there is none, ReportMessageEvent()
is called with DiscardRecvMessage and renv
and buf are returned using RetReceiveEnvelope() and RetReceiveBuffer().
Then the function returns.
Otherwise, ExtractMessage() is called to get the original
message, ModifyCrashStatus() is invoked, and afterwards the function
checks if the module is crashed or suspended. If it is, ReportMessageEvent()
is called with DiscardRecvMessage, the buffers
are returned as described above and the function returns.
Otherwise, ScrambleMessage() is called with the sender address,
the sender time and the original data buffer, and at last CClockSync::Announce()
is called to deliver the message. Afterwards, the buffers are returned.
Note: the function assumes that renv and buf
are local and were allocated using the member functions GetReceiveBuffer()
and GetReceiveEnvelope().
int Crash
(): Calls the Crash() function of the base class CCrashingModule
to crash the module, but in addition calls DeleteDelayedMessages()
to discard all delayed messages.
DelayMessage
(int mode, tenvx *tenv, char *message, INT16 msgsize, int if_num, int area):
Delays outgoing messages according to distDataSend. The function
gets the current time from the clock, then delays the message according
to the computed delay and calls Insert() to put the message into
the listOfDelayedMessages.
If member clock is NULL, an assert fails.
DelayMessage
(renvx *renv, bufx *buf, INT16 size, int if_num): Delays incoming
messages. Has the same behaviour as the function described above, but uses
the data structures for incoming messages.
If member clock is NULL, an assert fails.
void DeleteDelayedMessages
(): If member msg is NULL, the function returns at once.
Otherwise, it disables the duty timer B5, then deletes all messages contained
in msg or stored in the listOfDelayedMessages. At last,
msg
is set to NULL.
Dispose
(): Calls DeleteDelayedMessages() to discard all currently
delayed messages, then deletes members random and listOfDelayedMessages.
virtual
EBool ExecuteCommand (const SCommand& command): All commands are
first passed to the ExecuteCommand() function of the base class
CApplControlledObject.
If it returns True, than this function returns True as well. Otherwise,
it returns the value of
CCrashingModule::ExecuteCommand().
void GetBuffer
(INT16 msgsize, char **message, INT32& msgID): Allocates a local(!)
buffer which has AddedBufferLength more bytes than specified in
msgsize
and sets *message to the value of BufxToBuf(). Member
msgID
is copied into the additional buffer in front of
buf, and parameter
msgID is set to the value of internal member msgID. The
latter is then incremented.
If message is NULL, an assert fails.
Note: since messages can be delayed for a long time, the data
is kept locally until it is really sent so as not to waste the CI buffers.
void GetEnvelope
(tenvx **tenv): Allocates a structure of type tenvx. Again,
the structure resides in local memory and is only copied into a CI envelope
upon send.
If tenv is NULL, an assert fails.
virtual
EBool GetParameter (SParameter& param) const: Returns True if the
parameter could be read. If not specified otherwise, all parameters assume
that param is of type SSingleParameter.
void GetReceiveBuffer
(INT16 size, bufx **rbuf): Allocates a local buffer of the requested
size.
If rbuf is NULL, an assert fails.
void GetReceiveEnvelope
(renvx **renv): Allocates a local structure of type renvx.
If renv is NULL, an assert fails.
void
Init (): All members are set to their reset values, dynamic members
random
and listOfDelayedMessages are created. In addition, the function
calls Suspend() to suspend the module.
void Insert
(SDelayMcb *mcb): Adds the message contained in mcb to the
list of delayed messages. If the delivery time of the message is earlier
than that currently stored in member msg, the message stored in
msg
is put into the listOfDelayedMessages and msg is set
to mcb. Otherwise, mcb is simply inserted into the listOfDelayedMessages.
If mcb or clock is NULL, an assert fails.
int isr():
Checks if an interrupt from duty timer B5 is pending. If not, the function
returns at once. Otherwise, it clears the interrupt and sends event TimerEvent.
Then it gets the current time from the clock, and delivers (that
is, calls SendNow() or AnnounceNow()) all messages that
are due at or before the current time. Then, the duty timer is either loaded
with a new time (the delivery time of the next message that is due) or
disabled (if there are no more delayed messages).
If clock is NULL, an assert fails. Also, if a B5 interrupt
is pending and no message is delayed (i.e., msg is NULL), an assert
fails.
Note: In pure simulation, the fact that the granularity of the duty timer is less than the granularity of the double value of the delivery time can cause an endless loop, if the delivery time is compared to the exact current time. Therefore, a message is delivered if its delivery time is less than or equal to the current time plus one tick of the duty timer (2^-16 seconds). For simplicities sake, this is also done in hardware-based simulation, because the slight error in the delivery is not considered important.
virtual
void ReportCrashChange(): Creates an event of type SApplCrashEvent,
sets its type to CrashStatusChange, the
module
to Lance, and crashed to the return value of Crashed(),
then sends it to the evaluation.
virtual
void ReportError(): Calls the global ReportError()
function with module = Lance, nodeID = GetNodeID() and
area
= area_.
void
ReportMessageEvent (EEvent type, INT32 msgID): Creates an event of
type SApplSendMsgEvent, sets its type
and msgID members to the parameters, sets the receiver
to NoAccount, the module to Lance, and sends
the event to the evaluation.
void
ReportMessageEvent (EEvent type, SINT32 nodeID, int area, INT32 msgID):
Creates an event of type SApplRecvMsgEvent,
sets its type, sender, senderArea and msgID
members to the parameters, sets the receiver to its own node ID,
the module to Lance, and sends the event to the evaluation.
int Reset
(): Just calls the Reset() functions of the base classes
CCrashingModule
and CControlledObject.
void ReturnBuffer
(char *message): Calls BufToBux() to get the real bufx
pointer and then frees this pointer. The function assumes that the buffer
was allocated using GetBuffer().
If message is NULL, an assert fails.
void ReturnEnvelope
(tenvx *tenv): Frees the pointer. The function assumes that the envelope
was allocated using GetEnvelope().
If tenv is NULL, an assert fails.
void RetReceiveBuffer
(bufx *rbuf): Frees the buffer. The function assumes that the buffer
was allocated using GetReceiveBuffer().
If rbuf is NULL, an assert fails.
void RetReceiveEnvelope
(renvx *renv): Frees the envelope. The function assumes that the envelope
was allocated using GetReceiveEnvelope().
If renv is NULL, an assert fails.
void
Scramble (void *data, INT16 size): Scrambles size bytes of
the buffer pointed to by data. The function draws a uniform random
number in the interval (0, 0xFFFFFFFF), then XORs this value to every four
byte of the data. If size is no multiple of four, the last bytes
are scrambled using the first byte of the random number.
void
ScrambleMessage (addr address, char *msg, INT16 size, INT32 msgID):
Scrambles outgoing data. The function decides according to pSendScramble
if the data should be scrambled. If it should not, the function returns
at once. Otherwise, it calls ReportMessageEvent() with ScrambleSendMessage
and then calls Scramble() to scramble the the address
and msg buffers.
void
ScrambleMessage (addr address, STimeData *time, char *msg, INT16 size,
int if_num, int area, INT32 msgID): Scrambles incoming messages. The
function decides according to pRecvScramble if the message should
be scrambled. If it should not, the function returns at once. Otherwise,
it calls ReportMessageEvent() with ScrambleRecvMessage
and then calls Scramble() to scramble the address, time
and msg buffers.
void Send
(int mode, tenvx *tenv, char *message, INT16 size, int if_num, int area):
The function sets suspended to False, then calls ModifyCrashStatus()
and afterwards checks the crash status of the module. If it is crashed,
ReportMessageEvent()
is called with DiscardSendMessage and tenv
and message are returned using ReturnEnvelope() and ReturnBuffer().
If the module is not crashed, DelayMessage() is called to delay
the message. If the message should be duplicated, then tenv and
message
are copied into freshly allocated structures and DelayMessage()
is called a second time for the duplicated message. In this case,
ReportMessageEvent()
is called with DuplicateSendMessage to report
the duplication. The message ID that is reported is that of the duplicated
message.
Parameter tenv may be NULL.
int SendNow
(int mode, tenvx *tenv, char *message, INT16 size, int if_num, int area):
Is called by the isr() and delivers the message to the network.
Parameter tenv may be NULL.
The function calls ModifyCrashStatus() and then checks if
the module is crashed. If it is, ReportMessageEvent() is called
with event DiscardSendMessage, tenv and
message
are returned using ReturnEnvelope() and ReturnBuffer().
Then the function returns 0.
If the module is not crashed, ScrambleMessage() is called
with the message and the destination address (if tenv is NULL,
the broadcast address is used). Then the CI buffers are allocated using
CI_GetEnvelope()
and CI_GetBuffer(), and tenv and message are
copied into them (in the case of the latter, the
AddedBufferLength
bytes directly before the pointer are copied as well). At last, CI_Send()
is called to send the message, the CI buffers are returned and the local
tenv
and message are returned as well. The function returns the result
of CI_Send().
If message is NULL, an assert fails.
void SetClock
(CClockInterface *clock): Sets the CClockInterface
pointer clock_ to the object. More specifically, the function
checks if member clock is NULL, and if it is not, DisableInterrupt()
and DisableDutyTimer() of class CClockInterface are called
to disable the interrupt and timer B5 of the old clock, before the member
is set to the new clock. After the assignment, member clock is
checked again, and if it is not NULL, CClockInterface::EnableInterrupt()
is called for duty timer B5. In addition, if member msg is not
NULL, that is, if delayed messages exist, then the duty timer is programmed
to produce an interrupt at the delivery time of the message stored in msg.
void SetClockSync
(CClockSync *cs): Sets the CClockSync
pointer cs_ to the object.
virtual
EBool SetParameter (SParameter& param) const: Returns True if the
parameter could be set. If not specified otherwise, all parameters assume
that param is of type SSingleParameter.
void Suspend():
Sets suspended to True to go into suspension mode. In that mode,
function Announce() will ignore messages from the network. In
addition, the function discards all currently delayed messages via DeleteDelayedMessages().
The lance will stay in suspension mode until function Send()
is called.