/* libargus/libargus.h * * Client-side interface to argusd. * * Copyright (C) 2004 * Andy Goth * * This code is available under the GNU General Public License; see COPYING. */ #ifndef SEEN_LIBARGUS_LIBARGUS_H #define SEEN_LIBARGUS_LIBARGUS_H /* Forward declaration. */ struct argus; typedef struct argus argus_t; #if 0 /* Summary: */ typedef int (*argus_cb_t)(argus_t* ctx, char* sensor, int value, void* arg); typedef int (*argus_async_cb_t)(argus_t* ctx, void* arg); struct argus { int socket_fd; /* fd for argusd socket (-1 if closed). */ char* socket_path; /* Path to argusd socket node. */ int proto_version; /* Protocol version being used. */ char** sensor_names_all; /* Sorted list of available sensors. */ int sensor_count_all; /* Number of available sensors. */ char** sensor_names; /* List of sensors being monitored. */ int* sensor_values; /* Current values for sensors. */ argus_cb_t* sensor_callbacks; /* Callback functions for sensors. */ void** sensor_cb_args; /* void*'s passed to sensor callbacks. */ int sensor_count; /* Number of sensors being monitored. */ argus_cb_t packet_callback; /* Callback for each data packet. */ void* packet_cb_arg; /* void* passed to packet_callback(). */ argus_async_cb_t async_callback;/* Asynchronous callback, or NULL. */ void* async_cb_arg; /* void* passed to async_callback(). */ device_t* device; /* For use with the evlist library. */ evlist_t* evlist; /* evlist on which device is registered. */ int own_evlist; /* Do we own the evlist? */ key_t shm_key; /* Key for the argus shm, if attached. */ char* shm_data; /* Pointer to shm data (or NULL). */ int shm_data_len; /* Number of bytes in the shm segment. */ }; extern int argus_connect (argus_t* ctx, evlist_t* evlist, char* socket); extern int argus_disconnect(argus_t* ctx); extern int argus_listen (argus_t* ctx, char** sensors, int count, int* error); extern int argus_callback (argus_t* ctx, char* sensor, argus_cb_t cb, void* arg); extern int argus_loop (argus_t* ctx); extern int argus_loop_next (argus_t* ctx, int timeout); extern int argus_loop_exit (argus_t* ctx); extern int argus_shm_open (argus_t* ctx); extern int argus_shm_close (argus_t* ctx); extern int argus_async_connect (argus_t* ctx, evlist_t* evlist, char* socket, argus_async_cb_t cb, void* arg); extern int argus_async_listen (argus_t* ctx, char** sensors, int count, int* error, argus_async_cb_t cb, void* arg); extern int argus_async_shm_open(argus_t* ctx, argus_async_cb_t cb, void* arg); #endif /* Typedef: argus_cb_t * Sensor/packet callback function, executed every time a sensor changes or a * data packet is received, depending on how it is registered. * * Argument: argus_t* ctx * Argus connection context. This is most useful for getting at sensor * values. * * Argument: char* sensor * Name of the sensor triggering the callback. In the case of packet * callbacks, this argument is NULL. * * Argument: int value * Current value of the sensor. For packet callbacks, this is -1. * * Argument: void* arg * Extra parameter, as passed to argus_ll_connect(), argus_ll_listen(), or * argus_ll_shm_open(). This can be NULL if not needed or can point to a * struct containing additional data necessary for the callback function. * * Return value: int * On success, 0. On failure, -1, and errno should be set. If the callback * function returns error, argus_read() returns the same error, which causes * argus_loop() to exit. To exit the enclosing argus_loop() without * returning an error, use argus_loop_exit(). */ typedef int (*argus_cb_t)(argus_t* ctx, char* sensor, int value, void* arg); /* Typedef: argus_ll_cb_t * Callback function executed upon completion of an asynchronous low-level * operation initiated by argus_ll_*(). * * Argument: argus_t* ctx * Argus connection context. * * Argument: void* arg * Extra parameter, as passed to argus_callback() when registering this * callback function. This can be NULL if not needed or can point to a * struct containing additional data necessary for the callback function. * * Return value: int * On success, 0. On failure, -1, and errno should be set. If the callback * function returns error, causing evlist_loop() (therefore argus_loop()) to * fail. Use evlist_loop_exit() or argus_loop_exit() to quit the * enclosing event loop without incurring an error message. */ typedef int (*argus_ll_cb_t)(argus_t* ctx, void* arg); struct argus { /* fd used for reading from and writing to the argusd socket. If the * socket is closed (i.e., hasn't been opened yet or was closed and not * yet destroyed), this is -1. */ int socket_fd; /* Path to the argusd socket node. Can be either a filesystem path or a * 108-byte name in the abstract socket namespace, although the latter * is untested. */ char* socket_path; /* The protocol version being used. This is equal to the lesser of the * advertised client and server protocol versions. */ int proto_version; /* Sorted list of all sensors available on the argusd server. These names * are retrieved upon initial connection. */ char** sensor_names_all; /* Total number of available sensors on the argusd server. */ int sensor_count_all; /* List of names of the sensors currently being listened to. This array is * length-counted by sensor_count. Elements in this list are really * pointers into sensor_names_all, but that's not important. :^) */ char** sensor_names; /* The most recently-read values for all of the sensors. This is a * parallel array of sensor_names, so the value of the sensor named * sensor_names[5] is stored at sensor_values[5]. */ int* sensor_values; /* List of callback functions for each sensor. A NULL function pointer * indicates that a given sensor currently has no callback. Again, this is * parallel with sensor_names and sensor_values. */ argus_cb_t* sensor_callbacks; /* Extra void* arguments to be passed to the sensor callbacks upon * execution. This is useful to give the callbacks some context, making it * possible to use the same callback for multiple sensors and have it * behave differently based on the value of its extra argument. */ argus_cb_t* sensor_cb_args; /* The length of the sensor_names, sensor_values, sensor_callbacks, and * sensor_cb_args arrays. This is equal to the number of sensors currently * being listened to. */ int sensor_count; /* Callback to be executed every time a new data packet is received. Since * data packets are only sent whenever a sensor changes, this function * won't be called needlessly. Unlike registering this callback with * every sensor individually, it'll only be called once per packet. * Packet callbacks are executed before sensor callbacks. */ argus_cb_t packet_callback; /* Extra argument to be passed to the packet_callback when executed. */ void* packet_cb_arg; /* Pointer to the device_t struct used by the underlying evlist library. * Manipulating the contents of this struct isn't necessary for libargus * client applications. */ device_t* device; /* The libargus device is registered on this evlist, so it's equivalent to * device->evlist. But duplicating it out here makes some things a little * more convenient. */ evlist_t* evlist; /* If true, we're in charge of the evlist and must evlist_cleanup() and * free() it upon argus_disconnect(), argus_shm_open(), or the completion * of argus_async_shm_open(). So if you want to insert your own events * into the list, you probably want to take charge of the evlist_t struct * as well, or else you might be... surprised. */ int own_evlist; /* Key for the argus shared memory segment (shm). The shm is made through * the argus_shm_open() and argus_ll_shm_open() calls. If the shm is not * yet attached, this field is set to IPC_PRIVATE. */ key_t shm_key; /* Pointer to the argus shm data, or NULL if the shm isn't attached. */ char* shm_data; /* Length in bytes of the shm data segment. If the shm is not yet * attached, this field is 0. */ int shm_data_len; }; /* Function: argus_connect() * Opens a connection to argusd. This function doesn't return until the * connection is successfully opened or a fatal error is encountered. After * connection, proto_version, sensor_names_all, and sensor_count_all fields * of ctx are filled, and it becomes possible to run argus_listen(), * argus_shm_open(), argus_disconnect(), etc. * * Argument: argus_t* ctx * Argus connection context. This argus_t* is passed to all other argus * functions. * * Argument: evlist_t* evlist * If NULL, libargus will internally manage its evlist_t structure. This is * convenient but makes it unsafe for you to add devices and scheduled * events, since disconnection from argusd will cause the evlist to be * deallocated. So if that's a problem, pass the address of your own evlist, * which must have already been prepared with evlist_init(). * * Argument: char* socket * Path to the socket node to connect to. If a C-style null-terminated * string, this gives the path to a UNIX socket in the filesystem. If the * first byte is \0, this is a 108-byte string giving the name of a socket in * Linux's abstract socket namespace (although that may just be a rumor). * * Return value: int * On success, 0. On failure, -1, and errno is set. */ extern int argus_connect(argus_t* ctx, evlist_t* evlist, char* socket); /* Function: argus_disconnect() * Closes a connection to argusd. * * Argument: argus_t* ctx * Argus connection context describing the connection to close. If this call * succeeds, and if the argus shm is not currently open, then the argus_t is * deallocated and therefore this pointer becomes invalid and should not be * passed to any argus functions. On the other hand, if the argus shm is * open, then deallocation is deferred to argus_shm_close(). * * Return value: int * On success, 0. On failure, -1, and errno is set. */ extern int argus_disconnect(argus_t* ctx); /* Function: argus_listen() * Registers interest in the given list of sensors. This function returns * after completing all negotiation with argusd. Values for all requested * sensors are provided by the next call to argus_loop_next(), and at that * time, all callback functions will be triggered. * * Argument: argus_t* ctx * Argus connection context. * * Argument: char** sensors * List of names of sensors to listen to. Elements in this list can easily * be pointers into ctx->sensor_names_all. In fact, to listen to all * sensors, just pass ctx->sensor_names_all directly. This list is copied * to sensor_names. It is an error to specify a single sensor more than once. * * Argument: int count * Number of elements in the sensors list. If passing ctx->sensor_names_all * for the sensors argument, pass ctx->sensor_count_all as count. Because * requesting a single sensor more than once is disallowed, it is an error * for this argument to exceed ctx->sensor_count_all. * * Argument: int* error * If not NULL, *error is set equal to the index of the first element in * sensors that caused an error. This can be caused by the sensor not being * present in ctx->sensor_names_all or being a duplicate of a previously- * listed sensor. In case of success, *error is set to -1. * * Return value: int * On success, 0. On failure, -1, and errno is set. */ extern int argus_listen(argus_t* ctx, char** sensors, int count, int* error); /* Function: argus_callback() * Registers a callback function for a given named sensor. This callback * function is executed every time the named sensor's value changes. * * Argument: argus_t* ctx * Argus connection context. * * Argument: char* sensor * Name of the sensor for which values changes trigger the callback * function. Note that a single sensor can have only one callback function. * This parameter can be a pointer into the ctx->sensor_names array. * * Argument: argus_cb_t cb * Pointer to the function to be called when the sensor changes. Since only * one callback can be registered for each sensor, this replaces the previous * value. Passing NULL for this argument disables the callback. * * Argument: void* arg * Extra argument to pass to the callback function. If you don't need this * feature, just pass NULL. * * Return value: int * On success, 0. On failure, -1, and errno is set. */ extern int argus_callback(argus_t* ctx, char* sensor, argus_cb_t cb, void* arg); /* Function: argus_loop() * Enters an event loop which waits for incoming data from the argusd server * and continually processes it, executing callback functions as necessary. * If a callback function returns negative, this function returns with error, * preserving the errno value set by the callback function. * * If you need to process other events (file readability/writability, timer * events), use the low-level libargus interface and the evlist functions. * If you cannot integrate your other event handling in an evlist-compatible * form (for instance, you might be using a GUI library which fails to expose * the fd used for communication with the X server), you have two options. * You can make a while loop which calls each event loop function (including * argus_loop_next()). Specify a timeout for each, if possible. If that's * not acceptable (it's not very efficient and not always be supported), then * execute argus_loop() in its own thread. Sigh. * * argus_loop(ctx) is equivalent to evlist_loop(ctx->evlist). * * Argument: argus_t* ctx * Argus connection context. * * Return value: int * On success, 0. On failure, -1, and errno is set. */ extern int argus_loop(argus_t* ctx); /* Function: argus_loop_next() * Halts program execution until new data is available from the argusd * server. Doesn't return until a data packet arrives, the timeout expires, * or an error occurs (such as disconnection). When new data arrives, all * appropriate callback functions are executed. * * If your program needs to do more than simply Argus processing, you can * insert non-argus event sources into ctx->evlist using the evlist * functions. These events can cause argus_loop_next() to exit early, which * is to say argus_loop_next() processes the next event *of any type*, not * just data packets from the argusd server. * * argus_loop_next(ctx, timeout) is really just an alternate spelling for * evlist_loop_next(ctx->evlist, timeout). * * Argument: argus_t* ctx * Argus connection context. * * Argument: int timeout * Maximum amount of time in milliseconds argus_loop_next() will block * program execution waiting for data to arrive. If negative, no timeout is * set, and argus_loop_next() will not return until data arrives or an error * occurs. If zero, argus_loop_next() will process any backlogged events and * then return as soon as possible. * * Return value: int * On success, 0. On failure, -1, and errno is set. If new data is * available from the server, this function returns 1. */ extern int argus_loop_next(argus_t* ctx, int timeout); /* Function: argus_loop_exit() * If called from a sensor callback, causes the enclosing argus_loop() to * exit, returning control to its caller. This works precisely the same was * as evlist_loop_exit(ctx->evlist). * * Argument: argus_t* ctx * Argus connection context. * * Return value: int * On success, 0. On failure, -1, and errno is set. */ extern int argus_loop_exit(argus_t* ctx); /* Function: argus_shm_open() * Opens a read-only shm connected to the argusd server. Attaches * ctx->shm_data to the shm. Closes the socket connection to the server. * Modifies ctx->sensor_values to point to the sensor data in the shm. Sets * ctx->sensor_names to be equal to ctx->sensor_names_all. Disables all * sensor and packet callbacks. * * After this function is successfully executed, ctx->device is removed from * the ctx->evlist event list, so you won't be able to use the argus_loop*() * functions to detect sensor data packets--- instead you may wish to use * evlist_sched_add() on ctx->evlist to schedule a timer-driven callback to * process any possible updates to ctx->sensor_values. * * Beware that after this call the sensor ordering ctx->sensor_values will * probably change. Check ctx->sensor_names to see what names are associated * with which indices. * * Argument: argus_t* ctx * Argus connnection context through which the shm is to be opened. * * Return value: int * On success, 0. On failure, -1, and errno is set. */ extern int argus_shm_open(argus_t* ctx); /* Function: argus_shm_close() * Closes a previously-opened shm connected to the argusd server. * * Argument: argus_t* ctx * Argus connection context describing the shm to close. * * Return value: int * On success, 0. On failure, -1, and errno is set. */ extern int argus_shm_close(argus_t* ctx); /* Function: argus_async_connect() * Initializes an argus_t structure to serve as a connection context, adds it * to the named evlist, and starts the connection process. After connection * is complete, the callback is executed. Use this function if you don't * want program execution to halt while connection takes place. * * Argument: argus_t* ctx * The connection context to initialize and use. * * Argument: evlist_t* evlist * The evlist on which to place the device associated with the upcoming argus * connection. You should have already called evlist_init() on the evlist. * Or pass NULL to make libargus allocate its own evlist. * * Argument: char* socket * Path to the UNIX socket node to connect to. * * Argument: argus_async_cb_t cb * Callback function to execute after successful connection or asynchronous * connection error. errno is set to indicate the connection status (0 means * success). In case of success, the state of ctx is as it would be if the * argus_connect() function were used. * * Argument: void* arg * Extra parameter passed to the callback function. * * Return value: int * On success, 0. On failure, -1, and errno is set. */ extern int argus_async_connect(argus_t* ctx, evlist_t* evlist, char* socket, argus_async_cb_t cb, void* arg); /* Function: argus_async_listen() * Sends a sensor listen request to the server, and executes the callback * after confirmation or asynchronous error. Use this function if you don't * want program execution to halt while the listen request takes place. * * Argument: argus_t* ctx * The connection context. * * Argument: char** sensors * List of names of sensors to attempt to listen to. * * Argument: int count * Number of elements in the sensors list. * * Argument: int* error * This argument behaves exactly like its argus_listen() counterpart. * * Argument: argus_async_cb_t cb * Callback function to execute after confirmation of successful listen or * asynchronous error. errno is set to indicate the status (0 means success). * * Argument: void* arg * Extra parameter passed to the callback function. * * Return value: int * On success, 0. On failure, -1, and errno is set. */ extern int argus_async_listen(argus_t* ctx, char** sensors, int count, int* error, argus_async_cb_t cb, void* arg); /* Function: argus_async_shm_open() * Starts the process of connecting to the argusd's shm. Executes the * callback after asynchronous error or success. Use this function if you * don't want program execution to halt while the shm open request happens. * * Argument: argus_t* ctx * The connection context. * * Argument: argus_async_cb_t cb * Callback function to be executed after successful shm open or asynchronous * error. errno is set to indicate the status (0 means success). In case of * success, the state of ctx is just like as if argus_shm_open() had been * called, which means a great deal has changed--- everything has been * switched from socket-based to shm-based operation. * * Argument: void* arg * Extra parameter passed to the callback function. * * Return value: int * On success, 0. On failure, -1, and errno is set. */ extern int argus_async_shm_open(argus_t* ctx, argus_async_cb_t cb, void* arg); #endif /* vim: set ts=4 sts=4 sw=4 tw=80 et: */ /* EOF */