// ComThread.cpp : implementation file // #include "stdafx.h" #include "windows.h" #include "P2 Graphical Debug Terminal.h" #include "../Frame Lisp/telnet.h" #include "ComThread.h" #include "ComThreadProgress.h" #include "SerialProgress.h" #include "MainFrm.h" #define MEGABYTE (1048576) #define COM_THREAD_POLL_INTERVAL (10) // CComThread int port_speeds [] = { 110, 300, 1200, 2400, 4800, 9600, 19200, 31500, 38400, 57600, 64000, 115200, 128000, 230400, 460800, 921600, 2000000, 3000000, -1, }; IMPLEMENT_DYNCREATE(CComThread, CWinThread) BEGIN_MESSAGE_MAP(CComThread, CWinThread) ON_THREAD_MESSAGE(WM_FIND_HARDWARE,OnFindHardware) ON_THREAD_MESSAGE(WM_GET_HARDWARE_VERSION,OnGetHeardwareVersion) ON_THREAD_MESSAGE(WM_GET_VERSION_STRING,OnGetVersionString) ON_THREAD_MESSAGE(WM_LOAD_HARDWARE,OnLoadHardware) ON_THREAD_MESSAGE(WM_SET_PORT_NUM,OnSetPortNum) ON_THREAD_MESSAGE(WM_SET_BAUD_RATE,OnSetBaudRate) ON_THREAD_MESSAGE(WM_CREATE_SESSION,OnCreateSession) ON_THREAD_MESSAGE(WM_CLOSE_SESSION,OnCloseSession) ON_THREAD_MESSAGE(WM_TRANSMIT_DATA,OnTransmitData) ON_THREAD_MESSAGE(WM_TRANSMIT_CHAR,OnTransmitData) ON_THREAD_MESSAGE(WM_SEND_RESET,OnSendResetCmd) END_MESSAGE_MAP() CComThread::CComThread() { m_portId=0; m_iBytesTransmitted=0; m_iBytesRecieved=0; m_pages_allocated = 0; m_fileBuffer = 0; m_baud_rate = DEFAULT_BAUD_RATE; m_bConnected = false; } CComThread::~CComThread() { } CString CComThread::get_com_string(int id) { CString result; result.Format(_T("COM%d"),id); return result; } BOOL CComThread::OnIdle (LONG lCount) { DWORD dwStatus; m_bConnected=m_comunit.m_bCommOpen; dwStatus = WaitForSingleObject (m_comunit.m_hEventRx,COM_THREAD_POLL_INTERVAL); #if 0 if ((m_bConnected)&&(dwStatus==WAIT_OBJECT_0)) #endif if (m_bConnected) { CComThread::ReadBuffer(); } lCount++; CWinThread::OnIdle (lCount); return true; } size_t CComThread::get_page_size() { SYSTEM_INFO sSysInfo; GetSystemInfo(&sSysInfo); DWORD dwPageSize = sSysInfo.dwPageSize; return dwPageSize; } LPVOID CComThread::allocate_buffer(size_t size) { BOOL b_valid; LPVOID p_addr; size_t allocation = size; p_addr = (LPVOID) VirtualAlloc(NULL,allocation, MEM_COMMIT,PAGE_READWRITE|PAGE_NOCACHE); ASSERT (p_addr!=NULL); b_valid = (BOOL) VirtualLock (p_addr,allocation); return p_addr; } BOOL CComThread::InitInstance() { #if 0 AfxMessageBox (_T("Com Thread Started")); #endif LPVOID p_addr; m_iPageSize = get_page_size(); size_t pages_needed = (TxBuffSize+RxBuffSize)/m_iPageSize; if ((TxBuffSize+RxBuffSize)%m_iPageSize>0) pages_needed++; p_addr = allocate_buffer(m_iPageSize*pages_needed); m_comunit.m_pRxBuff=p_addr; // sneaky way to increment or add/subract a void* by the correct // number of bytes for the anticipated data type. #define SERIAL_DATA_TYPE char m_comunit.m_pTxBuff=(LPVOID)((SERIAL_DATA_TYPE*)p_addr +(size_t)RxBuffSize); m_pages_allocated = pages_needed; return TRUE; } int CComThread::Run() { int res; res = CWinThread::Run(); return res; } void CComThread::OutputDebugString (const char *str) { WPARAM w; LPARAM l; CWinApp *pApp; pApp = AfxGetApp(); CMainFrame *pMain = (CMainFrame*)pApp->m_pMainWnd; #if 0 // TODO - put in a system for various debug levels // like typedef enum { NONE, LACONIC, MEDIUM, VERBOSE, } // debug_level; if (m_debug==false) return; #endif w = (WPARAM) _strdup(str); l = 0; if (pMain!=NULL) { pMain->PostMessage(WM_RECIEVE_DEBUG_DATA,w,l); } else delete (char*)w; } void CComThread::OutputDebugString (const char *str, int val) { size_t len = strlen (str); char *p = new char [len+16]; sprintf_s (p,len+15,str,val); WPARAM w = (WPARAM) p; LPARAM l; CWinApp *pApp; pApp = AfxGetApp(); CMainFrame *pMain = (CMainFrame*)pApp->m_pMainWnd; l = 0; if (pMain!=NULL) { pMain->PostMessage(WM_RECIEVE_DEBUG_DATA,w,l); } else delete p; } int CComThread::ExitInstance() { // TODO: perform any per-thread cleanup here return CWinThread::ExitInstance(); } void CComThread::EnumerateComPorts(CComThread* pThread) { pThread->PostThreadMessage(WM_FIND_HARDWARE,0,0); } // CComThread message handlers ///////////////////////////////////////////////////// // // Step 1: The application posts a WM_FIND_HARDWARE // message to this thread; and then returns to doing // application related stuff, like handling OnDraw // commands in the GUI. // // Step 2: This thread receives a WM_FIND_HARDWARE // message so that it knows to call the Find // hardware method in the prop_serial object. // // Step 3: When the prop_serial object is done // (hopefully sucessfully) - we can post a message // back to the application main window. // // In the meantime - the communit is free to post // messages on its own to the main window - so // as to update things like "status text" or // progress bars, etc. void CComThread::FindHardware(CComThread *pThread) { pThread->PostThreadMessage(WM_FIND_HARDWARE,1,0); } void CComThread::OnSendResetCmd (WPARAM, LPARAM) { m_comunit.reset_hardware(); } void CComThread::OnFindHardware (WPARAM cmd, LPARAM) { bool result; CString *strVersion = new CString; result = m_comunit.detect_hardware(); if (result==true) { (*strVersion) = m_comunit.m_strVersion; int port = m_comunit.GetComPortNumber(); WPARAM wparam = (WPARAM) strVersion; AfxGetApp()->m_pMainWnd-> PostMessage(WM_SET_VERSION_STRING1, wparam,(LPARAM)port); } } //////////////////////////////////////////////////////////// bool CComThread::GetHardwareVersion(CComThread *pThread) { bool result; if (pThread==NULL) return false; pThread->PostThreadMessage(WM_GET_HARDWARE_VERSION,0,0); result = true; return result; } void CComThread::OnGetHeardwareVersion (WPARAM,LPARAM) { m_comunit.set_version_string (); } // the application, or a document within the application // has requested that the application level copy of // the version string be updated. Todo - handdle // multiple P2 chips connected over Wifi, or multiple // com ports - and make this information avaiable in // a dialog; similar to the way we do MidiEnnumerateDevices // and the MidiGetCaps, or RasEnum devices, etc. void CComThread::OnGetVersionString (WPARAM w,LPARAM) { int portNum = (int)w; CString str; LPCSTR pStr; m_comunit.detect_hardware(); str = m_comunit.m_strVersion; pStr = (LPCSTR) &str; CWinApp *pApp = AfxGetApp(); CWnd *pWnd = pApp->GetMainWnd(); pWnd->SendMessage (WM_SET_VERSION_STRING1,(WPARAM)pStr,0); } // proxy call from CDebugTermingalDoc. // Set the file name and then post the actual message // to the thread ... void CComThread::LoadHardwareAndRun(CComThread *pThread,CString strFile) { // dont need this AfxMessage, we will send progress information // from inside the actual thread - after the message that // we are about to send is processed. #if 0 CString msg; msg.Format(_T("CComThread::Uploading File: %s\n"),strFile); AfxMessageBox(msg,IDOK); #endif pThread->m_strFileName = strFile; pThread->PostThreadMessage(WM_LOAD_HARDWARE,0,0); } // now in the actual thread. Does the CString contain the // correct file name to upload? void CComThread::OnLoadHardware (WPARAM,LPARAM) { // int status; // status = AfxMessageBox (m_strFileName,IDOK); m_fileBuffer = allocate_buffer(MEGABYTE); ASSERT(m_fileBuffer); CPropertySheet s; s.SetWizardMode(); CComThreadProgress page1; CSerialProgress page2; s.AddPage(&page1); s.AddPage(&page2); CString msg;; msg.Format(_T("\n\rPreparing to Upload ... \r\n%s"),m_strFileName); CMainFrame *pMain = (CMainFrame*)(AfxGetApp()->GetMainWnd()); pMain->m_str_tracing.Append(msg); page1.m_progress_text.Append(pMain->m_str_tracing); s.DoModal(); } void CComThread::OnSetPortNum(WPARAM w,LPARAM) { int portNum = (int) w; } void CComThread::OnSetBaudRate(WPARAM w,LPARAM) { m_baud_rate = (int)w; } void CComThread::OnStartDebug(WPARAM w, LPARAM) { m_comunit.StartDebug(); } int CComThread::GetComPort(void) { int portNumber = m_comunit.GetComPortNumber(); return portNumber; } void CComThread::OnCreateSession (WPARAM w, LPARAM) { #if 0 m_comunit.CloseComm(); #endif bool result = m_comunit.open_com(); if (result==true) { m_comunit.reset_hardware(); m_bConnected = true; CComThread::OutputDebugString ("\r\nCComThread::CreateSession .., SUCCESS!"); m_comunit.open_forth (); } else { m_bConnected = false; CComThread::OutputDebugString ("\r\nCComThread::CreateSession ... FAILURE!"); } } CString CComThread::GetPortStatus(void) { CString str; return str; } void CComThread::OnCloseSession (WPARAM, LPARAM) { m_comunit.close_com(); m_bConnected = false; Sleep(2000); } // every key press in a terminal view is sent to // this thread, whether there is an active // connection or not. void CComThread::OnTransmitData (WPARAM w,LPARAM) { unsigned char c = (unsigned char) w; CString str; if (m_comunit.m_bCommOpen) { if (c>=32) str.Format(_T("\r\nCComThread::OnTransmitData '%c'"),c); else str.Format(_T("\r\nCComThread::OnTransmitData %02x"),c); TRACE(str); m_comunit.TxByte (c); // if (c==13) // m_comunit.TxByte (10); m_bConnected=true; } else TRACE ("\r\nNO COM PORT ACTIVE"); } void CComThread::ReadBuffer () { char *msg_buf; bool port_status = m_comunit.m_bCommOpen; if (port_status==false) return; bool read_status = m_comunit.RxCheck(); if (read_status==false) return; m_comunit.RxComm (); char *rxbuff = (char*) m_comunit.m_pRxBuff; int i,k; k = 0; for (i=0;im_pMainWnd-> PostMessage(WM_RECIEVE_SERIAL_DATA, (WPARAM)msg_buf,0); }