OSVR-Core
CheckFirmwareVersion.h
Go to the documentation of this file.
1 
11 // Copyright 2016 Sensics, Inc.
12 //
13 // Licensed under the Apache License, Version 2.0 (the "License");
14 // you may not use this file except in compliance with the License.
15 // You may obtain a copy of the License at
16 //
17 // http://www.apache.org/licenses/LICENSE-2.0
18 //
19 // Unless required by applicable law or agreed to in writing, software
20 // distributed under the License is distributed on an "AS IS" BASIS,
21 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 // See the License for the specific language governing permissions and
23 // limitations under the License.
24 
25 #ifndef INCLUDED_CheckFirmwareVersion_h_GUID_C1356250_0CF2_4595_83A5_1522F8AC6795
26 #define INCLUDED_CheckFirmwareVersion_h_GUID_C1356250_0CF2_4595_83A5_1522F8AC6795
27 
28 // Internal Includes
29 // - none
30 
31 // Library/third-party includes
32 #include <boost/assert.hpp>
33 #ifdef _WIN32
34 #include <boost/algorithm/string/erase.hpp>
35 #include <boost/algorithm/string/predicate.hpp>
36 #include <boost/algorithm/string/replace.hpp>
37 #include <boost/lexical_cast.hpp>
38 #define _WIN32_DCOM
39 #include <Wbemidl.h>
40 #include <comdef.h>
41 #include <comutils/ComPtr.h>
42 #include <comutils/ComVariant.h>
43 #include <tchar.h>
44 
45 #ifdef OSVR_HAVE_CODECVT
46 #include <codecvt>
47 #include <locale>
48 #else // !OSVR_HAVE_CODECVT
49 #include <boost/locale/encoding_utf.hpp>
50 #endif // OSVR_HAVE_CODECVT
51 #endif // _WIN32
52 
53 // Standard includes
54 #include <iostream>
55 
56 namespace osvr {
57 namespace vbtracker {
58  static const auto CAMERA_FIRMWARE_UPGRADE_REQUIRED = 6;
59  static const auto CURRENT_CAMERA_FIRMWARE_VERSION = 7;
60 
61  template <typename T> inline std::string wideToUTF8String(T input) {
62 #ifdef OSVR_HAVE_CODECVT
63  std::wstring_convert<std::codecvt_utf8<wchar_t> > strCvt;
64  return strCvt.to_bytes(input);
65 #else // !OSVR_HAVE_CODECVT
66  return boost::locale::conv::utf_to_utf<char>(input);
67 #endif // OSVR_HAVE_CODECVT
68  }
69 
70  template <typename T> inline std::wstring narrowToWideString(T input) {
71 #ifdef OSVR_HAVE_CODECVT
72  std::wstring_convert<std::codecvt_utf8<wchar_t> > strCvt;
73  return strCvt.from_bytes(input);
74 #else // !OSVR_HAVE_CODECVT
75  return boost::locale::conv::utf_to_utf<wchar_t>(input);
76 #endif // OSVR_HAVE_CODECVT
77  }
78 
79  enum class FirmwareStatus {
80  Good,
81  Future,
82  UpgradeUseful,
83  UpgradeRequired,
84  Unknown
85  };
86 
87 #ifdef _WIN32
88  inline FirmwareStatus checkCameraFirmwareRevision(std::string path) {
89 
90  FirmwareStatus ret = FirmwareStatus::Unknown;
91  // Remove the end of the path: #{GUID}\global
92  {
93  auto endOfPath = path.find("#{");
94  if (endOfPath != std::string::npos) {
95  path.erase(endOfPath);
96  }
97  }
98  // Remove the system prefix thing
99  {
100  static const auto prefixString = "\\\\?\\";
101  static const auto prefixLength = 4;
102  BOOST_ASSERT(std::strlen(prefixString) == prefixLength);
103 
104  if (boost::algorithm::starts_with(path, prefixString)) {
105  boost::algorithm::erase_head(path, prefixLength);
106  }
107  }
108  // Convert # to \\
109 
110  boost::algorithm::ireplace_all(path, "#", "\\\\");
111  std::wstring wpath = narrowToWideString(path);
112 
114 
115  // Set COM security should be done here. It's automatically
116  // called by COM when interface is marshaled/unmarshaled with default
117  // settings
118 
119  // Obtain the initial locator to WMI
121  auto result =
122  CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER,
123  IID_IWbemLocator, AttachPtr(locator));
124  if (FAILED(result)) {
125  return ret;
126  }
127 
128  // Connect to WMI through the IWbemLocator::ConnectServer method
129 
130  comutils::Ptr<IWbemServices> wbemServices;
131 
132  // Connect to the root\cimv2 namespace with
133  // the current user and obtain pointer pSvc
134  // to make IWbemServices calls.
135  result = locator->ConnectServer(
136  bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
137  nullptr, // User name. nullptr = current user
138  nullptr, // User password. nullptr = current
139  nullptr, // Locale. nullptr indicates current
140  WBEM_FLAG_CONNECT_USE_MAX_WAIT, // Security flags - here, requesting
141  // a timeout.
142  0, // Authority (for example, Kerberos)
143  nullptr, // Context object
144  AttachPtr(wbemServices) // pointer to IWbemServices proxy
145  );
146 
147  if (FAILED(result)) {
148  return ret;
149  }
150 
151  // Set security levels on the proxy
152 
153  result =
154  CoSetProxyBlanket(wbemServices.get(), RPC_C_AUTHN_WINNT,
155  RPC_C_AUTHZ_NONE, nullptr, RPC_C_AUTHN_LEVEL_CALL,
156  RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE);
157 
158  if (FAILED(result)) {
159  return ret;
160  }
161 
162  // Use the IWbemServices pointer to make requests of WMI
163 
164  std::wstring query =
165  L"SELECT * FROM Win32_PnPEntity WHERE DeviceID=\"" + wpath + L"\"";
166  // Get a list of serial devices
168  result = wbemServices->ExecQuery(bstr_t(L"WQL"), bstr_t(query.c_str()),
169  WBEM_FLAG_FORWARD_ONLY |
170  WBEM_FLAG_RETURN_IMMEDIATELY,
171  nullptr, AttachPtr(devEnum));
172  if (FAILED(result)) {
173  std::cout << "Query failed!" << std::endl;
174  return ret;
175  }
176  comutils::Ptr<IWbemClassObject> wbemClassObj;
177  ULONG numObjRet = 0;
178  while (devEnum) {
179  HRESULT hr = devEnum->Next(WBEM_INFINITE, 1,
180  AttachPtr(wbemClassObj), &numObjRet);
181 
182  if (FAILED(hr) || numObjRet == 0) {
183  break;
184  }
185 
186  using comutils::Variant;
187  using comutils::get;
188  using comutils::containsArray;
189  using comutils::getArray;
190 
191  // This is an array of hardware IDs - one of them should have
192  // REV_xxxx
193  Variant varHardwareID;
194  hr = wbemClassObj->Get(L"HardwareID", 0,
195  AttachVariant(varHardwareID), nullptr,
196  nullptr);
197  if (!containsArray<std::wstring>(varHardwareID)) {
198 #if 0
199  std::cout << "HardwareID doesn't contain a string array! VT is "
200  << varHardwareID.get().vt << std::endl;
201 #endif
202  break;
203  }
204 
205  for (auto &&hwid : getArray<std::wstring>(varHardwareID)) {
206  auto narrow = wideToUTF8String(hwid);
207  // std::cout << "hwid: " << narrow << std::endl;
208  auto loc = narrow.find("REV_");
209  if (loc != std::string::npos) {
210  auto revString = narrow.substr(loc);
211  // remove REV_
212  boost::algorithm::erase_head(revString, 4);
213  // Keep the four digit revision.
214  revString.resize(4);
215  std::istringstream iss(revString);
216  unsigned rev = 0;
217  if ((iss >> rev)) {
218  // OK, we could parse it as a number
219  if (rev < CAMERA_FIRMWARE_UPGRADE_REQUIRED) {
220  ret = FirmwareStatus::UpgradeRequired;
221 
222  } else if (rev < CURRENT_CAMERA_FIRMWARE_VERSION) {
223  ret = FirmwareStatus::UpgradeUseful;
224  } else if (rev > CURRENT_CAMERA_FIRMWARE_VERSION) {
225  ret = FirmwareStatus::Future;
226  std::cout
227  << "\n[Video-based Tracking] Detected camera "
228  "firmware version "
229  << rev << std::endl;
230  } else {
231  // they're on the current version.
232  ret = FirmwareStatus::Good;
233  }
234  return ret;
235  }
236  // Hmm, couldn't parse as a number, weird.
237  }
238  }
239  }
240  return ret;
241  }
242 #endif
243 } // namespace vbtracker
244 } // namespace osvr
245 #endif // INCLUDED_CheckFirmwareVersion_h_GUID_C1356250_0CF2_4595_83A5_1522F8AC6795
Header with a template alias for the desired COM smart pointer.
The main namespace for all C++ elements of the framework, internal and external.
Definition: namespace_osvr.dox:3
Header defining a wrapper for COM&#39;s VARIANT type.
A small structure to hold a non zero as a triplet (i,j,value).
Definition: SparseUtil.h:148
boost::intrusive_ptr< T > Ptr
Template alias for our desired COM smart pointer.
Definition: ComPtr.h:40