| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * This file is part of the Falcon Player (FPP) and is Copyright (C) | ||
| 3 | * 2013-2022 by the Falcon Player Developers. | ||
| 4 | * | ||
| 5 | * The Falcon Player (FPP) is free software, and is covered under | ||
| 6 | * multiple Open Source licenses. Please see the included 'LICENSES' | ||
| 7 | * file for descriptions of what files are covered by each license. | ||
| 8 | * | ||
| 9 | * This source file is covered under the GPL v2 as described in the | ||
| 10 | * included LICENSE.GPL file. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include "fpp-pch.h" | ||
| 14 | |||
| 15 | #include <fcntl.h> | ||
| 16 | |||
| 17 | #include "MCP23x17Utils.h" | ||
| 18 | #include "SPIUtils.h" | ||
| 19 | |||
| 20 | // SPI Command codes | ||
| 21 | #define CMD_WRITE 0x40 | ||
| 22 | #define CMD_READ 0x41 | ||
| 23 | |||
| 24 | // MCP23x17 Registers | ||
| 25 | #define MCP23x17_IODIRA 0x00 | ||
| 26 | #define MCP23x17_IPOLA 0x02 | ||
| 27 | #define MCP23x17_GPINTENA 0x04 | ||
| 28 | #define MCP23x17_DEFVALA 0x06 | ||
| 29 | #define MCP23x17_INTCONA 0x08 | ||
| 30 | #define MCP23x17_IOCON 0x0A | ||
| 31 | #define MCP23x17_GPPUA 0x0C | ||
| 32 | #define MCP23x17_INTFA 0x0E | ||
| 33 | #define MCP23x17_INTCAPA 0x10 | ||
| 34 | #define MCP23x17_GPIOA 0x12 | ||
| 35 | #define MCP23x17_OLATA 0x14 | ||
| 36 | |||
| 37 | #define MCP23x17_IODIRB 0x01 | ||
| 38 | #define MCP23x17_IPOLB 0x03 | ||
| 39 | #define MCP23x17_GPINTENB 0x05 | ||
| 40 | #define MCP23x17_DEFVALB 0x07 | ||
| 41 | #define MCP23x17_INTCONB 0x09 | ||
| 42 | #define MCP23x17_IOCONB 0x0B | ||
| 43 | #define MCP23x17_GPPUB 0x0D | ||
| 44 | #define MCP23x17_INTFB 0x0F | ||
| 45 | #define MCP23x17_INTCAPB 0x11 | ||
| 46 | #define MCP23x17_GPIOB 0x13 | ||
| 47 | #define MCP23x17_OLATB 0x15 | ||
| 48 | |||
| 49 | // Bits in the IOCON register | ||
| 50 | #define IOCON_UNUSED 0x01 | ||
| 51 | #define IOCON_INTPOL 0x02 | ||
| 52 | #define IOCON_ODR 0x04 | ||
| 53 | #define IOCON_HAEN 0x08 | ||
| 54 | #define IOCON_DISSLW 0x10 | ||
| 55 | #define IOCON_SEQOP 0x20 | ||
| 56 | #define IOCON_MIRROR 0x40 | ||
| 57 | #define IOCON_BANK_MODE 0x80 | ||
| 58 | |||
| 59 | // Default initialisation mode | ||
| 60 | #define IOCON_INIT (IOCON_SEQOP) | ||
| 61 | |||
| 62 | static SPIUtils* MCP23x17_SPI = nullptr; | ||
| 63 | static uint8_t status_port_a; | ||
| 64 | static uint8_t status_port_b; | ||
| 65 | |||
| 66 | 142 | static int writeByte(uint8_t reg, uint8_t data, uint8_t devId = 0) { | |
| 67 |
1/2✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
|
142 | if (MCP23x17_SPI) { |
| 68 | uint8_t spiData[4]; | ||
| 69 | |||
| 70 | 142 | spiData[0] = CMD_WRITE | ((devId & 7) << 1); | |
| 71 | 142 | spiData[1] = reg; | |
| 72 | 142 | spiData[2] = data; | |
| 73 |
1/2✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
|
142 | return MCP23x17_SPI->xfer(spiData, spiData, 3); |
| 74 | } | ||
| 75 | ✗ | return -1; | |
| 76 | } | ||
| 77 | 146 | static int32_t readByte(uint8_t reg, uint8_t devId = 0) { | |
| 78 |
1/2✓ Branch 0 taken 146 times.
✗ Branch 1 not taken.
|
146 | if (MCP23x17_SPI) { |
| 79 | 146 | uint8_t spiData[4] = { 0, 0, 0, 0 }; | |
| 80 | 146 | spiData[0] = CMD_READ | ((devId & 7) << 1); | |
| 81 | 146 | spiData[1] = reg; | |
| 82 |
1/2✓ Branch 0 taken 146 times.
✗ Branch 1 not taken.
|
146 | int i = MCP23x17_SPI->xfer(spiData, spiData, 3); |
| 83 |
2/2✓ Branch 0 taken 118 times.
✓ Branch 1 taken 28 times.
|
146 | if (i == -1) { |
| 84 | 118 | return -1; | |
| 85 | } | ||
| 86 | 28 | return spiData[2]; | |
| 87 | } | ||
| 88 | ✗ | return -1; | |
| 89 | } | ||
| 90 | |||
| 91 | 69 | MCP23x17PinCapabilities::MCP23x17PinCapabilities(const std::string& n, uint32_t kg, int chip) : | |
| 92 | 69 | PinCapabilitiesFluent(n, kg) { | |
| 93 | 69 | gpioIdx = chip; | |
| 94 | 69 | } | |
| 95 | |||
| 96 | 4 | int MCP23x17PinCapabilities::configPin(const std::string& mode, | |
| 97 | bool directionOut, | ||
| 98 | const std::string& desc) const { | ||
| 99 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
|
4 | if (mode == "pwm" || mode == "uart") { |
| 100 | ✗ | return 0; | |
| 101 | } | ||
| 102 | 4 | int pin = this->gpio; | |
| 103 | 4 | int reg = (pin < 8) ? MCP23x17_IODIRA : MCP23x17_IODIRB; | |
| 104 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | int pureg = (pin < 8) ? MCP23x17_GPPUA : MCP23x17_GPPUB; |
| 105 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (pin > 7) { |
| 106 | 4 | pin &= 0x07; | |
| 107 | } | ||
| 108 | 4 | int mask = 1 << pin; | |
| 109 | 4 | int old = readByte(reg); | |
| 110 | |||
| 111 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (directionOut) { |
| 112 | 4 | old &= (~mask); | |
| 113 | } else { | ||
| 114 | ✗ | old |= mask; | |
| 115 | } | ||
| 116 | 4 | writeByte(reg, old); | |
| 117 | |||
| 118 | 4 | old = readByte(pureg); | |
| 119 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (mode == "gpio_pu") { |
| 120 | ✗ | old |= mask; | |
| 121 | } else { | ||
| 122 | 4 | old &= (~mask); | |
| 123 | } | ||
| 124 | 4 | writeByte(pureg, old); | |
| 125 | 4 | return 0; | |
| 126 | } | ||
| 127 | |||
| 128 | 12 | bool MCP23x17PinCapabilities::getValue() const { | |
| 129 | 12 | int pin = this->gpio; | |
| 130 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | int gpio = (pin < 8) ? MCP23x17_GPIOA : MCP23x17_GPIOB; |
| 131 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | if (pin > 7) { |
| 132 | 12 | pin &= 0x07; | |
| 133 | } | ||
| 134 | 12 | int mask = 1 << pin; | |
| 135 | 12 | int value = readByte(gpio); | |
| 136 | 12 | return ((value & mask) != 0); | |
| 137 | } | ||
| 138 | 8 | void MCP23x17PinCapabilities::setValue(bool i) const { | |
| 139 | 8 | int pin = this->gpio; | |
| 140 | 8 | int bit = 1 << (pin & 7); | |
| 141 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | int old = (pin < 8) ? status_port_a : status_port_b; |
| 142 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | if (i == 0) { |
| 143 | 4 | old &= (~bit); | |
| 144 | } else { | ||
| 145 | 4 | old |= bit; | |
| 146 | } | ||
| 147 | |||
| 148 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (pin < 8) { |
| 149 | ✗ | writeByte(MCP23x17_GPIOA, old); | |
| 150 | ✗ | status_port_a = old; | |
| 151 | } else { | ||
| 152 | 8 | writeByte(MCP23x17_GPIOB, old); | |
| 153 | 8 | status_port_b = old; | |
| 154 | } | ||
| 155 | 8 | } | |
| 156 | |||
| 157 | class NullMCP23x17GPIOPinCapabilities : public MCP23x17PinCapabilities { | ||
| 158 | public: | ||
| 159 | 65 | NullMCP23x17GPIOPinCapabilities() : | |
| 160 |
2/4✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
|
195 | MCP23x17PinCapabilities("-none-", 0, 0) {} |
| 161 | 75 | virtual const PinCapabilities* ptr() const override { return nullptr; } | |
| 162 | }; | ||
| 163 | static NullMCP23x17GPIOPinCapabilities NULL_WP_INSTANCE; | ||
| 164 | |||
| 165 | static std::vector<MCP23x17PinCapabilities> MCP23x17_PINS; | ||
| 166 | |||
| 167 | 63 | void MCP23x17PinCapabilities::Init(int chip) { | |
| 168 |
2/6✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 63 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
63 | MCP23x17_SPI = new SPIUtils(0, 4000000); |
| 169 |
1/2✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
|
63 | if (MCP23x17_SPI->isOk()) { |
| 170 |
1/2✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
|
63 | writeByte(MCP23x17_IOCON, IOCON_INIT | IOCON_HAEN); |
| 171 |
1/2✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
|
63 | writeByte(MCP23x17_IOCONB, IOCON_INIT | IOCON_HAEN); |
| 172 | |||
| 173 |
1/2✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
|
63 | int iA = readByte(MCP23x17_OLATA); |
| 174 |
1/2✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
|
63 | int iB = readByte(MCP23x17_OLATB); |
| 175 | |||
| 176 |
3/4✓ Branch 0 taken 4 times.
✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
63 | if (iA == -1 || iB == -1) { |
| 177 |
1/2✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
|
59 | delete MCP23x17_SPI; |
| 178 | 59 | MCP23x17_SPI = nullptr; | |
| 179 | 63 | return; | |
| 180 | } | ||
| 181 | 4 | status_port_a = iA; | |
| 182 | 4 | status_port_b = iB; | |
| 183 | |||
| 184 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
8 | MCP23x17PinCapabilities testPin("MCP23x17-1", chip, 0); |
| 185 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
12 | testPin.configPin("gpio"); |
| 186 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | int a = testPin.getValue(); |
| 187 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | testPin.setValue(1); |
| 188 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | int b = testPin.getValue(); |
| 189 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | testPin.setValue(0); |
| 190 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | int c = testPin.getValue(); |
| 191 | |||
| 192 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | if (a == b && b == c) { |
| 193 | // could not change the value, assume no PiFace found | ||
| 194 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | delete MCP23x17_SPI; |
| 195 | 4 | MCP23x17_SPI = nullptr; | |
| 196 | 4 | return; | |
| 197 | } | ||
| 198 | |||
| 199 | ✗ | for (int x = 0; x < 16; x++) { | |
| 200 | ✗ | std::string name = "MCP23x17-" + std::to_string(x + 1); | |
| 201 | ✗ | MCP23x17_PINS.push_back(MCP23x17PinCapabilities(name, x, chip)); | |
| 202 | ✗ | } | |
| 203 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | } else { |
| 204 | ✗ | delete MCP23x17_SPI; | |
| 205 | ✗ | MCP23x17_SPI = nullptr; | |
| 206 | } | ||
| 207 | } | ||
| 208 | 56 | void MCP23x17PinCapabilities::getPinNames(std::vector<std::string>& ret) { | |
| 209 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
|
56 | for (auto& a : MCP23x17_PINS) { |
| 210 | ✗ | ret.push_back(a.name); | |
| 211 | } | ||
| 212 | 56 | } | |
| 213 | |||
| 214 | 12 | const PinCapabilities& MCP23x17PinCapabilities::getPinByName(const std::string& name) { | |
| 215 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | for (auto& a : MCP23x17_PINS) { |
| 216 | ✗ | if (a.name == name) { | |
| 217 | ✗ | return a; | |
| 218 | } | ||
| 219 | } | ||
| 220 | 12 | return NULL_WP_INSTANCE; | |
| 221 | } | ||
| 222 | 63 | const PinCapabilities& MCP23x17PinCapabilities::getPinByGPIO(int chip, int gpio) { | |
| 223 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
|
63 | for (auto& a : MCP23x17_PINS) { |
| 224 | ✗ | if (a.gpio == gpio && a.gpioIdx == chip) { | |
| 225 | ✗ | return a; | |
| 226 | } | ||
| 227 | } | ||
| 228 | 63 | return NULL_WP_INSTANCE; | |
| 229 | } | ||
| 230 | |||
| 231 | ✗ | const PinCapabilities& MCP23x17PinCapabilities::getPinByUART(const std::string& n) { | |
| 232 | ✗ | return NULL_WP_INSTANCE; | |
| 233 | } | ||
| 234 |