123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- /*
- This software is subject to the license described in the License.txt file
- included with this software distribution. You may not use this file except
- in compliance with this license.
- Copyright (c) Dynastream Innovations Inc. 2016
- All rights reserved.
- */
- #include "types.h"
- #if defined(DSI_TYPES_WINDOWS)
- #include "defines.h"
- #include "dsi_serial_vcp.hpp"
- #include "macros.h"
- //#include "usb_device_handle_si.hpp"
- #include <stdio.h>
- #include <string.h>
- #include <windows.h>
- #if defined(_MSC_VER)
- #include "WinDevice.h"
- #endif
- #include <vector>
- using namespace std;
- //#define NUMBER_OF_DEVICES_CHECK_THREAD_KILL //Only include this if we are sure we want to terminate the Rx thread if the number of devices are ever reduced.
- //////////////////////////////////////////////////////////////////////////////////
- // Private Definitions
- //////////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////////
- // Public Methods
- //////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////
- // Constructor
- ///////////////////////////////////////////////////////////////////////
- DSISerialVCP::DSISerialVCP()
- {
- hReceiveThread = NULL;
- hComm = INVALID_HANDLE_VALUE;
- }
- ///////////////////////////////////////////////////////////////////////
- // Destructor
- ///////////////////////////////////////////////////////////////////////
- DSISerialVCP::~DSISerialVCP()
- {
- Close();
- }
- ///////////////////////////////////////////////////////////////////////
- // Initializes and opens the object.
- ///////////////////////////////////////////////////////////////////////
- BOOL DSISerialVCP::AutoInit()
- {
- return FALSE; // unsupported
- }
- ///////////////////////////////////////////////////////////////////////
- // Initializes the object.
- ///////////////////////////////////////////////////////////////////////
- BOOL DSISerialVCP::Init(ULONG ulBaud_, UCHAR ucDeviceNumber_)
- {
- ulBaud = ulBaud_;
- ucDeviceNumber = ucDeviceNumber_; // make sure device number is in acceptable range for COM number translation
- return TRUE;
- }
- ///////////////////////////////////////////////////////////////////////
- // Opens port, starts receive thread.
- ///////////////////////////////////////////////////////////////////////
- BOOL DSISerialVCP::Open(void)
- {
- // Make sure all handles are reset before opening again.
- Close();
- if (pclCallback == NULL)
- return FALSE;
- bStopReceiveThread = FALSE;
- if(DSIThread_MutexInit(&stMutexCriticalSection) != DSI_THREAD_ENONE)
- {
- Close();
- return FALSE;
- }
- if(DSIThread_CondInit(&stEventReceiveThreadExit) != DSI_THREAD_ENONE)
- {
- DSIThread_MutexDestroy(&stMutexCriticalSection);
- Close();
- return FALSE;
- }
- //long enough to hold '\\.\COM255' and a null
- LPSTR lpstrComPort = new CHAR[11];
- SNPRINTF(lpstrComPort, 11, "\\\\.\\COM%u", ucDeviceNumber);
- hComm = CreateFile( lpstrComPort,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- 0,
- OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED,
- 0);
- //clean up after ourselves
- delete lpstrComPort;
- if (hComm == INVALID_HANDLE_VALUE)
- {
- DSIThread_CondDestroy(&stEventReceiveThreadExit);
- DSIThread_MutexDestroy(&stMutexCriticalSection);
- Close();
- return FALSE;
- }
- FillMemory(&dcb, sizeof(dcb), 0);
- dcb.DCBlength = sizeof(dcb);
- if (!GetCommState(hComm, &dcb))
- {
- DSIThread_CondDestroy(&stEventReceiveThreadExit);
- DSIThread_MutexDestroy(&stMutexCriticalSection);
- Close();
- return FALSE;
- }
- //if (!BuildCommDCB("57600,n,8,1", &dcb)) {
- // Couldn't build the DCB. Usually a problem
- // with the communications specification string.
- // return FALSE;
- //}
- dcb.BaudRate = ulBaud;
- dcb.ByteSize = 8;
- dcb.fParity = 0;
- dcb.Parity = 0;//NOPARITY; // no parity
- dcb.StopBits = 0;//ONESTOPBIT; // one stop bit
- dcb.fOutxCtsFlow = FALSE;
- dcb.fOutxDsrFlow = FALSE;
- dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
- if (!SetCommState(hComm, &dcb))
- {
- DSIThread_CondDestroy(&stEventReceiveThreadExit);
- DSIThread_MutexDestroy(&stMutexCriticalSection);
- Close();
- return FALSE;
- }
- COMMTIMEOUTS commTimeout;
- if (!GetCommTimeouts(hComm, &commTimeout))
- {
- DSIThread_CondDestroy(&stEventReceiveThreadExit);
- DSIThread_MutexDestroy(&stMutexCriticalSection);
- Close();
- return FALSE;
- }
- commTimeout.ReadIntervalTimeout = 0;
- commTimeout.ReadTotalTimeoutMultiplier = 0;
- commTimeout.ReadTotalTimeoutConstant = 0;
- if (!SetCommTimeouts(hComm, &commTimeout))
- {
- DSIThread_CondDestroy(&stEventReceiveThreadExit);
- DSIThread_MutexDestroy(&stMutexCriticalSection);
- Close();
- return FALSE;
- }
- hReceiveThread = DSIThread_CreateThread(&DSISerialVCP::ProcessThread, this);
- if(hReceiveThread == NULL)
- {
- DSIThread_MutexDestroy(&stMutexCriticalSection);
- DSIThread_CondDestroy(&stEventReceiveThreadExit);
- Close();
- return FALSE;
- }
- return TRUE;
- }
- ///////////////////////////////////////////////////////////////////////
- // Closes the USB connection, kills receive thread.
- ///////////////////////////////////////////////////////////////////////
- void DSISerialVCP::Close(BOOL /*bReset*/) //Commented to avoid compiler warning about unreferenced formal parameter.
- {
- if(hReceiveThread)
- {
- DSIThread_MutexLock(&stMutexCriticalSection);
- if(bStopReceiveThread == FALSE)
- {
- bStopReceiveThread = TRUE;
- if (DSIThread_CondTimedWait(&stEventReceiveThreadExit, &stMutexCriticalSection, 3000) != DSI_THREAD_ENONE)
- {
- // We were unable to stop the thread normally.
- DSIThread_DestroyThread(hReceiveThread);
- }
- }
- DSIThread_MutexUnlock(&stMutexCriticalSection);
- DSIThread_ReleaseThreadID(hReceiveThread);
- hReceiveThread = NULL;
- DSIThread_MutexDestroy(&stMutexCriticalSection);
- DSIThread_CondDestroy(&stEventReceiveThreadExit);
- }
- if (hComm != INVALID_HANDLE_VALUE)
- {
- // lower DTR
- //
- if (!EscapeCommFunction(hComm, CLRDTR))
- pclCallback->Error(255);
- //
- // restore original comm timeouts
- //
- //if (!SetCommTimeouts(COMDEV(TTYInfo), &(TIMEOUTSORIG(TTYInfo))))
- // pclCallback->Error(255);
- //
- // Purge reads/writes, input buffer and output buffer
- //
- if (!PurgeComm(hComm, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR))
- pclCallback->Error(255);
- CloseHandle(hComm);
- hComm = INVALID_HANDLE_VALUE;
- }
- return;
- }
- ///////////////////////////////////////////////////////////////////////
- // Writes ucSize_ bytes to USB, returns number of bytes not written.
- ///////////////////////////////////////////////////////////////////////
- BOOL DSISerialVCP::WriteBytes(void *pvData_, USHORT usSize_)
- {
- DWORD dwWritten;
- BOOL fRes;
- OVERLAPPED osWrite = {0};
- if(hComm == INVALID_HANDLE_VALUE || pvData_ == NULL)
- return FALSE;
- // Create this writes OVERLAPPED structure hEvent.
- osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (osWrite.hEvent == NULL)
- // Error creating overlapped event handle.
- return FALSE;
- // Issue write.
- if (!WriteFile(hComm, pvData_, (DWORD)usSize_, &dwWritten, &osWrite)) {
- if (GetLastError() != ERROR_IO_PENDING) {
- // WriteFile failed, but it isn't delayed. Report error and abort.
- fRes = FALSE;
- }
- else {
- // Write is pending.
- if (!GetOverlappedResult(hComm, &osWrite, &dwWritten, TRUE))
- fRes = FALSE;
- else
- // Write operation completed successfully.
- fRes = TRUE;
- }
- }
- else
- // WriteFile completed immediately.
- fRes = TRUE;
- CloseHandle(osWrite.hEvent);
- if (!fRes)
- pclCallback->Error(DSI_SERIAL_EWRITE);
- return fRes;
- }
- ///////////////////////////////////////////////////////////////////////
- // Returns the device serial number.
- ///////////////////////////////////////////////////////////////////////
- ULONG DSISerialVCP::GetDeviceSerialNumber()
- {
- return 0xFFFFFFFF; // unsupported
- }
- ///////////////////////////////////////////////////////////////////////
- // Returns the device port number.
- ///////////////////////////////////////////////////////////////////////
- UCHAR DSISerialVCP::GetDeviceNumber()
- {
- return ucDeviceNumber;
- }
- //////////////////////////////////////////////////////////////////////////////////
- // Private Methods
- //////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////
- void DSISerialVCP::ReceiveThread(void)
- {
- UCHAR ucRxByte;
- DWORD ulRxBytesRead;
- DWORD dwCommEvent;
- OVERLAPPED osRead = {0};
- // while (hComm == INVALID_HANDLE_VALUE);
- if (!SetCommMask(hComm, EV_RXCHAR))
- pclCallback->Error(DSI_SERIAL_EREAD);
- while(!bStopReceiveThread)
- {
- if (WaitCommEvent(hComm, &dwCommEvent, NULL))
- {
- do
- {
- osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (osRead.hEvent == NULL) // Error creating overlapped event handle.
- break;
- if (ReadFile(hComm, &ucRxByte, 1, &ulRxBytesRead, &osRead))
- {
- pclCallback->ProcessByte(ucRxByte);
- }
- else
- {
- if (GetLastError() != ERROR_IO_PENDING)
- pclCallback->Error(DSI_SERIAL_EREAD);
- else
- {
- DWORD hRes;
- do
- {
- hRes = WaitForSingleObject(osRead.hEvent, 999);
- } while (hRes == WAIT_TIMEOUT);
- if (hRes == WAIT_OBJECT_0)
- {
- if (!GetOverlappedResult(hComm, &osRead, &ulRxBytesRead, TRUE))
- pclCallback->Error(DSI_SERIAL_EREAD);
- else
- pclCallback->ProcessByte(ucRxByte);
- }
- }
- }
- CloseHandle(osRead.hEvent);
- } while (ulRxBytesRead);
- }
- else
- {
- pclCallback->Error(DSI_SERIAL_EREAD);
- }
- }
- DSIThread_MutexLock(&stMutexCriticalSection);
- bStopReceiveThread = TRUE;
- DSIThread_CondSignal(&stEventReceiveThreadExit); // Set an event to alert the main process that Rx thread is finished and can be closed.
- DSIThread_MutexUnlock(&stMutexCriticalSection);
- }
- ///////////////////////////////////////////////////////////////////////
- DSI_THREAD_RETURN DSISerialVCP::ProcessThread(void *pvParameter_)
- {
- DSISerialVCP *This = (DSISerialVCP *) pvParameter_;
- This->ReceiveThread();
- return 0;
- }
- #endif //defined(DSI_TYPES_WINDOWS)
|