sistemata la gestione dei devices
[avrdudequi:avrdudequi.git] / programmer.cpp
1 /***************************************************************************
2  *   Copyright (C) 2011 by Maurilio                                        *
3  *   mau_ri_tec@yahoo.it                                                   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
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.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21
22 #include <QDebug>
23 #include "programmer.h"
24 #include <QDir>
25 #include <QStringList>
26 #include <QMessageBox>
27 #include "global.h"
28
29 Programmer *Programmer::m_instance = 0;
30
31 Programmer::Programmer() :
32     QObject(0), programmerIsValid(false)
33 {
34     sysDevice = SysDevice::instance();
35     sysDevice->setParent(this);
36     _currentDevice = UdevQt::Device();
37
38     connect(sysDevice, SIGNAL(deviceRemoved(UdevQt::Device)), this, SLOT(deviceRemoved(UdevQt::Device)));
39
40 }
41
42 Programmer::~Programmer()
43 {
44
45 }
46
47 void Programmer::fillProgrammer(QComboBox *cBoxProg)
48 {
49     _cBoxProg = cBoxProg;
50     QDir programmer_dir(AvrDudeQuiPath::programmers());
51     QStringList xmlFileNames = programmer_dir.entryList(QStringList("*.xml"),
52                                                        QDir::Files);
53     streamParser(xmlFileNames);
54
55     connect(_cBoxProg, SIGNAL(currentIndexChanged(int)), this, SLOT(change(int)));
56 }
57
58 QMap<QString, QString> *Programmer::dataMap()
59 {
60     return &m_prog;
61 }
62
63 void Programmer::parseDeviceNode(QDomElement &child)
64 {
65     QDomElement saveChild = child;
66     child = child.firstChildElement();
67     for (; !child.isNull(); child = child.nextSiblingElement())
68         m_prog.insert(saveChild.nodeName() + "." + child.nodeName(), child.text());
69
70     child = saveChild;
71 }
72
73 void Programmer::deviceRemoved(const UdevQt::Device &dev)
74 {
75     /*
76     Tutto questo controllo dipende dal fatto che:
77     Device ha delle proprietà differenti se c'è attivato il monitor. Es "dev" viene
78     passato a questo slot se il device viene rimosso, dev contiene una proprietà ACTION
79     che può assumere valore stringa remove o added.
80     Device non ha la proprietà ACTION sempre e comunque, ma solo a seguito di un evento.
81     Infatti i device ritornati da UdevQt::Client::allDevices() non hanno questa proprietà.
82
83     Device currentDevice = theProgrammer->currentDevice();
84     currentDevice è il device salvato prima, questo non ha la proprietà ACTION.
85
86     Device non implementa l'operatore "==" quindi non è possibile comparare due
87     device, anche perchè la comparazione avrebbe dato esito negativo anche i due
88     device comparati si riferiscono allo stesso device, perchè uno contiene una proprietà
89     in più.
90
91     */
92     //theProgrammer->currentDevice() Action" << theProgrammer->currentDevice().deviceProperties();
93     //Device currentDevice = theProgrammer->currentDevice();
94     QString currentUdi;
95     QString removedUdi;
96     //QMap<QString,QString> * dataP = theProgrammer->dataMap();
97     if (_currentDevice.subsystem() == "usb") {
98         removedUdi = dev.subsystem() + "/"
99                 + dev.devType() + "/"
100                 + dev.deviceProperty("ID_VENDOR_ID") + "/"
101                 + dev.deviceProperty("ID_MODEL_ID") + "/"
102                 + dev.deviceProperty("ID_SERIAL_SHORT") + "/"
103                 + dev.deviceProperty("DEVNAME");
104         currentUdi = _currentDevice.subsystem() + "/"
105                 + _currentDevice.devType() + "/"
106                 + _currentDevice.deviceProperty("ID_VENDOR_ID") + "/"
107                 + _currentDevice.deviceProperty("ID_MODEL_ID") + "/"
108                 + _currentDevice.deviceProperty("ID_SERIAL_SHORT") + "/"
109                 + _currentDevice.deviceProperty("DEVNAME");
110
111
112     }
113     else
114     if (_currentDevice.subsystem() == "tty") {
115         removedUdi = dev.subsystem() + "/"
116                 + dev.deviceProperty("ID_TYPE") + "/"
117                 + dev.deviceProperty("ID_VENDOR_ID") + "/"
118                 + dev.deviceProperty("ID_MODEL_ID") + "/"
119                 + dev.deviceProperty("ID_USB_DRIVER") + "/"
120                 + dev.deviceProperty("ID_SERIAL_SHORT") + "/"
121                 + dev.deviceProperty("DEVNAME");
122         currentUdi = _currentDevice.subsystem() + "/"
123                 + _currentDevice.deviceProperty("ID_TYPE") + "/"
124                 + _currentDevice.deviceProperty("ID_VENDOR_ID") + "/"
125                 + _currentDevice.deviceProperty("ID_MODEL_ID") + "/"
126                 + _currentDevice.deviceProperty("ID_USB_DRIVER") + "/"
127                 + _currentDevice.deviceProperty("ID_SERIAL_SHORT") + "/"
128                 + _currentDevice.deviceProperty("DEVNAME");
129     }
130
131
132     // change(-1) rende invalido il device e il programmatore scelto
133     if (currentUdi == removedUdi) {
134         change(-1);
135     }
136     // !*!*!*!*! DEVE ESSERE PIÙ SEMPLICE !*!*!*!*!*!*
137 }
138
139
140
141 void Programmer::change(int idx)
142 {
143     _currentDevice = UdevQt::Device();
144     programmerIsValid = false;
145     m_prog.clear();
146     if ((_cBoxProg->currentIndex() < 1) || (idx < 0) ) {
147         _cBoxProg->setCurrentIndex(0);
148         emit programmerChanged("");
149         return;
150     }
151
152     QStringList file_id = _cBoxProg->itemData(idx).toString().split("/");
153     currentFile = file_id[0];       // es arduino.xml
154     idProgrammer = file_id[1];      // es 2009
155
156     QFile file(AvrDudeQuiPath::programmers() + "/" + currentFile);
157     if (!file.open(QFile::ReadOnly | QFile::Text)) {
158         QMessageBox::warning(_cBoxProg, tr("AvrDudeQui error dialog"),
159                              tr("Cannot read file %1:\n%2.")
160                              .arg(currentFile)
161                              .arg(file.errorString()));
162         return;
163     }
164     currentDoc.clear();
165     currentDoc.setContent(&file);
166     int n_id = currentDoc.elementsByTagName("id").count();
167
168     QDomElement root = currentDoc.documentElement();
169     QDomElement child = root.firstChildElement();
170
171     // parse and mach idProgrammer
172     for(int i=0; i<n_id; i++) {
173         if (child.nodeName() == "id") {
174             if (child.attribute("term") == idProgrammer) {
175                 currentProgrammer = child;
176                 break;
177             } else {
178                 child = child.nextSibling().toElement();
179             }
180         }
181     }
182     if (currentProgrammer.isNull())
183         return;
184
185
186     QString node_parent;
187     // parse device and opt element
188     child = currentProgrammer.firstChildElement();
189     for (; !child.isNull(); child = child.nextSibling().toElement()) {
190         if (child.hasAttribute("term")) {
191             m_prog.insert(child.nodeName(), child.attribute("term"));
192         } else {
193             if (child.nodeName() == "device") { // entra nel tag <device>
194                 parseDeviceNode(child);
195             } else {
196                 m_prog.insert(child.parentNode().nodeName()
197                               + "." + child.nodeName(), child.text());
198             }
199             if (child.nodeName() == "opt") { // entra nel tag <opt>
200                 parseDeviceNode(child);
201             }
202         }
203     }
204     file.close();
205     QString udi;
206     // assembling device udi
207     udi = m_prog.value("device.SUBSYSTEM") + "/";
208     if (m_prog.value("device.SUBSYSTEM") == "usb")
209         udi += m_prog.value("device.DEVTYPE")
210                 + "/" + m_prog.value("device.ID_VENDOR_ID")
211                 + "/" + m_prog.value("device.ID_MODEL_ID");
212     else
213         udi += m_prog.value("device.ID_TYPE")
214                 + "/" + m_prog.value("device.ID_VENDOR_ID")
215                 + "/" + m_prog.value("device.ID_MODEL_ID")
216                 + "/" + m_prog.value("device.ID_USB_DRIVER");
217
218     m_prog.insert("device.UDI", udi);
219
220     devListMatch = sysDevice->getMatchListFromUDI(udi);
221
222     if (devListMatch.isEmpty())
223         programmerIsValid = false;
224     else
225         programmerIsValid = true;
226
227     emit programmerChanged(udi);
228 }
229
230 UdevQt::DeviceList Programmer::getDevices()
231 {
232     return devListMatch;
233 }
234
235 bool Programmer::isValid()
236 {
237
238     return programmerIsValid;
239
240 }
241
242 void Programmer::streamParser(const QStringList &xmlFileNames)
243 {
244
245     foreach(QString xmlFileName, xmlFileNames)  {
246         QFile file(AvrDudeQuiPath::programmers() + "/" + xmlFileName);
247         if (!file.open(QFile::ReadOnly | QFile::Text)) {
248             qDebug() << "Errore nel leggere il file " + xmlFileName;
249         } else {
250             currentFile = xmlFileName;
251             reader.setDevice(&file);
252
253             reader.readNext();
254             while (!reader.atEnd()) {
255                 if (reader.isStartElement()) {
256                     if (reader.name() == "avrdude") {
257                            readVersion();
258                     } else {
259                         reader.raiseError(QObject::tr("version tag missing"));
260                     }
261                 } else {
262                     reader.readNext();
263                 }
264             }
265             file.close();
266         }
267     }
268 }
269 void Programmer::readVersion()
270 {
271
272     version = reader.attributes().value("version").toString();
273
274     reader.readNext();
275     while (!reader.atEnd()) {
276         if (reader.isEndElement()) {
277             reader.readNext();
278             break;
279         }
280
281         if (reader.isStartElement()) {
282             if (reader.name() == "id") {
283                 readId();
284             } else {
285                 skipUnknownElement();
286             }
287         } else {
288             reader.readNext();
289         }
290     }
291 }
292
293 void Programmer::readId()
294 {
295     idProgrammer = reader.attributes().value("term").toString();
296     reader.readNext();
297     while (!reader.atEnd()) {
298         if (reader.isEndElement()) {
299             reader.readNext();
300             break;
301         }
302
303         if (reader.isStartElement()) {
304             if (reader.name() == "name") {
305                 readName();
306             } else {
307                 skipUnknownElement();
308             }
309         } else {
310             reader.readNext();
311         }
312     }
313 }
314
315 void Programmer::readName()
316 {
317     _cBoxProg->addItem(reader.readElementText().simplified(),
318                        QVariant(currentFile + "/"+ idProgrammer));
319     if (reader.isEndElement())
320         reader.readNext();
321 }
322
323 void Programmer::skipUnknownElement()
324 {
325     reader.readNext();
326     while (!reader.atEnd()) {
327         if (reader.isEndElement()) {
328             reader.readNext();
329             break;
330         }
331
332         if (reader.isStartElement()) {
333             skipUnknownElement();
334         } else {
335             reader.readNext();
336         }
337     }
338 }