LinkManager.cc 7.49 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
#include "QGCApplication.h"
40

41 42 43
LinkManager* LinkManager::_instance = NULL;

LinkManager* LinkManager::instance(void)
44 45
{
    if(_instance == 0) {
46 47
        _instance = new LinkManager(qgcApp());
        Q_CHECK_PTR(_instance);
48
    }
49 50 51
    
    Q_ASSERT(_instance);
    
52
    return _instance;
pixhawk's avatar
pixhawk committed
53 54
}

55 56 57 58 59 60
void LinkManager::deleteInstance(void)
{
    _instance = NULL;
    delete this;
}

pixhawk's avatar
pixhawk committed
61 62
/**
 * @brief Private singleton constructor
63
 *
pixhawk's avatar
pixhawk committed
64 65
 * This class implements the singleton design pattern and has therefore only a private constructor.
 **/
66 67
LinkManager::LinkManager(QObject* parent) :
    QGCSingleton(parent),
68
    _connectionsSuspended(false)
pixhawk's avatar
pixhawk committed
69
{
70 71
    _links = QList<LinkInterface*>();
    _protocolLinks = QMap<ProtocolInterface*, LinkInterface*>();
pixhawk's avatar
pixhawk committed
72 73 74 75 76
}

LinkManager::~LinkManager()
{
    disconnectAll();
77 78 79 80 81
    
    _dataMutex.lock();
    foreach (LinkInterface* link, _links) {
        Q_ASSERT(link);
        link->deleteLater();
Lorenz Meier's avatar
Lorenz Meier committed
82
    }
83 84
    _links.clear();
    _dataMutex.unlock();
pixhawk's avatar
pixhawk committed
85 86 87 88
}

void LinkManager::add(LinkInterface* link)
{
89 90 91 92 93
    Q_ASSERT(link);
    
    _dataMutex.lock();
    
    if (!_links.contains(link))
Lorenz Meier's avatar
Lorenz Meier committed
94
    {
95
        connect(link, SIGNAL(destroyed(QObject*)), this, SLOT(removeObj(QObject*)));
96 97
        _links.append(link);
        _dataMutex.unlock();
98
        emit newLink(link);
99
    } else {
100
        _dataMutex.unlock();
101
    }
pixhawk's avatar
pixhawk committed
102 103 104 105
}

void LinkManager::addProtocol(LinkInterface* link, ProtocolInterface* protocol)
{
106 107 108
    Q_ASSERT(link);
    Q_ASSERT(protocol);
    
pixhawk's avatar
pixhawk committed
109 110
    // Connect link to protocol
    // the protocol will receive new bytes from the link
111 112
    _dataMutex.lock();
    QList<LinkInterface*> linkList = _protocolLinks.values(protocol);
113 114 115

    // 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
116
    if (!linkList.contains(link))
Lorenz Meier's avatar
Lorenz Meier committed
117
    {
118 119
        // Protocol is new, add
        connect(link, SIGNAL(bytesReceived(LinkInterface*, QByteArray)), protocol, SLOT(receiveBytes(LinkInterface*, QByteArray)));
120 121
        // Add status
        connect(link, SIGNAL(connected(bool)), protocol, SLOT(linkStatusChanged(bool)));
122
        // Store the connection information in the protocol links map
123 124
        _protocolLinks.insertMulti(protocol, link);
        _dataMutex.unlock();
125 126
        // Make sure the protocol clears its metadata for this link.
        protocol->resetMetadataForLink(link);
127
    } else {
128
        _dataMutex.unlock();
129
    }
130
    //qDebug() << __FILE__ << __LINE__ << "ADDED LINK TO PROTOCOL" << link->getName() << protocol->getName() << "NEW SIZE OF LINK LIST:" << _protocolLinks.size();
pixhawk's avatar
pixhawk committed
131 132 133 134
}

QList<LinkInterface*> LinkManager::getLinksForProtocol(ProtocolInterface* protocol)
{
135 136 137
    _dataMutex.lock();
    QList<LinkInterface*> links = _protocolLinks.values(protocol);
    _dataMutex.unlock();
138
    return links;
pixhawk's avatar
pixhawk committed
139 140
}

141 142
ProtocolInterface* LinkManager::getProtocolForLink(LinkInterface* link)
{
143
    _dataMutex.lock();
144
    ProtocolInterface* protocol = _protocolLinks.key(link);
145
    _dataMutex.unlock();
146
	return protocol;
147
}
pixhawk's avatar
pixhawk committed
148 149 150

bool LinkManager::connectAll()
{
151 152 153 154
    if (_connectionsSuspendedMsg()) {
        return false;
    }
    
155 156
    bool allConnected = true;

157 158 159 160 161 162
    _dataMutex.lock();
    foreach (LinkInterface* link, _links) {
        Q_ASSERT(link);
        if (!link->_connect()) {
            allConnected = false;
        }
163
    }
164
    _dataMutex.unlock();
165 166

    return allConnected;
pixhawk's avatar
pixhawk committed
167 168 169 170
}

bool LinkManager::disconnectAll()
{
171 172
    bool allDisconnected = true;

173 174
    _dataMutex.lock();
    foreach (LinkInterface* link, _links)
Lorenz Meier's avatar
Lorenz Meier committed
175
    {
176 177 178 179
        Q_ASSERT(link);
        if (!link->disconnect()) {
            allDisconnected = false;
        }
180
    }
181
    _dataMutex.unlock();
182 183

    return allDisconnected;
pixhawk's avatar
pixhawk committed
184 185 186 187
}

bool LinkManager::connectLink(LinkInterface* link)
{
188 189 190 191 192 193 194
    Q_ASSERT(link);
    
    if (_connectionsSuspendedMsg()) {
        return false;
    }

    return link->_connect();
pixhawk's avatar
pixhawk committed
195 196 197 198
}

bool LinkManager::disconnectLink(LinkInterface* link)
{
199 200
    Q_ASSERT(link);
    return link->_disconnect();
pixhawk's avatar
pixhawk committed
201 202
}

203
void LinkManager::removeObj(QObject* link)
204
{
205 206 207
    // 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);
208 209
}

210 211
bool LinkManager::removeLink(LinkInterface* link)
{
Lorenz Meier's avatar
Lorenz Meier committed
212 213
    if(link)
    {
214 215
        _dataMutex.lock();
        for (int i=0; i < _links.size(); i++)
Lorenz Meier's avatar
Lorenz Meier committed
216
        {
217
            if(link==_links.at(i))
Lorenz Meier's avatar
Lorenz Meier committed
218
            {
219
                _links.removeAt(i); //remove from link list
220 221
            }
        }
222
        // Remove link from protocol map
223
        QList<ProtocolInterface* > protocols = _protocolLinks.keys(link);
Lorenz Meier's avatar
Lorenz Meier committed
224 225
        foreach (ProtocolInterface* proto, protocols)
        {
226
            _protocolLinks.remove(proto, link);
227
        }
228
        _dataMutex.unlock();
229 230 231 232

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

233 234 235
        return true;
    }
    return false;
236 237
}

pixhawk's avatar
pixhawk committed
238 239 240 241 242 243 244 245
/**
 * 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)
{
246
    _dataMutex.lock();
247
    LinkInterface* linkret = NULL;
248
    foreach (LinkInterface* link, _links)
Lorenz Meier's avatar
Lorenz Meier committed
249
    {
250 251
        Q_ASSERT(link);
        
252 253 254 255
        if (link->getId() == id)
        {
            linkret = link;
        }
pixhawk's avatar
pixhawk committed
256
    }
257
    _dataMutex.unlock();
258
    return linkret;
pixhawk's avatar
pixhawk committed
259 260 261 262 263 264 265
}

/**
 *
 */
const QList<LinkInterface*> LinkManager::getLinks()
{
266 267 268
    _dataMutex.lock();
    QList<LinkInterface*> ret(_links);
    _dataMutex.unlock();
269
    return ret;
pixhawk's avatar
pixhawk committed
270
}
271 272 273

const QList<SerialLink*> LinkManager::getSerialLinks()
{
274
    _dataMutex.lock();
275 276
    QList<SerialLink*> s;

277
    foreach (LinkInterface* link, _links)
278
    {
279 280 281
        Q_ASSERT(link);
        
        SerialLink* serialLink = qobject_cast<SerialLink*>(link);
282

283 284
        if (serialLink)
            s.append(serialLink);
285
    }
286
    _dataMutex.unlock();
287 288 289

    return s;
}
290 291 292 293 294 295

/// @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
296 297
        QGCMessageBox::information(tr("Connect not allowed"),
                                   tr("Connect not allowed: %1").arg(_connectionsSuspendedReason));
298 299 300 301 302 303 304 305 306 307 308 309 310
        return true;
    } else {
        return false;
    }
}

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