1 /*******************************************************************************
2 *
3 * FindAppUART.cpp - PC command line utility for enumerating MSP430 EVM's
4 * Application UARTs.
5 *
6 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the
18 * distribution.
19 *
20 * Neither the name of Texas Instruments Incorporated nor the names of
21 * its contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 ******************************************************************************/
37
38 //------------------------------------------------------------------------------
39 // Desc: PC command line utility for enumerating MSP430 EVM's Application UARTs.
40 // The application returns the COM port number of the first UART that is
41 // found. If this is successful the error code is set to '0'. In case of
42 // the UART string could not be determined '1' is returned.
43 //
44 // The code was developed with the Express Edition of Visual C++ 2008
45 // http://www.microsoft.com/express/
46 //
47 // Ver.: 0.1 (February 2011)
48 // - Alpha version
49 //
50 // Auth: Andreas Dannenberg
51 // MSP430 Applications
52 // Texas Instruments, Inc.
53 //------------------------------------------------------------------------------
54
55 // Windows Header Files
56 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff
57 // from Windows headers
58 #include <windows.h>
59 #include <tchar.h>
60 #include <shellapi.h>
61 #include <setupapi.h> // "setupapi.lib" must be linked
62 // to the project
63 // C Runtime Header Files
64 #include <stdlib.h>
65 #include <malloc.h>
66 #include <memory.h>
67
68 //------------------------------------------------------------------------------
69 // DWORD WINAPI EnumComPorts(DWORD dwIndex, LPTSTR lptszName,
70 // DWORD dwNumOfElements)
71 //
72 // User-mode code fragment to identify attached VCP COMnn port[s] with a
73 // specific device instance ID based on USB VID and PID and returns the COMnn
74 // port that the OS embeds into the device instance ID. When called with
75 // dwIndex = 0, the function will enumerate all COMPORT class devices and
76 // return the name of the first one that was found. Subsequent calls using an
77 // incremented dwIndex parameter can be performed until ERROR_NO_MORE_ITEMS
78 // is returned.
79 //
80 // IN: dwIndex COMPORT class device # 0, 1, 2, ... to check
81 // dwNumOfElements The size of the lptszName buffer
82 // OUT: lptszName COMnn name of given device #
83 // return() ERROR_SUCCESS - lpszName is valid
84 // ERROR_NO_MORE_ITEMS - End of device list reached
85 //------------------------------------------------------------------------------
86 DWORD WINAPI EnumComPorts(DWORD dwIndex, LPTSTR lptszName, DWORD dwNumOfElements)
87 {
88 HDEVINFO hDevInfo;
89 SP_DEVINFO_DATA DeviceInfoData;
90 DWORD i;
91 TCHAR *pcParse;
92
93 // Create a HDEVINFO with all present devices
94 hDevInfo = SetupDiGetClassDevs(
95 NULL,
96 0, // Enumerator
97 0,
98 DIGCF_PRESENT | DIGCF_ALLCLASSES);
99
100 if (INVALID_HANDLE_VALUE == hDevInfo)
101 {
102 return GetLastError();
103 }
104
105 // Enumerate through all devices in set
106 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
107
108 for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++)
109 {
110 LPTSTR buffer = NULL;
111 DWORD buffersize = 0;
112
113 // Get the device instance ID that is associated with the device information element
114 while (!SetupDiGetDeviceInstanceId(
115 hDevInfo,
116 &DeviceInfoData,
117 buffer,
118 buffersize,
119 &buffersize))
120 {
121 if (buffer)
122 {
123 LocalFree(buffer);
124 }
125
126 if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
127 {
128 // Change the buffer size. Double the size to avoid problems on
129 // W2K MBCS systems per KB 888609.
130 buffer = (LPTSTR)LocalAlloc(LPTR, buffersize * 2);
131 }
132 else
133 {
134 // Error: could not get device instance ID
135 // Cleanup and return error code
136 SetupDiDestroyDeviceInfoList(hDevInfo);
137 return GetLastError();
138 }
139 }
140
141 if (buffer)
142 {
143 // Look for the "Application UART" of common MSP430 EVMs. The application UART
144 // has an USB VID of 0x0451 (Texas Instruments) and an PID of 0xF432.
145 const TCHAR testval[] = _T("USB\\VID_0451&PID_F432&MI_00");
146
147 if (NULL != _tcsstr(buffer, testval))
148 {
149 TCHAR szFriendlyName[MAX_PATH];
150
151 if (SetupDiGetDeviceRegistryProperty(
152 hDevInfo,
153 &DeviceInfoData,
154 SPDRP_FRIENDLYNAME,
155 NULL,
156 (PBYTE)szFriendlyName,
157 sizeof(szFriendlyName) - 1,
158 NULL))
159 {
160 // Check if we have reached the dwIndex-th element, if not keep looking
161 if (dwIndex == 0)
162 {
163 // Find pointer to "COM" substring (secure)
164 szFriendlyName[sizeof(szFriendlyName) - 1] = 0x00;
165 pcParse = _tcsstr(szFriendlyName, _T("COM"));
166
167 if (pcParse != NULL)
168 {
169 // Zero-terminate COM port string after last digit
170 if (!isdigit(pcParse[4])) {
171 pcParse[4] = 0;
172 }
173 else if (!isdigit(pcParse[5])) {
174 pcParse[5] = 0;
175 }
176 else {
177 pcParse[6] = 0;
178 }
179
180 // Pass string to the return parameter
181 _tcscpy_s(lptszName, dwNumOfElements, pcParse);
182
183 // Cleanup
184 SetupDiDestroyDeviceInfoList(hDevInfo);
185
186 return ERROR_SUCCESS;
187 }
188 }
189 else
190 {
191 dwIndex--;
192 }
193 }
194 }
195 }
196 }
197
198 // Cleanup
199 SetupDiDestroyDeviceInfoList(hDevInfo);
200
201 return ERROR_NO_MORE_ITEMS;
202 }
203
204 //------------------------------------------------------------------------------
205 // Main application entry point. Simply return the first Application UART
206 // COM port that was found to STDOUT.
207 //------------------------------------------------------------------------------
208 int _tmain(int argc, _TCHAR* argv[])
209 {
210 TCHAR szDeviceName[MAX_PATH];
211 DWORD dwReturnValue;
212
213 dwReturnValue = EnumComPorts(0, szDeviceName, _countof(szDeviceName));
214
215 if (dwReturnValue == ERROR_SUCCESS) {
216 _ftprintf_s(stdout, _T("%s\r\n"), szDeviceName);
217 return 0;
218 }
219
220 return 1;
221 }