void OCP_DataStreamInput_Thread::HandleASuccessfulRead( char *szBuf, int nread ) { if(nread > 0) { if((g_total_NMEAerror_messages < g_nNMEADebug) && (g_nNMEADebug > 1000)) { g_total_NMEAerror_messages++; wxString msg; msg.Printf(_T("NMEA activity...%d bytes"), nread); ThreadMessage(msg); } int nchar = nread; char *pb = szBuf; while(nchar) { if(0x0a == *pb) m_nl_found = true; *put_ptr++ = *pb++; if((put_ptr - rx_buffer) > DS_RX_BUFFER_SIZE) put_ptr = rx_buffer; nchar--; } if((g_total_NMEAerror_messages < g_nNMEADebug) && (g_nNMEADebug > 1000)) { g_total_NMEAerror_messages++; wxString msg1 = _T("Buffer is: "); int nc = nread; char *pb = szBuf; while(nc) { msg1.Append(*pb++); nc--; } ThreadMessage(msg1); } } // Found a NL char, thus end of message? if(m_nl_found) { char *tptr; char *ptmpbuf; bool partial = false; while (!partial) { // Copy the message into a temp buffer tptr = tak_ptr; ptmpbuf = temp_buf; while((*tptr != 0x0a) && (tptr != put_ptr)) { *ptmpbuf++ = *tptr++; if((tptr - rx_buffer) > RX_BUFFER_SIZE) tptr = rx_buffer; // wxASSERT_MSG((ptmpbuf - temp_buf) < DS_RX_BUFFER_SIZE, "temp_buf overrun"); } if((*tptr == 0x0a) && (tptr != put_ptr)) // well formed sentence { *ptmpbuf++ = *tptr++; if((tptr - rx_buffer) > DS_RX_BUFFER_SIZE) tptr = rx_buffer; // wxASSERT_MSG((ptmpbuf - temp_buf) < DS_RX_BUFFER_SIZE, "temp_buf overrun"); *ptmpbuf = 0; tak_ptr = tptr; // parse and send the message // wxString str_temp_buf(temp_buf, wxConvUTF8); if(temp_buf[0] == '\r') Parse_And_Send_Posn(&temp_buf[1]); else Parse_And_Send_Posn(temp_buf); } else { partial = true; } } // while !partial } // nl found }
// Entry Point void *OCP_DataStreamInput_Thread::Entry() { bool not_done = true; bool nl_found = false; wxString msg; // Request the com port from the comm manager if ((m_gps_fd = OpenComPortPhysical(m_PortName, m_baud)) < 0) { wxString msg(_T("NMEA input device open failed: ")); msg.Append(m_PortName); ThreadMessage(msg); goto thread_exit; } m_launcher->SetSecThreadActive(); // I am alive // The main loop while((not_done) && (m_launcher->m_Thread_run_flag > 0)) { if(TestDestroy()) not_done = false; // smooth exit // Blocking, timeout protected read of one character at a time // Timeout value is set by c_cc[VTIME] // Storing incoming characters in circular buffer // And watching for new line character // On new line character, send notification to parent char next_byte = 0; ssize_t newdata; newdata = read(m_gps_fd, &next_byte, 1); // read of one char // return (-1) if no data available, timeout #ifdef __WXOSX__ if (newdata < 0 ) wxThread::Sleep(100) ; #endif // Fulup patch for handling hot-plug or wakeup events // from serial port drivers { static int maxErrorLoop; if (newdata > 0) { // we have data, so clear error maxErrorLoop =0; } else { // no need to retry every 1ms when on error sleep (1); // if we have more no character for 5 second then try to reopen the port if (maxErrorLoop++ > 5) { // do not retry for the next 5s maxErrorLoop = 0; // free old unplug current port CloseComPortPhysical(m_gps_fd); // Request the com port from the comm manager if ((m_gps_fd = OpenComPortPhysical(m_PortName, m_baud)) < 0) { // wxString msg(_T("NMEA input device open failed (will retry): ")); // msg.Append(m_PortName); // ThreadMessage(msg); } else { // wxString msg(_T("NMEA input device open on hotplug OK: ")); // msg.Append(m_PortName); // ThreadMessage(msg); } } } } // And process any character if(newdata > 0) { nl_found = false; *put_ptr++ = next_byte; if((put_ptr - rx_buffer) > DS_RX_BUFFER_SIZE) put_ptr = rx_buffer; if(0x0a == next_byte) nl_found = true; // Found a NL char, thus end of message? if(nl_found) { char *tptr; char *ptmpbuf; // Copy the message into a temporary _buffer tptr = tak_ptr; ptmpbuf = temp_buf; while((*tptr != 0x0a) && (tptr != put_ptr)) { *ptmpbuf++ = *tptr++; if((tptr - rx_buffer) > DS_RX_BUFFER_SIZE) tptr = rx_buffer; wxASSERT_MSG((ptmpbuf - temp_buf) < DS_RX_BUFFER_SIZE, (const wxChar *)"temp_buf overrun1"); } if((*tptr == 0x0a) && (tptr != put_ptr)) // well formed sentence { *ptmpbuf++ = *tptr++; if((tptr - rx_buffer) > DS_RX_BUFFER_SIZE) tptr = rx_buffer; wxASSERT_MSG((ptmpbuf - temp_buf) < DS_RX_BUFFER_SIZE, (const wxChar *)"temp_buf overrun2"); *ptmpbuf = 0; tak_ptr = tptr; // Message is ready to parse and send out // Messages may be coming in as <blah blah><lf><cr>. // One example device is KVH1000 heading sensor. // If that happens, the first character of a new captured message will the <cr>, // and we need to discard it. // This is out of spec, but we should handle it anyway if(temp_buf[0] == '\r') Parse_And_Send_Posn(&temp_buf[1]); else Parse_And_Send_Posn(temp_buf); } } //if nl } // if newdata > 0 // Check for any pending output message m_outCritical.Enter(); { bool b_qdata = !out_que.empty(); while(b_qdata){ // Take a copy of message char *qmsg = out_que.front(); char msg[MAX_OUT_QUEUE_MESSAGE_LENGTH]; strncpy( msg, qmsg, MAX_OUT_QUEUE_MESSAGE_LENGTH-1 ); out_que.pop(); free(qmsg); m_outCritical.Leave(); WriteComPortPhysical(m_gps_fd, msg); m_outCritical.Enter(); b_qdata = !out_que.empty(); } //while b_qdata } m_outCritical.Leave(); } // the big while... // Close the port cleanly CloseComPortPhysical(m_gps_fd); thread_exit: m_launcher->SetSecThreadInActive(); // I am dead m_launcher->m_Thread_run_flag = -1; return 0; }
// Entry Point void *OCP_DataStreamInput_Thread::Entry() { bool not_done = true; bool nl_found; wxString msg; // Request the com port from the comm manager if ((m_gps_fd = OpenComPortPhysical(m_PortName, m_baud)) < 0) { wxString msg(_T("NMEA input device open failed: ")); msg.Append(m_PortName); ThreadMessage(msg); goto thread_exit; } m_launcher->SetSecThreadActive(); // I am alive // The main loop while((not_done) && (m_launcher->m_Thread_run_flag > 0)) { if(TestDestroy()) not_done = false; // smooth exit // Blocking, timeout protected read of one character at a time // Timeout value is set by c_cc[VTIME] // Storing incoming characters in circular buffer // And watching for new line character // On new line character, send notification to parent char next_byte = 0; ssize_t newdata; newdata = read(m_gps_fd, &next_byte, 1); // read of one char // return (-1) if no data available, timeout #ifdef __WXOSX__ if (newdata < 0 ) wxThread::Sleep(100) ; #endif // Fulup patch for handling hot-plug or wakeup events // from serial port drivers { static int maxErrorLoop; if (newdata > 0) { // we have data, so clear error maxErrorLoop =0; } else { // no need to retry every 1ms when on error sleep (1); // if we have more no character for 5 second then try to reopen the port if (maxErrorLoop++ > 5) { // do not retry for the next 5s maxErrorLoop = 0; // free old unplug current port CloseComPortPhysical(m_gps_fd); // Request the com port from the comm manager if ((m_gps_fd = OpenComPortPhysical(m_PortName, m_baud)) < 0) { // wxString msg(_T("NMEA input device open failed (will retry): ")); // msg.Append(m_PortName); // ThreadMessage(msg); } else { wxString msg(_T("NMEA input device open on hotplug OK: ")); msg.Append(m_PortName); ThreadMessage(msg); } } } } // And process any character if(newdata > 0) { nl_found = false; *put_ptr++ = next_byte; if((put_ptr - rx_buffer) > DS_RX_BUFFER_SIZE) put_ptr = rx_buffer; if(0x0a == next_byte) nl_found = true; // Found a NL char, thus end of message? if(nl_found) { char *tptr; char *ptmpbuf; // Copy the message into a temporary _buffer tptr = tak_ptr; ptmpbuf = temp_buf; while((*tptr != 0x0a) && (tptr != put_ptr)) { *ptmpbuf++ = *tptr++; if((tptr - rx_buffer) > DS_RX_BUFFER_SIZE) tptr = rx_buffer; wxASSERT_MSG((ptmpbuf - temp_buf) < DS_RX_BUFFER_SIZE, (const wxChar *)"temp_buf overrun1"); } if((*tptr == 0x0a) && (tptr != put_ptr)) // well formed sentence { *ptmpbuf++ = *tptr++; if((tptr - rx_buffer) > DS_RX_BUFFER_SIZE) tptr = rx_buffer; wxASSERT_MSG((ptmpbuf - temp_buf) < DS_RX_BUFFER_SIZE, (const wxChar *)"temp_buf overrun2"); *ptmpbuf = 0; tak_ptr = tptr; // Message is ready to parse and send out wxString str_temp_buf(temp_buf, wxConvUTF8); Parse_And_Send_Posn(str_temp_buf); } } //if nl } // if newdata > 0 // Check for any pending output message if( m_pout_mutex && (wxMUTEX_NO_ERROR == m_pout_mutex->TryLock()) ){ bool b_qdata = (m_takIndex != (-1) || m_putIndex != (-1)); while(b_qdata){ if(m_takIndex < OUT_QUEUE_LENGTH) { // Take a copy of message char msg[MAX_OUT_QUEUE_MESSAGE_LENGTH]; strncpy( msg, m_poutQueue[m_takIndex], MAX_OUT_QUEUE_MESSAGE_LENGTH-1 ); // Update and release the taker index if(m_takIndex==m_putIndex) m_takIndex=m_putIndex=(-1); else if(m_takIndex == (OUT_QUEUE_LENGTH-1) ) m_takIndex=0; else m_takIndex++; m_pout_mutex->Unlock(); WriteComPortPhysical(m_gps_fd, msg); if( wxMUTEX_NO_ERROR == m_pout_mutex->TryLock() ) b_qdata = (m_takIndex != (-1) || m_putIndex != (-1)); else b_qdata = false; } else { // some index error m_takIndex = (-1); m_putIndex = (-1); b_qdata = false; } } //while b_qdata m_pout_mutex->Unlock(); } bail_output: bool bail = true; } // the big while... // Close the port cleanly CloseComPortPhysical(m_gps_fd); thread_exit: m_launcher->SetSecThreadInActive(); // I am dead m_launcher->m_Thread_run_flag = -1; return 0; }
// Entry Point void *OCP_DataStreamInput_Thread::Entry() { wxString msg; bool not_done; HANDLE hSerialComm = (HANDLE)(-1); // Request the com port from the comm manager if ((m_gps_fd = OpenComPortPhysical(m_PortName, m_baud)) < 0) { wxString msg(_T("NMEA input device open failed: ")); msg.Append(m_PortName); wxString msg_error; msg_error.Printf(_T("...GetLastError(): %d"), GetLastError()); msg.Append(msg_error); ThreadMessage(msg); goto thread_exit; } m_launcher->SetSecThreadActive(); // I am alive hSerialComm = (HANDLE)m_gps_fd; // If port supports output, set a short timeout so that output polling mechanism works int max_timeout = 5; int loop_timeout = 2000; int n_reopen_wait = 2000; if( (m_io_select == DS_TYPE_INPUT_OUTPUT) || (m_io_select == DS_TYPE_OUTPUT) ) { loop_timeout = 2; max_timeout = 5000; } COMMTIMEOUTS timeouts; timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; timeouts.ReadTotalTimeoutConstant = loop_timeout; timeouts.WriteTotalTimeoutMultiplier = MAXDWORD; timeouts.WriteTotalTimeoutConstant = MAXDWORD; if (!SetCommTimeouts((HANDLE)m_gps_fd, &timeouts)) // Error setting time-outs. goto thread_exit; not_done = true; bool nl_found; #define READ_BUF_SIZE 200 char szBuf[READ_BUF_SIZE]; DWORD dwRead; DWORD dwOneRead; char chRead; int ic; int n_timeout; // The main loop while((not_done) && (m_launcher->m_Thread_run_flag > 0)) { if(TestDestroy()) not_done = false; // smooth exit // Was port closed due to error condition? while(!m_gps_fd) { if((TestDestroy()) || (m_launcher->m_Thread_run_flag == 0)) goto thread_exit; // smooth exit if(n_reopen_wait) { wxThread::Sleep(n_reopen_wait); // stall for a bit n_reopen_wait = 0; } if ((m_gps_fd = OpenComPortPhysical(m_PortName, m_baud)) > 0) { hSerialComm = (HANDLE)m_gps_fd; if(!SetCommMask((HANDLE)m_gps_fd, EV_RXCHAR)) // Setting Event Type goto thread_exit; COMMTIMEOUTS timeouts; timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; timeouts.ReadTotalTimeoutConstant = loop_timeout; timeouts.WriteTotalTimeoutMultiplier = MAXDWORD; timeouts.WriteTotalTimeoutConstant = MAXDWORD; if (!SetCommTimeouts((HANDLE)m_gps_fd, &timeouts)) // Error setting time-outs. goto thread_exit; } else { m_gps_fd = NULL; wxThread::Sleep(2000); // stall for a bit } } bool b_inner = true; bool b_sleep = false; dwRead = 0; n_timeout = 0; wxDateTime now = wxDateTime::Now(); int t = now.GetTicks(); // set a separate timer not controlled by serial port ic=0; while( b_inner ) { if( m_pout_mutex && (wxMUTEX_NO_ERROR == m_pout_mutex->TryLock()) ){ bool b_qdata = (m_takIndex != (-1) || m_putIndex != (-1)); while(b_qdata){ if(m_takIndex < OUT_QUEUE_LENGTH) { // Take a copy of message char msg[MAX_OUT_QUEUE_MESSAGE_LENGTH]; strncpy( msg, m_poutQueue[m_takIndex], MAX_OUT_QUEUE_MESSAGE_LENGTH-1 ); // Update and release the taker index if(m_takIndex==m_putIndex) m_takIndex=m_putIndex=(-1); else if(m_takIndex == (OUT_QUEUE_LENGTH-1) ) m_takIndex=0; else m_takIndex++; m_pout_mutex->Unlock(); WriteComPortPhysical(m_gps_fd, msg); if( wxMUTEX_NO_ERROR == m_pout_mutex->TryLock() ) b_qdata = (m_takIndex != (-1) || m_putIndex != (-1)); else b_qdata = false; } else { // some index error m_takIndex = (-1); m_putIndex = (-1); b_qdata = false; } } //while b_qdata m_pout_mutex->Unlock(); } // Mutex lock if( b_sleep ) // we need a sleep if the serial port does not honor commtimeouts wxSleep(1); if(ReadFile((HANDLE)m_gps_fd, &chRead, 1, &dwOneRead, NULL)) { if(1 == dwOneRead) { b_sleep = false; szBuf[ic] = chRead; dwRead++; if(++ic > READ_BUF_SIZE - 1) goto HandleASuccessfulRead; if(chRead == 0x0a) goto HandleASuccessfulRead; } else { // timed out n_timeout++;; if( n_timeout > max_timeout ) { bool b_close = true; // If the port is input only, double check the timeout // We do this since some virtual serial port emulators // do not seem to honor SetCommTimeouts() function if( m_io_select == DS_TYPE_INPUT ) { wxDateTime then = wxDateTime::Now(); int tt = then.GetTicks(); if( (tt - t) < (max_timeout * loop_timeout)/1000 ) { b_close = false; n_timeout = 0; b_sleep = true; } } if( b_close ) { b_inner = false; CloseComPortPhysical(m_gps_fd); m_gps_fd = NULL; dwRead = 0; nl_found = false; n_reopen_wait = 2000; } } else if((TestDestroy()) || (m_launcher->m_Thread_run_flag == 0)) { goto thread_exit; // smooth exit } } } else { // ReadFile Erorr b_inner = false; CloseComPortPhysical(m_gps_fd); m_gps_fd = NULL; dwRead = 0; nl_found = false; n_reopen_wait = 2000; } } HandleASuccessfulRead: if(dwRead > 0) { if((g_total_NMEAerror_messages < g_nNMEADebug) && (g_nNMEADebug > 1000)) { g_total_NMEAerror_messages++; wxString msg; msg.Printf(_T("NMEA activity...%d bytes"), dwRead); ThreadMessage(msg); } int nchar = dwRead; char *pb = szBuf; while(nchar) { if(0x0a == *pb) nl_found = true; *put_ptr++ = *pb++; if((put_ptr - rx_buffer) > DS_RX_BUFFER_SIZE) put_ptr = rx_buffer; nchar--; } if((g_total_NMEAerror_messages < g_nNMEADebug) && (g_nNMEADebug > 1000)) { g_total_NMEAerror_messages++; wxString msg1 = _T("Buffer is: "); int nc = dwRead; char *pb = szBuf; while(nc) { msg1.Append(*pb++); nc--; } ThreadMessage(msg1); } } // Found a NL char, thus end of message? if(nl_found) { char *tptr; char *ptmpbuf; bool partial = false; while (!partial) { // Copy the message into a temp buffer tptr = tak_ptr; ptmpbuf = temp_buf; while((*tptr != 0x0a) && (tptr != put_ptr)) { *ptmpbuf++ = *tptr++; if((tptr - rx_buffer) > RX_BUFFER_SIZE) tptr = rx_buffer; // wxASSERT_MSG((ptmpbuf - temp_buf) < DS_RX_BUFFER_SIZE, "temp_buf overrun"); } if((*tptr == 0x0a) && (tptr != put_ptr)) // well formed sentence { *ptmpbuf++ = *tptr++; if((tptr - rx_buffer) > DS_RX_BUFFER_SIZE) tptr = rx_buffer; // wxASSERT_MSG((ptmpbuf - temp_buf) < DS_RX_BUFFER_SIZE, "temp_buf overrun"); *ptmpbuf = 0; tak_ptr = tptr; // parse and send the message wxString str_temp_buf(temp_buf, wxConvUTF8); Parse_And_Send_Posn(str_temp_buf); } else { partial = true; } } // while !partial } // nl found } // the big while... thread_exit: // Close the port cleanly CloseComPortPhysical(m_gps_fd); m_launcher->SetSecThreadInActive(); // I am dead m_launcher->m_Thread_run_flag = -1; return 0; }
void *OCP_DataStreamInput_Thread::Entry() { bool not_done = true; bool nl_found = false; wxString msg; // Request the com port from the comm manager if (!OpenComPortPhysical(m_PortName, m_baud)) { wxString msg(_T("NMEA input device open failed: ")); msg.Append(m_PortName); ThreadMessage(msg); //goto thread_exit; // This means we will not be trying to connect = The device must be connected when the thread is created. Does not seem to be needed/what we want as the reconnection logic is able to pick it up whenever it actually appears (Of course given it appears with the expected device name). } m_launcher->SetSecThreadActive(); // I am alive // The main loop static size_t retries = 0; while((not_done) && (m_launcher->m_Thread_run_flag > 0)) { if(TestDestroy()) not_done = false; // smooth exit uint8_t next_byte = 0; size_t newdata = -1; if( m_serial.isOpen() ) { try { newdata = m_serial.read(&next_byte, 1); } catch (std::exception &e) { //std::cerr << "Serial read exception: " << e.what() << std::endl; if(10 < retries++) { // We timed out waiting for the next character 10 times, let's close the port so that the reconnection logic kicks in and tries to fix our connection. CloseComPortPhysical(); retries = 0; } } } else { // Reconnection logic. Let's try to reopen the port while waiting longer every time (until we simply keep trying every 2.5 seconds) //std::cerr << "Serial port seems closed." << std::endl; wxMilliSleep(250 * retries); CloseComPortPhysical(); if(OpenComPortPhysical(m_PortName, m_baud)) retries = 0; else if(retries < 10) retries++; } if(newdata == 1) { nl_found = false; *put_ptr++ = next_byte; if((put_ptr - rx_buffer) > DS_RX_BUFFER_SIZE) put_ptr = rx_buffer; if(0x0a == next_byte) nl_found = true; // Found a NL char, thus end of message? if(nl_found) { char *tptr; char *ptmpbuf; // Copy the message into a temporary _buffer tptr = tak_ptr; ptmpbuf = temp_buf; while((*tptr != 0x0a) && (tptr != put_ptr)) { *ptmpbuf++ = *tptr++; if((tptr - rx_buffer) > DS_RX_BUFFER_SIZE) tptr = rx_buffer; wxASSERT_MSG((ptmpbuf - temp_buf) < DS_RX_BUFFER_SIZE, (const wxChar *)L"temp_buf overrun1"); } if((*tptr == 0x0a) && (tptr != put_ptr)) // well formed sentence { *ptmpbuf++ = *tptr++; if((tptr - rx_buffer) > DS_RX_BUFFER_SIZE) tptr = rx_buffer; wxASSERT_MSG((ptmpbuf - temp_buf) < DS_RX_BUFFER_SIZE, (const wxChar *)L"temp_buf overrun2"); *ptmpbuf = 0; tak_ptr = tptr; // Message is ready to parse and send out // Messages may be coming in as <blah blah><lf><cr>. // One example device is KVH1000 heading sensor. // If that happens, the first character of a new captured message will the <cr>, // and we need to discard it. // This is out of spec, but we should handle it anyway if(temp_buf[0] == '\r') Parse_And_Send_Posn(&temp_buf[1]); else Parse_And_Send_Posn(temp_buf); } } //if nl } // if newdata > 0 // Check for any pending output message bool b_qdata = !out_que.empty(); while(b_qdata){ // Take a copy of message char *qmsg = out_que.front(); out_que.pop(); //m_outCritical.Leave(); char msg[MAX_OUT_QUEUE_MESSAGE_LENGTH]; strncpy( msg, qmsg, MAX_OUT_QUEUE_MESSAGE_LENGTH-1 ); free(qmsg); if( static_cast<size_t>(-1) == WriteComPortPhysical(msg) && 10 < retries++ ) { // We failed to write the port 10 times, let's close the port so that the reconnection logic kicks in and tries to fix our connection. retries = 0; CloseComPortPhysical(); } b_qdata = !out_que.empty(); } //while b_qdata } thread_exit: CloseComPortPhysical(); m_launcher->SetSecThreadInActive(); // I am dead m_launcher->m_Thread_run_flag = -1; return 0; }