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