diff --git a/libnymea-core/hardware/i2c/i2cmanagerimplementation.cpp b/libnymea-core/hardware/i2c/i2cmanagerimplementation.cpp
new file mode 100644
index 00000000..5b029f52
--- /dev/null
+++ b/libnymea-core/hardware/i2c/i2cmanagerimplementation.cpp
@@ -0,0 +1,278 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2020, nymea GmbH
+* Contact: contact@nymea.io
+*
+* This file is part of nymea.
+* This project including source code and documentation is protected by
+* copyright law, and remains the property of nymea GmbH. All rights, including
+* reproduction, publication, editing and translation, are reserved. The use of
+* this project is subject to the terms of a license agreement to be concluded
+* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
+* under https://nymea.io/license
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this project may be redistributed and/or modified under the
+* terms of the GNU Lesser General Public License as published by the Free
+* Software Foundation; version 3. This project 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this project. If not, see .
+*
+* For any further details and any questions please contact us under
+* contact@nymea.io or see our FAQ/Licensing Information on
+* https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "i2cmanagerimplementation.h"
+
+#include "hardware/i2c/i2cdevice.h"
+#include "loggingcategories.h"
+
+#include
+#include
+
+#include
+#include
+#include
+
+namespace nymeaserver {
+
+I2CManagerImplementation::I2CManagerImplementation(QObject *parent) : I2CManager(parent)
+{
+ m_pollTimer.setInterval(200);
+ m_pollTimer.setSingleShot(true);
+ connect(&m_pollTimer, &QTimer::timeout, this, &I2CManagerImplementation::nextCycle);
+}
+
+I2CManagerImplementation::~I2CManagerImplementation()
+{
+ m_watcher.waitForFinished();
+}
+
+QStringList nymeaserver::I2CManagerImplementation::availablePorts() const
+{
+ return QDir("/sys/class/i2c-adapter/").entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
+}
+
+QList nymeaserver::I2CManagerImplementation::scanRegisters(const QString &portName)
+{
+ QList ret;
+
+ QList portsToBeScanned = {portName};
+ if (portName.isEmpty()) {
+ portsToBeScanned = availablePorts();
+ }
+
+ m_mutex.lock();
+
+ foreach (const QString &p, portsToBeScanned) {
+ QFile f("/dev/" + p);
+ if (!f.open(QFile::ReadWrite)) {
+ qCWarning(dcI2C()) << "Failed to open I2C port" << p << "for scanning";
+ continue;
+ }
+
+ for (int address = 0x03; address <= 0x77; address++) {
+ // First check if selecting the slave address is possible at all
+ if (ioctl(f.handle(), I2C_SLAVE, address) >= 0) {
+ char probe = 0x00;
+ long res = 0;
+ // This is how the kernels i2cdetect scans:
+ // Try to read from address 0x30 - 0x35 and 0x50 to 0x5F and write to the others.
+ if ((address >= 0x30 && address <= 0x37)
+ || (address >= 0x50 && address <= 0x5F)) {
+ res = read(f.handle(), &probe, 1);
+ } else {
+ res = write(f.handle(), &probe, 1);
+ }
+ if (res == 1) {
+ qCDebug(dcI2C()) << QString("Found slave device at address 0x%1").arg(address, 0, 16);
+ I2CScanResult result;
+ result.portName = p;
+ result.address = address;
+ ret.append(result);
+ }
+ }
+ }
+ }
+ m_mutex.unlock();
+ return ret;
+}
+
+bool I2CManagerImplementation::open(I2CDevice *i2cDevice)
+{
+ if (m_openFiles.contains(i2cDevice)) {
+ qCWarning(dcI2C()) << "I2C device" << i2cDevice << "already opened.";
+ return false;
+ }
+
+ QString fileName = "/dev/" + i2cDevice->portName();
+
+ foreach (I2CDevice *d, m_openFiles.keys()) {
+ if (d->portName() == i2cDevice->portName()) {
+ // Another I2CDevice opened this file already. We'll hook into that.
+ m_mutex.lock();
+ m_openFiles.insert(i2cDevice, m_openFiles.value(d));
+ m_mutex.unlock();
+ return true;
+ }
+ }
+
+ if (!QFile::exists(fileName)) {
+ qCWarning(dcI2C()) << "The I2C port does not exist:" << i2cDevice->portName();
+ return false;
+ }
+
+ QFile *file = new QFile("/dev/" + i2cDevice->portName(), this);
+ if (!file->open(QFile::ReadWrite)) {
+ qCWarning(dcI2C()) << "Error opening I2C port" << i2cDevice << "Error:" << file->errorString();
+ delete file;
+ return false;
+ }
+
+ m_mutex.lock();
+ m_openFiles.insert(i2cDevice, file);
+ m_mutex.unlock();
+ return true;
+}
+
+bool I2CManagerImplementation::startReading(I2CDevice *i2cDevice, int interval)
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (!m_openFiles.contains(i2cDevice)) {
+ qCWarning(dcI2C()) << "I2CDevice not open. Cannot start reading.";
+ return false;
+ }
+ qCDebug(dcI2C()) << "Starting to poll I2C device" << i2cDevice;
+ ReadingInfo readingInfo;
+ readingInfo.interval = interval;
+ m_readers.insert(i2cDevice, readingInfo);
+
+ if (!m_pollTimer.isActive()) {
+ m_pollTimer.start();
+ }
+ return true;
+}
+
+
+void I2CManagerImplementation::stopReading(I2CDevice *i2cDevice)
+{
+ QMutexLocker locker(&m_mutex);
+ m_readers.remove(i2cDevice);
+
+ if (m_readers.count() == 0) {
+ m_pollTimer.stop();
+ }
+}
+
+bool I2CManagerImplementation::writeData(I2CDevice *i2cDevice, const QByteArray &data)
+{
+ m_writeQueueMutex.lock();
+ WritingInfo info;
+ info.device = i2cDevice;
+ info.data = data;
+ m_writeQueue.append(info);
+ m_writeQueueMutex.unlock();
+ return true;
+}
+
+void I2CManagerImplementation::close(I2CDevice *i2cDevice)
+{
+ bool isInUse = false;
+ m_mutex.lock();
+ if (m_readers.contains(i2cDevice)) {
+ isInUse = true;
+ }
+ m_mutex.unlock();
+
+ if (isInUse) {
+ stopReading(i2cDevice);
+ }
+
+ int refCount = 0;
+ foreach (I2CDevice* d, m_openFiles.keys()) {
+ if (d->portName() == i2cDevice->portName()) {
+ refCount++;
+ }
+ }
+ if (refCount == 0) {
+
+ m_mutex.lock();
+ QFile *f = m_openFiles.take(i2cDevice);
+ m_mutex.unlock();
+
+ f->close();
+ f->deleteLater();
+ }
+}
+
+void I2CManagerImplementation::nextCycle()
+{
+ QFuture future = QtConcurrent::run([this](){
+ // Copy the write queue to open it up as fast as possible for others to append new entries
+ m_writeQueueMutex.lock();
+ QList writeQueue = m_writeQueue;
+ m_writeQueue.clear();
+ m_writeQueueMutex.unlock();
+
+ m_mutex.lock();
+
+ foreach (const WritingInfo &info, writeQueue) {
+ I2CDevice *i2cDevice = info.device;
+
+ int fd = m_openFiles.value(i2cDevice)->handle();
+ if (fd == -1) {
+ qCWarning(dcI2C()) << "I2C device" << i2cDevice << "not opened. Cannot write to it.";
+ continue;
+ }
+
+ if (ioctl(fd, I2C_SLAVE, i2cDevice->address()) < 0) {
+ qCWarning(dcI2C()) << "Cannot select I2C slave address for I2C device" << i2cDevice;
+ continue;
+ }
+
+ qCDebug(dcI2C()) << "Writing to I2C device" << i2cDevice;
+ bool success = i2cDevice->writeData(fd, info.data);
+
+ QMetaObject::invokeMethod(i2cDevice, "dataWritten", Qt::QueuedConnection, Q_ARG(bool, success));
+
+ }
+
+ foreach (I2CDevice *i2cDevice, m_readers.keys()) {
+ ReadingInfo readingInfo = m_readers.value(i2cDevice);
+ if (readingInfo.lastReading.addMSecs(readingInfo.interval) > QDateTime::currentDateTime()) {
+ continue;
+ }
+ int fd = m_openFiles.value(i2cDevice)->handle();
+ if (fd == -1) {
+ qCWarning(dcI2C()) << "I2C device" << i2cDevice << "not opened. Cannot read.";
+ continue;
+ }
+
+ if (ioctl(fd, I2C_SLAVE, i2cDevice->address()) < 0) {
+ qCWarning(dcI2C()) << "Cannot select I2C slave address for I2C device" << i2cDevice;
+ continue;
+ }
+
+ qCDebug(dcI2C()) << "Reading I2C device" << i2cDevice;
+ QByteArray data = i2cDevice->readData(fd);
+
+ m_readers[i2cDevice].lastReading = QDateTime::currentDateTime();
+
+ QMetaObject::invokeMethod(i2cDevice, "readingAvailable", Qt::QueuedConnection, Q_ARG(QByteArray, data));
+ }
+
+ m_mutex.unlock();
+ });
+
+ m_watcher.setFuture(future);
+ connect(&m_watcher, SIGNAL(finished()), &m_pollTimer, SLOT(start()));
+}
+
+}
diff --git a/libnymea-core/hardware/i2c/i2cmanagerimplementation.h b/libnymea-core/hardware/i2c/i2cmanagerimplementation.h
new file mode 100644
index 00000000..3280ee6a
--- /dev/null
+++ b/libnymea-core/hardware/i2c/i2cmanagerimplementation.h
@@ -0,0 +1,95 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2020, nymea GmbH
+* Contact: contact@nymea.io
+*
+* This file is part of nymea.
+* This project including source code and documentation is protected by
+* copyright law, and remains the property of nymea GmbH. All rights, including
+* reproduction, publication, editing and translation, are reserved. The use of
+* this project is subject to the terms of a license agreement to be concluded
+* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
+* under https://nymea.io/license
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this project may be redistributed and/or modified under the
+* terms of the GNU Lesser General Public License as published by the Free
+* Software Foundation; version 3. This project 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this project. If not, see .
+*
+* For any further details and any questions please contact us under
+* contact@nymea.io or see our FAQ/Licensing Information on
+* https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef I2CMANAGERIMPLEMENTATION_H
+#define I2CMANAGERIMPLEMENTATION_H
+
+#include "hardware/i2c/i2cmanager.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+class QFile;
+
+namespace nymeaserver {
+
+class I2CManagerImplementation : public I2CManager
+{
+ Q_OBJECT
+public:
+
+ explicit I2CManagerImplementation(QObject *parent = nullptr);
+ ~I2CManagerImplementation();
+
+ QStringList availablePorts() const override;
+ QList scanRegisters(const QString &portName) override;
+
+ bool open(I2CDevice *i2cDevice) override;
+ bool startReading(I2CDevice *i2cDevice, int interval = 1000) override;
+ void stopReading(I2CDevice *i2cDevice) override;
+ bool writeData(I2CDevice *i2cDevice, const QByteArray &data) override;
+ void close(I2CDevice *i2cDevice) override;
+
+private slots:
+ void nextCycle();
+
+private:
+ class ReadingInfo {
+ public:
+ int interval;
+ QDateTime lastReading;
+ };
+ class WritingInfo {
+ public:
+ QByteArray data;
+ I2CDevice *device;
+ };
+
+ QMutex m_mutex;
+ QHash m_readers;
+ QHash m_openFiles;
+
+ QMutex m_writeQueueMutex;
+ QList m_writeQueue;
+
+ QFutureWatcher m_watcher;
+
+ QTimer m_pollTimer;
+
+};
+
+}
+
+#endif // I2CMANAGERIMPLEMENTATION_H
diff --git a/libnymea-core/hardwaremanagerimplementation.cpp b/libnymea-core/hardwaremanagerimplementation.cpp
index 82d582bc..7e057cf0 100644
--- a/libnymea-core/hardwaremanagerimplementation.cpp
+++ b/libnymea-core/hardwaremanagerimplementation.cpp
@@ -41,6 +41,7 @@
#include "hardware/radio433/radio433brennenstuhl.h"
#include "hardware/bluetoothlowenergy/bluetoothlowenergymanagerimplementation.h"
#include "hardware/network/mqtt/mqttproviderimplementation.h"
+#include "hardware/i2c/i2cmanagerimplementation.h"
namespace nymeaserver {
@@ -67,8 +68,11 @@ HardwareManagerImplementation::HardwareManagerImplementation(Platform *platform,
// Bluetooth LE
m_bluetoothLowEnergyManager = new BluetoothLowEnergyManagerImplementation(m_pluginTimerManager->registerTimer(10), this);
+ m_i2cManager = new I2CManagerImplementation(this);
+
qCDebug(dcHardware()) << "Hardware manager initialized successfully";
+
// Enable all the resources
setResourceEnabled(m_pluginTimerManager, true);
setResourceEnabled(m_radio433, true);
@@ -127,4 +131,9 @@ MqttProvider *HardwareManagerImplementation::mqttProvider()
return m_mqttProvider;
}
+I2CManager *HardwareManagerImplementation::i2cManager()
+{
+ return m_i2cManager;
+}
+
}
diff --git a/libnymea-core/hardwaremanagerimplementation.h b/libnymea-core/hardwaremanagerimplementation.h
index 404fceb8..0c5899eb 100644
--- a/libnymea-core/hardwaremanagerimplementation.h
+++ b/libnymea-core/hardwaremanagerimplementation.h
@@ -37,14 +37,6 @@
#include "hardwaremanager.h"
-class Radio433;
-class UpnpDiscovery;
-class PluginTimerManager;
-class NetworkAccessManager;
-class UpnpDeviceDescriptor;
-class PlatformZeroConfController;
-class BluetoothLowEnergyManager;
-
namespace nymeaserver {
class Platform;
@@ -65,6 +57,7 @@ public:
PlatformZeroConfController *zeroConfController() override;
BluetoothLowEnergyManager *bluetoothLowEnergyManager() override;
MqttProvider *mqttProvider() override;
+ I2CManager * i2cManager() override;
private:
QNetworkAccessManager *m_networkAccessManager = nullptr;
@@ -78,6 +71,7 @@ private:
UpnpDiscovery *m_upnpDiscovery = nullptr;
BluetoothLowEnergyManager *m_bluetoothLowEnergyManager = nullptr;
MqttProvider *m_mqttProvider = nullptr;
+ I2CManager *m_i2cManager = nullptr;
};
}
diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro
index 4255bf3f..1842a5a6 100644
--- a/libnymea-core/libnymea-core.pro
+++ b/libnymea-core/libnymea-core.pro
@@ -88,6 +88,7 @@ HEADERS += nymeacore.h \
hardware/network/upnp/upnpdiscoveryreplyimplementation.h \
hardware/network/mqtt/mqttproviderimplementation.h \
hardware/network/mqtt/mqttchannelimplementation.h \
+ hardware/i2c/i2cmanagerimplementation.h \
debugserverhandler.h \
tagging/tagsstorage.h \
tagging/tag.h \
@@ -165,6 +166,7 @@ SOURCES += nymeacore.cpp \
hardware/network/upnp/upnpdiscoveryreplyimplementation.cpp \
hardware/network/mqtt/mqttproviderimplementation.cpp \
hardware/network/mqtt/mqttchannelimplementation.cpp \
+ hardware/i2c/i2cmanagerimplementation.cpp \
debugserverhandler.cpp \
tagging/tagsstorage.cpp \
tagging/tag.cpp \
diff --git a/libnymea/hardware/i2c/i2cdevice.cpp b/libnymea/hardware/i2c/i2cdevice.cpp
new file mode 100644
index 00000000..f68fd7c7
--- /dev/null
+++ b/libnymea/hardware/i2c/i2cdevice.cpp
@@ -0,0 +1,118 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2020, nymea GmbH
+* Contact: contact@nymea.io
+*
+* This file is part of nymea.
+* This project including source code and documentation is protected by
+* copyright law, and remains the property of nymea GmbH. All rights, including
+* reproduction, publication, editing and translation, are reserved. The use of
+* this project is subject to the terms of a license agreement to be concluded
+* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
+* under https://nymea.io/license
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this project may be redistributed and/or modified under the
+* terms of the GNU Lesser General Public License as published by the Free
+* Software Foundation; version 3. This project 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this project. If not, see .
+*
+* For any further details and any questions please contact us under
+* contact@nymea.io or see our FAQ/Licensing Information on
+* https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "i2cdevice.h"
+#include "i2cmanager.h"
+
+#include
+
+/*! \fn QByteArray I2CDevice::readData(int fileDescriptor);
+ Reimplement this when implementing reading communication with an I2C device.
+ This method will be called repeatedly as soon as the I2CManager is instructed to start
+ reading from this device. Read the current value from the device, e.g. a sensor reading
+ and return the value.
+
+ The given file descriptor will already be opened, the I2C slave address already be
+ selected. The only task is to read the current value. Often that consists of a
+ write operation to configure registers on the device followed by a read operation.
+
+ IMPORTANT: This method will be called from a different thread. This means that you
+ are free to perform blocking operations, including calling QThread::msleep() but it
+ also implies that you must not access other members of the class if they may be
+ accessed from code outside of this method. If you absolutely must do so, make sure
+ to use mutexes (e.g. QMutex) accordingly.
+*/
+
+/*! \fn bool I2CDevice::writeData(int fileDescriptor, const QByteArray &data);
+ Reimplement this when implementing writing communication with an I2C device.
+ This method will be called when I2CManager::writeData(I2CDevice *device, const QByteArray &data)
+ is called. The data to be written is copied and passed on to this method.
+
+ The given file descriptor will already be opened, the I2C slave address already be
+ selected. The only task is to write the data to it. Often that consists of a
+ write operation to configure registers on the device followed by another write operation
+ to write the actual data.
+
+ IMPORTANT: This method will be called from a different thread. This means that you
+ are free to perform blocking operations, including calling QThread::msleep() but it
+ also implies that you must not access other members of the class if they may be
+ accessed from code outside of this method. If you absolutely must do so, make sure
+ to use mutexes (e.g. QMutex) accordingly.
+*/
+
+/*! Constructs an I2CDevice with the given portName and address. The \a portName
+ must match the file name of /dev, for example "i2c-0" for /dev/i2c-0. The
+ \a address describes the I2C slave address for this device.
+
+ I2CManager::scanRegisters() can be used to scan for available I2C devices connected
+ to the system.
+*/
+I2CDevice::I2CDevice(const QString &portName, int address, QObject *parent):
+ QObject(parent),
+ m_portName(portName),
+ m_address(address)
+{
+
+}
+
+I2CDevice::~I2CDevice()
+{
+}
+
+/*! Returns the port name of this I2C device. */
+QString I2CDevice::portName() const
+{
+ return m_portName;
+}
+
+/*! Returns the address of this I2C device. */
+int I2CDevice::address() const
+{
+ return m_address;
+}
+
+QByteArray I2CDevice::readData(int fileDescriptor)
+{
+ Q_UNUSED(fileDescriptor)
+ return QByteArray();
+}
+
+bool I2CDevice::writeData(int fileDescriptor, const QByteArray &data)
+{
+ Q_UNUSED(fileDescriptor)
+ Q_UNUSED(data)
+ return false;
+}
+
+QDebug operator<<(QDebug debug, const I2CDevice *i2cDevice)
+{
+ debug.nospace() << "I2CDevice(Port: " << i2cDevice->portName() << ", Address: 0x" << QString::number(i2cDevice->address(), 16) << ")";
+ return debug.space();
+}
diff --git a/libnymea/hardware/i2c/i2cdevice.h b/libnymea/hardware/i2c/i2cdevice.h
new file mode 100644
index 00000000..6ec3986c
--- /dev/null
+++ b/libnymea/hardware/i2c/i2cdevice.h
@@ -0,0 +1,61 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2020, nymea GmbH
+* Contact: contact@nymea.io
+*
+* This file is part of nymea.
+* This project including source code and documentation is protected by
+* copyright law, and remains the property of nymea GmbH. All rights, including
+* reproduction, publication, editing and translation, are reserved. The use of
+* this project is subject to the terms of a license agreement to be concluded
+* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
+* under https://nymea.io/license
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this project may be redistributed and/or modified under the
+* terms of the GNU Lesser General Public License as published by the Free
+* Software Foundation; version 3. This project 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this project. If not, see .
+*
+* For any further details and any questions please contact us under
+* contact@nymea.io or see our FAQ/Licensing Information on
+* https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef I2CDEVICE_H
+#define I2CDEVICE_H
+
+#include
+
+class I2CDevice : public QObject
+{
+ Q_OBJECT
+public:
+ explicit I2CDevice(const QString &portName, int address, QObject *parent = nullptr);
+ virtual ~I2CDevice();
+
+ QString portName() const;
+ int address() const;
+
+ virtual QByteArray readData(int fileDescriptor);
+ virtual bool writeData(int fileDescriptor, const QByteArray &data);
+
+signals:
+ void readingAvailable(const QByteArray &data);
+ void dataWritten(bool success);
+
+private:
+ QString m_portName;
+ int m_address;
+};
+
+QDebug operator<<(QDebug debug, const I2CDevice *i2cDevice);
+
+
+#endif // I2CDEVICE_H
diff --git a/libnymea/hardware/i2c/i2cmanager.cpp b/libnymea/hardware/i2c/i2cmanager.cpp
new file mode 100644
index 00000000..36669451
--- /dev/null
+++ b/libnymea/hardware/i2c/i2cmanager.cpp
@@ -0,0 +1,78 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2020, nymea GmbH
+* Contact: contact@nymea.io
+*
+* This file is part of nymea.
+* This project including source code and documentation is protected by
+* copyright law, and remains the property of nymea GmbH. All rights, including
+* reproduction, publication, editing and translation, are reserved. The use of
+* this project is subject to the terms of a license agreement to be concluded
+* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
+* under https://nymea.io/license
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this project may be redistributed and/or modified under the
+* terms of the GNU Lesser General Public License as published by the Free
+* Software Foundation; version 3. This project 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this project. If not, see .
+*
+* For any further details and any questions please contact us under
+* contact@nymea.io or see our FAQ/Licensing Information on
+* https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "i2cmanager.h"
+
+/*! \fn QStringList I2CManager::availablePorts() const
+ Lists the available I2C ports in the system.
+ */
+
+/*! \fn QList I2CManager::scanRegisters(const QString &portName = QString())
+ Scans the I2C systems for connected devices. If \a portName is given, only this port
+ will be scanned. If \a portName is empty, all available ports in the system will be
+ scanned.
+ */
+
+/*! \fn bool I2CManager::open(I2CDevice *i2cDevice)
+ Open the given I2CDevice. After reimplementing an I2CDevice, this method can be used
+ to open the device. Returns false if opening fails, for example because of missing
+ permissions or if the given \ai2cDevice is not valid, for example because of a bad
+ port name or slave address.
+*/
+
+/*! \fn bool I2CManager::startReading(I2CDevice *i2cDevice, int interval = 1000)
+ Start reading from the given \a i2cDevice. When calling this, the I2CManager will start
+ polling the given \a i2cDevice. Optionally, the interface can be given.
+ Note that the interval might not be met, for example if the device is busy by other
+ readers.
+ The given \a i2cDevice is required to be opened first.
+ */
+
+/*! \fn void I2CManager::stopReading(I2CDevice *i2cDevice)
+ Stops reading from the given \a i2cDevice.
+ */
+
+/*! \fn bool I2CManager::writeData(I2CDevice *i2cDevice, const QByteArray &data)
+ Write the given \a data to the given \a i2cDevice.
+ The data will be put into a write buffer and will be written to the device
+ in a different thread when the i2c device is available.
+ The given \a i2cDevice is required to be opened first.
+ */
+
+/*! \fn void I2CManager::close(I2CDevice *i2cDevice)
+ Closes the giben \a i2cDevice. If reading are still active for this device,
+ stopReading() will be called implicitly.
+ */
+
+I2CManager::I2CManager(QObject *parent):
+ QObject(parent)
+{
+
+}
diff --git a/libnymea/hardware/i2c/i2cmanager.h b/libnymea/hardware/i2c/i2cmanager.h
new file mode 100644
index 00000000..3aefbce4
--- /dev/null
+++ b/libnymea/hardware/i2c/i2cmanager.h
@@ -0,0 +1,60 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2020, nymea GmbH
+* Contact: contact@nymea.io
+*
+* This file is part of nymea.
+* This project including source code and documentation is protected by
+* copyright law, and remains the property of nymea GmbH. All rights, including
+* reproduction, publication, editing and translation, are reserved. The use of
+* this project is subject to the terms of a license agreement to be concluded
+* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
+* under https://nymea.io/license
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this project may be redistributed and/or modified under the
+* terms of the GNU Lesser General Public License as published by the Free
+* Software Foundation; version 3. This project 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this project. If not, see .
+*
+* For any further details and any questions please contact us under
+* contact@nymea.io or see our FAQ/Licensing Information on
+* https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef I2CMANAGER_H
+#define I2CMANAGER_H
+
+#include
+
+class I2CDevice;
+
+struct I2CScanResult {
+ QString portName;
+ int address;
+};
+
+class I2CManager : public QObject
+{
+ Q_OBJECT
+public:
+ I2CManager(QObject *parent = nullptr);
+ virtual ~I2CManager() = default;
+
+ virtual QStringList availablePorts() const = 0;
+ virtual QList scanRegisters(const QString &portName = QString()) = 0;
+
+ virtual bool open(I2CDevice *i2cDevice) = 0;
+ virtual bool startReading(I2CDevice *i2cDevice, int interval = 1000) = 0;
+ virtual void stopReading(I2CDevice *i2cDevice) = 0;
+ virtual bool writeData(I2CDevice *i2cDevice, const QByteArray &data) = 0;
+ virtual void close(I2CDevice *i2cDevice) = 0;
+};
+
+#endif // I2CMANAGER_H
diff --git a/libnymea/hardwaremanager.h b/libnymea/hardwaremanager.h
index d351ef38..d5ed2c45 100644
--- a/libnymea/hardwaremanager.h
+++ b/libnymea/hardwaremanager.h
@@ -41,6 +41,7 @@ class UpnpDeviceDescriptor;
class PlatformZeroConfController;
class BluetoothLowEnergyManager;
class MqttProvider;
+class I2CManager;
class HardwareResource;
class HardwareManager : public QObject
@@ -59,6 +60,7 @@ public:
virtual PlatformZeroConfController *zeroConfController() = 0;
virtual BluetoothLowEnergyManager *bluetoothLowEnergyManager() = 0;
virtual MqttProvider *mqttProvider() = 0;
+ virtual I2CManager *i2cManager() = 0;
protected:
void setResourceEnabled(HardwareResource* resource, bool enabled);
diff --git a/libnymea/libnymea.pro b/libnymea/libnymea.pro
index b8662168..76ff4cda 100644
--- a/libnymea/libnymea.pro
+++ b/libnymea/libnymea.pro
@@ -56,6 +56,8 @@ HEADERS += \
hardware/bluetoothlowenergy/bluetoothlowenergydevice.h \
hardware/bluetoothlowenergy/bluetoothdiscoveryreply.h \
hardware/bluetoothlowenergy/bluetoothlowenergymanager.h \
+ hardware/i2c/i2cmanager.h \
+ hardware/i2c/i2cdevice.h \
coap/coap.h \
coap/coappdu.h \
coap/coapoption.h \
@@ -133,6 +135,8 @@ SOURCES += \
hardware/bluetoothlowenergy/bluetoothlowenergymanager.cpp \
hardware/bluetoothlowenergy/bluetoothlowenergydevice.cpp \
hardware/bluetoothlowenergy/bluetoothdiscoveryreply.cpp \
+ hardware/i2c/i2cmanager.cpp \
+ hardware/i2c/i2cdevice.cpp \
coap/coap.cpp \
coap/coappdu.cpp \
coap/coapoption.cpp \
diff --git a/libnymea/loggingcategories.cpp b/libnymea/loggingcategories.cpp
index ee549c92..86b41c30 100644
--- a/libnymea/loggingcategories.cpp
+++ b/libnymea/loggingcategories.cpp
@@ -72,6 +72,7 @@ Q_LOGGING_CATEGORY(dcBluetoothServer, "BluetoothServer")
Q_LOGGING_CATEGORY(dcBluetoothServerTraffic, "BluetoothServerTraffic")
Q_LOGGING_CATEGORY(dcMqtt, "Mqtt")
Q_LOGGING_CATEGORY(dcTranslations, "Translations")
+Q_LOGGING_CATEGORY(dcI2C, "I2C")
static QFile s_logFile;
diff --git a/libnymea/loggingcategories.h b/libnymea/loggingcategories.h
index 5faca21b..7ace86f3 100644
--- a/libnymea/loggingcategories.h
+++ b/libnymea/loggingcategories.h
@@ -75,6 +75,7 @@ Q_DECLARE_LOGGING_CATEGORY(dcBluetoothServerTraffic)
Q_DECLARE_LOGGING_CATEGORY(dcMqtt)
Q_DECLARE_LOGGING_CATEGORY(dcTranslations)
Q_DECLARE_LOGGING_CATEGORY(dcCoap)
+Q_DECLARE_LOGGING_CATEGORY(dcI2C)
/*
Installs a nymea log message handler in the system.