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
|
/*
INDI Developers Manual
Tutorial #1
"Hello INDI"
We construct a most basic (and useless) device driver to illustate INDI.
Refer to README, which contains instruction on how to build this driver, and use it
with an INDI-compatible client.
*/
/** \file tutorial_one.c
\brief Construct a basic INDI driver with only one property.
\author Jasem Mutlaq
*/
/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
/* INDI Core headers */
/* indidevapi.h contains API declerations */
#include "indidevapi.h"
/* INDI Eventloop mechanism */
#include "eventloop.h"
/* INDI Common Routines */
#include "indicom.h"
/* Definitions */
#define mydev "Simple Device" /* Device name */
#define MAIN_GROUP "Main Control" /* Group name */
/* Function protptypes */
void connectDevice(void);
/*INDI controls */
/* We will define only one vector switch property. The CONNECTION property is an INDI Standard Property and should be implemented in all INDI drivers.
* A vector property may have one or more members. */
/* First, we define and initilize the members of the vector property */
static ISwitch PowerS[] = {
{"CONNECT" /* 1st Swtich name */
, "Connect" /* Switch Label, i.e. what the GUI displays */
, ISS_OFF /* State of the switch, initially off */
, 0 /* auxiluary, set to 0 for now.*/
, 0} /* auxiluary, set to 0 for now */
,{"DISCONNECT" /* 2nd Swtich name */
, "Disconnect" /* Switch Label, i.e. what the GUI displays */
, ISS_ON /* State of the switch, initially on */
, 0 /* auxiluary, set to 0 for now.*/
, 0} /* auxiluary, set to 0 for now */
};
/* Next, we define and initlize the vector switch property that contains the two switches we defined above */
static ISwitchVectorProperty PowerSP = {
mydev /* Device name */
, "CONNECTION" /* Property name */
, "Connection" /* Property label */
, MAIN_GROUP /* Property group */
, IP_RW /* Property premission, it's both read and write */
, ISR_1OFMANY /* Switch behavior. Only 1 of many switches are allowed to be on at the same time */
, 0 /* Timeout, 0 seconds */
, IPS_IDLE /* Initial state is idle */
, PowerS /* Switches comprimising this vector that we defined above */
, NARRAY(PowerS) /* Number of Switches. NARRAY is defined in indiapi.h */
, "" /* Timestamp, set to 0 */
, 0}; /* auxiluary, set to 0 for now */
/* void ISGetProperties (const char *dev)
* INDI will call this function when the client inquires about the device properties.
* Here we will use IDxxx functions to define new properties to the client */
void ISGetProperties (const char *dev)
{
/* Tell the client to create a new Switch property PowerSP */
IDDefSwitch(&PowerSP, NULL);
}
/* void ISNewSwitch(...)
* INDI will call this function when the client wants to set a new state of existing switches
** Parameters **
* dev: the device name
* name: the property name the client wants to update
* states: an array of states of members switches (ISS_ON and ISS_OFF)
* names: names of the switches. The names are parallel to the states. That is, member names[0] has a state states[0], and so on...
* n: number of switches to update, which is also the dimension of *states and names[]
*/
void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
{
/* Let's check if the property the client wants to change is the PowerSP (name: CONNECTION) property*/
if (!strcmp (name, PowerSP.name))
{
/* If the clients wants to update this property, let's perform the following */
/* A. We update the switches by sending their names and updated states IUUpdateSwitches function. If there is an error, we return */
if (IUUpdateSwitch(&PowerSP, states, names, n) < 0) return;
/* B. We try to establish a connection to our device */
connectDevice();
return;
}
}
/* void ISNewText(...)
* INDI will call this function when the client wants to update an existing text.
** Parameters **
* dev: the device name
* name: the property name the client wants to update
* texts: an array of texts.
* names: names of the members. The names are parallel to the texts.
* n: number of texts to update, which is also the dimension of *texts and names[]
*/
void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
{
/* Even though we didn't define any text members, we need to define this function. Otherwise, the driver will not compile */
/* Since there is nothing to do, we simply return */
return;
}
/* void ISNewNumber(...)
* INDI will call this function when the client wants to update an existing number.
** Parameters **
* dev: the device name
* name: the property name the client wants to update
* values: an array of values.
* names: names of the members. The names are parallel to the values.
* n: number of numbers to update, which is the dimension of *numbers and names[]
*/
void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
{
/* Even though we didn't define any number members, we need to define this function. Otherwise, the driver will not compile */
/* Since there is nothing to do, we simply return */
return;
}
/* Note that we must define ISNewBLOB and ISSnoopDevice even if we don't use them, otherwise, the driver will NOT compile */
void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {}
void ISSnoopDevice (XMLEle *root) {}
/* void connectDevice(void)
* This function is called when the state of PowerSP is changed in the ISNewSwitch() function.
* We check the state of CONNECT and DISCONNECT switches, and connect or disconnect our fake device accordingly */
void connectDevice(void)
{
/* Now we check the state of CONNECT, the 1st member of the PowerSP property we defined earliar */
switch (PowerS[0].s)
{
/* If CONNECT is on, then try to establish a connection to the device */
case ISS_ON:
/* The IDLog function is a very useful function that will log time-stamped messages to stderr. This function is invaluable to debug your drivers.
* It operates like printf */
IDLog ("Establishing a connection to %s...\n", mydev);
/* Change the state of the PowerSP (CONNECTION) property to OK */
PowerSP.s = IPS_OK;
/* Tell the client to update the states of the PowerSP property, and send a message to inform successful connection */
IDSetSwitch(&PowerSP, "Connection to %s is successful.", mydev);
break;
/* If CONNECT is off (which is the same thing as DISCONNECT being on), then try to disconnect the device */
case ISS_OFF:
IDLog ("Terminating connection to %s...\n", mydev);
/* The device is disconnected, change the state to IDLE */
PowerSP.s = IPS_IDLE;
/* Tell the client to update the states of the PowerSP property, and send a message to inform successful disconnection */
IDSetSwitch(&PowerSP, "%s has been disconneced.", mydev);
break;
}
}
/* That's it! check out tutorial_two where we simulate a simple telescope! */
|