Instrument Neutral Distributed Interface INDI 2.2.5
connectioni2c.cpp
Go to the documentation of this file.
1/*
2 I2C Connection Plugin
3 Copyright (C) 2025 Jasem Mutlaq ([email protected])
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21#include "connectioni2c.h"
23#include "indicom.h"
24#include "indilogger.h"
25
26#ifdef __linux__
27#include <fcntl.h>
28#include <sys/ioctl.h>
29#include <linux/i2c-dev.h>
30#include <unistd.h>
31#endif
32#include <cerrno>
33#include <cstring>
34
35namespace Connection
36{
37
38extern const char *CONNECTION_TAB;
39
40I2C::I2C(INDI::DefaultDevice *dev, IPerm permission) : Interface(dev, CONNECTION_I2C), m_Permission(permission)
41{
42 I2CConnectionTP[I2C_BUS].fill("BUS", "Bus Path", "/dev/i2c-1");
43 I2CConnectionTP[I2C_ADDRESS].fill("ADDRESS", "Address (hex)", "0x28");
44 I2CConnectionTP.fill(dev->getDeviceName(), "I2C_CONNECTION", "I2C Connection", CONNECTION_TAB, m_Permission, 60, IPS_IDLE);
45
46 char configBusPath[256] = {0};
47 if (IUGetConfigText(dev->getDeviceName(), "I2C_CONNECTION", "BUS", configBusPath, 256) == 0)
48 {
49 m_ConfigBusPath = configBusPath;
50 I2CConnectionTP[I2C_BUS].setText(configBusPath);
51 }
52
53 char configAddress[256] = {0};
54 if (IUGetConfigText(dev->getDeviceName(), "I2C_CONNECTION", "ADDRESS", configAddress, 256) == 0)
55 {
56 m_ConfigAddress = strtol(configAddress, nullptr, 16);
57 I2CConnectionTP[I2C_ADDRESS].setText(configAddress);
58 }
59}
60
62{
63}
64
65bool I2C::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
66{
67 INDI_UNUSED(names);
68 INDI_UNUSED(n);
69
70 if (!strcmp(dev, m_Device->getDeviceName()))
71 {
73 {
74 I2CConnectionTP.update(texts, names, n);
77 return true;
78 }
79 }
80
81 return false;
82}
83
85{
86#ifndef __linux__
87 LOG_ERROR("I2C connection is not supported on this platform.");
88 return false;
89#else
90 uint8_t addr = static_cast<uint8_t>(strtol(I2CConnectionTP[I2C_ADDRESS].getText(), nullptr, 16));
91 if (Connect(I2CConnectionTP[I2C_BUS].getText(), addr) && processHandshake())
92 return true;
93
94 // Important, disconnect from I2C immediately
95 // to release the lock, otherwise another driver will find it busy.
96 if (PortFD > 0)
97 {
98 close(PortFD);
99 PortFD = -1;
100 }
101
102 return false;
103#endif
104}
105
107{
108 LOG_DEBUG("I2C connection successful, attempting handshake...");
109 bool rc = Handshake();
110 if (rc)
111 {
112 LOGF_INFO("%s is online.", getDeviceName());
113 // If permission is read-write and either the config bus path or address are different from
114 // configuration values, then save them.
115 if (m_Permission != IP_RO && (std::string(I2CConnectionTP[I2C_BUS].getText()) != m_ConfigBusPath ||
116 static_cast<int>(strtol(I2CConnectionTP[I2C_ADDRESS].getText(), nullptr, 16)) != m_ConfigAddress))
118 }
119 else
120 LOG_DEBUG("Handshake failed.");
121
122 return rc;
123}
124
125bool I2C::Connect(const char *busPath, uint8_t addr)
126{
127 if (m_Device->isSimulation())
128 return true;
129
130#ifndef __linux__
132 INDI_UNUSED(addr);
133 LOG_ERROR("I2C connection is not supported on this platform.");
134 return false;
135#else
136 LOGF_DEBUG("Connecting to I2C device at address 0x%02X on bus %s", addr, busPath);
137
138 PortFD = open(busPath, O_RDWR);
139 if (PortFD < 0)
140 {
141 LOGF_ERROR("Failed to open I2C bus %s. Error: %s", busPath, strerror(errno));
142 return false;
143 }
144
145 if (ioctl(PortFD, I2C_SLAVE, addr) < 0)
146 {
147 LOGF_ERROR("Failed to set I2C address 0x%02X on bus %s. Error: %s", addr, busPath, strerror(errno));
148 close(PortFD);
149 PortFD = -1;
150 return false;
151 }
152
153 LOGF_DEBUG("I2C FD %d", PortFD);
154
155 return true;
156#endif
157}
158
160{
161#ifdef __linux__
162 if (PortFD > 0)
163 {
164 close(PortFD);
165 PortFD = -1;
166 }
167#endif
168 return true;
169}
170
175
180
182{
183 if (m_Permission != IP_RO)
184 {
186 }
187
188 return true;
189}
190
191const char *I2C::busPath()
192{
194}
195
196void I2C::setDefaultBusPath(const char *path)
197{
198 // Only set default bus path if configuration path was not loaded already.
199 if (m_ConfigBusPath.empty())
200 I2CConnectionTP[I2C_BUS].setText(path);
203}
204
205void I2C::setDefaultAddress(uint8_t addr)
206{
207 // Only set default address if configuration address was not loaded already.
208 if (m_ConfigAddress == -1)
209 {
210 char hexAddr[5];
211 snprintf(hexAddr, sizeof(hexAddr), "0x%02X", addr);
212 I2CConnectionTP[I2C_ADDRESS].setText(hexAddr);
213 }
214
217}
218
220{
221 return static_cast<uint8_t>(strtol(I2CConnectionTP[I2C_ADDRESS].getText(), nullptr, 16));
222}
223
224}
std::string m_ConfigBusPath
virtual void Activated() override
Activated Function called by the framework when the plugin is activated (i.e. selected by the user)....
void setDefaultAddress(uint8_t addr)
setDefaultAddress Set default I2C address. The default address is 0x28 unless otherwise changed by th...
INDI::PropertyText I2CConnectionTP
virtual const char * busPath()
void setDefaultBusPath(const char *path)
setDefaultBusPath Set default I2C bus path. Call this function in initProperties() of your driver if ...
virtual bool Connect() override
Connect Connect to device via the implemented communication medium. Do not perform any handshakes.
virtual bool processHandshake()
virtual uint8_t address()
virtual void Deactivated() override
Deactivated Function called by the framework when the plugin is deactivated. It is usually used to de...
virtual std::string name() override
virtual bool Disconnect() override
Disconnect Disconnect from device.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
virtual bool saveConfigItems(FILE *fp) override
I2C(INDI::DefaultDevice *dev, IPerm permission=IP_RW)
The Interface class is the base class for all INDI connection plugins.
std::function< bool()> Handshake
INDI::DefaultDevice * m_Device
const char * getDeviceName() const
Class to provide extended functionality for devices in addition to the functionality provided by INDI...
bool isInitializationComplete() const
isInitializationComplete Check if driver initialization is complete.
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
bool isSimulation() const
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void save(FILE *f) const
save Save property to configuration file.
const char * getName() const
bool isNameMatch(const char *otherName) const
bool update(const char *const texts[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
INDI::PropertyViewText * getText() const
int errno
IPerm
Permission hint, with respect to client.
Definition indiapi.h:181
@ IP_RO
Definition indiapi.h:182
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
Implementations for common driver routines.
#define INDI_UNUSED(x)
Definition indidevapi.h:132
int IUGetConfigText(const char *dev, const char *property, const char *member, char *value, int len)
IUGetConfigText Opens configuration file and reads single text property.
Definition indidriver.c:908
#define LOGF_INFO(fmt,...)
Definition indilogger.h:82
#define LOG_DEBUG(txt)
Definition indilogger.h:75
#define LOGF_DEBUG(fmt,...)
Definition indilogger.h:83
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition indilogger.h:72
#define LOGF_ERROR(fmt,...)
Definition indilogger.h:80
Combines all INDI Connection Plugins. Each INDI connection plugin is responsible of managing communic...
Definition arduino_st4.h:34
const char * CONNECTION_TAB