diff options
author | Dominik Riebeling <Dominik.Riebeling@gmail.com> | 2021-12-15 21:04:28 +0100 |
---|---|---|
committer | Dominik Riebeling <Dominik.Riebeling@gmail.com> | 2021-12-24 18:05:53 +0100 |
commit | c876d3bbefe0dc00c27ca0c12d29da5874946962 (patch) | |
tree | 69f468a185a369b01998314bc3ecc19b70f4fcaa /utils/rbutilqt/base/autodetection.cpp | |
parent | 6c6f0757d7a902feb293be165d1490c42bc8e7ad (diff) | |
download | rockbox-c876d3bbefe0dc00c27ca0c12d29da5874946962.tar.gz rockbox-c876d3bbefe0dc00c27ca0c12d29da5874946962.zip |
rbutil: Merge rbutil with utils folder.
rbutil uses several components from the utils folder, and can be
considered part of utils too. Having it in a separate folder is an
arbitrary split that doesn't help anymore these days, so merge them.
This also allows other utils to easily use libtools.make without the
need to navigate to a different folder.
Change-Id: I3fc2f4de19e3e776553efb5dea5f779dfec0dc21
Diffstat (limited to 'utils/rbutilqt/base/autodetection.cpp')
-rw-r--r-- | utils/rbutilqt/base/autodetection.cpp | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/utils/rbutilqt/base/autodetection.cpp b/utils/rbutilqt/base/autodetection.cpp new file mode 100644 index 0000000000..341f219c30 --- /dev/null +++ b/utils/rbutilqt/base/autodetection.cpp | |||
@@ -0,0 +1,376 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2007 by Dominik Wenger | ||
10 | * | ||
11 | * All files in this archive are subject to the GNU General Public License. | ||
12 | * See the file COPYING in the source tree root for full license agreement. | ||
13 | * | ||
14 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
15 | * KIND, either express or implied. | ||
16 | * | ||
17 | ****************************************************************************/ | ||
18 | |||
19 | #include <QtCore> | ||
20 | #include "autodetection.h" | ||
21 | #include "rbsettings.h" | ||
22 | #include "playerbuildinfo.h" | ||
23 | |||
24 | #include "../ipodpatcher/ipodpatcher.h" | ||
25 | #include "../sansapatcher/sansapatcher.h" | ||
26 | |||
27 | |||
28 | #include "system.h" | ||
29 | #include "utils.h" | ||
30 | #include "rockboxinfo.h" | ||
31 | #include "Logger.h" | ||
32 | |||
33 | Autodetection::Autodetection(QObject* parent): QObject(parent) | ||
34 | { | ||
35 | } | ||
36 | |||
37 | |||
38 | bool Autodetection::detect(void) | ||
39 | { | ||
40 | QMap<PlayerStatus, QString> states; | ||
41 | states[PlayerOk] = "Ok"; | ||
42 | states[PlayerAmbiguous] = "Ambiguous"; | ||
43 | states[PlayerError] = "Error"; | ||
44 | states[PlayerIncompatible] = "Incompatible"; | ||
45 | states[PlayerMtpMode] = "MtpMode"; | ||
46 | |||
47 | // clear detection state | ||
48 | m_detected.clear(); | ||
49 | |||
50 | detectUsb(); | ||
51 | mergeMounted(); | ||
52 | mergePatcher(); | ||
53 | // if any entry with usbdevices containing a value is left that entry | ||
54 | // hasn't been merged later. This indicates a problem during detection | ||
55 | // (ambiguous player but refining it failed). In this case create an entry | ||
56 | // for eacho of those so the user can select. | ||
57 | QList<struct Detected> detected; | ||
58 | for(int i = 0; i < m_detected.size(); ++i) { | ||
59 | int j = m_detected.at(i).usbdevices.size(); | ||
60 | if(j > 0) { | ||
61 | struct Detected entry = m_detected.at(i); | ||
62 | while(j--) { | ||
63 | struct Detected d; | ||
64 | d.device = entry.usbdevices.at(j); | ||
65 | d.mountpoint = entry.mountpoint; | ||
66 | d.status = PlayerAmbiguous; | ||
67 | detected.append(d); | ||
68 | } | ||
69 | } | ||
70 | else { | ||
71 | detected.append(m_detected.at(i)); | ||
72 | } | ||
73 | } | ||
74 | m_detected = detected; | ||
75 | for(int i = 0; i < m_detected.size(); ++i) { | ||
76 | LOG_INFO() << "Detected player:" << m_detected.at(i).device | ||
77 | << "at" << m_detected.at(i).mountpoint | ||
78 | << states[m_detected.at(i).status]; | ||
79 | } | ||
80 | |||
81 | return m_detected.size() > 0; | ||
82 | } | ||
83 | |||
84 | |||
85 | /** @brief detect devices based on usb pid / vid. | ||
86 | */ | ||
87 | void Autodetection::detectUsb() | ||
88 | { | ||
89 | // usb pid detection | ||
90 | QList<uint32_t> attached; | ||
91 | attached = System::listUsbIds(); | ||
92 | |||
93 | int i = attached.size(); | ||
94 | while(i--) { | ||
95 | QStringList a = PlayerBuildInfo::instance()->value(PlayerBuildInfo::UsbIdTargetList, attached.at(i)).toStringList(); | ||
96 | if(a.size() > 0) { | ||
97 | struct Detected d; | ||
98 | d.status = PlayerOk; | ||
99 | d.usbdevices = a; | ||
100 | m_detected.append(d); | ||
101 | LOG_INFO() << "[USB] detected supported player" << d.usbdevices; | ||
102 | } | ||
103 | QStringList b = PlayerBuildInfo::instance()->value(PlayerBuildInfo::UsbIdErrorList, attached.at(i)).toStringList(); | ||
104 | if(b.size() > 0) { | ||
105 | struct Detected d; | ||
106 | d.status = PlayerMtpMode; | ||
107 | d.usbdevices = b; | ||
108 | m_detected.append(d); | ||
109 | LOG_WARNING() << "[USB] detected problem with player" << d.device; | ||
110 | } | ||
111 | QString idstring = QString("%1").arg(attached.at(i), 8, 16, QChar('0')); | ||
112 | if(!PlayerBuildInfo::instance()->value( | ||
113 | PlayerBuildInfo::DisplayName, idstring).toString().isEmpty()) { | ||
114 | struct Detected d; | ||
115 | d.status = PlayerIncompatible; | ||
116 | d.device = idstring; | ||
117 | m_detected.append(d); | ||
118 | LOG_WARNING() << "[USB] detected incompatible player" << d.device; | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | |||
123 | |||
124 | // Merge players detected by checking mounted filesystems for known files: | ||
125 | // - rockbox-info.txt / rbutil.log | ||
126 | // - player specific files | ||
127 | void Autodetection::mergeMounted(void) | ||
128 | { | ||
129 | QStringList mounts = Utils::mountpoints(Utils::MountpointsSupported); | ||
130 | LOG_INFO() << "paths to check:" << mounts; | ||
131 | |||
132 | for(int i = 0; i < mounts.size(); i++) | ||
133 | { | ||
134 | // do the file checking | ||
135 | QDir dir(mounts.at(i)); | ||
136 | if(dir.exists()) | ||
137 | { | ||
138 | // check logfile first. | ||
139 | if(QFile(mounts.at(i) + "/.rockbox/rbutil.log").exists()) { | ||
140 | QSettings log(mounts.at(i) + "/.rockbox/rbutil.log", | ||
141 | QSettings::IniFormat, this); | ||
142 | if(!log.value("platform").toString().isEmpty()) { | ||
143 | struct Detected d; | ||
144 | d.device = log.value("platform").toString(); | ||
145 | d.mountpoint = mounts.at(i); | ||
146 | d.status = PlayerOk; | ||
147 | updateDetectedDevice(d); | ||
148 | LOG_INFO() << "rbutil.log detected:" | ||
149 | << log.value("platform").toString() << mounts.at(i); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | // check rockbox-info.txt afterwards. | ||
154 | RockboxInfo info(mounts.at(i)); | ||
155 | if(info.success()) | ||
156 | { | ||
157 | struct Detected d; | ||
158 | d.device = info.target(); | ||
159 | d.mountpoint = mounts.at(i); | ||
160 | d.status = PlayerOk; | ||
161 | updateDetectedDevice(d); | ||
162 | LOG_INFO() << "rockbox-info.txt detected:" | ||
163 | << info.target() << mounts.at(i); | ||
164 | } | ||
165 | |||
166 | // check for some specific files in root folder | ||
167 | QDir root(mounts.at(i)); | ||
168 | QStringList rootentries = root.entryList(QDir::Files); | ||
169 | if(rootentries.contains("archos.mod", Qt::CaseInsensitive)) | ||
170 | { | ||
171 | // archos.mod in root folder -> Archos Player | ||
172 | struct Detected d; | ||
173 | d.device = "player"; | ||
174 | d.mountpoint = mounts.at(i); | ||
175 | d.status = PlayerOk; | ||
176 | updateDetectedDevice(d); | ||
177 | } | ||
178 | if(rootentries.contains("ONDIOST.BIN", Qt::CaseInsensitive)) | ||
179 | { | ||
180 | // ONDIOST.BIN in root -> Ondio FM | ||
181 | struct Detected d; | ||
182 | d.device = "ondiofm"; | ||
183 | d.mountpoint = mounts.at(i); | ||
184 | d.status = PlayerOk; | ||
185 | updateDetectedDevice(d); | ||
186 | } | ||
187 | if(rootentries.contains("ONDIOSP.BIN", Qt::CaseInsensitive)) | ||
188 | { | ||
189 | // ONDIOSP.BIN in root -> Ondio SP | ||
190 | struct Detected d; | ||
191 | d.device = "ondiosp"; | ||
192 | d.mountpoint = mounts.at(i); | ||
193 | d.status = PlayerOk; | ||
194 | updateDetectedDevice(d); | ||
195 | } | ||
196 | if(rootentries.contains("ajbrec.ajz", Qt::CaseInsensitive)) | ||
197 | { | ||
198 | LOG_INFO() << "ajbrec.ajz found. Trying detectAjbrec()"; | ||
199 | struct Detected d; | ||
200 | d.device = detectAjbrec(mounts.at(i)); | ||
201 | d.mountpoint = mounts.at(i); | ||
202 | d.status = PlayerOk; | ||
203 | if(!d.device.isEmpty()) { | ||
204 | LOG_INFO() << d.device; | ||
205 | updateDetectedDevice(d); | ||
206 | } | ||
207 | } | ||
208 | // detection based on player specific folders | ||
209 | QStringList rootfolders = root.entryList(QDir::Dirs | ||
210 | | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System); | ||
211 | if(rootfolders.contains("GBSYSTEM", Qt::CaseInsensitive)) | ||
212 | { | ||
213 | // GBSYSTEM folder -> Gigabeat | ||
214 | struct Detected d; | ||
215 | d.device = "gigabeatf"; | ||
216 | d.mountpoint = mounts.at(i); | ||
217 | updateDetectedDevice(d); | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | #if 0 | ||
222 | // Ipods have a folder "iPod_Control" in the root. | ||
223 | for(int i = 0; i < m_detected.size(); ++i) { | ||
224 | struct Detected entry = m_detected.at(i); | ||
225 | for(int j = 0; j < entry.usbdevices.size(); ++j) { | ||
226 | // limit this to Ipods only. | ||
227 | if(!entry.usbdevices.at(j).startsWith("ipod") | ||
228 | && !entry.device.startsWith("ipod")) { | ||
229 | continue; | ||
230 | } | ||
231 | // look for iPod_Control on all supported volumes. | ||
232 | for(int k = 0; k < mounts.size(); k++) { | ||
233 | QDir root(mounts.at(k)); | ||
234 | QStringList rootfolders = root.entryList(QDir::Dirs | ||
235 | | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System); | ||
236 | if(rootfolders.contains("iPod_Control", Qt::CaseInsensitive)) { | ||
237 | entry.mountpoint = mounts.at(k); | ||
238 | m_detected.takeAt(i); | ||
239 | m_detected.append(entry); | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | } | ||
244 | #endif | ||
245 | |||
246 | } | ||
247 | |||
248 | |||
249 | void Autodetection::mergePatcher(void) | ||
250 | { | ||
251 | int n; | ||
252 | // try ipodpatcher | ||
253 | // initialize sector buffer. Needed. | ||
254 | struct ipod_t ipod; | ||
255 | ipod.sectorbuf = nullptr; | ||
256 | ipod_alloc_buffer(&ipod, BUFFER_SIZE); | ||
257 | n = ipod_scan(&ipod); | ||
258 | // FIXME: handle more than one Ipod connected in ipodpatcher. | ||
259 | if(n == 1) { | ||
260 | LOG_INFO() << "Ipod found:" << ipod.modelstr << "at" << ipod.diskname; | ||
261 | // since resolveMountPoint is doing exact matches we need to select | ||
262 | // the correct partition. | ||
263 | QString mp(ipod.diskname); | ||
264 | #ifdef Q_OS_LINUX | ||
265 | mp.append("2"); | ||
266 | #endif | ||
267 | #ifdef Q_OS_MACX | ||
268 | mp.append("s2"); | ||
269 | #endif | ||
270 | struct Detected d; | ||
271 | d.device = ipod.targetname; | ||
272 | d.mountpoint = Utils::resolveMountPoint(mp); | ||
273 | // if the found ipod is a macpod also notice it as device with problem. | ||
274 | if(ipod.macpod) | ||
275 | d.status = PlayerWrongFilesystem; | ||
276 | else | ||
277 | d.status = PlayerOk; | ||
278 | updateDetectedDevice(d); | ||
279 | } | ||
280 | else { | ||
281 | LOG_INFO() << "ipodpatcher: no Ipod found." << n; | ||
282 | } | ||
283 | ipod_dealloc_buffer(&ipod); | ||
284 | |||
285 | // try sansapatcher | ||
286 | // initialize sector buffer. Needed. | ||
287 | struct sansa_t sansa; | ||
288 | sansa_alloc_buffer(&sansa, BUFFER_SIZE); | ||
289 | n = sansa_scan(&sansa); | ||
290 | if(n == 1) { | ||
291 | LOG_INFO() << "Sansa found:" | ||
292 | << sansa.targetname << "at" << sansa.diskname; | ||
293 | QString mp(sansa.diskname); | ||
294 | #ifdef Q_OS_LINUX | ||
295 | mp.append("1"); | ||
296 | #endif | ||
297 | #ifdef Q_OS_MACX | ||
298 | mp.append("s1"); | ||
299 | #endif | ||
300 | struct Detected d; | ||
301 | d.device = QString("sansa%1").arg(sansa.targetname); | ||
302 | d.mountpoint = Utils::resolveMountPoint(mp); | ||
303 | d.status = PlayerOk; | ||
304 | updateDetectedDevice(d); | ||
305 | } | ||
306 | else { | ||
307 | LOG_INFO() << "sansapatcher: no Sansa found." << n; | ||
308 | } | ||
309 | sansa_dealloc_buffer(&sansa); | ||
310 | } | ||
311 | |||
312 | |||
313 | QString Autodetection::detectAjbrec(QString root) | ||
314 | { | ||
315 | QFile f(root + "/ajbrec.ajz"); | ||
316 | char header[24]; | ||
317 | f.open(QIODevice::ReadOnly); | ||
318 | if(!f.read(header, 24)) return QString(); | ||
319 | f.close(); | ||
320 | |||
321 | // check the header of the file. | ||
322 | // recorder v1 had a 6 bytes sized header | ||
323 | // recorder v2, FM, Ondio SP and FM have a 24 bytes header. | ||
324 | |||
325 | // recorder v1 has the binary length in the first 4 bytes, so check | ||
326 | // for them first. | ||
327 | int len = (header[0]<<24) | (header[1]<<16) | (header[2]<<8) | header[3]; | ||
328 | LOG_INFO() << "abjrec.ajz possible bin length:" << len | ||
329 | << "file len:" << f.size(); | ||
330 | if((f.size() - 6) == len) | ||
331 | return "recorder"; | ||
332 | |||
333 | // size didn't match, now we need to assume we have a headerlength of 24. | ||
334 | switch(header[11]) { | ||
335 | case 2: | ||
336 | return "recorderv2"; | ||
337 | case 4: | ||
338 | return "fmrecorder"; | ||
339 | case 8: | ||
340 | return "ondiofm"; | ||
341 | case 16: | ||
342 | return "ondiosp"; | ||
343 | default: | ||
344 | break; | ||
345 | } | ||
346 | return QString(); | ||
347 | } | ||
348 | |||
349 | |||
350 | int Autodetection::findDetectedDevice(QString device) | ||
351 | { | ||
352 | int i = m_detected.size(); | ||
353 | while(i--) { | ||
354 | if(m_detected.at(i).usbdevices.contains(device)) | ||
355 | return i; | ||
356 | } | ||
357 | i = m_detected.size(); | ||
358 | while(i--) { | ||
359 | if(m_detected.at(i).device == device) | ||
360 | return i; | ||
361 | } | ||
362 | return -1; | ||
363 | } | ||
364 | |||
365 | |||
366 | void Autodetection::updateDetectedDevice(Detected& entry) | ||
367 | { | ||
368 | int index = findDetectedDevice(entry.device); | ||
369 | if(index < 0) { | ||
370 | m_detected.append(entry); | ||
371 | } | ||
372 | else { | ||
373 | m_detected.takeAt(index); | ||
374 | m_detected.append(entry); | ||
375 | } | ||
376 | } | ||