mirror of https://github.com/nirenjan/libx52.git
212 lines
5.5 KiB
C
212 lines
5.5 KiB
C
/*
|
|
* Saitek X52 Pro MFD & LED driver - Clock manager
|
|
*
|
|
* Copyright (C) 2021 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
#define PINELOG_MODULE X52D_MOD_CLOCK
|
|
#include "pinelog.h"
|
|
#include "x52d_config.h"
|
|
#include "x52d_clock.h"
|
|
#include "x52d_const.h"
|
|
#include "x52d_device.h"
|
|
|
|
static bool clock_enabled = false;
|
|
static int clock_primary_is_local = false;
|
|
|
|
void x52d_cfg_set_Clock_Enabled(bool enabled)
|
|
{
|
|
PINELOG_DEBUG(_("Setting clock enable to %s"),
|
|
enabled ? _("on") : _("off"));
|
|
clock_enabled = enabled;
|
|
}
|
|
|
|
void x52d_cfg_set_Clock_PrimaryIsLocal(bool param)
|
|
{
|
|
PINELOG_DEBUG(_("Setting %s clock timezone to %s"),
|
|
libx52_clock_id_to_str(LIBX52_CLOCK_1),
|
|
param ? _("local") : _("UTC"));
|
|
clock_primary_is_local = !!param;
|
|
}
|
|
|
|
static int get_tz_offset(const char *tz)
|
|
{
|
|
char *orig_tz = NULL;
|
|
char *orig_tz_copy = NULL;
|
|
time_t t;
|
|
struct tm tmp;
|
|
struct tm *timeval;
|
|
char *new_tz = NULL;
|
|
size_t new_tz_len;
|
|
int offset = 0;
|
|
|
|
new_tz_len = strlen(tz) + 2;
|
|
new_tz = malloc(new_tz_len);
|
|
if (new_tz == NULL) {
|
|
PINELOG_WARN(_("Unable to allocate memory for timezone. Falling back to UTC"));
|
|
goto cleanup;
|
|
}
|
|
snprintf(new_tz, new_tz_len, ":%s", tz);
|
|
|
|
orig_tz = getenv("TZ");
|
|
if (orig_tz != NULL) {
|
|
/* TZ was set in the environment */
|
|
orig_tz_copy = strdup(orig_tz);
|
|
if (orig_tz_copy == NULL) {
|
|
PINELOG_WARN(_("Unable to backup timezone environment. Falling back to UTC"));
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
setenv("TZ", new_tz, true);
|
|
t = time(NULL);
|
|
tzset();
|
|
timeval = localtime_r(&t, &tmp);
|
|
if (timeval != NULL) {
|
|
#if HAVE_STRUCT_TM_TM_GMTOFF
|
|
/* If valid, then timeval.tm_gmtoff contains the offset in seconds east
|
|
* of GMT. Divide by 60 to get the offset in minutes east of GMT.
|
|
*/
|
|
offset = (int)(timeval->tm_gmtoff / 60);
|
|
#else
|
|
/* The compiler does not provide tm_gmtoff. Fallback to using the
|
|
* timezone variable, which is in seconds west of GMT. Divide by -60 to
|
|
* get the offset in minutes east of GMT.
|
|
*
|
|
* ============
|
|
* XXX NOTE XXX
|
|
* ============
|
|
* timezone is always the default (non-summer) timezone offset from GMT.
|
|
* Therefore, this may not be accurate during the summer time months
|
|
* for the region in question.
|
|
*/
|
|
offset = (int)(timezone / -60);
|
|
#endif
|
|
}
|
|
|
|
cleanup:
|
|
if (orig_tz == NULL) {
|
|
unsetenv("TZ");
|
|
} else {
|
|
setenv("TZ", orig_tz_copy, true);
|
|
free(orig_tz_copy);
|
|
}
|
|
|
|
if (new_tz != NULL) {
|
|
free(new_tz);
|
|
}
|
|
|
|
tzset();
|
|
PINELOG_TRACE("Offset for timezone '%s' is %d", tz, offset);
|
|
return offset;
|
|
}
|
|
|
|
static void set_clock_offset(libx52_clock_id id, const char *param)
|
|
{
|
|
if (clock_enabled) {
|
|
PINELOG_DEBUG(_("Setting %s clock timezone to %s"),
|
|
libx52_clock_id_to_str(id), param);
|
|
x52d_dev_set_clock_timezone(id, get_tz_offset(param));
|
|
}
|
|
}
|
|
|
|
void x52d_cfg_set_Clock_Secondary(char* param)
|
|
{
|
|
set_clock_offset(LIBX52_CLOCK_2, param);
|
|
}
|
|
|
|
void x52d_cfg_set_Clock_Tertiary(char* param)
|
|
{
|
|
set_clock_offset(LIBX52_CLOCK_3, param);
|
|
}
|
|
|
|
static void set_clock_format(libx52_clock_id id, libx52_clock_format fmt)
|
|
{
|
|
if (clock_enabled) {
|
|
PINELOG_DEBUG(_("Setting %s clock format to %s"),
|
|
libx52_clock_id_to_str(id), libx52_clock_format_to_str(fmt));
|
|
x52d_dev_set_clock_format(id, fmt);
|
|
}
|
|
}
|
|
|
|
void x52d_cfg_set_Clock_FormatPrimary(libx52_clock_format fmt)
|
|
{
|
|
set_clock_format(LIBX52_CLOCK_1, fmt);
|
|
}
|
|
|
|
void x52d_cfg_set_Clock_FormatSecondary(libx52_clock_format fmt)
|
|
{
|
|
set_clock_format(LIBX52_CLOCK_2, fmt);
|
|
}
|
|
|
|
void x52d_cfg_set_Clock_FormatTertiary(libx52_clock_format fmt)
|
|
{
|
|
set_clock_format(LIBX52_CLOCK_3, fmt);
|
|
}
|
|
|
|
void x52d_cfg_set_Clock_DateFormat(libx52_date_format fmt)
|
|
{
|
|
if (clock_enabled) {
|
|
PINELOG_DEBUG(_("Setting date format to %s"), libx52_date_format_to_str(fmt));
|
|
x52d_dev_set_date_format(fmt);
|
|
}
|
|
}
|
|
|
|
static pthread_t clock_thr;
|
|
|
|
static void * x52_clock_thr(void *param)
|
|
{
|
|
int rc;
|
|
|
|
PINELOG_INFO(_("Starting X52 clock manager thread"));
|
|
for (;;) {
|
|
time_t cur_time;
|
|
|
|
sleep(1);
|
|
if (!clock_enabled) {
|
|
/* Clock thread is disabled, check again next time */
|
|
continue;
|
|
}
|
|
|
|
if (time(&cur_time) < 0) {
|
|
PINELOG_WARN(_("Error %d retrieving current time: %s"),
|
|
errno, strerror(errno));
|
|
continue;
|
|
}
|
|
rc = x52d_dev_set_clock(cur_time, clock_primary_is_local);
|
|
if (rc == LIBX52_SUCCESS) {
|
|
// Device manager will update the clock, this is only for debugging
|
|
PINELOG_TRACE("Setting X52 clock to %ld", cur_time);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void x52d_clock_init(void)
|
|
{
|
|
int rc;
|
|
|
|
PINELOG_TRACE("Initializing clock manager");
|
|
rc = pthread_create(&clock_thr, NULL, x52_clock_thr, NULL);
|
|
if (rc != 0) {
|
|
PINELOG_FATAL(_("Error %d initializing clock thread: %s"),
|
|
rc, strerror(rc));
|
|
}
|
|
}
|
|
|
|
void x52d_clock_exit(void)
|
|
{
|
|
PINELOG_INFO(_("Shutting down X52 clock manager thread"));
|
|
pthread_cancel(clock_thr);
|
|
}
|