1 /**
2     @file ConnectionEVB7COM.cpp
3     @author Lime Microsystems
4     @brief Implementation of EVB7 connection of serial COM port.
5 */
6 
7 #include "ConnectionEVB7COM.h"
8 #include <fstream>
9 #include <iostream>
10 
11 using namespace std;
12 using namespace lime;
13 
14 static const int comBaudrate = 9600;
15 
16 //! make a static-initialized entry in the registry
__loadConnectionEVB7COMEntry(void)17 void __loadConnectionEVB7COMEntry(void) //TODO fixme replace with LoadLibrary/dlopen
18 {
19 static ConnectionEVB7COMEntry EVB7COMEntry;
20 }
21 
ConnectionEVB7COMEntry(void)22 ConnectionEVB7COMEntry::ConnectionEVB7COMEntry(void):
23     ConnectionRegistryEntry("EVB7COM")
24 {
25     return;
26 }
27 
enumerate(const ConnectionHandle & hint)28 std::vector<ConnectionHandle> ConnectionEVB7COMEntry::enumerate(const ConnectionHandle &hint)
29 {
30     std::vector<ConnectionHandle> result;
31     auto comPortList = this->FindAllComPorts();
32     auto availableComms = this->FilterDeviceList(comPortList);
33     for (const auto &comName : availableComms)
34     {
35         ConnectionHandle handle;
36         handle.media = "COM";
37         handle.name = "EVB7 ("+comName+")";
38         handle.addr = comName;
39         if(hint.addr.length() == 0 || hint.addr == handle.addr)
40             result.push_back(handle);
41     }
42     return result;
43 }
44 
make(const ConnectionHandle & handle)45 IConnection *ConnectionEVB7COMEntry::make(const ConnectionHandle &handle)
46 {
47     return new ConnectionEVB7COM(handle.addr.c_str(), comBaudrate);
48 }
49 
FindAllComPorts()50 std::vector<std::string> ConnectionEVB7COMEntry::FindAllComPorts()
51 {
52     std::vector<std::string> comPortList;
53     #ifndef __unix__
54 	HKEY hSERIALCOMM;
55 	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"),	0, KEY_QUERY_VALUE, &hSERIALCOMM) == ERROR_SUCCESS)
56 	{
57 		// Get the max value name and max value lengths
58 		DWORD dwMaxValueNameLen;
59 		DWORD dwMaxValueLen;
60 		DWORD dwQueryInfo = RegQueryInfoKey(hSERIALCOMM, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwMaxValueNameLen, &dwMaxValueLen, NULL, NULL);
61 		if (dwQueryInfo == ERROR_SUCCESS)
62 		{
63 			DWORD dwMaxValueNameSizeInChars = dwMaxValueNameLen + 1;
64 			// Include space for the NULL terminator
65 			DWORD dwMaxValueNameSizeInBytes = dwMaxValueNameSizeInChars*sizeof(TCHAR);
66 			DWORD dwMaxValueDataSizeInChars = dwMaxValueLen / sizeof(TCHAR) + 1;
67 			// Include space for the NULL terminator
68 			DWORD dwMaxValueDataSizeInBytes = dwMaxValueDataSizeInChars*sizeof(TCHAR);
69 
70 			// Allocate some space for the value name and value data
71 			TCHAR* szValueName = new TCHAR[dwMaxValueNameSizeInChars];
72 			TCHAR* byValue = new TCHAR[dwMaxValueDataSizeInBytes];
73 			if (szValueName && byValue)
74 			{
75 				// Enumerate all the values underneath HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM
76 				DWORD dwIndex = 0;
77 				DWORD dwType;
78 				DWORD dwValueNameSize = dwMaxValueNameSizeInChars;
79 				DWORD dwDataSize = dwMaxValueDataSizeInBytes;
80 				memset(szValueName, 0, dwMaxValueNameSizeInBytes);
81 				memset(byValue, 0, dwMaxValueDataSizeInBytes);
82 				LONG nEnum = RegEnumValue(hSERIALCOMM, dwIndex, szValueName, &dwValueNameSize, NULL, &dwType, (LPBYTE)byValue, &dwDataSize);
83 				while (nEnum == ERROR_SUCCESS)
84 				{
85 					// If the value is of the correct type, then add it to the array
86 					if (dwType == REG_SZ)
87 					{
88 					    char portname[512];
89 						TCHAR* szPort = byValue;
90 						int nUserNameLenUnicode = lstrlen( szPort ); // Convert all UNICODE characters
91 						int nUserNameLen = WideCharToMultiByte( CP_ACP, // ANSI Code Page
92                         0, // No special handling of unmapped chars
93                         (LPCWSTR)szPort, // wide-character string to be converted
94                         nUserNameLenUnicode,
95                         NULL, 0, // No output buffer since we are calculating length
96                         NULL, NULL ); // Unrepresented char replacement - Use Default
97                         TCHAR* pszUserName = new TCHAR[ nUserNameLen ]; // nUserNameLen includes the NULL character
98                         WideCharToMultiByte( CP_ACP, // ANSI Code Page
99                         0, // No special handling of unmapped chars
100 						(LPCWSTR)szPort, // wide-character string to be converted
101                         nUserNameLenUnicode,
102                         portname,
103                         nUserNameLen,
104                         NULL, NULL ); // Unrepresented char replacement - Use Default
105 						portname[nUserNameLen] = 0;
106 #ifdef UNICODE
107                         comPortList.push_back(portname);
108 #else
109                         comPortList.push_back(szPort);
110 #endif
111 					}
112 					// Prepare for the next time around
113 					dwValueNameSize = dwMaxValueNameSizeInChars;
114 					dwDataSize = dwMaxValueDataSizeInBytes;
115 					memset(szValueName, 0, dwMaxValueNameSizeInBytes);
116 					memset(byValue, 0, dwMaxValueDataSizeInBytes);
117 					++dwIndex;
118 					nEnum = RegEnumValue(hSERIALCOMM, dwIndex, szValueName,	&dwValueNameSize, NULL, &dwType, (LPBYTE)byValue, &dwDataSize);
119 				}
120 			}
121 			delete szValueName;
122 			delete byValue;
123 		}
124 		// Close the registry key now that we are finished with it
125 		RegCloseKey(hSERIALCOMM);
126 
127 		if (dwQueryInfo != ERROR_SUCCESS)
128 			SetLastError(dwQueryInfo);
129 	}
130 #else
131     char tempBuffer[256];
132     string result = "";
133     if (system( "ls /dev | grep ttyACM > /tmp/foundSerialPorts.txt") == -1)
134         return comPortList;
135 
136     fstream fin;
137     fin.open("/tmp/foundSerialPorts.txt", ios::in);
138     while(!fin.eof())
139     {
140         fin.getline(tempBuffer, 256);
141         result = "/dev/";
142         result.append(tempBuffer);
143         if( strlen(tempBuffer) > 3 ) //longer than tty
144             comPortList.push_back(result);
145     }
146     fin.close();
147 #endif
148 
149     return comPortList;
150 }
151 
FilterDeviceList(const std::vector<std::string> & comPortList)152 std::vector<std::string> ConnectionEVB7COMEntry::FilterDeviceList(const std::vector<std::string> &comPortList)
153 {
154     std::vector<std::string> deviceNames;
155 
156     string comName;
157     for(unsigned int i=0; i<comPortList.size(); i++)
158     {
159         comName = comPortList[i];
160 
161         //when not on unix, perform a test open to validate the port
162 #ifndef __unix__
163         ConnectionEVB7COM testConn(comName.c_str(), comBaudrate);
164         if (testConn.IsOpen()) deviceNames.push_back(comName);
165 #else
166         deviceNames.push_back(comName);
167 #endif
168     }
169     return deviceNames;
170 }
171