aboutsummaryrefslogtreecommitdiff
path: root/smartpenmanager.cc
blob: 0ac56e21b5940308e3bc43d285560a9f00c8a85d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
 * scribiu -- read notebooks and voice memos from Livescribe pens
 * Copyright (C) 2015 Javier S. Pedro <javier@javispedro.com>
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */

#include <QtCore/QDebug>
#include <libudev.h>

#include "smartpenmanager.h"

SmartpenManager::SmartpenManager(QObject *parent)
    : QObject(parent), _udev(udev_new()), _monitor(udev_monitor_new_from_netlink(_udev, "udev")),
      _notifier(new QSocketNotifier(udev_monitor_get_fd(_monitor), QSocketNotifier::Read))
{
	udev_monitor_filter_add_match_tag(_monitor, "livescribe-pen");

	connect(_notifier, SIGNAL(activated(int)), SLOT(handleMonitorActivity()));

	udev_monitor_enable_receiving(_monitor);

	udev_enumerate *scan = udev_enumerate_new(_udev);
	udev_enumerate_add_match_tag(scan, "livescribe-pen");

	if (udev_enumerate_scan_devices(scan) == 0) {
		udev_list_entry *l = udev_enumerate_get_list_entry(scan), *i;
		udev_list_entry_foreach(i, l) {
			const char *path = udev_list_entry_get_name(i);
			udev_device *dev = udev_device_new_from_syspath(_udev, path);
			processDevice(dev);
			udev_device_unref(dev);
		}
	} else {
		qWarning() << "Failed to scan for devices";
	}

	udev_enumerate_unref(scan);
}

SmartpenManager::~SmartpenManager()
{
	delete _notifier;
	udev_monitor_unref(_monitor);
	udev_unref(_udev);
}

QStringList SmartpenManager::pensBeingSynchronized() const
{
	QStringList pens;
	pens.reserve(_syncers.size());
	for (QMap<Smartpen::Address, SmartpenSyncer*>::const_iterator it = _syncers.begin();
	     it != _syncers.end(); ++it) {
		QString name = it.value()->penName();
		if (name.isEmpty()) {
			Smartpen::Address addr = it.value()->penAddress();
			name = QString("%1-%2").arg(addr.first).arg(addr.second);
		}
		pens.append(name);
	}
	return pens;
}

void SmartpenManager::handleMonitorActivity()
{
	qDebug() << "udev activity";
	udev_device *dev = udev_monitor_receive_device(_monitor);
	if (dev) {
		const char *action = udev_device_get_action(dev);
		if (action && strcmp(action, "add") == 0) {
			processDevice(dev);
		}
		udev_device_unref(dev);
	}
}

void SmartpenManager::handleSyncerFinished()
{
	SmartpenSyncer *syncer = static_cast<SmartpenSyncer*>(sender());
	Smartpen::Address addr = syncer->penAddress();

	qDebug() << "Finished synchronization with pen with address:" << addr;

	_syncers.remove(addr);
	emit pensBeingSynchronizedChanged();

	if (syncer->hasErrors()) {
		qWarning() << "Synchronization with address" << addr << "failed";
		emit syncFailed(syncer->penName());
	} else {
		emit syncComplete(syncer->penName());
	}

	syncer->deleteLater();
}

void SmartpenManager::processDevice(udev_device *dev)
{
	uint busnum = atol(udev_device_get_sysattr_value(dev, "busnum"));
	uint devnum = atol(udev_device_get_sysattr_value(dev, "devnum"));

	Smartpen::Address addr(busnum, devnum);
	if (!_syncers.contains(addr)) {
		SmartpenSyncer *syncer = new SmartpenSyncer(addr, this);
		_syncers.insert(addr, syncer);
		connect(syncer, SIGNAL(finished()), SLOT(handleSyncerFinished()));
		connect(syncer, SIGNAL(penNameChanged()), SIGNAL(pensBeingSynchronizedChanged()));
		syncer->start();
		emit pensBeingSynchronizedChanged();
	}
}