ckb-next  v0.2.8 at branch master
ckb-next driver for corsair devices
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
fwupgradedialog.cpp
Go to the documentation of this file.
1 #include <QDir>
2 #include <QMessageBox>
3 #include "fwupgradedialog.h"
4 #include "kbfirmware.h"
5 #include "ui_fwupgradedialog.h"
6 
7 // IDs for verifying firmware suitability
8 struct KbId {
9  short vendor;
10  short product;
11  const char* feature;
12 };
13 
14 static KbId ids[] = {
15  // Keyboards
16  { 0x1b1c, 0x1b17, "corsair k65 rgb" },
17  { 0x1b1c, 0x1b3f, "corsair k68" },
18  { 0x1b1c, 0x1b13, "corsair k70 rgb" },
19  { 0x1b1c, 0x1b11, "corsair k95 rgb" },
20  { 0x1b1c, 0x1b15, "corsair strafe monochrome" },
21  { 0x1b1c, 0x1b20, "corsair strafe rgb" },
22  // Mice
23  { 0x1b1c, 0x1b12, "corsair m65 rgb" },
24  { 0x1b1c, 0x1b1e, "corsair scimitar rgb" },
25  //SABRE CH-9000111-EU
26  { 0x1b1c, 0x1b32, "corsair sabre optical rgb" }
27 };
28 
29 static const int DIALOG_WIDTH = 420;
30 static const int DIALOG_HEIGHT_MIN = 200, DIALOG_HEIGHT_MAX(240);
31 
32 FwUpgradeDialog::FwUpgradeDialog(QWidget* parent, float newV, const QByteArray& fwBlob, Kb* device) :
33  QDialog(parent),
34  ui(new Ui::FwUpgradeDialog),
35  blob(fwBlob), kb(device), evLoop(0), exitSuccess(true)
36 {
37  ui->setupUi(this);
38  ui->curLabel->setText(kb->firmware);
39  ui->newLabel->setText(QString::number(newV, 'f', 2));
40  ui->devLabel->setText(kb->usbModel);
41 
42  connect(device, SIGNAL(destroyed()), this, SLOT(removeDev()));
43  connect(device, SIGNAL(fwUpdateProgress(int,int)), this, SLOT(fwUpdateProgress(int,int)));
44  connect(device, SIGNAL(fwUpdateFinished(bool)), this, SLOT(fwUpdateFinished(bool)));
45 
46  setFixedSize(DIALOG_WIDTH, DIALOG_HEIGHT_MIN);
47 }
48 
50  cleanBlob();
51  delete ui;
52 }
53 
54 void FwUpgradeDialog::closeEvent(QCloseEvent* event){
55  event->ignore();
56 }
57 
58 const QString& FwUpgradeDialog::saveBlob(){
59  if(!savePath.isEmpty())
60  return savePath;
61  QDir tmp = QDir::temp();
62  qint64 pid = QCoreApplication::applicationPid();
63  QString path = tmp.absoluteFilePath(QString("ckb-%1-fwblob.bin").arg(pid));
64  QFile output(path);
65  if(!output.open(QIODevice::WriteOnly)){
66  return savePath;
67  }
68  if(!output.write(blob)){
69  output.close();
70  tmp.remove(path);
71  return savePath;
72  }
73  output.close();
74  savePath = path;
75  return savePath;
76 }
77 
79  if(savePath.isEmpty())
80  return;
81  QFile(savePath).remove();
82  savePath = "";
83 }
84 
85 // Returns firmware version if valid for device, 0 if invalid
86 static float verifyFw(const QByteArray& blob, const QString& features){
87  if(blob.length() < 0x0108)
88  return 0.f;
89  const char* bData = blob.data();
90  // Make sure it matches this device based on the vendor and product IDs embedded in the blob
91  bool match = false;
92  for(uint i = 0; i < sizeof(ids)/sizeof(KbId); i++){
93  if(!memcmp(&ids[i].vendor, bData + 0x102, 2) && !memcmp(&ids[i].product, bData + 0x104, 2)
94  && features.startsWith(ids[i].feature, Qt::CaseInsensitive)){
95  match = true;
96  break;
97  }
98  }
99  if(!match)
100  return 0.f;
101  // Copy the version from the blob
102  short version;
103  memcpy(&version, bData + 0x106, 2);
104  // Un-hexify it
105  return QString::number(version, 16).toFloat() / 100.f;
106 }
107 
109  QString features = kb->features;
110  if(!blob.isEmpty()){
111  // If a blob was already specified, check its version and validity
112  float newV = verifyFw(blob, features);
113  if(newV == 0.f){
114  QMessageBox::warning(parentWidget(), "Error", "<center>Not a valid firmware for this device.</center>");
115  return QDialog::Rejected;
116  }
117  ui->newLabel->setText(QString::number(newV, 'f', 2));
118  } else {
119  // Download a new blob file
120  ui->progressBar->show();
121  ui->cancelButton->setEnabled(false);
122  ui->actionButton->setEnabled(false);
123  show();
124  // This can take a while
125  blob = KbFirmware::dataForBoard(features);
126  // Check validity
127  float newV = verifyFw(blob, features);
128  if(newV == 0.f){
129  hide();
130  QMessageBox::warning(parentWidget(), "Error", "<center>There was a problem with the downloaded file.<br />Please try again later.</center>");
131  return QDialog::Rejected;
132  }
133  }
134  // Save temporary file
135  if(saveBlob().isEmpty()){
136  hide();
137  QMessageBox::warning(parentWidget(), "Error", "<center>Unable to save temporary file.</center>");
138  return QDialog::Rejected;
139  }
140  // Set up UI
141  ui->progressBar->setValue(0);
142  ui->progressBar->setMaximum(1);
143  ui->progressBar->setTextVisible(false);
144  ui->statusLabel->setText("Ready to install new firmware.<br /><br /><b>Disclaimer:</b> ckb-next is not endorsed by Corsair.<br />This is <i>unlikely</i> to cause any damage, however the developers of this software do not accept any responsibility in such an event.");
145  ui->cancelButton->setEnabled(true);
146  ui->actionButton->setEnabled(true);
147  setFixedSize(DIALOG_WIDTH, DIALOG_HEIGHT_MAX);
148  show();
149  // Run modal event loop
150  evLoop = new QEventLoop(this);
151  evLoop->exec();
152  delete evLoop;
153  hide();
154  return exitSuccess ? QDialog::Accepted : QDialog::Rejected;
155 }
156 
158  kb = 0;
159  // Assume success if upgrade in progress
160  if(!savePath.isEmpty())
161  fwUpdateFinished(true);
162 }
163 
165  if(current > 0 && total > 0){
166  ui->progressBar->setMaximum(total);
167  ui->progressBar->setValue(current);
168  }
169 }
170 
172  cleanBlob();
173  if(succeeded)
174  ui->statusLabel->setText("Update successful!");
175  else
176  ui->statusLabel->setText("Update failed.");
177  ui->actionButton->setText("OK");
178  ui->actionButton->setEnabled(true);
179  ui->progressBar->setMaximum(1);
180  ui->progressBar->setValue(1);
181  // Exit after 10s
182  if(evLoop)
183  QTimer::singleShot(10000, evLoop, SLOT(quit()));
184 }
185 
187  exitSuccess = false;
188  if(evLoop)
189  evLoop->quit();
190 }
191 
193  if(!savePath.isEmpty() && kb){
194  // Start upgrade
195  setFixedSize(DIALOG_WIDTH, DIALOG_HEIGHT_MIN);
196  ui->progressBar->show();
197  ui->progressBar->setValue(0);
198  ui->progressBar->setMaximum(0);
199  ui->progressBar->setTextVisible(true);
200  ui->cancelButton->hide();
201  ui->actionButton->setEnabled(false);
202  ui->actionButton->setText("Please wait");
203  ui->statusLabel->setText("Installing firmware...");
204  kb->fwUpdate(savePath);
205  } else {
206  // Finished, close dialog.
207  if(evLoop)
208  evLoop->quit();
209  }
210 }
rgb * current
Definition: main.c:46
void fwUpdateFinished(bool succeeded)
short vendor
QPushButton * cancelButton
static void quit()
quit Stop working the daemon. function is called if the daemon received a sigterm In this case...
Definition: main.c:30
static QByteArray dataForBoard(const QString &features)
Definition: kbfirmware.h:25
void on_cancelButton_clicked()
QString firmware
Definition: kb.h:18
static const int DIALOG_HEIGHT_MAX(240)
QPushButton * actionButton
void closeEvent(QCloseEvent *event)
void fwUpdate(const QString &path)
Definition: kb.cpp:365
Definition: kb.h:11
const QString & saveBlob()
void on_actionButton_clicked()
QProgressBar * progressBar
QString usbModel
Definition: kb.h:16
QEventLoop * evLoop
static KbId ids[]
QString features
Definition: kb.h:18
void fwUpdateProgress(int current, int total)
static const int DIALOG_WIDTH
static float verifyFw(const QByteArray &blob, const QString &features)
Ui::FwUpgradeDialog * ui
short product
const char * feature
static const int DIALOG_HEIGHT_MIN
void setupUi(QDialog *FwUpgradeDialog)
FwUpgradeDialog(QWidget *parent, float newV, const QByteArray &fwBlob, Kb *device)