From c876d3bbefe0dc00c27ca0c12d29da5874946962 Mon Sep 17 00:00:00 2001 From: Dominik Riebeling Date: Wed, 15 Dec 2021 21:04:28 +0100 Subject: 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 --- utils/rbutilqt/base/autodetection.cpp | 376 ++++++++++++++++++++++++++++++++++ 1 file changed, 376 insertions(+) create mode 100644 utils/rbutilqt/base/autodetection.cpp (limited to 'utils/rbutilqt/base/autodetection.cpp') 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 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2007 by Dominik Wenger + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include "autodetection.h" +#include "rbsettings.h" +#include "playerbuildinfo.h" + +#include "../ipodpatcher/ipodpatcher.h" +#include "../sansapatcher/sansapatcher.h" + + +#include "system.h" +#include "utils.h" +#include "rockboxinfo.h" +#include "Logger.h" + +Autodetection::Autodetection(QObject* parent): QObject(parent) +{ +} + + +bool Autodetection::detect(void) +{ + QMap states; + states[PlayerOk] = "Ok"; + states[PlayerAmbiguous] = "Ambiguous"; + states[PlayerError] = "Error"; + states[PlayerIncompatible] = "Incompatible"; + states[PlayerMtpMode] = "MtpMode"; + + // clear detection state + m_detected.clear(); + + detectUsb(); + mergeMounted(); + mergePatcher(); + // if any entry with usbdevices containing a value is left that entry + // hasn't been merged later. This indicates a problem during detection + // (ambiguous player but refining it failed). In this case create an entry + // for eacho of those so the user can select. + QList detected; + for(int i = 0; i < m_detected.size(); ++i) { + int j = m_detected.at(i).usbdevices.size(); + if(j > 0) { + struct Detected entry = m_detected.at(i); + while(j--) { + struct Detected d; + d.device = entry.usbdevices.at(j); + d.mountpoint = entry.mountpoint; + d.status = PlayerAmbiguous; + detected.append(d); + } + } + else { + detected.append(m_detected.at(i)); + } + } + m_detected = detected; + for(int i = 0; i < m_detected.size(); ++i) { + LOG_INFO() << "Detected player:" << m_detected.at(i).device + << "at" << m_detected.at(i).mountpoint + << states[m_detected.at(i).status]; + } + + return m_detected.size() > 0; +} + + +/** @brief detect devices based on usb pid / vid. + */ +void Autodetection::detectUsb() +{ + // usb pid detection + QList attached; + attached = System::listUsbIds(); + + int i = attached.size(); + while(i--) { + QStringList a = PlayerBuildInfo::instance()->value(PlayerBuildInfo::UsbIdTargetList, attached.at(i)).toStringList(); + if(a.size() > 0) { + struct Detected d; + d.status = PlayerOk; + d.usbdevices = a; + m_detected.append(d); + LOG_INFO() << "[USB] detected supported player" << d.usbdevices; + } + QStringList b = PlayerBuildInfo::instance()->value(PlayerBuildInfo::UsbIdErrorList, attached.at(i)).toStringList(); + if(b.size() > 0) { + struct Detected d; + d.status = PlayerMtpMode; + d.usbdevices = b; + m_detected.append(d); + LOG_WARNING() << "[USB] detected problem with player" << d.device; + } + QString idstring = QString("%1").arg(attached.at(i), 8, 16, QChar('0')); + if(!PlayerBuildInfo::instance()->value( + PlayerBuildInfo::DisplayName, idstring).toString().isEmpty()) { + struct Detected d; + d.status = PlayerIncompatible; + d.device = idstring; + m_detected.append(d); + LOG_WARNING() << "[USB] detected incompatible player" << d.device; + } + } +} + + +// Merge players detected by checking mounted filesystems for known files: +// - rockbox-info.txt / rbutil.log +// - player specific files +void Autodetection::mergeMounted(void) +{ + QStringList mounts = Utils::mountpoints(Utils::MountpointsSupported); + LOG_INFO() << "paths to check:" << mounts; + + for(int i = 0; i < mounts.size(); i++) + { + // do the file checking + QDir dir(mounts.at(i)); + if(dir.exists()) + { + // check logfile first. + if(QFile(mounts.at(i) + "/.rockbox/rbutil.log").exists()) { + QSettings log(mounts.at(i) + "/.rockbox/rbutil.log", + QSettings::IniFormat, this); + if(!log.value("platform").toString().isEmpty()) { + struct Detected d; + d.device = log.value("platform").toString(); + d.mountpoint = mounts.at(i); + d.status = PlayerOk; + updateDetectedDevice(d); + LOG_INFO() << "rbutil.log detected:" + << log.value("platform").toString() << mounts.at(i); + } + } + + // check rockbox-info.txt afterwards. + RockboxInfo info(mounts.at(i)); + if(info.success()) + { + struct Detected d; + d.device = info.target(); + d.mountpoint = mounts.at(i); + d.status = PlayerOk; + updateDetectedDevice(d); + LOG_INFO() << "rockbox-info.txt detected:" + << info.target() << mounts.at(i); + } + + // check for some specific files in root folder + QDir root(mounts.at(i)); + QStringList rootentries = root.entryList(QDir::Files); + if(rootentries.contains("archos.mod", Qt::CaseInsensitive)) + { + // archos.mod in root folder -> Archos Player + struct Detected d; + d.device = "player"; + d.mountpoint = mounts.at(i); + d.status = PlayerOk; + updateDetectedDevice(d); + } + if(rootentries.contains("ONDIOST.BIN", Qt::CaseInsensitive)) + { + // ONDIOST.BIN in root -> Ondio FM + struct Detected d; + d.device = "ondiofm"; + d.mountpoint = mounts.at(i); + d.status = PlayerOk; + updateDetectedDevice(d); + } + if(rootentries.contains("ONDIOSP.BIN", Qt::CaseInsensitive)) + { + // ONDIOSP.BIN in root -> Ondio SP + struct Detected d; + d.device = "ondiosp"; + d.mountpoint = mounts.at(i); + d.status = PlayerOk; + updateDetectedDevice(d); + } + if(rootentries.contains("ajbrec.ajz", Qt::CaseInsensitive)) + { + LOG_INFO() << "ajbrec.ajz found. Trying detectAjbrec()"; + struct Detected d; + d.device = detectAjbrec(mounts.at(i)); + d.mountpoint = mounts.at(i); + d.status = PlayerOk; + if(!d.device.isEmpty()) { + LOG_INFO() << d.device; + updateDetectedDevice(d); + } + } + // detection based on player specific folders + QStringList rootfolders = root.entryList(QDir::Dirs + | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System); + if(rootfolders.contains("GBSYSTEM", Qt::CaseInsensitive)) + { + // GBSYSTEM folder -> Gigabeat + struct Detected d; + d.device = "gigabeatf"; + d.mountpoint = mounts.at(i); + updateDetectedDevice(d); + } + } + } +#if 0 + // Ipods have a folder "iPod_Control" in the root. + for(int i = 0; i < m_detected.size(); ++i) { + struct Detected entry = m_detected.at(i); + for(int j = 0; j < entry.usbdevices.size(); ++j) { + // limit this to Ipods only. + if(!entry.usbdevices.at(j).startsWith("ipod") + && !entry.device.startsWith("ipod")) { + continue; + } + // look for iPod_Control on all supported volumes. + for(int k = 0; k < mounts.size(); k++) { + QDir root(mounts.at(k)); + QStringList rootfolders = root.entryList(QDir::Dirs + | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System); + if(rootfolders.contains("iPod_Control", Qt::CaseInsensitive)) { + entry.mountpoint = mounts.at(k); + m_detected.takeAt(i); + m_detected.append(entry); + } + } + } + } +#endif + +} + + +void Autodetection::mergePatcher(void) +{ + int n; + // try ipodpatcher + // initialize sector buffer. Needed. + struct ipod_t ipod; + ipod.sectorbuf = nullptr; + ipod_alloc_buffer(&ipod, BUFFER_SIZE); + n = ipod_scan(&ipod); + // FIXME: handle more than one Ipod connected in ipodpatcher. + if(n == 1) { + LOG_INFO() << "Ipod found:" << ipod.modelstr << "at" << ipod.diskname; + // since resolveMountPoint is doing exact matches we need to select + // the correct partition. + QString mp(ipod.diskname); +#ifdef Q_OS_LINUX + mp.append("2"); +#endif +#ifdef Q_OS_MACX + mp.append("s2"); +#endif + struct Detected d; + d.device = ipod.targetname; + d.mountpoint = Utils::resolveMountPoint(mp); + // if the found ipod is a macpod also notice it as device with problem. + if(ipod.macpod) + d.status = PlayerWrongFilesystem; + else + d.status = PlayerOk; + updateDetectedDevice(d); + } + else { + LOG_INFO() << "ipodpatcher: no Ipod found." << n; + } + ipod_dealloc_buffer(&ipod); + + // try sansapatcher + // initialize sector buffer. Needed. + struct sansa_t sansa; + sansa_alloc_buffer(&sansa, BUFFER_SIZE); + n = sansa_scan(&sansa); + if(n == 1) { + LOG_INFO() << "Sansa found:" + << sansa.targetname << "at" << sansa.diskname; + QString mp(sansa.diskname); +#ifdef Q_OS_LINUX + mp.append("1"); +#endif +#ifdef Q_OS_MACX + mp.append("s1"); +#endif + struct Detected d; + d.device = QString("sansa%1").arg(sansa.targetname); + d.mountpoint = Utils::resolveMountPoint(mp); + d.status = PlayerOk; + updateDetectedDevice(d); + } + else { + LOG_INFO() << "sansapatcher: no Sansa found." << n; + } + sansa_dealloc_buffer(&sansa); +} + + +QString Autodetection::detectAjbrec(QString root) +{ + QFile f(root + "/ajbrec.ajz"); + char header[24]; + f.open(QIODevice::ReadOnly); + if(!f.read(header, 24)) return QString(); + f.close(); + + // check the header of the file. + // recorder v1 had a 6 bytes sized header + // recorder v2, FM, Ondio SP and FM have a 24 bytes header. + + // recorder v1 has the binary length in the first 4 bytes, so check + // for them first. + int len = (header[0]<<24) | (header[1]<<16) | (header[2]<<8) | header[3]; + LOG_INFO() << "abjrec.ajz possible bin length:" << len + << "file len:" << f.size(); + if((f.size() - 6) == len) + return "recorder"; + + // size didn't match, now we need to assume we have a headerlength of 24. + switch(header[11]) { + case 2: + return "recorderv2"; + case 4: + return "fmrecorder"; + case 8: + return "ondiofm"; + case 16: + return "ondiosp"; + default: + break; + } + return QString(); +} + + +int Autodetection::findDetectedDevice(QString device) +{ + int i = m_detected.size(); + while(i--) { + if(m_detected.at(i).usbdevices.contains(device)) + return i; + } + i = m_detected.size(); + while(i--) { + if(m_detected.at(i).device == device) + return i; + } + return -1; +} + + +void Autodetection::updateDetectedDevice(Detected& entry) +{ + int index = findDetectedDevice(entry.device); + if(index < 0) { + m_detected.append(entry); + } + else { + m_detected.takeAt(index); + m_detected.append(entry); + } +} -- cgit v1.2.3