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

📄 transportserial.cpp

📁 .net 方面的开发说明资料。
💻 CPP
📖 第 1 页 / 共 2 页
字号:
				m_idle_timestamp = EpGetTickCount();
			}

			m_delay_before_send = false;
		} else {
			// wait a moment when the user sends +++
			// (+++ causes a modem to go into command-mode, but only if a second of
			// silence comes before and after the string)

			if ((m_action->send_size == 3) && (m_action->send_data[0] == '+') && (m_action->send_data[1] == '+') && (m_action->send_data[2] == '+')) {
				int tick = EpGetTickCount();

				if (tick - m_idle_timestamp < 1000) {
					Sleep(1000 - (tick - m_idle_timestamp));
				}
			}
		}

		// now send the data

		switch(PollSend(m_action)) {
			case SEND_DONE :
			{
				Action *tmp = m_action;
				m_action = NULL;

				// if we just sent +++, wait a second to give the modem time to switch to command mode

				if ((tmp->send_size == 3) && (tmp->send_data[0] == '+') && (tmp->send_data[1] == '+') && (tmp->send_data[2] == '+'))
					Sleep(1000);

				// send propriety events around that the sending has finished

				DWORD perc = 100;
				EpDispatchSystemEvent(this, SYSTEM_SENT_PROGRESS_BYTES, &tmp->send_size, sizeof(DWORD));
				EpDispatchSystemEvent(this, SYSTEM_SENT_PROGRESS_PERCENTAGE, &perc, sizeof(DWORD));

				// tell the agent it can schedule the next action

				EpPacketSent(this, true);
				break;
			}

			case SEND_FAILED :
			{
				m_action = NULL;

				// store the error msg that windows set

				DWORD error = GetLastError();

				// send a system_io_error event, when the error value is not ERROR_SUCCESS

				if (error != ERROR_SUCCESS)
					EpDispatchSystemEvent(this, SYSTEM_IO_ERROR, (BYTE *)&error, sizeof(BYTE*));

				// tell the agent sending failed

				EpPacketSent(this, false);
				break;
			}

			case SEND_PENDING :
				break;
		};

		// 

		m_idle_timestamp = EpGetTickCount();
	}

	// if any data arrives or any flag changed, handle it

	if (PollIncomingEvents())
		m_idle_timestamp = EpGetTickCount();
}

bool
CTransportSerial::PollIncomingEvents() {
	// create a system family event for modem status events

	EpEvent pm_event;
	pm_event.reference_id = 0;
	pm_event.protocol = CLSID_SYSTEM_PROTOCOL;
	pm_event.size = 0;
	pm_event.data = NULL;

	// send out a new 'read event' request if it wasn't issued before

	if (!m_wait_pending) {
		if (WaitCommEvent(m_handle, &m_com_event, &m_overlapped_wait)) {
			// When there comes an event, try to handle it...
			// GetOverlappedResult will never fail with an ERROR_IO_INCOMPLETE, because
			// i already know there is an event waiting. It can fail with other errors though.
			// When this happens, i just return false

			DWORD transferred = 0;

			if (!GetOverlappedResult(m_handle, &m_overlapped_wait, &transferred, FALSE)) {
				m_wait_pending = false;
				return false;
			} else {
				m_wait_pending = false;

				HandleEvent(m_com_event);

				m_com_event = 0;
				return true;
			}
		} else {
			// is wait action pending in the background? if so start doing something else
			// if there was an error, just return false

			m_wait_pending = (GetLastError() == ERROR_IO_PENDING);
			return false;
		}	
	}

	// if there is still an open request, try to read it

	if (m_wait_pending) {
		switch(WaitForSingleObject(m_overlapped_wait.hEvent, 0)) {
			case WAIT_OBJECT_0 :
				// incoming event... try to handle it

				m_wait_pending = false;

				HandleEvent(m_com_event);

				m_com_event = 0;
				return true;

			case WAIT_TIMEOUT :
				return false;

			default :
				m_wait_pending = false;
				break;
		}
	}

	return false;
}

// --------------------------------------------------------
// Own class methods
// --------------------------------------------------------

SEND_RESULT
CTransportSerial::PollSend(Action *ac) {
	DWORD written = 0;

	// no incomplete sends pending in the overlapped io background, send out a new writefile

	if (!m_send_pending) {
		if (!WriteFile(m_handle, ac->send_data, ac->send_size, &written, &m_overlapped_tx)) {
			// not completed... check if the io is pending in the background

			if (GetLastError() != ERROR_IO_PENDING)
				return SEND_FAILED;

			// start polling for send completion...

			m_send_pending = true;
		} else {
			return SEND_DONE;
		}
	}

	// incomplete send pending in the overlapped io background, see if it's ready

	if (m_send_pending) {
		if (!GetOverlappedResult(m_handle, &m_overlapped_tx, &written, FALSE)) {
			if (GetLastError() == ERROR_IO_INCOMPLETE) {
				return SEND_PENDING;
			} else {
				m_send_pending = false;
				return SEND_FAILED;
			}
		}

		// the send of a chunk of data is completed... hurray!

		m_send_pending = false;
		return SEND_DONE;
	}

	// the send of a chunk of data has failed... bogus!

	m_send_pending = false;
	return SEND_FAILED;
}

void
CTransportSerial::HandleEvent(DWORD event) {
	DWORD modem_status;

	// A break was detected on input
	
	if ((event & EV_BREAK))
		EpDispatchSystemEvent(this, SYSTEM_RS232_BREAK, NULL, 0);

	// The CTS (clear-to-send) signal changed state

	if ((event & EV_CTS))
		if (GetCommModemStatus(m_handle, &modem_status))
			EpDispatchSystemEvent(this, (modem_status & MS_CTS_ON) ? SYSTEM_RS232_CTS_ON :SYSTEM_RS232_CTS_OFF, NULL, 0);

	// The DSR (data-set-ready) signal changed state.

	if ((event & EV_DSR))
		if (GetCommModemStatus(m_handle, &modem_status))
			EpDispatchSystemEvent(this, (modem_status & MS_DSR_ON) ? SYSTEM_RS232_DSR_ON :SYSTEM_RS232_DSR_OFF, NULL, 0);

	// A line-status error occurred. Line-status errors
	// are CE_FRAME, CE_OVERRUN, and CE_RXPARITY.

	if (event & EV_ERR) {
		DWORD error = 0;
		ClearCommError(m_handle, &error, NULL);

		if (error & CE_BREAK)
			EpDispatchSystemEvent(this, SYSTEM_RS232_ERR_BREAK, NULL, 0);

		if (error & CE_DNS)
			EpDispatchSystemEvent(this, SYSTEM_RS232_ERR_DNS, NULL, 0);

		if (error & CE_FRAME)
			EpDispatchSystemEvent(this, SYSTEM_RS232_ERR_FRAME, NULL, 0);

		if (error & CE_IOE)
			EpDispatchSystemEvent(this, SYSTEM_RS232_ERR_IOE, NULL, 0);

		if (error & CE_MODE)
			EpDispatchSystemEvent(this, SYSTEM_RS232_ERR_MODE, NULL, 0);

		if (error & CE_OOP)
			EpDispatchSystemEvent(this, SYSTEM_RS232_ERR_OOP, NULL, 0);

		if (error & CE_OVERRUN)
			EpDispatchSystemEvent(this, SYSTEM_RS232_ERR_OVERRUN, NULL, 0);

		if (error & CE_PTO)
			EpDispatchSystemEvent(this, SYSTEM_RS232_ERR_PTO, NULL, 0);

		if (error & CE_RXOVER)
			EpDispatchSystemEvent(this, SYSTEM_RS232_ERR_RXOVER, NULL, 0);

		if (error & CE_RXPARITY)
			EpDispatchSystemEvent(this, SYSTEM_RS232_ERR_RXPARITY, NULL, 0);

		if (error & CE_TXFULL)
			EpDispatchSystemEvent(this, SYSTEM_RS232_ERR_TXFULL, NULL, 0);
	}

	// A ring indicator was detected.

	if (event & EV_RING)
		if (GetOption(SERIAL_RING_STATUS, &modem_status, NULL))
			EpDispatchSystemEvent(this, modem_status ? SYSTEM_RS232_RING_ON : SYSTEM_RS232_RING_OFF, NULL, 0);

	// The RLSD (receive-line-signal-detect) signal changed state.

	if (event & EV_RLSD)
		if (GetOption(SERIAL_RLSD_STATUS, &modem_status, NULL))
			if (modem_status) {
				EpDispatchSystemEvent(this, SYSTEM_RS232_RLSD_ON, NULL, 0);

				if (m_modem) {
					EpDispatchSystemEvent(this, SYSTEM_CONNECTED, NULL, 0);
				}
			} else {
				EpDispatchSystemEvent(this, SYSTEM_RS232_RLSD_OFF, NULL, 0);

				if (m_modem) {
					EpDispatchSystemEvent(this, SYSTEM_DISCONNECTED, NULL, 0);
				}
			}

	// A character was received and placed into the input buffer.
	// This flag is not directly outputted to the callback.
	// Rather the data is read from the input buffer and passed to
	// the protocol, which then will try to figure out what it is

	if (event & EV_RXCHAR) {
		COMSTAT status;
		DWORD error = 0;
		DWORD read = 0;

		if (ClearCommError(m_handle, &error, &status)) {
			if (status.cbInQue > 0) {
				BYTE receive_buffer[2048];

				if (receive_buffer) {
					// ReadFile will not fail with ERROR_IO_PENDING, because it is
					// already known that there is data on the input buffer

					if (!ReadFile(m_handle, &receive_buffer, status.cbInQue, &read, &m_overlapped_rx)) {
						// error... output an error packet to the user callback

						DWORD error = GetLastError();
						EpDispatchSystemEvent(this, SYSTEM_IO_ERROR, (BYTE *)&error, sizeof(BYTE *));
					} else if (read != 0) {	
						// it could be that ReadFile comes back so quick that
						// it didn't receive any data. Only call the callback
						// when there is actually data received

						EpDispatchSystemEvent(this, SYSTEM_DATA_IN, receive_buffer, status.cbInQue);
					}
				}
			}
		}
	}
}

bool
CTransportSerial::GetOptionA(int option, void *value, int *size) {
	switch(option) {
		case SERIAL_GET_DCB :
			*size = sizeof(TDCB);
			break;

		case SERIAL_CTS_STATUS :
			*size = 4;
			break;

		case SERIAL_DSR_STATUS :
			*size = 4;
			break;

		case SERIAL_RING_STATUS :
			*size = 4;
			break;

		case SERIAL_RLSD_STATUS :
			*size = 4;
			break;
	}

	return false;
}

bool
CTransportSerial::GetOptionB(int option, void *value, int *size) {
	DWORD modem_status;

	switch(option) {
		case SERIAL_GET_DCB :
			return (GetCommState(m_handle, (DCB *)value) != 0);

		case SERIAL_CTS_STATUS :				
			GetCommModemStatus(m_handle, &modem_status);
			*((DWORD *)value) = (modem_status & MS_CTS_ON) != 0;
			return true;

		case SERIAL_DSR_STATUS :
			GetCommModemStatus(m_handle, &modem_status);
			*((DWORD *)value) = (modem_status & MS_DSR_ON) != 0;
			return true;

		case SERIAL_RING_STATUS :
			GetCommModemStatus(m_handle, &modem_status);
			*((DWORD *)value) = (modem_status & MS_RING_ON) != 0;
			return true;

		case SERIAL_RLSD_STATUS :
			GetCommModemStatus(m_handle, &modem_status);
			*((DWORD *)value) = (modem_status & MS_RLSD_ON) != 0;
			return true;
	}

	return false;
}

void DLL_CALLCONV
CTransportSerial::IncActionCount() {
	boost::mutex::scoped_lock scoped_lock(m_cs);
	++m_action_count;
}

// --------------------------------------------------------
// Instantation function
// --------------------------------------------------------

HRESULT DLL_CALLCONV
SerialCreate(void **iif) {
	CTransportSerial *serial = new CTransportSerial;

	if (serial) {
		*iif = serial;
		return S_OK;
	}

	return E_FAIL;
}

⌨️ 快捷键说明

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