diff --git a/i2cdevices/i2cdevices.pro b/i2cdevices/i2cdevices.pro index b6b22cbd9..78e7ac776 100644 --- a/i2cdevices/i2cdevices.pro +++ b/i2cdevices/i2cdevices.pro @@ -3,10 +3,12 @@ include(../plugins.pri) HEADERS += \ integrationplugini2cdevices.h \ ads1115channel.h \ + pca9685.h \ pi16adcchannel.h SOURCES += \ integrationplugini2cdevices.cpp \ ads1115channel.cpp \ + pca9685.cpp \ pi16adcchannel.cpp diff --git a/i2cdevices/integrationplugini2cdevices.cpp b/i2cdevices/integrationplugini2cdevices.cpp index e3f3b0b6d..120f0ce90 100644 --- a/i2cdevices/integrationplugini2cdevices.cpp +++ b/i2cdevices/integrationplugini2cdevices.cpp @@ -33,6 +33,7 @@ #include "pi16adcchannel.h" #include "ads1115channel.h" +#include "pca9685.h" #include @@ -122,6 +123,17 @@ void IntegrationPluginI2CDevices::discoverThings(ThingDiscoveryInfo *info) info->finish(Thing::ThingErrorNoError); } +void IntegrationPluginI2CDevices::executeAction(ThingActionInfo *info) +{ + if (info->thing()->thingClassId() == pca9685ThingClassId) { + I2CDevice *pca = m_i2cDevices.key(info->thing()); + if (info->action().actionTypeId() == pca9685FrequencyActionTypeId) { + QByteArray command = "FREQ:" + info->action().paramValue(pca9685FrequencyActionFrequencyParamTypeId).toByteArray(); + hardwareManager()->i2cManager()->writeData(pca, command); + } + } +} + void IntegrationPluginI2CDevices::setupThing(ThingSetupInfo *info) { if (info->thing()->thingClassId() == pi16ADCThingClassId) { @@ -200,6 +212,16 @@ void IntegrationPluginI2CDevices::setupThing(ThingSetupInfo *info) } info->finish(Thing::ThingErrorNoError); } + + if (info->thing()->thingClassId() == pca9685ThingClassId) { + QString i2cPortName = info->thing()->paramValue(ads1115ThingI2cPortParamTypeId).toString(); + int i2cAddress = info->thing()->paramValue(ads1115ThingI2cAddressParamTypeId).toInt(); + Pca9685 *pca = new Pca9685(i2cPortName, i2cAddress, this); + hardwareManager()->i2cManager()->writeData(pca, "init"); + m_i2cDevices.insert(pca, info->thing()); + info->finish(Thing::ThingErrorNoError); + return; + } } void IntegrationPluginI2CDevices::thingRemoved(Thing *thing) diff --git a/i2cdevices/integrationplugini2cdevices.h b/i2cdevices/integrationplugini2cdevices.h index b8d8ca063..df01efdc5 100644 --- a/i2cdevices/integrationplugini2cdevices.h +++ b/i2cdevices/integrationplugini2cdevices.h @@ -47,6 +47,8 @@ class IntegrationPluginI2CDevices: public IntegrationPlugin void init() override; void discoverThings(ThingDiscoveryInfo *info) override; + void executeAction(ThingActionInfo *info) override; + void setupThing(ThingSetupInfo *info) override; void thingRemoved(Thing *thing) override; diff --git a/i2cdevices/integrationplugini2cdevices.json b/i2cdevices/integrationplugini2cdevices.json index cb68e09a3..7ad66334b 100644 --- a/i2cdevices/integrationplugini2cdevices.json +++ b/i2cdevices/integrationplugini2cdevices.json @@ -451,6 +451,65 @@ ] } ] + }, + { + "id": "a17363f3-4e2a-4bfa-a937-bd7ef894b9d8", + "name": "pca9685", + "displayName": "PCA9685", + "thingClasses": [ + { + "id": "ef5e814e-9078-4e46-8528-685f72239278", + "name": "pca9685", + "displayName": "PCA9685", + "createMethods": ["user"], + "paramTypes": [ + { + "id": "9a8341a4-4d18-4832-a22b-9026136a6be5", + "name": "i2cPort", + "displayName": "I2C port", + "type": "QString" + }, + { + "id": "7e26abbb-b5c9-4761-85f1-f86eb7a86312", + "name": "i2cAddress", + "displayName": "I2C address", + "type": "int" + }, + { + "id": "e0fb6e69-b8b7-4c20-98fd-5352e5b85792", + "name": "channel", + "displayName": "Channel", + "type": "uint", + "minValue": 1, + "maxValue": 4 + } + ], + "stateTypes": [ + { + "id": "8ae3dada-efcc-446f-bb37-8554c32324dc", + "name": "power", + "displayName": "Power", + "displayNameEvent": "Power changed", + "displayNameAction": "Set power", + "type": "bool", + "defaultValue": false, + "writable": true + }, + { + "id": "a4a2de25-c0a9-43f3-8b86-d9f9cfd64b8d", + "name": "frequency", + "displayName": "Frequency", + "displayNameEvent": "Frequency changed", + "displayNameAction": "Set frequency", + "type": "uint", + "minValue": 1, + "maxValue": 1000, + "writable": true, + "defaultValue": 1 + } + ] + } + ] } ] } diff --git a/i2cdevices/pca9685.cpp b/i2cdevices/pca9685.cpp new file mode 100644 index 000000000..587f9ab0b --- /dev/null +++ b/i2cdevices/pca9685.cpp @@ -0,0 +1,92 @@ +#include "pca9685.h" + +#include + +#include "extern-plugininfo.h" + +#include +#include + +Pca9685::Pca9685(const QString &portName, int address, QObject *parent) : I2CDevice(portName, address, parent) +{ + +} + +bool Pca9685::writeData(int fd, const QByteArray &command) +{ + if (command == "init") { + writeByte8(fd, MODE2, OUTDRV); + writeByte8(fd, MODE1, ALLCALL); + QThread::msleep(5000); + quint8 mode1 = readByte8(fd, MODE1); + mode1 = mode1 & ~SLEEP; + writeByte8(fd, MODE1, mode1); + QThread::msleep(5000); + qCInfo(dcI2cDevices())<<"PCA9685 Initialization: SUCCESS"; + return true; + } + + if (command.startsWith("PWM")) { + QList parts = command.split(':'); + quint8 channel = parts.at(1).toUInt(); + quint16 on = parts.at(2).toUInt(); + quint16 off = parts.at(3).toUInt(); + writeByte8(fd, LED0_ON_L+4*channel, on & 0xFF); + writeByte8(fd, LED0_ON_H+4*channel, on >> 8); + writeByte8(fd, LED0_OFF_L+4*channel, off & 0xFF); + writeByte8(fd, LED0_OFF_H+4*channel, off >> 8); + return true; + } + + if (command.startsWith("FREQ")) { + QList parts = command.split(':'); + quint16 frequency = parts.at(1).toUInt(); + float prescaleval = 25000000.0; //25MHz + prescaleval /= 4096.0; //12-bit + prescaleval /= float(frequency); + prescaleval -= 1.0; + qInfo()<<"Setting PWM frequency to "< + +#include + +#define MODE1 0x00 +#define MODE2 0x01 +#define SUBADR1 0x02 +#define SUBADR2 0x03 +#define SUBADR3 0x04 +#define PRESCALE 0xFE +#define LED0_ON_L 0x06 +#define LED0_ON_H 0x07 +#define LED0_OFF_L 0x08 +#define LED0_OFF_H 0x09 +#define ALL_LED_ON_L 0xFA +#define ALL_LED_ON_H 0xFB +#define ALL_LED_OFF_L 0xFC +#define ALL_LED_OFF_H 0xFD +// Bits +#define RESTART 0x80 +#define SLEEP 0x10 +#define ALLCALL 0x01 +#define INVRT 0x10 +#define OUTDRV 0x04 + +#define PAN 0 +#define TILT 1 +#define FREQUENCY 50 +#define CLOCKFREQ 25000000 +#define PANOFFSET 1 +#define PANSCALE 1.4 +#define TILTOFFSET 30 +#define TILTSCALE 1.43 +#define PANMAX 270 +#define PANMIN 90 +#define TILTMAX 90 +#define TILTMIN -45 + +class Pca9685 : public I2CDevice +{ + Q_OBJECT +public: + explicit Pca9685(const QString &portName, int address, QObject *parent = nullptr); + + + bool writeData(int fd, const QByteArray &data) override; + +private: + bool writeByte8(int fd, uint8_t registerAddress, uint8_t data); + uint8_t readByte8(int fd, uint8_t registerAddress); + +}; + +#endif // PCA9685_H