Instrument Neutral Distributed Interface INDI 2.2.5
trutech_wheel.c
Go to the documentation of this file.
1#if 0
2 True Technology Filter Wheel
3 Copyright (C) 2006 Jasem Mutlaq (mutlaqja AT ikarustech DOT com)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19#endif
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <cstring>
24#include <stdarg.h>
25#include <cmath>
26#include <unistd.h>
27#include <ctime>
28#include <fcntl.h>
29#include <cerrno>
30#include <sys/stat.h>
31#include <sys/time.h>
32#include <sys/types.h>
33#include <sys/socket.h>
34
35#include "indidevapi.h"
36#include "eventloop.h"
37#include "indicom.h"
38
39void ISInit(void);
40void getBasicData(void);
41void ISPoll(void *);
42void handleExposure(void *);
43void connectFilter(void);
44int manageDefaults(char errmsg[]);
49int isFilterConnected(void);
50
51static int targetFilter;
52static int fd;
53const unsigned char COMM_PRE = 0x01;
54const unsigned char COMM_INIT = 0xA5;
55const unsigned char COMM_FILL = 0x20;
56
57#define mydev "TruTech Wheel"
58#define MAIN_GROUP "Main Control"
59#define currentFilter FilterPositionN[0].value
60#define POLLMS 3000
61#define DEFAULT_FILTER_COUNT 5
62#define MAX_FILTER_COUNT 10
63#define ERRMSG_SIZE 1024
64
65#define CMD_SIZE 5
66#define CMD_JUNK 64
67#define CMD_RESP 15
68
69#define FILTER_TIMEOUT 15 /* 15 Seconds before timeout */
70#define FIRST_FILTER 1
71
72#define DEBUG_ON 0
73#define SIMULATION_ON 0
74
75/*INDI controls */
76
77/* Connect/Disconnect */
78static ISwitch PowerS[] = { { "CONNECT", "Connect", ISS_OFF, 0, 0 }, { "DISCONNECT", "Disconnect", ISS_ON, 0, 0 } };
79static ISwitchVectorProperty PowerSP = { mydev, "CONNECTION", "Connection", MAIN_GROUP, IP_RW, ISR_1OFMANY,
80 60, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0 };
81
82/* Connection Port */
83static IText PortT[] = { { "PORT", "Port", 0, 0, 0, 0 } };
84static ITextVectorProperty PortTP = { mydev, "DEVICE_PORT", "Ports", MAIN_GROUP, IP_RW, 0,
85 IPS_IDLE, PortT, NARRAY(PortT), "", 0 };
86
87/* Home/Learn Swtich */
88static ISwitch HomeS[] = { { "Find", "", ISS_OFF, 0, 0 } };
89static ISwitchVectorProperty HomeSP = { mydev, "HOME", "", MAIN_GROUP, IP_RW, ISR_1OFMANY,
90 60, IPS_IDLE, HomeS, NARRAY(HomeS), "", 0 };
91
92/* Filter Count */
93static INumber FilterCountN[] = { { "Count", "", "%2.0f", 0, MAX_FILTER_COUNT, 1, DEFAULT_FILTER_COUNT, 0, 0, 0 } };
94static INumberVectorProperty FilterCountNP = { mydev, "Filter Count", "", MAIN_GROUP, IP_RW, 0, IPS_IDLE,
95 FilterCountN, NARRAY(FilterCountN), "", 0 };
96
97/* Filter Position */
98static INumber FilterPositionN[] = { { "FILTER_SLOT_VALUE", "Active Filter", "%2.0f", 1, DEFAULT_FILTER_COUNT, 1, 1, 0,
99 0, 0 } };
100static INumberVectorProperty FilterPositionNP = {
101 mydev, "FILTER_SLOT", "Filter", MAIN_GROUP, IP_RW, 0, IPS_IDLE, FilterPositionN, NARRAY(FilterPositionN), "", 0
102};
103
104/* send client definitions of all properties */
105void ISInit()
106{
107 static int isInit = 0;
108
109 if (isInit)
110 return;
111
112 targetFilter = -1;
113 fd = -1;
114
115 isInit = 1;
116}
117
118void ISGetProperties(const char *dev)
119{
120 ISInit();
121
122 if (dev != nullptr && strcmp(mydev, dev))
123 return;
124
125 /* Main Control */
126 IDDefSwitch(&PowerSP, NULL);
127 IDDefText(&PortTP, NULL);
128 IDDefNumber(&FilterCountNP, NULL);
129 IDDefSwitch(&HomeSP, NULL);
130 IDDefNumber(&FilterPositionNP, NULL);
131}
132
133void ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[],
134 char *names[], int n)
135{
136 INDI_UNUSED(dev);
137 INDI_UNUSED(name);
138 INDI_UNUSED(sizes);
139 INDI_UNUSED(blobsizes);
140 INDI_UNUSED(blobs);
141 INDI_UNUSED(formats);
142 INDI_UNUSED(names);
143 INDI_UNUSED(n);
144}
146{
147 INDI_UNUSED(root);
148}
149
150void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
151{
152 /* ignore if not ours */
153 if (dev != nullptr && strcmp(dev, mydev))
154 return;
155
156 ISInit();
157
158 /* Connection */
159 if (!strcmp(name, PowerSP.name))
160 {
161 IUUpdateSwitch(&PowerSP, states, names, n);
163 return;
164 }
165
166 /* Home Search */
167 if (!strcmp(name, HomeSP.name))
168 {
169 int err;
170 int nbytes = 0;
171 unsigned char type = 0x03;
172 unsigned char chksum = COMM_INIT + type + COMM_FILL;
173 unsigned char filter_command[CMD_SIZE];
174 //snprintf(filter_command, CMD_SIZE, "%c%c%c%c%c", COMM_PRE, COMM_INIT, type, COMM_FILL, chksum);
175 snprintf(filter_command, CMD_SIZE, "%c%c%c%c", COMM_INIT, type, COMM_FILL, chksum);
176
177 if (checkPowerS(&HomeSP))
178 return;
179
180 if (!SIMULATION_ON)
181 err = tty_write(fd, filter_command, CMD_SIZE, &nbytes);
182
183 if (DEBUG_ON)
184 {
185 IDLog("Home Search Command (int): #%d#%d#%d#%d#\n", COMM_INIT, type, COMM_FILL, chksum);
186 IDLog("Home Search Command (char): #%c#%c#%c#%c#\n", COMM_INIT, type, COMM_FILL, chksum);
187 }
188
189 /* Send Home Command */
190 if (err != TTY_OK)
191 {
192 char error_message[ERRMSG_SIZE];
193 tty_error_msg(err, error_message, ERRMSG_SIZE);
194
195 HomeSP.s = IPS_ALERT;
196 IDSetSwitch(&HomeSP, "Sending command Home to filter failed. %s", error_message);
197 IDLog("Sending command Home to filter failed. %s\n", error_message);
198
199 return;
200 }
201
202 FilterPositionN[0].value = 1;
203 FilterPositionNP.s = IPS_OK;
204 HomeSP.s = IPS_OK;
205 IDSetSwitch(&HomeSP, "Filter set to HOME.");
206 IDSetNumber(&FilterPositionNP, NULL);
207 }
208}
209
210void ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
211{
212 ISInit();
213
214 /* ignore if not ours */
215 if (dev != nullptr && strcmp(mydev, dev))
216 return;
217
218 if (!strcmp(name, PortTP.name))
219 {
220 if (IUUpdateText(&PortTP, texts, names, n))
221 return;
222
223 PortTP.s = IPS_OK;
224 IDSetText(&PortTP, NULL);
225 }
226}
227
228void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
229{
230 long err;
231 INumber *np;
232
233 /* ignore if not ours */
234 if (dev != nullptr && strcmp(dev, mydev))
235 return;
236
237 ISInit();
238
239 if (!strcmp(FilterPositionNP.name, name))
240 {
241 if (!isFilterConnected())
242 {
243 IDMessage(mydev, "Filter is not connected.");
244 FilterPositionNP.s = IPS_IDLE;
245 IDSetNumber(&FilterPositionNP, NULL);
246 return;
247 }
248
249 np = IUFindNumber(&FilterPositionNP, names[0]);
250 if (np == &FilterPositionN[0])
251 {
252 targetFilter = values[0];
253 int nbytes = 0;
254 unsigned char type = 0x01;
255 unsigned char chksum = COMM_INIT + type + (unsigned char)targetFilter;
256 /*char filter_command[5] = { COMM_PRE, COMM_INIT, type, targetFilter, chksum };*/
257 unsigned char filter_command[CMD_SIZE];
258
259 if (targetFilter < FilterPositionN[0].min || targetFilter > FilterPositionN[0].max)
260 {
261 FilterPositionNP.s = IPS_ALERT;
262 IDSetNumber(&FilterPositionNP, "Error: valid range of filter is from %d to %d",
263 (int)FilterPositionN[0].min, (int)FilterPositionN[0].max);
264 return;
265 }
266
267 IUUpdateNumber(&FilterPositionNP, values, names, n);
268
269 //snprintf(filter_command, CMD_SIZE, "%c%c%c%c%c", COMM_PRE, COMM_INIT, type, targetFilter, chksum);
270 snprintf(filter_command, CMD_SIZE, "%c%c%c%c", COMM_INIT, type, targetFilter, chksum);
271
272 if (DEBUG_ON)
273 {
274 IDLog("Filter Position Command (int): #%d#%d#%d#%d#\n", COMM_INIT, type, targetFilter, chksum);
275 IDLog("Filter Position Command (char): #%c#%c#%c#%c#\n", COMM_INIT, type, targetFilter, chksum);
276 }
277
278 if (!SIMULATION_ON)
279 err = tty_write(fd, filter_command, CMD_SIZE, &nbytes);
280
281 FilterPositionNP.s = IPS_OK;
282 IDSetNumber(&FilterPositionNP, "Setting current filter to slot %d", targetFilter);
283 }
284 else
285 {
286 FilterPositionNP.s = IPS_IDLE;
287 IDSetNumber(&FilterPositionNP, NULL);
288 }
289
290 return;
291 }
292
293 if (!strcmp(FilterCountNP.name, name))
294 {
295 if (!isFilterConnected())
296 {
297 IDMessage(mydev, "Filter is not connected.");
298 FilterCountNP.s = IPS_IDLE;
299 IDSetNumber(&FilterCountNP, NULL);
300 return;
301 }
302
303 np = IUFindNumber(&FilterCountNP, names[0]);
304 if (np == &FilterCountN[0])
305 {
306 if (IUUpdateNumber(&FilterCountNP, values, names, n) < 0)
307 return;
308
309 FilterPositionN[0].min = 1;
310 FilterPositionN[0].max = (int)FilterCountN[0].value;
311 IUUpdateMinMax(&FilterPositionNP);
312
313 FilterCountNP.s = IPS_OK;
314 IDSetNumber(&FilterCountNP, "Updated number of available filters to %d", ((int)FilterCountN[0].value));
315 }
316 else
317 {
318 FilterCountNP.s = IPS_IDLE;
319 IDSetNumber(&FilterCountNP, NULL);
320 }
321
322 return;
323 }
324}
325
327{
328 int i = 0;
329 for (i = 0; i < sp->nsp; i++)
330 {
331 if (sp->sp[i].s == ISS_ON)
332 return i;
333 }
334
335 return -1;
336}
337
339{
340 if (PowerSP.s != IPS_OK)
341 {
342 if (!strcmp(sp->label, ""))
343 IDMessage(mydev, "Cannot change property %s while the wheel is offline.", sp->name);
344 else
345 IDMessage(mydev, "Cannot change property %s while the wheel is offline.", sp->label);
346
347 sp->s = IPS_IDLE;
348 IDSetSwitch(sp, NULL);
349 return -1;
350 }
351
352 return 0;
353}
354
356{
357 if (PowerSP.s != IPS_OK)
358 {
359 if (!strcmp(np->label, ""))
360 IDMessage(mydev, "Cannot change property %s while the wheel is offline.", np->name);
361 else
362 IDMessage(mydev, "Cannot change property %s while the wheel is offline.", np->label);
363
364 np->s = IPS_IDLE;
365 IDSetNumber(np, NULL);
366 return -1;
367 }
368
369 return 0;
370}
371
373{
374 if (PowerSP.s != IPS_OK)
375 {
376 if (!strcmp(tp->label, ""))
377 IDMessage(mydev, "Cannot change property %s while the wheel is offline.", tp->name);
378 else
379 IDMessage(mydev, "Cannot change property %s while the wheel is offline.", tp->label);
380
381 tp->s = IPS_IDLE;
382 IDSetText(tp, NULL);
383 return -1;
384 }
385
386 return 0;
387}
388
390{
391 int err;
392 char errmsg[ERRMSG_SIZE];
393
394 switch (PowerS[0].s)
395 {
396 case ISS_ON:
397 if (SIMULATION_ON)
398 {
399 PowerSP.s = IPS_OK;
400 IDSetSwitch(&PowerSP, "Simulated Filter Wheel is online.");
401 return;
402 }
403
404 if ((err = tty_connect(PortT[0].text, 9600, 8, 0, 1, &fd)) != TTY_OK)
405 {
408 &PowerSP,
409 "Error: cannot connect to %s. Make sure the filter is connected and you have access to the port.",
410 PortT[0].text);
411 tty_error_msg(err, errmsg, ERRMSG_SIZE);
412 IDLog("Error: %s\n", errmsg);
413 return;
414 }
415
416 PowerSP.s = IPS_OK;
417 IDSetSwitch(&PowerSP, "Filter Wheel is online. True Technology filter wheel suffers from several bugs. "
418 "Please refer to http://indi.sf.net/profiles/trutech.html for more details.");
419 break;
420
421 case ISS_OFF:
422 if (SIMULATION_ON)
423 {
424 PowerSP.s = IPS_OK;
425 IDSetSwitch(&PowerSP, "Simulated Filter Wheel is offline.");
426 return;
427 }
428
429 if ((err = tty_disconnect(fd)) != TTY_OK)
430 {
432 IDSetSwitch(&PowerSP, "Error: cannot disconnect.");
433 tty_error_msg(err, errmsg, ERRMSG_SIZE);
434 IDLog("Error: %s\n", errmsg);
435 return;
436 }
437
439 IDSetSwitch(&PowerSP, "Filter Wheel is offline.");
440 break;
441 }
442}
443
444/* isFilterConnected: return 1 if we have a connection, 0 otherwise */
446{
447 return ((PowerS[0].s == ISS_ON) ? 1 : 0);
448}
Public interface to INDI's eventloop mechanism.
double max(void)
#define min(a, b)
ISState
Switch state.
Definition indiapi.h:148
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
#define NARRAY(a)
Handy macro to find the number of elements in array a[]. Must be used with actual array,...
Definition indiapi.h:498
@ IP_RW
Definition indiapi.h:184
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
@ ISR_1OFMANY
Definition indiapi.h:171
int tty_connect(const char *device, int bit_rate, int word_size, int parity, int stop_bits, int *fd)
Establishes a tty connection to a terminal device.
Definition indicom.c:1022
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition indicom.c:418
int tty_disconnect(int fd)
Closes a tty connection and flushes the bus.
Definition indicom.c:1224
void IDLog(const char *fmt,...)
Definition indicom.c:305
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition indicom.c:1243
Implementations for common driver routines.
@ TTY_OK
Definition indicom.h:54
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
Definition indidevapi.c:275
Interface to the reference INDI C API device implementation on the Device Driver side.
#define INDI_UNUSED(x)
Definition indidevapi.h:132
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
void IDMessage(const char *dev, const char *fmt,...)
Definition indidriver.c:983
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
void IUUpdateMinMax(const INumberVectorProperty *nvp)
Function to update the min and max elements of a number in the client.
void IDDefNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDDefText(const ITextVectorProperty *tvp, const char *fmt,...)
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
void IDDefSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
int fd
ISwitchVectorProperty PowerSP
ITextVectorProperty PortTP
Definition magellan1.cpp:65
uint16_t type
Definition pwc-ioctl.h:0
One number descriptor.
One switch descriptor.
One text descriptor.
Number vector property descriptor.
Definition indiapi.h:317
char name[MAXINDINAME]
Definition indiapi.h:321
char label[MAXINDILABEL]
Definition indiapi.h:323
Switch vector property descriptor.
Definition indiapi.h:365
char name[MAXINDINAME]
Definition indiapi.h:369
char label[MAXINDILABEL]
Definition indiapi.h:371
ISState s
Definition indiapi.h:353
Text vector property descriptor.
Definition indiapi.h:244
char label[MAXINDILABEL]
Definition indiapi.h:250
char name[MAXINDINAME]
Definition indiapi.h:248
const unsigned char COMM_FILL
#define SIMULATION_ON
#define ERRMSG_SIZE
int manageDefaults(char errmsg[])
Definition fli_wheel.c:364
#define DEFAULT_FILTER_COUNT
void ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
Update data of an existing blob vector property.
void connectFilter(void)
#define CMD_SIZE
void ISInit(void)
void handleExposure(void *)
void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Update the value of an existing switch vector property.
void ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Update the value of an existing text vector property.
int checkPowerS(ISwitchVectorProperty *sp)
void ISGetProperties(const char *dev)
Get Device Properties.
#define DEBUG_ON
#define MAX_FILTER_COUNT
int checkPowerN(INumberVectorProperty *np)
#define mydev
const unsigned char COMM_PRE
int getOnSwitch(ISwitchVectorProperty *sp)
void ISPoll(void *)
Definition fli_wheel.c:393
#define MAIN_GROUP
void getBasicData(void)
Definition fli_wheel.c:308
void ISSnoopDevice(XMLEle *root)
Function defined by Drivers that is called when another Driver it is snooping (by having previously c...
void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
const unsigned char COMM_INIT
int isFilterConnected(void)
int checkPowerT(ITextVectorProperty *tp)