Терминальный проект КиберПлат [open source]
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

639 lines
21KB

  1. /* @file Реализация сервиса для работы с устройствами. */
  2. // Qt
  3. #include <Common/QtHeadersBegin.h>
  4. #include <QtCore/QFileInfo>
  5. #include <QtConcurrent/QtConcurrentRun>
  6. #include <Common/QtHeadersEnd.h>
  7. // STL
  8. #include <algorithm>
  9. // SDK
  10. #include <SDK/PaymentProcessor/Core/Event.h>
  11. #include <SDK/PaymentProcessor/Settings/TerminalSettings.h>
  12. #include <SDK/Drivers/InteractionTypes.h>
  13. #include <SDK/Drivers/DeviceStatus.h>
  14. #include <SDK/Drivers/Components.h>
  15. #include <SDK/Drivers/HardwareConstants.h>
  16. // Modules
  17. #include "DeviceManager/DeviceManager.h"
  18. #include "Hardware/FR/FiscalFieldDescriptions.h"
  19. // Project
  20. #include "DatabaseUtils/IHardwareDatabaseUtils.h"
  21. #include "Services/ServiceNames.h"
  22. #include "Services/PluginService.h"
  23. #include "Services/DatabaseService.h"
  24. #include "Services/SettingsService.h"
  25. #include "System/IApplication.h"
  26. #include "DeviceService.h"
  27. namespace PPSDK = SDK::PaymentProcessor;
  28. //---------------------------------------------------------------------------
  29. DeviceService * DeviceService::instance(IApplication * aApplication)
  30. {
  31. return static_cast<DeviceService *>(aApplication->getCore()->getService(CServices::DeviceService));
  32. }
  33. //------------------------------------------------------------------------------
  34. DeviceService::Status::Status() :
  35. mLevel(SDK::Driver::EWarningLevel::Error), mDescription(tr("#status_undefined")), mStatus(0)
  36. {
  37. }
  38. //------------------------------------------------------------------------------
  39. DeviceService::Status::Status(SDK::Driver::EWarningLevel::Enum aLevel, const QString & aDescription, int aStatus) :
  40. mLevel(aLevel), mDescription(aDescription), mStatus(aStatus)
  41. {
  42. }
  43. //------------------------------------------------------------------------------
  44. DeviceService::Status::Status(const Status & aStatus) :
  45. mLevel(aStatus.mLevel), mDescription(aStatus.mDescription), mStatus(aStatus.mStatus)
  46. {
  47. }
  48. //------------------------------------------------------------------------------
  49. SDK::Driver::EWarningLevel::Enum DeviceService::Status::level() const
  50. {
  51. return mLevel;
  52. }
  53. //------------------------------------------------------------------------------
  54. const QString & DeviceService::Status::description() const
  55. {
  56. return mDescription;
  57. }
  58. //------------------------------------------------------------------------------
  59. bool DeviceService::Status::isMatched(SDK::Driver::EWarningLevel::Enum aLevel) const
  60. {
  61. return (mLevel <= aLevel && DSDK::getStatusType(mStatus) != DSDK::EStatus::Interface);
  62. }
  63. //------------------------------------------------------------------------------
  64. DeviceService::DeviceService(IApplication * aApplication)
  65. : mAccessMutex(QMutex::Recursive),
  66. mLog(aApplication->getLog()),
  67. mApplication(aApplication),
  68. mDeviceManager(0)
  69. {
  70. connect(&mDetectionResult, SIGNAL(finished()), this, SLOT(onDetectionFinished()));
  71. mDeviceCreationOrder[DSDK::CComponents::Watchdog] = EDeviceCreationOrder::AtStart;
  72. mDeviceCreationOrder[DSDK::CComponents::Health] = EDeviceCreationOrder::AtStart;
  73. #ifdef TC_USE_TOKEN
  74. mDeviceCreationOrder[DSDK::CComponents::Token] = EDeviceCreationOrder::AtStart;
  75. #endif
  76. }
  77. //------------------------------------------------------------------------------
  78. bool DeviceService::initialize()
  79. {
  80. // Вытаскиваем загрузчик плагинов.
  81. PluginService * pluginManager = PluginService::instance(mApplication);
  82. mDeviceManager = new DeviceManager(pluginManager->getPluginLoader());
  83. mDeviceManager->setLog(mApplication->getLog());
  84. // Здесь используем DirectConnction для того, чтобы инициализация устройства при автопоиске
  85. // производилась из потока автопоиска и не грузила основной поток.
  86. connect(mDeviceManager, SIGNAL(deviceDetected(const QString &, SDK::Driver::IDevice *)), this,
  87. SLOT(onDeviceDetected(const QString &, SDK::Driver::IDevice *)), Qt::DirectConnection);
  88. mDatabaseUtils = DatabaseService::instance(mApplication)->getDatabaseUtils<IHardwareDatabaseUtils>();
  89. mDeviceManager->initialize();
  90. mIntegratedDrivers.initialize(mDeviceManager);
  91. return true;
  92. }
  93. //------------------------------------------------------------------------------
  94. void DeviceService::finishInitialize()
  95. {
  96. // Повторный эмит статусов всех устройств
  97. QMapIterator<QString, Status> it(mDeviceStatusCache);
  98. while (it.hasNext())
  99. {
  100. it.next();
  101. Status status = it.value();
  102. emit deviceStatusChanged(it.key(), status.mLevel, status.mDescription, status.mStatus);
  103. }
  104. // Создаём устройства, которым положено запускаться при старте системы
  105. foreach (auto deviceInstance, getConfigurations(false))
  106. {
  107. QString deviceType = deviceInstance.section('.', 2, 2);
  108. if (mDeviceCreationOrder.contains(deviceType) && mDeviceCreationOrder.value(deviceType) == EDeviceCreationOrder::AtStart)
  109. {
  110. acquireDevice(deviceInstance);
  111. }
  112. }
  113. LOG(mLog, LogLevel::Normal, "DeviceService initialized.");
  114. }
  115. //---------------------------------------------------------------------------
  116. bool DeviceService::canShutdown()
  117. {
  118. return true;
  119. }
  120. //------------------------------------------------------------------------------
  121. bool DeviceService::shutdown()
  122. {
  123. if (mDetectionResult.isRunning())
  124. {
  125. stopDetection();
  126. mDetectionResult.waitForFinished();
  127. }
  128. releaseAll();
  129. delete mDeviceManager;
  130. return true;
  131. }
  132. //------------------------------------------------------------------------------
  133. QString DeviceService::getName() const
  134. {
  135. return CServices::DeviceService;
  136. }
  137. //------------------------------------------------------------------------------
  138. QVariantMap DeviceService::getParameters() const
  139. {
  140. return QVariantMap();
  141. }
  142. //------------------------------------------------------------------------------
  143. void DeviceService::resetParameters(const QSet<QString> &)
  144. {
  145. }
  146. //------------------------------------------------------------------------------
  147. const QSet<QString> & DeviceService::getRequiredServices() const
  148. {
  149. static QSet<QString> requiredServices = QSet<QString>()
  150. << CServices::DatabaseService
  151. << CServices::PluginService;
  152. return requiredServices;
  153. }
  154. //------------------------------------------------------------------------------
  155. DeviceService::~DeviceService()
  156. {
  157. }
  158. //------------------------------------------------------------------------------
  159. void DeviceService::detect(const QString & aFilter)
  160. {
  161. mAccessMutex.lock();
  162. mDetectionResult.setFuture(QtConcurrent::run(this, &DeviceService::doDetect, aFilter));
  163. }
  164. //------------------------------------------------------------------------------
  165. void DeviceService::doDetect(const QString & aFilter)
  166. {
  167. LOG(mLog, LogLevel::Normal, "Starting device detection...");
  168. mDeviceManager->detect(aFilter);
  169. }
  170. //------------------------------------------------------------------------------
  171. void DeviceService::stopDetection()
  172. {
  173. mDeviceManager->stopDetection();
  174. }
  175. //------------------------------------------------------------------------------
  176. void DeviceService::onDetectionFinished()
  177. {
  178. mAccessMutex.unlock();
  179. emit detectionStopped();
  180. LOG(mLog, LogLevel::Normal, "Device detection is completed or terminated.");
  181. }
  182. //------------------------------------------------------------------------------
  183. void DeviceService::onDeviceDetected(const QString & aConfigName, DSDK::IDevice * aDevice)
  184. {
  185. mAcquiredDevices.insert(aConfigName, aDevice);
  186. initializeDevice(aConfigName, aDevice);
  187. emit deviceDetected(aConfigName);
  188. }
  189. //------------------------------------------------------------------------------
  190. bool DeviceService::initializeDevice(const QString & aConfigName, DSDK::IDevice * aDevice)
  191. {
  192. // Устанавливаем параметры, необходимые для инициализации устройства.
  193. foreach (const QString & deviceType, mInitParameters.keys())
  194. {
  195. if (aConfigName.indexOf(deviceType) != -1)
  196. {
  197. aDevice->setDeviceConfiguration(mInitParameters[deviceType]);
  198. }
  199. }
  200. // Подписываемся на события об изменении статуса устройства.
  201. aDevice->subscribe(SDK::Driver::IDevice::StatusSignal, this, SLOT(onDeviceStatus(SDK::Driver::EWarningLevel::Enum, const QString &, int)));
  202. // Инициализируем устройство.
  203. aDevice->initialize();
  204. // Добавляем имя устройства как параметр в БД.
  205. mDatabaseUtils->setDeviceParam(aConfigName, PPSDK::CDatabaseConstants::Parameters::DeviceName, aDevice->getName());
  206. return true;
  207. }
  208. //------------------------------------------------------------------------------
  209. DSDK::IDevice * DeviceService::acquireDevice(const QString & aInstancePath)
  210. {
  211. QMutexLocker lock(&mAccessMutex);
  212. QString instancePath(aInstancePath);
  213. QString configInstancePath(instancePath);
  214. mDeviceManager->checkITInstancePath(instancePath);
  215. if (mAcquiredDevices.contains(instancePath))
  216. {
  217. return mAcquiredDevices.value(instancePath);
  218. }
  219. else
  220. {
  221. DSDK::IDevice * device = mDeviceManager->acquireDevice(instancePath, configInstancePath);
  222. if (device)
  223. {
  224. mAcquiredDevices.insert(instancePath, device);
  225. QMap<int, PPSDK::SKeySettings> keys = SettingsService::instance(mApplication)->getAdapter<PPSDK::TerminalSettings>()->getKeys();
  226. if (keys.contains(0))
  227. {
  228. QVariantMap configuration;
  229. configuration.insert(CHardware::FiscalFields::AutomaticNumber, keys.value(0).ap);
  230. device->setDeviceConfiguration(configuration);
  231. }
  232. initializeDevice(instancePath, device);
  233. }
  234. return device;
  235. }
  236. }
  237. //------------------------------------------------------------------------------
  238. void DeviceService::releaseDevice(DSDK::IDevice * aDevice)
  239. {
  240. QMutexLocker lock(&mAccessMutex);
  241. mAcquiredDevices.remove(mAcquiredDevices.key(aDevice));
  242. mDeviceManager->releaseDevice(aDevice);
  243. }
  244. //------------------------------------------------------------------------------
  245. PPSDK::IDeviceService::UpdateFirmwareResult DeviceService::updateFirmware(const QByteArray & aFirmware, const QString & aDeviceGUID)
  246. {
  247. //TODO: сделать проверку выше (например, в апдейтере) на то, что файл открывается и что он не пуст
  248. QMutexLocker lock(&mAccessMutex);
  249. DSDK::IDevice * device = nullptr;
  250. LOG(mLog, LogLevel::Normal, QString("Start update firmware device with GUID %1.").arg(aDeviceGUID));
  251. for (TAcquiredDevices::iterator it = mAcquiredDevices.begin(); it != mAcquiredDevices.end(); ++it)
  252. {
  253. if (it.key().contains(aDeviceGUID))
  254. {
  255. device = it.value();
  256. }
  257. }
  258. if (!device)
  259. {
  260. LOG(mLog, LogLevel::Error, QString("No device with GUID %1 for updating the firmware.").arg(aDeviceGUID));
  261. return IDeviceService::NoDevice;
  262. }
  263. QVariantMap config = device->getDeviceConfiguration();
  264. if (!device->canUpdateFirmware())
  265. {
  266. LOG(mLog, LogLevel::Error, "The device cannot be updated.");
  267. return IDeviceService::CantUpdate;
  268. }
  269. device->updateFirmware(aFirmware);
  270. return IDeviceService::OK;
  271. }
  272. //------------------------------------------------------------------------------
  273. QString DeviceService::createDevice(const QString & aDriverPath, const QVariantMap & aConfig)
  274. {
  275. QMutexLocker lock(&mAccessMutex);
  276. QString driverPath(aDriverPath);
  277. mIntegratedDrivers.checkDriverPath(driverPath, aConfig);
  278. TNamedDevice result = mDeviceManager->createDevice(driverPath, aConfig);
  279. if (result.second)
  280. {
  281. mAcquiredDevices.insert(result.first, result.second);
  282. QMap<int, PPSDK::SKeySettings> keys = SettingsService::instance(mApplication)->getAdapter<PPSDK::TerminalSettings>()->getKeys();
  283. if (keys.contains(0))
  284. {
  285. QVariantMap configuration;
  286. configuration.insert(CHardware::FiscalFields::AutomaticNumber, keys.value(0).ap);
  287. result.second->setDeviceConfiguration(configuration);
  288. }
  289. initializeDevice(result.first, result.second);
  290. }
  291. else
  292. {
  293. LOG(mLog, LogLevel::Error, QString("Failed to create device %1 .").arg(driverPath));
  294. }
  295. return result.first;
  296. }
  297. //------------------------------------------------------------------------------
  298. SDK::PaymentProcessor::TModelList DeviceService::getModelList(const QString & aFilter) const
  299. {
  300. PPSDK::TModelList result = mDeviceManager->getModelList(aFilter);
  301. mIntegratedDrivers.filterModelList(result);
  302. return result;
  303. }
  304. //------------------------------------------------------------------------------
  305. QStringList DeviceService::getAcquiredDevicesList() const
  306. {
  307. QMutexLocker lock(&mAccessMutex);
  308. return mAcquiredDevices.keys();
  309. }
  310. //------------------------------------------------------------------------------
  311. void DeviceService::releaseAll()
  312. {
  313. QMutexLocker lock(&mAccessMutex);
  314. foreach (DSDK::IDevice * device, mAcquiredDevices.values())
  315. {
  316. releaseDevice(device);
  317. }
  318. }
  319. //------------------------------------------------------------------------------
  320. QString DeviceService::getDeviceConfigName(DSDK::IDevice * aDevice)
  321. {
  322. QMutexLocker lock(&mAccessMutex);
  323. return mAcquiredDevices.key(aDevice);
  324. }
  325. //------------------------------------------------------------------------------
  326. void DeviceService::setInitParameters(const QString & aDeviceType, const QVariantMap & aParameters)
  327. {
  328. mInitParameters[aDeviceType] = aParameters;
  329. }
  330. //------------------------------------------------------------------------------
  331. QStringList DeviceService::getConfigurations(bool aAllowOldConfigs) const
  332. {
  333. PPSDK::TerminalSettings * settings = SettingsService::instance(mApplication)->getAdapter<PPSDK::TerminalSettings>();
  334. QStringList configurations = settings->getDeviceList();
  335. if (aAllowOldConfigs)
  336. {
  337. for (int i = 0; i < configurations.size(); ++i)
  338. {
  339. mDeviceManager->checkITInstancePath(configurations[i]);
  340. }
  341. }
  342. // Обязательные устройства "присуствуют" всегда
  343. QStringList driverList = mDeviceManager->getDriverList();
  344. QStringList requiredDevices;
  345. requiredDevices << DSDK::CComponents::Health;
  346. #ifdef TC_USE_TOKEN
  347. requiredDevices << DSDK::CComponents::Token;
  348. #endif
  349. foreach(QString type, requiredDevices)
  350. {
  351. auto isDevicePresent = [type](const QString & aConfigurationName) -> bool { return aConfigurationName.contains(type); };
  352. if (std::find_if(configurations.begin(), configurations.end(), isDevicePresent) == configurations.end() &&
  353. std::find_if(driverList.begin(), driverList.end(), isDevicePresent) != driverList.end())
  354. {
  355. configurations << *std::find_if(driverList.begin(), driverList.end(), isDevicePresent);
  356. }
  357. }
  358. return configurations;
  359. }
  360. //------------------------------------------------------------------------------
  361. bool DeviceService::saveConfigurations(const QStringList & aConfigList)
  362. {
  363. // Проходимся по всем задействованным устройствам и сохраняем конфигурацию.
  364. foreach (const QString & configName, aConfigList)
  365. {
  366. DSDK::IDevice * device = acquireDevice(configName);
  367. if (device)
  368. {
  369. mDeviceManager->saveConfiguration(device);
  370. }
  371. else
  372. {
  373. LOG(mLog, LogLevel::Error, QString("Failed to set device configuration. No such device: %1.").arg(configName));
  374. }
  375. }
  376. PPSDK::TerminalSettings * settings = SettingsService::instance(mApplication)->getAdapter<PPSDK::TerminalSettings>();
  377. settings->setDeviceList(aConfigList);
  378. mDatabaseUtils->removeUnknownDevice(aConfigList);
  379. // Посылаем сигнал, чтобы остальные сервисы обновили устройства.
  380. emit configurationUpdated();
  381. return true;
  382. }
  383. //------------------------------------------------------------------------------
  384. QVariantMap DeviceService::getDeviceConfiguration(const QString & aConfigName)
  385. {
  386. QMutexLocker lock(&mAccessMutex);
  387. DSDK::IDevice * device = acquireDevice(aConfigName);
  388. if (device)
  389. {
  390. return mDeviceManager->getDeviceConfiguration(device);
  391. }
  392. else
  393. {
  394. LOG(mLog, LogLevel::Error, QString("Failed to set device configuration. No such device: %1.").arg(aConfigName));
  395. return QVariantMap();
  396. }
  397. }
  398. //------------------------------------------------------------------------------
  399. void DeviceService::setDeviceConfiguration(const QString & aConfigName, const QVariantMap & aConfig)
  400. {
  401. DSDK::IDevice * device = acquireDevice(aConfigName);
  402. // Производим переинициализацию устройства.
  403. if (device)
  404. {
  405. device->release();
  406. {
  407. QMutexLocker lock(&mAccessMutex);
  408. mDeviceManager->setDeviceConfiguration(device, aConfig);
  409. }
  410. device->initialize();
  411. }
  412. else
  413. {
  414. LOG(mLog, LogLevel::Error, QString("Failed to set device configuration. No such device: %1.").arg(aConfigName));
  415. }
  416. }
  417. //------------------------------------------------------------------------------
  418. SDK::Plugin::TParameterList DeviceService::getDriverParameters(const QString & aDriverPath) const
  419. {
  420. SDK::Plugin::TParameterList result = mDeviceManager->getDriverParameters(aDriverPath);
  421. mIntegratedDrivers.filterDriverParameters(aDriverPath, result);
  422. return result;
  423. }
  424. //------------------------------------------------------------------------------
  425. QStringList DeviceService::getDriverList() const
  426. {
  427. // Выдаем список драйверов всех устройств, кроме портов.
  428. QStringList result = mDeviceManager->getDriverList().filter(QRegExp(".+\\.Driver\\.(?!IOPort)"));
  429. mIntegratedDrivers.filterDriverList(result);
  430. return result;
  431. }
  432. //------------------------------------------------------------------------------
  433. void DeviceService::overwriteDeviceStatus(DSDK::IDevice * aDevice, DSDK::EWarningLevel::Enum aLevel, const QString & aDescription, int aStatus)
  434. {
  435. // Берём последний статус и пишем в БД, только если новый статус отличается по WarningLevel
  436. QString configName = mAcquiredDevices.key(aDevice);
  437. if (!mDeviceStatusCache.contains(configName) ||
  438. mDeviceStatusCache[configName].mLevel != aLevel ||
  439. DSDK::getStatusType(mDeviceStatusCache[configName].mStatus) == DSDK::EStatus::Interface)
  440. {
  441. Status status(aLevel, aDescription, aStatus);
  442. statusChanged(aDevice, status);
  443. }
  444. }
  445. //------------------------------------------------------------------------------
  446. void DeviceService::onDeviceStatus(DSDK::EWarningLevel::Enum aLevel, const QString & aDescription, int aStatus)
  447. {
  448. LogLevel::Enum logLevel = (aLevel == DSDK::EWarningLevel::OK) ? LogLevel::Normal : (aLevel == DSDK::EWarningLevel::Error) ? LogLevel::Error : LogLevel::Warning;
  449. LOG(mLog, logLevel, QString("Received statuses: %1, status %2").arg(aDescription).arg(aStatus));
  450. DSDK::IDevice * device = dynamic_cast<DSDK::IDevice *>(sender());
  451. if (device)
  452. {
  453. Status status(aLevel, aDescription, aStatus);
  454. statusChanged(device, status);
  455. // Удаляем неиспользуемые устройства.
  456. foreach (auto configName, mDeviceStatusCache.keys())
  457. {
  458. if (!mAcquiredDevices.contains(configName))
  459. {
  460. mDeviceStatusCache.remove(configName);
  461. }
  462. }
  463. }
  464. }
  465. //------------------------------------------------------------------------------
  466. void DeviceService::statusChanged(DSDK::IDevice * aDevice, Status & aStatus)
  467. {
  468. DSDK::EStatus::Enum statusType = DSDK::getStatusType(aStatus.mStatus);
  469. // Если данный статус зарегистрирован в исключениях, то мы его не обрабатываем.
  470. if (statusType == DSDK::EStatus::Service)
  471. {
  472. return;
  473. }
  474. // Запоминаем последние статусы.
  475. QString configName = mAcquiredDevices.key(aDevice);
  476. mDeviceStatusCache[configName] = aStatus;
  477. LogLevel::Enum logLevel = (aStatus.mLevel == DSDK::EWarningLevel::OK) ? LogLevel::Normal : (aStatus.mLevel == DSDK::EWarningLevel::Error) ? LogLevel::Error : LogLevel::Warning;
  478. LOG(mLog, logLevel, QString("Send statuses: %1, status %2, device %3").arg(aStatus.mDescription).arg(aStatus.mStatus).arg(configName));
  479. if (statusType != DSDK::EStatus::Interface)
  480. {
  481. // Обновляем имя и информацию об устройстве в базе, т.к. возможно уточнено имя после обращения к устройству.
  482. mDatabaseUtils->setDeviceParam(configName, PPSDK::CDatabaseConstants::Parameters::DeviceName, aDevice->getName());
  483. QVariantMap deviceConfig = aDevice->getDeviceConfiguration();
  484. if (deviceConfig.contains(CHardwareSDK::DeviceData))
  485. {
  486. mDatabaseUtils->setDeviceParam(configName, PPSDK::CDatabaseConstants::Parameters::DeviceInfo, deviceConfig[CHardwareSDK::DeviceData].toString());
  487. }
  488. // Пишем статус в БД.
  489. mDatabaseUtils->addDeviceStatus(configName, aStatus.mLevel, aStatus.mDescription);
  490. }
  491. emit deviceStatusChanged(configName, aStatus.mLevel, aStatus.mDescription, aStatus.mStatus);
  492. }
  493. //------------------------------------------------------------------------------
  494. QSharedPointer<PPSDK::IDeviceStatus> DeviceService::getDeviceStatus(const QString & aConfigName)
  495. {
  496. if (mDeviceStatusCache.contains(aConfigName))
  497. {
  498. return QSharedPointer<PPSDK::IDeviceStatus>(new Status(mDeviceStatusCache.value(aConfigName)));
  499. }
  500. return QSharedPointer<PPSDK::IDeviceStatus>(nullptr);
  501. }
  502. //------------------------------------------------------------------------------