osmo-bts/src/osmo-bts-oc2g/misc/oc2gbts_clock.c

264 lines
5.6 KiB
C

/* Copyright (C) 2015 by Yves Godin <support@nuranwireless.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include "oc2gbts_clock.h"
#define CLKERR_ERR_SYSFS "/var/oc2g/clkerr/clkerr1_average"
#define CLKERR_ACC_SYSFS "/var/oc2g/clkerr/clkerr1_average_accuracy"
#define CLKERR_INT_SYSFS "/var/oc2g/clkerr/clkerr1_average_interval"
#define CLKERR_FLT_SYSFS "/var/oc2g/clkerr/clkerr1_fault"
#define CLKERR_RFS_SYSFS "/var/oc2g/clkerr/refresh"
#define CLKERR_RST_SYSFS "/var/oc2g/clkerr/reset"
#define OCXODAC_VAL_SYSFS "/var/oc2g/ocxo/voltage"
#define OCXODAC_ROM_SYSFS "/var/oc2g/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 oc2gbts_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) {
oc2gbts_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) {
oc2gbts_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) {
oc2gbts_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) {
oc2gbts_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) {
oc2gbts_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) {
oc2gbts_clock_err_close();
return clkerr_fd_reset;
}
}
return 0;
}
void oc2gbts_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 oc2gbts_clock_err_reset(void)
{
return sysfs_write_val(clkerr_fd_reset, 1);
}
int oc2gbts_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 oc2gbts_clock_dac_open(void)
{
if (ocxodac_fd_value < 0) {
ocxodac_fd_value = open(OCXODAC_VAL_SYSFS, O_RDWR);
if (ocxodac_fd_value < 0) {
oc2gbts_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) {
oc2gbts_clock_dac_close();
return ocxodac_fd_save;
}
}
return 0;
}
void oc2gbts_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 oc2gbts_clock_dac_get(int *dac_value)
{
return sysfs_read_val(ocxodac_fd_value, dac_value);
}
int oc2gbts_clock_dac_set(int dac_value)
{
return sysfs_write_val(ocxodac_fd_value, dac_value);
}
int oc2gbts_clock_dac_save(void)
{
return sysfs_write_val(ocxodac_fd_save, 1);
}