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