mirror of
https://github.com/nymea/nymea-plugins.git
synced 2026-07-15 00:22:26 +02:00
Add arduino and abstract transport
This commit is contained in:
parent
1852044ef1
commit
f7872915d0
@ -37,70 +37,104 @@
|
||||
#include "network/zeroconf/zeroconfservicebrowser.h"
|
||||
#include "network/zeroconf/zeroconfserviceentry.h"
|
||||
|
||||
#include "owlettcptransport.h"
|
||||
#include "owletserialtransport.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QTimer>
|
||||
|
||||
static QHash<ThingClassId, ParamTypeId> idParamTypeMap = {
|
||||
{ digitalOutputThingClassId, digitalOutputThingOwletIdParamTypeId },
|
||||
{ digitalInputThingClassId, digitalInputThingOwletIdParamTypeId },
|
||||
{ ws2812ThingClassId, ws2812ThingOwletIdParamTypeId }
|
||||
};
|
||||
|
||||
IntegrationPluginOwlet::IntegrationPluginOwlet()
|
||||
{
|
||||
}
|
||||
|
||||
void IntegrationPluginOwlet::init()
|
||||
{
|
||||
m_owletIdParamTypeMap.insert(digitalOutputThingClassId, digitalOutputThingOwletIdParamTypeId);
|
||||
m_owletIdParamTypeMap.insert(digitalInputThingClassId, digitalInputThingOwletIdParamTypeId);
|
||||
m_owletIdParamTypeMap.insert(ws2812ThingClassId, ws2812ThingOwletIdParamTypeId);
|
||||
|
||||
m_owletSerialPortParamTypeMap.insert(arduinoMiniProThingClassId, arduinoMiniProThingSerialPortParamTypeId);
|
||||
|
||||
m_zeroConfBrowser = hardwareManager()->zeroConfController()->createServiceBrowser("_nymea-owlet._tcp");
|
||||
}
|
||||
|
||||
void IntegrationPluginOwlet::discoverThings(ThingDiscoveryInfo *info)
|
||||
{
|
||||
foreach (const ZeroConfServiceEntry &entry, m_zeroConfBrowser->serviceEntries()) {
|
||||
qCDebug(dcOwlet()) << "Found owlet:" << entry;
|
||||
ThingDescriptor descriptor(info->thingClassId(), entry.name(), entry.txt("platform"));
|
||||
descriptor.setParams(ParamList() << Param(idParamTypeMap.value(info->thingClassId()), entry.txt("id")));
|
||||
foreach (Thing *existingThing, myThings().filterByParam(idParamTypeMap.value(info->thingClassId()), entry.txt("id"))) {
|
||||
descriptor.setThingId(existingThing->id());
|
||||
break;
|
||||
if (info->thingClassId() == arduinoMiniProThingClassId) {
|
||||
// Discover serial ports for arduino bords
|
||||
foreach(QSerialPortInfo port, QSerialPortInfo::availablePorts()) {
|
||||
qCDebug(dcOwlet()) << "Found serial port" << port.systemLocation();
|
||||
QString description = port.systemLocation() + " " + port.manufacturer() + " " + port.description();
|
||||
ThingDescriptor thingDescriptor(info->thingClassId(), "Owlet Arduino Pro Mini", description);
|
||||
ParamList parameters;
|
||||
|
||||
foreach (Thing *existingThing, myThings()) {
|
||||
if (existingThing->paramValue(m_owletSerialPortParamTypeMap.value(info->thingClassId())).toString() == port.systemLocation()) {
|
||||
thingDescriptor.setThingId(existingThing->id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
parameters.append(Param(m_owletSerialPortParamTypeMap.value(info->thingClassId()), port.systemLocation()));
|
||||
thingDescriptor.setParams(parameters);
|
||||
info->addThingDescriptor(thingDescriptor);
|
||||
}
|
||||
info->addThingDescriptor(descriptor);
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
} else {
|
||||
foreach (const ZeroConfServiceEntry &entry, m_zeroConfBrowser->serviceEntries()) {
|
||||
qCDebug(dcOwlet()) << "Found owlet:" << entry;
|
||||
ThingDescriptor descriptor(info->thingClassId(), entry.name(), entry.txt("platform"));
|
||||
descriptor.setParams(ParamList() << Param(m_owletIdParamTypeMap.value(info->thingClassId()), entry.txt("id")));
|
||||
foreach (Thing *existingThing, myThings().filterByParam(m_owletIdParamTypeMap.value(info->thingClassId()), entry.txt("id"))) {
|
||||
descriptor.setThingId(existingThing->id());
|
||||
break;
|
||||
}
|
||||
info->addThingDescriptor(descriptor);
|
||||
}
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
|
||||
void IntegrationPluginOwlet::setupThing(ThingSetupInfo *info)
|
||||
{
|
||||
Thing *thing = info->thing();
|
||||
|
||||
OwletTransport *transport = nullptr;
|
||||
QHostAddress ip;
|
||||
int port = 5555;
|
||||
foreach (const ZeroConfServiceEntry &entry, m_zeroConfBrowser->serviceEntries()) {
|
||||
if (entry.txt("id") == info->thing()->paramValue(idParamTypeMap.value(info->thing()->thingClassId()))) {
|
||||
ip = entry.hostAddress();
|
||||
port = entry.port();
|
||||
break;
|
||||
|
||||
if (thing->thingClassId() != arduinoMiniProThingClassId) {
|
||||
foreach (const ZeroConfServiceEntry &entry, m_zeroConfBrowser->serviceEntries()) {
|
||||
if (entry.txt("id") == info->thing()->paramValue(m_owletIdParamTypeMap.value(info->thing()->thingClassId()))) {
|
||||
ip = entry.hostAddress();
|
||||
port = entry.port();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Try cached ip
|
||||
if (ip.isNull()) {
|
||||
pluginStorage()->beginGroup(thing->id().toString());
|
||||
ip = QHostAddress(pluginStorage()->value("cachedIP").toString());
|
||||
pluginStorage()->endGroup();
|
||||
// Try cached ip
|
||||
if (ip.isNull()) {
|
||||
pluginStorage()->beginGroup(thing->id().toString());
|
||||
ip = QHostAddress(pluginStorage()->value("cachedIP").toString());
|
||||
pluginStorage()->endGroup();
|
||||
}
|
||||
|
||||
if (ip.isNull()) {
|
||||
qCWarning(dcOwlet()) << "Can't find owlet in the local network.";
|
||||
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||
return;
|
||||
}
|
||||
|
||||
transport = new OwletTcpTransport(ip, port, this);
|
||||
|
||||
} else if (thing->thingClassId() == arduinoMiniProThingClassId) {
|
||||
QString serialPort = thing->paramValue(arduinoMiniProThingSerialPortParamTypeId).toString();
|
||||
qCDebug(dcOwlet()) << "Setup arduino mini pro owlet on" << serialPort;
|
||||
transport = new OwletSerialTransport(serialPort, 115200, this);
|
||||
}
|
||||
|
||||
if (ip.isNull()) {
|
||||
qCWarning(dcOwlet()) << "Can't find owlet in the local network.";
|
||||
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||
return;
|
||||
}
|
||||
|
||||
OwletClient *client = new OwletClient(this);
|
||||
|
||||
OwletClient *client = new OwletClient(transport, this);
|
||||
connect(client, &OwletClient::connected, info, [=](){
|
||||
qCDebug(dcOwlet()) << "Connected to owleet";
|
||||
qCDebug(dcOwlet()) << "Connected to owlet";
|
||||
m_clients.insert(thing, client);
|
||||
|
||||
if (thing->thingClassId() == digitalOutputThingClassId) {
|
||||
@ -127,15 +161,31 @@ void IntegrationPluginOwlet::setupThing(ThingSetupInfo *info)
|
||||
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
});
|
||||
|
||||
connect(client, &OwletClient::error, info, [=](){
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
});
|
||||
|
||||
connect(client, &OwletClient::connected, thing, [=](){
|
||||
thing->setStateValue("connected", true);
|
||||
pluginStorage()->beginGroup(thing->id().toString());
|
||||
pluginStorage()->setValue("cachedIP", ip.toString());
|
||||
pluginStorage()->endGroup();
|
||||
|
||||
// FIXME: find a better way
|
||||
if (thing->thingClassId() != arduinoMiniProThingClassId) {
|
||||
pluginStorage()->beginGroup(thing->id().toString());
|
||||
pluginStorage()->setValue("cachedIP", ip.toString());
|
||||
pluginStorage()->endGroup();
|
||||
}
|
||||
|
||||
qCDebug(dcOwlet()) << "Sending get platform information request...";
|
||||
int id = client->sendCommand("Platform.GetInformation");
|
||||
connect(client, &OwletClient::replyReceived, thing, [=](int commandId, const QVariantMap ¶ms){
|
||||
if (id != commandId)
|
||||
return;
|
||||
|
||||
qCDebug(dcOwlet()) << "Reply from owlet platform information:" << params;
|
||||
});
|
||||
});
|
||||
|
||||
connect(client, &OwletClient::disconnected, thing, [=](){
|
||||
thing->setStateValue("connected", false);
|
||||
});
|
||||
@ -170,7 +220,7 @@ void IntegrationPluginOwlet::setupThing(ThingSetupInfo *info)
|
||||
}
|
||||
});
|
||||
|
||||
client->connectToHost(ip, port);
|
||||
client->transport()->connectTransport();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -56,8 +56,9 @@ public:
|
||||
private:
|
||||
ZeroConfServiceBrowser *m_zeroConfBrowser = nullptr;
|
||||
|
||||
QHash<Thing*, OwletClient*> m_clients;
|
||||
|
||||
QHash<Thing *, OwletClient *> m_clients;
|
||||
QHash<ThingClassId, ParamTypeId> m_owletIdParamTypeMap;
|
||||
QHash<ThingClassId, ParamTypeId> m_owletSerialPortParamTypeMap;
|
||||
};
|
||||
|
||||
#endif // INTEGRATIONPLUGINOWLET_H
|
||||
|
||||
@ -219,6 +219,286 @@
|
||||
"writable": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "22f216f4-9715-48f9-ab76-f7d7436d49c9",
|
||||
"name": "arduinoMiniPro",
|
||||
"displayName": "Arduino Pro Mini Owlet",
|
||||
"createMethods": ["user", "discovery"],
|
||||
"interfaces": ["gateway", "connectable"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "589715a6-aaf7-4ffb-9c34-015ac22d527e",
|
||||
"name": "serialPort",
|
||||
"displayName": "Serial port",
|
||||
"type": "QString",
|
||||
"inputType": "TextLine",
|
||||
"defaultValue": "/dev/ttyS0"
|
||||
},
|
||||
{
|
||||
"id": "d9643551-883a-4e33-89a8-6e2e1211eb22",
|
||||
"name": "resetGpio",
|
||||
"displayName": "Reset GPIO",
|
||||
"type": "uint",
|
||||
"defaultValue": 18
|
||||
}
|
||||
],
|
||||
"settingsTypes": [
|
||||
{
|
||||
"id": "82a8d0f5-3b42-4138-ae65-8554e19b73e5",
|
||||
"name": "pin2",
|
||||
"displayName": "Pin 2",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output",
|
||||
"Interrupt"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "3953ad67-69a6-4b5f-8a91-f913d75d7d2f",
|
||||
"name": "pin3",
|
||||
"displayName": "Pin 3",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output",
|
||||
"PWM",
|
||||
"Interrupt"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "cee570df-1669-49df-9eb6-6c28c9cb7aec",
|
||||
"name": "pin4",
|
||||
"displayName": "Pin 4",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "ec366d87-cfdb-4c7e-a23e-20cb8e99b1f5",
|
||||
"name": "pin5",
|
||||
"displayName": "Pin 5",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output",
|
||||
"PWM"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "40354097-c5e5-4d13-b94c-72cb7a97cf71",
|
||||
"name": "pin6",
|
||||
"displayName": "Pin 6",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output",
|
||||
"PWM"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "22e5320f-2f34-4fd5-8699-1e4ddf96a8c8",
|
||||
"name": "pin7",
|
||||
"displayName": "Pin 7",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "9b7b159c-9da1-4811-80e1-835d7743bebc",
|
||||
"name": "pin8",
|
||||
"displayName": "Pin 8",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "0d4aa38d-7607-4361-b8c7-cc5c28e17bb8",
|
||||
"name": "pin9",
|
||||
"displayName": "Pin 9",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output",
|
||||
"PWM"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "d18e6ac5-3bf7-47ac-8b5b-70a9ef8394d5",
|
||||
"name": "pin10",
|
||||
"displayName": "Pin 10",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output",
|
||||
"PWM"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "f0afb81c-dcd4-4d50-84a7-0ed6739c4011",
|
||||
"name": "pin11",
|
||||
"displayName": "Pin 11",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output",
|
||||
"PWM"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "c62ab191-40ab-4d20-8130-a6b37801b984",
|
||||
"name": "pin12",
|
||||
"displayName": "Pin 12",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "4522ce36-ba6f-46b0-a54b-410a93065b34",
|
||||
"name": "pin13",
|
||||
"displayName": "Pin 13 (LED)",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "d6cf8433-acef-4312-836b-b34be6592e22",
|
||||
"name": "pinA1",
|
||||
"displayName": "Pin A1",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output",
|
||||
"Analog Input"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "e22fd058-8eab-4450-a2ef-2f85c347602c",
|
||||
"name": "pinA2",
|
||||
"displayName": "Pin A2",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output",
|
||||
"Analog Input"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "1702602e-6c05-4dea-b0ff-89af8ec63a88",
|
||||
"name": "pinA3",
|
||||
"displayName": "Pin A3",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output",
|
||||
"Analog Input"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "02b5022f-8892-4e9d-b11e-6fd8a9d4616f",
|
||||
"name": "pinA4",
|
||||
"displayName": "Pin A4",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output",
|
||||
"Analog Input"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "704e2a48-b1f4-400e-a378-d7e546f2083d",
|
||||
"name": "pinA5",
|
||||
"displayName": "Pin A5",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output",
|
||||
"Analog Input"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "69c85170-9447-4a01-acd2-926fbe03489f",
|
||||
"name": "pinA6",
|
||||
"displayName": "Pin A6",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output",
|
||||
"Analog Input"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
"id": "3ad3b667-b51f-4deb-b5d3-8cad1e0fdbba",
|
||||
"name": "pinA7",
|
||||
"displayName": "Pin A7",
|
||||
"type": "QString",
|
||||
"allowedValues": [
|
||||
"None",
|
||||
"Input",
|
||||
"Output",
|
||||
"Analog Input"
|
||||
],
|
||||
"defaultValue": "None"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "9a7d9a6a-f131-4f18-bfc0-956c2dba9329",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"cached": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,13 +1,19 @@
|
||||
include(../plugins.pri)
|
||||
|
||||
QT += network
|
||||
QT += network serialport
|
||||
|
||||
SOURCES += \
|
||||
integrationpluginowlet.cpp \
|
||||
owletclient.cpp
|
||||
owletclient.cpp \
|
||||
owletserialtransport.cpp \
|
||||
owlettcptransport.cpp \
|
||||
owlettransport.cpp
|
||||
|
||||
HEADERS += \
|
||||
integrationpluginowlet.h \
|
||||
owletclient.h
|
||||
owletclient.h \
|
||||
owletserialtransport.h \
|
||||
owlettcptransport.h \
|
||||
owlettransport.h
|
||||
|
||||
|
||||
|
||||
@ -1,49 +1,33 @@
|
||||
#include "owletclient.h"
|
||||
|
||||
#include "owlettransport.h"
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QTimer>
|
||||
|
||||
OwletClient::OwletClient(QObject *parent) : QObject(parent)
|
||||
OwletClient::OwletClient(OwletTransport *transport, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_transport(transport)
|
||||
{
|
||||
|
||||
connect(m_transport, &OwletTransport::dataReceived, this, &OwletClient::dataReceived);
|
||||
connect(m_transport, &OwletTransport::error, this, &OwletClient::error);
|
||||
connect(m_transport, &OwletTransport::connectedChanged, this, [=](bool isConnected){
|
||||
if (isConnected) {
|
||||
emit connected();
|
||||
} else {
|
||||
emit disconnected();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void OwletClient::connectToHost(const QHostAddress &address, int port)
|
||||
OwletTransport *OwletClient::transport() const
|
||||
{
|
||||
if (m_socket) {
|
||||
m_socket->abort();
|
||||
m_socket->deleteLater();
|
||||
}
|
||||
|
||||
m_socket = new QTcpSocket(this);
|
||||
connect(m_socket, &QTcpSocket::connected, this, [this](){
|
||||
emit connected();
|
||||
});
|
||||
connect(m_socket, &QTcpSocket::disconnected, this, [this, address, port](){
|
||||
qCDebug(dcOwlet()) << "Disconnected from owleet";
|
||||
emit disconnected();
|
||||
QTimer::singleShot(1000, this, [=]{
|
||||
connectToHost(address, port);
|
||||
});
|
||||
|
||||
});
|
||||
typedef void (QTcpSocket:: *errorSignal)(QAbstractSocket::SocketError);
|
||||
connect(m_socket, static_cast<errorSignal>(&QTcpSocket::error), this, [this](){
|
||||
qCDebug(dcOwlet()) << "Error in owlet communication";
|
||||
emit error();
|
||||
});
|
||||
|
||||
connect(m_socket, &QTcpSocket::readyRead, this, [this](){
|
||||
dataReceived(m_socket->readAll());
|
||||
});
|
||||
m_socket->connectToHost(address, port);
|
||||
return m_transport;
|
||||
}
|
||||
|
||||
int OwletClient::sendCommand(const QString &method, const QVariantMap ¶ms)
|
||||
{
|
||||
if (!m_socket) {
|
||||
if (!m_transport->connected()) {
|
||||
qCWarning(dcOwlet()) << "Not connected to owlet. Not sending command.";
|
||||
return -1;
|
||||
}
|
||||
@ -54,7 +38,7 @@ int OwletClient::sendCommand(const QString &method, const QVariantMap ¶ms)
|
||||
packet.insert("id", id);
|
||||
packet.insert("method", method);
|
||||
packet.insert("params", params);
|
||||
m_socket->write(QJsonDocument::fromVariant(packet).toJson(QJsonDocument::Compact));
|
||||
m_transport->sendData(QJsonDocument::fromVariant(packet).toJson(QJsonDocument::Compact));
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
@ -5,15 +5,17 @@
|
||||
#include <QHostAddress>
|
||||
#include <QTcpSocket>
|
||||
|
||||
class OwletTransport;
|
||||
|
||||
class OwletClient : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OwletClient(QObject *parent = nullptr);
|
||||
explicit OwletClient(OwletTransport *transport, QObject *parent = nullptr);
|
||||
|
||||
void connectToHost(const QHostAddress &address, int port);
|
||||
OwletTransport *transport() const;
|
||||
|
||||
int sendCommand(const QString &method, const QVariantMap ¶ms);
|
||||
int sendCommand(const QString &method, const QVariantMap ¶ms = QVariantMap());
|
||||
|
||||
signals:
|
||||
void connected();
|
||||
@ -27,7 +29,7 @@ private slots:
|
||||
void dataReceived(const QByteArray &data);
|
||||
|
||||
private:
|
||||
QTcpSocket *m_socket = nullptr;
|
||||
OwletTransport *m_transport = nullptr;
|
||||
int m_commandId = 0;
|
||||
|
||||
QByteArray m_receiveBuffer;
|
||||
|
||||
168
owlet/owletserialtransport.cpp
Normal file
168
owlet/owletserialtransport.cpp
Normal file
@ -0,0 +1,168 @@
|
||||
#include "owletserialtransport.h"
|
||||
#include "owlettransport.h"
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
#include <QDataStream>
|
||||
|
||||
OwletSerialTransport::OwletSerialTransport(const QString &serialPortName, uint baudrate, QObject *parent) :
|
||||
OwletTransport(parent),
|
||||
m_serialPortName(serialPortName),
|
||||
m_baudrate(baudrate)
|
||||
{
|
||||
qRegisterMetaType<QSerialPort::SerialPortError>();
|
||||
|
||||
m_serialPort = new QSerialPort(this);
|
||||
m_serialPort->setPortName(serialPortName);
|
||||
m_serialPort->setBaudRate(115200);
|
||||
m_serialPort->setDataBits(QSerialPort::DataBits::Data8);
|
||||
m_serialPort->setParity(QSerialPort::Parity::NoParity);
|
||||
m_serialPort->setStopBits(QSerialPort::StopBits::OneStop);
|
||||
m_serialPort->setFlowControl(QSerialPort::FlowControl::NoFlowControl);
|
||||
|
||||
connect(m_serialPort, &QSerialPort::readyRead, this, &OwletSerialTransport::onReadyRead);
|
||||
connect(m_serialPort, &QSerialPort::errorOccurred, this, [=](QSerialPort::SerialPortError serialPortError){
|
||||
if (serialPortError != QSerialPort::NoError) {
|
||||
qCWarning(dcOwlet()) << "Serial port error occured" << serialPortError << m_serialPort->errorString();
|
||||
emit error();
|
||||
m_reconnectTimer->start();
|
||||
if (m_serialPort->isOpen()) {
|
||||
m_serialPort->close();
|
||||
}
|
||||
emit connectedChanged(false);
|
||||
}
|
||||
});
|
||||
|
||||
m_reconnectTimer = new QTimer(this);
|
||||
m_reconnectTimer->setInterval(5000);
|
||||
m_reconnectTimer->setSingleShot(false);
|
||||
connect(m_reconnectTimer, &QTimer::timeout, this, [=](){
|
||||
if (m_serialPort->isOpen()) {
|
||||
m_reconnectTimer->stop();
|
||||
return;
|
||||
} else {
|
||||
connectTransport();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool OwletSerialTransport::connected() const
|
||||
{
|
||||
return m_serialPort->isOpen();
|
||||
}
|
||||
|
||||
void OwletSerialTransport::sendData(const QByteArray &data)
|
||||
{
|
||||
// Stream bytes using SLIP
|
||||
QByteArray message;
|
||||
QDataStream stream(&message, QIODevice::WriteOnly);
|
||||
stream << static_cast<quint8>(SlipProtocolEnd);
|
||||
|
||||
for (int i = 0; i < data.length(); i++) {
|
||||
quint8 dataByte = data.at(i);
|
||||
switch (dataByte) {
|
||||
case SlipProtocolEnd:
|
||||
stream << static_cast<quint8>(SlipProtocolEsc);
|
||||
stream << static_cast<quint8>(SlipProtocolTransposedEnd);
|
||||
break;
|
||||
case SlipProtocolEsc:
|
||||
stream << static_cast<quint8>(SlipProtocolEsc);
|
||||
stream << static_cast<quint8>(SlipProtocolTransposedEsc);
|
||||
break;
|
||||
default:
|
||||
stream << dataByte;
|
||||
break;
|
||||
}
|
||||
}
|
||||
stream << static_cast<quint8>(SlipProtocolEnd);
|
||||
|
||||
qCDebug(dcOwlet()) << "UART -->" << qUtf8Printable(data) << message.toHex();
|
||||
m_serialPort->write(message);
|
||||
m_serialPort->flush();
|
||||
}
|
||||
|
||||
void OwletSerialTransport::connectTransport()
|
||||
{
|
||||
if (m_serialPort->isOpen())
|
||||
return;
|
||||
|
||||
qCDebug(dcOwlet()) << "Connecting to" << m_serialPortName;
|
||||
bool serialPortFound = false;
|
||||
foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) {
|
||||
if (serialPortInfo.systemLocation() == m_serialPortName) {
|
||||
serialPortFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent repeating warnings...
|
||||
if (!serialPortFound) {
|
||||
if (!m_reconnectTimer->isActive()) {
|
||||
m_reconnectTimer->start();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!m_serialPort->open(QIODevice::ReadWrite)) {
|
||||
qCWarning(dcOwlet()) << "Could not open serial port on" << m_serialPortName << m_serialPort->errorString();
|
||||
m_reconnectTimer->start();
|
||||
return;
|
||||
}
|
||||
|
||||
m_reconnectTimer->stop();
|
||||
emit connectedChanged(true);
|
||||
}
|
||||
|
||||
void OwletSerialTransport::disconnectTransport()
|
||||
{
|
||||
if (m_serialPort->isOpen()) {
|
||||
m_serialPort->close();
|
||||
emit connectedChanged(false);
|
||||
}
|
||||
}
|
||||
|
||||
void OwletSerialTransport::onReadyRead()
|
||||
{
|
||||
QByteArray data = m_serialPort->readAll();
|
||||
qCDebug(dcOwlet()) << "UART <-- raw:" << data.toHex() << qUtf8Printable(data);
|
||||
|
||||
for (int i = 0; i < data.length(); i++) {
|
||||
quint8 receivedByte = data.at(i);
|
||||
|
||||
if (m_protocolEscaping) {
|
||||
switch (receivedByte) {
|
||||
case SlipProtocolTransposedEnd:
|
||||
m_buffer.append(static_cast<quint8>(SlipProtocolEnd));
|
||||
m_protocolEscaping = false;
|
||||
break;
|
||||
case SlipProtocolTransposedEsc:
|
||||
m_buffer.append(static_cast<quint8>(SlipProtocolEsc));
|
||||
m_protocolEscaping = false;
|
||||
break;
|
||||
default:
|
||||
// SLIP protocol violation...received escape, but it is not an escaped byte
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (receivedByte) {
|
||||
case SlipProtocolEnd:
|
||||
// We are done with this package, process it and reset the buffer
|
||||
if (!m_buffer.isEmpty() && m_buffer.length() >= 3) {
|
||||
qCDebug(dcOwlet()) << "UART <--" << m_buffer.toHex() << qUtf8Printable(m_buffer);
|
||||
emit dataReceived(m_buffer);
|
||||
}
|
||||
m_buffer.clear();
|
||||
m_protocolEscaping = false;
|
||||
break;
|
||||
case SlipProtocolEsc:
|
||||
// The next byte will be escaped, lets wait for it
|
||||
m_protocolEscaping = true;
|
||||
break;
|
||||
default:
|
||||
// Nothing special, just add to buffer
|
||||
m_buffer.append(receivedByte);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
45
owlet/owletserialtransport.h
Normal file
45
owlet/owletserialtransport.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef OWLETSERIALTRANSPORT_H
|
||||
#define OWLETSERIALTRANSPORT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QSerialPort>
|
||||
#include <QSerialPortInfo>
|
||||
|
||||
#include "owlettransport.h"
|
||||
|
||||
class OwletSerialTransport : public OwletTransport
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OwletSerialTransport(const QString &serialPortName, uint baudrate, QObject *parent = nullptr);
|
||||
|
||||
bool connected() const override;
|
||||
void sendData(const QByteArray &data) override;
|
||||
|
||||
public slots:
|
||||
void connectTransport() override;
|
||||
void disconnectTransport() override;
|
||||
|
||||
private slots:
|
||||
void onReadyRead();
|
||||
|
||||
private:
|
||||
|
||||
enum SlipProtocol {
|
||||
SlipProtocolEnd = 0xC0,
|
||||
SlipProtocolEsc = 0xDB,
|
||||
SlipProtocolTransposedEnd = 0xDC,
|
||||
SlipProtocolTransposedEsc = 0xDD
|
||||
};
|
||||
|
||||
QSerialPort *m_serialPort = nullptr;
|
||||
QTimer *m_reconnectTimer = nullptr;
|
||||
QString m_serialPortName;
|
||||
uint m_baudrate;
|
||||
|
||||
QByteArray m_buffer;
|
||||
bool m_protocolEscaping = false;
|
||||
};
|
||||
|
||||
#endif // OWLETSERIALTRANSPORT_H
|
||||
51
owlet/owlettcptransport.cpp
Normal file
51
owlet/owlettcptransport.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include "owlettcptransport.h"
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
OwletTcpTransport::OwletTcpTransport(const QHostAddress &hostAddress, quint16 port, QObject *parent) :
|
||||
OwletTransport(parent),
|
||||
m_socket(new QTcpSocket(this)),
|
||||
m_hostAddress(hostAddress),
|
||||
m_port(port)
|
||||
{
|
||||
connect(m_socket, &QTcpSocket::connected, this, [=](){
|
||||
emit connectedChanged(true);
|
||||
});
|
||||
connect(m_socket, &QTcpSocket::disconnected, this, [=](){
|
||||
qCDebug(dcOwlet()) << "TCP transport: Disconnected from owlet" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port);
|
||||
emit connectedChanged(false);
|
||||
QTimer::singleShot(1000, this, &OwletTcpTransport::connectTransport);
|
||||
});
|
||||
|
||||
typedef void (QTcpSocket:: *errorSignal)(QAbstractSocket::SocketError);
|
||||
connect(m_socket, static_cast<errorSignal>(&QTcpSocket::error), this, [this](){
|
||||
qCDebug(dcOwlet()) << "TCP transport: Error in owlet communication" << m_socket->errorString();
|
||||
emit error();
|
||||
});
|
||||
|
||||
connect(m_socket, &QTcpSocket::readyRead, this, [this](){
|
||||
emit dataReceived(m_socket->readAll());
|
||||
});
|
||||
}
|
||||
|
||||
bool OwletTcpTransport::connected() const
|
||||
{
|
||||
return m_socket->state() == QAbstractSocket::ConnectedState;
|
||||
}
|
||||
|
||||
void OwletTcpTransport::sendData(const QByteArray &data)
|
||||
{
|
||||
m_socket->write(data);
|
||||
}
|
||||
|
||||
void OwletTcpTransport::connectTransport()
|
||||
{
|
||||
qCDebug(dcOwlet()) << "Connecting to" << m_hostAddress << m_port;
|
||||
m_socket->connectToHost(m_hostAddress, m_port);
|
||||
}
|
||||
|
||||
void OwletTcpTransport::disconnectTransport()
|
||||
{
|
||||
m_socket->close();
|
||||
}
|
||||
30
owlet/owlettcptransport.h
Normal file
30
owlet/owlettcptransport.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef OWLETTCPTRANSPORT_H
|
||||
#define OWLETTCPTRANSPORT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QHostAddress>
|
||||
#include <QTcpSocket>
|
||||
|
||||
#include "owlettransport.h"
|
||||
|
||||
class OwletTcpTransport : public OwletTransport
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OwletTcpTransport(const QHostAddress &hostAddress, quint16 port, QObject *parent = nullptr);
|
||||
|
||||
bool connected() const override;
|
||||
void sendData(const QByteArray &data) override;
|
||||
|
||||
public slots:
|
||||
void connectTransport() override;
|
||||
void disconnectTransport() override;
|
||||
|
||||
private:
|
||||
QTcpSocket *m_socket = nullptr;
|
||||
QHostAddress m_hostAddress;
|
||||
quint16 m_port;
|
||||
|
||||
};
|
||||
|
||||
#endif // OWLETTCPTRANSPORT_H
|
||||
11
owlet/owlettransport.cpp
Normal file
11
owlet/owlettransport.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "owlettransport.h"
|
||||
|
||||
OwletTransport::OwletTransport(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool OwletTransport::connected() const
|
||||
{
|
||||
return m_connected;
|
||||
}
|
||||
29
owlet/owlettransport.h
Normal file
29
owlet/owlettransport.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef OWLETTRANSPORT_H
|
||||
#define OWLETTRANSPORT_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class OwletTransport : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OwletTransport(QObject *parent = nullptr);
|
||||
|
||||
virtual bool connected() const;
|
||||
virtual void sendData(const QByteArray &data) = 0;
|
||||
|
||||
public slots:
|
||||
virtual void connectTransport() = 0;
|
||||
virtual void disconnectTransport() = 0;
|
||||
|
||||
signals:
|
||||
void connectedChanged(bool connected);
|
||||
void dataReceived(const QByteArray &data);
|
||||
void error();
|
||||
|
||||
protected:
|
||||
bool m_connected;
|
||||
|
||||
};
|
||||
|
||||
#endif // OWLETTRANSPORT_H
|
||||
Loading…
x
Reference in New Issue
Block a user