new functions: DefineCommDevice / QueryCommDevice / IsCommDevice
This commit is contained in:
parent
75ff8fd9a4
commit
f9fc107c20
@ -3,6 +3,7 @@
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -198,6 +199,7 @@
|
||||
#define RTS_CONTROL_HANDSHAKE 0x02
|
||||
#define RTS_CONTROL_TOGGLE 0x03
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214%28v=vs.85%29.aspx
|
||||
typedef struct _DCB
|
||||
{
|
||||
DWORD DCBlength;
|
||||
@ -334,11 +336,42 @@ WINPR_API BOOL TransmitCommChar(HANDLE hFile, char cChar);
|
||||
|
||||
WINPR_API BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask, LPOVERLAPPED lpOverlapped);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define BuildCommDCB BuildCommDCBW
|
||||
#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsW
|
||||
#define CommConfigDialog CommConfigDialogW
|
||||
#define GetDefaultCommConfig GetDefaultCommConfigW
|
||||
#define SetDefaultCommConfig SetDefaultCommConfigW
|
||||
#else
|
||||
#define BuildCommDCB BuildCommDCBA
|
||||
#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsA
|
||||
#define CommConfigDialog CommConfigDialogA
|
||||
#define GetDefaultCommConfig GetDefaultCommConfigA
|
||||
#define SetDefaultCommConfig SetDefaultCommConfigA
|
||||
#endif
|
||||
|
||||
/* Extended API */
|
||||
|
||||
/*
|
||||
* About DefineCommDevice() / QueryDosDevice()
|
||||
*
|
||||
* Did something close to QueryDosDevice() and DefineDosDevice() but with
|
||||
* folowing constraints:
|
||||
* - mappings are stored in a static wHashTable (thread safe)
|
||||
* - QueryCommDevice returns only the mappings that have been defined through DefineCommDevice()
|
||||
*/
|
||||
WINPR_API BOOL DefineCommDevice(/* DWORD dwFlags,*/ LPCTSTR lpDeviceName, LPCTSTR lpTargetPath);
|
||||
WINPR_API DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax);
|
||||
WINPR_API BOOL IsCommDevice(LPCTSTR lpDeviceName);
|
||||
|
||||
WINPR_API HANDLE _CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* WINPR_COMM_H */
|
||||
|
||||
|
@ -35,7 +35,7 @@ set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SO
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL
|
||||
MODULE winpr
|
||||
MODULES winpr-crt winpr-thread winpr-synch winpr-utils)
|
||||
MODULES winpr-crt winpr-file winpr-utils)
|
||||
|
||||
if(MONOLITHIC_BUILD)
|
||||
set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)
|
||||
|
@ -3,6 +3,7 @@
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -23,6 +24,8 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/comm.h>
|
||||
#include <winpr/collections.h>
|
||||
#include <winpr/tchar.h>
|
||||
|
||||
/**
|
||||
* Communication Resources:
|
||||
@ -263,4 +266,245 @@ BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask, LPOVERLAPPED lpOverlapped)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Extended API */
|
||||
|
||||
/* FIXME: DefineCommDevice / QueryCommDevice look over complicated for
|
||||
* just a couple of strings, should be simplified.
|
||||
*
|
||||
* TODO: what about libwinpr-io.so?
|
||||
*/
|
||||
static wHashTable *_CommDevices = NULL;
|
||||
|
||||
static int deviceNameCmp(void* pointer1, void* pointer2)
|
||||
{
|
||||
return _tcscmp(pointer1, pointer2);
|
||||
}
|
||||
|
||||
|
||||
static int devicePathCmp(void* pointer1, void* pointer2)
|
||||
{
|
||||
return _tcscmp(pointer1, pointer2);
|
||||
}
|
||||
|
||||
/* copied from HashTable.c */
|
||||
static unsigned long HashTable_StringHashFunctionA(void* key)
|
||||
{
|
||||
int c;
|
||||
unsigned long hash = 5381;
|
||||
unsigned char* str = (unsigned char*) key;
|
||||
|
||||
/* djb2 algorithm */
|
||||
while ((c = *str++) != '\0')
|
||||
hash = (hash * 33) + c;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
static void _CommDevicesInit()
|
||||
{
|
||||
/*
|
||||
* TMP: FIXME: What kind of mutex should be used here?
|
||||
* better have to let DefineCommDevice() and QueryCommDevice() thread unsafe ?
|
||||
* use of a module_init() ?
|
||||
*/
|
||||
|
||||
if (_CommDevices == NULL)
|
||||
{
|
||||
_CommDevices = HashTable_New(TRUE);
|
||||
_CommDevices->keycmp = deviceNameCmp;
|
||||
_CommDevices->valuecmp = devicePathCmp;
|
||||
_CommDevices->hashFunction = HashTable_StringHashFunctionA; /* TMP: FIXME: need of a HashTable_StringHashFunctionW */
|
||||
_CommDevices->keyDeallocator = free;
|
||||
_CommDevices->valueDeallocator = free;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static BOOL _IsReservedCommDeviceName(LPCTSTR lpName)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Serial ports, COM1-9 */
|
||||
for (i=1; i<10; i++)
|
||||
{
|
||||
TCHAR genericName[5];
|
||||
if (_stprintf_s(genericName, 5, "COM%d", i) < 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (_tcscmp(genericName, lpName) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Parallel ports, LPT1-9 */
|
||||
for (i=1; i<10; i++)
|
||||
{
|
||||
TCHAR genericName[5];
|
||||
if (_stprintf_s(genericName, 5, "LPT%d", i) < 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (_tcscmp(genericName, lpName) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* TMP: TODO: PRN ? */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns TRUE on success, FALSE otherwise. To get extended error
|
||||
* information, call GetLastError.
|
||||
*
|
||||
* ERRORS:
|
||||
* ERROR_OUTOFMEMORY was not possible to get mappings.
|
||||
* ERROR_INVALID_DATA was not possible to add the device.
|
||||
*/
|
||||
BOOL DefineCommDevice(/* DWORD dwFlags,*/ LPCTSTR lpDeviceName, LPCTSTR lpTargetPath)
|
||||
{
|
||||
LPTSTR storedDeviceName = NULL;
|
||||
LPTSTR storedTargetPath = NULL;
|
||||
|
||||
_CommDevicesInit();
|
||||
if (_CommDevices == NULL)
|
||||
{
|
||||
SetLastError(ERROR_OUTOFMEMORY);
|
||||
goto error_handle;
|
||||
}
|
||||
|
||||
if (_tcsncmp(lpDeviceName, _T("\\\\.\\"), 4) != 0)
|
||||
{
|
||||
if (!_IsReservedCommDeviceName(lpDeviceName))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_DATA);
|
||||
goto error_handle;
|
||||
}
|
||||
}
|
||||
|
||||
storedDeviceName = _tcsdup(lpDeviceName);
|
||||
if (storedDeviceName == NULL)
|
||||
{
|
||||
SetLastError(ERROR_OUTOFMEMORY);
|
||||
goto error_handle;
|
||||
}
|
||||
|
||||
storedTargetPath = _tcsdup(lpTargetPath);
|
||||
if (storedTargetPath == NULL)
|
||||
{
|
||||
SetLastError(ERROR_OUTOFMEMORY);
|
||||
goto error_handle;
|
||||
}
|
||||
|
||||
if (HashTable_Add(_CommDevices, storedDeviceName, storedTargetPath) < 0)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_DATA);
|
||||
goto error_handle;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
|
||||
error_handle:
|
||||
if (storedDeviceName != NULL)
|
||||
free(storedDeviceName);
|
||||
|
||||
if (storedTargetPath != NULL)
|
||||
free(storedTargetPath);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of target paths in the buffer pointed to by
|
||||
* lpTargetPath.
|
||||
*
|
||||
* The current implementation returns in any case 0 and 1 target
|
||||
* path. A NULL lpDeviceName is not supported yet to get all the
|
||||
* paths.
|
||||
*
|
||||
* ERRORS:
|
||||
* ERROR_SUCCESS
|
||||
* ERROR_OUTOFMEMORY was not possible to get mappings.
|
||||
* ERROR_NOT_SUPPORTED equivalent QueryDosDevice feature not supported.
|
||||
* ERROR_INVALID_DATA was not possible to retrieve any device information.
|
||||
* ERROR_INSUFFICIENT_BUFFER too small lpTargetPath
|
||||
*/
|
||||
DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax)
|
||||
{
|
||||
LPTSTR storedTargetPath;
|
||||
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
_CommDevicesInit();
|
||||
if (_CommDevices == NULL)
|
||||
{
|
||||
SetLastError(ERROR_OUTOFMEMORY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lpDeviceName == NULL || lpTargetPath == NULL)
|
||||
{
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
storedTargetPath = HashTable_GetItemValue(_CommDevices, (void*)lpDeviceName);
|
||||
if (storedTargetPath == NULL)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_DATA);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_tcslen(storedTargetPath) + 2 > ucchMax)
|
||||
{
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_tcscpy(lpTargetPath, storedTargetPath);
|
||||
_tcscat(lpTargetPath, ""); /* 2nd final '\0' */
|
||||
|
||||
return _tcslen(lpTargetPath) + 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether lpDeviceName is a valid and registered Communication device.
|
||||
*/
|
||||
BOOL IsCommDevice(LPCTSTR lpDeviceName)
|
||||
{
|
||||
TCHAR lpTargetPath[MAX_PATH];
|
||||
|
||||
if (QueryCommDevice(lpDeviceName, lpTargetPath, MAX_PATH) > 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
HANDLE _CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
|
||||
{
|
||||
HANDLE hComm;
|
||||
WINPR_COMM* pComm;
|
||||
|
||||
//SetLastError(ERROR_BAD_PATHNAME);
|
||||
|
||||
pComm = (WINPR_COMM*) calloc(1, sizeof(WINPR_COMM));
|
||||
hComm = (HANDLE) pComm;
|
||||
|
||||
WINPR_HANDLE_SET_TYPE(pComm, HANDLE_TYPE_COMM);
|
||||
|
||||
//return INVALID_HANDLE_VALUE;
|
||||
return hComm;
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
@ -5,6 +5,7 @@ set(MODULE_PREFIX "TEST_COMM")
|
||||
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
|
||||
|
||||
set(${MODULE_PREFIX}_TESTS
|
||||
TestCommDevice.c
|
||||
TestCommConfig.c
|
||||
TestCommMonitor.c)
|
||||
|
||||
@ -17,7 +18,7 @@ add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE winpr
|
||||
MODULES winpr-comm winpr-crt)
|
||||
MODULES winpr-comm winpr-crt winpr-file)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
|
115
winpr/libwinpr/comm/test/TestCommDevice.c
Normal file
115
winpr/libwinpr/comm/test/TestCommDevice.c
Normal file
@ -0,0 +1,115 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Serial Communication API
|
||||
*
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <winpr/comm.h>
|
||||
#include <winpr/tchar.h>
|
||||
|
||||
static int test_CommDevice(LPCTSTR lpDeviceName, BOOL expectedResult)
|
||||
{
|
||||
BOOL result;
|
||||
TCHAR lpTargetPath[MAX_PATH];
|
||||
DWORD tcslen;
|
||||
|
||||
result = DefineCommDevice(lpDeviceName, _T("/dev/test"));
|
||||
if ((!expectedResult && result) || (expectedResult && !result)) /* logical XOR */
|
||||
{
|
||||
_tprintf(_T("DefineCommDevice failure: device name: %s, expected result: %s, result: %s\n"),
|
||||
lpDeviceName,
|
||||
(expectedResult ? "TRUE" : "FALSE"),
|
||||
(result ? "TRUE" : "FALSE"));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
result = IsCommDevice(lpDeviceName);
|
||||
if ((!expectedResult && result) || (expectedResult && !result)) /* logical XOR */
|
||||
{
|
||||
_tprintf(_T("IsCommDevice failure: device name: %s, expected result: %s, result: %s\n"),
|
||||
lpDeviceName,
|
||||
(expectedResult ? "TRUE" : "FALSE"),
|
||||
(result ? "TRUE" : "FALSE"));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tcslen = QueryCommDevice(lpDeviceName, lpTargetPath, MAX_PATH);
|
||||
if (expectedResult)
|
||||
{
|
||||
if (tcslen <= _tcslen(lpDeviceName)) /* at least 2 more TCHAR are expected */
|
||||
{
|
||||
_tprintf(_T("QueryCommDevice failure: didn't found the device name: %s\n"), lpDeviceName);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (_tcscmp(_T("/dev/test"), lpTargetPath) != 0)
|
||||
{
|
||||
_tprintf(_T("QueryCommDevice failure: device name: %s, expected result: %s, result: %s\n"),
|
||||
lpDeviceName, _T("/dev/test"), lpTargetPath);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (lpTargetPath[_tcslen(lpTargetPath) + 1] != NULL)
|
||||
{
|
||||
_tprintf(_T("QueryCommDevice failure: device name: %s, the second NULL character is missing at the end of the buffer\n"), lpDeviceName);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tcslen > 0)
|
||||
{
|
||||
_tprintf(_T("QueryCommDevice failure: device name: %s, expected result: <none>, result: %d %s\n"),
|
||||
lpDeviceName, tcslen, lpTargetPath);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
int TestCommDevice(int argc, char* argv[])
|
||||
{
|
||||
if (!test_CommDevice(_T("COM0"), FALSE))
|
||||
return 1;
|
||||
|
||||
if (!test_CommDevice(_T("COM1"), TRUE))
|
||||
return 1;
|
||||
|
||||
if (!test_CommDevice(_T("COM1"), TRUE))
|
||||
return 1;
|
||||
|
||||
if (!test_CommDevice(_T("COM10"), FALSE))
|
||||
return 1;
|
||||
|
||||
if (!test_CommDevice(_T("\\\\.\\COM5"), TRUE))
|
||||
return 1;
|
||||
|
||||
if (!test_CommDevice(_T("\\\\.\\COM10"), TRUE))
|
||||
return 1;
|
||||
|
||||
if (!test_CommDevice(_T("\\\\.COM10"), FALSE))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
* File Functions
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -183,7 +184,6 @@
|
||||
#include "../handle/handle.h"
|
||||
|
||||
#include "../pipe/pipe.h"
|
||||
#include "../comm/comm.h"
|
||||
|
||||
#ifdef HAVE_AIO_H
|
||||
|
||||
@ -228,18 +228,14 @@ HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
if (!lpFileName)
|
||||
return INVALID_HANDLE_VALUE;
|
||||
|
||||
if (!IsNamedPipeFileNameA(lpFileName))
|
||||
{
|
||||
HANDLE hComm;
|
||||
WINPR_COMM* pComm;
|
||||
/* TMP: TODO: */
|
||||
/* if (IsCommDevice(lpFileName)) */
|
||||
/* { */
|
||||
/* return _CommCreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, */
|
||||
/* dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); */
|
||||
/* } */
|
||||
|
||||
pComm = (WINPR_COMM*) calloc(1, sizeof(WINPR_COMM));
|
||||
hComm = (HANDLE) pComm;
|
||||
|
||||
WINPR_HANDLE_SET_TYPE(pComm, HANDLE_TYPE_COMM);
|
||||
|
||||
return hComm;
|
||||
}
|
||||
/* FIXME: at this point lpFileName is not necessary a named pipe */
|
||||
|
||||
name = GetNamedPipeNameWithoutPrefixA(lpFileName);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user