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

📄 secs1btp.c

📁 SECS I, SECS II协议通讯源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * secs1btp.c
 *
 * SECS-1 Block Transfer protocol routines
 *
 * Code by David Lindauer, CIMple technologies
 *
 */
#include "secs1.h"
#include "units.h"

#include <stdio.h>


#define LOG

#ifdef LOG
FILE *file;
BOOL cleared=FALSE;
#endif

// Define this if you want to disable all SECS-1 and SECS-2 timeouts
// #define DISABLE_SECS_TIMERS

/* Code for Block Transfer Protocol flow chart*/

extern int last_expected_block;
extern EXPECTED expected_blocks[NUMBER_EXPECTED_BLOCKS];

/* Send, receive buffer allocations */
SECS1_BLOCK send_blocks[NUMBER_SEND_BLOCKS];
SECS1_BLOCK receive_blocks[NUMBER_RECEIVE_BLOCKS];

/* Que insertion/deletion pointers */
int send_insert, send_delete;

/* Block being received into */
static int receiving_block;

// The host computer is a slave, the equipment a master.
// Should be false for equipment according to SECS1 BTP standards,
BOOL is_slave;  // TRUE for HOST COMPUTER, FALSE for equipment
BOOL is_in_wait;  // TRUE if slave is waiting for a reply to
                          // primary message
int expected_waiting; // The expected block we are waiting on

// We set this true each time after we succeed at a send
// So the SECS-2 establish will know...
BOOL send_success;

// We set this true during a receive, false afterward
BOOL btp_receiving;

// We set this true if we pass the retry limit
// SECS-2 will drop into the CR/CRA handshaking to try to establish
// communications if it goes true
BOOL secs1_retrylimit;

/* Following SECS-1 parameters must be setable, e.g. from touch-screen */

SECS_TIMER to_interchar, to_protocol;
int retries, device_id;
COMMSTATES CommStates;

NUMBER secspre_interchar = { 0.0F, UN_SECONDS };
NUMBER secspre_protocol = { 0.0F, UN_SECONDS };
NUMBER secspre_retries = { 0.0F, UN_NOUNIT | UNI_INTEGER };
NUMBER secspre_devid = { 0.0F, UN_NOUNIT | UNI_INTEGER };

// Baud rates
MODIFY secspre_baud = { 0 , 5 };
int baudlist[] = { 300, 1200, 2400, 4800, 9600 } ;

// First block allocated for this SECS2 message
// Used if SECS2 wants to deallocate everything on error
int send_first;

/* Routine to put a character out over serial port.
 * Returns TRUE if character output
 * MUST be non-buffering
*/
static BOOL BtpCharout(int data)
{
  Pause();
#ifdef LOG
  cleared = TRUE;
  fprintf(file,"\n>>%02x ",(BYTE)data);
#endif
  return(Secs1Charout(data));
}
/* Buffered version of the above.
*/
static BOOL BtpBufferedCharout(int data)
{
#ifdef LOG
  cleared = TRUE;
  fprintf(file,">>%02x ",(BYTE)data);
#endif
  Pause();
  return(Secs1BufferedCharout(data));
}
/* Routine to get a character.  Returns -1 if no character.
  * Note that binary data is being recieved, not ASCII.
*/
static int BtpCharin(void)
{
  int data=Secs1Charin();
#ifdef LOG
  if (data != BTP_NO_DATA) {
    cleared = TRUE;
    fprintf(file,"<<%02x ",(BYTE)data);
  }
#endif
  Pause();
  return(data);
}
/*
* Clear all but last char from serial buffer, or last two if they
  * are ACK and ENQ.  My interpretation of A.4.1 takes it to mean the
 * FIRST time the listen state is entered from above.
 */
static void BtpClearbuf(void)
{
#ifdef LOG
  if (!cleared)
    fprintf(file,"\n");
  cleared = TRUE;
#endif
  Secs1Clearbuf();
}
/* Start a timer
*/
void SecsTimestart(SECS_TIMER *timer)
{
  timer->startval = GetBiosTicks();
	// Timer->length is in 10ths of seconds, we convert to MS
  timer->TickLength= CvtToTicks(timer->length*100);
  timer->timing = TRUE;
}
/* Return true if timer timed out */

BOOL SecsTimeout(SECS_TIMER *timer)
{
#ifdef DISABLE_SECS_TIMERS
  // Never times out if disabled!
  return FALSE;
#else
  BOOL retval;

  // If timer is timing
  if (timer->timing) {
    int length;

    // Get length we've been going and adjust if there was a rolloever
    // This depends upon the max tick length being much less than
    // the max value GetBiosTicks returns
    length = GetBiosTicks()-timer->startval;
    if (length <0)
      length += TimerMax();
    // Now if we've gone long enough stop the timer
    if (length > timer->TickLength) {
      timer->timing = FALSE;
      retval = TRUE;
    }
    else
      // Still going
      retval = FALSE;

  }
  else
    // Stopped timers are always timed out
    retval = TRUE;

  return(retval);
#endif // DISABLE_SECS_TIMERS
}
/* Calculate checksum.  The 1992 specs indicate it should be the
* sum of all unsigned data bytes in the message excluding length and
* checksum bytes.
*/
static int BtpChecksum(SECS1_BLOCK *data)
{
  int i, checksum=0,length;

  // The length byte NEVER reflects the header length
  length = data->length + SECS1_HEADLEN + 1;

  // Notice the indice on the loop, also this is one example of why
  // the 'data' 'header' and 'length' fields must follow each other
  for (i=1; i< length; i++)
    checksum+=*(&data->length+i);

  return(checksum);
}
/*
 * handle reception, at this point we've received an ENQ
 */
static void BtpReceive(void)
{
  int checksum, read_checksum = 0, thischar, length;
  BOOL skim_chars = FALSE;

  btp_receiving = TRUE;

  // EOT and start protocol timer and clear buffer
  BtpCharout(EOT);
  SecsTimestart(&to_protocol);
  BtpClearbuf();

  // If we don't get the length before the timeout, put a NAK & exit
  while ((thischar = BtpCharin()) == BTP_NO_DATA)
    if (SecsTimeout(&to_protocol)) {
      // NO LENGTH BYTE
      BtpCharout(NAK);
      btp_receiving = FALSE;
      return;
  }

  if ((thischar >= SECS1_HEADLEN) && (thischar <= MAX_BLOCK_LEN + SECS1_HEADLEN)) {
    // Valid length byte
    if ((receiving_block = MraAllocReceive()) != MRA_ALLOC_ERR) {
      int i;
      SECS1_BLOCK *bp = &receive_blocks[receiving_block];

      // We have a block, set up the data length and receive length
      bp->length = (BYTE) (thischar - SECS1_HEADLEN);
      length = thischar + 2;

      for (i=0; i<length; i++) {
        // For each char, start the timer
        SecsTimestart(&to_interchar);
        while (TRUE) {
          // Get it and decide what to do with it.  Another reason for the
          // specific ordering of fields in the block structure
          thischar = BtpCharin();
          if (thischar != BTP_NO_DATA) {
            if (i < length-2)
              *((BYTE *)(&bp->length)+i+1) = (BYTE) thischar;
            else {
              read_checksum = (read_checksum << 8) + thischar;
            }
            break;
          }
          else
            if (SecsTimeout(&to_interchar)) {
              // IF we get here there was a timeout, NAK the block and clean up
              BtpCharout(NAK);
              MraDeallocReceive(receiving_block);
              btp_receiving = FALSE;
              return;
            }
        }
      }
      // Got the whole block, verify the checksum
      checksum = BtpChecksum(bp);
      if (checksum != read_checksum) {
        skim_chars = TRUE;
        MraDeallocReceive(receiving_block);
      }
      else {
        /* Happily got a block, do something with it and then ACK it */
        MraReceive(receiving_block);
        BtpCharout(ACK);
      }
    }
    else // No blocks to allocate, ignore the message
      // SECS-2 will time out eventually and any partial message will be purged
      skim_chars = TRUE;
  }
  else // Length out of range
    skim_chars = TRUE;

  if (skim_chars) {
    // Bad data, keep getting characters from the input stream until there
    // is an intercharacter timeout
    SecsTimestart(&to_interchar);
    BtpClearbuf();
    while (TRUE) {

⌨️ 快捷键说明

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