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

📄 stream1.c

📁 SECS I, SECS II协议通讯源码
💻 C
字号:
/*
 * Stream1.c
 *
 * actual value handling, equipment functionality and communication init
 *
 * Code by David Lindauer, CIMple technologies
 *
 */
#include "secs2.h"
#include "units.h"
#include <string.h>

// Define this to disable the establish communications state routines
// #define DISABLE_ESTABLISH_METHOD

/* Establish Communication state diagram states */
enum CommStates { WaitCRA, WaitDELAY, WaitTX };
/* Establish Communication receive types */
enum ReceiveStates { None, CR, CRA0, CRA1, CRA_SENT, ERROR, BadData, Other };

/* A User configurable value, tenths of senconds */
/* Must be changeable */
int EstablishCommunicationsTimeout;
NUMBER secspre_establish = {0.0F, UN_SECONDS };

extern SECS1_BLOCK receive_blocks[NUMBER_RECEIVE_BLOCKS];
extern EXPECTED expected_blocks[NUMBER_EXPECTED_BLOCKS];
extern int last_expected_block;
extern CTEXT secs_model[SECS2_MODLEN+1];
extern CTEXT secs_softrev[SECS2_SOFTLEN+1];
extern SR_STRUC secs_actuallist[];
extern uint language;
extern int reply_time;
extern int err_insert, err_delete;
extern BOOL send_nothing;
extern BOOL send_success;
extern int receive_number;

/* List of routines to call based on Stream value received */
PASSFUNC streamlist[] = {
  {ST_ACTUALS,Stream1 },
  {ST_PRESETS,Stream2 },
  {ST_ALARMS,Stream5 },
  {ST_PROCPROG, Stream7 },
  {ST_TERMINAL,Stream10 },
  {0,0} };

/* List of stream initialize routines to call */
PASSFUNC streaminit[] = {
  {ST_ACTUALS,Stream1Init },
  {ST_PRESETS,Stream2Init },
  {ST_ALARMS,Stream5Init },
  {ST_PROCPROG, Stream7Init },
  {ST_TERMINAL,Stream10Init },
  {0,0} };

/* True if we've passed to the state COMMUNICATING in the
  * Establish communications state diagram
*/
BOOL communicating;

/* Number of entries in the actual list */
static int number_actual;
/* list of preset/actual items being enquired by the host */
int enquire_list[NUMBER_ENQUIRIES];
/* Timers used in Establishing communications */
static SECS_TIMER CommDelay;
static SECS_TIMER ReplyDelay;
/*
* Functions of the form sXXfYY specify the primary stream and function
* that the host requests a reply to.  By definition, the reply will
* have YY 1 greater than XX, e.g. the secondary message.  This is
* initialized generically in Secs2StreamDispatch.
*/
// Send the reply to are you there and communications requesters
static void SendModln(void)
{
  IF_LIST(2);
  IF_ASCII(SECS2_MODLEN);
  SA(secs_model,SECS2_MODLEN);
  IF_ASCII(SECS2_SOFTLEN);
  SA(secs_softrev,SECS2_SOFTLEN);
}
/* ARE YOU THERE */
static void S1f1(void)
{
  Secs2CheckHeaderOnly();
  SendModln();
}
/*
* Subroutine puts out an actual value according to the specification
* largely untested except for the default
*/
static void SrPutValue(int number)
{
  switch (secs_actuallist[number].units) {
    int temp;
    case UN_BINARY:
            IF_BINARY(1);
            SB(* ((BYTE *) (secs_actuallist[number].value)));
            break;
    case UN_BOOL:
            IF_BOOL(1);
            SB(* ((BYTE *) (secs_actuallist[number].value)));
            break;
    case UN_ASCII:
            IF_ASCII(temp = strlen((char *) secs_actuallist[number].value));
            SA((char *) secs_actuallist[number].value,temp);
            break;
    case UN_MODE:
            IF_UINT(1);
            SI(* ((int *) (secs_actuallist[number].value)));
            break;
    case UN_INT:
            IF_INT(1);
            SI(* ((int *) (secs_actuallist[number].value)));
            break;
    case UN_FLOAT:
            IF_FLOAT(1);
            SF(* ((float *) (secs_actuallist[number].value)));
            break;
    default:
            Secs2bSendValue(* ((float *) (secs_actuallist[number].value)),
                      secs_actuallist[number].units);
            break;
  }
}
/* GET SELECTED EQUIPMENT STATUS */
static void S1f3(void)
{
  int i, count,itemcount, allentries = FALSE;

  // Verify the format
  count = FV(FM_LIST);

  if (count > NUMBER_ENQUIRIES)
    Secs2ToomuchdataError();

  // IF no request or any request has zero length report all
  if (!count)
    allentries = TRUE;
  else
    // Read in requests
    for (i=0; i<count; i++) {
      itemcount = FV(FM_UWORD);
      if (!itemcount)
        allentries = TRUE;
      enquire_list[i] = RW();
    }


  if (allentries) {
    IF_LIST(number_actual);
    for (i=0; i<number_actual; i++)
      SrPutValue(i);
  }
  else {
    IF_LIST(count);
    for (i=0; i<count; i++)
      if (enquire_list[i] >= number_actual)
        // IF out of range we don't knowthe format, report binary
        IF_BINARY(0);
      else
        SrPutValue(enquire_list[i]);
  }
}
/* FORMATTED STATUS REQUEST */
static void S1f5(void)
{
  Secs2UnrecfunError();
}
/* FIXED FORM REQUEST */
static void S1f7(void)
{
  Secs2UnrecfunError();
}
/* STATUS VARIABLE NAMELIST REQUEST */
static void S1f11(void)
{
  int i, count,itemcount, allentries = FALSE, temp;

  // Validate format
  count = FV(FM_LIST);

  if (count > NUMBER_ENQUIRIES)
    Secs2ToomuchdataError();

  if (!count)
    allentries = TRUE;
  else
    for (i=0; i<count; i++) {
      itemcount = FV(FM_UWORD);
      if (!itemcount)
        allentries = TRUE;
      enquire_list[i] = RW();
    }

  if (allentries) {
    IF_LIST(number_actual);
    for (i=0; i<number_actual; i++) {
      IF_LIST(3);
      IF_UWORD(1);
      SW(i);
      IF_ASCII(temp=strlen(secs_actuallist[i].text[language]));
      SA(secs_actuallist[i].text[language],temp);
      if (secs_actuallist[i].units == UN_USEPRESET)
        Secs2bSendUnits(((PRESET *)secs_actuallist[i].value)->units);
      else
        Secs2bSendUnits(secs_actuallist[i].units);
    }
  }
  else {
    IF_LIST(count);
    for (i=0; i<count; i++) {
      int thisentry;
      IF_LIST(3);
      IF_UWORD(1);
      SW(thisentry=enquire_list[i]);
      /* 1992 SPECS do not say what happens if SVID out of range,
       * so, send back zero length items
       */
      if ((thisentry) > number_actual) {
        IF_ASCII(0);
        IF_ASCII(0);
      }
      else {
        IF_ASCII(temp=strlen(secs_actuallist[thisentry].text[language]));
        SA(secs_actuallist[thisentry].text[language],temp);
        if (secs_actuallist[i].units == UN_USEPRESET)
          Secs2bSendUnits(((PRESET *)secs_actuallist[i].value)->units);
        else
          Secs2bSendUnits(secs_actuallist[i].units);
      }
    }
  }
}
/*
* This response to CR will only be used when in the
* COMMUNICATING state; e.g. not during communications establish.
*/
static void S1f13(void)
{
  if (FV(FM_LIST) != 0)
    Secs2BaddataError();
  IF_LIST(2);
  IF_BINARY(1);
  SB(0);
  SendModln();
}
/* This secondary message may be received as a residue of the establish
* communications procedure.
*/
static void S1f14(void)
{
  // Verify format
  Secs2bReceiveSetup(0);
  if (FV(FM_LIST) != 2)
    Secs2BaddataError();
  if (FV(FM_BINARY) != 1)
    Secs2BaddataError();
  RB();
  if (FV(FM_LIST) != 0)
    Secs2BaddataError();
  send_nothing = TRUE;
}
// Now we send a CR as a part of the establish communications routine,
// not as a result of the normal parsing mechanism
static void SendCR(void)
{
  // We are going to wait for a reply so SECS1 will register the reply
  // as expected and net it.  But the reply timer may time out before
  // the communications establish timer does... whether this means anything
  // or not is a real mystery
  Secs2bInitheader(TRUE,TRUE,ST_ACTUALS,SR_CR);
  SendModln();
  Secs2bFlagSent();
}
// Now we send a CRA as a part of the establish communications routine,
// not as a result of the normal parsing mechansim
static void SendCRA(BOOL commack)
{
  BYTE data = 0;
  if (commack)
    data++;
  Secs2bInitheader(TRUE,FALSE,ST_ACTUALS,SR_CRA);
  IF_LIST(2);
  IF_BINARY(1);
  SB(data);
  SendModln();
  Secs2bFlagSent();
}
/*
* Receive a message and determine what class it is in:
* None received
* CR
* CRA
* ERROR
* Other message
*/
enum ReceiveStates ReceiveCR()
{
  enum ReceiveStates retval = None;
  int func,stream;

  if (send_success) {
    send_success = FALSE;
    return (CRA_SENT);
  }

  // Nothing here, return
  if ((last_expected_block == 0) || (expected_blocks[0].status != MRA_COMPLETE))
    return(None);

  // Get stream and func
  stream = receive_blocks[expected_blocks[0].firstblock].h.Umessage;
  func = receive_blocks[expected_blocks[0].firstblock].h.Lmessage;

  // Else find out what we got
  if (stream == ST_ACTUALS)
    if (func == SR_CR)
      retval = CR;
    else
      if (func == SR_CRA) {
        Secs2bReceiveSetup(0);
        if (FV(FM_LIST) != 2)
          retval = BadData;
        else
          if (FV(FM_BINARY) != 1)
            retval = BadData;
          else {
            if (RB())
              retval = CRA1;
            else
              retval = CRA0;
            if (FV(FM_LIST) != 0)
              retval = BadData;
            else
              if (receive_number != RECEIVE_COMPLETE)
                retval = BadData;
          }
      }
      else
        if (func == 0)
          retval = ERROR;
        else
          retval = Other;

  // Lose the message
  MraUnregisterExpected(0);

  return(retval);
}
/*
* Code for the Establish Communications state diagram
  */
void Secs2EstablishCommunications(void)
{
  enum CommStates currentState;
#ifdef DISABLE_ESTABLISH_METHOD
  communicating = TRUE;
  return;
#endif

  send_success = FALSE;

  // Start the timer, we send a CR out at this interval
  CommDelay.length = EstablishCommunicationsTimeout;
  SecsTimestart(&CommDelay);
  SendCR();

  // Start timer, we expect a CRA response within this interval
  ReplyDelay.length = reply_time;
  SecsTimestart(&ReplyDelay);

  // Go to initial state
  currentState = WaitCRA;
  while (!communicating) {
    Pause();
    switch (currentState) {
      int type_received;

      case WaitCRA:
              // Waiting for a CRA, if we get a CRA with COMMACK = 0
              // We are then communicating
              if ((type_received = ReceiveCR()) == CRA0)
                communicating = TRUE;
              else {
                // Otherwise if we have an error or time is up waiting for CRA
                // or COMMACK was 1 we wait around a bit
                if ( (type_received ==  BadData)
                    || SecsTimeout(&ReplyDelay) || (type_received == CRA1)
                    || (type_received == ERROR)) {
                  currentState = WaitDELAY;
                }
                else
                  // Otherwise if we get a CR we send a CRA
                  // and wait to see if we are communicating
                  if (type_received == CR) {
                    SendCRA(FALSE);
                    ReplyDelay.length = reply_time;
                    SecsTimestart(&ReplyDelay);
                    currentState = WaitTX;
                  }
              }
              break;
      case WaitDELAY:
              // If we get a CR send a CRA and wait to see if
              // we are communicating
              if ((type_received  = ReceiveCR()) == CR) {
                SendCRA(FALSE);
                ReplyDelay.length = reply_time;
                SecsTimestart(&ReplyDelay);
                currentState = WaitTX;
              }
              else
                // If there is a timeout or we get something other than
                // CR start over
                if (((type_received != None) && (type_received != CRA_SENT))
                      || SecsTimeout(&CommDelay)) {
                  CommDelay.length = EstablishCommunicationsTimeout;
                  SecsTimestart(&CommDelay);
                  SendCR();
                  currentState = WaitCRA;
                }
              break;
      case WaitTX:
              // IF there is an error or COMMACK = 1 start over
              if (((type_received = ReceiveCR()) == CRA1)
                  || (type_received == BadData)){
                SendCR();
                ReplyDelay.length = reply_time;
                SecsTimestart(&ReplyDelay);
                currentState = WaitCRA;
              }
              else
                // Else if is CRA with COMMACK = 0, or sending of
                // CRA is complete we are communicating
                if ((type_received == CRA0) || (type_received == CRA_SENT))
                  communicating = TRUE;
              break;
    }
  }
}
// List of all stream 1 functions
static PASSFUNC Stream1funcs[] = {
  { SR_AREYOUTHERE, S1f1 },
  { SR_SELDATA, S1f3 },
  { SR_FORMDATA, S1f5 },
  { SR_FORMSPEC, S1f7 },
  { SR_SELSPEC, S1f11 },
  { SR_CR,   S1f13 },
  { SR_CRA,  S1f14 },
  { 0,0 } };
/*
* Dispatch a function handler
*/
void Stream1(int number)
{
  Secs2FuncDispatch(number, Stream1funcs);
}
/*
* Initialize for stream
  *   count number of items in actual list
*/
void Stream1Init(BOOL power_up)
{
  BOOL done = FALSE;

  if (power_up) {
    communicating = FALSE;

    number_actual = 0;
    while (!done)
      if (secs_actuallist[++number_actual].text == 0)
        done = TRUE;
  }
  EstablishCommunicationsTimeout = TO_ESTABLISH;
  // Do this here in case SECS menu not included
  secspre_establish.value = ((INTVAL) TO_ESTABLISH) / 10;
}

⌨️ 快捷键说明

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