mirror of
https://github.com/nymea/nymea-plugins.git
synced 2026-07-17 00:36:35 +02:00
PoC implementation for the PCA9685
This commit is contained in:
parent
7f6ceb4171
commit
b03be207f3
@ -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
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
|
||||
#include "pi16adcchannel.h"
|
||||
#include "ads1115channel.h"
|
||||
#include "pca9685.h"
|
||||
|
||||
#include <hardware/i2c/i2cmanager.h>
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -47,6 +47,8 @@ public:
|
||||
void init() override;
|
||||
void discoverThings(ThingDiscoveryInfo *info) override;
|
||||
|
||||
void executeAction(ThingActionInfo *info) override;
|
||||
|
||||
void setupThing(ThingSetupInfo *info) 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