/* Copyright (C) 2015 by Yves Godin * * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ #include #include #include #include #include #include #include #include "lc15bts_clock.h" #define CLKERR_ERR_SYSFS "/var/lc15/clkerr/clkerr1_average" #define CLKERR_ACC_SYSFS "/var/lc15/clkerr/clkerr1_average_accuracy" #define CLKERR_INT_SYSFS "/var/lc15/clkerr/clkerr1_average_interval" #define CLKERR_FLT_SYSFS "/var/lc15/clkerr/clkerr1_fault" #define CLKERR_RFS_SYSFS "/var/lc15/clkerr/refresh" #define CLKERR_RST_SYSFS "/var/lc15/clkerr/reset" #define OCXODAC_VAL_SYSFS "/var/lc15/ocxo/voltage" #define OCXODAC_ROM_SYSFS "/var/lc15/ocxo/eeprom" /* clock error */ static int clkerr_fd_err = -1; static int clkerr_fd_accuracy = -1; static int clkerr_fd_interval = -1; static int clkerr_fd_fault = -1; static int clkerr_fd_refresh = -1; static int clkerr_fd_reset = -1; /* ocxo dac */ static int ocxodac_fd_value = -1; static int ocxodac_fd_save = -1; static int sysfs_read_val(int fd, int *val) { int rc; char szVal[32] = {0}; lseek( fd, 0, SEEK_SET ); rc = read(fd, szVal, sizeof(szVal) - 1); if (rc < 0) { return -errno; } rc = sscanf(szVal, "%d", val); if (rc != 1) { return -1; } return 0; } static int sysfs_write_val(int fd, int val) { int n, rc; char szVal[32] = {0}; n = sprintf(szVal, "%d", val); lseek(fd, 0, SEEK_SET); rc = write(fd, szVal, n+1); if (rc < 0) { return -errno; } return 0; } static int sysfs_write_str(int fd, const char *str) { int rc; lseek( fd, 0, SEEK_SET ); rc = write(fd, str, strlen(str)+1); if (rc < 0) { return -errno; } return 0; } int lc15bts_clock_err_open(void) { int rc; int fault; if (clkerr_fd_err < 0) { clkerr_fd_err = open(CLKERR_ERR_SYSFS, O_RDONLY); if (clkerr_fd_err < 0) { lc15bts_clock_err_close(); return clkerr_fd_err; } } if (clkerr_fd_accuracy < 0) { clkerr_fd_accuracy = open(CLKERR_ACC_SYSFS, O_RDONLY); if (clkerr_fd_accuracy < 0) { lc15bts_clock_err_close(); return clkerr_fd_accuracy; } } if (clkerr_fd_interval < 0) { clkerr_fd_interval = open(CLKERR_INT_SYSFS, O_RDONLY); if (clkerr_fd_interval < 0) { lc15bts_clock_err_close(); return clkerr_fd_interval; } } if (clkerr_fd_fault < 0) { clkerr_fd_fault = open(CLKERR_FLT_SYSFS, O_RDONLY); if (clkerr_fd_fault < 0) { lc15bts_clock_err_close(); return clkerr_fd_fault; } } if (clkerr_fd_refresh < 0) { clkerr_fd_refresh = open(CLKERR_RFS_SYSFS, O_WRONLY); if (clkerr_fd_refresh < 0) { lc15bts_clock_err_close(); return clkerr_fd_refresh; } } if (clkerr_fd_reset < 0) { clkerr_fd_reset = open(CLKERR_RST_SYSFS, O_WRONLY); if (clkerr_fd_reset < 0) { lc15bts_clock_err_close(); return clkerr_fd_reset; } } rc = sysfs_write_str(clkerr_fd_refresh, "once"); if (rc < 0) { lc15bts_clock_err_close(); return rc; } rc = sysfs_read_val(clkerr_fd_fault, &fault); if (rc < 0) { lc15bts_clock_err_close(); return rc; } if (fault) { rc = sysfs_write_val(clkerr_fd_reset, 1); if (rc < 0) { lc15bts_clock_err_close(); return rc; } } return 0; } void lc15bts_clock_err_close(void) { if (clkerr_fd_err >= 0) { close(clkerr_fd_err); clkerr_fd_err = -1; } if (clkerr_fd_accuracy >= 0) { close(clkerr_fd_accuracy); clkerr_fd_accuracy = -1; } if (clkerr_fd_interval >= 0) { close(clkerr_fd_interval); clkerr_fd_interval = -1; } if (clkerr_fd_fault >= 0) { close(clkerr_fd_fault); clkerr_fd_fault = -1; } if (clkerr_fd_refresh >= 0) { close(clkerr_fd_refresh); clkerr_fd_refresh = -1; } if (clkerr_fd_reset >= 0) { close(clkerr_fd_reset); clkerr_fd_reset = -1; } } int lc15bts_clock_err_reset(void) { return sysfs_write_val(clkerr_fd_reset, 1); } int lc15bts_clock_err_get(int *fault, int *error_ppt, int *accuracy_ppq, int *interval_sec) { int rc; rc = sysfs_write_str(clkerr_fd_refresh, "once"); if (rc < 0) { return -1; } rc = sysfs_read_val(clkerr_fd_fault, fault); rc |= sysfs_read_val(clkerr_fd_err, error_ppt); rc |= sysfs_read_val(clkerr_fd_accuracy, accuracy_ppq); rc |= sysfs_read_val(clkerr_fd_interval, interval_sec); if (rc) { return -1; } return 0; } int lc15bts_clock_dac_open(void) { if (ocxodac_fd_value < 0) { ocxodac_fd_value = open(OCXODAC_VAL_SYSFS, O_RDWR); if (ocxodac_fd_value < 0) { lc15bts_clock_dac_close(); return ocxodac_fd_value; } } if (ocxodac_fd_save < 0) { ocxodac_fd_save = open(OCXODAC_ROM_SYSFS, O_WRONLY); if (ocxodac_fd_save < 0) { lc15bts_clock_dac_close(); return ocxodac_fd_save; } } return 0; } void lc15bts_clock_dac_close(void) { if (ocxodac_fd_value >= 0) { close(ocxodac_fd_value); ocxodac_fd_value = -1; } if (ocxodac_fd_save >= 0) { close(ocxodac_fd_save); ocxodac_fd_save = -1; } } int lc15bts_clock_dac_get(int *dac_value) { return sysfs_read_val(ocxodac_fd_value, dac_value); } int lc15bts_clock_dac_set(int dac_value) { return sysfs_write_val(ocxodac_fd_value, dac_value); } int lc15bts_clock_dac_save(void) { return sysfs_write_val(ocxodac_fd_save, 1); }