📄 message.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
//
// FILE: Message.cpp : file
//
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "abcommsprocessor.h"
#include "message.h"
// English meanings for Allen-Bradley (Exception) error codes
PCHAR plcErrorLocal[9] = // local STS (low nibble)
{
"No error", // 0x0
"DST node out of buffer space", // 0x1
"Cannot guarantee delivery", // 0x2
"Duplicate token holder detected", // 0x3
"Local port is disconnected", // 0x4
"Application layer timed out waiting for response", // 0x5
"Duplicate node detected", // 0x6
"Station is offline", // 0x7
"Hardware fault" // 0x8
};
PCHAR plcErrorRemote[16] = // remote STS (high nibble)
{
"No error", // 0x00
"Illegal command or format", // 0x10
"Host has a problem and will not comm.", // 0x20
"Remote node host is missing,", // 0x30
"Host could not complete function due to h/w fault", // 0x40
"Addressing problem or memory protect rungs", // 0x50
"Function not allowed due to command protection selection", // 0x60
"Processor is in program mode", // 0x70
"Compatibility mode file missing or comm. zone problem", // 0x80
"Remote node cannot buffer command", // 0x90
"xxxx", // 0xA0
"Remote node problem due to download", // 0xB0
"xxxx", // 0xC0
"unused", // 0xD0
"unused", // 0xE0
"Error code is in EXT-STS" // 0xF0
};
// Global - Global data
BYTE txDLE_STX[SIZEOF_TAIL] =
{
ALLENBRADLEY_DLE,
ALLENBRADLEY_STX
};
BYTE txDLE_ACK[SIZEOF_TAIL] =
{
ALLENBRADLEY_DLE,
ALLENBRADLEY_ACK
};
BYTE txDLE_NAK[SIZEOF_TAIL] =
{
ALLENBRADLEY_DLE,
ALLENBRADLEY_NAK
};
BYTE txDLE_ETX[SIZEOF_TAIL] =
{
ALLENBRADLEY_DLE,
ALLENBRADLEY_ETX
};
BYTE txDLE_ENQ[SIZEOF_TAIL] =
{
ALLENBRADLEY_DLE,
ALLENBRADLEY_ENQ
};
// -------------------------------- CalcBCC ----------------------------
// Calculate Allen-Bradley specified BCC code
// the BCC is a 2'scomp sum of all bytes in the message frame excluding DLE-STX and DLE-ETX
BYTE CalcBCC(BYTE * lrcBuffPtr, // -> pointer to buffer at start of BCC
DWORD buffLen // ->
)
{
BYTE bcc=0;
CalcLRC(lrcBuffPtr, // -> pointer to buffer at start of LRC
buffLen, // ->
FALSE, // -> Calc 2's Compliment also (last call)
&bcc // <->
);
bcc = 256-bcc;
return(bcc);
} // CalcBCC
/////////////////////////////////////////////////////////////////////////////////
// CProtocolMessage implementation
/////////////////////////////////////////////////////////////////////////////////
CProtocolMessage::CProtocolMessage(const BYTE * pMessageRX, DWORD len)
{
}
CProtocolMessage::CProtocolMessage(const CProtocolMessage & oldProtMessage)
{ //copy constructor
}
/////////////////////////////////////////////////////////////////////////////////
// CABMessage implementation
/////////////////////////////////////////////////////////////////////////////////
// ----------------------- constructor -----------------------------------
CABMessage::CABMessage(const BYTE * pMessageRX, DWORD len, BOOL dataLayer)
: CProtocolMessage(pMessageRX, len)
{
BYTE *crcStartPtr = (BYTE*)pMessageRX;
WORD crc = 0;
BYTE bcc;
WORD *crcPtr;
WORD *bccPtr;
DWORD appStartOffset = 2; // data layer telegram
DWORD addressWidth, elementWidth;
transactionID = -1;
transmissionStatus = 0;
transmissionStatusEXT = 0;
if (!dataLayer)
{
appStartOffset=0; // this is an app layer telegram
len+=2;
}
ASSERT(len > 2);
ASSERT(len < sizeof(buffer));
memset(buffer, 0xCD, sizeof(buffer));
memcpy(&buffer[2], &pMessageRX[appStartOffset], len);
// double DLE stripping here
if (dataLayer)
StripDLEs(buffer, &len);
totalLen = (WORD)len;
// at this point we have a data layer message
crcCheckedOK = FALSE;
// break down the msg
count = 0;
if ((len>2) && (dataLayer))
{
if (buffer[0] != ALLENBRADLEY_DLE)
return;
if ((buffer[1] != ALLENBRADLEY_SOH )&&
(buffer[1] != ALLENBRADLEY_STX )&&
(buffer[1] != ALLENBRADLEY_ACK )&&
(buffer[1] != ALLENBRADLEY_NAK )&&
(buffer[1] != ALLENBRADLEY_ENQ )
)
return;
// we seem to have the beginning of the message, parse it
}
if (len > 3)
{
stationIDDest = (BYTE)buffer[AB_SOURCEBYTEOFF]; // Dest addr
stationIDSource = (BYTE)buffer[AB_DESTINATIONBYTEOFF]; // Source addr
}
if (len >4)
command = buffer[AB_COMMANDBYTEOFF]; // may be 0x0F other values are not processed
if (len >5)
transmissionStatus = buffer[AB_STATUSBYTEOFF];
if (len >=7)
{
transactionID = (buffer[6]) + (buffer[7]<<8);
}
if (len >8)
functionCode = buffer[8];
if (len > 9)
count = (BYTE)buffer[9]; // # bytes to be read (/2 to get integers)
if (len > 10)
fileNum = (BYTE)buffer[10];
if (len >11)
fileType = (BYTE)buffer[11];
addressWidth = 1;
elementWidth = 1;
if (len >12)
{
address = (BYTE)buffer[12];
if (address == 0xFF)
{
addressWidth=3;
address = buffer[12+1] + (buffer[13+1]<<8);
address = SwapBytes(address);
}
}
if (len >=(13+addressWidth)) // 14
{
subElement = buffer[12+addressWidth];
if (subElement == 0xFF)
{
elementWidth=3;
subElement = buffer[12+addressWidth+1] + (buffer[13+addressWidth+1]<<8);
subElement = SwapBytes(subElement);
}
}
if (len >=(13+addressWidth+elementWidth)) // 15
dataPtr = (BYTE*)&buffer[12+addressWidth+elementWidth];
if (dataLayer) // app messages will not have a CRC byte anyway
{
//check the CRC at this point
if (pGlobalDialog->m_useBCC)
{
if (len >= 17)
{
bccPtr = (WORD*)&buffer[totalLen-1];//count + 16];
crcStartPtr = (BYTE*)&buffer[2];
bcc = CalcBCC(crcStartPtr, totalLen-6); // Only one buffer to calc crc of
overalLen = count+16 + AB_BCC_LEN;
crcCheckedOK = (bcc==*bccPtr);
}
}
else
{
if (len >= 18)
{
CHAR ETXBuff[2];
crcPtr = (WORD*)&buffer[totalLen-2];//count + 16];
crcStartPtr = (BYTE*)&buffer[2];
crc = 0x0;
CalcCRC(crcStartPtr, totalLen-6, &crc); // Only one buffer to calc crc of
ETXBuff[0] = 0x03;
CalcCRC((BYTE*)&ETXBuff[0], 1, &crc); // include the ETX
overalLen = count+16 + AB_CRC_LEN;
crcCheckedOK = (crc==*crcPtr);
}
}
}
if (!crcCheckedOK)
return;
else
{
crc = 0xffff;
}
} // CABMessage
// --------------------------- CABMessage --------------------------
// PURPOSE: copy constructor used to build responses, does not actually
// copy the message.
CABMessage::CABMessage(const CABMessage & oldABMessage)
: CProtocolMessage(oldABMessage)
{
memset(buffer, 0xCD, sizeof(buffer));
//Copy in common stuff from both messages here!
m_localStationID = oldABMessage.m_localStationID;
stationIDSource = oldABMessage.stationIDSource;
stationIDDest = oldABMessage.stationIDDest;
functionCode = oldABMessage.functionCode;
fileType = oldABMessage.fileType;
address = oldABMessage.address; // where to copy data from
byteCount = oldABMessage.byteCount; // length of data to copy
overalLen = 0; //New message so 0 for now!
dataPtr = (BYTE*)buffer; //Nice a fresh pointer to the beginning!
}
// ------------------------- CalculateReadAheadLength -------------------------
// static function
WORD CABMessage::CalculateReadAheadLength(const BYTE*pBuffer, DWORD length)
{
//if (length < 2)
// return(2); // DLE ACK/NAK or DLE/STX in our case
// look at the rest of the telegram
return(1);
} // CalculateReadAheadLength
// -------------------------------- Status ----------------------------
// static function
BOOL CABMessage::Status(const BYTE*pBuffer, DWORD length)
{
if (length >6)
return(pBuffer[5]); // STS byte
return(FALSE);
} // CalculateReadAheadLength
// ------------------------------- GetValue -------------------------
//
WORD CABMessage::GetValue(WORD wIndex)
{
WORD *pData = (WORD*)dataPtr;
pData+=wIndex;
return(*pData);
}
// ------------------------------- StripDLEs ------------------------
LONG CProtocolMessage::StripDLEs(CHAR *bufferPtr, DWORD *numBytes)
{
char *pSourceData= bufferPtr;
char *pDestData = bufferPtr;
BOOL stripDLE = FALSE;
int count = *numBytes;
int bytesXferred=0;
int dleCount = 0;
//if (*numBytes <= 20)
return(0);
while (count>0)
{
if (*pSourceData == 0x10) // if current byte is a DLE
stripDLE = TRUE; // flag that byte was a DLE
else
stripDLE = FALSE;
// copy current byte
*pDestData++ = *pSourceData++;
bytesXferred++;
if ((stripDLE)&&(*pSourceData == 0x10))
{
*pSourceData++; // skip the byte and clear the flag
dleCount++;
count--;
stripDLE = FALSE;
}
count--;
}
*numBytes = bytesXferred;
return(dleCount);
}
// ------------------------------ BuildMessagePreamble -------------------------
// PURPOSE: Builds the STN,FN and LEN bytes of the telegram.
// on completion dataPtr pointsto where the data must be packed in (if any)
CHAR * CABMessage::BuildMessagePreamble(BOOL error, WORD errorCode)
{
WORD crc = 0;
WORD dataLength=6;
// swap the station IDs
buffer[2] = stationIDSource;
buffer[3] = stationIDDest;
//
buffer[AB_COMMANDBYTEOFF] |= 0x40; // CMD byte
buffer[5] = (BYTE)errorCode; // STS byte
if (error)
{
buffer[8] = (BYTE)(errorCode>>8); //EXT-STS
dataLength++;
}
// byte 6 & 7 contain the sender's TNS value
byteCount = 0;
totalLen = dataLength + 6;//13; 6+6=12 bytes
return(buffer);
} // BuildMessagePreamble
/*
// ------------------------------ BuildMessageEnd -------------------------------
// PURPOSE: glue a CRC onto the end of the message
// totalLen must be = the full telegram length (+CRC) when this is called.
CHAR * CABMessage::BuildMessageEnd()
{
WORD length;
BYTE *pCrcStart = (BYTE*)buffer;
WORD crc = 0xFFFF;
BYTE *crcPtr;
// Add the CRC bytes
length = totalLen - AB_CRC_LEN; //calc the CRC of all bytes but the 2 CRC bytes
CalcCRC(pCrcStart, length, &crc);
crcPtr = (BYTE*)&buffer[length];
*(WORD *)crcPtr = crc;
return (buffer);
} // BuildMessageEnd
*/
// ------------------------------ GetAddressArea --------------------
// Returns: A supported MEM area index for any MOD address class
// Parameter: A modbus command (e.g. 3 =read holding register)
//
WORD CABMessage::GetAddressArea(WORD classCode // modbus command byte
)
{
/*
switch(classCode)
{
// read commands
case MOD_READ_COILS : return(0); break;
case MOD_READ_DIGITALS : return(1); break;
case MOD_READ_REGISTERS : return(2); break;
case MOD_READ_HOLDING : return(3); break;
case MOD_READ_EXTENDED : return(4); break;
// write commands
case MOD_WRITE_HOLDING : return(3); break;
case MOD_WRITE_SINGLEHOLDING : return(3); break;
case MOD_WRITE_SINGLE_COIL : return(0); break;
case MOD_WRITE_MULTIPLE_COILS : return(0); break;
case MOD_WRITE_EXTENDED : return(4); break;
}
*/
return(3); //Default here for now, Should never get here anyways!
} // GetAddressArea
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -