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

📄 secs1btp.c

📁 SECS I, SECS II协议通讯源码
💻 C
📖 第 1 页 / 共 2 页
字号:
      if (BtpCharin() != BTP_NO_DATA)
        SecsTimestart(&to_interchar);
      if (SecsTimeout(&to_interchar))
        break;
    }
    // Then NAK the block
    BtpCharout(NAK);
  }
  btp_receiving = FALSE;
}
/*
* Allocate a send buffer */
// Note that we've implemented this as a circular que, however, very little
// of the code presumes this is the case, so it should be fairly simple to
// modify this stuff to use another implementation if desired
int BtpAllocSend(BOOL first)
{
  int retval = send_insert;

  // Send buffers are kept in a circular que
  if (++send_insert >= NUMBER_SEND_BLOCKS)
    send_insert = 0;

  // If there are no more send blocks tell the caller
  if (send_insert == send_delete) {
    send_insert = retval;
    return(BTP_ALLOC_ERR);
  }

  // if This is the first block of a message register it
  if (first)
    send_first = retval;

  return(retval);
}
/*
 * Deallocate a single send buffer, used during transmission to lose the
 * sent block
 */
static void BtpDeallocSend(void)
{
  if (send_insert == send_delete)
    return;

  send_blocks[send_delete].ready_to_send = 0;
  if (++send_delete >= NUMBER_SEND_BLOCKS)
    send_delete = 0;
}
/*
 * Deallocate all blocks in this message, used prior to send to invalidate
 * the message we were currently working on
 */
void BtpUnallocAll(void)
{
  // Quit if none
  if (send_first == BTP_NO_FIRST)
    return;

  // Back up one block at a time until all gone
  while ((send_insert != send_delete) && (send_first != send_insert)) {
    if (--send_insert < 0)
      send_insert = NUMBER_SEND_BLOCKS - 1;
    send_blocks[send_insert].ready_to_send = 0;
  }

  // Can't do this again
  send_first = BTP_NO_FIRST;
}
// Flush all send buffers
void BtpFlushSend(void)
{
  int i;

  for (i=0; i< NUMBER_SEND_BLOCKS; i++) {
    send_blocks[i].ready_to_send = 0;
  }
  send_insert = 0;
  send_delete = 0;
  send_first = BTP_NO_FIRST;
}
/* Put data out on the line, we get here after a block has been marked
 * as ready to send
 */
static void BtpSend(void)
{
  int i,length,checksum, thischar, total_tries;
  BOOL reading_response, sending_enq;
  SECS1_BLOCK *bp = &send_blocks[send_delete];

  // We can attempt this several times
  total_tries = retries;

  // Until we succed or give up
  while (TRUE) {
    // Send ENQ, start protocol timer, clear input buffer
    BtpCharout(ENQ);
    SecsTimestart(&to_protocol);
    BtpClearbuf();

    sending_enq = TRUE;
    while (sending_enq) {
      if ((thischar = BtpCharin()) == EOT)
        // If we get an EOT the ENQ was successful
        sending_enq = FALSE;
      else {
        if (SecsTimeout(&to_protocol)) {
          // IF we get a timeout try again
          if (--total_tries < 0) {
            // too many retries, LOSE BLOCK CONTENTS of entire multiblock message
            // and exit
            secs1_retrylimit = TRUE;
						do {
							BtpDeallocSend();
            } while (!send_blocks[send_delete].h.E && (send_insert != send_delete));
            return;
          }
          else {
            // Else another retry, restart timer and send another ENQ
            SecsTimestart(&to_protocol);
            BtpCharout(ENQ);
          }
        }
        else
          if (is_slave && (thischar == ENQ)) {
            // CONTENTION, go do receive logic
            BtpReceive();
            // Then try to send the thing again
            SecsTimestart(&to_protocol);
            BtpCharout(ENQ);
          }
      }
    }

    // ENQ resulted in EOT, get length and checksum
    length = bp->length + SECS1_HEADLEN;
    checksum = BtpChecksum(bp);

    // Send length, header, data, checksum
    // Note again the reliance on the order of fields in the block structure
    BtpBufferedCharout(length);
    for (i=0; i<length; i++)
      BtpBufferedCharout(*((BYTE *)(&bp->length)+i+1));
    BtpBufferedCharout(checksum>>8);
    BtpCharout(checksum & 0xff);

    // Start timer, wait for ACK
    SecsTimestart(&to_protocol);
    BtpClearbuf();

    reading_response = TRUE;
    while (reading_response) {
      thischar = BtpCharin();
      if (thischar == ACK) {
        // ACK, block received, release it
        if (bp->h.E && bp->h.W) {
          // Register the block as expected and mark a wait
          // for reply before sending anything else if you are the slave
          // Note that this leaves us with the R and W bits set but with
          // the SECS-2 func set to the reply value in the
          // event an error is issued, which is fine, it may help diagnose
          // problems at some point in the future
          is_in_wait = is_slave;
          expected_waiting = MraRegisterExpected(bp, TRUE);
        }
        BtpDeallocSend();
        send_success = TRUE;
        return;
      }
      if (SecsTimeout(&to_protocol) || (thischar != BTP_NO_DATA)) {
        // OUT OF TIME or INVALID CHAR, do OUTER (RETRY) LOOP
        reading_response = FALSE;
        if (--total_tries < 0){
          // too many retries, LOSE BLOCK CONTENTS of entire multiblock message
          // and exit.  This algorythm is one of the few places we make an
          // assumption about the order in which blocks are allocated, if
          // the allocation routines are changed this will need it too.
          // This also depends upon the SECS-2 format not mixing the blocks
          // of different messages, which, the current implementation will not
          secs1_retrylimit = TRUE;
          while (!bp->h.E && (send_insert != send_delete))
            BtpDeallocSend();
          return;
        }
      }
    }
  }
}
// Power-up init, init anything which might be a factory preset now
void Secs1pup(BOOL power_up)
{
  int i;
  if (power_up) {

    is_slave = FALSE;

    send_insert = 0;
    send_delete = 0;
    receiving_block = 0;
    send_first = BTP_NO_FIRST;

    is_in_wait = FALSE;
    expected_waiting = 0;

    send_success = FALSE;

    secs1_retrylimit = FALSE;

    // Clear buffers
    BtpFlushSend();
    for (i=0; i< NUMBER_RECEIVE_BLOCKS; i++) {
      receive_blocks[i].ready_to_send = 0;
    }

    // Line initialization
    Secs1CharInit();
  }

  retries = DF_RETRY;
  to_interchar.timing = FALSE;
  to_interchar.length = TO_INTERCHAR;
  to_protocol.timing = FALSE;
  to_protocol.length = TO_PROTOCOL;
  device_id = DF_DEVID;

  // Low level communication params
  CommStates.BaudRate = DF_BAUD;
  CommStates.MultiDropAddress = 0;

  // This has to be done here in case the SECS menu is not included
  secspre_interchar.value = ((INTVAL) TO_INTERCHAR) /10;
  secspre_protocol.value = ((INTVAL) TO_PROTOCOL) / 10 ;
  secspre_retries.value = ((INTVAL) DF_RETRY);
  secspre_devid.value = ((INTVAL) DF_DEVID);

  secspre_baud.value = 0;
  while( baudlist[secspre_baud.value] && (baudlist[secspre_baud.value] != DF_BAUD))
    secspre_baud.value++;

#ifdef LOG
  file = fopen("data","w");
#endif
  // MRA initialization
  MraInit(power_up);
}
/* Idle routine, waits for data available either to receive from
  * the line or send from a buffer.  Note we've added code to prevent the
  * host (slave) from sending more than one primary message at a time.  Not in the
  * specs but without this we get contention.
*/
void BtpIdle(void)
{
  BOOL sent;
  while (TRUE) {
    sent = FALSE;

    // Send data if ready and not waiting for a response
    if (send_blocks[send_delete].ready_to_send) {
      if (is_in_wait)
        if (expected_blocks[expected_waiting].status == MRA_COMPLETE)
          is_in_wait = FALSE;
      if (!is_in_wait) {
      	sent = TRUE;
        BtpSend();
      }
    }

    // Specs specify that we don't try to receive while there is stuff to send
    if (!sent) {
      BtpClearbuf();
      if (BtpCharin() == ENQ)
        BtpReceive();
    }

    /* check interblock and reply timers */
    MraTimeouts();
  }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -