diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a37531e..6aface0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,6 +49,61 @@ jobs: tag: ${{ github.ref }} repo_token: ${{ secrets.GITHUB_TOKEN }} + build-win32: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + include: + - { name: win32-x64, os: windows-latest } + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + submodules: recursive + + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + release: false + install: >- + git + zip + mingw-w64-x86_64-toolchain + mingw-w64-x86_64-cmake + mingw-w64-x86_64-ninja + + - name: Build + shell: msys2 {0} + run: | + cmake -G Ninja -B build + cmake --build build --config Release + ctest --test-dir build --build-config Release --output-on-failure + + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: cp2102-${{ matrix.name }} + path: | + build/cp2102/cp2102.exe + build/cp2102/CP210xRuntime.dll + if-no-files-found: error + + - name: Pack release assets + if: ${{ startsWith(github.ref, 'refs/tags/v') }} + shell: msys2 {0} + run: zip -9 -j cp2102-${{ matrix.name }}.zip build/cp2102/cp2102.exe build/cp2102/CP210xRuntime.dll + + - name: Release + if: ${{ startsWith(github.ref, 'refs/tags/v') }} + uses: svenstaro/upload-release-action@v2 + with: + file: cp2102-${{ matrix.name }}.zip + tag: ${{ github.ref }} + repo_token: ${{ secrets.GITHUB_TOKEN }} + build-docker: runs-on: ubuntu-latest diff --git a/CMakeLists.txt b/CMakeLists.txt index b4e4b59..48bc13b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,4 +6,6 @@ add_subdirectory(cp2102) add_subdirectory(libcp2102_usb) add_subdirectory(liblog) -add_subdirectory(libusb) +if(NOT WIN32) + add_subdirectory(libusb) +endif() diff --git a/cp2102/CMakeLists.txt b/cp2102/CMakeLists.txt index 5e9c05d..f05d97a 100644 --- a/cp2102/CMakeLists.txt +++ b/cp2102/CMakeLists.txt @@ -18,4 +18,12 @@ target_compile_options( -DGIT_INCREMENT=${GIT_INCREMENT} ) +if(WIN32) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + $/CP210xRuntime.dll + ${PROJECT_BINARY_DIR} + ) +endif() + install(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/libcp2102_usb/CMakeLists.txt b/libcp2102_usb/CMakeLists.txt index 41cae7a..912abdf 100644 --- a/libcp2102_usb/CMakeLists.txt +++ b/libcp2102_usb/CMakeLists.txt @@ -1,12 +1,18 @@ project(cp2102_usb) -set(SRCS "src/cp2102_libusb.c") +set(SRCS) + +if(WIN32) + list(APPEND SRCS "src/cp2102_win32.c") +else() + list(APPEND SRCS "src/cp2102_libusb.c") +endif() if(APPLE) list(APPEND SRCS "src/tty_utils_darwin.c") elseif(UNIX) list(APPEND SRCS "src/tty_utils_linux.c") -else() +elseif(NOT WIN32) list(APPEND SRCS "src/tty_utils_dummy.c") endif() @@ -18,7 +24,21 @@ target_include_directories( ) target_link_libraries(${PROJECT_NAME} log) -target_link_libraries(${PROJECT_NAME} usb) + +if(WIN32) + set(CP210XRT_DIR ${PROJECT_SOURCE_DIR}/cp210xrt) + + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CP210XRT_DIR}/CP210xRuntime.dll + ${PROJECT_BINARY_DIR} + ) + + target_include_directories(${PROJECT_NAME} PRIVATE ${CP210XRT_DIR}) + target_link_libraries(${PROJECT_NAME} ${CP210XRT_DIR}/CP210xRuntime.dll) +else() + target_link_libraries(${PROJECT_NAME} usb) +endif() if(APPLE) target_link_libraries(${PROJECT_NAME} "-framework IOKit") diff --git a/libcp2102_usb/cp210xrt/CP210xRuntime.dll b/libcp2102_usb/cp210xrt/CP210xRuntime.dll new file mode 100644 index 0000000..ab78642 Binary files /dev/null and b/libcp2102_usb/cp210xrt/CP210xRuntime.dll differ diff --git a/libcp2102_usb/cp210xrt/CP210xRuntime.lib b/libcp2102_usb/cp210xrt/CP210xRuntime.lib new file mode 100644 index 0000000..c1d4183 Binary files /dev/null and b/libcp2102_usb/cp210xrt/CP210xRuntime.lib differ diff --git a/libcp2102_usb/cp210xrt/CP210xRuntimeDLL.h b/libcp2102_usb/cp210xrt/CP210xRuntimeDLL.h new file mode 100644 index 0000000..b2c1f8c --- /dev/null +++ b/libcp2102_usb/cp210xrt/CP210xRuntimeDLL.h @@ -0,0 +1,358 @@ +// TODO: Header guards? Or is that what _CP210x_STANDARD_DEF_ is doing? If so, that same token is used in CP210xRuntimeDLL.h, is that by design, or error? +#ifndef HOST_LIB_RUNTIME_INCLUDE_CP210XRUNTIMEDLL_H_INCLUDED_QU4N7WC20W +#define HOST_LIB_RUNTIME_INCLUDE_CP210XRUNTIMEDLL_H_INCLUDED_QU4N7WC20W + +/// @addtogroup runtime CP201x Runtime Library +/// +/// The Silicon Labs CP210x USB-to-UART bridges are devices that communicate over +/// the Universal Serial Bus(USB) to perform Universal Asynchronous Receiver / Transmitter +/// (UART) data transfers. These devices have many programmable options that can +/// be configured via USB. These devices also often include flexible GPIO functions that +/// can be configured and accessed via USB during runtime. Silicon Labs provides libraries +/// that can be used to configure these devices and access their GPIOs. +/// +/// Two interface library files can be used to interface with CP210x devices, CP210xManufacturing.DLL and .LIB, which is responsible for reading and writing +/// the device settings, and CP210xRuntime.DLL and .LIB, which is responsible for interfacing with the device's GPIOs. The APIs for CP210xRuntime are +/// described below. +/// +/// This document supercedes, obsoletes and takes precedences over AN978. +/// +/// The CP210x Runtime Host API provides access to the GPIO port latch, and is meant for distribution with the product containing a CP210x +/// device. +/// +/// Typically, the user initiates communication with the target CP210x device by opening a handle to a COM port using CreateFile() (See +/// AN197: Serial Communication Guide for CP210x). The handle returned allows the user to call the API functions listed below. +/// +/// @note: Function calls into this API are blocked until completed. This can take several milliseconds depending on USB traffic. +/// +/// @{ + +#include // For C99 fixed sized types +#include // For C99 _Bool + +#include "silabs_defs.h" +#include "silabs_sal.h" + +#ifdef _WIN32 +// The following ifdef block is the standard way of creating macros which make exporting +// from a DLL simpler. All files within this DLL are compiled with the CP210xRUNTIMEDLL_EXPORTS +// symbol defined on the command line. this symbol should not be defined on any project +// that uses this DLL. This way any other project whose source files include this file see +// CP210xRUNTIMEDLL_API functions as being imported from a DLL, wheras this DLL sees symbols +// defined with this macro as being exported. +#ifdef CP210xRUNTIMEDLL_EXPORTS +#define CP210xRUNTIMEDLL_API +#else +#define CP210xRUNTIMEDLL_API __declspec(dllimport) +#pragma comment (lib, "CP210xRuntime.lib") +#endif +#else // !_WIN32 +#define CP210xDLL_API +#define WINAPI +#define CP210xRUNTIMEDLL_API +#endif // !_WIN32 + + +// CP210xRT_GetPartNumber() returned PartNums (@deprecated {instead see silabs_defs.h::CP210X_PARTNUM}) +#define CP210x_CP2101_VERSION CP210x_PARTNUM_CP2101 ///< @deprecated use @ref CP210x_PARTNUM_CP2101 +#define CP210x_CP2102_VERSION CP210x_PARTNUM_CP2102 ///< @deprecated use @ref CP210x_PARTNUM_CP2102 +#define CP210x_CP2103_VERSION CP210x_PARTNUM_CP2103 ///< @deprecated use @ref CP210x_PARTNUM_CP2103 +#define CP210x_CP2104_VERSION CP210x_PARTNUM_CP2104 ///< @deprecated use @ref CP210x_PARTNUM_CP2104 +#define CP210x_CP2105_VERSION CP210x_PARTNUM_CP2105 ///< @deprecated use @ref CP210x_PARTNUM_CP2105 +#define CP210x_CP2108_VERSION CP210x_PARTNUM_CP2108 ///< @deprecated use @ref CP210x_PARTNUM_CP2108 +#define CP210x_CP2109_VERSION CP210x_PARTNUM_CP2109 ///< @deprecated use @ref CP210x_PARTNUM_CP2109 +#define CP210x_CP2102N_QFN28_VERSION CP210x_PARTNUM_CP2102N_QFN28 ///< @deprecated use @ref CP210x_PARTNUM_CP2102N_QFN28 +#define CP210x_CP2102N_QFN24_VERSION CP210x_PARTNUM_CP2102N_QFN24 ///< @deprecated use @ref CP210x_PARTNUM_CP2102N_QFN24 +#define CP210x_CP2102N_QFN20_VERSION CP210x_PARTNUM_CP2102N_QFN20 ///< @deprecated use @ref CP210x_PARTNUM_CP2102N_QFN20 + + +/// API Status return codes +#if defined(NOT_YET) +typedef enum _CP210x_STATUS { + CP210x_SUCCESS = SILABS_STATUS_SUCCESS + , CP210x_INVALID_HANDLE = 0x01 ///< an handle parameter was not valid + , CP210x_INVALID_PARAMETER = 0x02 ///< a parameter was not valid + , CP210x_DEVICE_IO_FAILED = 0x03 ///< device I/O failed + , CP210x_FUNCTION_NOT_SUPPORTED = 0x04 ///< the specified function is not supported + , CP210x_GLOBAL_DATA_ERROR = 0x05 ///< global data error + , CP210x_FILE_ERROR = 0x06 ///< file error + , CP210x_COMMAND_FAILED = 0x08 ///< command failed + , CP210x_INVALID_ACCESS_TYPE = 0x09 ///< invalid access type + + , CP210x_DEVICE_NOT_FOUND = 0xFF ///< the specified device was not found +} CP210x_STATUS, *PCP210x_STATUS; +#else // defined(NOT_YET) +/// @defgroup RTCP210x_STATUS +/// @{ +#define CP210x_SUCCESS SILABS_STATUS_SUCCESS ///< Success +#define CP210x_INVALID_HANDLE 0x01 ///< an handle parameter was not valid +#define CP210x_INVALID_PARAMETER 0x02 ///< a parameter was not valid +#define CP210x_DEVICE_IO_FAILED 0x03 ///< device I/O failed +#define CP210x_FUNCTION_NOT_SUPPORTED 0x04 ///< the specified function is not supported +#define CP210x_GLOBAL_DATA_ERROR 0x05 ///< global data error +#define CP210x_FILE_ERROR 0x06 ///< file error +#define CP210x_COMMAND_FAILED 0x08 ///< command failed +#define CP210x_INVALID_ACCESS_TYPE 0x09 ///< invalid access type +#define CP210x_DEVICE_NOT_FOUND 0xFF ///< the specified device was not found +typedef int CP210x_STATUS; +/// @} +#endif // defined(NOT_YET) + +// Buffer size limits +#define CP210x_MAX_PRODUCT_STRLEN 126 +#define CP210x_MAX_SERIAL_STRLEN 63 + +// Type definitions +typedef char CP210x_PRODUCT_STRING[CP210x_MAX_PRODUCT_STRLEN]; +typedef char CP210x_SERIAL_STRING[CP210x_MAX_SERIAL_STRLEN]; + +// Mask and Latch value bit definitions +#define CP210x_GPIO_0 0x0001 +#define CP210x_GPIO_1 0x0002 +#define CP210x_GPIO_2 0x0004 +#define CP210x_GPIO_3 0x0008 +#define CP210x_GPIO_4 0x0010 +#define CP210x_GPIO_5 0x0020 +#define CP210x_GPIO_6 0x0040 +#define CP210x_GPIO_7 0x0080 +#define CP210x_GPIO_8 0x0100 +#define CP210x_GPIO_9 0x0200 +#define CP210x_GPIO_10 0x0400 +#define CP210x_GPIO_11 0x0800 +#define CP210x_GPIO_12 0x1000 +#define CP210x_GPIO_13 0x2000 +#define CP210x_GPIO_14 0x4000 +#define CP210x_GPIO_15 0x8000 + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus +/// @brief Determines the number of CP210x devices connected to the system +/// +/// @param[out] lpdwNumDevices a pointer to a uint32_t location to hold the returned device count +/// +/// @returns Returns #CP210x_SUCCESS on success, or another @ref CP210x_STATUS Return value if there is an error. +/// @retval #CP210x_SUCCESS -- success +/// @retval #CP210x_INVALID_PARAMETER -- lpdwNumDevices is an unexpected value +_Check_return_ +_Ret_range_(CP210x_SUCCESS, CP210x_DEVICE_NOT_FOUND) +_Success_(return == CP210x_SUCCESS) +CP210xRUNTIMEDLL_API CP210x_STATUS WINAPI +CP210xRT_GetNumDevices( + _Out_writes_bytes_(sizeof(uint32_t)) _Pre_defensive_ uint32_t *lpdwNumDevices + ); + +/// @brief Opens a handle to the device +/// +/// @detail Opens and returns a handle to a device using a device index determined by the number returned +/// from @ref CP210x_GetNumDevices(). +/// +/// @param[in] dwDeviceIndex is the desired device's index into the device list used to determine @ref CP210xRT_GetNumDevices() +/// @param[out] pcyHandle is a pointer to a HANDLE/4-byte location to hold the returned open handle to the device +/// +/// @returns Returns #CP210x_SUCCESS on success, or another @ref CP210x_STATUS Return value if there is an error. +/// @retval #CP210x_SUCCESS -- success +/// @retval #CP210x_INVALID_PARAMETER -- pcyHandle is an unexpected value +/// @retval #CP210x_DEVICE_NOT_FOUND -- the device specified by the dwDeviceIndex was not found +/// @retval #TBD -- tbd +_Check_return_ +_Ret_range_(CP210x_SUCCESS, CP210x_DEVICE_NOT_FOUND) +_Success_(return == CP210x_SUCCESS) +CP210xRUNTIMEDLL_API CP210x_STATUS WINAPI +CP210xRT_Open( + _In_ _Pre_defensive_ const uint32_t DeviceIndex, + _Out_writes_bytes_(sizeof(HANDLE)) _Pre_defensive_ PHANDLE pcyHandle +); + +/// @brief Closes an open handle to the device +/// +/// @param[in] cyHandle is an open handle to the device +/// +/// @returns Returns #CP210x_SUCCESS on success, or another @ref CP210x_STATUS Return value if there is an error. +/// @retval #CP210x_SUCCESS -- success +/// @retval #CP210x_INVALID_HANDLE -- cyHandle is invalid +_Ret_range_(CP210x_SUCCESS, CP210x_DEVICE_NOT_FOUND) +_Success_(return == CP210x_SUCCESS) +CP210xRUNTIMEDLL_API CP210x_STATUS WINAPI +CP210xRT_Close( + _In_ _Pre_defensive_ const HANDLE cyHandle +); + +/// Reads and returns the current GPIO port latch value from the device +/// +/// @param[in] cyHandle is an open handle to the device +/// @param[out] lpwLatch points at a 2-byte buffer into which the port latch value will be written +/// +/// @note Supported on CP210x devices @ref IsWriteReadLatchPartNum() +/// +/// @returns Returns #CP210x_SUCCESS on success, or another @ref RTCP210x_STATUS Return value if there is an error. +/// @retval #CP210x_SUCCESS -- success +/// @retval #CP210x_INVALID_HANDLE -- cyHandle is invalid +/// @retval #CP210x_INVALID_PARAMETER -- lpwLatch is an unexpected value +/// @retval #CP210x_DEVICE_NOT_FOUND -- the device could not be determined to be a CP210x device +/// @retval #CP210x_FUNCTION_NOT_SUPPORTED -- the device does not support port latch +/// @retval #CP210x_DEVICE_IO_FAILED -- the device failed to respond to I/O in any expected manner +_Check_return_ +_Ret_range_(CP210x_SUCCESS, CP210x_DEVICE_NOT_FOUND) +_Success_(return == CP210x_SUCCESS) +CP210xRUNTIMEDLL_API CP210x_STATUS WINAPI +CP210xRT_ReadLatch(_In_ _Pre_defensive_ const HANDLE cyHandle, + _Out_writes_bytes_(sizeof(WORD)) _Pre_defensive_ LPWORD lpwLatch); + +/// @brief Writes a new GPIO port latch value to the device +/// +/// @param[in] cyHandle is an open handle to the device +/// @param[in] mask is a bit-mask which determines which pins to change [Change = 1, Do not change = 0]. +/// @param[in] latch is the new 2-byte GPIO port latch value to be written to the device +/// +/// @note Supported on CP210x devices @ref IsWriteReadLatchPartNum() +/// +/// @returns Returns #CP210x_SUCCESS on success, or another @ref RTCP210x_STATUS Return value if there is an error. +/// @retval #CP210x_SUCCESS -- success +/// @retval #CP210x_INVALID_HANDLE -- cyHandle is invalid +/// @retval #CP210x_DEVICE_NOT_FOUND -- the device could not be determined to be a CP210x device +/// @retval #CP210x_FUNCTION_NOT_SUPPORTED -- the device does not support port latch +/// @retval #CP210x_DEVICE_IO_FAILED -- the device failed to respond to I/O in any expected manner +_Check_return_ +_Ret_range_(CP210x_SUCCESS, CP210x_DEVICE_NOT_FOUND) +_Success_(return == CP210x_SUCCESS) +CP210xRUNTIMEDLL_API CP210x_STATUS WINAPI +CP210xRT_WriteLatch(_In_ _Pre_defensive_ const HANDLE cyHandle, + _In_ _Pre_defensive_ const WORD mask, + _In_ _Pre_defensive_ const WORD latch); + +/// @brief Reads and returns the Part Number from the device +/// +/// @param[in] cyHandle is an open handle to the device +/// @param[out] lpbPartNum points at a 1-byte buffer into which the @ref CP210X_PARTNUM Part Number value will be written +/// +/// @returns Returns #CP210x_SUCCESS on success, or another @ref RTCP210x_STATUS Return value if there is an error. +/// @retval #CP210x_SUCCESS -- success +/// @retval #CP210x_INVALID_HANDLE -- cyHandle is invalid +/// @retval #CP210x_INVALID_PARAMETER -- lpbPartNum is an unexpected value +/// @retval #CP210x_DEVICE_IO_FAILED -- the device failed to respond to I/O in any expected manner +_Check_return_ +_Ret_range_(CP210x_SUCCESS, CP210x_DEVICE_NOT_FOUND) +_Success_(return == CP210x_SUCCESS) +CP210xRUNTIMEDLL_API CP210x_STATUS WINAPI +CP210xRT_GetPartNumber(_In_ _Pre_defensive_ const HANDLE cyHandle, + _Out_writes_bytes_(1) _Pre_defensive_ LPBYTE lpbPartNum); + +/// @brief Reads and returns the Product String directly from the device +/// +/// @param[in] cyHandle is an open handle to the device +/// @param[out] lpProductString points at a buffer into which the Product String will be written +/// @param[out] lpbProductStringLengthInBytes is the total number of characters in the Product String +/// @param[in] bConvertToASCII is a true or false value indicating whether the Product String is an 16-bit UCS-2 character string needing converting to 8-bit ascii characters (true) to not (false). +/// +/// @note Length of lpProductString must be <= @ref CP210x_MAX_SETUP_STRING_SIZE +/// +/// @returns Returns #CP210x_SUCCESS on success, or another @ref RTCP210x_STATUS Return value if there is an error. +/// @retval #CP210x_SUCCESS -- success +/// @retval #CP210x_INVALID_HANDLE -- cyHandle is invalid +/// @retval #CP210x_INVALID_PARAMETER -- lpProductString or lpbProductStringLengthInBytes are unexpected values +/// @retval #CP210x_DEVICE_IO_FAILED -- the device failed to respond to I/O in any expected manner +_Check_return_ +_Ret_range_(CP210x_SUCCESS, CP210x_DEVICE_NOT_FOUND) +_Success_(return == CP210x_SUCCESS) +CP210xRUNTIMEDLL_API CP210x_STATUS WINAPI +CP210xRT_GetDeviceProductString(_In_ _Pre_defensive_ const HANDLE cyHandle, + _Out_writes_bytes_(*lpbProductStringLengthInBytes) _Pre_defensive_ LPVOID lpProductString, + _Out_writes_bytes_(1) _Pre_defensive_ LPBYTE lpbProductStringLengthInBytes, + _In_ _Pre_defensive_ const BOOL bConvertToASCII); + +/// @brief Reads and returns the Serial Number String directly from the device +/// +/// @param[in] cyHandle is an open handle to the device +/// @param[out] lpSerialNumberString points at a buffer into which the Serial Number String will be written +/// @param[out] lpbSerialNumberStringLengthInBytes is the total number of characters in the Serial Number String +/// @param[in] bConvertToASCII is a true or false value indicating whether the Serial Number String is an 16-bit UCS-2 character string needing converting to 8-bit ascii characters (true) to not (false). +/// +/// @note Length of lpSerialNumberString must be <= @ref CP210x_MAX_SETUP_STRING_SIZE +/// +/// @returns Returns #CP210x_SUCCESS on success, or another @ref RTCP210x_STATUS Return value if there is an error. +/// @retval #CP210x_SUCCESS -- success +/// @retval #CP210x_INVALID_HANDLE -- cyHandle is invalid +/// @retval #CP210x_INVALID_PARAMETER -- lpSerialNumberString or lpbSerialNumberStringLengthInBytes are unexpected values +/// @retval #CP210x_DEVICE_IO_FAILED -- the device failed to respond to I/O in any expected manner +_Check_return_ +_Ret_range_(CP210x_SUCCESS, CP210x_DEVICE_NOT_FOUND) +_Success_(return == CP210x_SUCCESS) +CP210xRUNTIMEDLL_API CP210x_STATUS WINAPI +CP210xRT_GetDeviceSerialNumber(_In_ _Pre_defensive_ const HANDLE cyHandle, + _Out_writes_bytes_(*lpbSerialNumberStringLengthInBytes) _Pre_defensive_ LPVOID lpSerialNumberString, + _Out_writes_bytes_(1) _Pre_defensive_ LPBYTE lpbSerialNumberStringLengthInBytes, + _In_ _Pre_defensive_ const BOOL bConvertToASCII); + +/// @brief Reads and returns the Interface String directly from the device +/// +/// @param[in] cyHandle is an open handle to the device +/// @param[out] lpInterfaceString points at a buffer into which the Interface String will be written +/// @param[out] lpbInterfaceStringLengthInBytes is the total number of characters in the Interface String +/// @param[in] bConvertToASCII is a true or false value indicating whether the Interface String is an 16-bit UCS-2 character string needing converting to 8-bit ascii characters (true) to not (false). +/// +/// @note Length of lpInterfaceString must be <= @ref CP210x_MAX_SETUP_STRING_SIZE +/// +/// @returns Returns #CP210x_SUCCESS on success, or another @ref RTCP210x_STATUS Return value if there is an error. +/// @retval #CP210x_SUCCESS -- success +/// @retval #CP210x_INVALID_HANDLE -- cyHandle is invalid +/// @retval #CP210x_INVALID_PARAMETER -- lpInterfaceString or lpbInterfaceStringLengthInBytes are unexpected values +/// @retval #CP210x_DEVICE_IO_FAILED -- the device failed to respond to I/O in any expected manner +_Check_return_ +_Ret_range_(CP210x_SUCCESS, CP210x_DEVICE_NOT_FOUND) +_Success_(return == CP210x_SUCCESS) +CP210xRUNTIMEDLL_API CP210x_STATUS WINAPI +CP210xRT_GetDeviceInterfaceString(_In_ _Pre_defensive_ const HANDLE cyHandle, + _Out_writes_bytes_(*lpbInterfaceStringLengthInBytes) _Pre_defensive_ LPVOID lpInterfaceString, + _Out_writes_bytes_(1) _Pre_defensive_ LPBYTE lpbInterfaceStringLengthInBytes, + _In_ _Pre_defensive_ const BOOL bConvertToASCII); + + +/// @brief Reads and returns the Receiver Max Timeout directly from the device +/// +/// @param[in] cyHandle is an open handle to the device +/// @param[out] pReceiverMaxTimeoutInMicroseconds points at a buffer into which the current Receiver Max Timeout will be written +/// +/// @note xxx +/// +/// @returns Returns #CP210x_SUCCESS on success, or another @ref RTCP210x_STATUS Return value if there is an error. +/// @retval #CP210x_SUCCESS -- success +/// @retval #CP210x_INVALID_HANDLE -- cyHandle is invalid +/// @retval #CP210x_INVALID_PARAMETER -- pReceiverMaxTimeoutInMicroseconds is an unexpected value +/// @retval #CP210x_DEVICE_IO_FAILED -- the device failed to respond to I/O in any expected manner +_Check_return_ +_Ret_range_(CP210x_SUCCESS, CP210x_DEVICE_NOT_FOUND) +_Success_(return == CP210x_SUCCESS) +CP210xRUNTIMEDLL_API CP210x_STATUS WINAPI +CP210xRT_GetReceiverMaxTimeout(_In_ _Pre_defensive_ const HANDLE cyHandle, + _Out_writes_bytes_(2) _Pre_defensive_ uint16_t *pReceiverMaxTimeoutInMicroseconds); + + +/// @brief Sets the Receiver Max Timeout directly to the device +/// +/// @param[in] cyHandle is an open handle to the device +/// @param[in] ReceiverMaxTimeoutInMicroseconds is the new Receiver Max Timeout for the device to use +/// +/// @note xxx +/// +/// @returns Returns #CP210x_SUCCESS on success, or another @ref RTCP210x_STATUS Return value if there is an error. +/// @retval #CP210x_SUCCESS -- success +/// @retval #CP210x_INVALID_HANDLE -- cyHandle is invalid +/// @retval #CP210x_INVALID_PARAMETER -- ReceiverMaxTimeoutInMicroseconds is an unexpected value +/// @retval #CP210x_DEVICE_IO_FAILED -- the device failed to respond to I/O in any expected manner +_Check_return_ +_Ret_range_(CP210x_SUCCESS, CP210x_DEVICE_NOT_FOUND) +_Success_(return == CP210x_SUCCESS) +CP210xRUNTIMEDLL_API CP210x_STATUS WINAPI +CP210xRT_SetReceiverMaxTimeout(_In_ _Pre_defensive_ const HANDLE cyHandle, + _In_ _Pre_defensive_ const uint16_t ReceiverMaxTimeoutInMicroseconds); + +#ifdef __cplusplus +} +#endif // __cplusplus + +/// @} + +#endif // !HOST_LIB_RUNTIME_INCLUDE_CP210XRUNTIMEDLL_H_INCLUDED_QU4N7WC20W + + diff --git a/libcp2102_usb/cp210xrt/silabs_defs.h b/libcp2102_usb/cp210xrt/silabs_defs.h new file mode 100644 index 0000000..ca8de68 --- /dev/null +++ b/libcp2102_usb/cp210xrt/silabs_defs.h @@ -0,0 +1,239 @@ + /*++ + + VER_LEGALCOPYRIGHT_STR + +Module Name: + + silabs_defs.h + +Abstract: + + A top-level, across-all-repos, collection of some "useful" defines/enums + +Environment: + + User or kernel mode + +--*/ +// +#if (_MSC_VER > 1000) +#pragma once +#endif + +#ifndef HOST_COMMON_INCLUDE_SILABS_DEFS_H_INCLUDED_BVHHTNCO7E +#define HOST_COMMON_INCLUDE_SILABS_DEFS_H_INCLUDED_BVHHTNCO7E + +/// @addtogroup silabs_defs +/// @{ + +#include "silabs_sal.h" + +#ifdef _WIN32 +#if ! defined(__cplusplus) +// #define bool BOOLEAN +#endif // ! defined(__cplusplus) +#else +typedef unsigned char BYTE; +#endif + + +#ifndef _WIN32 +#define UNREFERENCED_PARAMETER(p) (void)(p) +#endif + +#if defined(DEFINE_GUID) +DEFINE_GUID(GUID_DEVINTERFACE_SILABS_CP210x, + 0xa2a39220, 0x39f4, 0x4b88, 0xae, 0xcb, 0x3d, 0x86, 0xa3, 0x5d, 0xc7, 0x48); + +// CP213x Device GUID (must match WinUSB Driver INF file's interface GUID) +// {F81D8403-3C27-45FF-98B7-3D00F19169CE} +DEFINE_GUID(GUID_DEVINTERFACE_SILABS_CP213x, + 0xf81d8403, 0x3c27, 0x45ff, 0x98, 0xb7, 0x3d, 0x00, 0xf1, 0x91, 0x69, 0xce); + +// CP2615 Device GUID +// {26C6CE68-9013-4B40-B72A-298EB2BDD269} +DEFINE_GUID(GUID_DEVINTERFACE_SILABS_CP2615, + 0x26C6CE68, 0x9013, 0x4B40, 0xB7, 0x2A, 0x29, 0x8E, 0xB2, 0xBD, 0xD2, 0x69); + +// USBXpress +// {3C5E1462-5695-4e18-876B-F3F3D08AAF18} +DEFINE_GUID(GUID_DEVINTERFACE_SILABS_USBXPRESS_BRIDGE, +0x3c5e1462, 0x5695, 0x4e18, 0x87, 0x6b, 0xf3, 0xf3, 0xd0, 0x8a, 0xaf, 0x18); +#endif // DEFINE_GUID + +#define SILABS_TEST_FILL 0xa5 // 10100101 + + +/// Company Vendor ID (VID) +typedef enum _SILABS_VID { + SILABS_VID_10C4 = ((unsigned short)(0xFFFF & 0x10C4)) ///< Decimal 4292; VID aquired via Cygnal. + , SILABS_VID_1BA4 = ((unsigned short)(0xFFFF & 0x1BA4)) ///< Decimal 7076; VID aquired via Ember. + , SILABS_VID_2544 = ((unsigned short)(0xFFFF & 0x2544)) ///< Decimal 9540; VID aquired via Energy Micro. +} SILABS_VID, *PSILABS_VID; +_Check_return_ +_Success_(return == TRUE) +__inline static bool IsValidSILABS_VID ( _In_ const SILABS_VID _v ) { return (SILABS_VID_10C4 == _v); } + +/// Device Product IDs (PIDs) +typedef enum _SILABS_PID { + SILABS_PID_UNKNOWN = ((unsigned short)(0xFFFF & 0x0000)) + , SILABS_PID_CP210SINGLEPORT = ((unsigned short)(0xFFFF & 0xEA60)) ///< Single port CP210x device/s + , SILABS_PID_CP210SINGLEPORTII = ((unsigned short)(0xFFFF & 0xEA63)) ///< Single port CP210x device/s (Windows Update PID) + , SILABS_PID_CP2101 = SILABS_PID_CP210SINGLEPORT ///< CP2101 + , SILABS_PID_CP2102 = SILABS_PID_CP210SINGLEPORT ///< CP2102 + , SILABS_PID_CP2102N = SILABS_PID_CP210SINGLEPORT ///< CP2102N + , SILABS_PID_CP2103 = SILABS_PID_CP210SINGLEPORT ///< CP2103 + , SILABS_PID_CP2104 = SILABS_PID_CP210SINGLEPORT ///< CP2104 + , SILABS_PID_CP210DUALPORT = ((unsigned short)(0xFFFF & 0xEA70)) ///< Dual port CP210x device/s + , SILABS_PID_CP210DUALPORTII = ((unsigned short)(0xFFFF & 0xEA7A)) ///< Dual port CP210x device/s (Windows Update PID) + , SILABS_PID_CP2105 = SILABS_PID_CP210DUALPORT ///< CP2105 + , SILABS_PID_CP2105II = SILABS_PID_CP210DUALPORTII ///< CP2105 (Windows Update PID) + , SILABS_PID_CP210QUADPORT = ((unsigned short)(0xFFFF & 0xEA71)) ///< Quad port CP210x device/s + , SILABS_PID_CP210QUADPORTII = ((unsigned short)(0xFFFF & 0xEA7B)) ///< Quad port CP210x device/s (Windows Update PID) + , SILABS_PID_CP2108 = SILABS_PID_CP210QUADPORT ///< CP2108 + , SILABS_PID_CP2108II = SILABS_PID_CP210QUADPORTII ///< CP2108 (Windows Update PID) + , SILABS_PID_CP2109 = SILABS_PID_CP210SINGLEPORT ///< CP2109 + , SILABS_PID_CP2110 = ((unsigned short)(0xFFFF & 0xEA80)) ///< CP2110 + , SILABS_PID_CP2111 = SILABS_PID_CP2110 ///< CP2111 + , SILABS_PID_CP2112 = ((unsigned short)(0xFFFF & 0xEA90)) ///< CP2112 + , SILABS_PID_CP2114 = ((unsigned short)(0xFFFF & 0xEAB0)) ///< CP2114 + , SILABS_PID_CP2130 = ((unsigned short)(0xFFFF & 0x87A0)) ///< CP2130 + , SILABS_PID_CP2615 = ((unsigned short)(0xFFFF & 0xEAC1)) ///< CP2615 + , SILABS_PID_DIRECTACCESS = ((unsigned short)(0xFFFF & 0xEA61)) ///< Direct Access + , SILABS_PID_USBXPress = SILABS_PID_DIRECTACCESS ///< Direct Access (nee USBXPress) @deprecate SILABS_PID_USBXPress +} SILABS_PID, *PSILABS_PID; +_Check_return_ +_Success_(return == TRUE) +__inline static bool IsValidSILABS_PID(_In_ const SILABS_PID _p) { +#pragma warning ( push ) +#pragma warning ( disable : 6287 ) // warning C6287: redundant code: the left and right sub-expressions are identical + return ((SILABS_PID_CP210SINGLEPORT == _p) || (SILABS_PID_CP210SINGLEPORTII == _p) + || (SILABS_PID_CP210DUALPORT == _p) || (SILABS_PID_CP210DUALPORTII == _p) + || (SILABS_PID_CP210QUADPORT == _p) || (SILABS_PID_CP210QUADPORTII == _p) + || (SILABS_PID_CP2101 == _p) || (SILABS_PID_CP2102 == _p) || (SILABS_PID_CP2102N == _p) || (SILABS_PID_CP2103 == _p) + || (SILABS_PID_CP2104 == _p) + || (SILABS_PID_CP2105 == _p) || (SILABS_PID_CP2105II == _p) + || (SILABS_PID_CP2108 == _p) || (SILABS_PID_CP2108II == _p) + || (SILABS_PID_CP2109 == _p) + || (SILABS_PID_CP2110 == _p) || (SILABS_PID_CP2111 == _p) || (SILABS_PID_CP2112 == _p) || (SILABS_PID_CP2114 == _p) + || (SILABS_PID_CP2130 == _p) + || (SILABS_PID_CP2615 == _p) + || (SILABS_PID_DIRECTACCESS == _p)); +#pragma warning ( pop ) +} +_Check_return_ +_Success_(return == TRUE) +__inline static bool IsValidCP210X_PID(_In_ const SILABS_PID _p) { +#pragma warning ( push ) +#pragma warning ( disable : 6287 ) // warning C6287: redundant code: the left and right sub-expressions are identical + return ((SILABS_PID_CP210SINGLEPORT == _p) || (SILABS_PID_CP210SINGLEPORTII == _p) + || (SILABS_PID_CP210DUALPORT == _p) || (SILABS_PID_CP210DUALPORTII == _p) + || (SILABS_PID_CP210QUADPORT == _p) || (SILABS_PID_CP210QUADPORTII == _p) + || (SILABS_PID_CP2101 == _p) || (SILABS_PID_CP2102 == _p) || (SILABS_PID_CP2102N == _p) || (SILABS_PID_CP2103 == _p) + || (SILABS_PID_CP2104 == _p) + || (SILABS_PID_CP2105 == _p) || (SILABS_PID_CP2105II == _p) + || (SILABS_PID_CP2108 == _p) || (SILABS_PID_CP2108II == _p) + || (SILABS_PID_CP2109 == _p)); +#pragma warning ( pop ) +} + +/// Device Part Numbers +typedef enum _SILABS_PARTNUM_CPXXXX { + CP210x_PARTNUM_UNKNOWN = ((BYTE)(0xFF & 0x00)) ///< + , CP210x_PARTNUM_CP2101 = ((BYTE)(0xFF & 0x01)) ///< CP2101 + , CP210x_PARTNUM_CP2102 = ((BYTE)(0xFF & 0x02)) ///< CP2102 + , CP210x_PARTNUM_CP2103 = ((BYTE)(0xFF & 0x03)) ///< CP2103 + , CP210x_PARTNUM_CP2104 = ((BYTE)(0xFF & 0x04)) ///< CP2104 + , CP210x_PARTNUM_CP2105 = ((BYTE)(0xFF & 0x05)) ///< CP2105 + , CP210x_PARTNUM_CP2108 = ((BYTE)(0xFF & 0x08)) ///< CP2108 + , CP210x_PARTNUM_CP2109 = ((BYTE)(0xFF & 0x09)) ///< CP2109 + + , SILABS_PARTNUM_CP2110 = ((BYTE)(0xFF & 0x0A)) ///< CP2110 HID_UART_PART_CP2110 + , HID_UART_PART_CP2110 = SILABS_PARTNUM_CP2110 + + , CP210x_PARTNUM_CP2112 = ((BYTE)(0xFF & 0x0C)) ///< CP2112 HID_SMBUS_PART_CP2112 + , HID_SMBUS_PART_CP2112 = CP210x_PARTNUM_CP2112 + + , SILABS_PARTNUM_CP2114 = ((BYTE)(0xFF & 0x0E)) ///< CP2114 HID_UART_PART_CP2114 + , HID_UART_PART_CP2114 = SILABS_PARTNUM_CP2114 + + , CP210x_PARTNUM_CP2102N_QFN28 = ((BYTE)(0xFF & 0x20)) ///< CP2102N QFN28 + , CP210x_PARTNUM_CP2102N_QFN24 = ((BYTE)(0xFF & 0x21)) ///< CP2102N QFN24 + , CP210x_PARTNUM_CP2102N_QFN20 = ((BYTE)(0xFF & 0x22)) ///< CP2102N QFN20 + + , CP210x_PARTNUM_USBXPRESS_F3XX = ((BYTE)(0xFF & 0x80)) ///< USBXPRESS_F3XX + , CP210x_PARTNUM_USBXPRESS_EFM8 = ((BYTE)(0xFF & 0x80)) ///< USBXPRESS_EFM8 + , CP210x_PARTNUM_USBXPRESS_EFM32 = ((BYTE)(0xFF & 0x81)) ///< USBXPRESS_EFM32 +} SILABS_PARTNUM_CPXXXX, *PSILABS_PARTNUM_CPXXXX; +#define CP210X_PARTNUM SILABS_PARTNUM_CPXXXX // TODO: Enstone: For now, preserve the old, CP210X-centric name for this enum +_Check_return_ +_Success_(return == TRUE) +__inline static bool IsValidCP210X_PARTNUM(_In_ const SILABS_PARTNUM_CPXXXX _v) { + return (((CP210x_PARTNUM_CP2101 <= _v) && (_v <= CP210x_PARTNUM_CP2105)) || (CP210x_PARTNUM_CP2108 == _v) || (CP210x_PARTNUM_CP2109 == _v) || (CP210x_PARTNUM_CP2112 == _v) || ((CP210x_PARTNUM_CP2102N_QFN28 <= _v) && (_v <= CP210x_PARTNUM_CP2102N_QFN20)) || (CP210x_PARTNUM_USBXPRESS_F3XX == _v)); +} +_Check_return_ +_Success_(return == TRUE) +__inline static bool IsCP2102N_PARTNUM(_In_ const SILABS_PARTNUM_CPXXXX _v) { + return ((CP210x_PARTNUM_CP2102N_QFN28 == _v) || (CP210x_PARTNUM_CP2102N_QFN24 == _v) || (CP210x_PARTNUM_CP2102N_QFN20 == _v)); +} +_Check_return_ +_Success_(return == TRUE) +__inline static bool IsOTPCP210X_PARTNUM(_In_ const SILABS_PARTNUM_CPXXXX _v) { + return ((CP210x_PARTNUM_CP2104 == _v) || (CP210x_PARTNUM_CP2105 == _v) || (CP210x_PARTNUM_CP2109 == _v)); +} +_Check_return_ +_Success_(return == TRUE) +__inline static bool IsOTP(_In_ const SILABS_PID _p, _In_ const SILABS_PARTNUM_CPXXXX _v) { + return IsValidCP210X_PID(_p) ? IsOTPCP210X_PARTNUM(_v) : ((SILABS_PID_CP2110 == _v) || (SILABS_PID_CP2112 == _v) || (SILABS_PID_CP2114 == _v) || (SILABS_PID_CP2130 == _v)); +} +_Check_return_ +_Success_(return == TRUE) +__inline static bool IsWriteReadLatchPartNum(_In_ const SILABS_PARTNUM_CPXXXX _v) { + return (IsCP2102N_PARTNUM(_v) || (CP210x_PARTNUM_CP2103 == _v) || (CP210x_PARTNUM_CP2104 == _v) || (CP210x_PARTNUM_CP2105 == _v) || (CP210x_PARTNUM_CP2108 == _v)); +} +_Check_return_ +_Success_(return == TRUE) +__inline static bool IsMultiInterfacePartNum(_In_ const SILABS_PARTNUM_CPXXXX _v) { + return ((CP210x_PARTNUM_CP2105 == _v) || (CP210x_PARTNUM_CP2108 == _v)); +} + +/// API Status return codes +/// @enum SILABS_STATUS +typedef enum _SILABS_STATUS { + SILABS_STATUS_SUCCESS = ((BYTE)(0xFF & 0x00)) ///< no error + + , SILABS_STATUS_TBD = ((BYTE)(0xFF & 0x01)) ///< tbd + , SILABS_STATUS_INVALID_PARAMETER = ((BYTE)(0xFF & 0x02)) ///< a parameter was not valid + , SILABS_STATUS_INVALID_HANDLE = ((BYTE)(0xFF & 0x03)) ///< an handle parameter was not valid + + , SILABS_STATUS_DEVICE_NOT_FOUND = ((BYTE)(0xFF & 0x04)) ///< the specified device was not found + , SILABS_STATUS_DEVICE_TBD = ((BYTE)(0xFF & 0x05)) ///< the specified device is tbd + , SILABS_STATUS_DEVICE_ALREADY_OPENED = ((BYTE)(0xFF & 0x06)) ///< the specified device is already (exclusively) opened + + , SILABS_STATUS_DEVICE_ERROR = ((BYTE)(0xFF & 0x07)) ///< general/underetmined device-side error + , SILABS_STATUS_DEVICE_ERROR_STATE = ((BYTE)(0xFF & 0x08)) ///< device-side in wrong state to perform operation + , SILABS_STATUS_DEVICE_ERROR_TIMEOUT = ((BYTE)(0xFF & 0x09)) ///< device-side timed out the operation + + , SILABS_STATUS_FUNCTION_NOT_SUPPORTED = ((BYTE)(0xFF & 0x0F)) ///< the specified function is not supported + + , SILABS_STATUS_MEMORY_ALLOC_ERROR = ((BYTE)(0xFF & 0x44)) ///< an attempt to dynamically allocate memory failed + , SILABS_STATUS_SYSTEM_ERROR = ((BYTE)(0xFF & 0x74)) ///< an unexpected, unrecoverable error happened while interacting with the operating system + , SILABS_STATUS_UNKNOWN_ERROR = ((BYTE)(0xFF & 0xFF)) ///< an otherwise unclassified error occurred +} SILABS_STATUS, *PSILABS_STATUS; +_Check_return_ +_Success_(return == TRUE) +__inline static bool IsValidSILABS_STATUS(_In_ const SILABS_STATUS _s) { + return (((SILABS_STATUS_SUCCESS <= _s) && (_s <= SILABS_STATUS_DEVICE_ERROR_TIMEOUT)) + || (SILABS_STATUS_FUNCTION_NOT_SUPPORTED == _s) + || (SILABS_STATUS_MEMORY_ALLOC_ERROR == _s) + || (SILABS_STATUS_SYSTEM_ERROR == _s) + || (SILABS_STATUS_UNKNOWN_ERROR == _s)); +} +_Check_return_ +_Success_(return == TRUE) +__inline static bool IsSuccessSILABS_STATUS(_In_ const SILABS_STATUS _s) { return SILABS_STATUS_SUCCESS == _s; } + +/// @} + +#endif // !defined(HOST_COMMON_INCLUDE_SILABS_DEFS_H_INCLUDED_BVHHTNCO7E) + diff --git a/libcp2102_usb/cp210xrt/silabs_sal.h b/libcp2102_usb/cp210xrt/silabs_sal.h new file mode 100644 index 0000000..b643be5 --- /dev/null +++ b/libcp2102_usb/cp210xrt/silabs_sal.h @@ -0,0 +1,87 @@ + /*++ + + VER_LEGALCOPYRIGHT_STR + +Module Name: + + silabs_sal.h + +Abstract: + + A top-level, across all repos, authoritative, Master include file for + older IDEs that do not support the SAL-annotations that our API Header files use. + +Environment: + + User mode + +--*/ +// +#if (_MSC_VER > 1000) +#pragma once +#endif + +#ifndef HOST_COMMON_INCLUDE_SILABS_SAL_H_INCLUDED_VASIQW4TVT +#define HOST_COMMON_INCLUDE_SILABS_SAL_H_INCLUDED_VASIQW4TVT + +#if ! defined(_Check_return_) +#define _Check_return_ +#endif // ! defined(_Check_return_) +#if ! defined(_Ret_range_) +#define _Ret_range_(lb,ub) +#endif // ! defined(_Ret_range_) +#if ! defined(_Success_) +#define _Success_(expr) +#endif // ! defined(_Success_) +#if ! defined(_In_) +#define _In_ +#endif // ! defined(_In_) +#if ! defined(_In_opt_) +#define _In_opt_ +#endif // ! defined(_In_opt_) +#if ! defined(_Out_) +#define _Out_ +#endif // ! defined(_Out_) +#if ! defined(_In_range_) +#define _In_range_(lb,ub) +#endif // ! defined(_In_range_) +#if ! defined(_Out_range_) +#define _Out_range_(lb,ub) +#endif // ! defined(_Out_range_) +#if ! defined(_In_reads_bytes_) +#define _In_reads_bytes_(n) +#endif // ! defined(_In_reads_bytes_) +#if ! defined(_Out_writes_bytes_) +#define _Out_writes_bytes_(n) +#endif // ! defined(_Out_writes_bytes_) +#if ! defined(_Out_writes_bytes_opt_) +#define _Out_writes_bytes_opt_(n) +#endif // ! defined(_Out_writes_bytes_opt_) +#if ! defined(_Inout_updates_bytes_opt_) +#define _Inout_updates_bytes_opt_(n) +#endif // ! defined(_Inout_updates_bytes_opt_) +#if ! defined(_Printf_format_string_) +#define _Printf_format_string_ +#endif // ! defined(_Printf_format_string_) +#if ! defined(_Use_decl_annotations_) +#define _Use_decl_annotations_ +#endif // ! defined(_Use_decl_annotations_) +#if ! defined(_Acquires_lock_) +#define _Acquires_lock_(arg) +#endif // ! defined(_Acquires_lock_) +#if ! defined(_Releases_lock_) +#define _Releases_lock_(arg) +#endif // !defined(_Releases_lock_) +#if ! defined(_Pre_defensive_) +#define _Pre_defensive_ +#endif +#if ! defined(_Struct_size_bytes_) +#define _Struct_size_bytes_(n) +#endif +#if ! defined(_Null_terminated_) +#define _Null_terminated_ +#endif + + +#endif // !defined(HOST_COMMON_INCLUDE_SILABS_SAL_H_INCLUDED_VASIQW4TVT) + diff --git a/libcp2102_usb/src/cp2102_win32.c b/libcp2102_usb/src/cp2102_win32.c new file mode 100644 index 0000000..7d0e781 --- /dev/null +++ b/libcp2102_usb/src/cp2102_win32.c @@ -0,0 +1,105 @@ +#include "cp2102_win32.h" + +#include "CP210xRuntimeDLL.h" +#include "cp2102.h" + +#define LOG_TAG "cp2102_win32" +#include "log.h" + +#define SERIAL_NUMBER_LEN 256 + +bool +cp2102_init(void) +{ + return true; +} + +void +cp2102_exit(void) +{ +} + +cp2102_dev_t * +cp2102_open(const char *dev_name) +{ + LOGD("device: %s", dev_name); + + HANDLE handle = CreateFile(dev_name, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0); + + if (handle == INVALID_HANDLE_VALUE) { + return NULL; + } + + LOGD("port opened"); + + BYTE partNumber = 0; + if (CP210xRT_GetPartNumber(handle, &partNumber) != CP210x_SUCCESS) { + CloseHandle(handle); + return NULL; + } + LOGD("part number: 0x%02x", partNumber); + + CHAR serial[SERIAL_NUMBER_LEN] = {0}; + BYTE serialLength = (BYTE)SERIAL_NUMBER_LEN; + if (CP210xRT_GetDeviceSerialNumber(handle, serial, &serialLength, true) != CP210x_SUCCESS) { + CloseHandle(handle); + return NULL; + } + LOGD("serial number: %s", serial); + + cp2102_dev_t *dev = malloc(sizeof(cp2102_dev_t)); + dev->handle = handle; + + dev->serial_number = malloc(strlen(serial) + 1); + strcpy(dev->serial_number, serial); + + return dev; +} + +void +cp2102_close(cp2102_dev_t **dev) +{ + if (dev == NULL || *dev == NULL) { + return; + } + if ((*dev)->handle != NULL) { + CloseHandle((*dev)->handle); + } + if ((*dev)->serial_number != NULL) { + free((*dev)->serial_number); + } + free(*dev); + *dev = NULL; +} + +const char * +cp2102_get_serial_number(cp2102_dev_t *dev) +{ + return (const char *)dev->serial_number; +} + +bool +cp2102_set_value(cp2102_dev_t *dev, uint8_t state, uint8_t mask) +{ + CP210x_STATUS ret = CP210xRT_WriteLatch(dev->handle, mask, state); + LOGD("CP210xRT_WriteLatch: state: 0x%02x, mask: 0x%02x, ret: %d", state, mask, ret); + + return ret == CP210x_SUCCESS; +} + +bool +cp2102_get_value(cp2102_dev_t *dev, uint8_t *state) +{ + WORD latch = 0; + + CP210x_STATUS ret = CP210xRT_ReadLatch(dev->handle, &latch); + LOGD("CP210xRT_ReadLatch: ret: %d, latch: 0x%02x", ret, latch); + + if (ret == CP210x_SUCCESS) { + *state = latch; + return true; + } else { + return false; + } +} diff --git a/libcp2102_usb/src/cp2102_win32.h b/libcp2102_usb/src/cp2102_win32.h new file mode 100644 index 0000000..be336d1 --- /dev/null +++ b/libcp2102_usb/src/cp2102_win32.h @@ -0,0 +1,13 @@ +#ifndef __LIB_CP2102_WIN32_H__ +#define __LIB_CP2102_WIN32_H__ + +#include + +#include "cp2102.h" + +struct _cp2102_dev_t { + HANDLE handle; + char *serial_number; +}; + +#endif // __LIB_CP2102_WIN32_H__