#include "stdafx.h" #include "Keyence_Proto.h" #include "math.h" #define MY_CONFIG 1 #define MAX_DEVPATH_LENGTH 256 #define ENDPOINT_TIMEOUT 500 //***** Static Data ***** struct_Keyence_ep_buff CKeyence_Proto::ep_buff[lEPSIZE]; //================================================================ int CKeyence_Proto::g_hEP81_Thread_State=THREAD_PAUSED; HANDLE CKeyence_Proto::g_hEP81_Thread_Id=NULL; //================================================================ int CKeyence_Proto::g_hEP82_Thread_State=THREAD_PAUSED; HANDLE CKeyence_Proto::g_hEP82_Thread_Id=NULL; //================================================================ int CKeyence_Proto::g_hEP01_Thread_State=THREAD_PAUSED; HANDLE CKeyence_Proto::g_hEP01_Thread_Id=NULL; HANDLE CKeyence_Proto::g_hEP01_Serial_Mutex; //================================================================ int CKeyence_Proto::g_hEP02_Thread_State=THREAD_PAUSED; HANDLE CKeyence_Proto::g_hEP02_Thread_Id=NULL; HANDLE CKeyence_Proto::g_hEP02_Serial_Mutex; //================================================================ struct_Keyence_machine CKeyence_Proto::g_machine; usb_dev_handle *CKeyence_Proto::g_dev=NULL; CLogger *CKeyence_Proto::g_pLogger; HANDLE CKeyence_Proto::g_hHomedEvent = NULL; //=========================================================================== // Worker Thread to serialize EP_KEYENCE_01 commands. //=========================================================================== unsigned __stdcall CKeyence_Proto::g_EP01_Thread(LPVOID pThis) { CKeyence_Proto* _This = (CKeyence_Proto*)pThis; for (;;) { TRACE0("g_hSerialUsbThread in loop set.\n"); if (g_hEP01_Thread_State == THREAD_EXIT) ExitThread(0); WaitForSingleObject(ep_buff[EP_01_CMD_IDX]._event,INFINITE); TRACE0("g_hSerialUsbThread obtained event.\n"); switch (g_hEP01_Thread_State) { case THREAD_EXIT: { ExitThread(0); } case THREAD_PAUSED: break; case THREAD_RUNNING: { TRACE0("g_hSerialUsbThread processing _send_usb_data();\n"); _This->_send_usb_data(EP_01_CMD_IDX); TRACE0("g_hSerialUsbThread return from _send_usb_data();\n"); break; } default: ExitThread(0); } }; g_hEP01_Thread_State = THREAD_EXIT; ExitThread(0); }; //=========================================================================== // Worker Thread to serialize EP_KEYENCE_02 commands. //=========================================================================== unsigned __stdcall CKeyence_Proto::g_EP02_Thread(LPVOID pThis) { CKeyence_Proto* _This = (CKeyence_Proto*)pThis; for (;;) { TRACE0("g_hEP02_Thread in loop set.\n"); if (g_hEP02_Thread_State == THREAD_EXIT) ExitThread(0); WaitForSingleObject(ep_buff[EP_02_CMD_IDX]._event,INFINITE); TRACE0("g_hEP02_Thread obtained event.\n"); switch (g_hEP02_Thread_State) { case THREAD_EXIT: { ExitThread(0); } case THREAD_PAUSED: break; case THREAD_RUNNING: { TRACE0("g_hEP02_Thread calling _send_usb_data. EP_KEYENCE_02; %x\n"); _This->_send_usb_data(EP_02_CMD_IDX); TRACE0("g_hEP02_Thread return _send_usb_data. EP_KEYENCE_02; %x\n"); break; } default: ExitThread(0); } }; g_hEP02_Thread_State = THREAD_EXIT; ExitThread(0); }; //****************************************************************************** // This is the worker thread to process USBD_TRANSFER_DIRECTION_IN //****************************************************************************** unsigned __stdcall CKeyence_Proto::g_EP81_Thread(LPVOID pThis) { CKeyence_Proto* _This = (CKeyence_Proto*)pThis; for (;;) { WaitForSingleObject(ep_buff[EP_81_DATA_IDX]._event, INFINITE); switch (g_hEP81_Thread_State) { case THREAD_EXIT: { ExitThread(0); } case THREAD_PAUSED: break; case THREAD_RUNNING: { _This->_reap_async_8x(EP_81_DATA_IDX); break; } default: ExitThread(0); } } } //****************************************************************************** // This is the worker thread to process USBD_TRANSFER_DIRECTION_IN //****************************************************************************** unsigned __stdcall CKeyence_Proto::g_EP82_Thread(LPVOID pThis) { CKeyence_Proto* _This = (CKeyence_Proto*)pThis; for (;;) { WaitForSingleObject(ep_buff[EP_82_DATA_IDX]._event, INFINITE); switch (g_hEP82_Thread_State) { case THREAD_EXIT: { ExitThread(0); } case THREAD_PAUSED: break; case THREAD_RUNNING: { _This->_reap_async_8x(EP_82_DATA_IDX); break; } default: ExitThread(0); } } } //=========================================================================== void CKeyence_Proto::Trace_EP_Buff(long lIndex) { UCHAR tmp[256]; CString csTmp; memcpy(tmp, ep_buff[lIndex]._buffer, ep_buff[lIndex]._size); csTmp = _T("Trace_EP_Buff _59 "); for (int ii= 0 ; ii < ep_buff[lIndex]._size ; ++ii) { CString csTmpHex; csTmpHex.Format(_T("%2X"), tmp[ii] ); csTmp += csTmpHex; } TRACE1("_process_KEYENCE_CMD_GET_INDEX_4E() Trace_EP_Buff %s \n", csTmp); } //****************************************************************************** // Parse the data received based on the index (which EP are we processing). // The CCmdObj should only have one CMD_STATUS_PROCESSING. // Update CCmdObj _ep_01_status and _ep_81_status. // Update _status to CMD_STATUS_COMPLETE when both _ep_01_status and _ep_81_status // are CMD_STATUS_COMPLETE. // //****************************************************************************** void CKeyence_Proto::_process_rcv_transfer_data(int iEP) { static long lRcvCnt = 0; static long lRcvCnt2 = 0; switch (iEP) { case EP_01_CMD_IDX : TRACE0("_process_rcv_transfer_data() : Update EP_01_CMD_IDX.\r\n"); ++lRcvCnt; break; case EP_81_DATA_IDX : // ++lRcvCnt; TRACE0("_process_rcv_transfer_data() : Update EP_81_DATA_IDX status.\r\n"); break; case EP_02_CMD_IDX : TRACE0("_process_rcv_transfer_data() : Update EP_02_CMD_IDX.\r\n"); ++lRcvCnt2; break; case EP_82_DATA_IDX : // parse result and put into its proper place. _process_KEYENCE_CMD_GET_LASER_DATA(); ++lRcvCnt2; break; default: break; }; lRcvCnt = (lRcvCnt == 2) ? 0:lRcvCnt; lRcvCnt2 = (lRcvCnt2 == 2) ? 0:lRcvCnt2; }; //****************************************************************************** CKeyence_Proto::CKeyence_Proto() { ep_buff[EP_01_CMD_IDX]._ep = EP_KEYENCE_01; ep_buff[EP_81_DATA_IDX]._ep = EP_KEYENCE_81; ep_buff[EP_02_CMD_IDX]._ep = EP_KEYENCE_02; ep_buff[EP_82_DATA_IDX]._ep = EP_KEYENCE_82; for (int i=0;inext) { for (dev = bus->devices; dev; dev = dev->next) { if (dev->descriptor.idVendor == KEYENCE_VID && dev->descriptor.idProduct == KEYENCE_PID) { return usb_open(dev); } } } return NULL; } //****************************************************************************** SSI_STATUS CKeyence_Proto::_usb_reset(void) { if (g_dev) { usb_reset(g_dev); g_dev = NULL; } else { ASSERT(0); return SSI_STATUS_TIMEOUT; } return SSI_STATUS_TIMEOUT; } //****************************************************************************** // Send is direct and async. // The receive thread will receive data and interpret it. //****************************************************************************** SSI_STATUS CKeyence_Proto::Init_MvUsb() { // Set initial state of the machine g_machine.s_status._machine_running = false; SSI_STATUS Status=SSI_STATUS_NORMAL; UNREFERENCED_PARAMETER(Status); /*if (g_pLogger->m_lLogMask & LOGACTIONS) g_pLogger->SendAndFlushPerMode(_T("Enter Initialize Mv Usb\n")); */ int usb_status = NULL; usb_init(); // initialize the library usb_status = usb_find_busses(); // find all busses usb_status = usb_find_devices(); // find all connected devices g_dev = _open_usb_dev(); if (!g_dev) { MessageBox(NULL, _T("Unable to open device"), _T("Message"), MB_OK); g_pLogger->SendAndFlushPerMode(_T("Unable to open device %s"), usb_strerror()); return SSI_STATUS_DATALINK_ERROR; } if (usb_set_configuration(g_dev, MY_CONFIG) < 0) { MessageBox(NULL, _T("Unable to SET CONFIGURATION"), _T("Message"), MB_OK); return SSI_STATUS_DATALINK_ERROR; } if (usb_claim_interface(g_dev, 0) < 0) { usb_close(g_dev); MessageBox(NULL, _T("Unable to CLAIM DEVICE"), _T("Message"), MB_OK); return SSI_STATUS_DATALINK_ERROR; } // ******************************************************************** // This event is used to kick the Serial Usb Command process. This threading model // is important because the underlying library is not thread-safe. // ep_buff[EP_01_CMD_IDX]._event = CreateEvent(NULL, // default security attributes FALSE, // manual reset event object NULL, // signaled NULL); // unamed object g_hEP01_Thread_Id = CreateThread( (LPSECURITY_ATTRIBUTES) NULL, 0, (LPTHREAD_START_ROUTINE) g_EP01_Thread, (LPVOID) this, 0, NULL); g_hEP01_Thread_State = THREAD_RUNNING; // ******************************************************************** // This event is used to kick the Serial Usb Command process. This threading model // is important because the underlying library is not thread-safe. // ep_buff[EP_02_CMD_IDX]._event = CreateEvent(NULL, // default security attributes FALSE, // manual reset event object NULL, // signaled NULL); // unamed object g_hEP02_Thread_Id = CreateThread( (LPSECURITY_ATTRIBUTES) NULL, 0, (LPTHREAD_START_ROUTINE) g_EP02_Thread, (LPVOID) this, 0, NULL); g_hEP02_Thread_State = THREAD_RUNNING; // ******************************************************************** // Prepare and start EP_KEYENCE_81 Thread - Use async commit. // ep_buff[EP_81_DATA_IDX]._event = CreateEvent(NULL, // default security attributes FALSE, // manual reset event object NULL, // signaled NULL); // unamed object g_hEP81_Thread_State = THREAD_PAUSED; g_hEP81_Thread_Id = CreateThread( (LPSECURITY_ATTRIBUTES) NULL, 0, (LPTHREAD_START_ROUTINE) g_EP81_Thread, (LPVOID) this, 0, NULL); g_hEP01_Serial_Mutex = CreateMutex(NULL, // default security attributes FALSE, // initial owner NULL); // name // ******************************************************************** // Prepare and start EP_KEYENCE_82 Thread - Use async commit. // ep_buff[EP_82_DATA_IDX]._event = CreateEvent(NULL, // default security attributes FALSE, // manual reset event object NULL, // signaled NULL); // unamed object g_hEP82_Thread_State = THREAD_PAUSED; g_hEP82_Thread_Id = CreateThread( (LPSECURITY_ATTRIBUTES) NULL, 0, (LPTHREAD_START_ROUTINE) g_EP82_Thread, (LPVOID) this, 0, NULL); g_hEP02_Serial_Mutex = CreateMutex(NULL, // default security attributes FALSE, // initial owner NULL); // name // ********************************************************************* g_hHomedEvent = CreateEvent(NULL, // default security attributes TRUE, // manual reset event object FALSE, // initial state is signaled NULL); // unamed object //if (g_pLogger->m_lLogMask & LOGACTIONS) // g_pLogger->SendAndFlushPerMode(_T("Exit Initialize Usb\n")); return SSI_STATUS_NORMAL; } //****************************************************************************** SSI_STATUS CKeyence_Proto::Exit_MvUsb() { SSI_STATUS Status=SSI_STATUS_NORMAL; //if (g_pLogger->m_lLogMask & LOGACTIONS) // g_pLogger->SendAndFlushPerMode(_T("Enter Exit_MvUsb\n")); g_hEP81_Thread_State = THREAD_EXIT; g_hEP82_Thread_State = THREAD_EXIT; g_hEP01_Thread_State = THREAD_EXIT; g_hEP02_Thread_State = THREAD_EXIT; SetEvent(ep_buff[EP_81_DATA_IDX]._event); if (g_hEP81_Thread_Id) { DWORD dwCode = STILL_ACTIVE; while (dwCode == STILL_ACTIVE) { GetExitCodeThread(g_hEP81_Thread_Id,&dwCode); Sleep(1); } } SetEvent(ep_buff[EP_82_DATA_IDX]._event); if (g_hEP82_Thread_Id) { DWORD dwCode = STILL_ACTIVE; while (dwCode == STILL_ACTIVE) { GetExitCodeThread(g_hEP82_Thread_Id,&dwCode); Sleep(1); } } SetEvent(ep_buff[EP_01_CMD_IDX]._event); if (g_hEP01_Thread_Id) { DWORD dwCode = STILL_ACTIVE; while (dwCode == STILL_ACTIVE) { GetExitCodeThread(g_hEP01_Thread_Id,&dwCode); Sleep(1); } } SetEvent(ep_buff[EP_02_CMD_IDX]._event); if (g_hEP02_Thread_Id) { DWORD dwCode = STILL_ACTIVE; while (dwCode == STILL_ACTIVE) { GetExitCodeThread(g_hEP02_Thread_Id,&dwCode); Sleep(1); } } if (g_dev) { usb_release_interface(g_dev,0); usb_close(g_dev); g_dev = NULL; } SetEvent(ep_buff[EP_81_DATA_IDX]._event); CloseHandle(ep_buff[EP_81_DATA_IDX]._event); SetEvent(ep_buff[EP_82_DATA_IDX]._event); CloseHandle(ep_buff[EP_82_DATA_IDX]._event); g_hEP01_Thread_State = THREAD_EXIT; SetEvent(ep_buff[EP_01_CMD_IDX]._event); CloseHandle(ep_buff[EP_01_CMD_IDX]._event); g_hEP02_Thread_State = THREAD_EXIT; SetEvent(ep_buff[EP_02_CMD_IDX]._event); CloseHandle(ep_buff[EP_02_CMD_IDX]._event); ReleaseMutex(g_hEP01_Serial_Mutex); CloseHandle(g_hEP01_Serial_Mutex); ReleaseMutex(g_hEP02_Serial_Mutex); CloseHandle(g_hEP02_Serial_Mutex); //if (g_pLogger->m_lLogMask & LOGACTIONS) // g_pLogger->SendAndFlushPerMode(_T("Exit Exit_MvUsb\n")); return Status; } //****************************************************************************** // Kick the g_hEP01_Thread_Event to get the g_EP01_Thread going. // iEP = EP_KEYENCE_01 or EP_KEYENCE_02 = 0x01 or 0x02 //****************************************************************************** SSI_STATUS CKeyence_Proto::_do_single_threaded_usb_comm(int iEP_Base) { TRACE1("=====_do_single_threaded_usb_comm(iEP) g_hEP01_Thread_Event. %x\n", iEP_Base); while ((ep_buff[iEP_Base]._hProtoPending == TRUE) || (ep_buff[iEP_Base+1]._hProtoPending == TRUE)) { ASSERT(0); Sleep(3); } ep_buff[iEP_Base]._hProtoPending = ep_buff[iEP_Base+1]._hProtoPending = TRUE; TRACE1("=====_do_single_threaded_usb_comm(iEP_Base) SetEvent(g_hEP01_Thread_Event): %X \r\n", ep_buff[iEP_Base]._save_send_cmd); SetEvent(ep_buff[iEP_Base]._event); while ((ep_buff[iEP_Base]._hProtoPending == TRUE) || (ep_buff[iEP_Base+1]._hProtoPending == TRUE)) { Sleep(3); } TRACE1("=====_do_single_threaded_usb_comm(iEP) g_hProtoDoneEvents. %x\n", iEP_Base); return SSI_STATUS_NORMAL; } //****************************************************************************** // This startup just kicks off the EP_KEYENCE_81 worker thread. //****************************************************************************** SSI_STATUS CKeyence_Proto::_start_machine() { g_hEP81_Thread_State = THREAD_RUNNING; g_hEP82_Thread_State = THREAD_RUNNING; g_machine.s_status._machine_running = true; return SSI_STATUS_NORMAL; }; //=============================================================================== SSI_STATUS CKeyence_Proto::_shutdown_machine() { g_machine.s_status._machine_running = false; return SSI_STATUS_NORMAL; }; //=============================================================================== // iEP = EP_KEYENCE_01 or EP_KEYENCE_02 //=============================================================================== SSI_STATUS CKeyence_Proto::_submit_async_8x(int iEP_Base) { int _ret; _ret = usb_bulk_setup_async(g_dev, &(ep_buff[iEP_Base]._async_context), (unsigned char)ep_buff[iEP_Base]._ep); if (_ret < 0) { return SSI_STATUS_SETUP_ASYNC_CONTEXT_ERROR; } _ret = usb_submit_async(ep_buff[iEP_Base]._async_context, ep_buff[iEP_Base]._buffer, ep_buff[iEP_Base]._size); if (_ret < 0) { printf("error usb_submit_async_ep_xx:\n%s\n", usb_strerror()); return SSI_STATUS_SETUP_ASYNC_CONTEXT_ERROR; } return SSI_STATUS_NORMAL; } //=============================================================================== // iEP_Base : EP_81_DATA_IDX/EP_82_DATA_IDX // //=============================================================================== SSI_STATUS CKeyence_Proto::_reap_async_8x(int iEP_Base) { int _ret; _ret = usb_reap_async(ep_buff[iEP_Base]._async_context, 1000); if (_ret > 0) { _process_rcv_transfer_data(iEP_Base); usb_free_async(&(ep_buff[iEP_Base]._async_context)); ep_buff[iEP_Base]._hProtoPending = false; } else { usb_free_async(&(ep_buff[iEP_Base]._async_context)); ASSERT(0); return SSI_STATUS_TIMEOUT; } return SSI_STATUS_NORMAL; } //=============================================================================== // _send_usb_data(iEP) sends data to the corresponding iEP channel. // iEP = EP_KEYENCE_01 / EP_KEYENCE_02 EP_KEYENCE_01 = 0x01; EP_KEYENCE_02 = 0x02; //=============================================================================== SSI_STATUS CKeyence_Proto::_send_usb_data(int iEP_Base) { int _ret; ep_buff[iEP_Base]._save_send_cmd = ep_buff[iEP_Base]._buffer[0]; ep_buff[iEP_Base]._save_send_cmd0 = ep_buff[iEP_Base]._buffer[1]; ep_buff[iEP_Base]._save_send_cmd1 = ep_buff[iEP_Base]._buffer[2]; TRACE3("_send_usb_data() iEP : %X - ep_buff[iEP]._save_send_cmd : %X ._buffer[0] : %X\r\n", iEP_Base, ep_buff[EP_01_CMD_IDX]._save_send_cmd, ep_buff[EP_81_DATA_IDX]._buffer[0]); _ret = usb_bulk_setup_async(g_dev, &(ep_buff[iEP_Base]._async_context), (unsigned char)ep_buff[iEP_Base]._ep); if (_ret < 0) { return SSI_STATUS_SETUP_ASYNC_CONTEXT_ERROR; } _ret = usb_submit_async(ep_buff[iEP_Base]._async_context, ep_buff[iEP_Base]._buffer, ep_buff[iEP_Base]._size);//send data if (_ret < 0) { printf("error usb_submit_async_ep_xx:\n%s\n", usb_strerror()); return SSI_STATUS_SETUP_ASYNC_CONTEXT_ERROR; } TRACE1("_submit_async_8x(EP:%X)\r\n", iEP_Base); // ep_buff[iEP_Base+1]._save_send_cmd = ep_buff[iEP_Base+1]._buffer[0]; ep_buff[iEP_Base+1]._save_send_cmd0 = ep_buff[iEP_Base+1]._buffer[1]; ep_buff[iEP_Base+1]._save_send_cmd1 = ep_buff[iEP_Base+1]._buffer[2]; // _submit_async_8x(iEP_Base+1); // Send EP_KEYENCE_81/EP_KEYENCE_82 // Get ready to receive on EP_KEYENCE_81 or EP_KEYENCE_82 SetEvent(ep_buff[iEP_Base+1]._event); // Get ready to receive on EP_KEYENCE_01 or EP_KEYENCE_02 _ret = usb_reap_async(ep_buff[iEP_Base]._async_context, 10000); if (_ret > 0) { _process_rcv_transfer_data(iEP_Base); usb_free_async(&(ep_buff[iEP_Base]._async_context)); ep_buff[iEP_Base]._hProtoPending = false; } else { usb_free_async(&(ep_buff[iEP_Base]._async_context)); ASSERT(0); return SSI_STATUS_TIMEOUT; } return SSI_STATUS_NORMAL; } //============================================================== SSI_STATUS CKeyence_Proto::_send_cmd_KEYENCE_CMD_GET_LASER_DATA() { WaitForSingleObject(g_hEP01_Serial_Mutex, INFINITE); memset(ep_buff[EP_01_CMD_IDX]._buffer, 0x00, MAX_BUFF_SIZE); ep_buff[EP_01_CMD_IDX]._buffer[0] = 0x00; ep_buff[EP_01_CMD_IDX]._buffer[1] = 0x01; ep_buff[EP_01_CMD_IDX]._buffer[2] = 0x01; ep_buff[EP_01_CMD_IDX]._buffer[3] = 0x01; ep_buff[EP_01_CMD_IDX]._buffer[4] = 0x01; ep_buff[EP_01_CMD_IDX]._buffer[5] = 0x01; ep_buff[EP_01_CMD_IDX]._size = 0x0C; ep_buff[EP_82_DATA_IDX]._size = 0x45; _do_single_threaded_usb_comm(EP_01_CMD_IDX); ReleaseMutex(g_hEP01_Serial_Mutex); return SSI_STATUS_NORMAL; }; //============================================================== SSI_STATUS CKeyence_Proto::_process_KEYENCE_CMD_GET_LASER_DATA() { return SSI_STATUS_NORMAL; };