#pragma once #include #include #include #include "ByteCommandQueue.h" #include "ByteArrayProvider.h" #include "EEcgMode.h" #include "UsbDeviceCommandSet.h" #include "UsbDeviceEcgModeController.h" #include "ReadInnerChannelsLsbCommand.h" #include "ReadEcgLsbCommand.h" #include "ReadCableExistCommand.h" #include "ReadExternAccLsbCommand.h" #include "ReadEcgModeCommand.h" #include "GetTimeCommand.h" #include "DeviceCommandStatusConverter.h" #include "CableTypeInfo.h" #include "ComplexCommandCreateData.h" #include "ComplexCommandCreateMultidata.h" #include namespace Incart::Usb { enum class UsbDeviceManagerFlags { DeviceExistAutoCheck, // Проверка подключения прибора посредством отправки какой-либо команды, например, Echo, в "бесконечном" цикле CableExistAutoCheck, // Проверка подключения кабеля посредством отправки соответствующей команды в "бесконечном" цикле // данный флаг отключает автоматическое применение калибровок и пользователю отдается исходный сигнал в мкВ WithoutAdcOn, // По умолчанию, после подключения прибора автоматически выполняется команда AdcOn. С данным флагом команда AdcOn автоматически не отправляется. WithoutEmbeddedCommands // Отключает отправку любых внутренних команд кроме команды Name }; class UsbDeviceManager : public QObject { Q_OBJECT private: DeviceInfo m_connectedDeviceInfo; UsbDeviceCommandSet m_commandSet; UsbDeviceEcgModeController m_ecgModeController; ByteCommandQueue m_commandQueue; std::shared_ptr m_signalManager; // генерируем команды при первом обращении (после коннекта с прибором) // данный механизм не подходит для команд которые могут менять свои параментры (например для команд калибровок) std::unordered_map> m_executedComplexCommands; // необходимо хранить указатели на запущенные команды, иначе shared_ptr может автоматически их удалить QTimer m_deviceExistCheckTimer; bool m_hasConnectedDevice = false; bool m_canStartDeviceExistCommand = true; std::unordered_set m_flags; std::vector m_cableTypes; bool m_isReoAndPelRead = false; bool m_isReoOn = false; public: UsbDeviceManager(UsbCmdWriter* cmdWriter, UsbCmdListener* cmdListener, const std::unordered_map& devicesInfo, const std::vector& cableTypes, ComplexCommandFactory* complexCommandFactory, std::shared_ptr signalManager, const std::unordered_set& flags) : m_commandSet(devicesInfo, complexCommandFactory) , m_ecgModeController(signalManager) , m_commandQueue(cmdWriter, cmdListener) , m_signalManager(signalManager) , m_flags(flags) , m_cableTypes(cableTypes) { connect(&m_commandQueue, &ByteCommandQueue::signalCommandError, this, &UsbDeviceManager::handleCommandError, Qt::QueuedConnection); m_deviceExistCheckTimer.setInterval(300); } ~UsbDeviceManager() { m_deviceExistCheckTimer.stop(); } signals: void deviceIsConnected(); void cableIsConnected(); void cableIsDisconnected(); void signalError(const std::string& errorType, const std::string& message); public: void handleDeviceConnect() { m_hasConnectedDevice = true; m_commandQueue.setIsDeviceConnected(true); std::shared_ptr getNameByteCommand = std::make_shared("Name", m_commandQueue.generateUid(), std::vector{ 0x7e, 0x00, 0x00, 0x02, 0x99, 0xcd, 0xbd }); connect(getNameByteCommand.get(), &ByteCommand::answerIsReady, this, &UsbDeviceManager::handleNameCommandAnswer); m_commandQueue.enqueue(getNameByteCommand); } void handleDeviceDisconnect() { m_hasConnectedDevice = false; m_deviceExistCheckTimer.stop(); m_commandQueue.handleDisconnect(); m_commandSet.setConnectedDeviceInfo(DeviceInfo{}); m_commandSet.setHasConnectedDevice(false); m_connectedDeviceInfo = DeviceInfo{}; m_canStartDeviceExistCommand = true; } bool getIsReoOn() { return m_isReoOn; } bool getIsReoAndPelRead() { return m_isReoAndPelRead; } void setIsReoOn(bool isReoOn) { m_isReoAndPelRead = true; m_isReoOn = isReoOn; } DeviceInfo getConnectedDeviceInfo() { return m_connectedDeviceInfo; } UsbDeviceCommandSet* getCommandSet() { return &m_commandSet; } std::vector getCableTypes() { return m_cableTypes; } UsbDeviceEcgModeController* getEcgModeController() { return &m_ecgModeController; } ByteCommandQueue* getCommandQueue() { return &m_commandQueue; } void executeCommand(std::shared_ptr command) { std::cout << __PRETTY_FUNCTION__ << std::endl; m_commandQueue.enqueue(command); } private slots: void handleCommandError(std::string commandName, std::vector sendBytes, std::vector answer, int errorCode) { std::string message = "Command \"" + commandName + "\" finished with error: " + DeviceCommandStatusConverter::toText((DeviceCommand::EStatus)errorCode); message += ".\r\nSend: [" + Common::ByteArrayProvider::packToText(sendBytes) + "], Received: [" + Common::ByteArrayProvider::packToText(answer) + "]."; emit signalError("CommandError", message); } void handleNameCommandAnswer(std::shared_ptr /*command*/, const std::vector& answer, int32_t status) { if (!m_hasConnectedDevice) { // если после помещения в очередь прибор отключился, по идее такого не должно быть, т.к. команда Name - первая команда прибору, // а до подачи команды прибору мы не может узнать, отключился он или нет status = DeviceCommand::EStatus::DEVICE_DISCONNECTED; } if ((status != DeviceCommand::EStatus::OK) || (answer.size() < 12)) { std::string errorMessage = "Command \"Name\" finished with error: "; if (status == DeviceCommand::EStatus::OK) { errorMessage += DeviceCommandStatusConverter::toText(DeviceCommand::EStatus::WRONG_FRAME_FORMAT) + " [" + Common::ByteArrayProvider::packToText(answer) + "]"; } else { errorMessage += DeviceCommandStatusConverter::toText((DeviceCommand::EStatus)status); } emit signalError("CommandError", errorMessage); return; } uint16_t deviceType = Common::ByteArrayProvider::getWordFromArray(answer, 6); DevicesInfo::DeviceCommonInfo deviceTypeInfo = m_commandSet.getDeviceInfo(deviceType); m_connectedDeviceInfo.typeInfo = deviceTypeInfo; DeviceBaseInfoAggregator::aggregateDeviceInfo(m_connectedDeviceInfo, answer); Common::JTerminal() << __PRETTY_FUNCTION__ << "connected device name:" << DeviceBaseInfoAggregator::getDeviceName(m_connectedDeviceInfo); if (hasFlag(UsbDeviceManagerFlags::WithoutEmbeddedCommands)) { m_signalManager->setConnectedDeviceInfo(m_connectedDeviceInfo); m_commandSet.setConnectedDeviceInfo(m_connectedDeviceInfo); m_commandSet.setHasConnectedDevice(true); emit deviceIsConnected(); return; } // to execute time command m_commandSet.setConnectedDeviceInfo(m_connectedDeviceInfo); getTime(); } void handleAdcOnCommandAnswer(std::shared_ptr command, std::vector /*answer*/, int32_t status) { if (status != DeviceCommand::EStatus::OK) { sendCommandFinishError(command->getName(), (DeviceCommand::EStatus)status); } } void handleEchoCommandAnswer(std::shared_ptr command, std::vector answer, int32_t status) { // проверяем что данные в ответе совпадают с отправленными if ((answer.size() != 8) || (answer[4] != command->getBytes()[4])) { status = DeviceCommand::EStatus::WRONG_FRAME_FORMAT; } // Прибор может быть занят и не обработать команду, ждем когда освободится if (m_hasConnectedDevice && (status != DeviceCommand::EStatus::TIMEOUT) && (status != DeviceCommand::EStatus::OK)) { if (status == DeviceCommand::EStatus::WRONG_FRAME_FORMAT) { std::string errorMessage = "Command \"Echo\" finished with error: " + DeviceCommandStatusConverter::toText((DeviceCommand::EStatus)status) + " [" + Common::ByteArrayProvider::packToText(answer) + "]"; emit signalError("CommandError", errorMessage); } else { sendCommandFinishError(command->getName(), (DeviceCommand::EStatus)status); } } m_canStartDeviceExistCommand = true; } void handleGetTimeCommandAnswer(ComplexCommand* command_, Common::DateTimeObject dateTime_, std::shared_ptr status_) { if (!m_hasConnectedDevice) { status_->status = DeviceCommand::EStatus::DEVICE_DISCONNECTED; } std::string commandName = command_->getName(); removeExecutedCommand(command_); if (status_->status != DeviceCommand::EStatus::OK) { sendCommandFinishError(commandName, status_); return; } m_connectedDeviceInfo.restartTime = dateTime_; m_signalManager->setConnectedDeviceInfo(m_connectedDeviceInfo); m_commandSet.setConnectedDeviceInfo(m_connectedDeviceInfo); m_commandSet.setHasConnectedDevice(true); emit deviceIsConnected(); tryAdcOn(); tryStartDeviceExistCheck(); } void checkDeviceExist() { if (!m_hasConnectedDevice || !m_canStartDeviceExistCommand) { return; } m_canStartDeviceExistCommand = false; std::shared_ptr echoByteCommand = std::make_shared("Echo", m_commandQueue.generateUid(), std::vector{ 0x7e,0x01,0x00,0x01,0xdd,0xff,0xff,0xbd }); connect(echoByteCommand.get(), &ByteCommand::answerIsReady, this, &UsbDeviceManager::handleEchoCommandAnswer); m_commandQueue.enqueue(echoByteCommand); } void checkCableExist() { if (!m_hasConnectedDevice || !m_canStartDeviceExistCommand) { return; } m_canStartDeviceExistCommand = false; std::shared_ptr commandData = std::make_shared>(m_commandQueue.generateUid()); std::shared_ptr readCableExistCommand = std::dynamic_pointer_cast(m_commandSet.createComplexCommand("ReadCableExist", commandData)); addExecutedCommand(readCableExistCommand); connect(readCableExistCommand.get(), &ReadCableExistCommand::answerIsReady, this, &UsbDeviceManager::handleReadCableExistAnswer); std::shared_ptr statusInfo = executeInitCommand(readCableExistCommand); if (statusInfo->status != DeviceCommand::EStatus::OK) { m_canStartDeviceExistCommand = true; } } void handleReadCableExistAnswer(ComplexCommand* command, bool cableExist, std::shared_ptr statusInfo) { std::string commandName = command->getName(); // Прибор может быть занят и не обработать команду, ждем когда освободится if (!m_hasConnectedDevice || (statusInfo->status == DeviceCommand::EStatus::TIMEOUT)) { m_canStartDeviceExistCommand = true; return; } if (statusInfo->status != DeviceCommand::EStatus::OK) { m_connectedDeviceInfo.cableIsConnected = false; sendCommandFinishError(commandName, statusInfo); handleCableDisconnect(); m_canStartDeviceExistCommand = true; return; } //std::cout << __PRETTY_FUNCTION__ << " cableExist = " << cableExist << std::endl; if (m_connectedDeviceInfo.cableIsConnected != cableExist) { m_connectedDeviceInfo.cableIsConnected = cableExist; if (m_connectedDeviceInfo.cableIsConnected) { //std::cout << __PRETTY_FUNCTION__ << " connect (1)" << std::endl; handleCableConnect(); } else { //std::cout << __PRETTY_FUNCTION__ << " disconnect (2)" << std::endl; handleCableDisconnect(); m_canStartDeviceExistCommand = true; } } } void handleReadEcgModeCommandAnswer(ComplexCommand* command, UsbDevice::EEcgMode cableMode, std::shared_ptr status) { if (!m_hasConnectedDevice) { status->status = DeviceCommand::EStatus::DEVICE_DISCONNECTED; } std::string commandName = command->getName(); removeExecutedCommand(command); if (status->status != DeviceCommand::EStatus::OK) { sendCommandFinishError(commandName, status); m_canStartDeviceExistCommand = true; return; } std::cout << __PRETTY_FUNCTION__ << " cableMode = " << (int)cableMode << std::endl; m_ecgModeController.changeEcgConfiguration(cableMode); m_canStartDeviceExistCommand = true; } private: void getTime() { std::cout << "getTime (0)" << std::endl; std::string commandName = "GetTime"; std::shared_ptr commandData = std::make_shared>(m_commandQueue.generateUid()); auto getTimeCommand = std::dynamic_pointer_cast(m_commandSet.createComplexCommand("GetTime", commandData)); if (getTimeCommand == nullptr) { sendImplementationNotFoundError(commandName); std::cout << "getTime (2)" << std::endl; return; } addExecutedCommand(getTimeCommand); connect(getTimeCommand.get(), &GetTimeCommand::answerIsReady, this, &UsbDeviceManager::handleGetTimeCommandAnswer); std::shared_ptr statusInfo = getTimeCommand->execute(); if (statusInfo->status != DeviceCommand::EStatus::OK) { sendCommandStartError(commandName, statusInfo->status); std::cout << "getTime (3)" << std::endl; return; } std::cout << "getTime (1)" << std::endl; } void tryAdcOn() { if (!hasFlag(UsbDeviceManagerFlags::WithoutAdcOn)) { std::shared_ptr adcOnByteCommand = std::make_shared("AdcOn", m_commandQueue.generateUid(), std::vector{ 0x7e,0x01,0x00,0x07,0x01,0xff,0xff,0xbd }); connect(adcOnByteCommand.get(), &ByteCommand::answerIsReady, this, &UsbDeviceManager::handleAdcOnCommandAnswer); m_commandQueue.enqueue(adcOnByteCommand); } } void tryStartDeviceExistCheck() { if (hasFlag(UsbDeviceManagerFlags::CableExistAutoCheck) || hasFlag(UsbDeviceManagerFlags::DeviceExistAutoCheck)) { disconnect(&m_deviceExistCheckTimer, &QTimer::timeout, this, &UsbDeviceManager::checkDeviceExist); connect(&m_deviceExistCheckTimer, &QTimer::timeout, this, &UsbDeviceManager::checkCableExist); m_deviceExistCheckTimer.start(); } } bool hasFlag(UsbDeviceManagerFlags flag) { return m_flags.find(flag) != m_flags.end(); } void handleCableConnect() { Common::JTerminal() << __PRETTY_FUNCTION__ << "CableIsConnected"; emit cableIsConnected(); std::shared_ptr commandData = std::make_shared>(m_commandQueue.generateUid()); std::shared_ptr readEcgModeCommand = std::dynamic_pointer_cast(m_commandSet.createComplexCommand("ReadEcgMode", commandData)); if (readEcgModeCommand == nullptr) { sendImplementationNotFoundError("ReadEcgMode"); m_canStartDeviceExistCommand = true; return; } addExecutedCommand(readEcgModeCommand); connect(readEcgModeCommand.get(), &ReadEcgModeCommand::answerIsReady, this, &UsbDeviceManager::handleReadEcgModeCommandAnswer); executeInitCommand(readEcgModeCommand); } void handleCableDisconnect() { Common::JTerminal() << __PRETTY_FUNCTION__ << "CableIsDisconnected"; emit cableIsDisconnected(); std::cout << __PRETTY_FUNCTION__ << std::endl; m_ecgModeController.changeEcgConfiguration(UsbDevice::EEcgMode::Mode12x10); } void sendImplementationNotFoundError(const std::string& commandName) { emit signalError("CommandError", "Implementation \"" + commandName + "\" is not found"); } void sendCommandStartError(const std::string& commandName, DeviceCommand::EStatus status) { emit signalError("CommandError", "Command \"" + commandName + "\" is not executed: " + DeviceCommandStatusConverter::toText(status)); } void sendCommandFinishError(const std::string& commandName, std::shared_ptr statusInfo_) { std::string errorMessage = "Command \"" + commandName + "\" finished with error: " + DeviceCommandStatusConverter::toText(statusInfo_->status); if (statusInfo_->status == DeviceCommand::EStatus::WRONG_FRAME_FORMAT) { std::shared_ptr>> statusInfo = std::dynamic_pointer_cast>>(statusInfo_); errorMessage += " [" + Common::ByteArrayProvider::packToText(statusInfo->info) + "]"; } emit signalError("CommandError", errorMessage); } void sendCommandFinishError(const std::string& commandName, DeviceCommand::EStatus status) { std::string errorMessage = "Command \"" + commandName + "\" finished with error: " + DeviceCommandStatusConverter::toText(status); emit signalError("CommandError", errorMessage); } void addExecutedCommand(std::shared_ptr command) { m_executedComplexCommands[command.get()] = command; } void removeExecutedCommand(ComplexCommand* command) { auto it = m_executedComplexCommands.find(command); if (it != m_executedComplexCommands.end()) { m_executedComplexCommands.erase(it); } } std::shared_ptr executeInitCommand(std::shared_ptr command) { std::shared_ptr status = command->execute(); if (status->status != Usb::DeviceCommand::EStatus::OK) { removeExecutedCommand(command.get()); sendCommandStartError(command->getName(), status->status); } return status; } }; } // namespace Incart::Usb