LinkManager.cc 7.36 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
    {
Don Gagne's avatar
Don Gagne committed
95
        connect(link, SIGNAL(destroyed(QObject*)), this, SLOT(_removeLink(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
        Q_ASSERT(link);
Don Gagne's avatar
Don Gagne committed
177
        if (!disconnectLink(link)) {
178 179
            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
}

Don Gagne's avatar
Don Gagne committed
203
void LinkManager::_removeLink(QObject* obj)
204
{
205 206
    // Be careful of the fact that by the time this signal makes it through the queue
    // the link object has already been destructed.
Don Gagne's avatar
Don Gagne committed
207 208 209 210 211 212 213
    
    Q_ASSERT(obj);
    
    LinkInterface* link = static_cast<LinkInterface*>(obj);
    
    _dataMutex.lock();
    for (int i=0; i < _links.size(); i++)
Lorenz Meier's avatar
Lorenz Meier committed
214
    {
Don Gagne's avatar
Don Gagne committed
215
        if(link==_links.at(i))
Lorenz Meier's avatar
Lorenz Meier committed
216
        {
Don Gagne's avatar
Don Gagne committed
217
            _links.removeAt(i); //remove from link list
218 219
        }
    }
Don Gagne's avatar
Don Gagne committed
220 221 222 223 224 225 226 227 228 229
    // Remove link from protocol map
    QList<ProtocolInterface* > protocols = _protocolLinks.keys(link);
    foreach (ProtocolInterface* proto, protocols)
    {
        _protocolLinks.remove(proto, link);
    }
    _dataMutex.unlock();

    // Emit removal of link
    emit linkRemoved(link);
230 231
}

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

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

const QList<SerialLink*> LinkManager::getSerialLinks()
{
268
    _dataMutex.lock();
269 270
    QList<SerialLink*> s;

271
    foreach (LinkInterface* link, _links)
272
    {
273 274 275
        Q_ASSERT(link);
        
        SerialLink* serialLink = qobject_cast<SerialLink*>(link);
276

277 278
        if (serialLink)
            s.append(serialLink);
279
    }
280
    _dataMutex.unlock();
281 282 283

    return s;
}
284 285 286 287 288 289

/// @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
290 291
        QGCMessageBox::information(tr("Connect not allowed"),
                                   tr("Connect not allowed: %1").arg(_connectionsSuspendedReason));
292 293 294 295 296 297 298 299 300 301 302 303 304
        return true;
    } else {
        return false;
    }
}

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