/* See LICENSE file for copyright and license details. */ #ifndef LIBRADHARC_H #define LIBRADHARC_H #include #include #include #include #include #include enum libradharc_property { LIBRADHARC_PROPERTY_FADE_IN, LIBRADHARC_PROPERTY_FADE_OUT, LIBRADHARC_PROPERTY_HIGH_TEMPERATURE, LIBRADHARC_PROPERTY_LOW_TEMPERATURE, LIBRADHARC_PROPERTY_HIGH_ELEVATION, LIBRADHARC_PROPERTY_LOW_ELEVATION, LIBRADHARC_PROPERTY_LOCATION, LIBRADHARC_PROPERTY_OPERATION_MODE, LIBRADHARC_PROPERTY_TEMPERATURE, LIBRADHARC_PROPERTY_PRIORITY, LIBRADHARC_PROPERTY_VENDOR_OPTION, LIBRADHARC_PROPERTY_STATUS }; enum libradharc_request_type { LIBRADHARC_REQUEST_GET, LIBRADHARC_REQUEST_SET, LIBRADHARC_REQUEST_UNSET, LIBRADHARC_REQUEST_SIGNAL }; /** * How radharc determines which colour temperature to apply */ enum libradharc_operation_mode { /** * A specific colour temperature has been selected */ LIBRADHARC_OPERATION_STATIC, /** * A colour temperature range has been selected * along with a range of solar elevations and the * user's location. The temperature is changed * gradually by mapping to current solar elevation's * position in the range of solar elevations * (clips to the range's boundaries) to a colour * temperature, in corresponding position, the * colour temperature range. */ LIBRADHARC_OPERATION_BY_SOLAR_ELEVATION }; /** * Request response type */ enum libradharc_response_type { /** * The made request was invalid */ LIBRADHARC_RESPONSE_INVALID_REQUEST, /** * Value sent with the request was unsupported */ LIBRADHARC_RESPONSE_UNSUPPORTED, /** * Action performed */ LIBRADHARC_RESPONSE_ACK, /** * No action to perform */ LIBRADHARC_RESPONSE_ACK_NOOP, /** * The requested property is not set */ LIBRADHARC_RESPONSE_UNSET, /** * The requested property is set to the true boolean value */ LIBRADHARC_RESPONSE_YES, /** * The requested property is set to the false boolean value */ LIBRADHARC_RESPONSE_NO, /** * A server-side error was encountered */ LIBRADHARC_RESPONSE_ERROR_STRING, /** * The requested property is set, and has a string value */ LIBRADHARC_RESPONSE_SET_STRING, /** * The requested property is set, and has a time duration */ LIBRADHARC_RESPONSE_SET_TIME, /** * The requested property is set, and has a real value */ LIBRADHARC_RESPONSE_SET_REAL, /** * The requested property is set, and has two real values * * For the geographical location, this would be the the * latitude as the first value, and a the longitude as * the second value */ LIBRADHARC_RESPONSE_SET_REAL_PAIR, /** * The requested property is set, and has a signed * 64-bit integer value */ LIBRADHARC_RESPONSE_SET_SIGNED64, /** * The requested property is set, and has a named value */ LIBRADHARC_RESPONSE_SET_ENUM }; /** * Response from radharc */ struct libradharc_response { /** * Response from radharc or indicate of * type used for the response */ enum libradharc_response_type type; /** * Value send back by radharc * * Only set if `.type` has one of the values * listed the union member fields. The following * values of `.type` do not have an associated * value: * - `LIBRADHARC_RESPONSE_INVALID_REQUEST` * - `LIBRADHARC_RESPONSE_UNSUPPORTED` * - `LIBRADHARC_RESPONSE_ACK` * - `LIBRADHARC_RESPONSE_ACK_NOOP` * - `LIBRADHARC_RESPONSE_UNSET` * - `LIBRADHARC_RESPONSE_YES` * - `LIBRADHARC_RESPONSE_NO` */ union { /** * Use if `.type` is `LIBRADHARC_RESPONSE_SET_STRING` or * `LIBRADHARC_RESPONSE_ERROR_STRING` */ const char *string; /** * Use if `.type` is `LIBRADHARC_RESPONSE_SET_TIME` */ struct timespec time; /** * Use if `.type` is `LIBRADHARC_RESPONSE_SET_REAL` */ double real; /** * Use if `.type` is `LIBRADHARC_RESPONSE_SET_REAL_PAIR` */ double real_pair[2]; /** * Use if `.type` is `LIBRADHARC_RESPONSE_SET_SIGNED64` */ int64_t signed64; /** * Use if `.type` is `LIBRADHARC_RESPONSE_SET_ENUM`, * and the response is for a get-request for radharc's * operation mode */ enum libradharc_operation_mode operation_mode; } value; }; /** * Parse a response from radharc * * All requests generate a response, which are sent in order * * @param msg The received message * @param msglen The length of the message * @param response_out Output parameter for the prased message * @return 0 on success, -1 on failure * * @throws EINVAL `msglen` is 0 * @throws EINVAL `msg` is `NULL` * @throws EINVAL `response_out` is `NULL` * @throws EBADMSG The received message is invalid */ int libradharc_parse_response(const void *msg, size_t msglen, struct libradharc_response *response_out); size_t libradharc_format_request__n__(void *buffer, enum libradharc_request_type type, int what, size_t n, ...); inline size_t libradharc_format_request__0__(void *buffer, enum libradharc_request_type type, int what) { return libradharc_format_request__n__(buffer, type, what, 0); } inline size_t libradharc_format_request__1__(void *buffer, enum libradharc_request_type type, int what, const void *value1, size_t size1) { return libradharc_format_request__n__(buffer, type, what, 1, value1, size1); } inline size_t libradharc_format_request__2__(void *buffer, enum libradharc_request_type type, int what, const void *value1, size_t size1, const void *value2, size_t size2) { return libradharc_format_request__n__(buffer, type, what, 2, value1, size1, value2, size2); } inline size_t libradharc_format_request__3__(void *buffer, enum libradharc_request_type type, int what, const void *value1, size_t size1, const void *value2, size_t size2, const void *value3, size_t size3) { return libradharc_format_request__n__(buffer, type, what, 3, value1, size1, value2, size2, value3, size3); } inline size_t libradharc_format_get_request__0__(void *buffer, enum libradharc_property property) { return libradharc_format_request__0__(buffer, LIBRADHARC_REQUEST_GET, (int)property); } inline size_t libradharc_format_get_request__s__(void *buffer, enum libradharc_property property, const char *arg1) { if (!arg1) { errno = EINVAL; return 0; } return libradharc_format_request__1__(buffer, LIBRADHARC_REQUEST_GET, (int)property, arg1, strlen(arg1) + 1U); } inline size_t libradharc_format_set_request__64i__(void *buffer, enum libradharc_property property, int64_t arg1) { return libradharc_format_request__1__(buffer, LIBRADHARC_REQUEST_SET, (int)property, &arg1, sizeof(arg1)); } inline size_t libradharc_format_set_request__i__(void *buffer, enum libradharc_property property, int arg1) { return libradharc_format_request__1__(buffer, LIBRADHARC_REQUEST_SET, (int)property, &arg1, sizeof(arg1)); } inline size_t libradharc_format_set_request__r__(void *buffer, enum libradharc_property property, double arg1) { return libradharc_format_request__1__(buffer, LIBRADHARC_REQUEST_SET, (int)property, &arg1, sizeof(arg1)); } inline size_t libradharc_format_set_request__rt__(void *buffer, enum libradharc_property property, double arg1, const struct timespec *arg2) { if (!arg2 || arg2->tv_sec < 0 || arg2->tv_nsec < 0 || arg2->tv_nsec >= 1000000000L) { errno = EINVAL; return 0; } return libradharc_format_request__3__(buffer, LIBRADHARC_REQUEST_SET, property, &arg1, sizeof(arg1), &arg2->tv_sec, sizeof(arg2->tv_sec), &arg2->tv_nsec, sizeof(arg2->tv_nsec)); } inline size_t libradharc_format_set_request__rr__(void *buffer, enum libradharc_property property, double arg1, double arg2) { return libradharc_format_request__2__(buffer, LIBRADHARC_REQUEST_SET, (int)property, &arg1, sizeof(arg1), &arg2, sizeof(arg2)); } inline size_t libradharc_format_set_request__s__(void *buffer, enum libradharc_property property, const char *arg1) { if (!arg1) { errno = EINVAL; return 0; } return libradharc_format_request__1__(buffer, LIBRADHARC_REQUEST_SET, (int)property, arg1, strlen(arg1) + 1U); } inline size_t libradharc_format_set_request__ss__(void *buffer, enum libradharc_property property, const char *arg1, const char *arg2) { if (!arg1 || !arg2) { errno = EINVAL; return 0; } return libradharc_format_request__2__(buffer, LIBRADHARC_REQUEST_SET, (int)property, arg1, strlen(arg1) + 1U, arg2, strlen(arg2) + 1U); } inline size_t libradharc_format_set_request__t__(void *buffer, enum libradharc_property property, const struct timespec *arg1) { if (!arg1 || arg1->tv_sec < 0 || arg1->tv_nsec < 0 || arg1->tv_nsec >= 1000000000L) { errno = EINVAL; return 0; } return libradharc_format_request__2__(buffer, LIBRADHARC_REQUEST_SET, (int)property, &arg1->tv_sec, sizeof(arg1->tv_sec), &arg1->tv_nsec, sizeof(arg1->tv_nsec)); } inline size_t libradharc_format_unset_request__0__(void *buffer, enum libradharc_property property) { return libradharc_format_request__0__(buffer, LIBRADHARC_REQUEST_UNSET, (int)property); } inline size_t libradharc_format_signal_request__0__(void *buffer, int signal) { return libradharc_format_request__0__(buffer, LIBRADHARC_REQUEST_SIGNAL, signal); } inline size_t libradharc_format_signal_request__t__(void *buffer, int signal, const struct timespec *arg1) { if (!arg1 || arg1->tv_sec < 0 || arg1->tv_nsec < 0 || arg1->tv_nsec >= 1000000000L) { errno = EINVAL; return 0; } return libradharc_format_request__2__(buffer, LIBRADHARC_REQUEST_SIGNAL, signal, &arg1->tv_sec, sizeof(arg1->tv_sec), &arg1->tv_nsec, sizeof(arg1->tv_nsec)); } inline size_t libradharc_format_set_request__rnt__(void *buffer, enum libradharc_property property, double arg1, const struct timespec *arg2) { if (arg2) return libradharc_format_set_request__rt__(buffer, property, arg1, arg2); else return libradharc_format_set_request__r__(buffer, property, arg1); } inline size_t libradharc_format_set_request__sns__(void *buffer, enum libradharc_property property, const char *arg1, const char *arg2) { if (arg2) return libradharc_format_set_request__ss__(buffer, property, arg1, arg2); else return libradharc_format_set_request__s__(buffer, property, arg1); } inline size_t libradharc_format_signal_request__nt__(void *buffer, int signal, const struct timespec *arg1) { if (arg1) return libradharc_format_signal_request__t__(buffer, signal, arg1); else return libradharc_format_signal_request__0__(buffer, signal); } /** * Format a message that instructs radharc to reconfigure * its effect fade-in time * * It is unspecified how this effects any ongoing fade-in * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @param duration The new fade duration * @return The size of the message, 0 on failure * * @throws EINVAL `duration` is `NULL` * @throws EINVAL `duration->tv_nsec` is invalid * @throws EINVAL `duration->tv_sec` is negative */ inline size_t libradharc_format_set_fade_in(void *buffer, const struct timespec *duration) { return libradharc_format_set_request__t__(buffer, LIBRADHARC_PROPERTY_FADE_IN, duration); } /** * Format a message that instructs radharc to send back * its currently configured effect fade-in time * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @return The size of the message, 0 on failure */ inline size_t libradharc_format_get_fade_in(void *buffer) { return libradharc_format_get_request__0__(buffer, LIBRADHARC_PROPERTY_FADE_IN); } /** * Format a message that instructs radharc to reconfigure * its effect fade-out time * * It is unspecified how this effects any ongoing fade-out * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @param duration The new fade duration * @return The size of the message, 0 on failure * * @throws EINVAL `duration` is `NULL` * @throws EINVAL `duration->tv_nsec` is invalid * @throws EINVAL `duration->tv_sec` is negative */ inline size_t libradharc_format_set_fade_out(void *buffer, const struct timespec *duration) { return libradharc_format_set_request__t__(buffer, LIBRADHARC_PROPERTY_FADE_OUT, duration); } /** * Format a message that instructs radharc to send back * its currently configured effect fade-out time * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @return The size of the message, 0 on failure */ inline size_t libradharc_format_get_fade_out(void *buffer) { return libradharc_format_get_request__0__(buffer, LIBRADHARC_PROPERTY_FADE_OUT); } /** * Format a message that instructs radharc to configure * the colour temperature that shall be applied * when the Sun's elevation at least at the configured * upper threshold of twilight, that at daytime after * daybreak * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @param temperature The colour temperature, in Kelvins, must be at least 1000 * @return The size of the message, 0 on failure */ inline size_t libradharc_format_set_high_temperature(void *buffer, double temperature) { return libradharc_format_set_request__r__(buffer, LIBRADHARC_PROPERTY_HIGH_TEMPERATURE, temperature); } /** * Format a message that instructs radharc to send back * its configured colour temperature that shall be applied * when the Sun's elevation at least at the configured * upper threshold of twilight, that at daytime after * daybreak * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @return The size of the message, 0 on failure */ inline size_t libradharc_format_get_high_temperature(void *buffer) { return libradharc_format_get_request__0__(buffer, LIBRADHARC_PROPERTY_HIGH_TEMPERATURE); } /** * Format a message that instructs radharc to configure * the colour temperature that shall be applied * when the Sun's elevation at most at the configured * lower threshold of twilight, that at nighttime after * nightfall * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @param temperature The colour temperature, in Kelvins, must be at least 1000 * @return The size of the message, 0 on failure */ inline size_t libradharc_format_set_low_temperature(void *buffer, double temperature) { return libradharc_format_set_request__r__(buffer, LIBRADHARC_PROPERTY_LOW_TEMPERATURE, temperature); } /** * Format a message that instructs radharc to send back * its configured colour temperature that shall be applied * when the Sun's elevation at most at the configured * lower threshold of twilight, that at nighttime after * nightfall * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @return The size of the message, 0 on failure */ inline size_t libradharc_format_get_low_temperature(void *buffer) { return libradharc_format_get_request__0__(buffer, LIBRADHARC_PROPERTY_LOW_TEMPERATURE); } /** * Format a message that instructs radharc to configure * the upper theshold of twilight, that is, the solar * elevation that marks the end of daybreak and the * beginning of nightfall * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @param degrees The solar elevation, in degrees * @return The size of the message, 0 on failure */ inline size_t libradharc_format_set_high_elevation(void *buffer, double degrees) { return libradharc_format_set_request__r__(buffer, LIBRADHARC_PROPERTY_HIGH_ELEVATION, degrees); } /** * Format a message that instructs radharc to send back * its configured upper theshold of twilight, that is, * the solar elevation that marks the end of daybreak * and the beginning of nightfall * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @return The size of the message, 0 on failure */ inline size_t libradharc_format_get_high_elevation(void *buffer) { return libradharc_format_get_request__0__(buffer, LIBRADHARC_PROPERTY_HIGH_ELEVATION); } /** * Format a message that instructs radharc to configure * the lower theshold of twilight, that is, the solar * elevation that marks the end of nightfall and the * beginning of daybreak * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @param degrees The solar elevation, in degrees * @return The size of the message, 0 on failure */ inline size_t libradharc_format_set_low_elevation(void *buffer, double degrees) { return libradharc_format_set_request__r__(buffer, LIBRADHARC_PROPERTY_LOW_ELEVATION, degrees); } /** * Format a message that instructs radharc to send back * its configured lower theshold of twilight, that is, * the solar elevation that marks the end of nightfall * and the beginning of daybreak * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @return The size of the message, 0 on failure */ inline size_t libradharc_format_get_low_elevation(void *buffer) { return libradharc_format_get_request__0__(buffer, LIBRADHARC_PROPERTY_LOW_ELEVATION); } /** * Format a message that instructs radharc to reconfigured * the geographical location * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @param latitude The new latitude, in degrees north of the equator according to GPS * @param longitude The new longitude, in degrees east of the prime meridian according to GPS * @return The size of the message, 0 on failure */ inline size_t libradharc_format_set_location(void *buffer, double latitude, double longitude) { return libradharc_format_set_request__rr__(buffer, LIBRADHARC_PROPERTY_LOCATION, latitude, longitude); } /** * Format a message that instructs radharc to send back * its currently configured geographical location * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @return The size of the message, 0 on failure */ inline size_t libradharc_format_get_location(void *buffer) { return libradharc_format_get_request__0__(buffer, LIBRADHARC_PROPERTY_LOCATION); } /** * Format a message that instructs radharc remove its * currently configured geolocation, causing it to * freeze at the current temperature, until modified * or a new location is set, unless another operation * mode that doesn't need the user's location is being * used * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @return The size of the message, 0 on failure */ inline size_t libradharc_format_unset_location(void *buffer) { return libradharc_format_unset_request__0__(buffer, LIBRADHARC_PROPERTY_LOCATION); } /** * Format a message that instructs radharc to use another * operation mode * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @param mode The new operation mode * @return The size of the message, 0 on failure */ inline size_t libradharc_format_set_operation_mode(void *buffer, enum libradharc_operation_mode mode) { return libradharc_format_set_request__i__(buffer, LIBRADHARC_PROPERTY_OPERATION_MODE, (int)mode); } /** * Format a message that instructs radharc to send back * its currently configured operation mode * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @return The size of the message, 0 on failure */ inline size_t libradharc_format_get_operation_mode(void *buffer) { return libradharc_format_get_request__0__(buffer, LIBRADHARC_PROPERTY_OPERATION_MODE); } /** * Format a message that instructs radharc to apply * a specific colour temperature * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @param temperature The temperature to apply, in Kelvins, must be at least 1000 * @param transition_duration The transition time, or `NULL` to use the configured fade time * (it's implementation specific how it is defined) * @return The size of the message, 0 on failure * * Implementations of radharc need not implement support for * smooth temperature transitions, so `transition_duration` * may be ignored */ inline size_t libradharc_format_set_temperature(void *buffer, double temperature, const struct timespec *transition_duration) { return libradharc_format_set_request__rnt__(buffer, LIBRADHARC_PROPERTY_TEMPERATURE, temperature, transition_duration); } /** * Format a message that instructs radharc to send back * its currently applied temperature * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @return The size of the message, 0 on failure */ inline size_t libradharc_format_get_temperature(void *buffer) { return libradharc_format_get_request__0__(buffer, LIBRADHARC_PROPERTY_TEMPERATURE); } /** * Format a message that instructs radharc to reconfigure * its effect priority * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @param priority The new priority * @return The size of the message, 0 on failure */ inline size_t libradharc_format_set_priority(void *buffer, int64_t priority) { return libradharc_format_set_request__64i__(buffer, LIBRADHARC_PROPERTY_PRIORITY, priority); } /** * Format a message that instructs radharc to send back * its currently configured effect priority * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @return The size of the message, 0 on failure */ inline size_t libradharc_format_get_priority(void *buffer) { return libradharc_format_get_request__0__(buffer, LIBRADHARC_PROPERTY_PRIORITY); } /** * Format a message that instructs radharc to apply * or modify an implemenation specific setting * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @param option The name of the option * @param value The value for the option, or `NULL` if there is none * @return The size of the message, 0 on failure * * @throws EINVAL `option` is `NULL` */ inline size_t libradharc_format_set_vendor_option(void *buffer, const char *option, const char *value) { return libradharc_format_set_request__sns__(buffer, LIBRADHARC_PROPERTY_VENDOR_OPTION, option, value); } /** * Format a message that instructs radharc to send * back the value of a implemenation specific setting * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @param option The name of the option * @return The size of the message, 0 on failure * * @throws EINVAL `option` is `NULL` */ inline size_t libradharc_format_get_vendor_option(void *buffer, const char *option) { return libradharc_format_get_request__s__(buffer, LIBRADHARC_PROPERTY_VENDOR_OPTION, option); } /** * Format a message that instructs radharc to send back * its current status * * radharc will respond with an with a single-line string, * but it's content is implementation defined * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @return The size of the message, 0 on failure */ inline size_t libradharc_format_get_status(void *buffer) { return libradharc_format_get_request__0__(buffer, LIBRADHARC_PROPERTY_STATUS); } /** * Format a message that instructs radharc to fade out its * effect and terminate * * Sending this message is equivalent to sending SIGINT once, * except the transition duration can be overridden ad hoc, * or twice if `transition_duration` is `{0, 0}` * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @param transition_duration The transition time, or `NULL` to use the configured fade out time * @return The size of the message, 0 on failure * * @throws EINVAL `transition_duration->tv_nsec` is invalid * @throws EINVAL `transition_duration->tv_sec` is negative */ inline size_t libradharc_format_smooth_terminate(void *buffer, const struct timespec *transition_duration) { return libradharc_format_signal_request__nt__(buffer, SIGINT, transition_duration); } /** * Format a message that instructs radharc to, once any * current transition has take place, terminate without * restoring the colour temperature * * Sending this message is equivalent to sending SIGHUP * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @return The size of the message, 0 on failure */ inline size_t libradharc_format_freeze_terminate(void *buffer) { return libradharc_format_signal_request__0__(buffer, SIGHUP); } /** * Format a message that instructs radharc to disable itself * * Sending this message is equivalent to sending SIGUSR1, * except the transition duration can be overridden ad hoc * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @param transition_duration The transition time, or `NULL` to use the configured fade out time * @return The size of the message, 0 on failure * * @throws EINVAL `transition_duration->tv_nsec` is invalid * @throws EINVAL `transition_duration->tv_sec` is negative */ inline size_t libradharc_format_disable(void *buffer, const struct timespec *transition_duration) { return libradharc_format_signal_request__nt__(buffer, SIGUSR1, transition_duration); } /** * Format a message that instructs radharc to enable itself * * Sending this message is equivalent to sending SIGUSR2, * except the transition duration can be overridden ad hoc * * @param buffer Output buffer for the message, or `NULL` to measure the required size * @param transition_duration The transition time, or `NULL` to use the configured fade in time * @return The size of the message, 0 on failure * * @throws EINVAL `transition_duration->tv_nsec` is invalid * @throws EINVAL `transition_duration->tv_sec` is negative */ inline size_t libradharc_format_enable(void *buffer, const struct timespec *transition_duration) { return libradharc_format_signal_request__nt__(buffer, SIGUSR2, transition_duration); } #endif