mirror of
https://github.com/nymea/nymea-plugins.git
synced 2026-10-22 14:33:25 +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/zeroconfservicebrowser.h"
|
||||||
#include "network/zeroconf/zeroconfserviceentry.h"
|
#include "network/zeroconf/zeroconfserviceentry.h"
|
||||||
|
|
||||||
|
#include "owlettcptransport.h"
|
||||||
|
#include "owletserialtransport.h"
|
||||||
|
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
static QHash<ThingClassId, ParamTypeId> idParamTypeMap = {
|
|
||||||
{ digitalOutputThingClassId, digitalOutputThingOwletIdParamTypeId },
|
|
||||||
{ digitalInputThingClassId, digitalInputThingOwletIdParamTypeId },
|
|
||||||
{ ws2812ThingClassId, ws2812ThingOwletIdParamTypeId }
|
|
||||||
};
|
|
||||||
|
|
||||||
IntegrationPluginOwlet::IntegrationPluginOwlet()
|
IntegrationPluginOwlet::IntegrationPluginOwlet()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginOwlet::init()
|
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");
|
m_zeroConfBrowser = hardwareManager()->zeroConfController()->createServiceBrowser("_nymea-owlet._tcp");
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginOwlet::discoverThings(ThingDiscoveryInfo *info)
|
void IntegrationPluginOwlet::discoverThings(ThingDiscoveryInfo *info)
|
||||||
{
|
{
|
||||||
foreach (const ZeroConfServiceEntry &entry, m_zeroConfBrowser->serviceEntries()) {
|
if (info->thingClassId() == arduinoMiniProThingClassId) {
|
||||||
qCDebug(dcOwlet()) << "Found owlet:" << entry;
|
// Discover serial ports for arduino bords
|
||||||
ThingDescriptor descriptor(info->thingClassId(), entry.name(), entry.txt("platform"));
|
foreach(QSerialPortInfo port, QSerialPortInfo::availablePorts()) {
|
||||||
descriptor.setParams(ParamList() << Param(idParamTypeMap.value(info->thingClassId()), entry.txt("id")));
|
qCDebug(dcOwlet()) << "Found serial port" << port.systemLocation();
|
||||||
foreach (Thing *existingThing, myThings().filterByParam(idParamTypeMap.value(info->thingClassId()), entry.txt("id"))) {
|
QString description = port.systemLocation() + " " + port.manufacturer() + " " + port.description();
|
||||||
descriptor.setThingId(existingThing->id());
|
ThingDescriptor thingDescriptor(info->thingClassId(), "Owlet Arduino Pro Mini", description);
|
||||||
break;
|
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)
|
void IntegrationPluginOwlet::setupThing(ThingSetupInfo *info)
|
||||||
{
|
{
|
||||||
Thing *thing = info->thing();
|
Thing *thing = info->thing();
|
||||||
|
OwletTransport *transport = nullptr;
|
||||||
QHostAddress ip;
|
QHostAddress ip;
|
||||||
int port = 5555;
|
int port = 5555;
|
||||||
foreach (const ZeroConfServiceEntry &entry, m_zeroConfBrowser->serviceEntries()) {
|
|
||||||
if (entry.txt("id") == info->thing()->paramValue(idParamTypeMap.value(info->thing()->thingClassId()))) {
|
if (thing->thingClassId() != arduinoMiniProThingClassId) {
|
||||||
ip = entry.hostAddress();
|
foreach (const ZeroConfServiceEntry &entry, m_zeroConfBrowser->serviceEntries()) {
|
||||||
port = entry.port();
|
if (entry.txt("id") == info->thing()->paramValue(m_owletIdParamTypeMap.value(info->thing()->thingClassId()))) {
|
||||||
break;
|
ip = entry.hostAddress();
|
||||||
|
port = entry.port();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
// Try cached ip
|
||||||
// Try cached ip
|
if (ip.isNull()) {
|
||||||
if (ip.isNull()) {
|
pluginStorage()->beginGroup(thing->id().toString());
|
||||||
pluginStorage()->beginGroup(thing->id().toString());
|
ip = QHostAddress(pluginStorage()->value("cachedIP").toString());
|
||||||
ip = QHostAddress(pluginStorage()->value("cachedIP").toString());
|
pluginStorage()->endGroup();
|
||||||
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()) {
|
OwletClient *client = new OwletClient(transport, this);
|
||||||
qCWarning(dcOwlet()) << "Can't find owlet in the local network.";
|
|
||||||
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OwletClient *client = new OwletClient(this);
|
|
||||||
|
|
||||||
connect(client, &OwletClient::connected, info, [=](){
|
connect(client, &OwletClient::connected, info, [=](){
|
||||||
qCDebug(dcOwlet()) << "Connected to owleet";
|
qCDebug(dcOwlet()) << "Connected to owlet";
|
||||||
m_clients.insert(thing, client);
|
m_clients.insert(thing, client);
|
||||||
|
|
||||||
if (thing->thingClassId() == digitalOutputThingClassId) {
|
if (thing->thingClassId() == digitalOutputThingClassId) {
|
||||||
@ -127,15 +161,31 @@ void IntegrationPluginOwlet::setupThing(ThingSetupInfo *info)
|
|||||||
|
|
||||||
info->finish(Thing::ThingErrorNoError);
|
info->finish(Thing::ThingErrorNoError);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(client, &OwletClient::error, info, [=](){
|
connect(client, &OwletClient::error, info, [=](){
|
||||||
info->finish(Thing::ThingErrorHardwareFailure);
|
info->finish(Thing::ThingErrorHardwareFailure);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(client, &OwletClient::connected, thing, [=](){
|
connect(client, &OwletClient::connected, thing, [=](){
|
||||||
thing->setStateValue("connected", true);
|
thing->setStateValue("connected", true);
|
||||||
pluginStorage()->beginGroup(thing->id().toString());
|
|
||||||
pluginStorage()->setValue("cachedIP", ip.toString());
|
// FIXME: find a better way
|
||||||
pluginStorage()->endGroup();
|
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, [=](){
|
connect(client, &OwletClient::disconnected, thing, [=](){
|
||||||
thing->setStateValue("connected", false);
|
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:
|
private:
|
||||||
ZeroConfServiceBrowser *m_zeroConfBrowser = nullptr;
|
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
|
#endif // INTEGRATIONPLUGINOWLET_H
|
||||||
|
|||||||
@ -219,6 +219,286 @@
|
|||||||
"writable": true
|
"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)
|
include(../plugins.pri)
|
||||||
|
|
||||||
QT += network
|
QT += network serialport
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
integrationpluginowlet.cpp \
|
integrationpluginowlet.cpp \
|
||||||
owletclient.cpp
|
owletclient.cpp \
|
||||||
|
owletserialtransport.cpp \
|
||||||
|
owlettcptransport.cpp \
|
||||||
|
owlettransport.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
integrationpluginowlet.h \
|
integrationpluginowlet.h \
|
||||||
owletclient.h
|
owletclient.h \
|
||||||
|
owletserialtransport.h \
|
||||||
|
owlettcptransport.h \
|
||||||
|
owlettransport.h
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,49 +1,33 @@
|
|||||||
#include "owletclient.h"
|
#include "owletclient.h"
|
||||||
|
#include "owlettransport.h"
|
||||||
#include "extern-plugininfo.h"
|
#include "extern-plugininfo.h"
|
||||||
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QTimer>
|
#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) {
|
return m_transport;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int OwletClient::sendCommand(const QString &method, const QVariantMap ¶ms)
|
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.";
|
qCWarning(dcOwlet()) << "Not connected to owlet. Not sending command.";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -54,7 +38,7 @@ int OwletClient::sendCommand(const QString &method, const QVariantMap ¶ms)
|
|||||||
packet.insert("id", id);
|
packet.insert("id", id);
|
||||||
packet.insert("method", method);
|
packet.insert("method", method);
|
||||||
packet.insert("params", params);
|
packet.insert("params", params);
|
||||||
m_socket->write(QJsonDocument::fromVariant(packet).toJson(QJsonDocument::Compact));
|
m_transport->sendData(QJsonDocument::fromVariant(packet).toJson(QJsonDocument::Compact));
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,15 +5,17 @@
|
|||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
|
|
||||||
|
class OwletTransport;
|
||||||
|
|
||||||
class OwletClient : public QObject
|
class OwletClient : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
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:
|
signals:
|
||||||
void connected();
|
void connected();
|
||||||
@ -27,7 +29,7 @@ private slots:
|
|||||||
void dataReceived(const QByteArray &data);
|
void dataReceived(const QByteArray &data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTcpSocket *m_socket = nullptr;
|
OwletTransport *m_transport = nullptr;
|
||||||
int m_commandId = 0;
|
int m_commandId = 0;
|
||||||
|
|
||||||
QByteArray m_receiveBuffer;
|
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