📄 mod232commsprocessor.cpp
字号:
void CMOD232CommsProcessor::RSDataDebugger(const BYTE * buffer, LONG length, int transmit)
{
CRS232Port::GenDataDebugger(buffer,length,transmit);
/*
CString debuggerString;
BYTE *data;
byte hiNib,loNib;
//convert BIN-ary to ASCII for display
data = new BYTE[(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';
if (transmit)
{
if (length)
pGlobalDialog->OnCharactersSent();
debuggerString.Format("TX:%s\n", data);
}
else
{
if (length)
pGlobalDialog->OnCharactersReceived();
debuggerString.Format("RX:%s\n", data);
}
// Send to debugger list-box
if (length)
pGlobalDialog->AddCommsDebugString(debuggerString);
#ifdef _COMMS_DEBUGGING
OutputDebugString(debuggerString);
#endif
delete (data);*/
} // RSDataDebugger
// ------------------------------- RSStateChanged -----------------------
void CMOD232CommsProcessor::RSStateChanged(DWORD state)
{
EnterCriticalSection(&stateCS);
if (NULL==pGlobalDialog)
return;
pGlobalDialog->m_ServerRSState = state;
LeaveCriticalSection(&stateCS);
} // RSStateChanged
// ------------------------------ RSDataMessage ------------------------------
void CMOD232CommsProcessor::RSDataMessage(LPCTSTR msg)
{
EnterCriticalSection(&stateCS);
OutputDebugString("##");
if (NULL!=pGlobalDialog)
pGlobalDialog->AddCommsDebugString(msg);
LeaveCriticalSection(&stateCS);
}
// ------------------------------- RSModemStatus ---------------------------
void CMOD232CommsProcessor::RSModemStatus(DWORD status)
{
EnterCriticalSection(&stateCS);
if (NULL!=pGlobalDialog)
pGlobalDialog->OnModemStatusUpdate(status);
LeaveCriticalSection(&stateCS);
}
// ------------------------------ OnProcessData --------------------------------
BOOL CMOD232CommsProcessor::OnProcessData(const CHAR *pBuffer, DWORD numBytes, BOOL *discardData)
{
// build noise telegram
if (numBytes)
{ //append recieved bytes to the noise telegram
if (m_noiseLength + numBytes >= sizeof(m_noiseBuffer))
{
RSDataMessage("OVERFLOW:Restarting interpretation.");
m_noiseLength = 0;
//SetEngineState(ENG_STATE_IDLE);
return(TRUE);
}
memcpy(&m_noiseBuffer[m_noiseLength], pBuffer, numBytes);
m_noiseLength += numBytes;
*discardData = TRUE;
}
if (m_noiseLength < MODBUS_NORMAL_LEN)
return(FALSE);
CMODMessage::SetEthernetFrames(FALSE);
CMODMessage msg((char*)m_noiseBuffer, m_noiseLength);
if (msg.CRCOK())
{
BOOL ret;
// build a response etc
ret = ProcessData((char*)m_noiseBuffer, msg.overalLen + 2); //+2 for the CRC
m_noiseLength = 0;
return(ret);
}
else
{
// try strip away leading byte "noise"?
// comment out the following 2 lines, from spaccabbomm [beta@mmedia.it]
/*
m_noiseLength--;
memmove(m_noiseBuffer, &m_noiseBuffer[1], m_noiseLength);
*/
return(TRUE);
}
*discardData = FALSE;
return(FALSE);
}
// --------------------------------- TestMessage ------------------------
//
BOOL CMOD232CommsProcessor::TestMessage(CMODMessage &modMsg,
WORD &startRegister,
WORD &endRegister,
WORD &MBUSerrorCode,
WORD &requestMemArea,
WORD &numBytesInReq
)
{
BOOL MBUSError = FALSE;
if (!modMsg.CRCOK())
{
// bail
}
//Get memory area which to update or retrieve from
requestMemArea = modMsg.GetAddressArea(modMsg.functionCode);
if (requestMemArea >= MAX_MOD_MEMTYPES)
{
// TO DO!
// handle the error
Beep(2000,200);
requestMemArea = 3; // for now just default to "Holding" for now!
}
// validate the request is a valid command code
startRegister = modMsg.address;
//endRegister = startRegister + modMsg.byteCount;
endRegister = startRegister + modMsg.byteCount/2; // CDB rev 7.0
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.
if ((modMsg.functionCode == MOD_READ_COILS)|| // 01
(modMsg.functionCode == MOD_READ_DIGITALS)|| // 02
(modMsg.functionCode == MOD_WRITE_MULTIPLE_COILS)) // 0F
numBytesInReq = modMsg.byteCount/8; // # bits
else
numBytesInReq = modMsg.byteCount*2; // # registers
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
if ((m_MOSCADchecks)&& // Is a (Analog/holding/extended register)
((requestMemArea == 2)||(requestMemArea == 3)||(requestMemArea == 4))
)
{
WORD startTable,endTable; // table #
WORD startCol,endCol; // col #
endTable = MOSCADTABLENUMBER(endRegister); // MOSCAD specify register # on the wire for the formula
endCol = MOSCADCOLNUMBER(endRegister);
startTable = MOSCADTABLENUMBER(startRegister);
startCol = MOSCADCOLNUMBER(startRegister);
// test that this request does not bridge 2 columns.
// , else we cannot job/request them together.
if ((endTable != startTable) ||
(endCol != startCol))
{
MBUSError = TRUE;
MBUSerrorCode = MOD_EXCEPTION_ILLEGALADDR; // 02
}
}
// if we want to disable all writes
if ((m_disableWrites) &&
((modMsg.functionCode == MOD_WRITE_SINGLE_COIL) ||
(modMsg.functionCode == MOD_WRITE_SINGLEHOLDING) ||
(modMsg.functionCode == MOD_WRITE_MULTIPLE_COILS) ||
(modMsg.functionCode == MOD_WRITE_HOLDING) ||
(modMsg.functionCode == MOD_WRITE_EXTENDED)
)
)
{
CString deb;
MBUSError = TRUE;
MBUSerrorCode = MOD_EXCEPTION_ILLEGALFUNC; // 02
deb.Format("Writting to registers or I/O is disabled!\n");
OutputDebugString(deb);
RSDataMessage(deb);
}
// do a address+length range check too
if (!MBUSError)
if (PLCMemory[requestMemArea].GetSize() < endRegister)
{
MBUSError = TRUE;
MBUSerrorCode = (PLCMemory[requestMemArea].GetSize() < startRegister ?
MOD_EXCEPTION_ILLEGALADDR:MOD_EXCEPTION_ILLEGALVALUE); // 02
}
if (MBUSError)
{
CString msg;
msg.Format("Modbus message in error x%02X\n", MBUSerrorCode);
OutputDebugString(msg);
RSDataMessage(msg);
}
return(MBUSError);
}
// --------------------------------- ProcessData -----------------------------
// Interpret MODBUS request pBuffer, and respond to it.
//
BOOL CMOD232CommsProcessor::ProcessData(const CHAR *pBuffer, DWORD numBytes)
{
BYTE telegramBuffer[MAX_RX_MESSAGELENGTH+MODBUS_FRAME_LENGTH_MAX];
CHAR debugStr[160];
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;
WORD seperationOffset; // offset added to each address, due to stations having seperate reg.s
BOOL MBUSError = TRUE;
WORD numBytesInReq;
WORD numRegs;
CString deb;
m_debuggerStep = 100;
// inc counter
pGlobalDialog->PacketsReceivedInc();
// simulate the I/O and network delays of a real PLC
Sleep(m_responseDelay);
//
// Parse the telegram
//
// 1. break up the telegram
memcpy(telegramBuffer, pBuffer, numBytes);
CMODMessage::SetEthernetFrames(FALSE);
CMODMessage modMsg((CHAR*)telegramBuffer, numBytes);
ActivateStationLED(modMsg.stationID);
if (!StationIsEnabled(modMsg.stationID))
return(TRUE);
// 2. parse it, by testing it first
CMODMessage responseModMsg(modMsg); //Call copy constructor
MBUSError = TestMessage(modMsg,
startRegister,
endRegister,
MBUSerrorCode,
requestMemArea,
numBytesInReq
);
if (pGlobalDialog->m_seperateRegisters)
{
seperationOffset = (WORD)(pGlobalDialog->m_numSeperate * modMsg.stationID);
if ((PLCMemory[requestMemArea].GetSize() < seperationOffset+endRegister) ||
(endRegister > pGlobalDialog->m_numSeperate))
{
MBUSError = TRUE;
MBUSerrorCode = (PLCMemory[requestMemArea].GetSize() < seperationOffset + startRegister ?
MOD_EXCEPTION_ILLEGALADDR:MOD_EXCEPTION_ILLEGALVALUE); // 02
}
}
else
seperationOffset = 0;
// 1st 3 bytes + any others up to data get
// added in at this time
responseModMsg.BuildMessagePreamble(MBUSError,
MBUSerrorCode);
// A read must now pack into dataPtr onwards! and calc len etc!
// writes must update our mem areas accordingly.
if (!MBUSError)
{
// 4. fill in the data portion of telegram
switch (modMsg.functionCode)
{
case MOD_READ_COILS : // 01 READ
case MOD_READ_DIGITALS : // 02 READ
pDataPortion = responseModMsg.dataPtr; //Get offset to fill in data
if (MAX_MOD_MEMWORDS >= modMsg.address + modMsg.byteCount)
{
WORD memValueTemp;
WORD bitOffset;
deb.Format("Read In/output from %d for %d bits.\n", modMsg.address, modMsg.byteCount);
OutputDebugString(deb);
RSDataMessage(deb);
// pack SIM memory: one WORD of sim memory for every BIT in the data.
// Ie the sim uses one word for each I/O bit in modbus.
numBytesInReq = modMsg.byteCount/8;
if (modMsg.byteCount%8) // if we overflow the byte
numBytesInReq++;
for (i=0; i <numBytesInReq;i++)
{
// grab the memory now
memValueTemp = 0;
for (bitOffset=0;bitOffset<8;bitOffset++)
{
if ((i*8)+bitOffset < modMsg.byteCount)
if (PLCMemory[requestMemArea][(seperationOffset + modMsg.address)+(i*8)+bitOffset])
memValueTemp += (0x01<<bitOffset);
// else bit is off
}
*(BYTE*)pDataPortion = (BYTE)memValueTemp;
pDataPortion +=1;
}
}
else
{
// pack the exception code into the message
ASSERT(0); // this is supposed to be caught in TestMessage()
responseModMsg.buffer[1] |= 0x80;
responseModMsg.buffer[2] = 0x02; // exception code here (could also use 0x03)
}
break;
case MOD_READ_REGISTERS :
case MOD_READ_HOLDING :
case MOD_READ_EXTENDED :
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -