/*---------------------------------------------------------------------------* Project: Host I/O Interface for HIO2 File: Hio2IfHost.cpp (C)2005 HUDSON SOFT $Header: /home/cvsroot/SDK/build/demos/hio2demo/vc++/HioIf/src/Hio2IfHost.cpp,v 1.3 2006/03/15 06:31:26 mitu Exp $ $NoKeywords: $ *---------------------------------------------------------------------------*/ // Host I/O API wrapper interface #include "stdafx.h" #include "Hio2IfHost.h" #include /////////////////////////////////////////////////////////////////////////////// // // CHiosIf object for callback function reference // static CHio2If* l_pHio2If = NULL; /////////////////////////////////////////////////////////////////////////////// // // comparative function from CStatusList to IndexOf // // HIO handle comparison BOOL Hio2IfCompHandle(LPHIO2IF_STATUS pItem, LPVOID pData) { // pData == handle return (pItem->m_hHIO == pData) ? TRUE : FALSE; } // PC channel comparison BOOL Hio2IfCompPcChan(LPHIO2IF_STATUS pItem, LPVOID pData) { #ifndef HW0 return (lstrcmp(pItem->m_pPathName, (LPCSTR)pData) == 0) ? TRUE : FALSE; #else // HW0 return (pItem->m_pPathName == (HIO2DevicePath)pData) ? TRUE : FALSE; #endif // HW0 } /////////////////////////////////////////////////////////////////////////////// // // error strings // LPCSTR CHio2If::m_lpszErrorStrings[HIO2IF_ERROR_MAX] = { #include "Hio2IfErr.str" }; /////////////////////////////////////////////////////////////////////////////// // // callback // // HIO2EnumDevices() - callback static BOOL hio2EnumCallback(HIO2DevicePath pathName, void* param) { CHio2If* pHio2If = static_cast(param); pHio2If->AddDevicePath(pathName); return TRUE; } // HIO2Open() - callback static void hio2Callback(HIO2Handle h) { static const HIO2IF_MODE l_nOpenMode[] = { HIO2IF_MODE_WRONLY, // send only HIO2IF_MODE_RDONLY, // receive only HIO2IF_MODE_RDWR // send and receive }; // for multithreading l_pHio2If->EnterCriticalSection(); HIO2IF_EVENT event; int id, cmd; u32 mail = 0; // gets the CHio2If ID from the HIO handle id = l_pHio2If->GetIdOfHandle(h); l_pHio2If->GetDllIf().ReadMailbox(h, &mail); cmd = HIO2IF_GET_PACKET_CMD(mail); switch ( cmd ) { case HIO2IF_CMD_OPEN_RDONLY: case HIO2IF_CMD_OPEN_WRONLY: case HIO2IF_CMD_OPEN_RDWR: // perform the following and notify NNGC when an open notification arrives from NNGC: // 1. establish a connection with the PC // 2) open mode settings // settings are for NNGC (opposite) for read only and write only // 3) NNGC EXI channel number l_pHio2If->SetConnect(id, TRUE); l_pHio2If->SetOpenMode(id, l_nOpenMode[cmd -1]); l_pHio2If->SetDeviceType(id, (HIO2DeviceType)HIO2IF_GET_PACKET_CHAN(mail)); l_pHio2If->GetDllIf().WriteMailbox(h, HIO2IF_SET_PACKET( l_pHio2If->GetPcChan(id), HIO2IF_CMD_OPEN_RESULT ) ); event = HIO2IF_EVENT_CONNECT; break; case HIO2IF_CMD_SEND: l_pHio2If->SetReceived(id, TRUE); event = HIO2IF_EVENT_RECEIVED; break; case HIO2IF_CMD_SEND_RESULT: l_pHio2If->SetSendPossible(id, TRUE); event = HIO2IF_EVENT_SEND_POSSIBLE; break; case HIO2IF_CMD_CLOSE: // the actual close process takes place in the application l_pHio2If->SetConnect(id, FALSE); event = HIO2IF_EVENT_DISCONNECT; break; default: event = HIO2IF_EVENT_UNKOWN; break; } // for multithreading l_pHio2If->LeaveCriticalSection(); l_pHio2If->CallEventCallback(id, event); } // HIOReadAsync() - callback static void hio2ReadAsyncCallback(HIO2Handle h) { // gets the CHio2If ID from the HIO handle int id = l_pHio2If->GetIdOfHandle(h); DWORD async = HIO2IF_ASYNC_READ_MASK(l_pHio2If->GetAsyncMode(id)); // if there is an Async specification from CHio2If::Read, perform a Read completion notification to the connection target // (CHio2If::ReadFree notification not needed) if ( async & HIO2IF_ASYNC_READ ) { // for multithreading l_pHio2If->EnterCriticalSection(); l_pHio2If->GetDllIf().WriteMailbox(h, HIO2IF_SET_PACKET( l_pHio2If->GetPcChan(id), HIO2IF_CMD_SEND_RESULT ) ); // for multithreading l_pHio2If->LeaveCriticalSection(); } l_pHio2If->SetAsyncMode(id, l_pHio2If->GetAsyncMode(id) & ~async); // event callback function call l_pHio2If->CallEventCallback(id, HIO2IF_EVENT_READ_ASYNC_DONE); } // HIOWriteAsync() - callback static void hio2WriteAsyncCallback(HIO2Handle h) { // gets the CHio2If ID from the HIO handle int id = l_pHio2If->GetIdOfHandle(h); DWORD async = HIO2IF_ASYNC_WRITE_MASK(l_pHio2If->GetAsyncMode(id)); // if there is an Async specification from CHio2If::Write, perform a Write notification to the connection target // (CHio2If::WriteFree notification not needed) if ( async & HIO2IF_ASYNC_WRITE ) { // for multithreading l_pHio2If->EnterCriticalSection(); l_pHio2If->GetDllIf().WriteMailbox(h, HIO2IF_SET_PACKET( l_pHio2If->GetPcChan(id), HIO2IF_CMD_SEND ) ); // for multithreading l_pHio2If->LeaveCriticalSection(); } l_pHio2If->SetAsyncMode(id, l_pHio2If->GetAsyncMode(id) & ~async); // event callback function call l_pHio2If->CallEventCallback(id, HIO2IF_EVENT_WRITE_ASYNC_DONE); } /////////////////////////////////////////////////////////////////////////////// // // CHio2If // //----------------------------------------------------------------------------- CHio2If::CHio2If() { m_szMessage[0] = '\0'; m_nLastError = HIO2IF_ERROR_NONE; m_bInitialized = FALSE; InitializeCriticalSection(&m_csCriticalSection); } CHio2If::~CHio2If() { Exit(); DeleteCriticalSection(&m_csCriticalSection); } //----------------------------------------------------------------------------- HIO2IF_RESULT CHio2If::Init() { // when initialized, terminate HIO if ( m_bInitialized ) m_cHio2Dll.Exit(); else if ( !m_cHio2Dll.Create() ) return SetFatal(HIO2IF_FATAL_LOAD_DLL); InitInstance(); // HIO initialization if ( !m_cHio2Dll.Init() ) return SetFatal(HIO2IF_FATAL_INIT, m_cHio2Dll.GetLastError()); // search for an EXI device if ( m_cHio2Dll.EnumDevices(hio2EnumCallback, this) == -1 ) return SetFatal(HIO2IF_FATAL_ENUMDEVICES, m_cHio2Dll.GetLastError()); m_bInitialized = TRUE; return HIO2IF_RESULT_SUCCESS; } //----------------------------------------------------------------------------- HIO2IF_RESULT CHio2If::Open(HIO2DevicePath pathName, HIO2IF_EVENT_CALLBACK callback, HIO2IF_ID& id) { LPHIO2IF_STATUS pStatus = NULL; int nIndex, nPcChan = 0; #ifndef HW0 // use any numbers included in the device path name as a dummy PC channel number LPCSTR p = pathName; while ( *p != '\0' ) { if ( (*p >= '0') && (*p <= '9') ) { nPcChan *= 10; nPcChan += *p - '0'; } p++; } #else // HW0 nPcChan = pathName; #endif // HW0 nPcChan &= HIO2IF_CMD_MASK; // when the specified EXI channel is in use nIndex = m_cHioStatus.IndexOf((LPVOID)pathName, Hio2IfCompPcChan); if ( nIndex != -1 ) { pStatus = m_cHioStatus[nIndex]; if ( pStatus->m_hHIO != HIO2IF_INVALID_HANDLE_VALUE ) return SetError(HIO2IF_ERROR_CHAN_ALREADY_OPENED, pathName); } HIO2Handle h = m_cHio2Dll.Open(pathName, hio2Callback, NULL, NULL); if ( h == HIO2_INVALID_HANDLE_VALUE ) return SetFatal(HIO2IF_FATAL_OPEN, pathName, m_cHio2Dll.GetLastError()); // for previously opened (detected) channels if ( nIndex != -1 ) id = nIndex; else { pStatus = new HIO2IF_STATUS; id = m_cHioStatus.AddTail(pStatus); } // Host I/O interface default settings #ifndef HW0 pStatus->m_pPathName = new TCHAR [lstrlen(pathName) + 1]; lstrcpy((LPSTR)pStatus->m_pPathName, pathName); #else // HW0 pStatus->m_pPathName = pathName; #endif // HW0 pStatus->m_nPcChan = nPcChan; pStatus->m_hHIO = h; pStatus->m_fncCallback = callback; return HIO2IF_RESULT_SUCCESS; } //----------------------------------------------------------------------------- HIO2IF_RESULT CHio2If::Read(HIO2IF_ID id, DWORD addr, LPVOID buffer, int size, BOOL async) { if ( !IsValidID(id) ) return SetError(HIO2IF_ERROR_INVALID_ID); LPHIO2IF_STATUS pStatus = m_cHioStatus[id]; // for the write-only mode if ( pStatus->m_nMode == HIO2IF_MODE_WRONLY ) return SetError(HIO2IF_ERROR_WRITE_ONLY, pStatus->m_nPcChan); // not connected to the PC if ( !pStatus->m_bConnect ) return SetError(HIO2IF_ERROR_NOT_CONNECT, pStatus->m_nPcChan); // when data has not been received if ( !pStatus->m_bReceived ) return SetError(HIO2IF_ERROR_NOT_RECV_DATA, pStatus->m_nPcChan); pStatus->m_bReceived = FALSE; // synchronous Read if ( !async ) { if ( !m_cHio2Dll.Read(pStatus->m_hHIO, addr, buffer, size) ) return SetFatal(HIO2IF_FATAL_READ, pStatus->m_nPcChan, m_cHio2Dll.GetLastError()); // perform a Read completion notification to the connection target m_cHio2Dll.WriteMailbox(pStatus->m_hHIO, HIO2IF_SET_PACKET(pStatus->m_nPcChan, HIO2IF_CMD_SEND_RESULT)); } // asynchronous Read else { pStatus->m_dwAsyncMode |= HIO2IF_ASYNC_READ; if ( !m_cHio2Dll.ReadAsync(pStatus->m_hHIO, addr, buffer, size, hio2ReadAsyncCallback) ) return SetFatal(HIO2IF_FATAL_READ, pStatus->m_nPcChan, m_cHio2Dll.GetLastError()); } return HIO2IF_RESULT_SUCCESS; } //----------------------------------------------------------------------------- HIO2IF_RESULT CHio2If::ReadFree(HIO2IF_ID id, DWORD addr, LPVOID buffer, int size, BOOL async) { if ( !IsValidID(id) ) return SetError(HIO2IF_ERROR_INVALID_ID); LPHIO2IF_STATUS pStatus = m_cHioStatus[id]; // for the write-only mode if ( pStatus->m_nMode == HIO2IF_MODE_WRONLY ) return SetError(HIO2IF_ERROR_WRITE_ONLY, pStatus->m_nPcChan); // not connected to the PC if ( !pStatus->m_bConnect ) return SetError(HIO2IF_ERROR_NOT_CONNECT, pStatus->m_nPcChan); // synchronous Read if ( !async ) { if ( !m_cHio2Dll.Read(pStatus->m_hHIO, addr, buffer, size) ) return SetFatal(HIO2IF_FATAL_READ, pStatus->m_nPcChan, m_cHio2Dll.GetLastError()); } // asynchronous Read else { // if the prior ReadAsync or WriteAsync is not completed if ( pStatus->m_dwAsyncMode ) return SetError(HIO2IF_ERROR_BUSY, pStatus->m_nPcChan); pStatus->m_dwAsyncMode |= HIO2IF_ASYNC_READ_FREE; if ( !m_cHio2Dll.ReadAsync(pStatus->m_hHIO, addr, buffer, size, hio2ReadAsyncCallback) ) return SetFatal(HIO2IF_FATAL_READ, pStatus->m_nPcChan, m_cHio2Dll.GetLastError()); } return HIO2IF_RESULT_SUCCESS; } //----------------------------------------------------------------------------- HIO2IF_RESULT CHio2If::Write(HIO2IF_ID id, DWORD addr, LPVOID buffer, int size, BOOL async) { if ( !IsValidID(id) ) return SetError(HIO2IF_ERROR_INVALID_ID); LPHIO2IF_STATUS pStatus = m_cHioStatus[id]; // for the read-only mode if ( pStatus->m_nMode == HIO2IF_MODE_RDONLY ) return SetError(HIO2IF_ERROR_READ_ONLY, pStatus->m_nPcChan); // not connected to the PC if ( !pStatus->m_bConnect ) return SetError(HIO2IF_ERROR_NOT_CONNECT, pStatus->m_nPcChan); // when it can't be sent (when the target cannot receive data) if ( !pStatus->m_bSendPossible ) return SetError(HIO2IF_ERROR_CANNOT_SEND_DATA, pStatus->m_nPcChan); pStatus->m_bSendPossible = FALSE; // synchronous Write if ( !async ) { if ( !m_cHio2Dll.Write(pStatus->m_hHIO, addr, buffer, size) ) return SetFatal(HIO2IF_FATAL_WRITE, pStatus->m_nPcChan, m_cHio2Dll.GetLastError()); // perform a Write notification to the connection target m_cHio2Dll.WriteMailbox(pStatus->m_hHIO, HIO2IF_SET_PACKET(pStatus->m_nPcChan, HIO2IF_CMD_SEND)); } // asynchronous Write else { pStatus->m_dwAsyncMode |= HIO2IF_ASYNC_WRITE; if ( !m_cHio2Dll.WriteAsync(pStatus->m_hHIO, addr, buffer, size, hio2WriteAsyncCallback) ) return SetFatal(HIO2IF_FATAL_WRITE, pStatus->m_nPcChan, m_cHio2Dll.GetLastError()); } return HIO2IF_RESULT_SUCCESS; } //----------------------------------------------------------------------------- HIO2IF_RESULT CHio2If::WriteFree(HIO2IF_ID id, DWORD addr, LPVOID buffer, int size, BOOL async) { if ( !IsValidID(id) ) return SetError(HIO2IF_ERROR_INVALID_ID); LPHIO2IF_STATUS pStatus = m_cHioStatus[id]; // for the read-only mode if ( pStatus->m_nMode == HIO2IF_MODE_RDONLY ) return SetError(HIO2IF_ERROR_READ_ONLY, pStatus->m_nPcChan); // not connected to the PC if ( !pStatus->m_bConnect ) return SetError(HIO2IF_ERROR_NOT_CONNECT, pStatus->m_nPcChan); // synchronous Write if ( !async ) { if ( !m_cHio2Dll.Write(pStatus->m_hHIO, addr, buffer, size) ) return SetFatal(HIO2IF_FATAL_WRITE, pStatus->m_nPcChan, m_cHio2Dll.GetLastError()); } // asynchronous Write else { // if the prior ReadAsync or WriteAsync is not completed if ( pStatus->m_dwAsyncMode ) return SetError(HIO2IF_ERROR_BUSY, pStatus->m_nPcChan); pStatus->m_dwAsyncMode |= HIO2IF_ASYNC_WRITE_FREE; if ( !m_cHio2Dll.WriteAsync(pStatus->m_hHIO, addr, buffer, size, hio2WriteAsyncCallback) ) return SetFatal(HIO2IF_FATAL_WRITE, pStatus->m_nPcChan, m_cHio2Dll.GetLastError()); } return HIO2IF_RESULT_SUCCESS; } //----------------------------------------------------------------------------- HIO2IF_RESULT CHio2If::ReadStatus(HIO2IF_ID id, DWORD& status) { if ( !IsValidID(id) ) return SetError(HIO2IF_ERROR_INVALID_ID); LPHIO2IF_STATUS pStatus = m_cHioStatus[id]; // not connected to the PC if ( !pStatus->m_bConnect ) return SetError(HIO2IF_ERROR_NOT_CONNECT, pStatus->m_nPcChan); return m_cHio2Dll.ReadStatus(pStatus->m_hHIO, (u32 *)&status) ? HIO2IF_RESULT_SUCCESS : SetFatal(HIO2IF_FATAL_READSTATUS, pStatus->m_nPcChan, m_cHio2Dll.GetLastError()); } //----------------------------------------------------------------------------- HIO2IF_RESULT CHio2If::Close(HIO2IF_ID id) { if ( !IsValidID(id) ) return SetError(HIO2IF_ERROR_INVALID_ID); LPHIO2IF_STATUS pStatus = m_cHioStatus[id]; int chan = pStatus->m_nPcChan; // Perform a close notification when connected to the target if ( pStatus->m_bConnect ) { pStatus->m_bConnect = FALSE; m_cHio2Dll.WriteMailbox(pStatus->m_hHIO, HIO2IF_SET_PACKET(chan, HIO2IF_CMD_CLOSE)); } BOOL result = m_cHio2Dll.Close(pStatus->m_hHIO); // just initialize, without deleting, given that re-opening might occur // (keep the channel number) // pStatus->m_nPcChan = HIO2IF_INVALID_ID; pStatus->m_nDevType = HIO2_DEVICE_INVALID; pStatus->m_hHIO = HIO2IF_INVALID_HANDLE_VALUE; pStatus->m_nMode = HIO2IF_MODE_NONE; pStatus->m_bReceived = FALSE; pStatus->m_bSendPossible = TRUE; pStatus->m_fncCallback = NULL; return result ? HIO2IF_RESULT_SUCCESS : SetFatal(HIO2IF_FATAL_CLOSE, chan, m_cHio2Dll.GetLastError()); } //----------------------------------------------------------------------------- void CHio2If::Exit() { if ( !m_bInitialized ) return ; // perform a close notification when EXI channel is opened, and connection to the PC is available for (int i=0; im_hHIO != HIO2IF_INVALID_HANDLE_VALUE ) Close(i); } // HIO2Exit() force-closes opened channels m_cHio2Dll.Exit(); m_cHio2Dll.Release(); InitInstance(); m_bInitialized = FALSE; } //----------------------------------------------------------------------------- void CHio2If::AddDevicePath(HIO2DevicePath pathName) { #ifndef HW0 LPSTR lpPath = new TCHAR [lstrlen(pathName) + 1]; lstrcpy(lpPath, pathName); m_cDevices.push_back(lpPath); #else // HW0 m_cDevices.push_back(pathName); #endif // HW0 } //----------------------------------------------------------------------------- HIO2IF_RESULT CHio2If::SetFatal(HIO2IF_ERROR errID, ...) { va_list argptr; va_start(argptr, errID); vsprintf(m_szMessage, (char*)m_lpszErrorStrings[errID], argptr); va_end(argptr); m_nLastError = errID; return HIO2IF_RESULT_FATAL; } //----------------------------------------------------------------------------- HIO2IF_RESULT CHio2If::SetError(HIO2IF_ERROR errID, ...) { va_list argptr; va_start(argptr, errID); vsprintf(m_szMessage, (char*)m_lpszErrorStrings[errID], argptr); va_end(argptr); m_nLastError = errID; return HIO2IF_RESULT_ERROR; } //----------------------------------------------------------------------------- void CHio2If::InitInstance() { #ifndef HW0 // HW0 for (int i=0; i<(int)m_cDevices.size(); i++) delete [] m_cDevices[i]; m_cDevices.clear(); #else // HW0 m_cDevices.clear(); #endif m_cHioStatus.Clear(); } /////////////////////////////////////////////////////////////////////////////// // // create a release Host I/O interface for PC // CHio2If* Hio2CreateInterface(void) { if ( l_pHio2If == NULL ) l_pHio2If = new CHio2If; return l_pHio2If; } void Hio2ReleaseInterface(CHio2If* pHioIf) { ASSERT(l_pHio2If == pHioIf); delete static_cast(pHioIf); l_pHio2If = NULL; } // end of HioIfHost.cpp