| 1 | /* | 
|---|
| 2 | INDI Developers Manual | 
|---|
| 3 | Tutorial #1 | 
|---|
| 4 |  | 
|---|
| 5 | "Hello INDI" | 
|---|
| 6 |  | 
|---|
| 7 | We construct a most basic (and useless) device driver to illustate INDI. | 
|---|
| 8 |  | 
|---|
| 9 | Refer to README, which contains instruction on how to build this driver, and use it | 
|---|
| 10 | with an INDI-compatible client. | 
|---|
| 11 |  | 
|---|
| 12 | */ | 
|---|
| 13 |  | 
|---|
| 14 | /** \file tutorial_one.c | 
|---|
| 15 | \brief Construct a basic INDI driver with only one property. | 
|---|
| 16 | \author Jasem Mutlaq | 
|---|
| 17 | */ | 
|---|
| 18 |  | 
|---|
| 19 | /* Standard headers */ | 
|---|
| 20 | #include <stdio.h> | 
|---|
| 21 | #include <stdlib.h> | 
|---|
| 22 | #include <string.h> | 
|---|
| 23 | #include <math.h> | 
|---|
| 24 | #include <unistd.h> | 
|---|
| 25 |  | 
|---|
| 26 | /* INDI Core headers */ | 
|---|
| 27 |  | 
|---|
| 28 | /* indidevapi.h contains API declerations */ | 
|---|
| 29 | #include "indidevapi.h" | 
|---|
| 30 |  | 
|---|
| 31 | /* INDI Eventloop mechanism */ | 
|---|
| 32 | #include "eventloop.h" | 
|---|
| 33 |  | 
|---|
| 34 | /* INDI Common Routines */ | 
|---|
| 35 | #include "indicom.h" | 
|---|
| 36 |  | 
|---|
| 37 | /* Definitions */ | 
|---|
| 38 |  | 
|---|
| 39 | #define mydev           "Simple Device"                         /* Device name */ | 
|---|
| 40 | #define MAIN_GROUP      "Main Control"                          /* Group name */ | 
|---|
| 41 |  | 
|---|
| 42 | /* Function protptypes */ | 
|---|
| 43 | void connectDevice(void); | 
|---|
| 44 |  | 
|---|
| 45 | /*INDI controls */ | 
|---|
| 46 |  | 
|---|
| 47 | /* We will define only one vector switch property. The CONNECTION property is an INDI Standard Property and should be implemented in all INDI drivers. | 
|---|
| 48 | * A vector property may have one or more members. */ | 
|---|
| 49 |  | 
|---|
| 50 | /* First, we define and initilize the members of the vector property */ | 
|---|
| 51 | static ISwitch PowerS[]                 = { | 
|---|
| 52 | {"CONNECT"                    /* 1st Swtich name */ | 
|---|
| 53 | , "Connect"                   /* Switch Label, i.e. what the GUI displays */ | 
|---|
| 54 | , ISS_OFF                     /* State of the switch, initially off */ | 
|---|
| 55 | , 0                                   /* auxiluary, set to 0 for now.*/ | 
|---|
| 56 | , 0}                                  /* auxiluary, set to 0 for now */ | 
|---|
| 57 |  | 
|---|
| 58 | ,{"DISCONNECT"         /* 2nd Swtich name */ | 
|---|
| 59 | , "Disconnect"                 /* Switch Label, i.e. what the GUI displays */ | 
|---|
| 60 | , ISS_ON                               /* State of the switch, initially on */ | 
|---|
| 61 | , 0                                    /* auxiluary, set to 0 for now.*/ | 
|---|
| 62 | , 0}                                   /* auxiluary, set to 0 for now */ | 
|---|
| 63 | }; | 
|---|
| 64 |  | 
|---|
| 65 | /* Next, we define and initlize the vector switch property that contains the two switches we defined above */ | 
|---|
| 66 | static ISwitchVectorProperty PowerSP    = { | 
|---|
| 67 | mydev                   /* Device name */ | 
|---|
| 68 | , "CONNECTION"          /* Property name */ | 
|---|
| 69 | , "Connection"          /* Property label */ | 
|---|
| 70 | , MAIN_GROUP    /* Property group */ | 
|---|
| 71 | , IP_RW                 /* Property premission, it's both read and write */ | 
|---|
| 72 | , ISR_1OFMANY   /* Switch behavior. Only 1 of many switches are allowed to be on at the same time */ | 
|---|
| 73 | , 0                             /* Timeout, 0 seconds */ | 
|---|
| 74 | , IPS_IDLE              /* Initial state is idle */ | 
|---|
| 75 | , PowerS                        /* Switches comprimising this vector that we defined above */ | 
|---|
| 76 | , NARRAY(PowerS)        /* Number of Switches. NARRAY is defined in indiapi.h */ | 
|---|
| 77 | , ""                            /* Timestamp, set to 0 */ | 
|---|
| 78 | , 0};                           /* auxiluary, set to 0 for now */ | 
|---|
| 79 |  | 
|---|
| 80 |  | 
|---|
| 81 | /* void ISGetProperties (const char *dev) | 
|---|
| 82 | *  INDI will call this function when the client inquires about the device properties. | 
|---|
| 83 | *  Here we will use IDxxx functions to define new properties to the client */ | 
|---|
| 84 | void ISGetProperties (const char *dev) | 
|---|
| 85 | { | 
|---|
| 86 | /* Tell the client to create a new Switch property PowerSP */ | 
|---|
| 87 | IDDefSwitch(&PowerSP, NULL); | 
|---|
| 88 | } | 
|---|
| 89 |  | 
|---|
| 90 | /* void ISNewSwitch(...) | 
|---|
| 91 | * INDI will call this function when the client wants to set a new state of existing switches | 
|---|
| 92 | ** Parameters ** | 
|---|
| 93 |  | 
|---|
| 94 | * dev: the device name | 
|---|
| 95 | * name: the property name the client wants to update | 
|---|
| 96 | * states: an array of states of members switches (ISS_ON and ISS_OFF) | 
|---|
| 97 | * 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... | 
|---|
| 98 | * n: number of switches to update, which is also the dimension of *states and names[] | 
|---|
| 99 | */ | 
|---|
| 100 | void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) | 
|---|
| 101 | { | 
|---|
| 102 | /* Let's check if the property the client wants to change is the PowerSP (name: CONNECTION) property*/ | 
|---|
| 103 | if (!strcmp (name, PowerSP.name)) | 
|---|
| 104 | { | 
|---|
| 105 | /* If the clients wants to update this property, let's perform the following */ | 
|---|
| 106 |  | 
|---|
| 107 | /* A. We update the switches by sending their names and updated states IUUpdateSwitches function. If there is an error, we return */ | 
|---|
| 108 | if (IUUpdateSwitch(&PowerSP, states, names, n) < 0) return; | 
|---|
| 109 |  | 
|---|
| 110 | /* B. We try to establish a connection to our device */ | 
|---|
| 111 | connectDevice(); | 
|---|
| 112 | return; | 
|---|
| 113 | } | 
|---|
| 114 | } | 
|---|
| 115 |  | 
|---|
| 116 | /* void ISNewText(...) | 
|---|
| 117 | * INDI will call this function when the client wants to update an existing text. | 
|---|
| 118 | ** Parameters ** | 
|---|
| 119 |  | 
|---|
| 120 | * dev: the device name | 
|---|
| 121 | * name: the property name the client wants to update | 
|---|
| 122 | * texts: an array of texts. | 
|---|
| 123 | * names: names of the members. The names are parallel to the texts. | 
|---|
| 124 | * n: number of texts to update, which is also the dimension of *texts and names[] | 
|---|
| 125 | */ | 
|---|
| 126 | void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) | 
|---|
| 127 | { | 
|---|
| 128 | /* Even though we didn't define any text members, we need to define this function. Otherwise, the driver will not compile */ | 
|---|
| 129 | /* Since there is nothing to do, we simply return */ | 
|---|
| 130 | return; | 
|---|
| 131 | } | 
|---|
| 132 |  | 
|---|
| 133 | /* void ISNewNumber(...) | 
|---|
| 134 | * INDI will call this function when the client wants to update an existing number. | 
|---|
| 135 | ** Parameters ** | 
|---|
| 136 |  | 
|---|
| 137 | * dev: the device name | 
|---|
| 138 | * name: the property name the client wants to update | 
|---|
| 139 | * values: an array of values. | 
|---|
| 140 | * names: names of the members. The names are parallel to the values. | 
|---|
| 141 | * n: number of numbers to update, which is the dimension of *numbers and names[] | 
|---|
| 142 | */ | 
|---|
| 143 | void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) | 
|---|
| 144 | { | 
|---|
| 145 | /* Even though we didn't define any number members, we need to define this function. Otherwise, the driver will not compile */ | 
|---|
| 146 | /* Since there is nothing to do, we simply return */ | 
|---|
| 147 | return; | 
|---|
| 148 | } | 
|---|
| 149 |  | 
|---|
| 150 | /* Note that we must define ISNewBLOB and ISSnoopDevice even if we don't use them, otherwise, the driver will NOT compile */ | 
|---|
| 151 | void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {} | 
|---|
| 152 | void ISSnoopDevice (XMLEle *root) {} | 
|---|
| 153 |  | 
|---|
| 154 |  | 
|---|
| 155 | /* void connectDevice(void) | 
|---|
| 156 | * This function is called when the state of PowerSP is changed in the ISNewSwitch() function. | 
|---|
| 157 | * We check the state of CONNECT and DISCONNECT switches, and connect or disconnect our fake device accordingly */ | 
|---|
| 158 | void connectDevice(void) | 
|---|
| 159 | { | 
|---|
| 160 |  | 
|---|
| 161 | /* Now we check the state of CONNECT, the 1st member of the PowerSP property we defined earliar */ | 
|---|
| 162 | switch (PowerS[0].s) | 
|---|
| 163 | { | 
|---|
| 164 | /* If CONNECT is on, then try to establish a connection to the device */ | 
|---|
| 165 | case ISS_ON: | 
|---|
| 166 |  | 
|---|
| 167 | /* The IDLog function is a very useful function that will log time-stamped messages to stderr. This function is invaluable to debug your drivers. | 
|---|
| 168 | * It operates like printf */ | 
|---|
| 169 | IDLog ("Establishing a connection to %s...\n", mydev); | 
|---|
| 170 |  | 
|---|
| 171 | /* Change the state of the PowerSP (CONNECTION) property to OK */ | 
|---|
| 172 | PowerSP.s = IPS_OK; | 
|---|
| 173 |  | 
|---|
| 174 | /* Tell the client to update the states of the PowerSP property, and send a message to inform successful connection */ | 
|---|
| 175 | IDSetSwitch(&PowerSP, "Connection to %s is successful.", mydev); | 
|---|
| 176 | break; | 
|---|
| 177 |  | 
|---|
| 178 | /* If CONNECT is off (which is the same thing as DISCONNECT being on), then try to disconnect the device */ | 
|---|
| 179 | case ISS_OFF: | 
|---|
| 180 |  | 
|---|
| 181 | IDLog ("Terminating connection to %s...\n", mydev); | 
|---|
| 182 |  | 
|---|
| 183 | /* The device is disconnected, change the state to IDLE */ | 
|---|
| 184 | PowerSP.s = IPS_IDLE; | 
|---|
| 185 |  | 
|---|
| 186 | /* Tell the client to update the states of the PowerSP property, and send a message to inform successful disconnection */ | 
|---|
| 187 | IDSetSwitch(&PowerSP, "%s has been disconneced.", mydev); | 
|---|
| 188 |  | 
|---|
| 189 | break; | 
|---|
| 190 | } | 
|---|
| 191 |  | 
|---|
| 192 | } | 
|---|
| 193 |  | 
|---|
| 194 | /* That's it! check out tutorial_two where we simulate a simple telescope! */ | 
|---|