📄 modethcommsprocessor.cpp
字号:
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 (!MBUSError)
{
// 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);
SockDataMessage(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);
SockDataMessage(msg);
}
//
// Request message seems error free, process it.
//
// 1st 3 bytes + any others up to data get
// added in at this time
responseModMsg.BuildMessagePreamble(MBUSError,
MBUSerrorCode);
// If a write is done then the copy constructor will have done all required for ack
// else a read must now pack into dataPtr onwards! and calc len etc!
// 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;
//#ifdef _COMMS_DEBUGGING
deb.Format("Read In/output from %d for %d bits.\n", modMsg.address, modMsg.byteCount);
OutputDebugString(deb);
SockDataMessage(deb);
//#endif
// 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][(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
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 :
pDataPortion = responseModMsg.dataPtr; //Get offset to fill in data
if (MAX_MOD_MEMWORDS >= modMsg.address + modMsg.byteCount)
{
WORD memValueTemp;
//#ifdef _COMMS_DEBUGGING
deb.Format("Read Register from %d for %d .\n", modMsg.address, modMsg.byteCount);
OutputDebugString(deb);
SockDataMessage(deb);
//#endif
for (i=0; i <modMsg.byteCount;i++)
{
// grab the memory now
memValueTemp = PLCMemory[requestMemArea][(modMsg.address)+i];
*(WORD*)pDataPortion = SwapBytes( memValueTemp );
pDataPortion += 2;
}
}
else
{
// pack the exception code into the message
responseModMsg.buffer[1] |= 0x80;
responseModMsg.buffer[2] = 0x02; // exception code here (could also use 0x03)
deb.Format("Read register past %d error x%02X!\n", MAX_MOD_MEMWORDS, (BYTE)responseModMsg.buffer[2]);
OutputDebugString(deb);
SockDataMessage(deb);
}
break;
default :
//Writes acks are all built in copy constructor
//But the update is done here!
if (MAX_MOD_MEMWORDS >= modMsg.address + modMsg.byteCount)
{
// lock memory for writting
CMemWriteLock lk(PLCMemory.GetMutex());
pDataPortion = responseModMsg.dataPtr; //Get offset to fill in data
if (!lk.IsLocked())
//...Update
switch (modMsg.functionCode)
{
case MOD_WRITE_SINGLE_COIL :
{
CString deb;
deb.Format("Write single output %d.\n", modMsg.address);
OutputDebugString(deb);
SockDataMessage(deb);
}
//data gets copied in now
if (m_modifyThenRespond)
PLCMemory.SetAt(requestMemArea, modMsg.address, (*(WORD*)modMsg.dataPtr?1:0));
pDataPortion = responseModMsg.dataPtr; //Get offset to fill in data
*pDataPortion++ = (PLCMemory[requestMemArea][(modMsg.address)+i] ? 0xFF : 0x00);
*pDataPortion++ = 0x00;
if (!m_modifyThenRespond)
PLCMemory.SetAt(requestMemArea, modMsg.address, (*(WORD*)modMsg.dataPtr?1:0));
numRegs = 1; // repaint 1 item
break;
case MOD_WRITE_MULTIPLE_COILS :
// unpack into the SIM memory on WORD of sim memory for every BIT in the data
//WORD numBytes;
numBytesInReq = modMsg.count/8;
if (modMsg.count%8) // if we overflow a byte
numBytesInReq++;
{
CString deb;
deb.Format("Write multiple outputs from %d for %d bits.\n", modMsg.address, modMsg.count);
OutputDebugString(deb);
SockDataMessage(deb);
}
numRegs = numBytesInReq; // repaint X bits
for (i=0;i<numBytesInReq;i++)
{
WORD bitOffset;
for (bitOffset=0;bitOffset<8;bitOffset++)
{
if ((i*8)+bitOffset < modMsg.count)
{
if (*(BYTE*)modMsg.dataPtr & (0x01<<bitOffset))
PLCMemory.SetAt(requestMemArea, modMsg.address+(i*8)+bitOffset, 1);
else
PLCMemory.SetAt(requestMemArea, modMsg.address+(i*8)+bitOffset, 0);
}
}
modMsg.dataPtr++;
}
break;
case MOD_WRITE_HOLDING : //WRITE multiple holdings
case MOD_WRITE_EXTENDED:
//PLCMemory[requestMemArea][modMsg.address] = SwapBytes(*(WORD*)modMsg.dataPtr);
//break;
numRegs = modMsg.byteCount/2;
{
CString deb;
deb.Format("Write multiple registers from %d for %d registers.\n", modMsg.address, numRegs);
OutputDebugString(deb);
SockDataMessage(deb);
}
for (i=0;i<numRegs;i++)
{
PLCMemory.SetAt(requestMemArea, modMsg.address + i, SwapBytes(*(WORD*)modMsg.dataPtr));
modMsg.dataPtr +=2; // inc pointer by 2 bytes
}
break;
case MOD_WRITE_SINGLEHOLDING : //WRITE single holding reg.
{
CString deb;
deb.Format("Write single register %d.\n", modMsg.address);
OutputDebugString(deb);
SockDataMessage(deb);
}
numRegs = 1; //repaint 1 register
PLCMemory.SetAt(requestMemArea, modMsg.address + i, SwapBytes(*(WORD*)modMsg.dataPtr));
modMsg.dataPtr +=2; // inc pointer by 2 bytes
break;
}
}
// we can only call on the GUI thread once we have un-locked
if (pGlobalDialog)
{
int cols = pGlobalDialog->GetListDisplayedWidth();
pGlobalDialog->RedrawListItems(modMsg.GetAddressArea(modMsg.functionCode),
modMsg.address/(cols),
(modMsg.address+(numRegs-1))/(cols)
); // repaint only the needed rows
}
break;
} //end switch
}
else
{ // error occurred
pDataPortion = responseModMsg.dataPtr; // Get offset to fill in data
}
// THERE IS no CRC, so do not call BuildMessageEnd
responseModMsg.totalLen = (WORD)((LONG)pDataPortion-(LONG)responseModMsg.buffer);
// insert the frame info
//responseModMsg
memmove(&responseModMsg.buffer[ETH_PREAMBLE_LENGTH], responseModMsg.buffer, responseModMsg.totalLen);
responseLen = ETH_PREAMBLE_LENGTH + responseModMsg.totalLen; //SwapBytes(*(WORD*)(responseModMsg.preambleLenPtr)) + 6; //hdr;
memset(responseModMsg.buffer, 0 , ETH_PREAMBLE_LENGTH);
WORD tn = responseModMsg.GetEthernetTransNum();
*((WORD*)&responseModMsg.buffer[0]) = tn;
*((WORD*)&responseModMsg.buffer[4]) = SwapBytes(responseModMsg.totalLen);
// 6. send it back
m_debuggerStep = 102;
sprintf(debugStr, "Send %d bytes\n", responseLen);
OutputDebugString(debugStr);
//Send(openSocket, responseLen, responseBuffer, debugStr);
SockStateChanged(SOCKETCURRENTLY_WRITTING);
Send(openSocket, responseLen, responseModMsg.buffer, debugStr);
m_debuggerStep = 103;
// inc counter
pGlobalDialog->PacketsSentInc();
return (TRUE);
}
// ----------------------------- LoadRegisters -----------------------------
// load binary dump of the register values from file.
BOOL CMODEthCommsProcessor::LoadRegisters()
{
BOOL ret = CMOD232CommsProcessor::LoadRegistersIMP();
if (ret)
SockDataMessage("Register values loaded OK\n");
return (ret);
} // LoadRegisters
// ----------------------------- SaveRegisters -----------------------------
// Save binary dump of the register values from file.
BOOL CMODEthCommsProcessor::SaveRegisters()
{
BOOL ret = CMOD232CommsProcessor::SaveRegistersIMP();
if (ret)
SockDataMessage("Register values Saved OK\n");
return (ret);
} // SaveRegisters
// -------------------------- SetEmulationParameters ------------------------
void CMODEthCommsProcessor::SetEmulationParameters(BOOL moscadChecks,
BOOL modifyThenRespond,
BOOL disableWrites)
{
m_MOSCADchecks = moscadChecks;
m_modifyThenRespond = modifyThenRespond;
m_disableWrites = disableWrites;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -