2024-11-26 16:24:50 +08:00
|
|
|
|
#include "BCIManager.h"
|
|
|
|
|
#include <QFile>
|
|
|
|
|
#include <QApplication>
|
|
|
|
|
#include <QDebug>
|
2025-01-05 14:41:32 +08:00
|
|
|
|
#include <QSettings>
|
|
|
|
|
#include <QTextCodec>
|
2024-11-26 16:24:50 +08:00
|
|
|
|
|
|
|
|
|
BCIManager::BCIManager(QObject *parent)
|
|
|
|
|
: QObject{parent}
|
|
|
|
|
{
|
2025-01-05 14:41:32 +08:00
|
|
|
|
readConfigFile();
|
2024-11-26 16:24:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool BCIManager::startLinkerPrograme()
|
|
|
|
|
{
|
|
|
|
|
QString strPath = QApplication::applicationDirPath().append("/cmd.txt");
|
|
|
|
|
|
|
|
|
|
QFile file(strPath);
|
|
|
|
|
if (!file.open(QIODevice::ReadOnly))
|
|
|
|
|
{
|
|
|
|
|
qDebug() << file.errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
QString strContent;
|
|
|
|
|
QTextStream in(&file);
|
|
|
|
|
while (!in.atEnd())
|
|
|
|
|
{
|
|
|
|
|
strContent = in.readLine();
|
|
|
|
|
if(!strContent.isEmpty())
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(strContent.isEmpty())
|
|
|
|
|
{
|
|
|
|
|
qDebug() << "cmd is empty";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//启动进程
|
|
|
|
|
//QString strCmd = QApplication::applicationDirPath().append("/BCILinker/SunnyLinkTool/") + strContent;
|
|
|
|
|
|
2025-01-05 14:41:32 +08:00
|
|
|
|
QString strCmd = QString("./%1 -t 1 -c %2 -p %3").arg(m_strExe).arg(m_strIp).arg(m_nPort);
|
2024-11-26 16:24:50 +08:00
|
|
|
|
|
|
|
|
|
qDebug() << strCmd;
|
|
|
|
|
if(nullptr == m_pCmd)
|
|
|
|
|
{
|
|
|
|
|
m_pCmd = new QProcess(this);
|
|
|
|
|
connect(m_pCmd, &QProcess::readyReadStandardOutput, this, &BCIManager::slotLinkerProgrameReadyReadStandardOutput);
|
|
|
|
|
connect(m_pCmd, &QProcess::readyReadStandardError, this, &BCIManager::slotLinkerProgrameReadyReadStandardError);
|
|
|
|
|
}
|
2025-01-05 14:41:32 +08:00
|
|
|
|
m_pCmd->startDetached(strCmd);
|
2024-11-26 16:24:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-11-28 13:38:22 +08:00
|
|
|
|
void BCIManager::initTrain()
|
|
|
|
|
{
|
|
|
|
|
if(nullptr == heartTimer)
|
|
|
|
|
{
|
|
|
|
|
heartTimer = new QTimer();
|
|
|
|
|
heartTimer->setInterval(1000);
|
|
|
|
|
heartTimer->start();
|
|
|
|
|
connect(heartTimer, SIGNAL(timeout()), this, SLOT(slotHeartTimer()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(nullptr == trainTimer)
|
|
|
|
|
{
|
|
|
|
|
trainTimer = new QTimer();
|
|
|
|
|
connect(trainTimer, SIGNAL(timeout()), this, SLOT(slotTrainTimer()));
|
|
|
|
|
|
|
|
|
|
m_st_bicycleParam.trainMode = 0; //被动
|
|
|
|
|
m_st_bicycleParam.spasmSwitch = 1; //开启
|
|
|
|
|
m_st_bicycleParam.spasmLevel = 1; //默认一级
|
|
|
|
|
m_st_bicycleParam.configPower = 0; //默认低
|
2024-11-28 15:20:18 +08:00
|
|
|
|
m_st_bicycleParam.switchDirectonTime = 0; //换向时间默认10
|
2024-11-28 13:38:22 +08:00
|
|
|
|
m_st_bicycleParam.phaseValue = 0; //协同相位值
|
|
|
|
|
m_st_bicycleParam.direction = 1; //方向正向
|
2024-11-29 17:47:45 +08:00
|
|
|
|
m_st_bicycleParam.speed = 20; //速度 10
|
2024-11-28 15:20:18 +08:00
|
|
|
|
m_st_bicycleParam.resistance = 0; //阻力 Nm 0~20挡
|
2024-11-28 13:38:22 +08:00
|
|
|
|
m_st_bicycleParam.spasmType = 0; //默认逆向
|
|
|
|
|
}
|
2024-12-03 13:41:51 +08:00
|
|
|
|
|
|
|
|
|
connect(this, &BCIManager::signalDeviceStatus, &getInstance(), &BCIManager::signalDeviceStatus);
|
2024-11-28 13:38:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-11-26 16:24:50 +08:00
|
|
|
|
void BCIManager::slotLinkerProgrameReadyReadStandardOutput()
|
|
|
|
|
{
|
|
|
|
|
if(m_pCmd)
|
|
|
|
|
{
|
|
|
|
|
qDebug() << m_pCmd->readAllStandardOutput();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BCIManager::slotLinkerProgrameReadyReadStandardError()
|
|
|
|
|
{
|
|
|
|
|
if(m_pCmd)
|
|
|
|
|
{
|
|
|
|
|
qDebug() << m_pCmd->readAllStandardError();
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-11-28 13:38:22 +08:00
|
|
|
|
|
|
|
|
|
void BCIManager::slotHeartTimer()
|
|
|
|
|
{
|
|
|
|
|
//qDebug()<<"上位机发送心跳";
|
|
|
|
|
CCommunicateAPI::getInstance()->sendHeartBeat();
|
|
|
|
|
static int num = 0;
|
|
|
|
|
++num;
|
|
|
|
|
if(num > 3)
|
|
|
|
|
{
|
|
|
|
|
num = 0;
|
|
|
|
|
QPixmap pixmap;
|
|
|
|
|
if(heartCount < 1)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if(heartCount >= 3)
|
|
|
|
|
{
|
|
|
|
|
heartCount = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BCIManager::slotTrainTimer()
|
|
|
|
|
{
|
|
|
|
|
stopTrain();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BCIManager::startTrain(int Part, int Time)
|
|
|
|
|
{
|
2025-01-05 14:41:32 +08:00
|
|
|
|
qDebug() << "33333333333333333333";
|
2024-11-28 13:38:22 +08:00
|
|
|
|
initTrain();
|
|
|
|
|
if(trainTimer->isActive())
|
|
|
|
|
{
|
|
|
|
|
stopTrain();
|
|
|
|
|
}
|
|
|
|
|
trainTimer->setInterval(Time * 1000);
|
|
|
|
|
trainTimer->start();
|
|
|
|
|
//状态控制 0-停止 1启动 2-暂停 3-继续
|
|
|
|
|
m_st_bicycleParam.controlState = 1;
|
|
|
|
|
m_st_bicycleParam.bodyPart = Part; //训练部位 0-上肢 1-下肢 2-四肢 3-垂直上肢
|
2024-12-03 13:41:51 +08:00
|
|
|
|
if(Part == 2)
|
2024-11-28 15:20:18 +08:00
|
|
|
|
{
|
|
|
|
|
m_st_bicycleParam.trainMode = 4;
|
|
|
|
|
}
|
2024-11-29 17:47:45 +08:00
|
|
|
|
else
|
|
|
|
|
{
|
2024-11-28 15:20:18 +08:00
|
|
|
|
m_st_bicycleParam.trainMode = 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
m_st_bicycleParam.trainTime = 99;
|
2024-11-28 13:38:22 +08:00
|
|
|
|
CCommunicateAPI::getInstance()->sendBicycleParam(m_st_bicycleParam);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
void BCIManager::stopTrain()
|
|
|
|
|
{
|
|
|
|
|
if(trainTimer)
|
|
|
|
|
{
|
|
|
|
|
if(trainTimer->isActive())
|
|
|
|
|
{
|
|
|
|
|
trainTimer->stop();
|
|
|
|
|
}
|
|
|
|
|
m_st_bicycleParam.controlState = 0;
|
|
|
|
|
CCommunicateAPI::getInstance()->sendBicycleParam(m_st_bicycleParam);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void BCIManager::pauseTrain()
|
|
|
|
|
{
|
|
|
|
|
if(trainTimer)
|
|
|
|
|
{
|
|
|
|
|
trainTimer->stop();
|
|
|
|
|
m_st_bicycleParam.controlState = 2;
|
|
|
|
|
CCommunicateAPI::getInstance()->sendBicycleParam(m_st_bicycleParam);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void BCIManager::continueTrain()
|
|
|
|
|
{
|
|
|
|
|
if(trainTimer)
|
|
|
|
|
{
|
|
|
|
|
trainTimer->start();
|
|
|
|
|
m_st_bicycleParam.controlState = 3;
|
|
|
|
|
CCommunicateAPI::getInstance()->sendBicycleParam(m_st_bicycleParam);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-12-03 13:41:51 +08:00
|
|
|
|
|
|
|
|
|
void BCIManager::deviceStatus(bool bConnected)
|
|
|
|
|
{
|
|
|
|
|
emit signalDeviceStatus(bConnected);
|
|
|
|
|
}
|
2025-01-05 14:41:32 +08:00
|
|
|
|
|
|
|
|
|
QVariantList BCIManager::getChannels()
|
|
|
|
|
{
|
|
|
|
|
QVariantList lstChannels;
|
|
|
|
|
for(int i = 0; i < m_vecChannels.length(); i++)
|
|
|
|
|
{
|
|
|
|
|
lstChannels.push_back(m_vecChannels.at(i));
|
|
|
|
|
}
|
|
|
|
|
return lstChannels;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString BCIManager::getExe()
|
|
|
|
|
{
|
|
|
|
|
return m_strExe;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString BCIManager::getIp()
|
|
|
|
|
{
|
|
|
|
|
return m_strIp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int BCIManager::getPort()
|
|
|
|
|
{
|
|
|
|
|
return m_nPort;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BCIManager::readConfigFile()
|
|
|
|
|
{
|
|
|
|
|
//文件路径+文件名
|
|
|
|
|
QString fileName = QCoreApplication::applicationDirPath() + "/DevConfig.ini";
|
|
|
|
|
//创建配置目标,输入文件路径,文件格式
|
|
|
|
|
QSettings *setting = new QSettings(fileName, QSettings::IniFormat);
|
|
|
|
|
//设置文件编码,配置文件中使用中文时,这是必须的,否则乱码
|
|
|
|
|
setting->setIniCodec(QTextCodec::codecForName("UTF-8"));
|
|
|
|
|
// 判断文件是否存在
|
|
|
|
|
if(QFile::exists(fileName)) // 文件存在,读出配置项
|
|
|
|
|
{
|
|
|
|
|
// 这里的setting->value的第二参数,是配置项缺省值,即当读取的配置项不存在时,读取该值
|
|
|
|
|
// User是配置组,name和age是配置项
|
|
|
|
|
m_strExe = setting->value("Comm/Exe", "decoder_main.exe").toString();
|
|
|
|
|
m_strIp = setting->value("Comm/Ip", "192.168.1.111").toString();
|
|
|
|
|
m_nPort = setting->value("Comm/Port", 5086).toInt();
|
|
|
|
|
m_vecChannels.push_back(setting->value("Channels/Channel_0", 13).toInt());
|
|
|
|
|
m_vecChannels.push_back(setting->value("Channels/Channel_1", 14).toInt());
|
|
|
|
|
m_vecChannels.push_back(setting->value("Channels/Channel_2", 15).toInt());
|
|
|
|
|
m_vecChannels.push_back(setting->value("Channels/Channel_3", 27).toInt());
|
|
|
|
|
m_vecChannels.push_back(setting->value("Channels/Channel_4", 28).toInt());
|
|
|
|
|
m_vecChannels.push_back(setting->value("Channels/Channel_5", 32).toInt());
|
|
|
|
|
m_vecChannels.push_back(setting->value("Channels/Channel_6", 34).toInt());
|
|
|
|
|
m_vecChannels.push_back(setting->value("Channels/Channel_7", 58).toInt());
|
|
|
|
|
m_nSamplerate = setting->value("Dev/Samplerate", 250).toUInt();
|
|
|
|
|
}
|
|
|
|
|
else // 文件不存在,写入配置项,生成配置文件
|
|
|
|
|
{
|
|
|
|
|
setting->value("Comm/Exe", "decoder_main.exe").toString();
|
|
|
|
|
m_strExe = "decoder_main.exe";
|
|
|
|
|
setting->setValue("Comm/Ip", "192.168.1.111");
|
|
|
|
|
m_strIp = "192.168.1.111";
|
|
|
|
|
setting->setValue("Comm/Port", 5086);
|
|
|
|
|
m_nPort = 5086;
|
|
|
|
|
setting->setValue("Channels/Channel_0", 13);
|
|
|
|
|
m_vecChannels.push_back(13);
|
|
|
|
|
setting->setValue("Channels/Channel_1", 14);
|
|
|
|
|
m_vecChannels.push_back(14);
|
|
|
|
|
setting->setValue("Channels/Channel_2", 15);
|
|
|
|
|
m_vecChannels.push_back(15);
|
|
|
|
|
setting->setValue("Channels/Channel_3", 27);
|
|
|
|
|
m_vecChannels.push_back(27);
|
|
|
|
|
setting->setValue("Channels/Channel_4", 28);
|
|
|
|
|
m_vecChannels.push_back(28);
|
|
|
|
|
setting->setValue("Channels/Channel_5", 32);
|
|
|
|
|
m_vecChannels.push_back(32);
|
|
|
|
|
setting->setValue("Channels/Channel_6", 34);
|
|
|
|
|
m_vecChannels.push_back(34);
|
|
|
|
|
setting->setValue("Channels/Channel_7", 58);
|
|
|
|
|
m_vecChannels.push_back(58);
|
|
|
|
|
setting->setValue("Dev/Samplerate", 250);
|
|
|
|
|
m_nSamplerate = 250;
|
|
|
|
|
setting->sync();
|
|
|
|
|
}
|
|
|
|
|
delete setting;
|
|
|
|
|
}
|