//    Entry Point
void *OCP_DataStreamInput_Thread::Entry()
{
    wxString msg;
    OVERLAPPED osReader = {0};
    OVERLAPPED osWriter = {0};
    
    m_launcher->SetSecThreadActive();               // I am alive
    
    wxSleep(1);         //  allow Bluetooth SPP connections to re-cycle after the parent's test for existence.
                        //  In the MS Bluetooth stack, there is apparently a minimum time required
                        //  between CloseHandle() and CreateFile() on the same port.
                        // FS#1008

    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 initial open failed: "));
        msg.Append(m_PortName);
        wxString msg_error;
        msg_error.Printf(_T("...GetLastError():  %d"), GetLastError());
        msg.Append(msg_error);

        ThreadMessage(msg);
        m_gps_fd = NULL;
//        goto thread_exit;
    }

    hSerialComm = (HANDLE)m_gps_fd;

    int n_reopen_wait = 2000;
    
    COMMTIMEOUTS timeouts;

    //  Short read timeout for faster response
    timeouts.ReadIntervalTimeout = 1;
    timeouts.ReadTotalTimeoutMultiplier = 0;
    timeouts.ReadTotalTimeoutConstant = 0;
    timeouts.WriteTotalTimeoutMultiplier = 0;
    timeouts.WriteTotalTimeoutConstant = 500; 
    
    
    if(m_gps_fd){
        if (!SetCommTimeouts(hSerialComm, &timeouts)){ // Error setting time-outs.
            CloseComPortPhysical(m_gps_fd);
            m_gps_fd = NULL;
        }            
    }

      // Create the reader overlapped event.
    osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    // Create the writer overlapped event.
    osWriter.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    
      
    not_done = true;

#define READ_BUF_SIZE 200
    char szBuf[READ_BUF_SIZE];
    
#define READ_TIMEOUT      50      // milliseconds
    
    DWORD dwRead;
    DWORD dwWritten;
    DWORD dwRes;
    DWORD dwToWrite;

    int n_timeout = 0;
    int max_timeout = 100;
    
    bool fWaitingOnRead = false;
    bool fWaitingOnWrite = false;
    
    
//    The main loop

    while(not_done)
    {
        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){
                int nrwd10 = wxMax(1, n_reopen_wait /10);

                while(n_reopen_wait > 0){
                    wxThread::Sleep(nrwd10);                        // stall for a bit
                    
                    if((TestDestroy()) || (m_launcher->m_Thread_run_flag == 0))
                        goto thread_exit;                               // smooth exit
                    
                    n_reopen_wait -= nrwd10;
                }
                        
                n_reopen_wait = 0;
            }


            if ((m_gps_fd = OpenComPortPhysical(m_PortName, m_baud)) > 0)
            {
                hSerialComm = (HANDLE)m_gps_fd;

                wxThread::Sleep(100);                        // stall for a bit
                
                if (!SetCommTimeouts(hSerialComm, &timeouts)){ // Error setting time-outs.
                      int errt = GetLastError();                // so just retry
                      CloseComPortPhysical(m_gps_fd);
                      m_gps_fd = NULL;
                      
                }
                
                fWaitingOnWrite = FALSE;
                fWaitingOnRead = FALSE;
                n_timeout = 0;
                
            }
            else
            {
                m_gps_fd = 0;
                
                int nwait = 2000;
                while(nwait > 0){
                    wxThread::Sleep(200);                        // stall for a bit
                    
                    if((TestDestroy()) || (m_launcher->m_Thread_run_flag == 0))
                        goto thread_exit;                               // smooth exit
                        
                    nwait -= 200;
                }
            }
        }

        if( (m_io_select == DS_TYPE_INPUT_OUTPUT) || (m_io_select == DS_TYPE_OUTPUT) ) {
                m_outCritical.Enter();
                bool b_qdata = !out_que.empty();
                    
                bool b_break = false;
                while(!b_break && b_qdata){
                    char msg[MAX_OUT_QUEUE_MESSAGE_LENGTH];
                    
//                    printf("wl %d\n", out_que.size());
                    {
                        
                        if(fWaitingOnWrite){
//                            printf("wow\n");
                            dwRes = WaitForSingleObject(osWriter.hEvent, INFINITE);
                            
                            switch(dwRes)
                            {
                                case WAIT_OBJECT_0:
                                    if (!GetOverlappedResult(hSerialComm, &osWriter, &dwWritten, FALSE)) {
                                        if (GetLastError() == ERROR_OPERATION_ABORTED){
                                            //    UpdateStatus("Write aborted\r\n");
                                        }
                                        else{
                                            b_break = true;
                                        }
                                    }
                                    
                                    if (dwWritten != dwToWrite) {
                                        //ErrorReporter("Error writing data to port (overlapped)");
                                    }
                                    else {
                                        // Delayed write completed
                                        fWaitingOnWrite = false;
//                                        printf("-wow\n");
                                    }
                                    break;
                                    
                                //                
                                // wait timed out
                                //
                                case WAIT_TIMEOUT:
                                    break;
                                    
                                case WAIT_FAILED:
                                default:
                                    break;
                            }
                            
                        }
                        if(!fWaitingOnWrite){          // not waiting on Write, OK to issue another
                        
                        //  Take a copy of message
                            char *qmsg = out_que.front();
                            strncpy( msg, qmsg, MAX_OUT_QUEUE_MESSAGE_LENGTH-1 );
                            out_que.pop();
                            free(qmsg);
 
                            dwToWrite = strlen(msg);
                            //
                            // issue write
                            //
                            n_timeout = 0;
                            
//                            printf("w\n");
                            if (!WriteFile(hSerialComm, msg, dwToWrite, &dwWritten, &osWriter)) {
                                if (GetLastError() == ERROR_IO_PENDING) { 
                                //
                                // write is delayed
                                //
                                    fWaitingOnWrite = true;
//                                    printf("+wow\n");
                                }
                                else{
                                    b_break = true;
                                }
                            }
                            else {
                            //
                            // writefile returned immediately
                            //
                            }

                            b_qdata = !out_que.empty();
                            
                        }
                    }
                    
                } //while b_qdata
                

            
                m_outCritical.Leave();
        }
        
        
        //
        // if no read is outstanding, then issue another one
        //
//        printf("r\n");
        if (!fWaitingOnRead) {
            if (!ReadFile(hSerialComm, szBuf, READ_BUF_SIZE, &dwRead, &osReader)) {
                if (GetLastError() != ERROR_IO_PENDING) {  // read not delayed?
                        CloseComPortPhysical(m_gps_fd);
                        m_gps_fd = NULL;
                        fWaitingOnRead = FALSE;
                        n_reopen_wait = 2000;
                }
                else
                    fWaitingOnRead = TRUE;
            }
            else {    // read completed immediately
                n_timeout = 0;
                
                if (dwRead)
                    HandleASuccessfulRead(szBuf, dwRead);
            }
        }
        
        //
        // wait for pending operations to complete
        //
        if ( fWaitingOnRead ) {
            dwRes = WaitForSingleObject(osReader.hEvent, READ_TIMEOUT);
            
            switch(dwRes)
            {
                //
                // read completed
                //
                case WAIT_OBJECT_0:
                    if (!GetOverlappedResult(hSerialComm, &osReader, &dwRead, FALSE)) {
                        int err = GetLastError();
                        if (GetLastError() == ERROR_OPERATION_ABORTED){
                        }
                        else{
                                //      Some other error
                            n_reopen_wait = 2000;
                            CloseComPortPhysical(m_gps_fd);
                            m_gps_fd = 0;
                        }
                    }
                    else {      // read completed successfully
                        if (dwRead)
                            HandleASuccessfulRead(szBuf, dwRead);
                    }
                    
                    fWaitingOnRead = FALSE;
                    n_timeout = 0;
                    
                    break;
                    
                case WAIT_TIMEOUT:
                    n_timeout++;
                        
                    break;                       
                    
                default:                // error of some kind with handles
                    fWaitingOnRead = FALSE;
                    break;
            }
        }
        
        if(m_launcher->m_Thread_run_flag <= 0)
            not_done = false;
        
    }           // 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;

}
//    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;
}