/***************************************************************************
**
** File name : UISERIAL.CPP
** Author:john chow
** Description:
**    Descript the function of serial communication for PIC-SLD
**
**    Finished date: 96.7
**    modifed date:
**
**    Copyright (C) 1995 Microtek International, Inc.
**    All Rights Reserved
**
****************************************************************************/

#include "stdafx.h"

#include "uiserial.h"
#include "conio.h"
#include "abitype.h"
#include "abiextfn.h"
#include "..\initAPI.h"

//implemention of class CWinSerialAgree

CWinSerialAgree::CWinSerialAgree()
{                     
    for(int i=0;i<=COM_PORT_4;i++) {
        char strTmp[10];
        int nTmpID;
        sprintf(strTmp,"COM%01d",i+1);
        nTmpID = OpenComm(strTmp,128,128);
        if (nTmpID <0) SerialInfor[i] = FALSE;
        else {
            SerialInfor[i] = TRUE;
            CloseComm(nTmpID);
        }
    }       
                
    m_nDeviceID = -1;
    m_bRelinkTimes = 0;
 }
 
CWinSerialAgree::~CWinSerialAgree()
{   
    if(m_nDeviceID >= 0) CloseComm(m_nDeviceID);
 }

BOOL CWinSerialAgree::SetSerialOption()
{                       
   /*
   m_DCB.Id = 0x01;
   m_DCB.BaudRate = 0xff18;
   m_DCB.ByteSize = 0x08;
   m_DCB.Parity = 0x00;
   m_DCB.StopBits = 0x00;
   m_DCB.RlsTimeout = 0x0000;
   m_DCB.CtsTimeout = 0x0000;
   m_DCB.DsrTimeout = 0x0000;
   m_DCB.fBinary = 0x0001;
   m_DCB.fRtsDisable = 0x0000;
   m_DCB.fParity = 0x0000;
   m_DCB.fOutxCtsFlow = 0x0001;
   m_DCB.fOutxDsrFlow = 0x0000;
   m_DCB.fDummy = 0x0000;
   m_DCB.fDtrDisable = 0x0000;
   m_DCB.fOutX = 0x0000;
   m_DCB.fInX = 0x0000;
   m_DCB.fPeChar = 0x0000;
   m_DCB.fNull = 0x0000;
   m_DCB.fChEvt = 0x0000;
   m_DCB.fDtrflow = 0x0001;
   m_DCB.fRtsflow = 0x0000;
   m_DCB.fDummy2 = 0x0000;
   m_DCB.XonChar = 0x00;
   m_DCB.XoffChar = 0x00;
   m_DCB.XonLim = XON_LIMIT;
   m_DCB.XoffLim = XOFF_LIMIT;
   m_DCB.PeChar = 0x00;
   m_DCB.EofChar = 0x00;
   m_DCB.EvtChar = 0x00;
   m_DCB.TxDelay = 0x0000;*/
   m_DCB.Id = 0x01;
   m_DCB.BaudRate = 0xff18;
   m_DCB.ByteSize = 0x08;
   m_DCB.Parity = 0x00;
   m_DCB.StopBits = 0x00;
   m_DCB.RlsTimeout = 0x0000;
   m_DCB.CtsTimeout = 0x0000;
   m_DCB.DsrTimeout = 0x0000;
   m_DCB.fBinary = 0x0001;
   m_DCB.fRtsDisable = 0x0000;
   m_DCB.fParity = 0x0000;
   m_DCB.fOutxCtsFlow = 0x0000;
   m_DCB.fOutxDsrFlow = 0x0000;
   m_DCB.fDummy = 0x0000;
   m_DCB.fDtrDisable = 0x0000;
   m_DCB.fOutX = 0x0000;
   m_DCB.fInX = 0x0000;
   m_DCB.fPeChar = 0x0000;
   m_DCB.fNull = 0x0000;
   m_DCB.fChEvt = 0x0000;
   m_DCB.fDtrflow = 0x0000;
   m_DCB.fRtsflow = 0x0000;
   m_DCB.fDummy2 = 0x0000;
   m_DCB.XonChar = 0x00;
   m_DCB.XoffChar = 0x00;
   m_DCB.XonLim = 0x007f;
   m_DCB.XoffLim = 0x007f;
   m_DCB.PeChar = 0x00;
   m_DCB.EofChar = 0x00;
   m_DCB.EvtChar = 0x00;
   m_DCB.TxDelay = 0x0000;

   return TRUE;
 }
 
BOOL CWinSerialAgree::SetSerialPortBaud(BYTE bPortNum,BYTE bBaudRate) 
{                                                
    if(m_nDeviceID>=0) CloseComm(m_nDeviceID);
    m_nDeviceID = -1;
    
    isConnected = FALSE;
    m_isCanBeUsed = FALSE;
    
    switch (bBaudRate) {
        case BAUD_9600  : m_DCB.BaudRate = CBR_9600; break;
        case BAUD_19200 : m_DCB.BaudRate = CBR_19200; break;
        case BAUD_38400 : m_DCB.BaudRate = CBR_38400; break;
        case BAUD_57600 : m_DCB.BaudRate = CBR_56000; break;
        case BAUD_115200: m_DCB.BaudRate = CBR_128000; break;
    }                                         
    
    char strTmp[10];
    int nTmpID;
    sprintf(strTmp,"COM%01d",bPortNum+1);
    nTmpID = OpenComm(strTmp,MAX_BUFFER,MAX_BUFFER);
    if (nTmpID <0) { 
        SerialInfor[bPortNum] = FALSE; 
        m_nError = ERR_OPEN;
        return FALSE; 
    }
    
    m_DCB.Id = (BYTE)nTmpID;                     
    nTmpID = SetCommState(&m_DCB);
    if (nTmpID <0) {
        CloseComm(m_DCB.Id);  
        m_nError = ERR_BAUD;
        return FALSE;
    }   
    
    m_isCanBeUsed = TRUE;
    m_nDeviceID = m_DCB.Id;
    
    m_bBaudRate = bBaudRate;
    m_bPortNum = bPortNum;  
    
    m_nError = m_nDetailError = ERR_NO;
    
    return TRUE;
 }                            
 
BOOL CWinSerialAgree::TryInit()      
{                 
	if (!SetSerialOption()) return FALSE;
    for (char j=BAUD_115200; j>=BAUD_19200; j--) {
        SetSerialPortBaud(m_bPortNum,j);
        BYTE bTmp;
        for (BYTE i=0; i<3; i++) {
            SetTimer(80);
            if(FALSE == SendByte('?')) continue;
            SetTimer(100);
            if(!ReceiveByte(bTmp)) {
                if (ERR_ESC == m_nError) break;
                else continue;
            } else {
                if ('!' == bTmp) {
                    isConnected = TRUE;
                    m_nError = m_nDetailError = ERR_NO;
                    if (ICE_OK == ::emuFwInit())
                    	return TRUE;
                    else {     
            			m_nError = ERR_FWINIT;        	
            			isConnected = FALSE;
                    	return FALSE;
                    }	
                } else return FALSE;
            }    
        }// send '?' and receive '!'      
    }//baud for                    
    
    isConnected = FALSE;
    m_nError = ERR_TRYINIT;
    return FALSE;
	
 }

BOOL CWinSerialAgree::CommInit()
{   
	//read init savings                        
    m_bPortNum = (BYTE)(AfxGetApp()->GetProfileInt("COMM", "Type", COM_PORT_2));
    if(m_bPortNum < COM_PORT_1 || m_bPortNum > COM_PORT_4) {
        m_bPortNum =  COM_PORT_2;    
    }
    
    m_bBaudRate = (BYTE)(AfxGetApp()->GetProfileInt("COMM", "BaudRate",BAUD_115200));
    if(m_bBaudRate < BAUD_9600 || m_bBaudRate > BAUD_115200) {
        m_bBaudRate = BAUD_19200;    
    }                               
    
    BYTE bTmpBaudRate = m_bBaudRate;
    BOOL isAutoBaud = TRUE;                
    if(m_isFirstTime) {           
    	if(!OpenCommunicationDialog(m_bPortNum,m_bBaudRate,isAutoBaud))  {
        	return FALSE;   	            
        }	
    }
    //try to connect to 196 with the settings
    while (TRUE && (!m_isFirstTime)) {
        if (!SetSerialOption()) return FALSE;
        if (SetSerialPortBaud(m_bPortNum,m_bDefaultBaudRate)) {
            if (Init() || TryInit()) {  
                
                BYTE bMaxBaudRate = BAUD_115200;
                if(isAutoBaud) {
                	int x = 5;
	                switch (x) {
	                	case 1 :
	                	case 2 : bMaxBaudRate = BAUD_19200; break;
	                	case 3 : bMaxBaudRate = BAUD_38400; break;
	                	case 4 : bMaxBaudRate = BAUD_57600; break;
	                	case 5 : 
	                	default: bMaxBaudRate = BAUD_115200; break;
	                }	
	                bTmpBaudRate = (bTmpBaudRate > bMaxBaudRate)
	                			   ? bMaxBaudRate : bTmpBaudRate;
	            }            
	            if (m_bBaudRate == bTmpBaudRate) break;
	            
	            m_bBaudRate = bTmpBaudRate;
                                  
                if (ICE_OK != emuSelectBaud(m_bBaudRate)) return FALSE;
                if (SetSerialPortBaud(m_bPortNum,m_bBaudRate) 
                    && Init()) break;  
                if (0 != m_bBaudRate) {
                    m_bBaudRate--;   
                    bTmpBaudRate = m_bBaudRate;
                    continue;
                }    
            }
        }               
        
        if(!m_isRepeat) return FALSE;//used for relink,not for init
        
        m_bPortNum++;
        if (m_bPortNum > COM_PORT_4) m_bPortNum = COM_PORT_1;
        
        
        if(!OpenCommunicationDialog(m_bPortNum,bTmpBaudRate,isAutoBaud)) 
        	return FALSE;   
        	
        
    }
    
    AfxGetApp()->WriteProfileInt("COMM", "Type", m_bPortNum);
    AfxGetApp()->WriteProfileInt("COMM", "BaudRate", m_bBaudRate);
    
    return TRUE;

}

void CWinSerialAgree::IsUnstable()
{ 
	return;
 }
 
 
BOOL CWinSerialAgree::SendByte(BYTE bSend)
{   
    if (!m_isCanBeUsed) {
        m_nError = m_isCanBeUsed;
        return FALSE;
    }
    
    if (1 != WriteComm(m_nDeviceID,&bSend,1)) {   
        m_nError = ERR_FATAL;
        m_nDetailError = GetCommError(m_nDeviceID,&m_ComStatus);
        return FALSE;
    }   
        
    do {
        m_nDetailError = GetCommError(m_nDeviceID,&m_ComStatus);
        if(0 == m_ComStatus.cbOutQue) {
            m_nError = m_nDetailError = ERR_NO;
            return TRUE;                       
        } 
        /*              
        if (IsEscape()) {
            m_nError = ERR_ESC;
            return FALSE;
        } */   
    } while(!IsTimeOut());
    m_nError = ERR_TIME_OUT;
    return FALSE;
 }
 
BOOL CWinSerialAgree::ReceiveByte(BYTE& bReceive)
{                    
    int nTmp;

    if (!m_isCanBeUsed) {
        m_nError = m_isCanBeUsed;
        return FALSE;
    }            
    
    do {
        m_nDetailError = GetCommError(m_nDeviceID,&m_ComStatus);
        if(1 <= m_ComStatus.cbInQue) {
            if (1 == (nTmp = ReadComm(m_nDeviceID,&bReceive,1))) {
                m_nError = m_nDetailError = ERR_NO;
                return TRUE;                       
            }    
            m_nError = ERR_FATAL;
            m_nDetailError = GetCommError(m_nDeviceID,&m_ComStatus);
            return FALSE;
        }  
        /*  
        if (IsEscape()) {
            m_nError = ERR_ESC;
            return FALSE;
        } */   
    } while(!IsTimeOut());
    m_nError = ERR_TIME_OUT;
    return FALSE;
 }
 
BOOL CWinSerialAgree::SendString(BYTE *strSend,int nNum)
{       
    if (!m_isCanBeUsed) {
        m_nError = m_isCanBeUsed;
        return FALSE;
    }            
    
    if (nNum != WriteComm(m_nDeviceID,strSend,nNum)) {   
        m_nError = ERR_FATAL;
        m_nDetailError = GetCommError(m_nDeviceID,&m_ComStatus);
        return FALSE;
    }   
    
    int nTmp = nNum;    
    do {
        m_nDetailError = GetCommError(m_nDeviceID,&m_ComStatus);
        if(0 == m_ComStatus.cbOutQue) {
            m_nError = m_nDetailError = ERR_NO;
            return TRUE;  
        }    
        if(nTmp>m_ComStatus.cbOutQue) {
            RestartTimer();
            nTmp = m_ComStatus.cbOutQue;
        }   
        /* 
        if (IsEscape()) {
            m_nError = ERR_ESC;
            return FALSE;
        } */   
    } while(!IsTimeOut());
    
    m_nError = ERR_TIME_OUT;
    return FALSE;
    
 }
 
BOOL CWinSerialAgree::ReceiveString(BYTE *strReceive,int nNum)
{       
    if (!m_isCanBeUsed) {
        m_nError = m_isCanBeUsed;
        return FALSE;
    }            
    
    int nTmp = 0;
    
    do {
        m_nDetailError = GetCommError(m_nDeviceID,&m_ComStatus);
        
        if(nNum <= m_ComStatus.cbInQue) {
            if (nNum == ReadComm(m_nDeviceID,strReceive,nNum)) {
                m_nError = m_nDetailError = ERR_NO;
                return TRUE;                       
            }    
            m_nError = ERR_FATAL;
            m_nDetailError = GetCommError(m_nDeviceID,&m_ComStatus);
            return FALSE;
        }   
        
        if(nTmp<m_ComStatus.cbInQue) {
            RestartTimer();
            nTmp = m_ComStatus.cbInQue;
        }      
        /*
        if (IsEscape()) {
            m_nError = ERR_ESC;
            return FALSE;
        } */                      
    } while(!IsTimeOut());
    
    FlushBufferIn();
    m_nError = ERR_TIME_OUT;
    return FALSE;
 }
    
BOOL CWinSerialAgree::IsEscape()
{              
	MSG msg;
    WORD wKey = VK_ESCAPE;
    if(PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST,
	PM_NOREMOVE|PM_NOYIELD)) {
	PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST,
	    PM_REMOVE|PM_NOYIELD);
	if(msg.message == WM_KEYDOWN && msg.wParam == wKey) 
	    return  TRUE;        
    }            
    return  FALSE;
 }
 
BOOL CWinSerialAgree::IsRelink()
{                       
	int nYesNo = !IDOK;
	if ( m_isRepeat == FALSE) return FALSE;
	
	
    if (++m_bRelinkTimes >= 2) {
        if ( SELECT_BAUD == *(m_pPipe->GetBuffer()) ) return FALSE;
    	//delay    
	    SetTimer(500); 
	    m_bRelinkTimes = 0;                           
	    while(!IsTimeOut()) {}   
	    
	    CBasePipe* pPipe = new CAbiPipe;
	    pPipe->Copy(*m_pPipe);
	    int nTmpError = m_nError;
	    
	    m_isRepeat  = FALSE;
	    
    	if (!CommInit()) {
    		while (TRUE) {
	    		if( IDOK != OpenAbiComDlg(1) ) {
	    			m_nError = ERR_TIME_OUT;
			    	CloseComm(m_nDeviceID);
			    	m_nDeviceID = -1;
			    	//AfxMessageBox("Communication Failure!!!\n\rPlease exit programe!");
			    	AfxAbort(); 
			    	return FALSE;
	    		}
					
	    		if( CommInit() ) break;
	        }
	    }                   
	    
	    m_isRepeat  = TRUE;
	    m_pPipe->Copy(*pPipe);
	    m_nError = nTmpError;
        return TRUE;      
    } else if (m_bRelinkTimes <= 2) {
    	//delay    
	    SetTimer(500);
	    while(!IsTimeOut()) {}
        return TRUE;      
    } else {      
        if(m_nDeviceID>=0) CloseComm(m_nDeviceID);
    	m_nDeviceID = -1;
//        ExitEpsld();
    }               
     
    return FALSE;

 }
    
void CWinSerialAgree::FlushBufferIn()
{                            
    FlushComm(m_nDeviceID,1);
 }
 
void CWinSerialAgree::FlushBufferOut()
{   
    FlushComm(m_nDeviceID,0);
 }
 
//CWinSerialAgree_196_Diagnostic
BOOL CWinSerialAgree_196_Diagnostic::Do() 
{   
	m_bWaitTime = 0;
	m_isStop = FALSE;
	unsigned long nBackTimeBak = nBackTime;
	nBackTime = 1000;
	
	m_nErrorTime = 0;               
	m_bRelinkTimes = 0;
	while (TRUE) {          
		if (m_nErrorTime > 30) 
			return FALSE;
	    do {
	        if(Shakehand()) break;
	        if(ERR_TIME_OUT != m_nError)
	        	return FALSE;
	        if(!IsRelink()) {
	            m_nError = ERR_RELINKQUIT;
	            m_nDetailError = ERR_SHAKE_HAND;
	            return FALSE;
	        } else break;   
	    } while (TRUE);  
	    
	    if(ERR_TIME_OUT == m_nError) continue;
	    
	    do {         
	        if(SendCommand()) break;
	        if(ERR_RECEIVE_DOLLAR == m_nError ||
	           ERR_RECEIVE_NACK == m_nError) break;
	        if(ERR_TIME_OUT != m_nError) 
	        	return FALSE;
	        if(!IsRelink()) {
	            m_nError = ERR_RELINKQUIT;
	            m_nDetailError = ERR_SEND_COMMAND;
	            return FALSE;
	        } else break;   
	    } while (TRUE);
	    
	    if(ERR_TIME_OUT == m_nError || ERR_RECEIVE_DOLLAR == m_nError
	       || ERR_RECEIVE_NACK == m_nError) continue;
	       
	    do {
	    	while(!Shakehand_()) { 
	        	if(ERR_TIME_OUT != m_nError) return FALSE;
	        	if(++m_bWaitTime >= (nBackTimeBak/1000)) break;
	        	if(m_isStop) {                
	        		m_nError = ICE_ERR_STOP_BY_USER;       
	        		m_nDetailError = ERR_RECEIVE_RESULT;
	        		return FALSE;
	        	}	
	        	TestMessage();
	        }	
	        
	        if(ERR_NO == m_nError) break;            
	        if(!IsRelink()) {
	            m_nError = ERR_RELINKQUIT;    
	            m_nDetailError = ERR_SHAKE_HAND_;
	            return FALSE;
	        } else break;   
	        //if(Shakehand_()) break;
	    } while (TRUE);         
	    
	    if(ERR_TIME_OUT == m_nError) continue;
	                     
	    do {      
	    	
	        if(ReceiveResult()) break;
	        if(ERR_SEND_DOLLAR == m_nError 
	           || ERR_RECEIVE_WRONGCODE == m_nError) break;
	        if(ERR_TIME_OUT != m_nError) 
	        	return FALSE;
	        if(!IsRelink()) {
	            m_nError = ERR_RELINKQUIT;  
	            m_nDetailError = ERR_RECEIVE_RESULT;
	            return FALSE;
	        } else break;   
	    } while (TRUE);
	                     
	    if(ERR_TIME_OUT == m_nError || ERR_SEND_DOLLAR == m_nError
	      || ERR_RECEIVE_WRONGCODE == m_nError ) continue;   
	    
	    return TRUE;
	}   
 }