📄 secs1mra.c
字号:
/*
* secs1mra.c
*
* Secs 1 Message Receive allocation
*
* figures out what blocks go with what messages
*
* Code by David Lindauer, CIMple technologies
*
*/
#include <memory.h>
#include "secs2.h"
#include "units.h"
extern SECS1_BLOCK receive_blocks[NUMBER_RECEIVE_BLOCKS];
extern int device_id;
extern int expected_waiting;
extern BOOL is_in_wait;
/*
* list of stream, function pairs we are expecting or have received
* when an element of this queue is deleted, other elements are moved
* down, therefore it is not really a circular que but a type of list.
*/
EXPECTED expected_blocks[NUMBER_EXPECTED_BLOCKS];
int last_expected_block;
/* Host must be able to change these SECS-1 values
*/
int interblock_time, reply_time;
BOOL discarding_duplicates;
NUMBER secspre_interblock = { 0.0F, UN_SECONDS };
NUMBER secspre_reply = { 0.0F, UN_SECONDS };
/* unused receive blocks are kept on a free list which is composed of
* a pointer to the first entry and a count, number of entries */
static int free_pointer, free_count;
/*
* Register a primary message as expecting a reply, or expecting
* more blocks in a multi-block received message.
*/
int MraRegisterExpected(SECS1_BLOCK *block_ptr, BOOL useSecondary)
{
EXPECTED *ep;
// Quit if full up
if (last_expected_block == NUMBER_EXPECTED_BLOCKS)
return(MRA_ALLOC_ERR);
// Set up the system and message bytes appropriately
ep = &expected_blocks[last_expected_block];
memcpy(&ep->h,&block_ptr->h, sizeof(SECS1_HEADER));
if (useSecondary)
ep->h.Lmessage++;
// Turn on reply timer if waiting
if (block_ptr->h.W) {
ep->timing = MRA_REPLY_TIME;
ep->timer.length = reply_time;
SecsTimestart(&ep->timer);
}
// Always waiting on first block
ep->blocknum = 1;
// No blocks received
ep->firstblock = MRA_NO_BLOCK;
return(last_expected_block++);
}
/*
* Delete an entry form the expected list and return all associated
* receive buffers to the free list
*/
void MraUnregisterExpected(int number)
{
int i,done = FALSE, lastblock;
EXPECTED *ep;
// Quit if nothing to delete
if ((number == MRA_NO_BLOCK) || (last_expected_block == 0)) return;
ep = &expected_blocks[number];
if ((lastblock = ep->firstblock) != MRA_NO_BLOCK) {
// IF any receive blocks Count up number of receive blocks to free
while (!done) {
free_count++;
if (lastblock == ep->nextblock)
done = TRUE;
else
lastblock = receive_blocks[lastblock].nextblock;
}
// Now add blocks back into free list
receive_blocks[ep->nextblock].nextblock = free_pointer;
free_pointer = ep->firstblock;
}
// Adjust if this is the slave waiting for a reply
if (is_in_wait)
if (expected_waiting == number)
is_in_wait = FALSE;
else
if (expected_waiting > number)
expected_waiting--;
/* Release entry from expected list */
if ( number != last_expected_block - 1) {
for (i=number; i<last_expected_block - 1; i++)
expected_blocks[i] = expected_blocks[i+1];
}
expected_blocks[--last_expected_block].status = MRA_FREE;
}
/* Return number of free buffers */
int MraFreeBuffers(void)
{
return(free_count);
}
/* Find out if block is in expected list
* Return -1 if not
*
*/
static int MraFindExpected( int number)
{
int i, retval=MRA_NO_BLOCK,blocknum;
SECS1_BLOCK *rp;
EXPECTED *ep;
// Get the blocknum of this block
rp = &receive_blocks[number];
blocknum = (rp->h.Ublock << 8) + rp->h.Lblock;
for (i=0; i< last_expected_block; i++) {
ep = &expected_blocks[i];
// For a block to be expected, the following must match expectations
// Block Number, Stream, Function, System bytes
if ((blocknum == ep->blocknum)
&& !memcmp( &ep->h.system1, &rp->h.system1, 4)
&& (ep->h.Umessage == rp->h.Umessage)
&& (ep->h.Lmessage == rp->h.Lmessage)) {
retval = i;
break;
}
}
return(retval);
}
/* Checks block against last block in this stream,func received
* for a duplicate
*/
static BOOL MraCheckDuplicate(int number, int linkage)
{
int retval=FALSE;
EXPECTED *ep;
ep = &expected_blocks[linkage];
if ((linkage != MRA_NO_BLOCK) && (ep->firstblock != MRA_NO_BLOCK))
if (!memcmp( &receive_blocks[number].h,
&receive_blocks[ep->nextblock].h,10))
retval = TRUE;
return(retval);
}
/* Find a free block for data reception.
* Return -1 if none.
*/
int MraAllocReceive(void)
{
int retval;
// Return if none
if (free_count == 0) return(MRA_ALLOC_ERR);
// Else free a block from the list
free_count--;
retval = free_pointer;
free_pointer = receive_blocks[free_pointer].nextblock;
// and return it
return(retval);
}
// Add a single block back into the free list
void MraDeallocReceive(int number)
{
free_count++;
receive_blocks[number].nextblock = free_pointer;
free_pointer = number;
}
/*
* Perform primary block portion of MRA flowchart
*/
static void MraPrimaryBlock(int block, int linkage, BOOL firstblock)
{
EXPECTED *ep;
ep = &expected_blocks[linkage];
if (!firstblock)
// Link in block
receive_blocks[ep->nextblock].nextblock = block;
ep->nextblock = block;
if (receive_blocks[block].h.E) {
// All done with this message
ep->timing = MRA_NOTIMING;
ep->status = MRA_COMPLETE;
}
else {
// Else turn on interblock timer and expect next block
ep->timing = MRA_REPLY_TIME;
ep->timer.length = interblock_time;
SecsTimestart(&ep->timer);
ep->blocknum++;
}
}
/*
* Perform secondary block portion of MRA flowchart
*/
static void MraSecondaryBlock(int block, int linkage)
{
EXPECTED *ep;
ep = &expected_blocks[linkage];
// Assume no more blocks
ep->timing = MRA_NOTIMING;
if (((receive_blocks[block].h.Ublock << 8) + receive_blocks[block].h.Lblock) == 1) {
// First block, set up
ep->firstblock = block;
ep->nextblock = block;
}
else {
// Not first block of multi-block message
receive_blocks[ep->nextblock].nextblock = block;
ep->nextblock = block;
}
if (receive_blocks[block].h.E) {
// IF last block, mark it
ep->status = MRA_COMPLETE;
ep->timing = MRA_NOTIMING;
}
else {
// Otherwise turn on timer and expect next block
ep->timing = MRA_INTERBLOCK_TIME;
ep->timer.length = interblock_time;
SecsTimestart(&ep->timer);
ep->blocknum++;
}
}
/*
* Main portion of MRA flowchart
*/
void MraReceive(int block)
{
int linkage;
BOOL block_error = FALSE;
// See if block is expected
linkage = MraFindExpected(block);
if (((receive_blocks[block].h.Udevice << 8) + receive_blocks[block].h.Ldevice) == device_id) {
// Meant for this machine
if (discarding_duplicates && MraCheckDuplicate(block,linkage)) {
// Duplicate block detected, ignore it
MraDeallocReceive(block);
}
else { // Check if expecting block
if (linkage == MRA_NO_BLOCK) { // Check if primary block
if (!IS_PRIMARY(receive_blocks[block])) {
// Unexpected secondary message
block_error = TRUE;
}
else { // Check if first block
if (((receive_blocks[block].h.Ublock << 8) + receive_blocks[block].h.Lblock) != 1) {
// Not first block of unexpected primary message
block_error =TRUE;
}
else { // No errors
if ((linkage =MraRegisterExpected(&receive_blocks[block], FALSE)) != MRA_ALLOC_ERR ) {
// Now pretend the block is registered and handle it
expected_blocks[linkage].firstblock = block;
MraPrimaryBlock(block,linkage,TRUE);
}
else {
// No expected blocks left to register in, ignore the data
MraDeallocReceive(block);
}
}
}
}
else { // Block expected
if (IS_PRIMARY(receive_blocks[block])) {
// Multiple block of a primary message
MraPrimaryBlock(block,linkage,FALSE);
}
else { // Secondary block received
// First or any block of secondary message,
MraSecondaryBlock(block,linkage);
}
}
}
}
else { // Device Error, tell SECS2 about it
block_error = TRUE;
Secs2ErrorInsert(ST_ERRORS,ER_UNRECDEV, &receive_blocks[block].h,
MRA_NO_BLOCK);
}
if (block_error)
// Block Error, delete the expectation
if (linkage != MRA_NO_BLOCK)
MraUnregisterExpected(linkage);
}
/*
* Check all expected block entries for timeout
*/
void MraTimeouts(void)
{
int i;
for (i=0; i<last_expected_block; i++)
if (expected_blocks[i].timing != MRA_NOTIMING)
if (SecsTimeout(&expected_blocks[i].timer))
if (expected_blocks[i].timing == MRA_REPLY_TIME) {
expected_blocks[i].status = MRA_ABORT;
Secs2ErrorInsert(ST_ERRORS,ER_TIMEOUT,
&expected_blocks[i].h,i);
}
else { // MRA_INTERBLOCK_TIME
expected_blocks[i].status = MRA_ABORT;
Secs2ErrorInsert(ST_ERRORS,ER_TIMEOUT,
&expected_blocks[i].h,i);
}
}
/*
* Initialize for MRA
*/
void MraInit(BOOL power_up)
{
if (power_up) {
int i;
// Init free list
free_count = NUMBER_RECEIVE_BLOCKS;
free_pointer = 0;
for (i=0; i< free_count -1; i++)
receive_blocks[i].nextblock = i+1;
// Initialize expected blocks
last_expected_block = 0;
for (i=0; i< NUMBER_EXPECTED_BLOCKS; i++) {
expected_blocks[i].status = MRA_FREE;
expected_blocks[i].timing = MRA_NOTIMING;
}
}
interblock_time = TO_INTERBLOCK;
reply_time = TO_REPLY;
// Do this here in case SECS menu not included
secspre_interblock.value = ((INTVAL) TO_INTERBLOCK);
secspre_reply.value = ((INTVAL) TO_REPLY) / 10;
discarding_duplicates = TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -