indidevapi(4)

NAME
indidevapi - INDI Device Driver C-language reference API

SYNOPSIS
#include "indidevapi.h"

Functions an INDI driver must define

void ISGetProperties (const char *dev);
void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n);
void ISNewNumber (const char *dev, const char *name, double *doubles, char *names[], int n);
void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);
void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n);

Functions an INDI driver may call

void IDDefText (const ITextVectorProperty *t, const char *msg, ...);
void IDDefNumber (const INumberVectorProperty *n, const char *msg, ...);
void IDDefSwitch (const ISwitchVectorProperty *s, const char *msg, ...);
void IDDefLight (const ILightVectorProperty *l, const char *msg, ...);
void IDDefBLOB (const IBLOBVectorProperty *b, const char *msg, ...);
void IDSetText (const ITextVectorProperty *t, const char *msg, ...);
void IDSetNumber (const INumberVectorProperty *n, const char *msg, ...);
void IDSetSwitch (const ISwitchVectorProperty *s, const char *msg, ...);
void IDSetLight (const ILightVectorProperty *l, const char *msg, ...);
void IDSetBLOB (const IBLOBVectorProperty *b, const char *msg, ...);
void IDMessage (const char *dev, const char *msg, ...);
void IDDelete (const char *dev, const char *name, const char *msg, ...);
void IDLog (const char *msg, ...);

IText *IUFindText (const ITextVectorProperty *tp, const char *name);
INumber *IUFindNumber(const INumberVectorProperty *tp, const char *name);
ISwitch *IUFindSwitch(const ISwitchVectorProperty *tp, const char *name);
ISwitch *IUFindOnSwitch (const ISwitchVectorProperty *tp);
int IUCrackNumber(INumberVectorProperty *nvp, const char *dev, const char *name, double *doubles, char *names[], int n);
int IUCrackText(ITextVectorProperty *tvp, const char *dev, const char *name, char *texts[], char *names[], int n);
void IUResetSwitches(const ISwitchVectorProperty *svp);

int IEAddCallback (int readfiledes, IE_CBF *fp, void *userpointer);
void IERmCallback (int callbackid);
int IEAddTimer (int millisecs, IE_TCF *fp, void *userpointer);
void IERmTimer (int timerid);
int IEAddWorkProc (IE_WPF *fp, void *userpointer);
void IERmWorkProc (int workprocid);
int IEDeferLoop (int maxms, int *flagp);
int IEDeferLoop0 (int maxms, int *flagp);

OVERVIEW

These functions are the interface to the INDI C-language Device Driver reference implementation library. Any driver that uses this interface is expected to #include "indidevapi.h" and to link with indidrivermain.o and eventloop.o. Indidevapi.h further includes indiapi.h. The former contains the prototypes for the functions documented here, although many functions take arguments defined in the latter.

These functions make it much easier to write a compliant INDI driver than starting from scratch, and also serve as a concrete example of the interactions an INDI driver, in any language, is expected to accommodate. The reference driver framework and the optimizations made within the reference indiserver both assume and require that one driver program implements exactly one logical INDI device.

The functions in this framework fall into two broad categories. Some are functions that a driver must define because they are called by the reference framework; these functions begin with IS. The remaining functions are library utilities a driver may use to do important operations.

A major point to realize is that an INDI driver built with this framework does not contain the C main() function. As soon as a driver begins executing, it listens on stdin for INDI messages. Only when a valid and appropriate message is received will it then call the driver via one of the IS functions. The driver is then expected to respond promptly by calling one of the ID library functions. It may also use any of the IU utility functions as desired to make processing a message easier.

Rather separate from these IS, ID and IU functions are a collection of functions that utilize the notion of a callback. In a callback design, the driver registers a function with the framework to be called under certain circumstances. When said circumstances occur, the framework will call the callback function. The driver never calls these callbacks directly. These callback functions begin with IE. They can arrange for a callback function to be called under three kinds of circumstances: when a given file descriptor may be read without blocking (because either data is available or EOF has been encountered), when a given time interval has elapsed, or when the framework has nothing urgent to do. The callback functions for each circumstance must be written according to a well defined prototype since, after all, the framework must know how to call the callback correctlt.

IS Functions: functions all drivers must define

This section defines functions that must be defined in each driver. These functions are never called by the driver, but are called by the driver framework. These must always be defined even if they do nothing.

void ISGetProperties (const char *dev);

    This function is called by the framework whenever the driver has received a getProperties message from an INDI client. The argument dev is either a string containing the name of the device specified within the message, or NULL if no device was specified. If the driver does not recognize the device, it should ignore the message and do nothing. If dev matches the device the driver is implementing, or dev is NULL, the driver must respond by sending one defXXX message to describe each property defined by this device, including its current (or initial) value. The recommended way to send these messages is to call the appropriate IDDef functions.

void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n);

    This function is called by the framework whenever the driver has received a newTextVector message from an INDI client. The arguments dev and name are the device and name attribute within the message, respectively. The arguments texts and names are parallel arrays, each containing n entries, that contain the content and name pairs of each of the oneText elements within the message. The function IUCrackText makes it easier to handle these arguments. The usual response to having received a newTextVector message is to perform any associated processing then send updated values and states for effected properties implemented by the driver using the IDSet functions.

void ISNewNumber (const char *dev, const char *name, double *doubles, char *names[], int n);

    This function is called by the framework whenever the driver has received a newNumberVector message from an INDI client. The arguments dev and name are the device and name attribute within the message, respectively. The arguments doubles and names are parallel arrays, each containing n entries, that contain the value and name pairs of each of the oneNumber elements within the message. The function IUCrackNumber makes it easier to handle these arguments. The usual response to having received a newNumberVector message is to perform any associated processing then send updated values and states for effected properties implemented by the driver using the IDSet functions.

void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);

    This function is called by the framework whenever the driver has received a newSwitchVector message from an INDI client. The arguments dev and name are the device and name attribute within the message, respectively. The arguments states and names are parallel arrays, each containing n entries, that contain the state and name pairs of each of the oneSwitch elements within the message. The function IUFindSwitch makes it easier to handle these arguments. The usual response to having received a newSwitchVector message is to perform any associated processing then send updated values and states for effected properties implemented by the driver using the IDSet functions.

void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n);

    This function is called by the framework whenever the driver has received a newBLOBVector message from an INDI client. The arguments dev and name are the device and name attribute within the message, respectively. The remaining array arguments are parallel arrays of n entries each, one for each oneBLOB element in the newBLOBVectory message. sizes is the number of bytes in the original BLOB; blobsizes is the number of bytes in the BLOB which itself is in blobs, already base64 decoded; formats is its format specification or file suffix; and names is the name of this BLOB.

ID Functions: functions a driver calls to send a message to a Client

Each of the following functions creates the appropriate XML formatted INDI message from its arguments and writes it to stdout. From there, is it typically read by indiserver which then sends it to the clients that have expressed interest in messages from the Device indicated in the message.

In addition to type-specific arguments, all end with a printf-style format string, and appropriate subsequent arguments, that form the message attribute within the INDI message. If the format argument is NULL, no message attribute is included with the message. Note that a timestamp attribute is also always added automatically based on the clock on the computer on which this driver is running.

void IDDefText (const ITextVectorProperty *t, const char *msg, ...);

void IDDefNumber (const INumberVectorProperty *n, const char *msg, ...);

void IDDefSwitch (const ISwitchVectorProperty *s, const char *msg, ...);

void IDDefLight (const ILightVectorProperty *l, const char *msg, ...);

void IDDefBLOB (const IBLOBVectorProperty *b, const char *msg, ...);

void IDSetText (const ITextVectorProperty *t, const char *msg, ...);

void IDSetNumber (const INumberVectorProperty *n, const char *msg, ...);

void IDSetSwitch (const ISwitchVectorProperty *s, const char *msg, ...);

void IDSetLight (const ILightVectorProperty *l, const char *msg, ...);

void IDSetBLOB (const IBLOBVectorProperty *b, const char *msg, ...);

void IDMessage (const char *dev, const char *msg, ...);

    This function formats an INDI message message. If dev is NULL, the message will be sent at large (that is, without being associated with a particular device), otherwise the message will be marked as coming from the given device.

void IDDelete (const char *dev, const char *name, const char *msg, ...);

    This function formats an INDI delProperty message for the given device. If name is NULL, the message indicates that all Properties should be deleted, otherwise only the Property with the given name.

IU Functions: utility functions a driver may call for its convenience

This section describes handy utility functions that are provided by the framework for tasks commonly required in the processing of client messages. It is not strictly necessary to use these functions, but it both prudent and efficient to do so.

IText *IUFindText (const ITextVectorProperty *tp, const char *name);

    This function searches through the given ITextVectorProperty for an IText member with the given name. Return a pointer to the found IText if found, else NULL.

INumber *IUFindNumber(const INumberVectorProperty *tp, const char *name);

    This function searches through the given INumberVectorProperty for an INumber member with the given name. Return a pointer to the found INumber if found, else NULL.

ISwitch *IUFindSwitch(const ISwitchVectorProperty *tp, const char *name);

    This function searches through the given ISwitchVectorProperty for an ISwitch member with the given name. Return a pointer to the found ISwitch if found, else NULL.

ISwitch *IUFindOnSwitch (const ISwitchVectorProperty *tp);

    This function searches through the given ISwitchVectorProperty for the first ISwitch member that is set to ISS_ON. Return a pointer to said member if found, else NULL. Note it is up to the caller to make sense of the result keeping in mind the ISRule for the given ISwitchVectorProperty.

int IUCrackNumber(INumberVectorProperty *nvp, const char *dev, const char *name, double *doubles, char *names[], int n);

    This is a convenience function for use in your implementation of ISNewNumber() whose arguments can be passed directly here. This function scans the doubles passed in and fills in corresponding INumber members of the given INumberVectorProperty. This function returns zero for success, or -1 if the device and name do not match the given INumberVectorProperty or if all INumber members of the given INumberVectorProperty are not defined.

int IUCrackText(ITextVectorProperty *tvp, const char *dev, const char *name, char *texts[], char *names[], int n);

    This is a convenience function for use in your implementation of ISNewText() whose arguments can be passed directly here. This function scans the text strings passed in and fills in corresponding IText members of the given INumberVectorProperty. This function returns zero for success, or -1 if the device and name do not match the given ITextVectorProperty or if all IText members of the given INumberVectorProperty are not defined. This function uses IUSaveText to make freshly malloced copies of all strings.

void IUResetSwitches(const ISwitchVectorProperty *svp);

    This function sets the state of each ISwitch within the given ISwitchVectorProperty to ISS_OFF.

void IUSaveText (IText *tp, const char *newtext);

    This function is always to be used to set the text value for an IText. It saves a freshly malloced copy of newtext, reallocing memory already in use by the given IText if necessary.

    It is important not to mix using this function with setting the text field of the given IText directly from stack or static strings. Similarly, static definitions of IText must not include static initializer strings for the text field, but should leave the field 0.

IE Functions: functions a driver may call to arrange for or cancel a callback

The following functions record a function and call it in the future under certain conditions. It is important that these functions return quickly because while they are executing the other functionality provided by the framework is unavailable. Of course "quickly" is a nebulous term but you can think of it as the longest period of time in which you want your driver to appear unresponsive to client interactions.

int IEAddCallback (int readfiledes, IE_CBF *fp, void *userpointer);

    This function records the function pointed to by fp and arranges for the driver framework to call it whenever reading from the given file descriptor will not block, ie, when there is data ready or EOF has been encountered. userpointer is also recorded with its value at the time this function is called and will be passed as an argument to the callback function whenever it is called in the future. This function returns a unique indentifier cookie that may be passed to IERmCallback to remove the record of fp from the framework. fp must point to a function that has the following prototype:

    typedef void (IE_CBF) (int readfiledes, void *userpointer);

void IERmCallback (int callbackid);

    This function takes as an argument an indentifier cookie returned by a previous call to IEAddCallback and removes the corresponding callback function from the framework.

int IEAddTimer (int millisecs, IE_TCF *fp, void *userpointer);

    This function records the function pointed to by fpP and arranges for the driver framework to call it one time after at least the given number of milliseconds have elapsed. userpointer is also recorded with its value at the time this function is called and will be passed as an argument to the callback function whenever it is called in the future. This function returns a unique indentifier cookie that may be passed to IERmTimer to remove the record of fp from the framework. fp must point to a function that has the following prototype:

    typedef void (IE_TCF) (void *userpointer);

void IERmTimer (int timerid);

    This function takes as an argument an indentifier cookie returned by a previous call to IEAddTimer and removes the corresponding callback function from the framework.

int IEAddWorkProc (IE_WPF *fp, void *userpointer);

    This function records the function pointed to by fpP and arranges for the driver framework to call it when it has nothing else to do. userpointer is also recorded with its value at the time this function is called and will be passed as an argument to the callback function whenever it is called in the future. This function returns a unique indentifier cookie that may be passed to IERmWorkProc to remove the record of fp from the framework. fp must point to a function that has the following prototype:

    typedef void (IE_WPF) (void *userpointer);

void IERmWorkProc (int workprocid);

    This function takes as an argument an indentifier cookie returned by a previous call to IEAddWorkProc and removes the corresponding callback function from the framework.

int IEDeferLoop (int maxms, int *flagp);

    Unlike the "callback" model used by the other event functions, this function gives the caller a means to wait in-line for a flag to be set. The flag is presumed to be set by some other event function, and a pointer to it is passed here. This function allows other timers/callbacks/workprocs to run until either the value pointed to becomes non-zero, or at least maxms milliseconds elapses. If maxms is 0, then there is no timeout and the deferral is willing to wait forever. This function returns 0 if the flag was set, or -1 if it times out.

int IEDeferLoop0 (int maxms, int *flagp);

    This is identical to IEDeferLoop() but waits for *flagp to become 0.

SEE ALSO

evalINDI, getINDI, setINDI, indiserver
http://www.clearskyinstitute.com/INDI/INDI.pdf