| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | /* | ||
| 3 | * This file is part of the Falcon Player (FPP) and is Copyright (C) | ||
| 4 | * 2013-2022 by the Falcon Player Developers. | ||
| 5 | * | ||
| 6 | * The Falcon Player (FPP) is free software, and is covered under | ||
| 7 | * multiple Open Source licenses. Please see the included 'LICENSES' | ||
| 8 | * file for descriptions of what files are covered by each license. | ||
| 9 | * | ||
| 10 | * This source file is covered under the GPL v2 as described in the | ||
| 11 | * included LICENSE.GPL file. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include "ChannelOutput.h" | ||
| 15 | #include "fpp-json.h" | ||
| 16 | #include "util/I2CUtils.h" | ||
| 17 | #include "commands/Commands.h" | ||
| 18 | |||
| 19 | #include <mutex> | ||
| 20 | |||
| 21 | class PCA9685Output : public ChannelOutput { | ||
| 22 | public: | ||
| 23 | class ServoPositionCommand : public Command { | ||
| 24 | public: | ||
| 25 | ServoPositionCommand(PCA9685Output* output); | ||
| 26 | virtual ~ServoPositionCommand(); | ||
| 27 | |||
| 28 | virtual std::unique_ptr<Command::Result> run(const std::vector<std::string>& args) override; | ||
| 29 | |||
| 30 | private: | ||
| 31 | PCA9685Output* m_output; | ||
| 32 | }; | ||
| 33 | PCA9685Output(unsigned int startChannel, unsigned int channelCount); | ||
| 34 | virtual ~PCA9685Output(); | ||
| 35 | |||
| 36 | 28 | virtual std::string GetOutputType() const { | |
| 37 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
56 | return "PCA9685 PWM"; |
| 38 | } | ||
| 39 | |||
| 40 | virtual void OverlayTestData(unsigned char* channelData, int cycleNum, float percentOfCycle, int testType, const Json::Value& config) override; | ||
| 41 | virtual bool SupportsTesting() const override; | ||
| 42 | |||
| 43 | virtual int Init(Json::Value config) override; | ||
| 44 | virtual int Close(void) override; | ||
| 45 | |||
| 46 | virtual void PrepData(unsigned char* channelData) override; | ||
| 47 | virtual int SendData(unsigned char* channelData) override; | ||
| 48 | |||
| 49 | virtual void StartingOutput() override; | ||
| 50 | virtual void StoppingOutput() override; | ||
| 51 | |||
| 52 | virtual void DumpConfig(void) override; | ||
| 53 | |||
| 54 | virtual void GetRequiredChannelRanges(const std::function<void(int, int)>& addRange) override; | ||
| 55 | |||
| 56 | enum class ZeroType { | ||
| 57 | HOLD = 0, | ||
| 58 | NORMAL = 1, | ||
| 59 | CENTER = 2, | ||
| 60 | OFF = 3, | ||
| 61 | MIN = 4, | ||
| 62 | MAX = 5 | ||
| 63 | }; | ||
| 64 | |||
| 65 | enum class DataType { | ||
| 66 | SCALED, | ||
| 67 | ABSOLUTE, | ||
| 68 | ABSOLUTE_HALF, | ||
| 69 | ABSOLUTE_DOUBLE | ||
| 70 | }; | ||
| 71 | |||
| 72 | enum class PWMType { | ||
| 73 | SERVO, | ||
| 74 | LED | ||
| 75 | }; | ||
| 76 | |||
| 77 | void restoreOriginalConfig(); | ||
| 78 | void loadPortConfig(const Json::Value& portConfig); | ||
| 79 | |||
| 80 | // Made public for ServoPositionCommand access | ||
| 81 | I2CUtils* i2c; | ||
| 82 | int m_deviceID; | ||
| 83 | std::string m_i2cDevice; | ||
| 84 | int m_frequency; | ||
| 85 | float m_actualFrequency; | ||
| 86 | |||
| 87 | class PCA9685Port { | ||
| 88 | public: | ||
| 89 | std::string description; | ||
| 90 | PWMType type = PWMType::SERVO; | ||
| 91 | bool is16Bit = true; | ||
| 92 | uint32_t startChannel = 0; | ||
| 93 | |||
| 94 | // servo properties | ||
| 95 | int m_min = 1000; | ||
| 96 | int m_max = 2000; | ||
| 97 | int m_center = 1500; | ||
| 98 | DataType m_dataType = DataType::SCALED; | ||
| 99 | ZeroType m_zeroBehavior = ZeroType::HOLD; | ||
| 100 | bool m_reverse = false; | ||
| 101 | |||
| 102 | // LED properties | ||
| 103 | float gamma = 1.0f; | ||
| 104 | uint32_t brightness = 100; | ||
| 105 | |||
| 106 | unsigned short m_lastValue = 0; | ||
| 107 | unsigned short m_nextValue = 0; | ||
| 108 | |||
| 109 | unsigned short readValue(unsigned char* channelData, float frequency, int port); | ||
| 110 | |||
| 111 | unsigned short mapLEDValue(unsigned short val); | ||
| 112 | }; | ||
| 113 | |||
| 114 | PCA9685Port m_ports[16]; | ||
| 115 | uint32_t numPorts; | ||
| 116 | |||
| 117 | private: | ||
| 118 | std::atomic<uint64_t> lastFrameTime; | ||
| 119 | std::array<uint16_t, 32> data; | ||
| 120 | Json::Value origConfig; | ||
| 121 | int lastTestType = 0; | ||
| 122 | |||
| 123 | // The Servo Position command runs on a command thread and sets the ports | ||
| 124 | // and sends, while the output thread prepares and sends frames (and the | ||
| 125 | // test overlay reloads the port config): both write data[] and the bus. | ||
| 126 | // Recursive: the command calls SendData(). | ||
| 127 | std::recursive_mutex m_portsLock; | ||
| 128 | |||
| 129 | // Servo Position Command | ||
| 130 | ServoPositionCommand* m_servoCommand = nullptr; | ||
| 131 | }; | ||
| 132 |