mirror of
https://github.com/nymea/nymea-plugins.git
synced 2026-08-05 03:33:51 +02:00
PoC implementation for the PCA9685
This commit is contained in:
parent
7f6ceb4171
commit
b03be207f3
@ -3,10 +3,12 @@ include(../plugins.pri)
|
|||||||
HEADERS += \
|
HEADERS += \
|
||||||
integrationplugini2cdevices.h \
|
integrationplugini2cdevices.h \
|
||||||
ads1115channel.h \
|
ads1115channel.h \
|
||||||
|
pca9685.h \
|
||||||
pi16adcchannel.h
|
pi16adcchannel.h
|
||||||
|
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
integrationplugini2cdevices.cpp \
|
integrationplugini2cdevices.cpp \
|
||||||
ads1115channel.cpp \
|
ads1115channel.cpp \
|
||||||
|
pca9685.cpp \
|
||||||
pi16adcchannel.cpp
|
pi16adcchannel.cpp
|
||||||
|
|||||||
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include "pi16adcchannel.h"
|
#include "pi16adcchannel.h"
|
||||||
#include "ads1115channel.h"
|
#include "ads1115channel.h"
|
||||||
|
#include "pca9685.h"
|
||||||
|
|
||||||
#include <hardware/i2c/i2cmanager.h>
|
#include <hardware/i2c/i2cmanager.h>
|
||||||
|
|
||||||
@ -122,6 +123,17 @@ void IntegrationPluginI2CDevices::discoverThings(ThingDiscoveryInfo *info)
|
|||||||
info->finish(Thing::ThingErrorNoError);
|
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)
|
void IntegrationPluginI2CDevices::setupThing(ThingSetupInfo *info)
|
||||||
{
|
{
|
||||||
if (info->thing()->thingClassId() == pi16ADCThingClassId) {
|
if (info->thing()->thingClassId() == pi16ADCThingClassId) {
|
||||||
@ -200,6 +212,16 @@ void IntegrationPluginI2CDevices::setupThing(ThingSetupInfo *info)
|
|||||||
}
|
}
|
||||||
info->finish(Thing::ThingErrorNoError);
|
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)
|
void IntegrationPluginI2CDevices::thingRemoved(Thing *thing)
|
||||||
|
|||||||
@ -47,6 +47,8 @@ public:
|
|||||||
void init() override;
|
void init() override;
|
||||||
void discoverThings(ThingDiscoveryInfo *info) override;
|
void discoverThings(ThingDiscoveryInfo *info) override;
|
||||||
|
|
||||||
|
void executeAction(ThingActionInfo *info) override;
|
||||||
|
|
||||||
void setupThing(ThingSetupInfo *info) override;
|
void setupThing(ThingSetupInfo *info) override;
|
||||||
void thingRemoved(Thing *thing) override;
|
void thingRemoved(Thing *thing) override;
|
||||||
|
|
||||||
|
|||||||
@ -451,6 +451,57 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
92
i2cdevices/pca9685.cpp
Normal file
92
i2cdevices/pca9685.cpp
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#include "pca9685.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "extern-plugininfo.h"
|
||||||
|
|
||||||
|
#include <QThread>
|
||||||
|
#include <qmath.h>
|
||||||
|
|
||||||
|
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(5);
|
||||||
|
quint8 mode1 = readByte8(fd, MODE1);
|
||||||
|
mode1 = mode1 & ~SLEEP;
|
||||||
|
writeByte8(fd, MODE1, mode1);
|
||||||
|
QThread::msleep(5);
|
||||||
|
qCInfo(dcI2cDevices())<<"PCA9685 Initialization: SUCCESS";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.startsWith("PWM")) {
|
||||||
|
QList<QByteArray> 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<QByteArray> 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 "<<frequency<<" hz";
|
||||||
|
qInfo()<<"Estimated pre-scale: "<<prescaleval;
|
||||||
|
int prescale = (int)qFloor(prescaleval + 0.5);
|
||||||
|
qInfo()<<"Final pre-scale: "<<prescale;
|
||||||
|
uint8_t oldmode = readByte8(fd, MODE1);
|
||||||
|
uint8_t newmode = (oldmode & 0x7F) | 0x10; // sleep
|
||||||
|
writeByte8(fd, MODE1, newmode); //go to sleep
|
||||||
|
writeByte8(fd, PRESCALE, prescale);
|
||||||
|
writeByte8(fd, MODE1, oldmode);
|
||||||
|
//time.sleep(0.005) # wait
|
||||||
|
QThread::msleep(5);
|
||||||
|
writeByte8(fd, MODE1, oldmode | 0x80);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Pca9685::writeByte8(int fd, uint8_t registerAddress, uint8_t data)
|
||||||
|
{
|
||||||
|
uint8_t buffer[2] = {0};
|
||||||
|
buffer[0] = registerAddress & 0x00FF;
|
||||||
|
buffer[1] = data;
|
||||||
|
|
||||||
|
if (write(fd, buffer, 2) != 2){
|
||||||
|
qCDebug(dcI2cDevices())<<"I2C Transaction failed!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Pca9685::readByte8(int fd, uint8_t registerAddress)
|
||||||
|
{
|
||||||
|
uint8_t buffer[1] = {0};
|
||||||
|
buffer[0] = registerAddress & 0x00FF;
|
||||||
|
write(fd, buffer, 1);
|
||||||
|
|
||||||
|
uint8_t result_buffer[1] = {0};
|
||||||
|
if (read(fd, result_buffer, 1) != 1){
|
||||||
|
qDebug()<<"I2C Transaction failed!";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result_buffer[0];
|
||||||
|
}
|
||||||
57
i2cdevices/pca9685.h
Normal file
57
i2cdevices/pca9685.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#ifndef PCA9685_H
|
||||||
|
#define PCA9685_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <hardware/i2c/i2cdevice.h>
|
||||||
|
|
||||||
|
#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
|
||||||
Loading…
x
Reference in New Issue
Block a user