📄 udprotcl.c
字号:
\***********************************************************/
count = LimitStringLength (lpSymEnt->msAddr1, lpSymEnt->msCount,
(WORD) lpSymEnt->msNumBytes, TRUE);
if (count < lpSymEnt->msCount) {
/* indicate string is truncated */
ptQuality = WW_SQ_CLAMPHI;
}
iStrLen = count * lpSymEnt->msNumBytes;
switch (lpSymEnt->msSubType)
{
case PLCS_STRC:
case PLCS_STRB:
case PLCS_STR_:
/* just copy the string */
_fstrncpy ((LPSTR) pStrBuf, (LPSTR) lpBuf, (size_t) iStrLen);
break;
case PLCS_STRP:
/* first byte is string length, get it, limit if needed */
i = (int) ((unsigned char) lpBuf[0]);
if ((i < 0) || (iStrLen <= i))
{
i = iStrLen - 1;
/* indicate string is truncated */
ptQuality = WW_SQ_CLAMPHI;
}
/* copy remainder of string, terminate it */
_fstrncpy ((LPSTR) pStrBuf, (LPSTR) &lpBuf[1], (size_t) i);
pStrBuf[i] = '\0';
break;
} /* switch */
/* Make sure the string is null-terminated */
pStrBuf [iStrLen] = '\0';
/* report new string value */
#ifdef DEBUG_CALL_TRAFFIC
if (Verbose)
debug (GetString (STRUSER + 151),
/* "DbNewVTQFromDevice ( 0x%08lX, 0x%08lX, 0x%08lX, %Fs, 0x%04lX ) %s = \"%s\"" */
(long) lpMsg->mmIdLogDev, (long) lpSymEnt->msDbHnd,
(long) ptValue.intg, UdprotGetDateTimeString(lpPtTime, szDateTime),
(long) ptQuality, "", pStrBuf);
#endif
ptValue = StrValInitialString ((LPSTR) pStrBuf);
DbNewVTQFromDevice(lpMsg->mmIdLogDev, lpSymEnt->msDbHnd, ptValue, lpPtTime, ptQuality);
break;
default:
break;
}
} /* UdprotExtractDbItem */
/***********************************************************************/
/** Extract data from response to read message.
The rspBuffer has the last message received from the communication port.
This function will extract the data from the response,
put it in ptValue, and send the data to the Toolkit database.
It is up to the Toolkit to detect whether the value has changed.
If it has, the Toolkit will relay the data to any clients who
are interested in the new value.
Called from ProcessValidResponse( ) **/
void
WINAPI
UdprotExtractReadData(LPPORT lpPort,
LPSTAT lpTopic,
LPUDMSG lpMsg)
{
LPEXTARRAY lpSymbol_table;
SYMPTR lpSymEnt;
BOOL bHaveDateTimeStamp;
PTTIME ptTime;
WORD startAddr, myAddr, count;
unsigned long firstSymIdx, lastSymIdx;
WORD numBytes;
WORD blockStart, blockOffset, bitOffset;
BOOL done;
CHAINSCANNER symbol_scanner;
ACTIVE_CHECK compValue;
/* get pointer to symbol table */
lpSymbol_table = &lpTopic->statSymTab;
if (lpSymbol_table == (LPEXTARRAY) NULL) {
/* cannot access symbol table structure, just return */
return;
}
/* indicate no date/time stamp set up yet */
bHaveDateTimeStamp = FALSE;
/*
* For each symbol table entry in this message
* extract the data from the message.
*/
/********************************************************************\
Set blockStart to the BYTE offset of the data block from the
beginning of the message as shown below.
Define the constant shown to have the required value.
\********************************************************************/
blockStart = UD_BLOCK_DATA_START;
/* get address of first point in message */
startAddr = lpMsg->mmStartAddr;
/* set up comparison value */
compValue.lpMsg = lpMsg; /* pointer to this message */
compValue.finalHandle = lpMsg->mmLastSym; /* last symbol in message */
compValue.SymHandle = 0; /* no symbol found yet */
/* get handles for first and last symbols in this message */
firstSymIdx = lpMsg->mmFirstSym;
lastSymIdx = lpMsg->mmLastSym;
/* get pointer to first symbol entry referenced by the message */
lpSymEnt = (SYMPTR) NULL;
if (firstSymIdx >= SYM_OFFSET) {
/* valid symbol handle, get pointer to symbol entry */
lpSymEnt = (SYMPTR) GetExtArrayMemberPtr (lpSymbol_table,
firstSymIdx - SYM_OFFSET);
/* get first active symbol referenced by this message */
/* Note: if found, compValue.SymHandle will be non-zero */
if (lpSymEnt != (SYMPTR) NULL)
lpSymEnt = (SYMPTR) FindItemStartingAt ((LPCHAINLINK) lpSymEnt,
&lpTopic->statSymUsed,
SCAN_FROM_HEAD,
IsActiveOnMessage,
&compValue,
&symbol_scanner);
}
/* scan through range of symbols covered by this message */
done = FALSE;
while ((!done) && (lpSymEnt != (SYMPTR) NULL)) {
/* check whether symbol is active and polled by this message */
if (compValue.SymHandle != 0) {
/* match found, get parameters from symbol table entry */
myAddr = lpSymEnt->msAddr1;
count = lpSymEnt->msCount;
numBytes = (WORD) lpSymEnt->msNumBytes;
/* check whether already have date/time stamp */
if (!bHaveDateTimeStamp) {
/* set up date/time stamp */
#ifdef WIN32
DbGetGMTasFiletime( &ptTime );
#else
ptTime.dwLowDateTime = 0;
ptTime.dwHighDateTime = 0;
#endif
/* indicate date/time stamp ready */
bHaveDateTimeStamp = TRUE;
}
/* determine starting point and length of data to convert */
switch (lpMsg->mmDataType) {
case PTT_DISCRETE:
/***********************************************************\
Compute the blockOffset and bitOffset, which are
dependent on the message format for this protocol.
The following example calculates these values where:
'blockStart' is BYTE offset from the beginning of
the message for the data block;
'startAddr' is the first bit number in the data block
'myAddr' is the bit number for this symbol
8-bits per BYTE is assumed
\***********************************************************/
blockOffset = (WORD) (blockStart + (myAddr-startAddr) / 8L);
bitOffset = (WORD) ((myAddr-startAddr) % 8);
break;
default:
/*
* The default section is for the PTT_INTEGER
* and PTT_REAL data types.
*/
/***********************************************************\
Compute the blockOffset and bitOffset, which are
dependent on the message format for this protocol.
The following example calculates these values where:
'blockStart' is BYTE offset from the beginning of
the message for the data block;
'startAddr' is the first symbol address in the data
block
'myAddr' is the symbol address for this symbol
'numBytes' is the number of BYTES in the message
for each "cell"
8-bits per BYTE is assumed
\***********************************************************/
blockOffset = (WORD) (blockStart + numBytes * (myAddr-startAddr));
bitOffset = 0;
break;
}
/* convert message segment to value and report it */
UdprotExtractDbItem(lpPort, lpSymEnt, lpMsg, blockOffset, bitOffset, &ptTime);
}
/* check whether to continue scanning */
if (lpSymEnt->msIndex + SYM_OFFSET == lastSymIdx) {
/* last symbol handle for message, exit */
done = TRUE;
} else {
/* get pointer to next active symbol on message, if any */
lpSymEnt = (SYMPTR) FindNextItem (&symbol_scanner);
}
}
} /* UdprotExtractReadData */
/***********************************************************************/
/** Process validated response back from the device **/
void
WINAPI
ProcessValidResponse(LPPORT lpPort)
{
LPUDMSG lpMsg;
LPSTAT lpTopic;
BYTE FAR *rsp;
/* get pointer to current message, if any */
lpMsg = lpPort->mbCurMsg;
if (lpMsg == (LPUDMSG) NULL) {
/* no current message, just return */
return;
}
/* check whether message has changed */
if (lpMsg->mmChanged) {
/* If was changed after it was written -- ignore the response */
return;
}
/* get pointer to corresponding station */
lpTopic = lpMsg->mmTopic;
if (lpTopic == (LPSTAT) NULL) {
/* unable to access station structure, just return */
return;
}
/* reset station retry limits */
lpTopic->statRetries = TOPIC_CONSEC_FAILURE_LIMIT;
lpTopic->statPortRetries = TOPIC_NORMAL_RETRIES;
/*********************************************************\
How messages are handled may depend on the protocol.
The following example handles reads and writes
and also processes error responses from the device.
\*********************************************************/
/* check type of message received */
rsp = (BYTE FAR *) lpPort->mbRspBuffer;
switch (*rsp) {
case 0x00: /* error message */
/* indicate error */
UdprotSetMsgQuality (lpTopic, lpMsg, WW_SQ_NOACCESS);
if (ShowingErrors) {
debug ("Error message received.");
showReceivedData (lpPort);
}
break;
default:
/* check type of message */
if (lpMsg->mmRead) {
/* was a "read" -- extract data from response and report it */
UdprotExtractReadData(lpPort, lpTopic, lpMsg);
}
break;
} /* switch */
/* check type of message */
if (!lpMsg->mmRead) {
/* was a "write" -- delete the write message */
UdprotDeleteCurWriteMsg(lpPort);
}
/* check station status, ensure we're out of slow poll mode */
UdprotSetTopicStatus (lpPort, lpTopic, FALSE);
} /* ProcessValidResponse */
/***********************************************************************/
/** Validate the received message, ensure it is in binary form
return TRUE if message is OK **/
static
BOOL
WINAPI
UdprotValidMessage(LPPORT lpPort)
{
/*******************************************************************\
The contents of this routine are protocol dependent.
Validate the frame format i.e. the checksum/CRC, start BYTE,
end BYTE, message contents, etc...
The following example uses the same validation routine used
by the PLC simulator itself to verify that the message contains
the right header, tail, characters, length, and checksum.
\*******************************************************************/
BOOL valid;
int len;
/* check whether message is valid format */
valid = IsCommandValid ((LPSTR) &lpPort->mbRspBuffer[0], lpPort->mbRspIndex);
/* if message is valid, convert hex ASCII to binary bytes as necessary */
if (valid) {
if (!lpPort->mbMsgInBinary) {
/* convert message to binary, determine whether result is valid */
len = lpPort->mbRspIndex;
valid = GetMsgAsBinary ((LPSTR) &lpPort->mbRspBuffer[0], &len);
lpPort->mbRspIndex = len;
/* indicate message in binary */
lpPort->mbMsgInBinary = TRUE;
}
}
return (valid);
} /* UdprotValidMessage */
/***********************************************************************/
/** Validate the frame and call ProcessValidResponse( ) if OK.
Called from DoProtocol( ) **/
void
WINAPI
UdprotProcessResponse(LPPORT lpPort)
{
/******************************************************************\
If the protocol for this driver uses ASCII characters, the
contents of lpPort->mbRspBuffer must be converted to binary now.
All code after this point assumes that lpPort->mbRspBuffer is
binary.
Example:
len = lpPort->mbRspIndex;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -