📄 abcomms.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
//
// FILE: ABComms.cpp : implementation file
//
// See "_README.CPP"
//
// implementation of the CABCommsProcessor class.
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "mod_RSsimdlg.h"
#include "message.h"
#include "ABCommsProcessor.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//
PCHAR parityNames[] =
{
"N ", //NOPARITY
"O ", //ODDPARITY
"E ", //EVENPARITY
"Mark ", //MARKPARITY
"Space" //SPACEPARITY
};
PCHAR stopNames[]=
{
"1",
"1.5",
"2"
};
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
// constructor to open port
IMPLEMENT_DYNAMIC( CABCommsProcessor, CCommsProcessor);
CABCommsProcessor::CABCommsProcessor(LPCTSTR portNameShort,
DWORD baud,
DWORD byteSize,
DWORD parity,
DWORD stopBits,
DWORD rts,
int responseDelay,
BOOL bcc
)
: CCommsProcessor(portNameShort,
19200, //baud,
8,//byteSize,
parity,
ONESTOPBIT, //stopBits,
RTS_CONTROL_ENABLE,//rts,
responseDelay
)
{
CString portName;
CString description;
if (PROTOCOL_SELAB232 == pGlobalDialog->m_selectedProtocol)
SetProtocolName("Allen-Bradley DF1");
else
SetProtocolName("JOY SCC");
m_ABmasterIDLETime = 100;
m_ABtimeoutValue = 300;
m_masterBusy = FALSE; // master-mode PLC internal state flags
m_masterWaiting = FALSE;
m_guardJunk = 0xAAAAAAAA;
m_lastMasterTick = GetTickCount(); //
m_useBCCchecks = TRUE;
m_surfacePolls = 0;
m_CPUmode = (pGlobalDialog->m_PLCMaster? MODE_MASTER : MODE_SLAVE);
m_CPUstateEngineStep = ENG_STATE_IDLE;
m_noiseLength = 0;
//m_transactionID = 0;
memset(m_masterTN, 0 , sizeof(m_masterTN));
m_JOYsource = 1;
m_JOYdest = 10;
m_JOYShields = 22;
m_JOYrunMode = TRUE;
m_JOYreadVariables = FALSE;
m_JOYwriteVariables = TRUE;
m_ABmasterIDLETime = 100;
m_ABtimeoutValue = 300;
if (PROTOCOL_SELAB232 == pGlobalDialog->m_selectedProtocol)
{
m_useBCCchecks = bcc;
// SLC PLC defaults for DF1
if ((pGlobalDialog->m_baud !=19200)||
(pGlobalDialog->m_parity != NOPARITY)||
(pGlobalDialog->m_byteSize != 8)||
(pGlobalDialog->m_rts != RTS_CONTROL_ENABLE)||
(pGlobalDialog->m_stopBits != ONESTOPBIT))
if (IDYES == AfxMessageBox("Load DF1 port setting defaults Y/N?\n Settings: 19200,8,N,1 and RTS enabled", MB_YESNO))
{
pGlobalDialog->m_baud = 19200;
pGlobalDialog->m_parity = NOPARITY;
pGlobalDialog->m_byteSize = 8;
pGlobalDialog->m_rts = RTS_CONTROL_ENABLE;
pGlobalDialog->m_stopBits = ONESTOPBIT;
pGlobalDialog->SaveApplicationSettings();
}
}
else
{
m_CPUmode = MODE_MASTER;
//m_useBCCchecks = TRUE;
// JOY
if ((pGlobalDialog->m_baud !=19200)||
(pGlobalDialog->m_parity != EVENPARITY)||
(pGlobalDialog->m_byteSize != 8)||
(pGlobalDialog->m_rts != RTS_CONTROL_ENABLE)||
(pGlobalDialog->m_stopBits != ONESTOPBIT))
if (IDYES == AfxMessageBox("Load JOY SCC port setting defaults Y/N?\n Settings: 19200,8,E,1 and RTS enabled", MB_YESNO))
{
pGlobalDialog->m_baud = 19200;
pGlobalDialog->m_parity = EVENPARITY;
pGlobalDialog->m_byteSize = 8;
pGlobalDialog->m_rts = RTS_CONTROL_ENABLE;
pGlobalDialog->m_stopBits = ONESTOPBIT;
pGlobalDialog->SaveApplicationSettings();
}
}
//
portName.Format("%s %d:%d-%s-%s", portNameShort, pGlobalDialog->m_baud, pGlobalDialog->m_byteSize, parityNames[pGlobalDialog->m_parity], stopNames[pGlobalDialog->m_stopBits]);
portName += (IsMaster()?" -Master":" -Slave");
description.Format("Starting comms emulation : %s", portName);
RSDataMessage(description);
// open the port etc...
if (OpenPort(portNameShort))
{
COMMTIMEOUTS timeout;
BOOL err;
DWORD reason;
ConfigurePort(pGlobalDialog->m_baud, pGlobalDialog->m_byteSize, pGlobalDialog->m_parity, pGlobalDialog->m_stopBits, pGlobalDialog->m_rts, (NOPARITY==parity?FALSE:TRUE));
//set the timeouts shorter
// fill timeout structure
GetCommTimeouts(h232Port, &timeout);
timeout.ReadIntervalTimeout = 100; //
timeout.ReadTotalTimeoutConstant = 200;
timeout.ReadTotalTimeoutMultiplier = 0; // #chars to read does not add to timeout amount
timeout.WriteTotalTimeoutConstant = 2000;
timeout.WriteTotalTimeoutMultiplier = 60; // 60ms per char sent
err = SetCommTimeouts(h232Port, &timeout);
reason = GetLastError();
}
m_responseDelay = responseDelay;
}
// ------------------------------- MasterTimedOut ---------------------------
BOOL CABCommsProcessor::MasterTimedOut()
{
LONG tick = (LONG)GetTickCount();
if (tick - (LONG)m_lastMasterTick > (LONG)m_ABmasterIDLETime) //PORT_MAX_IDLETIME*3)
{
return(TRUE);
}
return(FALSE);
}
// ------------------------------------- DoMaster ----------------------------
// called in the IDLE state
void CABCommsProcessor::DoMaster()
{
static m_masterTN[256];
//check if scripts are running
if (pGlobalDialog->ScriptIsRunning())
return;
// check if we may send
if (m_masterBusy && (ENG_STATE_IDLE == m_CPUstateEngineStep))
{
if (MasterTimedOut() || m_masterWaiting)
{
m_lastMasterTick = GetTickCount(); // transaction has ended
m_masterBusy = FALSE;
m_masterWaiting = FALSE;
return;
}
}
if (m_masterWaiting)
return; // not timed out yet, hold on
// check if it is time to send again
if (GetTickCount() - m_lastMasterTick > m_ABtimeoutValue)//ABMASTER_IDLETIME )
{ // send a message.
CPLCApplication *pApp;
WORD fileNumber, numElements = 10;
static WORD lastShieldNumber; // starting shield number is arbitrary
static WORD lastCutterDirection; // direction is arbitrary
// go back to shield 0 (non-existent) to make us move to shield 1 on the next transaction
if (lastShieldNumber >= JOY_NUMSHIELDS)
lastShieldNumber = 0;
m_masterBusy = TRUE;
m_masterWaiting = FALSE;
// we need to use the App layer to do this, so let's verify our app layer object
pApp = (CPLCApplication *)this;
ASSERT(pApp->IsKindOf(RUNTIME_CLASS(CPLCApplication)));
if (m_JOYreadVariables && (0 >= pApp->m_surfacePolls))
{ // do a shearer read
fileNumber = 100 + (m_masterRandom % (WORD)JOY_NUMSHIELDS) + (WORD)JOY_FIRSTSHIELD;
pApp->FetchPLCBlock(AB_MASTER_ID, // source
JOY_SURFACEPLC_ID,
GetNextTransactionID(JOY_SURFACEPLC_ID), // increments the TNS as well
fileNumber,
0, // start offset
numElements//40 // # elements
);
pApp->m_surfacePolls = JOY_SURFACEPLCPOLLCOUNT;
}
else
{
if (m_JOYwriteVariables)
{
// decide which PLC file # to send data for
if (0 == m_masterRandom % 10)
{
WORD direction, cutterPosition;
WORD lastCutterPosition; // position
BOOL oldDirection;
// every 10 transactions, we send cutter motor position info again
fileNumber = 99;
numElements = 3; // cutter info is 3 items only
lastCutterPosition = PLCMemory[99][0];
if ((lastCutterPosition > JOY_NUMSHIELDS)||(0 == lastCutterPosition))// cutter pos wrap check
lastCutterPosition = 1;
direction = PLCMemory[99][1];
oldDirection = direction;
cutterPosition = lastCutterPosition;
switch(direction)
{
case 1 : //up
if (lastCutterPosition == JOY_NUMSHIELDS)
PLCMemory.SetAt(99, 1, 2); // change direction to DOWN
else
PLCMemory.SetAt(99, 1, 1);
break;
case 2 : // down
default:
if (lastCutterPosition == 1)
PLCMemory.SetAt(99, 1, 1); // change direction to UP
else
PLCMemory.SetAt(99, 1, 2);
break;
}
// use direction to determine shield #
direction = PLCMemory[99][1];
if (direction == oldDirection)
{ // cutter does not actually move on the "turn-around"
switch(direction)
{
case 1 : //up
cutterPosition = lastCutterPosition+1;
break;
case 2 : // down
default:
cutterPosition = lastCutterPosition-1;
break;
}
}
// update things
PLCMemory.SetAt(99, 0, cutterPosition);
PLCMemory.SetAt(99, 2, JOY_NUMSHIELDS);
}
else
{
// increment
lastShieldNumber++;
fileNumber = lastShieldNumber + 100;
}
//fileNumber = 101 + (m_masterRandom % JOY_NUMSHIELDS) + JOY_FIRSTSHIELD;
if (0 == m_masterRandom % 10) // every 10th message is the cutter position
{
fileNumber = 99;
}
pApp->SendPLCBlock((BYTE)AB_MASTER_ID, // source
(BYTE)JOY_SURFACEPLC_ID, // destination
GetNextTransactionID(JOY_SURFACEPLC_ID), // increments the TNS as well
fileNumber,
JOY_SURFACEELEMENTS_START,
numElements ); // 10 registers
pApp->m_surfacePolls --;
}
else
pApp->m_surfacePolls = 0; // read again
}
m_masterRandom++;
}
}
// ------------------------------- StationIsEnabled ---------------------------
// Return TRUE if station is enabled
BOOL CABCommsProcessor::StationIsEnabled(LONG stationID)
{
if (stationID>0 && stationID<STATIONTICKBOXESMAX)
{
return (pGlobalDialog->StationEnabled(stationID));//m_microTickState==1);
}
return TRUE;
} // StationIsEnabled
// --------------------------------- SendPLCMessage ------------------------------------
// pAppLayerMsg = buffer pointig to start of the app layer (stationID)
// length = length of the app layer only (before DLE expansion)
//
BOOL CABCommsProcessor::SendPLCMessage(const BYTE* pAppLayerMsg, DWORD length) // if False, then re-send
{
BYTE telegram[MAX_AB_MESSAGELEN];
DWORD telegramLength;
WORD crc = 0;
BYTE bcc = 0;
BYTE *crcStartPtr;
crcStartPtr = (BYTE*)pAppLayerMsg;
m_noiseLength = 0; // kill all stuff in the buffer before we start to respond
// send of DLE-STX
// calculate CRC
// send telegram (expand DLEs)
// send DLE-ETX and CRC
//////////////////////////////////////////////////////////
// send DLE-STX
Send(2, txDLE_STX, FALSE, NULL);
// calc CRC
{
CHAR ETXBuff[2];
crcStartPtr = (BYTE*)pAppLayerMsg;
CalcCRC(crcStartPtr, length, &crc); // application layer CRC
ETXBuff[0] = 0x03;
CalcCRC((BYTE*)&ETXBuff[0], 1, &crc); // include the ETX
}
// calc a bcc
bcc = CalcBCC(crcStartPtr, length);
// send telegram
Send(length, pAppLayerMsg, TRUE, NULL);
//make a copy in case it gets lost on the device side, and they NAK us
m_lastAppLength = length;
memcpy(m_lastAppBuffer, pAppLayerMsg, length);
//Send DLE-ETX
Send(2, txDLE_ETX, FALSE, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -