#include "stdafx.h" #include "compatibility.h" #include "debugdisplayunit.h" #include "propserial.h" #include "globalunit.h" #include "ComThread.h" extern CPropellerDebug P2; #define DEBUG_SERIAL_TX 1 #define HARDWARE_MISMATCH (1) #define HARDWARE_UNRESPONSIVE (2) static char HexChr[16] = { 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, 0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46 }; static char Base64Chr[64] = { 0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C, 0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A, 0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E, 0x6F,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A, 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x2B,0x2F }; prop_serial::prop_serial() { m_strCommId = _T("NOT CONFIGURED"); m_strVersion = _T("NOT AVAILABLE"); m_cVersion = '?'; m_iPortId = 0; m_hCommHandle = NULL; m_hEventRx = CreateEvent (NULL,TRUE,FALSE,_T("RxData")); memset((void*)&m_overlap,0,sizeof(OVERLAPPED)); m_overlap.hEvent = m_hEventRx; reset_buffers(); reset_flags(); } int prop_serial::GetComPortNumber() { int portId; portId = m_iPortId; return portId; } // Return comm port string void prop_serial::make_com_string(int id) { CString result; result.Format(_T("COM%d"),id); m_strCommId = result;; } // Wait milliseconds void prop_serial::Waitms(int ms) { Sleep(ms); } void prop_serial::reset_buffers() { m_dwTxBuffPos = 0; m_dwBytesWritten = 0; m_dwBytesRead = 0; m_dwBytesRead = 0; m_dwRxBuffStart = 0; m_dwRxBuffEnd = 0; m_iErrorCount = 0; m_dwLastError = 0; } void prop_serial::reset_flags () { m_bCommOpen = false; m_bDebugActive = false; m_bVersionMode = false; m_bAbortMode = false; m_bFatalError = false; } void prop_serial::reset_dcb (LPDCB pDCB) { // get the current command state and the // write it back after making any needed changes BuildCommDCB(_T(_DEFAULT_PORT_SPEED_),pDCB); ASSERT (m_hCommHandle); SetCommState(m_hCommHandle,pDCB); GetCommState(m_hCommHandle,pDCB); pDCB->BaudRate=3000000; pDCB->fDtrControl=0; pDCB->fRtsControl=0; pDCB->ByteSize=8; pDCB->fBinary=1; pDCB->fTXContinueOnXoff=1; pDCB->XoffLim=512; pDCB->XonLim=2048; pDCB->XonChar=17; pDCB->XoffChar=19; CComThread::OutputDebugString ("\r\nResetting Flags."); SetCommState(m_hCommHandle,pDCB); } void prop_serial::reset_com_timeouts () { // likewise, fiddle with the CommTimouts COMMTIMEOUTS CommTimeouts; int ReadIntervalTimeout = MAXDWORD; int ReadTotalTimeoutMultiplier = 0; int ReadTotalTimeoutConstant = 0; int WriteTotalTimeoutMultiplier = 0; int WriteTotalTimeoutConstant = 0; CComThread::OutputDebugString ("\r\nResetting COM Timeoouts."); GetCommTimeouts(m_hCommHandle,&CommTimeouts); CommTimeouts.ReadIntervalTimeout = ReadIntervalTimeout; CommTimeouts.ReadTotalTimeoutConstant = ReadTotalTimeoutMultiplier; CommTimeouts.ReadTotalTimeoutMultiplier = ReadTotalTimeoutMultiplier; CommTimeouts.WriteTotalTimeoutConstant = WriteTotalTimeoutConstant; CommTimeouts.WriteTotalTimeoutMultiplier = WriteTotalTimeoutMultiplier; SetCommTimeouts(m_hCommHandle, &CommTimeouts); } void prop_serial::flush_rx (bool z) { // purge any previously-received bytes&clear any break PurgeComm(m_hCommHandle, PURGE_RXCLEAR); PurgeComm(m_hCommHandle, PURGE_TXCLEAR); for (int rcount=0;rcount<2;rcount++) { int count=0; do { RxComm(); count++; } while (m_dwBytesRead!=0); CComThread::OutputDebugString ("\r\nCalled RxComm %d times.",count++); Waitms(10); } // if parameter is true - also write zeroes to the // recieve buffer if (z==true) { memset(m_pRxBuff,0,RxBuffSize); reset_buffers(); } } // Reset hardware bool prop_serial::reset_hardware() { BOOL res; CComThread::OutputDebugString ("\r\nResetting Hardware on COM%d",m_iPortId); m_iErrorCount = 0; m_bFatalError = false; // generate reset pulse via dtr&wait 25ms Waitms(10); res = EscapeCommFunction(m_hCommHandle, SETDTR); Waitms(10); res = EscapeCommFunction(m_hCommHandle, CLRDTR); Waitms(10); if (m_hCommHandle==NULL) return false; flush_rx (true); CComThread::OutputDebugString ("\r\nReset COM%d Completed. (SET/CLEAR DTR)",m_iPortId); return res; } ///////////////////// // Comm Routines // ///////////////////// // Open comm port bool prop_serial::open_com() { if (m_hCommHandle!=NULL) close_com(); CString str; m_bCommOpen = false; str = _T("\\\\.\\"); str.Append(m_strCommId); m_hCommHandle = CreateFile(str, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, // FILE_FLAG_OVERLAPPED, 0); DWORD dwError; dwError = GetLastError(); if (dwError==ERROR_ACCESS_DENIED) { ASSERT(false); return false; } if ((dwError==ERROR_FILE_NOT_FOUND) ||(m_hCommHandle==INVALID_HANDLE_VALUE)) { CComThread::OutputDebugString ("\r\nUanable to Open COM%d:",m_iPortId); if (m_iPortId==3) ASSERT(false); return false; } CComThread::OutputDebugString ("\r\nprop_serial::OpenCom COM%d:",m_iPortId); LPDCB pDCB = &m_CommDCB; reset_dcb (pDCB); reset_com_timeouts (); reset_buffers (); reset_flags (); return true; } // Comm error void prop_serial::CommError(CString msg) { CString str; m_iErrorCount++; str = msg; str.Append(_T(" ")); str.Append(m_strCommId); str.Append(_T("\n")); TRACE(msg); if (m_iErrorCount>16) { ASSERT(false); throw (msg); } if (m_bCommOpen) close_com(); if (m_bAbortMode==true) { /// result = AfxMessageBox(str,IDOK,0); Abort(); } } // Close comm port bool prop_serial::close_com () { BOOL res; CComThread::OutputDebugString ("\r\nprop_serial::CloseComm: %08x",(DWORD)m_hCommHandle); // Your milage may vary depending on OS version. Not // responsible for lost dog, missed bus transfer, ballots // cast or counted for the wrong candidate. #if 0 ASSERT(m_hCommHandle!=NULL); #endif if (m_hCommHandle==NULL) return true; #if 0 ASSERT(m_hCommHandle!=INVALID_HANDLE_VALUE); #endif if (m_hCommHandle==INVALID_HANDLE_VALUE) { m_hCommHandle=NULL; return true; } res = CloseHandle(m_hCommHandle); m_hCommHandle = INVALID_HANDLE_VALUE; if (res==0) { CComThread::OutputDebugString ("\r\nCLOSE HANDLE UNKNOWN ERROR"); } m_bCommOpen = false; return true; } ///////////////////////// // Hardware Routines // ///////////////////////// void prop_serial::Abort () { CComThread::OutputDebugString ("\r\nprop_serial::Abort() ... COM port ERROR"); } bool prop_serial::open_forth () { bool res; m_bAbortMode = false; res = open_com (); if(res==false) return false; reset_hardware(); CComThread::OutputDebugString( "\r\nTransmitting PROPELLER_BAUD_RATE_SYNC on COM%d:",m_iPortId); TxString(PROPELLER_BAUD_RATE_SYNC); CComThread::OutputDebugString( "\r\nTransmitting LOAD_FORTH command on COM%d:",m_iPortId); TxString(PROPELLER_FORTH); TxComm(); m_bCommOpen=true; return true; } bool prop_serial::version_check() { CString s, ver; ver.AppendChar(char(13)); ver.AppendChar(char(10)); ver.Append(_T("Prop_Ver X")); ver.AppendChar(char(13)); ver.AppendChar(char(10)); CComThread::OutputDebugString ("\r\nprop_serial::version_check on COM%d:",m_iPortId); // assmuing that we have jusst successfully // opened a com port and flashed the DTR/RTS // lines, now probe for P2 hardware on the // detected and hopefully open port. CComThread::OutputDebugString( "\r\nTransmitting \"> Prop_Chk 0 0 0 0 \" on COM%d:",m_iPortId); TxString(PROPELLER_BAUD_RATE_SYNC); TxString(PROPELLER_CHECK_STRING); TxComm(); // receive version string s = _T(""); for (int i=1;i<=14;i++) { char c = (char)RxByte(); #if 0 CComThread::OutputDebugString( "\r\nP2 Reading version check RxByte returning: '%c'",c); #endif s.AppendChar(c); } m_strVersion = s; m_cVersion = char(s[11]); s.SetAt(11,'X'); // if we made it this far - then is there // something sending us data? CComThread::OutputDebugString ("\r\nHardware Found on COM%d.",m_iPortId); if (s.Compare(ver)!=0) return false; else return true; } bool prop_serial::HardwareFound() { bool result; m_bCommOpen=false; try { result = false; m_bAbortMode = false; result = open_com (); if(result==false) return false; reset_hardware(); result = version_check (); if (result==false) { throw((int)HARDWARE_MISMATCH); } m_bCommOpen = true; m_bAbortMode = true; result = true; } catch(int) { // error, result is false, allow abort CommError(_T("\r\nHardware Type MISMATCH:")); CComThread::OutputDebugString ("\r\nHardware Type MISMATCH:"); m_bAbortMode = true; close_com (); result = false; } return result; } bool prop_serial::detect_hardware() { int i, FirstPort; // check com99..com1 for hardware FirstPort = m_iPortId; for (i=100;i>0;i--) { if (i!=100) m_iPortId = i; make_com_string(m_iPortId); if ((i==100)||(i!=FirstPort)) { if (HardwareFound()) return true; } } m_iPortId = 99; CommError(_T("\r\nNo hardware found on COM1 through")); return false; } // Get hardware version bool prop_serial::set_version_string () { CString s,str; s = _T("Unknown."); if (m_cVersion==char('A')) s = _T("FPGA-8 cogs, 512KB hub, 48 smart pins 63..56, 39..0, 80MHz."); else if (m_cVersion==char('B')) s = _T("FPGA-4 cogs, 256KB hub, 12 smart pins 63..60/7..0, 80MHz."); else if (m_cVersion==char('C')) s = _T("unsupported"); //1 cog, 32KB hub, 8 smart pins 63..62/5..0, 80MHz, No CORDIC'; else if (m_cVersion==char('D')) s = _T("unsupported"); //1 cog, 128KB hub, 7 smart pins 63..62/4..0, 80MHz, No CORDIC'; if (m_cVersion==char('E')) s = _T("FPGA-4 cogs, 512KB hub, 18 smart pins 63..62/15..0, 80MHz."); if (m_cVersion==char('F')) s = _T("unsupported"); //16 cogs, 1024KB hub, 7 smart pins 63..62/33..32/2..0, 80MHz'; if (m_cVersion==char('G')) s = _T("P2X8C4M64P Rev B/C-8 cogs, 512KB hub, 64 smart pins."); m_strVersion = s; return true; } // Load Hardware void prop_serial::LoadHardware() { CString msg; CString iTemp; int LoadLimit, i, n; int m = 0; // find hardware m_bVersionMode = false; detect_hardware (); // check version if ((m_cVersionchar('G'))) { msg = _T("Invalid Hardware Version: "); msg.AppendChar(m_cVersion); msg.Append(_T(" Found on")); CommError(msg); } // update progress form // ProgressForm.StatusLabel = _T("\r\nLoading RAM"); // ProgressForm.StatusLabel.Repaint(); // cap load sizes by Version if (m_cVersion==char('A')) LoadLimit = Smaller(P2.ObjLength, 0x100000); else if (m_cVersion==char('B')) LoadLimit = Smaller(P2.ObjLength, 0x040000); else if (m_cVersion==char('C')) LoadLimit = Smaller(P2.ObjLength, 0x008000); else if (m_cVersion==char('D')) LoadLimit = Smaller(P2.ObjLength, 0x020000); else if (m_cVersion==char('E')) LoadLimit = Smaller(P2.ObjLength, 0x080000); else if (m_cVersion==char('F')) LoadLimit = Smaller(P2.ObjLength, 0x100000); else if (m_cVersion==char('G')) LoadLimit = Smaller(P2.ObjLength, 0x100000); // send bytes in Base64 format TxString(_T("Prop_Txt 0 0 0 0 ")); n = 0; for (i=0;i=6) { TxBase64((m>>(n-6))&0x3F); n = n-6; } if (n>=6) { TxBase64((m>>(n-6))&0x3F); n = n-6; } } if (n>0) TxBase64((m<<(6-n))&0x3F); TxString(_T("~")); TxComm(); #if 0 close_com (); #endif } // Add hex byte to comm buffer void prop_serial::TxHex(unsigned char x) { TxByte(HexChr[(x>>4)&0xF]); TxByte(HexChr[x&0xF]); TxByte(0x20); } // Add base64 byte to comm buffer void prop_serial::TxBase64(unsigned char x) { TxByte(Base64Chr[x]); } // Add byte to comm buffer void prop_serial::TxByte(unsigned char x) { if (x<32) TRACE ("\r\nTxByte: %02x",x); else TRACE ("\r\nTxByte: '%c'",x); ((char*)m_pTxBuff)[m_dwTxBuffPos] = x; m_dwTxBuffPos++; if (m_dwTxBuffPos