📄 transportserial.cpp
字号:
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 + -