⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 secs1mra.c

📁 SECS I, SECS II协议通讯源码
💻 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 + -