⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 itkplcdlg.cpp

📁 工业强度的PLC模拟程序
💻 CPP
📖 第 1 页 / 共 5 页
字号:
//----(Member Function)-------------------------------------------------------
//
// @mfunc void | CItkPlcDlg | OnClearMemory |
//
// Clears the entire memory map.
//
void CItkPlcDlg::OnClearMemory() 
{
	this->UpdateMemoryMap(CLEAR_MEMORY);
}




/////////////////////////////////////////////////////////////////////////////
//
// All of the member functions from here are for communications to the 
// I/O Driver and thread management.
//
/////////////////////////////////////////////////////////////////////////////




#include <Serial.h>
#include <ItkErr.h>

//----(Member Function)-------------------------------------------------------
//
// @mfunc UINT | CItkPlcDlg | IoHandler |
//
// Handler for the I/O Communication's thread.
//
UINT CItkPlcDlg::IoHandler(LPVOID ptr)
{
	CItkPlcDlg		*pThis = (CItkPlcDlg *)ptr;

	DWORD			dwStatus = IO_SUCCESS,
					dwActualSize = 0;

	BOOL			bTcp = TRUE;
	unsigned char	buffer[4096];


	pThis->m_hNotifyEvt = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (NULL == pThis->m_hNotifyEvt)
	{
		return(0);
	}

	switch (pThis->m_dwProtocol)
	{
	case TCPIP_PROTOCOL:
		// Create TCP/IP version of Io Object
		bTcp = TRUE;
		memset((char *)pThis->m_chReceiveBuffer, 0, RECEIVE_BUFFER_SIZE);
		pThis->m_pTcp = new CTcpIp("Itk", pThis->m_szIpAddress, 0, bTcp, NULL, (void *)pThis, NULL, &TcpSrvCallback, NULL, (unsigned short) pThis->m_uPortNumber, pThis->m_chReceiveBuffer, RECEIVE_BUFFER_SIZE);
		break;

	case UDPIP_PROTOCOL:
		// Create UDP/IP version of Io Object
		bTcp = FALSE;

		memset((char *)pThis->m_chReceiveBuffer, 0, RECEIVE_BUFFER_SIZE);
		pThis->m_pTcp = new CTcpIp("Itk", pThis->m_szIpAddress, 0, bTcp, NULL, (void *)pThis, NULL, NULL, &UdpSrvCallback, (unsigned short) pThis->m_uPortNumber, pThis->m_chReceiveBuffer, RECEIVE_BUFFER_SIZE);
		break;

	case SERIAL_PROTOCOL:
	default:
		// Create Serial version of Io Object
		pThis->m_pIo = new CSerial("ItkPlc");
		break;
	}

	if (pThis->m_pIo || pThis->m_pTcp )
	{
		memset((char *)buffer, 0, 4096);

		switch (pThis->m_dwProtocol)
		{
			case TCPIP_PROTOCOL:
			case UDPIP_PROTOCOL:
				// If tcpip do nothing. Server already started
				//
				break;

			case SERIAL_PROTOCOL:
			default:
				dwStatus = pThis->m_pIo->Open(pThis->m_szPortName,
											pThis->m_szPortMode,
											(HANDLE)pThis->m_hNotifyEvt);
				break;
		}

		if (IO_SUCCESS == dwStatus)
		{
			switch (pThis->m_dwProtocol)
			{
				case TCPIP_PROTOCOL:
				case UDPIP_PROTOCOL:
//					SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
					SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
					SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
				break;

				case SERIAL_PROTOCOL:
					SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
					SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
				default:
				break;
			}// End switch


			//
			// Kick off a thread for unsolicited messages, if needed
			//
			if ((NULL == pThis->m_hUnsolThread) && (pThis->m_bUnsolicited))
			{
				DWORD	dwUnsolIoThreadId = 0;
				pThis->m_hUnsolThread = CreateThread(NULL,
						 							0,
													(LPTHREAD_START_ROUTINE)UnsolIoHandler, 
													(LPVOID)pThis, 
													0, 
													&dwUnsolIoThreadId); 
			}

			while (!pThis->m_bShutdown)
			{
				switch (pThis->m_dwProtocol)
				{
				case TCPIP_PROTOCOL:
				case UDPIP_PROTOCOL:
					//
					// If tcpip do nothing. Server already started
					//	If there is anything in receive buffer it will 
					//	invoke the CALLBACK function
					//

					Sleep(WAIT_TIME);
					break;

				case SERIAL_PROTOCOL:
				default:
					//
					// Receive and parse a serial message.
					//
					switch(WaitForSingleObject(pThis->m_hNotifyEvt, INFINITE))
					{
					case WAIT_ABANDONED:
					case WAIT_TIMEOUT:
						AfxMessageBox("Wait for IO notification failed");
						break;
					case WAIT_OBJECT_0:
						dwStatus = pThis->m_pIo->Receive(buffer, 
														 4096, 
														 &dwActualSize);
						if (IO_SUCCESS == dwStatus)
						{
							pThis->ParseMsg(buffer, dwActualSize);
						}
						else
						{
							AfxMessageBox("Failed to read data");
						}
						break;
					}

					break;
				}	// end switch (pThis->m_dwProtocol)
			}	// end while (!pThis->m_bShutdown)

			switch (pThis->m_dwProtocol)
			{
				case TCPIP_PROTOCOL:
				case UDPIP_PROTOCOL:
					break;

				case SERIAL_PROTOCOL:
				default:
					pThis->m_pIo->Close();
					break;
			}
		}
		else
		{
			AfxMessageBox("Error occurred while performing an open");
		}
		
		CloseHandle(pThis->m_hNotifyEvt);
		
		switch (pThis->m_dwProtocol)
		{
			case TCPIP_PROTOCOL:
			case UDPIP_PROTOCOL:
				delete pThis->m_pTcp;
				break;

			case SERIAL_PROTOCOL:
			default:
				delete pThis->m_pIo;
				break;
		}
	}

	return(1);
}



//----(Member Function)-------------------------------------------------------
//
// @mfunc void | CItkPlcDlg | ParseMsg |
//
// Parses a message from the I/O Driver
//
void CItkPlcDlg::ParseMsg(unsigned char buffer[], DWORD dwSize)
{
	DWORD						dwLoop;

	unsigned char				Value;

	static unsigned short int	rcv_state	= DLE1,
								calc_bcc	= 0,
								dest		= 0,	// destination (our station)
								src			= 0,	// source (from who)
								start		= 0,
								len			= 0, 
								cmd			= 0, 
								dle_flag	= 0,
								ans_len		= 0, 
								ans_start	= 0, 
								ans_src		= 0,	// destination (to who)
								ans_dest	= 0,	// source (our station)
								set_mask	= 0, 
								reset_mask	= 0,
								transaction	= 0;

	static unsigned short int	write_val[120];
	
	unsigned int				i;
	
    
	for (dwLoop = 0; dwLoop < dwSize; dwLoop++)
	{
		Value = buffer[dwLoop];

		//
		//  Check for doubled-up DLE's
		//
		if (Value == DLE)
        {
			if (dle_flag)				// was previous dle ?
            {
				dle_flag = FALSE;       // clear flag
				continue;               // done
            }    
			else
			{
				dle_flag = TRUE;        // first dle
			}
        }
		else
		{
			dle_flag = FALSE;           // clear flag
		}

		switch (rcv_state)
        {
        case DLE1:
            if (Value == DLE)
            {
                calc_bcc = 0;			// reset bcc
                rcv_state = STX1;
            }
            break;

        case STX1:
			switch(Value)
			{
			case STX:
				if (this->m_bSourceStn)
				{
					rcv_state = SRC1;
				}
				else
				{
					rcv_state = DEST1;
				}
				calc_bcc = 0;			// reset bcc
				break;
			case NAK:
				rcv_state = DLE1;
				this->m_pdlgCommStats->m_dwNakRcvdCount++;
				AnswerRead(ans_dest, ans_src, ans_start, ans_len, cmd, transaction);
				break;
			case ACK:
				rcv_state = DLE1;
				this->m_pdlgCommStats->m_dwAckRcvdCount++;
				break;
			}
			break;

		case SRC1:				// Source Station address
			src = Value;
			rcv_state = DEST1;
			calc_bcc += Value;
			break;

        case DEST1:				// Destination Station address
            dest = Value;
			//
			// Make sure the message is for us. A Local Station
			// set to 0 means to accept ALL messages.
			//
			if ((this->m_dwLocalStation == 0) || 
				(this->m_dwLocalStation == dest))
			{
				rcv_state = CMD1;
				calc_bcc += Value;
				break;
			}
			else
			{
				rcv_state = DLE1;
				SendDLE(NAK);
				return;
			}

        case CMD1:				// Command
            cmd = Value;
			if (this->m_bTransNum)
			{
				rcv_state = TRANHI;
			}
			else
			{
				rcv_state = ADDLO;
			}
            calc_bcc += Value;
            break;

		case TRANHI:			// Transaction Number hi-byte
			transaction = (Value << 8);
			rcv_state = TRANLO;
			calc_bcc += Value;
			break;

		case TRANLO:			// Transaction Number lo-byte
			transaction += Value;
			rcv_state = ADDLO;
			calc_bcc += Value;
			break;

        case ADDLO:				// Start Adress lo-byte
            start = Value;
            rcv_state = ADDHI;
            calc_bcc += Value;
            break;

        case ADDHI:				// Start Address hi-byte
            start |= ((Value<<8) & 0xff00);
            calc_bcc += Value;
            switch (cmd)
            {
			case READ_CMD:
				rcv_state = LEN1;
				break;    
			case BIT_WRITE_CMD:
				rcv_state = SET1;
				break;    
			case WRITE_CMD:    
				len = 0;
				rcv_state = DATA1;
				break;    
			default:
				rcv_state = DLE1;
            }
            break;

        case DATA1:
            write_val[len] = Value;

			if (Value == DLE)     
			{
				rcv_state = DATA_DLE;
				dle_flag = FALSE;
			}
			else
			{
				rcv_state = DATA2;
				calc_bcc += Value;
			}
            break;

        case DATA2:
            write_val[len] |= ((Value << 8) & 0xff00);
            len++;             

			if (Value == DLE)          
			{
				rcv_state = DATA_DLE2;
				dle_flag = FALSE;
			}
			else
			{
				rcv_state = DATA1;
				calc_bcc += Value;
			}
			break;

        case DATA_DLE:
			switch(Value)
			{
			case DLE:
				rcv_state = DATA2;
                calc_bcc += Value;
                break;
			case ETX:
				rcv_state = BCC1;
				break;
			default:
				rcv_state = DLE1;
				break;
			}
			break;
 
        case DATA_DLE2:  
			switch(Value)
			{
			case DLE:
				rcv_state = DATA1;
                calc_bcc += Value;
                break;
			case ETX:
				rcv_state = BCC1;
				break;
			default:
				rcv_state = DLE1;
				break;
			}
			break;
 
        case SET1:
            set_mask = Value;
            rcv_state = SET2;
            calc_bcc += Value;
            break;

        case SET2:
            set_mask |= ((Value<<8) & 0xff00 );
            rcv_state = RESET1;
            calc_bcc += Value; 
            break;

        case RESET1:
            reset_mask = Value;
            rcv_state = RESET2;
            calc_bcc += Value;
            break;

        case RESET2:
            reset_mask |= ( (Value<<8) & 0xff00 );
            rcv_state = DLE2;
            calc_bcc += Value;
            break;

        case LEN1:
            len = Value;
            rcv_state = DLE2;
            calc_bcc += Value;
            break;

        case DLE2:
            if (Value == DLE)
            {
				rcv_state = ETX1;
			}
            else
			{
				rcv_state = DLE1;
			}
            break;

        case ETX1:
            if ( Value == ETX )
			{
				rcv_state = BCC1;
			}
            else
			{
				rcv_state = DLE1;
			}
            break;
    
        case BCC1:					// Checksum
            calc_bcc += Value;
            rcv_state = DLE1;

            if ((calc_bcc & this->m_cBCCMask) == 0)
            {
				SendDLE(ACK);

                switch (cmd)
                {
                case READ_CMD:
					this->m_pdlgCommStats->m_dwReadCount++;
                    ans_len = len;
                    ans_start = start;
                    ans_src = dest;
					ans_dest = src;
                    AnswerRead(ans_dest, ans_src, ans_start, ans_len, cmd, transaction);
                    break;    

				case BIT_WRITE_CMD:
					this->m_pdlgCommStats->m_dwBitWriteCount++;
					PlcMemory[start] &= ~reset_mask;	// clear bits
					PlcMemory[start] |= set_mask;		// set bits
					this->UpdateRow((start / REGISTERS_PER_ROW));
					ans_len = 2;
					ans_start = start;
					ans_src = dest;
					ans_dest = src;
					AnswerRead(ans_dest, ans_src, ans_start, ans_len, cmd, transaction);
					break;    

				case WRITE_CMD:    
				{
					DWORD	dwNumRows = 0,
							dwFirstRow,
							dwRow;

					this->m_pdlgCommStats->m_dwWriteCount++;

					//
					// Put the write data in the memory map
					//
                    for (i = 0; i < len; i++)
                    {
						PlcMemory[start + i] = write_val[i];
					}     
						
					dwNumRows = (len / REGISTERS_PER_ROW) + 1;
					dwFirstRow = (start / REGISTERS_PER_ROW);
					
					//
					// Update the rows changed
					//
					for (dwRow = 0; dwRow < dwNumRows; dwRow++)
					{
						this->UpdateRow(dwFirstRow + dwRow);
					}
                    ans_len = 2;
                    ans_start = start;
                    ans_src = dest;
					ans_dest = src;
                    AnswerRead(ans_dest, ans_src, ans_start, ans_len, cmd, transaction);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -