Universal Blood Pressure Manager: manage your blood pressure data on Windows/Linux/macOS, view/print/mail as chart/table/statistics, analyze via SQL queries, import/export data as CSV/JSON/XML/SQL and much more…
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.
 
 
 
 
 

255 lines
5.9 KiB

#include "DialogImport.h"
DialogImport::DialogImport(QWidget *parent, QString theme, QVector <struct HEALTHDATA> *user1, QVector <struct HEALTHDATA> *user2, struct SETTINGS *psettings) : QDialog(parent)
{
u1 = user1;
u2 = user2;
settings = psettings;
setStyleSheet(theme);
setupUi(this);
resize(0, 0);
layout()->setSizeConstraint(QLayout::SetFixedSize);
setWindowTitle(MODEL);
checkBox_auto_import->setChecked(settings->plugin.import);
toolButton->setChecked(settings->plugin.logging);
hid_init();
if((hid = hid_open(VID, PID, nullptr)))
{
wchar_t manufacturer[255], product[255], serial[255];
hid_get_manufacturer_string(hid, manufacturer, 255);
hid_get_product_string(hid, product, 255);
hid_get_serial_number_string(hid, serial, 255);
label_producer->setText(QString::fromWCharArray(manufacturer));
label_product->setText(QString::fromWCharArray(product));
label_serial->setText(QString::fromWCharArray(serial));
}
else
{
hid_exit();
QMessageBox::critical(nullptr, MODEL, tr("Could not open usb device %1:%2.").arg(VID, 4, 16, QChar('0')).arg(PID, 4, 16, QChar('0')));
failed = true;
return;
}
log.setFileName(LOGFILE);
if(settings->plugin.import)
{
QTimer::singleShot(100, this, &DialogImport::on_pushButton_import_clicked);
}
}
int DialogImport::sendCMD(quint8 *cmd)
{
int bytes;
bytes = hid_write(hid, cmd, 1 + cmd[1]);
logRawData(true, bytes, cmd);
bytes = hid_read_timeout(hid, rawdata, 64, 1000);
logRawData(false, bytes, rawdata);
return bytes;
}
int DialogImport::buildCRC(quint8* data)
{
int crc = 0;
int len = data[1];
while(--len)
{
crc ^= data[len];
}
return crc;
}
void DialogImport::decryptPayload()
{
HEALTHDATA record;
int user1 = 0;
int user2 = 0;
for(int i = 0; i < 14*MEMORY; i += 14) // fixme: get real count of measurements?
{
if((quint8(payload[i]) != 0xFF) & (quint8(payload[i + 1]) != 0xFF) && (quint8(payload[i + 2]) != 0xFF))
{
user1++;
}
if((quint8(payload[i + 14*MEMORY]) != 0xFF) & (quint8(payload[i + 1 + 14*MEMORY]) != 0xFF) && (quint8(payload[i + 2 + 14*MEMORY]) != 0xFF))
{
user2++;
}
}
for(int i = 0; i < 14*user1; i += 14)
{
record.dts = QDateTime(QDate(2000 + quint8(payload[i + 2]), (quint8(payload[i + 4])>>2) & 0x0F, ((quint8(payload[i + 4])<<8 | quint8(payload[i + 5]))>>5) & 0x1F), QTime(quint8(payload[i + 5]) & 0x1F, ((quint8(payload[i + 6])<<8 | quint8(payload[i + 7]))>>6) & 0x3F, quint8(payload[i + 7]) & 0x3F)).toMSecsSinceEpoch();
record.sys = quint8(payload[i + 1]) + 25;
record.dia = quint8(payload[i]);
record.bpm = quint8(payload[i + 3]);
record.ihb = (quint8(payload[i + 4])>>6) & 0x01;
record.mov = quint8(payload[i + 4])>>7;
record.inv = false;
record.msg = "";
u1->append(record);
}
for(int i = 0; i < 14*user2; i += 14)
{
record.dts = QDateTime(QDate(2000 + quint8(payload[i + 2 + 14*MEMORY]), (quint8(payload[i + 4 + 14*MEMORY])>>2) & 0x0F, ((quint8(payload[i + 4 + 14*MEMORY])<<8 | quint8(payload[i + 5 + 14*MEMORY]))>>5) & 0x1F), QTime(quint8(payload[i + 5 + 14*MEMORY]) & 0x1F, ((quint8(payload[i + 6 + 14*MEMORY])<<8 | quint8(payload[i + 7 + 14*MEMORY]))>>6) & 0x3F, quint8(payload[i + 7 + 14*MEMORY]) & 0x3F)).toMSecsSinceEpoch();
record.sys = quint8(payload[i + 1 + 14*MEMORY]) + 25;
record.dia = quint8(payload[i + 14*MEMORY]);
record.bpm = quint8(payload[i + 3 + 14*MEMORY]);
record.ihb = (quint8(payload[i + 4 + 14*MEMORY])>>6) & 0x01;
record.mov = quint8(payload[i + 4 + 14*MEMORY])>>7;
record.inv = false;
record.msg = "";
u2->append(record);
}
}
void DialogImport::logRawData(bool direction, int bytes, quint8* data)
{
if(log.isOpen())
{
log.write(QString("%1 %2 : ").arg(direction ? "->" : "<-").arg((bytes ? 1 + data[1] : 0), 2, 10, QChar('0')).toUtf8());
if(bytes)
{
log.write(QByteArray(reinterpret_cast<char*>(data), 1 + data[1]).toHex(' ').toUpper());
}
else
{
log.write(QString("Error!").toUtf8());
}
log.write("\n");
}
}
void DialogImport::on_checkBox_auto_import_toggled(bool state)
{
settings->plugin.import = state;
}
void DialogImport::on_toolButton_toggled(bool state)
{
settings->plugin.logging = state;
}
void DialogImport::on_pushButton_import_clicked()
{
quint16 addr = 0x02AC;
pushButton_import->setDisabled(true);
pushButton_cancel->setEnabled(true);
if(toolButton->isChecked())
{
if(!log.isOpen())
{
if(log.open(QIODevice::WriteOnly))
{
log.write(QString("%1\n\n Producer : %2\n Product : %3\n Serial : %4\n\n").arg(MODEL, label_producer->text(), label_product->text(), label_serial->text()).toUtf8());
}
else
{
QMessageBox::critical(this, MODEL, tr("Could not open the logfile %1.\n\n%2").arg(log.fileName(), log.errorString()));
}
}
}
if(!sendCMD(cmd_init))
{
pushButton_import->setEnabled(true);
pushButton_cancel->setDisabled(true);
QMessageBox::warning(this, MODEL, tr("Press START/STOP on device and try again…"));
return;
}
finished = false;
for(int i = 0; i < 2*14*MEMORY / 40; i++)
{
QGuiApplication::processEvents();
if(abort)
{
sendCMD(cmd_fail);
QMessageBox::warning(this, MODEL, tr("Import aborted by user."));
done(QDialog::Rejected);
return;
}
cmd_data[4] = addr >> 8;
cmd_data[5] = addr & 0xFF;
cmd_data[8] = buildCRC(cmd_data);
sendCMD(cmd_data);
payload.append(reinterpret_cast<char*>(&rawdata[7]), 40);
progressBar->setValue((i+1)*100 / (2*14*MEMORY / 40));
addr += 40;
}
finished = true;
sendCMD(cmd_done);
decryptPayload();
done(QDialog::Accepted);
}
void DialogImport::on_pushButton_cancel_clicked()
{
if(QMessageBox::question(this, MODEL, tr("Really abort import?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)
{
finished = true;
abort = true;
}
}
void DialogImport::reject()
{
if(!finished)
{
QMessageBox::warning(this, MODEL, tr("Import in progress…"));
return;
}
hid_close(hid);
hid_exit();
log.close();
QDialog::reject();
}