Merge pull request #3 from kej715/master
Expand implementation of FEI protocol and make it interoperable with DtCyber, the CDC mainframe simulator
This commit is contained in:
commit
bca82a2542
@ -7,218 +7,335 @@
|
||||
/////////////////////////////////////////////////////////
|
||||
// IopConcentrator_c
|
||||
/////////////////////////////////////////////////////////
|
||||
void IopConcentrator_c::MasterClear(bool aValue) {
|
||||
if (mState != State_InMasterClear && aValue) {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Going in to master clear" << std::endl;
|
||||
mState = State_InMasterClear;
|
||||
void IopConcentrator_c::StartListen() {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Listen on port " << DecPrinter(mPort) << std::endl;
|
||||
try {
|
||||
mListenSocket = std::make_shared<boost::asio::ip::tcp::acceptor>(mIoService, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), mPort), true);
|
||||
mConnectionSocket = std::make_shared<boost::asio::ip::tcp::socket>(mIoService);
|
||||
}
|
||||
catch (boost::system::system_error &Ex) {
|
||||
throw Generic_x() << "Failed to create listen socket: " << Ex.code().message();
|
||||
}
|
||||
}
|
||||
|
||||
void IopConcentrator_c::StartAccept() {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Start accept on port " << DecPrinter(mPort) << std::endl;
|
||||
mListenSocket->async_accept(*mConnectionSocket, boost::bind(&IopConcentrator_c::AcceptHandler, this, boost::asio::placeholders::error));
|
||||
mIoService.poll();
|
||||
}
|
||||
|
||||
void IopConcentrator_c::AcceptHandler(const boost::system::error_code& aError) {
|
||||
if (aError) {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Accept failed: " << aError.message() << std::endl;
|
||||
CloseConnSocket();
|
||||
return;
|
||||
}
|
||||
if (mState == State_InMasterClear && !aValue) {
|
||||
// Falling edge on master clear: reset state...
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Comming out of master clear" << std::endl;
|
||||
mState = State_ClearingBuffers;
|
||||
mFromCrayData.clear();
|
||||
mToCrayData.clear();
|
||||
mToCrayIdx = 0;
|
||||
mToCrayLast = true;
|
||||
mToCrayPacketIdx = 0;
|
||||
mLogger << setloglevel(LogLevel_IoActivity)
|
||||
<< "Connection from " << mConnectionSocket->remote_endpoint( ).address( ).to_string( )
|
||||
<< std::endl;
|
||||
try {
|
||||
mConnectionSocket->set_option(boost::asio::socket_base::keep_alive(true));
|
||||
boost::asio::ip::tcp::no_delay option(true);
|
||||
mConnectionSocket->set_option(option);
|
||||
mAccepted = true;
|
||||
ClearBuffers();
|
||||
StartReceive();
|
||||
mIoService.poll();
|
||||
}
|
||||
catch (boost::system::system_error &Ex) {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Failed to start receive: " << Ex.code().message() << std::endl;
|
||||
CloseConnSocket();
|
||||
}
|
||||
}
|
||||
|
||||
bool IopConcentrator_c::HasData() {
|
||||
switch (mState) {
|
||||
case State_InMasterClear: return false;
|
||||
case State_ClearingBuffers: return false;
|
||||
case State_Operational: return mToCrayData.size() > 0 && mToCrayIdx < mToCrayData.size();
|
||||
default: CRAY_ASSERT(false);
|
||||
void IopConcentrator_c::ClearBuffers() {
|
||||
ClearReceiveBuffers();
|
||||
ClearTransmitBuffers();
|
||||
}
|
||||
|
||||
void IopConcentrator_c::ClearReceiveBuffers() {
|
||||
mToCrayData.clear();
|
||||
mToCrayIdx = 0;
|
||||
mReceiveBuf.consume(mReceiveBuf.size());
|
||||
}
|
||||
|
||||
void IopConcentrator_c::ClearTransmitBuffers() {
|
||||
mFromCrayData.clear();
|
||||
mTransmitBufIdx = 0;
|
||||
}
|
||||
|
||||
void IopConcentrator_c::CloseConnSocket() {
|
||||
if (mAccepted) {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Close connection" << std::endl;
|
||||
boost::system::error_code IgnoredError;
|
||||
mConnectionSocket->close(IgnoredError);
|
||||
mAccepted = false;
|
||||
}
|
||||
throw Generic_x("Unreachable code");
|
||||
StartAccept();
|
||||
}
|
||||
|
||||
void IopConcentrator_c::ProcessReceivedBytes() {
|
||||
size_t i;
|
||||
size_t size = mReceiveBuf.size();
|
||||
while (size > 0) {
|
||||
const uint8_t *data = boost::asio::buffer_cast<const uint8_t *>(mReceiveBuf.data());
|
||||
switch (mRcvState) {
|
||||
case State_RcvLcpPduLength: // process 4-byte PDU length value
|
||||
if (size < 4) return;
|
||||
mPduLength = (data[0] << 24)
|
||||
| (data[1] << 16)
|
||||
| (data[2] << 8)
|
||||
| data[3];
|
||||
mReceiveBuf.consume(4);
|
||||
size -= 4;
|
||||
mRcvState = State_RcvLcpPduContent;
|
||||
mLogger << setloglevel(LogLevel_IoTrace) << "Received LCP PDU length " << DecPrinter(mPduLength) << std::endl;
|
||||
break;
|
||||
case State_RcvLcpPduContent: // process LCP PDU content
|
||||
if (size < mPduLength) return;
|
||||
mSubsegmentCount = data[4];
|
||||
mLastRcvdMessageCode = data[6];
|
||||
i = 0;
|
||||
while (mPduLength > 0) {
|
||||
CInt_t word = 0;
|
||||
for (size_t n = 0; n < 8; n++) word = (word << 8) | data[i++];
|
||||
mToCrayData.push_back(word);
|
||||
size -= 8;
|
||||
mPduLength -= 8;
|
||||
}
|
||||
mReceiveBuf.consume(i);
|
||||
mLogger << setloglevel(LogLevel_IoTrace) << "MC: " << OctPrinter(mLastRcvdMessageCode)
|
||||
<< ", NSSG: " << DecPrinter(mSubsegmentCount) << std::endl;
|
||||
mLogger << setloglevel(LogLevel_IoTrace) << DecPrinter(mToCrayData.size())
|
||||
<< " total upline QWords queued" << std::endl;
|
||||
mRcvState = (mSubsegmentCount > 0) ? State_RcvSegPduLength : State_RcvLcpPduLength;
|
||||
break;
|
||||
case State_RcvSegPduLength: // process 4-byte PDU length value
|
||||
if (size < 4) return;
|
||||
mPduLength = (data[0] << 24)
|
||||
| (data[1] << 16)
|
||||
| (data[2] << 8)
|
||||
| data[3];
|
||||
mReceiveBuf.consume(4);
|
||||
size -= 4;
|
||||
mRcvState = State_RcvSegPduContent;
|
||||
mLogger << setloglevel(LogLevel_IoTrace) << "Received Segment PDU length " << DecPrinter(mPduLength) << std::endl;
|
||||
break;
|
||||
case State_RcvSegPduContent: // process segment PDU content
|
||||
if (size < mPduLength) return;
|
||||
if (mLastRcvdMessageCode == McLogon) {
|
||||
mSegmentSize = ((data[6] << 8) | data[7]) * 8;
|
||||
mLogger << setloglevel(LogLevel_IoTrace) << "Subsegment size: "
|
||||
<< DecPrinter(mSegmentSize) << " bytes / "
|
||||
<< DecPrinter(mSegmentSize/8) << " QWords"
|
||||
<< std::endl;
|
||||
}
|
||||
i = 0;
|
||||
while (mPduLength > 0) {
|
||||
CInt_t word = 0;
|
||||
for (size_t n = 0; n < 8; n++) word = (word << 8) | data[i++];
|
||||
mToCrayData.push_back(word);
|
||||
size -= 8;
|
||||
mPduLength -= 8;
|
||||
}
|
||||
mReceiveBuf.consume(i);
|
||||
mLogger << setloglevel(LogLevel_IoTrace) << DecPrinter(mToCrayData.size())
|
||||
<< " total upline QWords queued" << std::endl;
|
||||
mSubsegmentCount -= 1;
|
||||
mRcvState = (mSubsegmentCount > 0) ? State_RcvSegPduLength : State_RcvLcpPduLength;
|
||||
break;
|
||||
default:
|
||||
mParent.GetLogger() << setloglevel(LogLevel_Error) << SideEffectIndent
|
||||
<< "ERROR: Invalid receive state" << std::endl;
|
||||
MasterClear();
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IopConcentrator_c::StartReceive() {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Start receive" << std::endl;
|
||||
boost::asio::async_read(*mConnectionSocket, mReceiveBuf, boost::asio::transfer_at_least(1),
|
||||
boost::bind(&IopConcentrator_c::ReadHandler, this, boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void IopConcentrator_c::ReadHandler(const boost::system::error_code& aError, std::size_t bytesTransferred) {
|
||||
if (aError) {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Read failed: " << aError.message() << std::endl;
|
||||
CloseConnSocket();
|
||||
return;
|
||||
}
|
||||
mLogger << setloglevel(LogLevel_IoTrace) << DecPrinter(bytesTransferred) << " bytes received" << std::endl;
|
||||
StartReceive();
|
||||
}
|
||||
|
||||
void IopConcentrator_c::StartTransmit() {
|
||||
mTransmitBufs[mTransmitBufIdx].consume(mTransmitBufs[mTransmitBufIdx].size());
|
||||
size_t wordCount = mFromCrayData.size();
|
||||
size_t byteCount = wordCount * 8;
|
||||
switch (mXmtState) {
|
||||
case State_XmtLcpPduStart:
|
||||
mTransmitBufs[mTransmitBufIdx].sputc(0);
|
||||
mTransmitBufs[mTransmitBufIdx].sputc(0);
|
||||
mTransmitBufs[mTransmitBufIdx].sputc(0);
|
||||
mTransmitBufs[mTransmitBufIdx].sputc(BytesPerLCP);
|
||||
mXmtState = State_XmtLcpPduContent;
|
||||
// fall through
|
||||
case State_XmtLcpPduContent:
|
||||
for (size_t w = 0; w < wordCount; w++) {
|
||||
CInt_t word = mFromCrayData[w];
|
||||
size_t shiftCount = 56;
|
||||
for (size_t b = 0; b < 8; b++) {
|
||||
mTransmitBufs[mTransmitBufIdx].sputc((char)((word >> shiftCount) & 0xff));
|
||||
shiftCount -= 8;
|
||||
}
|
||||
}
|
||||
mLastXmitMessageCode = (mFromCrayData[0] >> 8) & 0xff;
|
||||
mSubsegmentCount = (mFromCrayData[0] >> 24) & 0xff;
|
||||
mXmtState = (mSubsegmentCount > 0) ? State_XmtSegPduStart : State_XmtLcpPduStart;
|
||||
break;
|
||||
case State_XmtSegPduStart:
|
||||
if (mLastXmitMessageCode == McStart) {
|
||||
mTransmitBufs[mTransmitBufIdx].sputc((char)((byteCount >> 24) & 0xff));
|
||||
mTransmitBufs[mTransmitBufIdx].sputc((char)((byteCount >> 16) & 0xff));
|
||||
mTransmitBufs[mTransmitBufIdx].sputc((char)((byteCount >> 8) & 0xff));
|
||||
mTransmitBufs[mTransmitBufIdx].sputc((char)(byteCount & 0xff));
|
||||
}
|
||||
else {
|
||||
mTransmitBufs[mTransmitBufIdx].sputc((char)((mSegmentSize >> 24) & 0xff));
|
||||
mTransmitBufs[mTransmitBufIdx].sputc((char)((mSegmentSize >> 16) & 0xff));
|
||||
mTransmitBufs[mTransmitBufIdx].sputc((char)((mSegmentSize >> 8) & 0xff));
|
||||
mTransmitBufs[mTransmitBufIdx].sputc((char)(mSegmentSize & 0xff));
|
||||
}
|
||||
mBytesTransmitted = 0;
|
||||
mXmtState = State_XmtSegPduContent;
|
||||
// fall through
|
||||
case State_XmtSegPduContent:
|
||||
for (size_t w = 0; w < wordCount; w++) {
|
||||
CInt_t word = mFromCrayData[w];
|
||||
size_t shiftCount = 56;
|
||||
for (size_t b = 0; b < 8; b++) {
|
||||
mTransmitBufs[mTransmitBufIdx].sputc((char)((word >> shiftCount) & 0xff));
|
||||
shiftCount -= 8;
|
||||
}
|
||||
}
|
||||
mBytesTransmitted += byteCount;
|
||||
if (mBytesTransmitted >= mSegmentSize || mLastXmitMessageCode == McStart) {
|
||||
mSubsegmentCount -= 1;
|
||||
mXmtState = (mSubsegmentCount > 0) ? State_XmtSegPduStart : State_XmtLcpPduStart;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
mParent.GetLogger() << setloglevel(LogLevel_Error) << SideEffectIndent
|
||||
<< "ERROR: Invalid transmit state" << std::endl;
|
||||
MasterClear();
|
||||
return;
|
||||
break;
|
||||
}
|
||||
mFromCrayData.clear();
|
||||
mLogger << setloglevel(LogLevel_IoTrace) << "Start transmitting "
|
||||
<< DecPrinter(wordCount) << " QWords/" << DecPrinter(byteCount) << " bytes to front end." << std::endl;
|
||||
try {
|
||||
boost::asio::async_write(*mConnectionSocket, mTransmitBufs[mTransmitBufIdx],
|
||||
boost::bind(&IopConcentrator_c::WriteHandler, this, boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
mTransmitBufIdx = (mTransmitBufIdx + 1) % MaxTransmitBufs;
|
||||
}
|
||||
catch (boost::system::system_error &Ex) {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Failed to start write: " << Ex.code().message() << std::endl;
|
||||
CloseConnSocket();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void IopConcentrator_c::WriteHandler(const boost::system::error_code& aError, std::size_t bytesTransferred) {
|
||||
if (aError) {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Write failed: " << aError.message() << std::endl;
|
||||
CloseConnSocket();
|
||||
return;
|
||||
}
|
||||
mLogger << setloglevel(LogLevel_IoTrace) << DecPrinter(bytesTransferred) << " bytes transmitted to front end." << std::endl;
|
||||
}
|
||||
|
||||
void IopConcentrator_c::MasterClear() {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Master clear" << std::endl;
|
||||
CloseConnSocket();
|
||||
ClearBuffers();
|
||||
mRcvState = State_RcvLcpPduLength;
|
||||
mPduLength = 0;
|
||||
mXmtState = State_XmtLcpPduStart;
|
||||
mBytesTransmitted = 0;
|
||||
mSegmentSize = 0;
|
||||
}
|
||||
|
||||
CInt_t IopConcentrator_c::GetData() {
|
||||
CInt_t Data = 0;
|
||||
if(mToCrayIdx < mToCrayData.size()) {
|
||||
Data = mToCrayData[mToCrayIdx];
|
||||
++mToCrayIdx;
|
||||
/* if (mToCrayIdx == mToCrayData.size()) {
|
||||
if (!mToCrayLast) {
|
||||
SetupNextTransfer();
|
||||
} else {
|
||||
mToCrayData.clear();
|
||||
mToCrayIdx = 0;
|
||||
mToCrayLast = true;
|
||||
}
|
||||
}*/
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Sending data: " << HexPrinter(Data) << std::endl;
|
||||
if (mToCrayIdx < mToCrayData.size()) {
|
||||
Data = mToCrayData[mToCrayIdx++];
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Receive " << HexPrinter(Data) << std::endl;
|
||||
if (mToCrayIdx >= mToCrayData.size()) {
|
||||
mToCrayData.clear();
|
||||
mToCrayIdx = 0;
|
||||
}
|
||||
} else {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Sending empty data: " << HexPrinter(Data) << std::endl;
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Sending empty data " << HexPrinter(Data) << std::endl;
|
||||
}
|
||||
return Data;
|
||||
}
|
||||
|
||||
void IopConcentrator_c::ProcessFromCrayLcp() {
|
||||
mFromCrayLcp = FrontEndLcp_c(mFromCrayData);
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Processing CRAY message: " << OctPrinter(mFromCrayLcp.GetMessageCode()) << std::endl;
|
||||
switch (mFromCrayLcp.GetMessageCode()) {
|
||||
case FrontEndLcp_c::MessageCode_Restart: {
|
||||
/* FrontEndLcp_c Control;
|
||||
Control.SetSourceId(mFrontEndId);
|
||||
Control.SetDestinationId(mMainframeId);
|
||||
Control.SetNumberOfSubsegments(0);
|
||||
Control.SetMessageNumber(1);
|
||||
Control.SetMessageCode(FrontEndLcp_c::MessageCode_Control);
|
||||
Control.SetDataBitsInSegment(0000);
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Sending reply of: " << DecPrinter(Control.GetData().size()) << " QWORDS" << std::endl;
|
||||
SetToCrayData(Control.GetData(), true);*/
|
||||
/* In reality we only send a logon message once a client is connected, not right after the restart. The logic is this:
|
||||
- Upon power-up, restart initializes the concentrator and opens it up for network connections
|
||||
- Upon connection of a client, logon is sent (this is only accepted on a fully booted system
|
||||
At least this is what the logic *should be*. However if I don't send a logon, I get a timeout. If I send a control message, I get some other error...
|
||||
*/
|
||||
//mMainframeId = mFromCrayLcp.GetSourceId();
|
||||
FrontEndLcp_c Logon;
|
||||
Logon.SetSourceId(mFrontEndId);
|
||||
Logon.SetDestinationId(mMainframeId);
|
||||
Logon.SetNumberOfSubsegments(1);
|
||||
Logon.SetMessageNumber(++mMessageNumber);
|
||||
Logon.SetMessageCode(FrontEndLcp_c::MessageCode_Logon);
|
||||
Logon.SetDataBitsInSegment(0200); // It is 0200 (2x64) in the documentation, thought the message actually supposed to have 6 QWORDS in it...
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Sending reply of: " << DecPrinter(Logon.GetData().size()) << " QWORDS" << std::endl;
|
||||
SetToCrayData(Logon.GetData(), false);
|
||||
}
|
||||
break;
|
||||
case FrontEndLcp_c::MessageCode_MessageError: {
|
||||
std::cout << "Front-end error received: " << OctPrinter(mFromCrayLcp.GetMessageSubcode()) << " for message: " << DecPrinter(mFromCrayLcp.GetMessageNumber()) << std::endl;
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Front-end error received: " << OctPrinter(mFromCrayLcp.GetMessageSubcode()) << " for message: " << DecPrinter(mFromCrayLcp.GetMessageNumber()) << std::endl;
|
||||
if (mFromCrayLcp.GetMessageSubcode() == 0251) {
|
||||
std::cout << "Front-end re-sending logon..." << std::endl;
|
||||
// Resend logon...
|
||||
FrontEndLcp_c Logon;
|
||||
Logon.SetSourceId(mFrontEndId);
|
||||
Logon.SetDestinationId(mMainframeId);
|
||||
Logon.SetNumberOfSubsegments(1);
|
||||
Logon.SetMessageNumber(++mMessageNumber);
|
||||
Logon.SetMessageCode(FrontEndLcp_c::MessageCode_Logon);
|
||||
Logon.SetDataBitsInSegment(0200); // It is 0200 (2x64) in the documentation, thought the message actually supposed to have 6 QWORDS in it...
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Sending reply of: " << DecPrinter(Logon.GetData().size()) << " QWORDS" << std::endl;
|
||||
SetToCrayData(Logon.GetData(), false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: CRAY_ASSERT(false);
|
||||
}
|
||||
size_t IopConcentrator_c::GetDataSize() {
|
||||
return mToCrayData.size() - mToCrayIdx;
|
||||
}
|
||||
|
||||
void IopConcentrator_c::SetupNextTransfer() {
|
||||
switch (mFromCrayLcp.GetMessageCode()) {
|
||||
case FrontEndLcp_c::MessageCode_Restart: {
|
||||
std::vector<CInt_t> Data;
|
||||
Data.resize(6,0);
|
||||
// STYP DBSZ CKSZ MIST MOST MAST MSSG SSGZ
|
||||
Data[0] = 2ULL << 0 | 0ULL << 2 | 0ULL << 8 | 1ULL << 16 | 1ULL << 24 | 2ULL << 32 | 255ULL << 40 | 255ULL << 48;
|
||||
// MRE SLOT ISLT VARS FRCE MTE DSZ
|
||||
Data[1] = 1ULL << 0 | 1ULL << 8 | 1ULL << 9 | 1ULL << 10 | 0ULL << 15 | 15ULL << 16 | 0ULL << 40;
|
||||
// STOP
|
||||
//Data[4] = 0ULL; //TODO: This should be the password, but what is it???
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Sending data segment of : " << DecPrinter(Data.size()) << " QWORDS" << std::endl;
|
||||
SetToCrayData(Data, true);
|
||||
}
|
||||
break;
|
||||
default: CRAY_ASSERT(false);
|
||||
}
|
||||
bool IopConcentrator_c::HasData() {
|
||||
return mToCrayIdx < mToCrayData.size();
|
||||
}
|
||||
|
||||
bool IopConcentrator_c::IsReceptionComplete() {
|
||||
return (mRcvState == State_RcvLcpPduLength || mRcvState == State_RcvSegPduLength) && HasData() == false && mPduLength <= 0;
|
||||
}
|
||||
|
||||
void IopConcentrator_c::Poll() {
|
||||
mIoService.poll();
|
||||
}
|
||||
|
||||
void IopConcentrator_c::SetData(CInt_t aData) {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Receiving data: " << HexPrinter(aData) << std::endl;
|
||||
switch (mState) {
|
||||
case State_ClearingBuffers:
|
||||
if ((aData & 0xffff000000000000ULL) == 0x0000000000000000ULL) {
|
||||
BufferClearComplete();
|
||||
}
|
||||
break;
|
||||
case State_Operational:
|
||||
mFromCrayData.push_back(aData);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Transmit " << HexPrinter(aData) << std::endl;
|
||||
mFromCrayData.push_back(aData);
|
||||
}
|
||||
|
||||
void IopConcentrator_c::ProcessFromCrayData() {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Processing CRAY data of " << DecPrinter(mFromCrayData.size()) << " QWORDs" << std::endl;
|
||||
if (mFromCrayData.size() == FrontEndLcp_c::LcpSize) ProcessFromCrayLcp();
|
||||
mFromCrayData.clear();
|
||||
}
|
||||
|
||||
void IopConcentrator_c::TransferCompleted() {
|
||||
if (!mToCrayLast) {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Setting up next transfer" << std::endl;
|
||||
SetupNextTransfer();
|
||||
} else {
|
||||
/* mLogger << setloglevel(LogLevel_IoActivity) << "Setting up poll reply" << std::endl;
|
||||
|
||||
FrontEndLcp_c PollReply;
|
||||
PollReply.SetSourceId(mFrontEndId);
|
||||
PollReply.SetDestinationId(mMainframeId);
|
||||
PollReply.SetNumberOfSubsegments(0);
|
||||
PollReply.SetMessageNumber(0);
|
||||
PollReply.SetMessageCode(0);
|
||||
PollReply.SetDataBitsInSegment(0);
|
||||
SetToCrayData(PollReply.GetData(), true);*/
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Start transmitting " << DecPrinter(mFromCrayData.size())
|
||||
<< " QWords to front end" << std::endl;
|
||||
if (mAccepted) {
|
||||
StartTransmit();
|
||||
}
|
||||
}
|
||||
|
||||
void IopConcentrator_c::BufferClearComplete() {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "State transition to State_Operational" << std::endl;
|
||||
CRAY_ASSERT(mState == State_ClearingBuffers);
|
||||
mState = State_Operational;
|
||||
mFromCrayData.clear();
|
||||
mToCrayData.clear();
|
||||
mToCrayIdx = 0;
|
||||
mToCrayLast = true;
|
||||
mToCrayPacketIdx = 0;
|
||||
}
|
||||
|
||||
void IopConcentrator_c::LogState(const char *aHeader) const {
|
||||
switch (mState) {
|
||||
case State_InMasterClear: mLogger << setloglevel(LogLevel_IoActivity) << aHeader << " State: State_InMasterClear" << std::endl; break;
|
||||
case State_ClearingBuffers: mLogger << setloglevel(LogLevel_IoActivity) << aHeader << " State: State_ClearingBuffers" << std::endl; break;
|
||||
case State_Operational: mLogger << setloglevel(LogLevel_IoActivity) << aHeader << " State: State_Operational" << std::endl; break;
|
||||
default: CRAY_ASSERT(false);
|
||||
else {
|
||||
mFromCrayData.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void IopConcentrator_c::Tick() {
|
||||
/* if (mState == State_Operational) {
|
||||
++mPollTimer;
|
||||
if (mPollTimer == mPollDelay) {
|
||||
mPollTimer = 0;
|
||||
if (!HasData()) {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Setting up poll reply" << std::endl;
|
||||
|
||||
FrontEndLcp_c PollReply;
|
||||
PollReply.SetSourceId(mFrontEndId);
|
||||
PollReply.SetDestinationId(mMainframeId);
|
||||
PollReply.SetNumberOfSubsegments(0);
|
||||
PollReply.SetMessageNumber(0);
|
||||
PollReply.SetMessageCode(0);
|
||||
PollReply.SetDataBitsInSegment(0);
|
||||
SetToCrayData(PollReply.GetData(), true);
|
||||
} else {
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Not setting up poll reply mToCrayData.size()=" << DecPrinter(_ToCrayData.size()) << " _ToCrayIdx=" << DecPrinter(_ToCrayIdx) << std::endl;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
ProcessReceivedBytes();
|
||||
if (++mPollCnt > 100) {
|
||||
Poll();
|
||||
mPollCnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
boost::asio::io_service IopConcentrator_c::mIoService;
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// IopConcentratorChannel_c
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
IopConcentratorChannel_c::IopConcentratorChannel_c(class IopConcentrator_c &aParent, const Configuration_c &aConfig, size_t aChannelIdx, bool aAllowOut, bool aAllowIn):
|
||||
mParent(aParent),
|
||||
mAllowOut(aAllowOut),
|
||||
mAllowIn(aAllowIn),
|
||||
mAllowOut(aAllowOut),
|
||||
mChannelIdx(aChannelIdx),
|
||||
mChannelActive(false)
|
||||
mParent(aParent)
|
||||
{
|
||||
CRAY_ASSERT(aAllowOut ^ aAllowIn);
|
||||
mTransferDelay = aConfig.get<size_t>("TransferDelay", 10);
|
||||
@ -226,83 +343,81 @@ IopConcentratorChannel_c::IopConcentratorChannel_c(class IopConcentrator_c &aPar
|
||||
}
|
||||
|
||||
IopInt_t IopConcentratorChannel_c::DoIo(IopIoFunction_t aFunction, IopInt_t aData) {
|
||||
mChannelActive = true; // TODO: this is not what should happen: this is set from the other side, when the destination address is written
|
||||
//mParent.LogState("DoIo begin");
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity) << (mAllowIn?"CONCI":"CONCO") << " DoIo with function code: " << OctPrinter(aFunction) << " data: " << HexPrinter(aData) << std::endl;
|
||||
switch (aFunction) {
|
||||
case 000:
|
||||
case 000: // Clear Channel
|
||||
mInActive = false;
|
||||
mOutActive = false;
|
||||
mDone = false;
|
||||
return 0;
|
||||
case 001:
|
||||
case 001: // Enter Local Memory Address, Start Transfer
|
||||
mIoMemoryAddr = aData >> 2; // Clear the lowest two bits
|
||||
if (mAllowIn) {
|
||||
if (mParent.HasData()) {
|
||||
mInActive = true;
|
||||
mOutActive = false;
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity) << "Initiating transfer of " << DecPrinter(mTransferSize) << " QWords" << " from Concentrator to I/O memory address " << HexPrinter(mIoMemoryAddr,4) << std::endl;
|
||||
mDone = false;
|
||||
} else {
|
||||
mInActive = false;
|
||||
mOutActive = false;
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity) << "Data transfer request with no data pending: " << DecPrinter(mTransferSize) << " QWords" << " from Concentrator to I/O memory address " << HexPrinter(mIoMemoryAddr,4) << std::endl;
|
||||
mDone = false;
|
||||
}
|
||||
mInActive = true;
|
||||
mOutActive = false;
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity)
|
||||
<< "Start transferring " << DecPrinter(mTransferSize) << " QWords"
|
||||
<< " with " << DecPrinter(mParent.GetDataSize()) << " available"
|
||||
<< " from front end to I/O memory address " << HexPrinter(mIoMemoryAddr,4)
|
||||
<< std::endl;
|
||||
mDone = false;
|
||||
}
|
||||
if (mAllowOut) {
|
||||
mInActive = false;
|
||||
mOutActive = true;
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity) << "Initiating transfer of " << DecPrinter(mTransferSize) << " QWords" << " from I/O memory address " << HexPrinter(mIoMemoryAddr,4) << " to Concentrator" << std::endl;
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity)
|
||||
<< "Start transferring " << DecPrinter(mTransferSize) << " QWords"
|
||||
<< " from I/O memory address " << HexPrinter(mIoMemoryAddr,4)
|
||||
<< " to front end" << std::endl;
|
||||
mDone = false;
|
||||
}
|
||||
mTransferDelayCounter = mTransferDelay;
|
||||
return 0;
|
||||
case 002:
|
||||
case 002: // Enter Parcel Count
|
||||
mTransferSize = aData >> 2;
|
||||
return 0;
|
||||
case 003:
|
||||
case 003: // Clear Error Flag
|
||||
// Clear parity error bits for CIA and sequence error flags for COA
|
||||
return 0;
|
||||
case 004:
|
||||
// Would set active to false, but that's not supported yet
|
||||
case 004: // (CIA) Clear Ready Waiting Flog | (COA) Set/Clear External Control Signals
|
||||
if (mAllowIn) {
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity) << "CONCI function 4 with value: " << HexPrinter(aData,4) << std::endl;
|
||||
//mChannelActive = false;
|
||||
mReadyWaiting = false;
|
||||
}
|
||||
if (mAllowOut) {
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity) << "CONCO function 4 with value: " << HexPrinter(aData,4) << std::endl;
|
||||
mWriteDisconnect = (aData & (1 << 8)) != 0;
|
||||
mHoldDisconnect = (aData & (1 << 9)) != 0;
|
||||
/* if ((aData & (1 << 4)) != 0) {
|
||||
// This bit seems to be set once the buffer clear is complete
|
||||
mParent.BufferClearComplete();
|
||||
}*/
|
||||
if ((aData & (1 << 8)) != 0) {
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity) << "would be sending disconnect to concentrator!" << std::endl;
|
||||
if (mWriteDisconnect) {
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity) << "would be sending disconnect to concentrator" << std::endl;
|
||||
}
|
||||
mHoldDisconnect = ((aData & (1 << 9)) != 0);
|
||||
mParent.MasterClear((aData & (1 << 14)) != 0);
|
||||
if ((aData & (1 << 14)) != 0) mParent.MasterClear();
|
||||
}
|
||||
return 0;
|
||||
case 006:
|
||||
case 006: // Clear Interrupt Enable Flag
|
||||
mInterruptEnabled = false;
|
||||
return 0;
|
||||
case 007:
|
||||
case 007: // Set Interrupt Enable Flag
|
||||
mInterruptEnabled = true;
|
||||
return 0;
|
||||
case 010:
|
||||
case 010: // Read Local Memory Address
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity)
|
||||
<< (mAllowIn ? "CONCI" : "CONCO")
|
||||
<< " function 010 returning: " << HexPrinter(mIoMemoryAddr << 2, 4)
|
||||
<< std::endl;
|
||||
return mIoMemoryAddr << 2;
|
||||
case 011:
|
||||
if (mAllowIn) aData = mParent.HasData() ? (1 << 15) : 0; // Would return parity error bits in the low-order four bits - for now we won't signal ready waiting as it is an endless loop during initialization
|
||||
case 011: // Read Ready Waiting / Error Flags
|
||||
if (mAllowIn) aData = mReadyWaiting ? (1 << 15) : 0; // Would return parity error bits in the low-order four bits
|
||||
if (mAllowOut) aData = 0; // Would return sequence error and 4-bit channels none of which is supported
|
||||
if (mAllowIn) {
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity) << "CONCI function 011 returning: " << HexPrinter(aData,4) << std::endl;
|
||||
}
|
||||
if (mAllowOut) {
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity) << "CONCO function 011 returning: " << HexPrinter(aData,4) << std::endl;
|
||||
}
|
||||
return aData;
|
||||
CRAY_ASSERT(false);
|
||||
return 0;
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity)
|
||||
<< (mAllowIn ? "CONCI" : "CONCO")
|
||||
<< " function 011 returning: " << HexPrinter(aData,4)
|
||||
<< std::endl;
|
||||
return aData;
|
||||
default:
|
||||
mParent.GetLogger() << setloglevel(LogLevel_Error) << SideEffectIndent << "ERROR: Invalid function code for channel" << std::endl;
|
||||
return 0;
|
||||
@ -315,25 +430,17 @@ IopBit_t IopConcentratorChannel_c::GetInterrupt() {
|
||||
}
|
||||
|
||||
void IopConcentratorChannel_c::Tick() {
|
||||
/* if ((mInActive || mOutActive) && mChannelActive) {
|
||||
if (mTransferDelayCounter > 0) {
|
||||
--mTransferDelayCounter;
|
||||
return;
|
||||
}
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity) << "Transfer resumed" << std::endl;
|
||||
}*/
|
||||
if (mAllowIn) mParent.Tick(); // Forward ticks to concentrator, but only once per tick (i.e. from the input channel only)
|
||||
if (mAllowIn) mParent.Tick(); // Forward ticks to concentrator from the input channel only
|
||||
|
||||
while ((mInActive || mOutActive) && mChannelActive) {
|
||||
while (mInActive || mOutActive) {
|
||||
CRAY_ASSERT(!mDone);
|
||||
if (mOutActive) {
|
||||
CInt_t Data = SwapBytesInWords(mParent.GetParent().IoMemAccessByType<uint64_t>(mIoMemoryAddr));
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity) << "Sending data " << HexPrinter(Data) << " to concentrator!" << std::endl;
|
||||
mParent.SetData(SwapBytes(Data));
|
||||
}
|
||||
if (mInActive) {
|
||||
if (mParent.HasData() == false) return;
|
||||
CInt_t Data = SwapBytes(mParent.GetData());
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity) << "Receiving data " << HexPrinter(Data) << " from concentrator!" << std::endl;
|
||||
mParent.GetParent().IoMemAccessByType<uint64_t>(mIoMemoryAddr) = SwapBytesInWords(Data);
|
||||
}
|
||||
if (mIoMemoryAddr != 0x3fff) {
|
||||
@ -344,16 +451,15 @@ void IopConcentratorChannel_c::Tick() {
|
||||
// We're exploiting the fact that this can underflow.
|
||||
mTransferSize = (mTransferSize - 1) & 0x3fff;
|
||||
|
||||
if (mTransferSize == 0 || (mInActive && !mParent.HasData())) {
|
||||
if (mTransferSize == 0 || (mAllowIn && mParent.IsReceptionComplete())) {
|
||||
if (!mHoldDisconnect && mOutActive) {
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity) << "would be sending disconnect to concentrator!" << std::endl;
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity) << "would be sending disconnect to concentrator" << std::endl;
|
||||
}
|
||||
mInActive = false;
|
||||
mOutActive = false;
|
||||
mDone = true;
|
||||
mParent.GetLogger() << setloglevel(LogLevel_IoActivity) << "Transfer completed" << std::endl;
|
||||
if (mAllowOut) mParent.ProcessFromCrayData();
|
||||
if (mAllowIn) mParent.TransferCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,7 +24,17 @@ public:
|
||||
virtual IopBit_t GetInterrupt() override;
|
||||
virtual size_t GetChannelIdx() const override { return mChannelIdx; }
|
||||
|
||||
virtual void MasterClear() override { mDone = false; mInActive = false; mOutActive = false; mInterruptEnabled = true; mIoMemoryAddr = 0; mTransferSize = 0; mChannelActive = false; mHoldDisconnect = false; }
|
||||
virtual void MasterClear() override {
|
||||
mDone = false;
|
||||
mHoldDisconnect = false;
|
||||
mInActive = false;
|
||||
mInterruptEnabled = true;
|
||||
mIoMemoryAddr = 0;
|
||||
mOutActive = false;
|
||||
mReadyWaiting = false;
|
||||
mTransferSize = 0;
|
||||
mWriteDisconnect = false;
|
||||
}
|
||||
virtual void Tick() override;
|
||||
virtual bool NeedsTick() override { return true; }
|
||||
virtual void Dump(size_t aIdent=0) override {}
|
||||
@ -35,103 +45,66 @@ protected:
|
||||
|
||||
bool mAllowIn;
|
||||
bool mAllowOut;
|
||||
bool mDone;
|
||||
bool mInActive;
|
||||
bool mOutActive;
|
||||
bool mInterruptEnabled;
|
||||
bool mChannelActive;
|
||||
bool mHoldDisconnect;
|
||||
size_t mTransferDelayCounter;
|
||||
size_t mTransferDelay;
|
||||
size_t mChannelIdx;
|
||||
bool mDone;
|
||||
bool mHoldDisconnect;
|
||||
bool mInActive;
|
||||
bool mInterruptEnabled;
|
||||
bool mOutActive;
|
||||
bool mReadyWaiting;
|
||||
size_t mTransferDelay;
|
||||
size_t mTransferDelayCounter;
|
||||
bool mWriteDisconnect;
|
||||
};
|
||||
|
||||
class FrontEndLcp_c {
|
||||
public:
|
||||
static const size_t LcpSize = 6;
|
||||
FrontEndLcp_c() {
|
||||
mData.resize(6,0);
|
||||
}
|
||||
explicit FrontEndLcp_c(const std::vector<CInt_t> &aData): mData(aData) {
|
||||
CRAY_ASSERT(aData.size() == LcpSize);
|
||||
}
|
||||
std::vector<CInt_t> &GetData() { return mData; }
|
||||
const std::vector<CInt_t> &GetData() const { return mData; }
|
||||
#ifdef CREATE_FIELD
|
||||
#error CREATE_FIELD is alreadt defined
|
||||
#endif
|
||||
#define CREATE_FIELD(aType,aName,aEntry,aStartBit,aEndBit) \
|
||||
aType Get##aName() { return (aType)GetBits(mData[aEntry], 63-aStartBit, 63-aEndBit); } \
|
||||
void Set##aName(aType aValue) { mData[aEntry] = SetBits(mData[aEntry], 63-aStartBit, 63-aEndBit, aValue); }
|
||||
|
||||
CREATE_FIELD(uint16_t, DestinationId, 0, 0, 15)
|
||||
CREATE_FIELD(uint16_t, SourceId, 0, 16, 31)
|
||||
CREATE_FIELD(uint8_t, NumberOfSubsegments, 0, 32, 39)
|
||||
CREATE_FIELD(uint8_t, MessageNumber, 0, 40, 47)
|
||||
CREATE_FIELD(uint8_t, MessageCode, 0, 48, 55)
|
||||
CREATE_FIELD(uint8_t, MessageSubcode, 0, 56, 63)
|
||||
|
||||
CREATE_FIELD(uint8_t, RequestPending, 1, 0, 0)
|
||||
CREATE_FIELD(uint8_t, StreamNumber, 1, 4, 7)
|
||||
CREATE_FIELD(uint32_t, SegmentNumber, 1, 8, 31)
|
||||
CREATE_FIELD(uint32_t, DataBitsInSegment, 1, 32, 63)
|
||||
#undef CREATE_FIELD
|
||||
|
||||
uint8_t GetInputStreamCtrlByte(uint8_t aStrmIdx) { return (uint8_t)GetBits(mData[3], aStrmIdx*8, aStrmIdx*8+7); }
|
||||
void SetInputStreamCtrlByte(uint8_t aStrmIdx, uint8_t aValue) { SetBits(mData[3], aStrmIdx*8, aStrmIdx*8+7, aValue); }
|
||||
|
||||
uint8_t GetOutputStreamCtrlByte(uint8_t aStrmIdx) { return (uint8_t)GetBits(mData[4], aStrmIdx*8, aStrmIdx*8+7); }
|
||||
void SetOutputStreamCtrlByte(uint8_t aStrmIdx, uint8_t aValue) { SetBits(mData[4], aStrmIdx*8, aStrmIdx*8+7, aValue); }
|
||||
|
||||
//TODO: This list is highly incomplete. I'll have to finish it up if/when we implement a full front-end interface
|
||||
enum MessageCodes_e {
|
||||
MessageCode_Logon = 0001,
|
||||
MessageCode_Logoff = 0003,
|
||||
MessageCode_Start = 0004,
|
||||
MessageCode_Restart = 0005,
|
||||
MessageCode_DatasetHeader = 0006,
|
||||
MessageCode_DatasetSegment = 0007,
|
||||
MessageCode_Control = 0011,
|
||||
MessageCode_MessageError = 0012,
|
||||
MessageCode_DatasetTransferRequest = 0013,
|
||||
MessageCode_DatasetTransferReply = 0014,
|
||||
MessageCode_EnterLogfileRequest = 0015,
|
||||
MessageCode_EnterLogfileReply = 0016
|
||||
};
|
||||
protected:
|
||||
std::vector<CInt_t> mData;
|
||||
};
|
||||
#define BytesPerLCP 48
|
||||
#define MaxTransmitBufs 16
|
||||
#define WordsPerLCP 6
|
||||
/*
|
||||
* Key message codes
|
||||
*/
|
||||
#define McLogon 001
|
||||
#define McStart 004
|
||||
#define McControl 011
|
||||
|
||||
class IopConcentrator_c: public IopPeripheral_i {
|
||||
public:
|
||||
enum RcvStates_e {
|
||||
State_RcvLcpPduLength,
|
||||
State_RcvLcpPduContent,
|
||||
State_RcvSegPduLength,
|
||||
State_RcvSegPduContent
|
||||
};
|
||||
enum XmtStates_e {
|
||||
State_XmtLcpPduStart,
|
||||
State_XmtLcpPduContent,
|
||||
State_XmtSegPduStart,
|
||||
State_XmtSegPduContent
|
||||
};
|
||||
explicit IopConcentrator_c(const Configuration_c &aConfig, IopCpu_c &aParent):
|
||||
mParent(aParent),
|
||||
mLogger(aConfig, "CONC"),
|
||||
mAccepted(false),
|
||||
mBytesTransmitted(0),
|
||||
mConnectionSocket(nullptr),
|
||||
mInputChannel(*this,aConfig,aConfig.get<size_t>("InputChannelIdx"),false,true),
|
||||
mLastRcvdMessageCode(0),
|
||||
mLastXmitMessageCode(0),
|
||||
mListenSocket(nullptr),
|
||||
mLogger(aConfig, "CONC"),
|
||||
mOutputChannel(*this,aConfig,aConfig.get<size_t>("OutputChannelIdx"),true,false),
|
||||
mState(State_InMasterClear),
|
||||
mPollDelay(aConfig.get<uint32_t>("PollDelay", 10)),
|
||||
mPollTimer(0),
|
||||
mMainframeId(0),
|
||||
mParent(aParent),
|
||||
mPduLength(0),
|
||||
mPort(aConfig.get<uint16_t>("Port",9000)),
|
||||
mRcvState(State_RcvLcpPduLength),
|
||||
mSegmentSize(0),
|
||||
mToCrayIdx(0),
|
||||
mToCrayLast(true),
|
||||
mToCrayPacketIdx(0),
|
||||
mMessageNumber(0)
|
||||
mTransmitBufIdx(0),
|
||||
mXmtState(State_XmtLcpPduStart)
|
||||
{
|
||||
std::string SidStr =aConfig.get<std::string>("SID", "FE");
|
||||
CRAY_ASSERT(SidStr.length() == 2);
|
||||
mFrontEndId = ((uint16_t)SidStr[0]) << 8 | ((uint16_t)SidStr[1]) << 0;
|
||||
mMainframeId = 0x4331; // This is 'C1' but how should he concentrator know about it? It's not the SID of the RESET request...
|
||||
mLogger.SetParent(mParent.GetLogger());
|
||||
MasterClear(false);
|
||||
StartListen();
|
||||
MasterClear();
|
||||
}
|
||||
void MasterClear(bool aValue);
|
||||
CLogger_c &GetLogger() { return mLogger; }
|
||||
bool HasData();
|
||||
CInt_t GetData();
|
||||
void SetData(CInt_t aData);
|
||||
void ProcessFromCrayData();
|
||||
void TransferCompleted();
|
||||
void ClearBuffers();
|
||||
virtual const IopChannel_i &GetChannel(size_t aIdx) const override {
|
||||
switch (aIdx) {
|
||||
case 0: return mInputChannel;
|
||||
@ -141,44 +114,58 @@ public:
|
||||
throw Generic_x("Unreachable code");
|
||||
}
|
||||
virtual size_t GetChannelCnt() const override { return 2; }
|
||||
IopCpu_c &GetParent() { return mParent; }
|
||||
void BufferClearComplete();
|
||||
enum States_e {
|
||||
State_InMasterClear,
|
||||
State_ClearingBuffers,
|
||||
State_Operational
|
||||
};
|
||||
States_e GetState() const { return mState; }
|
||||
void LogState(const char *aHeader) const;
|
||||
void Tick();
|
||||
virtual PeripheralType_e GetType() const override { return PeripheralType_e::Other; }
|
||||
virtual void GetStatus(StatusReport_c &aStatus, PeripheralType_e aFilter, bool aLongFormat) const override {}
|
||||
virtual void RegisterCommands(CommandHooks_t &aHooks)override {}
|
||||
CInt_t GetData();
|
||||
size_t GetDataSize();
|
||||
CLogger_c &GetLogger() { return mLogger; }
|
||||
virtual std::string GetName() const override { return "CONC"; }
|
||||
IopCpu_c &GetParent() { return mParent; }
|
||||
virtual void GetStatus(StatusReport_c &aStatus, PeripheralType_e aFilter, bool aLongFormat) const override {}
|
||||
virtual PeripheralType_e GetType() const override { return PeripheralType_e::Other; }
|
||||
bool HasData();
|
||||
bool IsReceptionComplete();
|
||||
void MasterClear();
|
||||
void ProcessFromCrayData();
|
||||
virtual void RegisterCommands(CommandHooks_t &aHooks)override {}
|
||||
void SetData(CInt_t aData);
|
||||
void Tick();
|
||||
protected:
|
||||
void ProcessFromCrayLcp();
|
||||
void SetupNextTransfer();
|
||||
void SetToCrayData(std::vector<CInt_t> &aData, bool aIsLast, size_t aPacketIdx = 0) {
|
||||
mToCrayData = aData; mToCrayIdx = 0; mToCrayLast = aIsLast; mToCrayPacketIdx = aPacketIdx;
|
||||
mLogger << setloglevel(LogLevel_IoActivity) << "Setting up data tansfer mToCrayData.size()=" << DecPrinter(mToCrayData.size()) << " mToCrayLast=" << (mToCrayLast?"true":"false") << std::endl;
|
||||
}
|
||||
void AcceptHandler(const boost::system::error_code& aError);
|
||||
void ClearReceiveBuffers();
|
||||
void ClearTransmitBuffers();
|
||||
void CloseConnSocket();
|
||||
void Poll();
|
||||
void ProcessReceivedBytes();
|
||||
void ReadHandler(const boost::system::error_code& aError, std::size_t bytesTransferred);
|
||||
void StartAccept();
|
||||
void StartListen();
|
||||
void StartReceive();
|
||||
void StartTransmit();
|
||||
void WriteHandler(const boost::system::error_code& aError, std::size_t bytesTransferred);
|
||||
|
||||
bool mAccepted;
|
||||
size_t mBytesTransmitted;
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> mConnectionSocket;
|
||||
std::vector<CInt_t> mFromCrayData;
|
||||
FrontEndLcp_c mFromCrayLcp;
|
||||
IopConcentratorChannel_c mInputChannel;
|
||||
static boost::asio::io_service mIoService;
|
||||
uint8_t mLastRcvdMessageCode;
|
||||
uint8_t mLastXmitMessageCode;
|
||||
std::shared_ptr<boost::asio::ip::tcp::acceptor> mListenSocket;
|
||||
mutable CLogger_c mLogger;
|
||||
IopConcentratorChannel_c mOutputChannel;
|
||||
IopCpu_c &mParent;
|
||||
size_t mPduLength;
|
||||
size_t mPollCnt;
|
||||
uint16_t mPort;
|
||||
boost::asio::streambuf mReceiveBuf;
|
||||
RcvStates_e mRcvState;
|
||||
size_t mSegmentSize;
|
||||
size_t mSubsegmentCount;
|
||||
std::vector<CInt_t> mToCrayData;
|
||||
size_t mToCrayIdx;
|
||||
bool mToCrayLast;
|
||||
size_t mToCrayPacketIdx;
|
||||
uint32_t mPollDelay;
|
||||
uint32_t mPollTimer;
|
||||
IopCpu_c &mParent;
|
||||
IopConcentratorChannel_c mInputChannel;
|
||||
IopConcentratorChannel_c mOutputChannel;
|
||||
mutable CLogger_c mLogger;
|
||||
States_e mState;
|
||||
uint16_t mFrontEndId;
|
||||
uint16_t mMainframeId;
|
||||
uint8_t mMessageNumber;
|
||||
size_t mTransmitBufIdx;
|
||||
boost::asio::streambuf mTransmitBufs[MaxTransmitBufs];
|
||||
XmtStates_e mXmtState;
|
||||
};
|
||||
|
||||
#endif // __IOP_CONCENTRATOR_H__
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user