removed PrefixPath debug line
[opentx.git] / companion / src / firmwareinterface.cpp
blob4f11fcbd4316809f0635136add50712249d3a54c
1 /*
2 * Author - Bertrand Songis <bsongis@gmail.com>
3 *
4 * Based on th9x -> http://code.google.com/p/th9x/
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
17 #include <QtGui>
18 #include "hexinterface.h"
19 #include "splash.h"
20 #include "firmwareinterface.h"
21 #include "helpers.h"
23 #define FW_MARK "FW"
24 #define VERS_MARK "VERS"
25 #define DATE_MARK "DATE"
26 #define TIME_MARK "TIME"
27 #define EEPR_MARK "EEPR"
29 int getFileType(const QString &fullFileName)
31 QString suffix = QFileInfo(fullFileName).suffix().toUpper();
32 if (suffix == "HEX")
33 return FILE_TYPE_HEX;
34 else if (suffix == "BIN")
35 return FILE_TYPE_BIN;
36 else if (suffix == "EEPM")
37 return FILE_TYPE_EEPM;
38 else if (suffix == "EEPE")
39 return FILE_TYPE_EEPE;
40 else if (suffix == "XML")
41 return FILE_TYPE_XML;
42 else
43 return 0;
46 FirmwareInterface::FirmwareInterface(const QString &filename):
47 flash(MAX_FSIZE, 0),
48 flashSize(0),
49 versionId(0),
50 eepromVersion(0),
51 eepromVariant(0),
52 splashOffset(0),
53 splashSize(0),
54 splashWidth(0),
55 splashHeight(0),
56 isValidFlag(false)
58 if (!filename.isEmpty()) {
59 QFile file(filename);
60 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { // reading HEX TEXT file
61 QTextStream inputStream(&file);
62 flashSize = HexInterface(inputStream).load((uint8_t *)flash.data(), MAX_FSIZE);
63 file.close();
64 if (flashSize == 0) {
65 file.open(QIODevice::ReadOnly);
66 flashSize = file.read((char *)flash.data(), MAX_FSIZE);
71 if (flashSize > 0) {
72 flavour = seekLabel(FW_MARK);
73 version = seekLabel(VERS_MARK);
74 if (version.startsWith("opentx-")) {
75 // old version format
76 int index = version.lastIndexOf('-');
77 flavour = version.mid(0, index);
78 version = version.mid(index+1);
80 date = seekLabel(DATE_MARK);
81 time = seekLabel(TIME_MARK);
82 eepromId = seekLabel(EEPR_MARK);
84 if (eepromId.contains('-')) {
85 QStringList list = eepromId.split('-');
86 eepromVersion = list[0].toInt();
87 eepromVariant = list[1].toInt();
89 else {
90 eepromVersion = eepromId.toInt();
93 versionId = version2index(version);
94 SeekSplash();
95 isValidFlag = !version.isEmpty();
99 QString FirmwareInterface::seekString(const QString & string)
101 QString result = "";
103 int start = flash.indexOf(string);
104 if (start > 0) {
105 start += string.length();
106 int end = -1;
107 for (int i=start; i<start+50; i++) {
108 char c = flash.at(i);
109 if (c == '\0' || c == '\036') {
110 end = i;
111 break;
114 if (end > 0) {
115 result = flash.mid(start, (end - start)).trimmed();
119 return result;
122 QString FirmwareInterface::seekLabel(const QString & label)
124 QString result = seekString(label + "\037\033:");
125 if (!result.isEmpty())
126 return result;
128 return seekString(label + ":");
131 QString FirmwareInterface::getFlavour() const
133 if (flavour == "opentx-x9dp")
134 return "opentx-taranis-plus";
135 else if (flavour == "opentx-x9d")
136 return "opentx-taranis";
137 else
138 return flavour;
141 bool FirmwareInterface::isHardwareCompatible(const FirmwareInterface &previousFirmware) const
143 QString newFlavour = getFlavour();
144 if (newFlavour.isEmpty())
145 return true;
147 QString previousFlavour = previousFirmware.getFlavour();
148 if (previousFlavour.isEmpty())
149 return true;
151 return (newFlavour == previousFlavour);
154 bool FirmwareInterface::SeekSplash(QByteArray splash)
156 int start = flash.indexOf(splash);
157 if (start>0) {
158 splashOffset = start;
159 splashSize = splash.size();
160 return true;
162 else {
163 return false;
167 bool FirmwareInterface::SeekSplash(QByteArray sps, QByteArray spe, int size)
169 int start = 0;
170 while (start>=0) {
171 start = flash.indexOf(sps, start+1);
172 if (start>0) {
173 int end = start + sps.size() + size;
174 if (end == flash.indexOf(spe, end)) {
175 splashOffset = start + sps.size();
176 splashSize = end - start - sps.size();
177 return true;
179 else {
180 qDebug() << flash.indexOf(spe, start) << end << sps.size() << spe;
184 return false;
187 #define OTX_SPS_9X "SPS\0\200\100"
188 #define OTX_SPS_TARANIS "SPS\0\324\100"
189 #define OTX_SPS_SIZE 6
190 #define OTX_SPE "SPE"
191 #define OTX_SPE_SIZE 4
193 void FirmwareInterface::SeekSplash(void)
195 splashSize = 0;
196 splashOffset = 0;
197 splashWidth = SPLASH_WIDTH;
198 splashHeight = SPLASH_HEIGHT;
199 splash_format = QImage::Format_Mono;
201 if (SeekSplash(QByteArray((const char *)gr9x_splash, sizeof(gr9x_splash))) || SeekSplash(QByteArray((const char *)gr9xv4_splash, sizeof(gr9xv4_splash)))) {
202 return;
205 if (SeekSplash(QByteArray((const char *)er9x_splash, sizeof(er9x_splash)))) {
206 return;
209 if (SeekSplash(QByteArray((const char *)opentx_splash, sizeof(opentx_splash)))) {
210 return;
213 if (SeekSplash(QByteArray((const char *)opentxtaranis_splash, sizeof(opentxtaranis_splash)))) {
214 splashWidth = SPLASHX9D_WIDTH;
215 splashHeight = SPLASHX9D_HEIGHT;
216 splash_format = QImage::Format_Indexed8;
217 return;
220 if (SeekSplash(QByteArray((const char *)ersky9x_splash, sizeof(ersky9x_splash)))) {
221 return;
224 if (SeekSplash(QByteArray(OTX_SPS_9X, OTX_SPS_SIZE), QByteArray(OTX_SPE, OTX_SPE_SIZE), 1024)) {
225 return;
228 if (SeekSplash(QByteArray(OTX_SPS_TARANIS, OTX_SPS_SIZE), QByteArray(OTX_SPE, OTX_SPE_SIZE), 6784)) {
229 splashWidth = SPLASHX9D_WIDTH;
230 splashHeight = SPLASHX9D_HEIGHT;
231 splash_format = QImage::Format_Indexed8;
232 return;
235 if (SeekSplash(QByteArray(ERSKY9X_SPS, sizeof(ERSKY9X_SPS)), QByteArray(ERSKY9X_SPE, sizeof(ERSKY9X_SPE)), 1030)) {
236 return;
239 if (SeekSplash(QByteArray(ERSPLASH_MARKER, sizeof(ERSPLASH_MARKER)))) {
240 splashOffset += sizeof(ERSPLASH_MARKER);
241 splashSize = sizeof(er9x_splash);
245 bool FirmwareInterface::setSplash(const QImage & newsplash)
247 if (splashOffset == 0 || splashSize == 0) {
248 return false;
251 char b[SPLASH_SIZE_MAX] = {0};
252 QColor color;
253 QByteArray splash;
254 if (splash_format == QImage::Format_Indexed8) {
255 for (unsigned int y=0; y<splashHeight; y++) {
256 unsigned int idx = (y/2)*splashWidth;
257 for (unsigned int x=0; x<splashWidth; x++, idx++) {
258 QRgb gray = qGray(newsplash.pixel(x, y));
259 uint8_t z = ((255-gray)*15)/255;
260 if (y & 1) z <<= 4;
261 b[idx] |= z;
265 else {
266 QColor black = QColor(0,0,0);
267 QImage blackNwhite = newsplash.convertToFormat(QImage::Format_MonoLSB);
268 for (uint y=0; y<splashHeight; y++) {
269 for (uint x=0; x<splashWidth; x++) {
270 color = QColor(blackNwhite.pixel(x,y));
271 b[splashWidth*(y/8) + x] |= ((color==black ? 1: 0)<<(y % 8));
275 splash.clear();
276 splash.append(b, splashSize);
277 flash.replace(splashOffset, splashSize, splash);
278 return true;
281 int FirmwareInterface::getSplashWidth()
283 return splashWidth;
286 uint FirmwareInterface::getSplashHeight()
288 return splashHeight;
291 QImage::Format FirmwareInterface::getSplashFormat()
293 return splash_format;
296 QImage FirmwareInterface::getSplash()
298 if (splashOffset == 0 || splashSize == 0) {
299 return QImage(); // empty image
302 if (splash_format == QImage::Format_Indexed8) {
303 QImage image(splashWidth, splashHeight, QImage::Format_RGB888);
304 if (splashOffset > 0) {
305 for (unsigned int y=0; y<splashHeight; y++) {
306 unsigned int idx = (y/2)*splashWidth;
307 for (unsigned int x=0; x<splashWidth; x++, idx++) {
308 uint8_t byte = flash.at(splashOffset+idx);
309 unsigned int z = (y & 1) ? (byte >> 4) : (byte & 0x0F);
310 z = 255-(z*255)/15;
311 QRgb rgb = qRgb(z, z, z);
312 image.setPixel(x, y, rgb);
316 return image;
318 else {
319 QImage image(splashWidth, splashHeight, QImage::Format_Mono);
320 if (splashOffset > 0) {
321 for (unsigned int y=0; y<splashHeight; y++) {
322 for(unsigned int x=0; x<splashWidth; x++) {
323 image.setPixel(x, y, (flash.at(splashOffset+(splashWidth*(y/8)+x)) & (1<<(y % 8))) ? 0 : 1);
327 return image;
331 bool FirmwareInterface::hasSplash()
333 return (splashOffset > 0 ? true : false);
336 bool FirmwareInterface::isValid()
338 return isValidFlag;
341 unsigned int FirmwareInterface::save(QString fileName)
343 uint8_t binflash[MAX_FSIZE];
344 memcpy(&binflash, flash.constData(), flashSize);
345 QFile file(fileName);
347 int fileType = getFileType(fileName);
349 if (fileType == FILE_TYPE_HEX) {
350 if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text)) { //reading HEX TEXT file
351 return -1;
353 QTextStream outputStream(&file);
354 HexInterface hex=HexInterface(outputStream);
355 hex.save(binflash, flashSize);
357 else {
358 if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate)) { //reading HEX TEXT file
359 return -1;
361 file.write((char*)binflash, flashSize);
364 file.close();
366 return flashSize;