LinkManager.cc 7.42 KB
Newer Older
pixhawk's avatar
pixhawk committed
1
/*=====================================================================
lm's avatar
lm committed
2 3 4 5 6 7 8 9

QGroundControl Open Source Ground Control Station

(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

This file is part of the QGROUNDCONTROL project

    QGROUNDCONTROL is free software: you can redistribute it and/or modify
pixhawk's avatar
pixhawk committed
10 11 12
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
lm's avatar
lm committed
13 14

    QGROUNDCONTROL is distributed in the hope that it will be useful,
pixhawk's avatar
pixhawk committed
15 16 17
    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.
lm's avatar
lm committed
18

pixhawk's avatar
pixhawk committed
19
    You should have received a copy of the GNU General Public License
lm's avatar
lm committed
20 21
    along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

pixhawk's avatar
pixhawk committed
22
======================================================================*/
23

pixhawk's avatar
pixhawk committed
24 25 26 27 28 29 30 31 32 33
/**
 * @file
 *   @brief Brief Description
 *
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QList>
#include <QApplication>
34 35
#include <QDebug>

36 37
#include "LinkManager.h"
#include "MainWindow.h"
Don Gagne's avatar
Don Gagne committed
38
#include "QGCMessageBox.h"
39

40 41 42 43 44 45 46 47 48 49 50
LinkManager* LinkManager::instance()
{
    static LinkManager* _instance = 0;
    if(_instance == 0) {
        _instance = new LinkManager();

        /* Set the application as parent to ensure that this object
         * will be destroyed when the main application exits */
        _instance->setParent(qApp);
    }
    return _instance;
pixhawk's avatar
pixhawk committed
51 52 53 54
}

/**
 * @brief Private singleton constructor
55
 *
pixhawk's avatar
pixhawk committed
56 57
 * This class implements the singleton design pattern and has therefore only a private constructor.
 **/
58 59
LinkManager::LinkManager() :
    _connectionsSuspended(false)
pixhawk's avatar
pixhawk committed
60
{
61 62
    _links = QList<LinkInterface*>();
    _protocolLinks = QMap<ProtocolInterface*, LinkInterface*>();
pixhawk's avatar
pixhawk committed
63 64 65 66 67
}

LinkManager::~LinkManager()
{
    disconnectAll();
68 69 70 71 72
    
    _dataMutex.lock();
    foreach (LinkInterface* link, _links) {
        Q_ASSERT(link);
        link->deleteLater();
Lorenz Meier's avatar
Lorenz Meier committed
73
    }
74 75
    _links.clear();
    _dataMutex.unlock();
pixhawk's avatar
pixhawk committed
76 77 78 79
}

void LinkManager::add(LinkInterface* link)
{
80 81 82 83 84
    Q_ASSERT(link);
    
    _dataMutex.lock();
    
    if (!_links.contains(link))
Lorenz Meier's avatar
Lorenz Meier committed
85
    {
86
        connect(link, SIGNAL(destroyed(QObject*)), this, SLOT(removeObj(QObject*)));
87 88
        _links.append(link);
        _dataMutex.unlock();
89
        emit newLink(link);
90
    } else {
91
        _dataMutex.unlock();
92
    }
pixhawk's avatar
pixhawk committed
93 94 95 96
}

void LinkManager::addProtocol(LinkInterface* link, ProtocolInterface* protocol)
{
97 98 99
    Q_ASSERT(link);
    Q_ASSERT(protocol);
    
pixhawk's avatar
pixhawk committed
100 101
    // Connect link to protocol
    // the protocol will receive new bytes from the link
102 103
    _dataMutex.lock();
    QList<LinkInterface*> linkList = _protocolLinks.values(protocol);
104 105 106

    // If protocol has not been added before (list length == 0)
    // OR if link has not been added to protocol, add
Lorenz Meier's avatar
Lorenz Meier committed
107
    if (!linkList.contains(link))
Lorenz Meier's avatar
Lorenz Meier committed
108
    {
109 110
        // Protocol is new, add
        connect(link, SIGNAL(bytesReceived(LinkInterface*, QByteArray)), protocol, SLOT(receiveBytes(LinkInterface*, QByteArray)));
111 112
        // Add status
        connect(link, SIGNAL(connected(bool)), protocol, SLOT(linkStatusChanged(bool)));
113
        // Store the connection information in the protocol links map
114 115
        _protocolLinks.insertMulti(protocol, link);
        _dataMutex.unlock();
116 117
        // Make sure the protocol clears its metadata for this link.
        protocol->resetMetadataForLink(link);
118
    } else {
119
        _dataMutex.unlock();
120
    }
121
    //qDebug() << __FILE__ << __LINE__ << "ADDED LINK TO PROTOCOL" << link->getName() << protocol->getName() << "NEW SIZE OF LINK LIST:" << _protocolLinks.size();
pixhawk's avatar
pixhawk committed
122 123 124 125
}

QList<LinkInterface*> LinkManager::getLinksForProtocol(ProtocolInterface* protocol)
{
126 127 128
    _dataMutex.lock();
    QList<LinkInterface*> links = _protocolLinks.values(protocol);
    _dataMutex.unlock();
129
    return links;
pixhawk's avatar
pixhawk committed
130 131
}

132 133
ProtocolInterface* LinkManager::getProtocolForLink(LinkInterface* link)
{
134
    _dataMutex.lock();
135
    ProtocolInterface* protocol = _protocolLinks.key(link);
136
    _dataMutex.unlock();
137
	return protocol;
138
}
pixhawk's avatar
pixhawk committed
139 140 141

bool LinkManager::connectAll()
{
142 143 144 145
    if (_connectionsSuspendedMsg()) {
        return false;
    }
    
146 147
    bool allConnected = true;

148 149 150 151 152 153
    _dataMutex.lock();
    foreach (LinkInterface* link, _links) {
        Q_ASSERT(link);
        if (!link->_connect()) {
            allConnected = false;
        }
154
    }
155
    _dataMutex.unlock();
156 157

    return allConnected;
pixhawk's avatar
pixhawk committed
158 159 160 161
}

bool LinkManager::disconnectAll()
{
162 163
    bool allDisconnected = true;

164 165
    _dataMutex.lock();
    foreach (LinkInterface* link, _links)
Lorenz Meier's avatar
Lorenz Meier committed
166
    {
167 168 169 170
        Q_ASSERT(link);
        if (!link->disconnect()) {
            allDisconnected = false;
        }
171
    }
172
    _dataMutex.unlock();
173 174

    return allDisconnected;
pixhawk's avatar
pixhawk committed
175 176 177 178
}

bool LinkManager::connectLink(LinkInterface* link)
{
179 180 181 182 183 184 185
    Q_ASSERT(link);
    
    if (_connectionsSuspendedMsg()) {
        return false;
    }

    return link->_connect();
pixhawk's avatar
pixhawk committed
186 187 188 189
}

bool LinkManager::disconnectLink(LinkInterface* link)
{
190 191
    Q_ASSERT(link);
    return link->_disconnect();
pixhawk's avatar
pixhawk committed
192 193
}

194
void LinkManager::removeObj(QObject* link)
195
{
196 197 198
    // Be careful of the fact that by the time this signal makes it through the queue
    // the link object has already been destructed.
    removeLink((LinkInterface*)link);
199 200
}

201 202
bool LinkManager::removeLink(LinkInterface* link)
{
Lorenz Meier's avatar
Lorenz Meier committed
203 204
    if(link)
    {
205 206
        _dataMutex.lock();
        for (int i=0; i < _links.size(); i++)
Lorenz Meier's avatar
Lorenz Meier committed
207
        {
208
            if(link==_links.at(i))
Lorenz Meier's avatar
Lorenz Meier committed
209
            {
210
                _links.removeAt(i); //remove from link list
211 212
            }
        }
213
        // Remove link from protocol map
214
        QList<ProtocolInterface* > protocols = _protocolLinks.keys(link);
Lorenz Meier's avatar
Lorenz Meier committed
215 216
        foreach (ProtocolInterface* proto, protocols)
        {
217
            _protocolLinks.remove(proto, link);
218
        }
219
        _dataMutex.unlock();
220 221 222 223

        // Emit removal of link
        emit linkRemoved(link);

224 225 226
        return true;
    }
    return false;
227 228
}

pixhawk's avatar
pixhawk committed
229 230 231 232 233 234 235 236
/**
 * The access time is linear in the number of links.
 *
 * @param id link identifier to search for
 * @return A pointer to the link or NULL if not found
 */
LinkInterface* LinkManager::getLinkForId(int id)
{
237
    _dataMutex.lock();
238
    LinkInterface* linkret = NULL;
239
    foreach (LinkInterface* link, _links)
Lorenz Meier's avatar
Lorenz Meier committed
240
    {
241 242
        Q_ASSERT(link);
        
243 244 245 246
        if (link->getId() == id)
        {
            linkret = link;
        }
pixhawk's avatar
pixhawk committed
247
    }
248
    _dataMutex.unlock();
249
    return linkret;
pixhawk's avatar
pixhawk committed
250 251 252 253 254 255 256
}

/**
 *
 */
const QList<LinkInterface*> LinkManager::getLinks()
{
257 258 259
    _dataMutex.lock();
    QList<LinkInterface*> ret(_links);
    _dataMutex.unlock();
260
    return ret;
pixhawk's avatar
pixhawk committed
261
}
262 263 264

const QList<SerialLink*> LinkManager::getSerialLinks()
{
265
    _dataMutex.lock();
266 267
    QList<SerialLink*> s;

268
    foreach (LinkInterface* link, _links)
269
    {
270 271 272
        Q_ASSERT(link);
        
        SerialLink* serialLink = qobject_cast<SerialLink*>(link);
273

274 275
        if (serialLink)
            s.append(serialLink);
276
    }
277
    _dataMutex.unlock();
278 279 280

    return s;
}
281 282 283 284 285 286

/// @brief If all new connections should be suspended a message is displayed to the user and true
///         is returned;
bool LinkManager::_connectionsSuspendedMsg(void)
{
    if (_connectionsSuspended) {
Don Gagne's avatar
Don Gagne committed
287 288
        QGCMessageBox::information(tr("Connect not allowed"),
                                   tr("Connect not allowed: %1").arg(_connectionsSuspendedReason));
289 290 291 292 293 294 295 296 297 298 299 300 301
        return true;
    } else {
        return false;
    }
}

void LinkManager::setConnectionsSuspended(QString reason)
{
    _connectionsSuspended = true;
    _connectionsSuspendedReason = reason;
    Q_ASSERT(!reason.isEmpty());
}