You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

409 lines
8.8 KiB

/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2016
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "io.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <linux/input.h>
#include <termios.h>
#include <string.h>
#include <pthread.h>
#include "freedv_eth_config.h"
static RIG *rig;
static int dcd_level = 0;
static int dcd_threshold = 1;
static ptt_type_t ptt_type = RIG_PTT_NONE;
static dcd_type_t dcd_type = RIG_DCD_NONE;
static long token_aux1 = -1;
static long token_aux2 = -1;
static long token_aux3 = -1;
static volatile ptt_t rig_thread_ptt = RIG_PTT_OFF;
static volatile dcd_t rig_thread_dcd = RIG_DCD_OFF;
static volatile bool rig_thread_aux1 = false;
static volatile bool rig_thread_aux2 = false;
static volatile bool rig_thread_aux3 = false;
static bool toggle;
static bool input_state = false;
static int fd_input = -1;
int io_init_input(char *device, bool inputtoggle)
{
fd_input = open(device, O_RDONLY);
printf("open %s: %d\n", device, fd_input);
if (fd_input >= 0)
ioctl(fd_input, EVIOCGRAB, (void*)1);
toggle = inputtoggle;
return fd_input;
}
static int input_handle(int fd)
{
struct input_event ev;
ssize_t r;
r = read(fd, &ev, sizeof(ev));
if (r == sizeof(ev)) {
if (ev.type == EV_KEY) {
if (!toggle) {
input_state = ev.value;
} else {
if (ev.value) {
input_state = !input_state;
}
}
printf("DCD input: %d\n", input_state);
}
} else {
printf("input r: %zd\n", r);
}
return 0;
}
static int fd_tty = -1;
int io_init_tty(void)
{
fd_tty = 0;
struct termios attribs;
if(tcgetattr(STDIN_FILENO, &attribs) < 0) {
perror("stdin");
return -1;
}
attribs.c_lflag &= ~(ICANON | ECHO | ECHONL);
if(tcsetattr(STDIN_FILENO, TCSANOW, &attribs) < 0) {
perror("stdin");
return -1;
}
return 0;
}
static int tty_rx = false;
bool io_state_rx_get(void)
{
return input_state || tty_rx;
}
int io_handle(struct pollfd *fds, int count, void (*cb_control)(char *))
{
int nr = 0;
if (fd_input >= 0 && nr < count) {
if (fds[nr].revents == POLLIN) {
printf("io input\n");
input_handle(fd_input);
}
nr++;
}
if (fd_tty >= 0 && nr < count) {
if (fds[nr].revents == POLLIN) {
ssize_t r;
char buffer[2];
r = read(0, buffer, 1);
if (r == 1) {
if (buffer[0] == '\n') {
tty_rx = ! tty_rx;
printf("tty DCD input: %d\n", tty_rx);
} else {
buffer[1] = 0;
cb_control(buffer);
}
}
}
nr++;
}
return nr;
}
bool io_hl_dcd_get(void)
{
dcd_t dcd;
if (dcd_type == RIG_DCD_NONE)
return false;
dcd = rig_thread_dcd;
if (dcd == RIG_DCD_ON)
dcd_level++;
else
dcd_level = 0;
return dcd_level >= dcd_threshold;
}
bool io_hl_aux1_get(void)
{
return rig_thread_aux1;
}
bool io_hl_aux2_get(void)
{
return rig_thread_aux2;
}
bool io_hl_aux3_get(void)
{
return rig_thread_aux3;
}
void io_hl_ptt_set(enum io_hl_ptt state)
{
ptt_t pstate;
switch (state) {
case IO_HL_PTT_AUDIO:
pstate = RIG_PTT_ON_MIC;
break;
case IO_HL_PTT_OTHER:
pstate = RIG_PTT_ON_DATA;
break;
case IO_HL_PTT_OFF:
default:
pstate = RIG_PTT_OFF;
break;
}
rig_thread_ptt = pstate;
__sync_synchronize();
if (pstate == RIG_PTT_OFF && dcd_level <= 0) {
/* make dcd insensitive for a little while */
dcd_level = -dcd_threshold;
}
}
#define CYCLE_NS (20*1000*1000)
void *io_hl_rig_thread(void *arg)
{
dcd_t cur_dcd = rig_thread_dcd;
ptt_t cur_ptt = rig_thread_ptt;
value_t cur_value;
struct timespec t_cycle_start;
struct timespec t_cycle_end;
struct timespec t_wait;
while (1) {
clock_gettime(CLOCK_MONOTONIC, &t_cycle_start);
__sync_synchronize();
// printf("%d %d\n", rig_thread_ptt, cur_ptt);
if (rig_thread_ptt != cur_ptt) {
cur_ptt = rig_thread_ptt;
rig_set_ptt(rig, RIG_VFO_CURR, cur_ptt);
}
rig_get_dcd(rig, RIG_VFO_CURR, &cur_dcd);
if (token_aux1 > 0) {
if (rig_get_ext_parm(rig, token_aux1, &cur_value) == RIG_OK)
rig_thread_aux1 = cur_value.i;
}
if (token_aux2 > 0) {
if (rig_get_ext_parm(rig, token_aux2, &cur_value) == RIG_OK)
rig_thread_aux2 = cur_value.i;
}
if (token_aux3 > 0) {
if (rig_get_ext_parm(rig, token_aux3, &cur_value) == RIG_OK)
rig_thread_aux3 = cur_value.i;
}
rig_thread_dcd = cur_dcd;
__sync_synchronize();
clock_gettime(CLOCK_MONOTONIC, &t_cycle_end);
t_wait.tv_sec = 0;
t_wait.tv_nsec = CYCLE_NS;
t_wait.tv_nsec -= t_cycle_end.tv_nsec - t_cycle_start.tv_nsec;
t_wait.tv_nsec -= (t_cycle_end.tv_sec - t_cycle_start.tv_sec) * 1000000000;
if (t_wait.tv_nsec > CYCLE_NS) {
/* Clock not monotonic? */
t_wait.tv_nsec = CYCLE_NS;
}
if (t_wait.tv_nsec > 0) {
nanosleep(&t_wait, NULL);
}
}
}
int io_hl_init(rig_model_t rig_model, int dcd_th, ptt_type_t ptt, char *ptt_file, dcd_type_t dcd, char *dcd_file, char *rig_file)
{
int retcode;
ptt_type = ptt;
dcd_type = dcd;
dcd_threshold = dcd_th;
rig_set_debug(RIG_DEBUG_WARN);
rig = rig_init(rig_model);
if (!rig) {
printf("Could not init rig\n");
return -1;
}
rig->state.pttport.type.ptt = ptt_type;
rig->state.dcdport.type.dcd = dcd_type;
if (ptt_file)
strncpy(rig->state.pttport.pathname, ptt_file, FILPATHLEN - 1);
if (dcd_file)
strncpy(rig->state.dcdport.pathname, dcd_file, FILPATHLEN - 1);
if (rig_file)
strncpy(rig->state.rigport.pathname, rig_file, FILPATHLEN - 1);
char *conf_set = NULL;
while ((conf_set = freedv_eth_config_value("rig_conf_set", conf_set, NULL))) {
char conf[81];
strncpy(conf, conf_set, 80);
conf_set[80] = 0;
char *conf_tok;
char *conf_val;
char *svp;
conf_tok = strtok_r(conf, " \t=:", &svp);
conf_val = strtok_r(NULL, " \t=:", &svp);
if (conf_tok && conf_val) {
printf("Conf param: '%s' will be set to: '%s'\n", conf_tok, conf_val);
long token = rig_token_lookup(rig, conf_tok);
if (token > 0) {
if (rig_set_conf(rig, token, conf_val)) {
printf("Conf param with token %ld could not be set\n", token);
}
} else {
printf("Could not get token for '%s'\n", conf_tok);
}
}
}
retcode = rig_open(rig);
if (retcode != RIG_OK) {
fprintf(stderr,"rig_open: error = %s \n", rigerror(retcode));
return -2;
}
char *rig_ctcss_sql = freedv_eth_config_value("rig_ctcss_sql", NULL, NULL);
if (rig_ctcss_sql) {
printf("rig ctcss squelch: %s\n", rig_ctcss_sql);
tone_t tone = atoi(rig_ctcss_sql);
rig_set_ctcss_sql(rig, RIG_VFO_CURR, tone);
}
char *rig_ctcss_tone = freedv_eth_config_value("rig_ctcss_tone", NULL, NULL);
if (rig_ctcss_tone) {
printf("rig ctcss tone: %s\n", rig_ctcss_tone);
tone_t tone = atoi(rig_ctcss_tone);
rig_set_ctcss_tone(rig, RIG_VFO_CURR, tone);
}
char *rig_freq_rx = freedv_eth_config_value("rig_freq_rx", NULL, NULL);
if (rig_freq_rx) {
printf("rig frequency for rx: %s\n", rig_freq_rx);
freq_t freq = atof(rig_freq_rx);
int r = rig_set_freq(rig, RIG_VFO_RX, freq);
if (r != RIG_OK) {
printf("error from rig: %d\n", r);
}
}
char *rig_freq_tx = freedv_eth_config_value("rig_freq_tx", NULL, NULL);
if (rig_freq_tx) {
printf("rig frequency for tx: %s\n", rig_freq_tx);
freq_t freq = atof(rig_freq_tx);
int r = rig_set_split_vfo(rig, RIG_VFO_CURR, RIG_SPLIT_ON, RIG_VFO_TX);
if (r != RIG_OK) {
printf("error from rig: %d\n", r);
}
r = rig_set_freq(rig, RIG_VFO_TX, freq);
if (r != RIG_OK) {
printf("error from rig: %d\n", r);
}
}
/* Init to sane status */
rig_set_ptt(rig, RIG_VFO_CURR, RIG_PTT_OFF);
rig_get_dcd(rig, RIG_VFO_CURR, (dcd_t*)&rig_thread_dcd);
token_aux1 = rig_ext_token_lookup(rig, "AUX1");
token_aux2 = rig_ext_token_lookup(rig, "AUX2");
token_aux3 = rig_ext_token_lookup(rig, "AUX3");
printf("rig AUX tokens: %ld %ld %ld\n", token_aux1, token_aux2, token_aux3);
pthread_t rig_thread;
pthread_create(&rig_thread, NULL, io_hl_rig_thread, NULL);
return 0;
}
int io_fs_nr(void)
{
int nr = 0;
if (fd_input >= 0)
nr++;
if (fd_tty >= 0)
nr++;
return nr;
}
int io_poll_fill(struct pollfd *fds, int count)
{
int nr = 0;
if (fd_input >= 0 && nr < count) {
fds[nr].fd = fd_input;
fds[nr].events = POLLIN;
nr++;
}
if (fd_tty >= 0 && nr < count) {
fds[nr].fd = fd_tty;
fds[nr].events = POLLIN;
nr++;
}
return 0;
}
static bool io_dmlassoc = false;
bool io_dmlassoc_get(void)
{
return io_dmlassoc;
}
void io_dmlassoc_set(bool val)
{
io_dmlassoc = val;
}