Skip to content

Commit

Permalink
Add preliminary relay interface
Browse files Browse the repository at this point in the history
  • Loading branch information
knro committed Jul 22, 2024
1 parent 07557fa commit da0fe39
Show file tree
Hide file tree
Showing 6 changed files with 308 additions and 0 deletions.
2 changes: 2 additions & 0 deletions libs/indibase/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ list(APPEND ${PROJECT_NAME}_SOURCES
indiguiderinterface.cpp
indifilterinterface.cpp
indirotatorinterface.cpp
indirelayinterface.cpp
indidome.cpp
indigps.cpp
indiweather.cpp
Expand Down Expand Up @@ -194,6 +195,7 @@ list(APPEND ${PROJECT_NAME}_HEADERS
indiguiderinterface.h
indifilterinterface.h
indirotatorinterface.h
indirelayinterface.h
timer/inditimer.h
timer/indielapsedtimer.h
thread/indisinglethreadpool.h
Expand Down
2 changes: 2 additions & 0 deletions libs/indibase/defaultdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,8 @@ class DefaultDevice : public ParentDevice
friend class FilterInterface;
friend class FocuserInterface;
friend class WeatherInterface;
friend class RelayInterface;
friend class PowerInterface;

protected:
DefaultDevice(const std::shared_ptr<DefaultDevicePrivate> &dd);
Expand Down
181 changes: 181 additions & 0 deletions libs/indibase/indirelayinterface.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
Relay Interface
Copyright (C) 2024 Jasem Mutlaq ([email protected])
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "indirelayinterface.h"
#include <cstring>
#include "indilogger.h"

namespace INDI
{

/////////////////////////////////////////////////////////////////////////////////////////////
///
/////////////////////////////////////////////////////////////////////////////////////////////
RelayInterface::RelayInterface(DefaultDevice *defaultDevice) : m_defaultDevice(defaultDevice)
{
}

/////////////////////////////////////////////////////////////////////////////////////////////
///
/////////////////////////////////////////////////////////////////////////////////////////////
RelayInterface::~RelayInterface()
{
}

/////////////////////////////////////////////////////////////////////////////////////////////
///
/////////////////////////////////////////////////////////////////////////////////////////////
void RelayInterface::initProperties(const char *groupName, uint8_t relays)
{
RelayLabelsTP.reserve(relays);

// Initialize labels
for (auto i = 0; i < relays; i++)
{
auto name = "RELAY_" + std::to_string(i);
auto label = "Relay #" + std::to_string(i);

INDI::WidgetText oneLabel;
oneLabel.fill(name, label, label);
RelayLabelsTP.push(std::move(oneLabel));
}

RelayLabelsTP.fill(m_defaultDevice->getDeviceName(), "RELAY_LABELS", "Labels", groupName, IP_RW, 60, IPS_IDLE);
RelayLabelsTP.shrink_to_fit();
RelayLabelsTP.load();

RelaysSP.reserve(relays);
// Initialize switches, use labels if loaded.
for (auto i = 0; i < relays; i++)
{
auto name = "RELAY_" + std::to_string(i);
auto label = "Relay #" + std::to_string(i);

INDI::PropertySwitch oneRelay {3};
oneRelay[Open].fill("OPEN", "Open", ISS_OFF);
oneRelay[Close].fill("CLOSE", "Close", ISS_OFF);
oneRelay[Flip].fill("FLIP", "Flip", ISS_OFF);

if (i < RelayLabelsTP.count())
label = RelayLabelsTP[i].getText();
oneRelay.fill(m_defaultDevice->getDeviceName(), name.c_str(), label.c_str(), groupName, IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
RelaysSP.push_back(std::move(oneRelay));
}
}

/////////////////////////////////////////////////////////////////////////////////////////////
///
/////////////////////////////////////////////////////////////////////////////////////////////
bool RelayInterface::updateProperties()
{
if (m_defaultDevice->isConnected())
{
for (auto &oneRelay : RelaysSP)
m_defaultDevice->defineProperty(oneRelay);
m_defaultDevice->defineProperty(RelayLabelsTP);
}
else
{
for (auto &oneRelay : RelaysSP)
m_defaultDevice->deleteProperty(oneRelay);
m_defaultDevice->deleteProperty(RelayLabelsTP);
}

return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////
///
/////////////////////////////////////////////////////////////////////////////////////////////
bool RelayInterface::processSwitch(const char *dev, const char *name, ISState states[], char *names[], int n)
{
if (dev && !strcmp(dev, m_defaultDevice->getDeviceName()))
{
for (auto i = 0; i < RelaysSP.size(); i++)
{
if (RelaysSP[i].isNameMatch(name))
{
auto oldState = RelaysSP[i].findOnSwitchIndex();
RelaysSP[i].update(states, names, n);
auto newState = RelaysSP[i].findOnSwitchIndex();
if (oldState != newState)
{
// Cast to Command and send
if (CommandRelay(i, static_cast<Command>(newState)))
{
RelaysSP[i].setState(IPS_OK);
}
else
{
RelaysSP[i].setState(IPS_ALERT);
RelaysSP[i].reset();
RelaysSP[i][oldState].setState(ISS_ON);
}

// Apply and return
RelaysSP[i].apply();
return true;
}
// No state change
else
{
RelaysSP[i].setState(IPS_OK);
RelaysSP[i].apply();
return true;
}
}

}
}

return false;
}

/////////////////////////////////////////////////////////////////////////////////////////////
///
/////////////////////////////////////////////////////////////////////////////////////////////
bool RelayInterface::processText(const char *dev, const char *name, char *texts[], char *names[], int n)
{
if (dev && !strcmp(dev, m_defaultDevice->getDeviceName()))
{
// If this call due to config loading, let's delete existing dummy property and define the full one
if (RelayLabelsTP.isNameMatch(name))
{
RelayLabelsTP.update(texts, names, n);
RelayLabelsTP.setState(IPS_OK);
RelayLabelsTP.apply();
m_defaultDevice->saveConfig(RelayLabelsTP);
return true;
}
}

return false;
}

/////////////////////////////////////////////////////////////////////////////////////////////
///
/////////////////////////////////////////////////////////////////////////////////////////////
bool RelayInterface::saveConfigItems(FILE *fp)
{
RelayLabelsTP.save(fp);
return true;
}

}
117 changes: 117 additions & 0 deletions libs/indibase/indirelayinterface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
Relay Interface
Copyright (C) 2024 Jasem Mutlaq ([email protected])
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#pragma once

#include "indibase.h"
#include <vector>
#include <stdint.h>
#include "indipropertyswitch.h"
#include "indipropertytext.h"

/**
* \class RelayInterface
\brief Provides interface to implement Remote Relay functionality.
A web controlled relay is a simple device that can open, close, or flip a relay switch.
\e IMPORTANT: initFilterProperties() must be called before any other function to initialize the filter properties.
\author Jasem Mutlaq
*/
namespace INDI
{

class RelayInterface
{
public:
/*! Relay switch status. This is regardless on whether switch is normally closed or normally opened. */
typedef enum
{
Opened, /*!< Switch is open circuit. */
Closed, /*!< Switch is close circuit. */
Unknown /*!< Could not determined switch status. */
} Status;

/*! Relay switch Command. */
typedef enum
{
Open,
Close,
Flip
} Command;

/**
* \brief Query single relay status
* \param index Relay index
* \param status Store relay status in this variable.
* \return True if operation is successful, false otherwise
*/
virtual bool QueryRelay(uint32_t index, Status &status) = 0;

/**
* \brief Send command to relay
* \return True if operation is successful, false otherwise
*/
virtual bool CommandRelay(uint32_t index, Command command) = 0;

protected:
/**
* @brief RelayInterface Initiailize Relay Interface
* @param defaultDevice default device that owns the interface
*/
explicit RelayInterface(DefaultDevice *defaultDevice);
~RelayInterface();

/**
* \brief Initialize filter wheel properties. It is recommended to call this function within
* initProperties() of your primary device
* \param groupName Group or tab name to be used to define filter wheel properties.
* \param relays Number of relays
*/
void initProperties(const char *groupName, uint8_t relays);

/**
* @brief updateProperties Defines or Delete properties based on default device connection status
* @return True if all is OK, false otherwise.
*/
bool updateProperties();

/** \brief Process switch properties */
bool processSwitch(const char *dev, const char *name, ISState states[], char *names[], int n);

/** \brief Process text properties */
bool processText(const char *dev, const char *name, char *texts[], char *names[], int n);

/**
* @brief saveConfigItems save Filter Names in config file
* @param fp pointer to config file
* @return Always return true
*/
bool saveConfigItems(FILE *fp);

// Relay Toggle
std::vector<INDI::PropertySwitch> RelaysSP;
// Relay Labels
INDI::PropertyText RelayLabelsTP {0};

DefaultDevice *m_defaultDevice { nullptr };
};
}
2 changes: 2 additions & 0 deletions libs/indidevice/basedevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ class BaseDevice
SPECTROGRAPH_INTERFACE = (1 << 13), /**< Spectrograph interface */
CORRELATOR_INTERFACE = (1 << 14), /**< Correlators (interferometers) interface */
AUX_INTERFACE = (1 << 15), /**< Auxiliary interface */
RELAY_INTERFACE = (1 << 16), /**< Relay interface */
POWER_INTERFACE = (1 << 17), /**< Auxiliary interface */

SENSOR_INTERFACE = SPECTROGRAPH_INTERFACE | DETECTOR_INTERFACE | CORRELATOR_INTERFACE
};
Expand Down
4 changes: 4 additions & 0 deletions libs/indidevice/indibase.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
* <li>RotatorInterface: Basic interface for Rotator functions.</li>
* <li>DustCapInterface: Basic interface remotely controlled dust covers.</li>
* <li>LightBoxInterface: Basic interface for remotely controlled light boxes/switches.</li>
* <li>RelayInterface: Basic interface for remotely controller relays.</li>
* <li>PowerInterface: Basic interface for generic power boxes.</li>
* <li>CCD: Base class for CCD drivers. Provides basic support for single chip CCD and CCDs with a guide head as well.</li>
* <li>Telescope: Base class for telescope drivers.</li>
* <li>FilterWheel: Base class for Filter Wheels. It implements the FilterInterface.</li>
Expand Down Expand Up @@ -65,6 +67,8 @@ class SensorInterface;
class DomeInterface;
class DustCapInterface;
class LightBoxInterface;
class RelayInterface;
class PowerInterface;
class CCD;
class Spectrograph;
class Detector;
Expand Down

0 comments on commit da0fe39

Please sign in to comment.