📄 modethcommsprocessor.cpp
字号:
// CMODEthCommsProcessor.cpp: implementation of the Ethernet CMODEthCommsProcessor class.
//
// Ethernet:
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define MAX_MOD_MESSAGELENGTH 2048
// --------------------------------- PackASCIIField ------------------------------
void PackASCIIField(CHAR **pBuffer, WORD value, WORD length)
{
CHAR tempStr[80];
CHAR formatStr[80];
// build a format string
sprintf(formatStr, "%%0%dX", length);
// plonk it in
sprintf(tempStr, formatStr, value);
strncpy(*pBuffer, tempStr, length);
// increment pointer
*pBuffer+=length;
**pBuffer = '\0'; // add a null
}
// ------------------------- GetBCC ---------------------------------
// PURPOSE: Calculates a messages BCC value and returns it
// NOTE:
// The message must be "[NNNNNNNN"
// The bcc may be "cccc" or come from a valid message from the PLC.
//
LONG GetBCC(CHAR * bccString, DWORD msgLen)
{
LONG accumulator = 0;
return (accumulator);
} // GetBCC
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
// constructor to create listen socket
CMODEthCommsProcessor::CMODEthCommsProcessor(int responseDelay,
BOOL MOSCADchecks,
BOOL modifyThenRespond,
BOOL disableWrites,
LONG PDUSize,
WORD portNum) : CDDKSrvSocket(portNum)
{
CString description;
InitializeCriticalSection(&stateCS);
description.Format("Starting comms emulation : %s", "MODBUS TCP/IP [host]");
SockDataMessage(description);
m_responseDelay = 0;
m_linger = FALSE;
m_responseDelay = responseDelay;
SetPDUSize(PDUSize);
SetEmulationParameters(MOSCADchecks, modifyThenRespond, disableWrites);
m_pWorkerThread->ResumeThread(); //start thread off here
}
// constructor to re-use the listen socket
CMODEthCommsProcessor::CMODEthCommsProcessor(int responseDelay,
BOOL MOSCADchecks,
BOOL modifyThenRespond,
BOOL disableWrites,
LONG PDUSize,
SOCKET * pServerSocket) : CDDKSrvSocket(0, 0, pServerSocket)
{
InitializeCriticalSection(&stateCS);
m_responseDelay = 0;
m_linger = FALSE;
m_responseDelay = responseDelay;
SetPDUSize(PDUSize);
SetEmulationParameters(MOSCADchecks, modifyThenRespond, disableWrites);
m_pWorkerThread->ResumeThread(); //start thread off here
}
CMODEthCommsProcessor::~CMODEthCommsProcessor()
{
}
// ------------------------------- SockDataMessage ------------------------------
void CMODEthCommsProcessor::SockDataMessage(LPCTSTR msg)
{
EnterCriticalSection(&stateCS);
OutputDebugString("##");
if (NULL!=pGlobalDialog)
pGlobalDialog->AddCommsDebugString(msg);
LeaveCriticalSection(&stateCS);
}
// ------------------------------ SockDataDebugger ------------------------------
void CMODEthCommsProcessor::SockDataDebugger(const CHAR * buffer, LONG length, BOOL transmit)
{
CRS232Port::GenDataDebugger((BYTE*)buffer, length, transmit);
/*
CString debuggerString;
char *data;
byte hiNib,loNib;
data = new char[(length*2)+1];
for (int i = 0; i < length; i++)
{
hiNib = ( *(buffer+i) >>4) & 0x0f;
loNib = ( *(buffer+i) ) & 0x0f;
data[(i*2)] = ( (hiNib < 0x0A) ? ('0' + hiNib) : ('A' + hiNib-10) );
data[(i*2)+1] = ( (loNib < 0x0A) ? ('0' + loNib) : ('A' + loNib-10) );
}
data[(length*2)] = '\0';
// call the base class
//CDDKSocket::SockDataDebugger(buffer, length, transmit);
if (transmit)
{
if (length)
pGlobalDialog->OnCharactersSent();
debuggerString.Format("TX:%s\n", data);
}
else
{
if (length)
pGlobalDialog->OnCharactersReceived();
debuggerString.Format("RX:%s\n", data);
}
OutputDebugString(debuggerString);
// Send to debugger list-box
if (length)
pGlobalDialog->AddCommsDebugString(debuggerString);
delete (data);*/
} // SockDataDebugger
// ------------------------------- SockStateChanged -----------------------
void CMODEthCommsProcessor::SockStateChanged(DWORD state)
{
EnterCriticalSection(&stateCS);
if (NULL != pGlobalDialog)
pGlobalDialog->m_ServerSocketState = state;
LeaveCriticalSection(&stateCS);
} // SockStateChanged
// ------------------------------- ActivateStationLED ---------------------------
void CMODEthCommsProcessor::ActivateStationLED(LONG stationID)
{
if (stationID>0 && stationID<STATIONTICKBOXESMAX)
{
//start the counter for this station at the beginning
if (NULL != pGlobalDialog)
pGlobalDialog->m_microTicksCountDown[stationID] = pGlobalDialog->GetAnimationOnPeriod();
// it will count down untill it extinguishes
}
} // ActivateStation
// ------------------------------- StationIsEnabled ---------------------------
// Return TRUE if station is enabled
BOOL CMODEthCommsProcessor::StationIsEnabled(LONG stationID)
{
if (!pGlobalDialog)
return(FALSE);
if (stationID>0 && stationID<STATIONTICKBOXESMAX)
{
return (pGlobalDialog->StationEnabled(stationID));
}
return TRUE;
} // StationIsEnabled
// --------------------------------- ProcessData -----------------------------
BOOL CMODEthCommsProcessor::ProcessData(SOCKET openSocket, CHAR *pBuffer, DWORD numBytes)
{
CHAR telegramBuffer[MAX_MOD_MESSAGELENGTH];
CHAR responseBuffer[MAX_MOD_MESSAGELENGTH];
CHAR debugStr[MAX_MOD_MESSAGELENGTH];
WORD responseLen;
BYTE *pDataPortion;
int i=0;
//WORD guardword1=1;
WORD requestMemArea; // telegram read/write are being referenced=0..MAX_MOD_MEMTYPES
//WORD guardword2=2;
WORD startRegister, endRegister, MBUSerrorCode=0;
BOOL MBUSError = TRUE;
WORD numBytesInReq;
WORD numRegs;
CString deb;
m_debuggerStep = 100;
// inc counter
pGlobalDialog->PacketsReceivedInc();
responseBuffer[0] = '\0';
// copy the Rx'd telegram neatly
memcpy(telegramBuffer, pBuffer, numBytes);
telegramBuffer[numBytes] = '\0';
// simulate the I/O and network delays
Sleep(m_responseDelay);
if (pGlobalDialog->m_Unloading)
return(TRUE); // stop processing during shutdown of the socket array to allow easy closing.
// parse the telegram
// 1. break up the telegram
CMODMessage::SetEthernetFrames();
CMODMessage modMsg(telegramBuffer, numBytes);
//check the station #
ActivateStationLED(modMsg.stationID);
if (!StationIsEnabled(modMsg.stationID))
{
CString msg;
// station off-line
msg.Format("Station ID %d off-line, no response sent\n", telegramBuffer[6]);
SockDataMessage(msg);
return(TRUE);
}
// 2. parse
//Get memory area which to update or retrieve from
requestMemArea = modMsg.GetAddressArea(modMsg.functionCode);//.type);
if (requestMemArea >= MAX_MOD_MEMTYPES)
{
// TO DO!
// handle the error
Beep(2000,200);
requestMemArea = 3; // for now just default to "Holding" for now!
}
//
// Validate that the request is a valid command code
//
startRegister = modMsg.address;
//endRegister = startRegister + modMsg.byteCount/2;
if (MOD_WRITE_SINGLE_COIL == modMsg.functionCode)
endRegister = startRegister;
else
endRegister = startRegister + modMsg.byteCount;
if ((modMsg.functionCode == MOD_READ_COILS)|| // 01
(modMsg.functionCode == MOD_READ_DIGITALS)|| // 02
(modMsg.functionCode == MOD_READ_REGISTERS)|| // 04
(modMsg.functionCode == MOD_READ_HOLDING)|| // 03
(modMsg.functionCode == MOD_READ_EXTENDED)|| // 14
(modMsg.functionCode == MOD_WRITE_SINGLE_COIL)|| // 05
(modMsg.functionCode == MOD_WRITE_MULTIPLE_COILS)|| // 0F
(modMsg.functionCode == MOD_WRITE_HOLDING)|| // 10
(modMsg.functionCode == MOD_WRITE_SINGLEHOLDING)|| // 06 (testing)
(modMsg.functionCode == MOD_WRITE_EXTENDED) // 15
)
{
// Check the request length against our PDU size.
switch (modMsg.functionCode)
{
case MOD_READ_COILS: // 01
case MOD_READ_DIGITALS: // 02
numBytesInReq = modMsg.byteCount/8; // # bits
break;
case MOD_WRITE_MULTIPLE_COILS: // 0F
numBytesInReq = (WORD)ceil(modMsg.byteCount/8); // # bits
break;
case MOD_WRITE_SINGLE_COIL:
numBytesInReq = 1;
break;
default:
numBytesInReq = modMsg.byteCount*2; // # registers
break;
}
if (numBytesInReq > m_PDUSize)
{
MBUSError = TRUE;
MBUSerrorCode = MOD_EXCEPTION_ILLEGALVALUE; // too long data field
}
else
MBUSError = FALSE;
}
else
{
MBUSError = TRUE;
MBUSerrorCode = MOD_EXCEPTION_ILLEGALFUNC; // 01
}
if (modMsg.m_packError)
{
// request message has a corrupted field somewhere
MBUSError = TRUE;
MBUSerrorCode = MOD_EXCEPTION_ILLEGALVALUE; // too long data field
}
// 3. build response
CMODMessage responseModMsg(modMsg); //Call copy constructor
//
// Do some more message validation tests etc.
//
if (!MBUSError)
{
if ((m_MOSCADchecks)&& // Is a (Analog/holding/extended register)
((requestMemArea == 2)||(requestMemArea == 3)||(requestMemArea == 4))
)
{
WORD startTable,endTable; // table #
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -