/* * Copyright (c) 2008 Sean C. Rhea (srhea@srhea.net) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SrmDevice.h" #include "SrmRideFile.h" #include #include #include #include #include static bool srmRegistered = Device::addDevice("SRM", new SrmDevice()); QString SrmDevice::downloadInstructions() const { return ""; // no particular instructions for SRM } static Device::StatusCallback cb; static void logfunc(const char *msg) { // XXX: better log function // fprintf(stderr, "%s\n", msg); cb(QString(msg).left(40)); } static bool get_tmpname(const QDir &tmpdir, QString &tmpname, QString &err) { QString tmpl = tmpdir.absoluteFilePath(".srmdl.XXXXXX.srm"); QTemporaryFile tmp(tmpl); tmp.setAutoRemove(false); if (!tmp.open()) { err = "Failed to create temporary file " + tmpl + ": " + tmp.error(); return false; } tmpname = tmp.fileName(); // after close(), tmp.fileName() is "" tmp.close(); return true; } struct SrmpcConn : public boost::noncopyable { srmpc_conn_t d; SrmpcConn(const QString &path, srmpc_log_callback_t logfunc = NULL) { int opt_force = 0; // setting this to 1 is potentially dangerous d = srmpc_open(path.toAscii().constData(), opt_force, logfunc); } ~SrmpcConn() { if (d) srmpc_close(d); } }; struct SrmioData : public boost::noncopyable { srm_data_t d; SrmioData(srm_data_t d) : d(d) {} ~SrmioData() { if (d) srm_data_free(d); } }; static bool dev2path(CommPortPtr dev, QString &path, QString &err) { // Read device path out of device name. Sketchy. QRegExp rx("^Serial: (.+)$"); if (!rx.exactMatch(dev->name())) { err = "SRM download not supported by device " + dev->name(); return false; } path = rx.cap(1); return true; } bool SrmDevice::download(CommPortPtr dev, const QDir &tmpdir, QString &tmpname, QString &filename, StatusCallback statusCallback, QString &err) { // Totally ghetto, proof-of-concept integration with srmio. cb = statusCallback; QString path; if (!dev2path(dev, path, err)) return false; if (!get_tmpname(tmpdir, tmpname, err)) return false; SrmpcConn srm(path, logfunc); if (!srm.d) { err = "Couldn't open device " + path + ": " + strerror(errno); return false; } int opt_all = 0; // XXX: what does this do? int opt_fixup = 1; // fix bad data like srmwin.exe does SrmioData srmdata(srmpc_get_data(srm.d, opt_all, opt_fixup)); if (!srmdata.d) { err = "srmpc_get_data failed"; return false; } if (srm_data_write_srm7(srmdata.d, tmpname.toAscii().constData()) < 0) { err = "Couldn't write to file " + tmpname + ": " + strerror(errno); return false; } // Read it back in to get the ride start time. SrmFileReader reader; QStringList errs; QFile file(tmpname); QStringList errors; boost::scoped_ptr ride( RideFileFactory::instance().openRideFile(file, errors)); BOOST_FOREACH(QString err, errors) fprintf(stderr, "error: %s\n", err.toAscii().constData()); filename = ride->startTime().toString("yyyy_MM_dd_hh_mm_ss") + ".srm"; return true; } void SrmDevice::cleanup(CommPortPtr dev) { QString path, err; if (!dev2path(dev, path, err)) assert(false); if (QMessageBox::question(0, "Powercontrol", "Erase downloaded ride from device memory?", "&Erase", "&Save Only", "", 1, 1) == 0) { SrmpcConn srm(path); if(!srm.d || (srmpc_clear_chunks(srm.d) < 0)) { QMessageBox::warning(0, "Error", "Error communicating with device."); } } }