1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
|
/*
INDI Developers Manual
Tutorial #5 - Snooping
Dome
Refer to README, which contains instruction on how to build this driver, and use it
with an INDI-compatible client.
*/
/** \file dome.cpp
\brief Construct a dome device that the user may operate to open or close the dome shutter door. This driver is \e snooping on the Rain Detector rain property status.
If rain property state is alert, we close the dome shutter door if it is open, and we prevent the user from opening it until the rain threat passes.
\author Jasem Mutlaq
\example dome.cpp
The dome driver \e snoops on the rain detector signal and watches whether rain is detected or not. If it is detector and the dome is closed, it performs
no action, but it also prevents you from opening the dome due to rain. If the dome is open, it will automatically starts closing the shutter. In order
snooping to work, both drivers must be started by the same indiserver (or chained INDI servers):
\code indiserver tutorial_dome tutorial_rain \endcode
The dome driver keeps a copy of RainL light property from the rain driver. This makes it easy to parse the property status once an update from the rain
driver arrives in the dome driver. Alternatively, you can directly parse the XML root element in ISSnoopDevice(XMLEle *root) to extract the required data.
*/
#include <unistd.h>
#include <memory>
#include "dome.h"
std::auto_ptr<Dome> dome(0);
void ISInit()
{
static int isInit =0;
if (isInit == 1)
return;
isInit = 1;
if(dome.get() == 0) dome.reset(new Dome());
}
void ISGetProperties(const char *dev)
{
ISInit();
dome->ISGetProperties(dev);
}
void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num)
{
ISInit();
dome->ISNewSwitch(dev, name, states, names, num);
}
void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num)
{
ISInit();
dome->ISNewText(dev, name, texts, names, num);
}
void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num)
{
ISInit();
dome->ISNewNumber(dev, name, values, names, num);
}
void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
{
INDI_UNUSED(dev);
INDI_UNUSED(name);
INDI_UNUSED(sizes);
INDI_UNUSED(blobsizes);
INDI_UNUSED(blobs);
INDI_UNUSED(formats);
INDI_UNUSED(names);
INDI_UNUSED(n);
}
void ISSnoopDevice (XMLEle *root)
{
ISInit();
dome->ISSnoopDevice(root);
}
Dome::Dome()
{
}
/**************************************************************************************
** Client is asking us to establish connection to the device
***************************************************************************************/
bool Dome::Connect()
{
IDMessage(getDeviceName(), "Dome connected successfully!");
return true;
}
/**************************************************************************************
** Client is asking us to terminate connection to the device
***************************************************************************************/
bool Dome::Disconnect()
{
IDMessage(getDeviceName(), "Dome disconnected successfully!");
return true;
}
/**************************************************************************************
** INDI is asking us for our default device name
***************************************************************************************/
const char * Dome::getDefaultName()
{
return "Dome";
}
/**************************************************************************************
** INDI is asking us to init our properties.
***************************************************************************************/
bool Dome::initProperties()
{
// Must init parent properties first!
INDI::DefaultDevice::initProperties();
IUFillSwitch(&ShutterS[0], "Open", "", ISS_ON);
IUFillSwitch(&ShutterS[1], "Close", "", ISS_OFF);
IUFillSwitchVector(&ShutterSP, ShutterS, 2, getDeviceName(), "Shutter Door", "", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
// We init here the property we wish to "snoop" from the target device
IUFillLight(&RainL[0], "Status", "", IPS_IDLE);
// Make sure to set the device name to "Rain Detector" since we are snooping on rain detector device.
IUFillLightVector(&RainLP, RainL, 1, "Rain Detector", "Rain Alert", "", MAIN_CONTROL_TAB, IPS_IDLE);
return true;
}
/********************************************************************************************
** INDI is asking us to update the properties because there is a change in CONNECTION status
** This fucntion is called whenever the device is connected or disconnected.
*********************************************************************************************/
bool Dome::updateProperties()
{
// Call parent update properties first
INDI::DefaultDevice::updateProperties();
if (isConnected())
{
defineSwitch(&ShutterSP);
/* Let's listen for Rain Alert property in the device Rain */
IDSnoopDevice("Rain Detector", "Rain Alert");
}
else
// We're disconnected
deleteProperty(ShutterSP.name);
return true;
}
/********************************************************************************************
** Client is asking us to update a switch
*********************************************************************************************/
bool Dome::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
{
if (!strcmp(dev, getDeviceName()))
{
if (!strcmp(name, ShutterSP.name))
{
IUUpdateSwitch(&ShutterSP, states, names, n);
ShutterSP.s = IPS_BUSY;
if (ShutterS[0].s == ISS_ON)
{
if (RainL[0].s == IPS_ALERT)
{
ShutterSP.s = IPS_ALERT;
ShutterS[0].s = ISS_OFF;
ShutterS[1].s = ISS_ON;
IDSetSwitch(&ShutterSP, "It is raining, cannot open Shutter.");
return true;
}
IDSetSwitch(&ShutterSP, "Shutter is opening.");
}
else
IDSetSwitch(&ShutterSP, "Shutter is closing.");
sleep(5);
ShutterSP.s = IPS_OK;
if (ShutterS[0].s == ISS_ON)
IDSetSwitch(&ShutterSP, "Shutter is open.");
else
IDSetSwitch(&ShutterSP, "Shutter is closed.");
return true;
}
}
return INDI::DefaultDevice::ISNewSwitch(dev, name, states, names, n);
}
/********************************************************************************************
** We received snooped property update from rain detector device
*********************************************************************************************/
bool Dome::ISSnoopDevice(XMLEle *root)
{
IPState old_state = RainL[0].s;
/* If the "Rain Alert" property gets updated in the Rain device, we will receive a notification. We need to process the new values of Rain Alert and update the local version
of the property.*/
if (IUSnoopLight(root, &RainLP) == 0)
{
// If the dome is connected and rain is Alert */
if (RainL[0].s == IPS_ALERT)
{
// If dome is open, then close it */
if (ShutterS[0].s == ISS_ON)
closeShutter();
else
IDMessage(getDeviceName(), "Rain Alert Detected! Dome is already closed.");
}
else if (old_state == IPS_ALERT && RainL[0].s != IPS_ALERT)
IDMessage(getDeviceName(), "Rain threat passed. Opening the dome is now safe.");
return true;
}
return false;
}
/********************************************************************************************
** Close shutter
*********************************************************************************************/
void Dome::closeShutter()
{
ShutterSP.s = IPS_BUSY;
IDSetSwitch(&ShutterSP, "Rain Alert! Shutter is closing...");
sleep(5);
ShutterS[0].s = ISS_OFF;
ShutterS[1].s = ISS_ON;
ShutterSP.s = IPS_OK;
IDSetSwitch(&ShutterSP, "Shutter is closed.");
}
|