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! */
|
---|