• Article
  • Discussion
  • Edit
  • History

Developing INDI drivers

INDI drivers consist of the low-level code that communicates with the device, and of the INDI API code that enables the driver to serve any INDI compatible client.

Details of the data acquisition and control methods are unique to each device, and therefore it is up to the developer to implement these functions. In this chapter, you will learn how to abstract the complicated functions of your device into a set of well-defined, simple, and coherent collection of elementary properties in the INDI architecture; namely: switches, numbers, texts, lights, and blobs.

All examples discussed hereafter are available in the INDI official distribution. Refere to README in the INDI release from sourceforge on how to build and run the example tutorials.

Contents

  • 1 General
  • 2 Simple Device
  • 3 Telescopes
  • 4 CCDs
  • 5 Video
  • 6 Filter wheels and focusers
    • 6.1 Filter Wheel
    • 6.2 Focusers
[edit]

General

The basic steps required to build an INDI driver are generally the following:

  1. Define a list of properties that describe your device operation.
  2. Initialize properties initial state.
  3. When a client connects, send a list of existing properties.
  4. Implement functions that will carry out the operations offered by the properties.
  5. Report device status to client if desired.
  6. Clean up the driver if the client disconnects.

In addition to the steps outlined above, developers are strongly encouraged to follow common INDI design philosophies. The design philosophies stem from experiences gained by the INDI developer community over the years:

  • Drivers should be minimal: Your driver should support the most basic functions only. Generally speaking, there should be a 1-to-1 correspondence between the driver's properties and the device's functions. For example, if you're writing a driver for a CCD chip, don't code complicated routines to compute WCS. These functions should be handled at the client side. Minimal also means that the driver should try to avoid any dependence on external libraries when possible. The INDI server and most drivers only require the standard headers and a compiler, we prefer to keep it this way.
  • Drivers should adhere to INDI standard properties: INDI standard properties were created to establish interoperability among drivers and clients alike. If you have a function that is similar to an existing standard property, try to adjust your function to use it. For example, both CCDs and Webcams employ the CCD_EXPOSURE property to perform an exposure. This happens despite the fact that in most webcams, you cannot control the exposure duration. Nevertheless, the video driver simply considers the exposure time to be zero and takes an exposure. Therefore, the client only needs to be aware of one property instead of two.
  • Drivers should be secure: The driver has a complete authority over the device, and it should not trust clients blindly. While some clients perform border-checks for numerical values, drivers should assume that no check took place and hence, all checks must be performed in the driver itself. Moreover, work with memory allocation, reallocation, and freeing carefully as buffer overflows pose a common security threat.
  • Drivers should support multiple simultaneous clients: INDI server takes care of most of the processing and logic related to multiple clients, but you should design your drivers to be scalable. Consider all the functions your driver provide, and whether they can be affected in anyway when more clients request these functions.
  • Drivers should be safe to operate. Likewise, conflicting commands should be handled properly at the driver level. Consider all possible scenarios and make sure that actions are subjected to interlocking checks before the action is performed. The user should be able to halt operations once they started, and drivers must prepare for such sudden interruptions if necessary. For example, if your telescope tube can hit the tripod base at certain altitudes, then all necessary checks must be performed to make sure no such incident takes place.
Warning
noframe
Always prepare for the worst case scenario when developing drivers. If your system is critical, develop stringent interlocking checks, redundancy, fail-over and notification mechanisms. If something can go wrong, it will go wrong.


  • Driver should be flexible: Be flexible in your design while remembering that drivers need to be minimal. Try to group common properties together. Arrange common properties in logical groups. A plethora of individual properties that otherwise could have been grouped together will only confuse the user and make the operation of your device tougher.
[edit]

Simple Device

To best illustrates the concepts discussed thus far, let's build our first INDI device driver. Our sample driver is rather trivial, it only contains one INDI standard switch vector property (CONNECTION), and it does not perform any useful functions. The following example (tutorial_one.c) is available in the official INDI distribution.

We first begin by giving our device a name:

#define mydev "Simple Device"

Next, we need to create a group to hold our properties:

#define MAIN_GROUP "Main Control"

Now, let's define our only property, which also happens to be an INDI standard property. All properties consist of individual elements. In our example, we will have two switches, or two elements: Connect and Disconnect.

static ISwitch PowerS[] = {
 {"CONNECT"    /* 1st Swtich name */
, "Connect"    /* Switch Label, i.e. what the GUI displays */
, ISS_OFF      /* State of the switch, initially off */
, 0            /* auxiluary, set to 0 for now.*/
, 0}           /* auxiluary, set to 0 for now */
,{"DISCONNECT" /* 2nd Swtich name */
, "Disconnect" /* Switch Label, i.e. what the GUI displays */
, ISS_ON       /* State of the switch, initially on */
, 0            /* auxiluary, set to 0 for now.*/
, 0}           /* auxiluary, set to 0 for now */
};

The two switches defined above need to be inserted in a switch vector property:

static ISwitchVectorProperty PowerSP = {
  mydev          /* Device name */
, "CONNECTION"   /* Property name */
, "Connection"   /* Property label */
, MAIN_GROUP     /* Property group */
, IP_RW          /* Property premission, it's both read and write */
, ISR_1OFMANY    /* Switch behavior.
, 0              /* Timeout, 0 seconds */
, IPS_IDLE       /* Initial state is idle */
, PowerS         /* Switches comprimising this vector that we defined above */
, NARRAY(PowerS) /* Number of Switches. NARRAY is defined in indiapi.h */
, 0              /* Timestamp, set to 0 */
, 0}; /* auxiluary, set to 0 for now */

All drivers are event-driven and must define all ISxxx() functions. When a new client connects to us, it needs to know what properties our device provides:

void ISGetProperties (const char *dev)

{

 /* Tell the client to create a new Switch property PowerSP */
 IDDefSwitch(&PowerSP, NULL);
}

When the client want to change the status of switches (to connect or disconnect in our example), it sends a request and we must process it in ISNewSwitch:

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

{

    /* Let's check if the property the client wants to
       change is the PowerSP (name: CONNECTION) property*/
    if (!strcmp (name, PowerSP.name))
    {
          /* We update the switches by sending their names
             and updated states IUUpdateSwitches function, if something goes 
             wrong, we return */
          if (IUUpdateSwitches(&PowerSP, states, names, n) < 0)
              return;
 
          /* We try to establish a connection to our device */
           connectDevice();
           return;
    } 
}

Even though our driver did not define any text, number, or blob properties, we must define the corresponding ISxxx functions:

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

void ISNewNumber (const char *dev, const char *name, double values[ ], char *names[ ], int n) {}

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

Next, we implement the connectDevice() function which handles client requests:

void connectDevice(void)

{

 /* Now we check the state of CONNECT, the 1st member of
    the PowerSP property we defined earliar */
 switch (PowerS[0].s)
 {
    /* If CONNECT is on, then try to establish a connection to the device */
    case ISS_ON:
     
     /* The IDLog function is a very useful function that will log time-stamped
        messages to stderr. This function is invaluable to debug your drivers.
        It operates like printf */
    IDLog ("Establishing a connection to %s...\n", mydev);
     /* Change the state of the PowerSP (CONNECTION) property to OK */
     PowerSP.s = IPS_OK;
     
     /* Tell the client to update the states of the PowerSP
        property, and send a message to inform successful connection */
     IDSetSwitch(&PowerSP, "Connection to %s is successful.", mydev);
     break;
     
   /* If CONNECT is off (which is the same thing as DISCONNECT being on),
      then try to disconnect the device */
   case ISS_OFF:
   
      IDLog ("Terminating connection to %s...\n", mydev);
      
     /* The device is disconnected, change the state to IDLE */
     PowerSP.s = IPS_IDLE;
     
     /* Tell the client to update the states of the PowerSP property,
        and send a message to inform successful disconnection */
     IDSetSwitch(&PowerSP, "%s has been disconneced.", mydev);
     
     break;
    }
    
}

We can run our example driver under any INDI-compatible client. The screenshot below shows the driver running under KStars:

Simple Device under KStars
Enlarge
Simple Device under KStars
[edit]

Telescopes

Due to the self-describing nature of INDI, developers may write drivers for virtually any device. But since the focus of INDI is astronomy, we shall discuss the development specifics for astronomical instrumentation.

Telescopes may differ vastly in their optical and mechanical properties, but all telescopes share common characteristics pertaining to their function. It is the goal of INDI standard properties to encapsulate such characteristics to insure interoperability among drivers and clients alike. Generally speaking, developing a telescope driver involves the following steps:

  1. Define your telescope fundamental properties: time, coordinate system, slew/trach/sync options, ability to abort motion..etc
  2. Implement a library to send commands to the telescope's electronics via a bus channel. In most amateur telescopes, this bus is RS232.
  3. Calculate initial ephemeris values if necessary (JD, Sidereal time..etc).
  4. Upon connection, retrieve the telescope's current values and report them to the client (e.g. Current RA, DEC).
  5. It is possible to setup timers to poll for changes in properties state in order to act accordingly. For example, if the telescope motion property is BUSY, then keep polling the current coordinates until they match the desired coordinates; should coordinates match, change the telescope motion property state to OK and report to the client.

Telescope drivers share a set of standard properties, part of which is discussed below:

  • Coordinates: You have a choice for target coordinate format: EQUATORIAL_EOD_COORD, EQUATORIAL_COORD, and HORIZONTAL_COORD.
  • Telescope Action: When a client sends new coordinates, the telescope can either SLEW to the object, or SLEW and then TRACK the object, or SYNC its internal coordinates to match the client supplied coordinates. The standard switch property for this action is ON_COORD_SET.
  • Abort: Telescopes should be able to abort any slew or track operations quickly and safely. TELESCOPE_ABORT_MOTION.
  • Parking: Park the telescope to HOME position or unpark the telescope. TELESCOPE_PARK.

In the following tutorial (tutorial_two.c), we will create a simple telescope simulator. We will also use a few handy utility functions provided by INDI like timers, string, number conversions, and more.

Like our initial simple device, we need to define the device name and property groups:

#define mydev "Telescope Simulator"

Next we define the telescope properties:

static ISwitch connectS[] = {{"CONNECT", "On", ISS_OFF, 0, 0}, {"DISCONNECT", "Off", ISS_ON, 0, 0}};

static ISwitchVectorProperty connectSP = { mydev, "CONNECTION", "Connection", MAIN_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, connectS, NARRAY(connectS), "", 0 };

/* Equatorial position. EQUATORIAL_COORD is one of INDI's reserved Standard Properties */


static INumber eqN[] = {

/* 1st member is Right ascension */

{"RA" /* 1st Number name */

,"RA H:M:S" /* Number label */

, "%10.6m" /* Format. */

,0. /* Minimum value */

, 24. /* Maximum value */

, 0. /* Steps */

, 0. /* Initial value */

, 0 /* Pointer to parent, we don't use it, so set it to 0 */

, 0 /* Auxiliary member, set it to 0 */

, 0}, /* Auxiliary member, set it to 0 */

/* 2nd member is Declination */

{"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0} };

static INumberVectorProperty eqNP = { mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", MAIN_GROUP , IP_RW, 0, IPS_IDLE, eqN, NARRAY(eqN), "", 0};

When the client connects, we inform it of our properties:

void ISGetProperties (const char *dev)

{
IDDefSwitch (&powSw, NULL);
IDDefNumber (&eqNum, NULL);

}

For simulation purposes, we use a timer to simulate the scope movements across the sky:

static void mountInit()

{
static int inited; /* set once mountInit is called */

if (inited) return;

/* start timer to simulate mount motion The timer will call function mountSim after POLLMS milliseconds */ IEAddTimer (POLLMS, mountSim, NULL);

inited = 1;

}

When the client tell us to move to a new coordinate, we need to process the request:

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

{
/* Make sure to initialize */
mountInit();

if (!strcmp (name, eqNP.name)) {
/* new equatorial target coords */
double newra = 0, newdec = 0;
int i, nset;

/* Check connectSP, if it is idle, then return */
if (connectSP.s == IPS_IDLE)
{
eqNP.s = IPS_IDLE;
IDSetNumber(&eqNP, "Telescope is offline.");
return;
}

for (nset = i = 0; i < n; i++)
{
/* Find numbers with the passed names in the eqNP property */
INumber *eqp = IUFindNumber (&eqNP, names[i]);

/* If the number found is Right ascension (eqN[0]) then process it */
if (eqp == &eqN[0])
{
newra = (values[i]);
nset += newra >= 0 && newra <= 24;
}
/* Otherwise, if the number found is Declination (eqN[1]) then process it */
else if (eqp == &eqN[1]) {
newdec = (values[i]);
nset += newdec >= -90 && newdec <= 90;
}
} /* end for */

/* Did we process the two numbers? */
if (nset == 2)
{
char r[32], d[32];

/* Set the mount state to BUSY */
eqNP.s = IPS_BUSY;

/* Set the new target coordinates */
targetRA = newra;
targetDEC = newdec;

/* Convert the numeric coordinates to a sexagesmal string (H:M:S) */
fs_sexa (r, targetRA, 2, 3600);
fs_sexa (d, targetDEC, 3, 3600);

IDSetNumber(&eqNP, "Moving to RA Dec %s %s", r, d);
}
/* We didn't process the two number correctly, report an error */
else
{
/* Set property state to idle */
eqNP.s = IPS_IDLE;

IDSetNumber(&eqNP, "RA or Dec absent or bogus.");
}
return;
}

}

We handle the Connect/Disconnect request like we did in simple device.

Finally, the mountSim(void *p) function is responsible for simulating the telescope. Note that we need to call mountSim() again since IEAddTimer only calls the respective function once.

void mountSim (void *p)

{
static struct timeval ltv; struct timeval tv; double dt, da, dx; int nlocked;

/* If telescope is not on, do not simulate */
if (connectSP.s == IPS_IDLE) { IEAddTimer (POLLMS, mountSim, NULL); return; }

/* update elapsed time since last poll, don't presume exactly POLLMS */
gettimeofday (&tv, NULL);

if (ltv.tv_sec == 0 && ltv.tv_usec == 0) ltv = tv;

dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec)/1e6; ltv = tv; da = SLEWRATE*dt;

/* Process per current state. We check the state of EQUATORIAL_COORDS and act accordingly */
switch (eqNP.s) {

/* #1 State is idle, update telescope at sidereal rate */
case IPS_IDLE: /* RA moves at sidereal, Dec stands still */
currentRA += (SIDRATE*dt/15.); IDSetNumber(&eqNP, NULL); break;

case IPS_BUSY: /* slewing - nail it when both within one pulse @ SLEWRATE */
nlocked = 0;

dx = targetRA - currentRA;

if (fabs(dx) <= da) { currentRA = targetRA; nlocked++; } else if (dx > 0) currentRA += da/15.; else currentRA -= da/15.;


dx = targetDEC - currentDec; if (fabs(dx) <= da) { currentDec = targetDEC; nlocked++; } else if (dx > 0) currentDec += da; else currentDec -= da;

if (nlocked == 2) { eqNP.s = IPS_OK; IDSetNumber(&eqNP, "Now tracking"); } else IDSetNumber(&eqNP, NULL);

break;

case IPS_OK: /* tracking */
IDSetNumber(&eqNP, NULL); break;

case IPS_ALERT: break; }

/* again */
IEAddTimer (POLLMS, mountSim, NULL);

}

The following is a screenshot for the telescope simulator running under Xephem.

Telescope Simulator under Xephem
Enlarge
Telescope Simulator under Xephem
[edit]

CCDs

A minimal CCD driver is expected to perform the following basic functions:

  • Exposure
  • Temperature control
  • Subframing
  • Binning

All exposures must be saved as FITS before they get uploaded to the client. Bundled with INDI is the robust CFITSIO library which you can use to create and save FITS files in 8, 16, 32, -32, and -64 bit formats. Additionally, the FITSIO features common routines like card addition, searching, and decoding.

In [thttp://indi.sourceforge.net/api/tutorial__three_8c-source.html tutorial_three] we will implement, and it should be no surprise by now, a CCD simulator. Since we will employ the binary transfer capabilities of INDI in this tutorial, it's highly recommended to review Binary Transfer in INDI.

Let's define the CCD specific properties:

static INumber ExposeTimeN[] = {{ "CCD_EXPOSURE_VALUE", "Duration (s)", "%5.2f",
                                     0., 36000., .5, 1., 0, 0, 0}};

static INumberVectorProperty ExposeTimeNP = { mydev, "CCD_EXPOSURE", "Expose", COMM_GROUP, IP_RW, 60, IPS_IDLE, ExposeTimeN, NARRAY(ExposeTimeN), "", 0};

static INumber TemperatureN[] = { {"CCD_TEMPERATURE_VALUE", "Temperature", "%+06.2f", -30., 40., 1., 0., 0, 0, 0} };

static INumberVectorProperty TemperatureNP = { mydev, "CCD_TEMPERATURE", "Temperature (C)", COMM_GROUP, IP_RW, 60, IPS_IDLE, TemperatureN, NARRAY(TemperatureN), "", 0};

static IBLOB imageB = {"CCD1", "Feed", "", 0, 0, 0, 0, 0, 0, 0}; static IBLOBVectorProperty imageBP = {mydev, "Video", "Video", COMM_GROUP,

IP_RO, 0, IPS_IDLE, &imageB, 1, "", 0};

Like the telescope simulator, we shall setup a 1-second timer to call the function ISPoll which checks the status of pending commands.

void CCDInit()

{

 static int init=0;
 if (init) return;
 IEAddTimer(1000, ISPoll, NULL);
 init = 1;
}

In ISNewNumber(), we check if the client requested to expose the CCD, or a change in CCD temperature.

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

{

   /* Exposure time */
if (!strcmp (ExposeTimeNP.name, name)) {
    /* Let's make sure that our simulator is online */
if (PowerS[0].s != ISS_ON) { ExposeTimeNP.s = IPS_IDLE; IDSetNumber(&ExposeTimeNP, "CCD Simulator is offline."); return; }
     IDLog("Sending BLOB FITS...\n");
     ExposeTimeNP.s = IPS_BUSY;
     ExposeTimeN[0].value = values[0];

     return;
   } 
   /* Temperature */
if (!strcmp (TemperatureNP.name, name)) {
    /* Let's make sure that our simulator is online */
if (PowerS[0].s != ISS_ON) { TemperatureNP.s = IPS_IDLE; IDSetNumber(&TemperatureNP, "CCD Simulator is offline"); return; }
     targetTemp = values[0];
     /* If the requested temperature is the current CCD chip temperature, then return */
if (targetTemp == TemperatureN[0].value) { TemperatureNP.s = IPS_OK; IDSetNumber(&TemperatureNP, NULL); return; } /* Otherwise, set property state to busy */
TemperatureNP.s = IPS_BUSY; IDSetNumber(&TemperatureNP, "Setting CCD temperature to %g", targetTemp);
     return;
   }
}

in ISPoll(), we monitor any changes in our properties and act upon changes of status. For example, the default status for ExposeTimeNP is IPS_IDLE, when the client issues a valid expose request in ISNewNumber, we change the status of ExposeTimeNP to IPS_BUSY. ISPoll() checks the status of ExposeTimeNP each second and starts the simulated exposure procedure as soon as the status changes from IDLE to BUSY. When the exposure procedure is over, we change the status of ExposeTimeNP to OK.

void ISPoll(void * p)

{

  /* We need to check the status of properties that we want to watch. */
  /* #1 CCD Exposure */
switch (ExposeTimeNP.s) { case IPS_IDLE: case IPS_OK: case IPS_ALERT:

break;

    /* If an exposure state is busy, decrement the exposure
       value until it's zero (done exposing). */
case IPS_BUSY:

ExposeTimeN[0].value--;

       /* Are we done yet?*/
if (ExposeTimeN[0].value == 0) { /* Let's set the state of OK and report that to the client */
ExposeTimeNP.s = IPS_OK; /* Upload a sample FITS file */
uploadFile("ngc1316o.fits");
         IDSetNumber(&ExposeTimeNP, NULL);

break;

       }

IDSetNumber(&ExposeTimeNP, NULL);

       break;
  } 
  /* #2 CCD Temperature */
switch (TemperatureNP.s) { case IPS_IDLE: case IPS_OK: case IPS_ALERT:

break;

    case IPS_BUSY:
    /* If target temperature is higher, then increase current CCD temperature */
if (currentTemp < targetTemp) currentTemp++; /* If target temperature is lower, then decrese current CCD temperature */
else if (currentTemp > targetTemp) currentTemp--; /* If they're equal, stop updating */
else { TemperatureNP.s = IPS_OK; IDSetNumber(&TemperatureNP, "Target temperature reached.");
      break;
    }
    IDSetNumber(&TemperatureNP, NULL);
    break;
  }
  /* Keep polling alive */
IEAddTimer (1000, ISPoll, NULL);
}

Finally, we implement the uploadFile() function which is responsible for uploading the FITS file to our client:

void uploadFile(const char* filename)

{

   FILE * fitsFile;
  unsigned char *fitsData, *compressedData;
  int r=0;
  unsigned int i =0, nr = 0;
  uLongf compressedBytes=0;
  uLong  totalBytes;
  struct stat stat_p; 

     /* #1 Let's get the file size */
if ( -1 == stat (filename, &stat_p)) { IDLog(" Error occoured attempting to stat file.\n"); return; } /* #2 Allocate memory for raw and compressed data */
totalBytes = stat_p.st_size; fitsData = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes); compressedData = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3); if (fitsData == NULL || compressedData == NULL) { IDLog("Error! low memory. Unable to initialize fits buffers."); return; }
  /* #3 Open the FITS file */
fitsFile = fopen(filename, "r"); if (fitsFile == NULL) return;
  /* #4 Read file from disk */ 
for (i=0; i < totalBytes; i+= nr) { nr = fread(fitsData + i, 1, totalBytes - i, fitsFile); if (nr <= 0) { IDLog("Error reading temporary FITS file.\n"); return; } } compressedBytes = sizeof(char) * totalBytes + totalBytes / 64 + 16 + 3; /* #5 Compress raw data */
r = compress2(compressedData, &compressedBytes, fitsData, totalBytes, 9); if (r != Z_OK) { /* this should NEVER happen */
IDLog("internal error - compression failed: %d\n", r);

return;

  }
  
  /* #6 Send it */
imageB.blob = compressedData; imageB.bloblen = compressedBytes; imageB.size = totalBytes; strcpy(imageB.format, ".fits.z");
  /* #7 Set BLOB state to Ok */
imageBP.s = IPS_OK; IDSetBLOB (&imageBP, NULL);
  /* #8 Set Exposure status to Ok */
ExposeTimeNP.s = IPS_OK; IDSetNumber(&ExposeTimeNP, "Sending FITS..."); /* #9 Let's never forget to free our memory */
free (fitsData); free (compressedData);
}

We're done! The following is a screenshot of the CCD simulator under KStars.

CCD Simulator Under KStars
Enlarge
CCD Simulator Under KStars
[edit]

Video

Video support in INDI is based on the implementation of the Video4Linux project. INDI supports both V4L1 and V4L2, but it is highly recommended to write drivers in V4L2 as V4L1 is obselete.Property-wise, webcams drivers are identical to those of CCDs, with a addition of a few webcams-specific properties like live video streams.

Developing INDI webcam drivers is a simple three-step process:

  1. Make sure that your webcam is supported under the Video For Linux architecture, either V4L1 or V4L2.
  2. v4ldriver.[h,cpp] provide generic V4L access for both V4L1 and V4L2, subclass V4L_Driver to add support for webcam-specific functionality. Refer to v4lphilips.[h,cpp] for an example implementation.
  3. After you create your webcam specific class, you need to link your class to form an INDI driver. Check indi_philips.[h,cpp] in the source distribution for further details.
  4. Provide users with a choice of compressed vs. raw streams which will enable users to balance the Network vs. CPU load to match their requirtments.
[edit]

Filter wheels and focusers

[edit]

Filter Wheel

Filter wheel devices perfrom one simple function: rotate the wheel to the target slot. Suppose we have a filter wheel with N slots, we need to define a standard number property (FILTER_SLOT) for slots 0 to N-1. The designation of each slot is performed in the client (e.g. http://docs.kde.org/development/en/kdeedu/kstars/indi-capture.html).

Refer to fli_wheel.c in the source distribution for an example implementation.

[edit]

Focusers

Electric focusers perform fine-tuned focusing of the telescope primary mirror. Focusers should be able to focus in and out at different speeds/rates. Furthermore, drivers can provide the user with a timed focus operation (e.g. focus in at rate X for Y seconds). These functions are encapsulated in the following properties.

Device standard properties:

  • Focus Speed: Select focusing rate (halt, slow, medium, fast). FOCUS_SPEED.
  • Focus Motion: Select focusing direction (in or out). FOCUS_MOTION.
  • Focus Timer: Perform focus operation in the specified direction and speed for X milliseconds. FOCUS_TIMER

Prev: 6. Driver Construction
Next: 8. Status and Command behavior
Retrieved from "http://indi.sourceforge.net/index.php/Developing_INDI_drivers"

Navigation

  • Main Page
  • Community portal
  • Current events
  • Recent changes
  • Random page
  • Help
  • Manual

Toolbox

  • What links here
  • Related changes
  • Upload file
  • Special pages
  • Printable version
  • Permanent link

Personal tools

  • Log in / create account
INDI Library - 2008 - Jasem Mutlaq (mutlaqja AT ikarustech DOT com)
SourceForge.net Logo