📄 stream1.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 + -