diff --git a/racal/Makefile.am b/racal/Makefile.am new file mode 100644 index 000000000..e54dc456e --- /dev/null +++ b/racal/Makefile.am @@ -0,0 +1,8 @@ +RACALSRCLIST = ra6790.c + +lib_LTLIBRARIES = hamlib-racal.la +hamlib_racal_la_SOURCES = $(RACALSRCLIST) racal.c +hamlib_racal_la_LDFLAGS = -no-undefined -module -avoid-version +hamlib_racal_la_LIBADD = $(top_builddir)/src/libhamlib.la + +noinst_HEADERS = racal.h diff --git a/racal/ra6790.c b/racal/ra6790.c new file mode 100644 index 000000000..edc32109d --- /dev/null +++ b/racal/ra6790.c @@ -0,0 +1,143 @@ +/* + * Hamlib Racal backend - RA6790 description + * Copyright (c) 2004 by Stephane Fillod + * + * $Id: ra6790.c,v 1.1 2004-09-12 21:28:26 fillods Exp $ + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include "idx_builtin.h" +#include "racal.h" + + +/* FIXME: ISB */ +#define RA6790_MODES (RIG_MODE_AM|RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_AMS|RIG_MODE_FM) + +#define RA6790_FUNC (RIG_FUNC_NONE) + +#define RA6790_LEVEL_ALL (RIG_LEVEL_RF|RIG_LEVEL_AGC|RIG_LEVEL_IF) + +#define RA6790_PARM_ALL (RIG_PARM_NONE) + +#define RA6790_VFO (RIG_VFO_A) + +/* + * ra6790 rig capabilities. + * + * Required A6A1 serial asynchronous interface + * + */ +const struct rig_caps ra6790_caps = { +.rig_model = RIG_MODEL_RA6790, +.model_name = "RA6790/GM", +.mfg_name = "Racal", +.version = "0.1", +.copyright = "LGPL", +.status = RIG_STATUS_UNTESTED, +.rig_type = RIG_TYPE_RECEIVER, +.ptt_type = RIG_PTT_NONE, +.dcd_type = RIG_DCD_NONE, +.port_type = RIG_PORT_SERIAL, +.serial_rate_min = 300, +.serial_rate_max = 9600, +.serial_data_bits = 7, +.serial_stop_bits = 2, +.serial_parity = RIG_PARITY_EVEN, +.serial_handshake = RIG_HANDSHAKE_NONE, +.write_delay = 0, +.post_write_delay = 10, +.timeout = 2000, +.retry = 3, + +.has_get_func = RA6790_FUNC, +.has_set_func = RA6790_FUNC, +.has_get_level = RA6790_LEVEL_ALL, +.has_set_level = RIG_LEVEL_SET(RA6790_LEVEL_ALL), +.has_get_parm = RA6790_PARM_ALL, +.has_set_parm = RIG_PARM_SET(RA6790_PARM_ALL), +.vfo_ops = RIG_OP_NONE, +.preamp = { RIG_DBLST_END }, +.attenuator = { RIG_DBLST_END }, +.max_rit = Hz(0), +.max_xit = Hz(0), +.max_ifshift = kHz(8), +.targetable_vfo = 0, +.transceive = RIG_TRN_OFF, +.bank_qty = 0, +.chan_desc_sz = 0, + +.chan_list = { RIG_CHAN_END, }, + +.rx_range_list1 = { + {kHz(500),MHz(30)-1,RA6790_MODES,-1,-1,RA6790_VFO}, + RIG_FRNG_END, + }, +.tx_range_list1 = { RIG_FRNG_END, }, +.rx_range_list2 = { + {kHz(500),MHz(30)-1,RA6790_MODES,-1,-1,RA6790_VFO}, + RIG_FRNG_END, + }, +.tx_range_list2 = { RIG_FRNG_END, }, +.tuning_steps = { + {RA6790_MODES,1}, + RIG_TS_END, + }, + /* mode/filter list, remember: order matters! */ +.filters = { + /* at -3dB */ + {RIG_MODE_SSB, kHz(2.55)}, /* BW2 */ + {RA6790_MODES, Hz(300)}, /* BW1 */ + {RA6790_MODES, kHz(1)}, /* BW2 */ + {RA6790_MODES, kHz(3.2)}, /* BW3 */ + {RA6790_MODES, kHz(6)}, /* BW4 */ + {RA6790_MODES, kHz(20)}, /* BW5 */ + {RA6790_MODES, 0}, /* accept any BW */ + RIG_FLT_END, + }, + +.cfgparams = racal_cfg_params, + +.rig_init = racal_init, +.rig_cleanup = racal_cleanup, +.rig_open = racal_open, +.rig_close = racal_close, +.set_conf = racal_set_conf, +.get_conf = racal_get_conf, + +.set_freq = racal_set_freq, +.get_freq = racal_get_freq, +.set_mode = racal_set_mode, +.get_mode = racal_get_mode, +.set_level = racal_set_level, +.get_level = racal_get_level, + +.reset = racal_reset, +.get_info = racal_get_info, + +}; + +/* + * Function definitions below + */ + diff --git a/racal/racal.c b/racal/racal.c new file mode 100644 index 000000000..fa1550a2e --- /dev/null +++ b/racal/racal.c @@ -0,0 +1,474 @@ +/* + * Hamlib Racal backend - main file + * Copyright (c) 2004 by Stephane Fillod + * + * $Id: racal.c,v 1.1 2004-09-12 21:28:26 fillods Exp $ + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include /* String function definitions */ +#include /* UNIX standard function definitions */ +#include + +#include "hamlib/rig.h" +#include "serial.h" +#include "misc.h" +#include "cal.h" +#include "register.h" +#include "token.h" + +#include "racal.h" + + +const struct confparams racal_cfg_params[] = { + { TOK_RIGID, "receiver_id", "receiver ID", "receiver ID", + "0", RIG_CONF_NUMERIC, { .n = { 0, 99, 1 } } + }, + { RIG_CONF_END, NULL, } +}; + + + +#define BUFSZ 32 + +#define SOM "$" +#define EOM "\x0d" /* CR */ + +/* + * modes + */ +#define MD_AM 1 +#define MD_FM 2 +#define MD_MCW 3 /* variable BFO */ +#define MD_CW 4 /* BFO center */ +#define MD_ISB 5 /* option */ +#define MD_LSB 6 +#define MD_USB 7 + + +/* + * racal_transaction + * We assume that rig!=NULL, rig->state!= NULL + * + * TODO: Status Response handling with G/T commands + */ +static int racal_transaction(RIG *rig, const char *cmd, char *data, int *data_len) +{ + struct racal_priv_data *priv = (struct racal_priv_data*)rig->state.priv; + struct rig_state *rs = &rig->state; + char cmdbuf[BUFSZ+1]; + int cmd_len; + int retval; + + cmd_len = sprintf(cmdbuf, SOM "%d%s" EOM, priv->receiver_id, cmd); + + serial_flush(&rs->rigport); + + retval = write_block(&rs->rigport, cmdbuf, cmd_len); + if (retval != RIG_OK) + return retval; + + + /* no data expected */ + if (!data || !data_len) { + return retval; + } + + retval = read_string(&rs->rigport, data, BUFSZ, EOM, strlen(EOM)); + if (retval <= 0) + return retval; + + /* strip CR from string + */ + if (data[retval-1] == '\x0d') { + data[--retval] = '\0'; /* chomp */ + } + *data_len = retval; + return RIG_OK; +} + + +int racal_init(RIG *rig) +{ + struct racal_priv_data *priv; + + if (!rig || !rig->caps) + return -RIG_EINVAL; + + priv = (struct racal_priv_data*)malloc(sizeof(struct racal_priv_data)); + if (!priv) { + /* whoops! memory shortage! */ + return -RIG_ENOMEM; + } + + rig->state.priv = (void*)priv; + + priv->receiver_id = 0; + priv->bfo = 0; + priv->threshold = 0; + + return RIG_OK; +} + +/* + */ +int racal_cleanup(RIG *rig) +{ + if (!rig) + return -RIG_EINVAL; + + if (rig->state.priv) + free(rig->state.priv); + rig->state.priv = NULL; + + return RIG_OK; +} + + + +/* + * Assumes rig!=NULL, rig->state.priv!=NULL + */ +int racal_set_conf(RIG *rig, token_t token, const char *val) +{ + struct racal_priv_data *priv = (struct racal_priv_data*)rig->state.priv; + + switch (token) { + case TOK_RIGID: + priv->receiver_id = atoi(val); + break; + default: + return -RIG_EINVAL; + } + return RIG_OK; +} + +/* + * assumes rig!=NULL, + * Assumes rig!=NULL, rig->state.priv!=NULL + * and val points to a buffer big enough to hold the conf value. + */ +int racal_get_conf(RIG *rig, token_t token, char *val) +{ + struct racal_priv_data *priv = (struct racal_priv_data*)rig->state.priv; + + switch(token) { + case TOK_RIGID: + sprintf(val, "%d", priv->receiver_id); + break; + default: + return -RIG_EINVAL; + } + return RIG_OK; +} + +/* + * racal_open + * Assumes rig!=NULL + */ +int racal_open(RIG *rig) +{ + /* Set Receiver to remote control + * + * TODO: Perform the BITE routine (1mn!) at each open? + * TODO: "S5" request values of IF bandwidth filters found? + */ + return racal_transaction (rig, "S2", NULL, NULL); +} + + +/* + * racal_close + * Assumes rig!=NULL + */ +int racal_close(RIG *rig) +{ + /* Set Receiver to local control */ + return racal_transaction (rig, "S1", NULL, NULL); +} + + +/* + * racal_set_freq + * Assumes rig!=NULL + */ +int racal_set_freq(RIG *rig, vfo_t vfo, freq_t freq) +{ + char freqbuf[BUFSZ]; + int freq_len; + + freq_len = sprintf(freqbuf, "F%0g", (double)(freq/MHz(1))); + + return racal_transaction (rig, freqbuf, NULL, NULL); +} + +int racal_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) +{ + char freqbuf[BUFSZ]; + int retval, len; + double f; + + retval = racal_transaction (rig, "TF", freqbuf, &len); + if (retval < RIG_OK) + return retval; + + if (len < 2 || freqbuf[0] != 'F') + return -RIG_EPROTO; + + sscanf(freqbuf+1, "%lf", &f); + *freq = (freq_t)f * MHz(1); + + return RIG_OK; +} + +/* + * racal_set_mode + * Assumes rig!=NULL + */ +int racal_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) +{ + struct racal_priv_data *priv = (struct racal_priv_data*)rig->state.priv; + int ra_mode; + char buf[BUFSZ]; + + switch (mode) { + case RIG_MODE_CW: ra_mode = (priv->bfo!=0) ? MD_MCW:MD_CW; break; + case RIG_MODE_USB: ra_mode = MD_USB; break; + case RIG_MODE_LSB: ra_mode = MD_LSB; break; + case RIG_MODE_AM: ra_mode = MD_AM; break; + case RIG_MODE_AMS: ra_mode = MD_ISB; break; /* TBC */ + case RIG_MODE_FM: ra_mode = MD_FM; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported mode %d\n", + __FUNCTION__, mode); + return -RIG_EINVAL; + } + + if (width == RIG_PASSBAND_NORMAL) + width = rig_passband_normal(rig, mode); + + sprintf(buf, "D%dI%.f", ra_mode, (double)(width/kHz(1))); + + return racal_transaction (rig, buf, NULL, NULL); +} + +int racal_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) +{ + char resbuf[BUFSZ], *p; + int retval, len; + double f; + + retval = racal_transaction (rig, "TDI", resbuf, &len); + if (retval < RIG_OK) + return retval; + + p = strchr(resbuf, 'I'); + if (len < 3 || resbuf[0] != 'D' || !p) + return -RIG_EPROTO; + + switch (resbuf[1]-'0') { + case MD_MCW: + case MD_CW: *mode = RIG_MODE_CW; break; + case MD_LSB: *mode = RIG_MODE_LSB; break; + case MD_USB: *mode = RIG_MODE_USB; break; + case MD_ISB: *mode = RIG_MODE_AMS; break; /* TBC */ + case MD_FM: *mode = RIG_MODE_FM; break; + case MD_AM: *mode = RIG_MODE_AM; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported mode %d\n", + __FUNCTION__, mode); + return -RIG_EPROTO; + } + + sscanf(p+1, "%lf", &f); + *width = (pbwidth_t)(f * kHz(1)); + + return RIG_OK; +} + + + +/* + * racal_set_level + * Assumes rig!=NULL + */ +int racal_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) +{ + struct racal_priv_data *priv = (struct racal_priv_data*)rig->state.priv; + char cmdbuf[BUFSZ]; + int agc; + + switch (level) { + case RIG_LEVEL_RF: + /* Manually set threshold */ + sprintf(cmdbuf, "A%d", (int)(val.f*120)); + priv->threshold = val.f; + break; + + case RIG_LEVEL_IF: + sprintf(cmdbuf, "B%+0g", ((double)val.i)/kHz(1)); + priv->bfo = val.i; + break; + + case RIG_LEVEL_AGC: + switch (val.i) { + case RIG_AGC_FAST: agc = 1; break; + case RIG_AGC_MEDIUM: agc = 2; break; + case RIG_AGC_SLOW: agc = 3; break; + case RIG_AGC_USER: agc = 4; break; + default: return -RIG_EINVAL; + } + if (priv->threshold != 0 && agc != 4) + agc += 4; /* with manually set threshold */ + sprintf(cmdbuf, "M%d", agc); + break; + + default: + rig_debug(RIG_DEBUG_ERR,"%s: unsupported %d\n", + __FUNCTION__, level); + return -RIG_EINVAL; + } + + + return racal_transaction (rig, cmdbuf, NULL, NULL); +} + + +/* + * racal_get_level + * Assumes rig!=NULL + */ +int racal_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) +{ + struct racal_priv_data *priv = (struct racal_priv_data*)rig->state.priv; + char resbuf[BUFSZ]; + int retval, len, att; + double f; + + switch (level) { + case RIG_LEVEL_RF: + /* Manually set threshold */ + retval = racal_transaction (rig, "TA", resbuf, &len); + if (retval < RIG_OK) + return retval; + + if (len < 2 || resbuf[0] != 'A') + return -RIG_EPROTO; + + sscanf(resbuf+1, "%d", &att); + + val->f = priv->threshold = (float)att/120; + break; + + case RIG_LEVEL_IF: + retval = racal_transaction (rig, "TB", resbuf, &len); + if (retval < RIG_OK) + return retval; + + if (len < 2 || resbuf[0] != 'B') + return -RIG_EPROTO; + + sscanf(resbuf+1, "%lf", &f); + val->i = priv->bfo = (shortfreq_t)(f * kHz(1)); + break; + + case RIG_LEVEL_AGC: + retval = racal_transaction (rig, "TM", resbuf, &len); + if (retval < RIG_OK) + return retval; + + if (len < 2 || resbuf[0] != 'M') + return -RIG_EPROTO; + + switch (resbuf[1]-'0') { + case 1: + case 5: val->i = RIG_AGC_FAST; break; + case 2: + case 6: val->i = RIG_AGC_MEDIUM; break; + case 3: + case 7: val->i = RIG_AGC_SLOW; break; + case 4: val->i = RIG_AGC_USER; break; + default: return -RIG_EINVAL; + } + break; + default: + rig_debug(RIG_DEBUG_ERR,"%s: Unsupported %d\n", __FUNCTION__, level); + return -RIG_EINVAL; + } + + return RIG_OK; +} + +/* + * Assumes rig!=NULL, rig->state.priv!=NULL + */ +int racal_reset(RIG *rig, reset_t reset) +{ + /* Initiate BITE routine, takes 1 minute! */ + return racal_transaction (rig, "S3", NULL, NULL); +} + +const char* racal_get_info(RIG *rig) +{ + static char infobuf[64]; + char bitebuf[BUFSZ]; + char filterbuf[BUFSZ]; + int res_len, retval; + + /* get BITE results */ + retval = racal_transaction (rig, "S6", bitebuf, &res_len); + if (retval < 0) + return "IO error"; + if (bitebuf[1] == 'O' && bitebuf[2] == 'K') { + bitebuf[3] = '\0'; + } else { + char *p = strstr(bitebuf, "END"); + if (p) + *p = '\0'; + } + + /* get filters */ + retval = racal_transaction (rig, "S5", filterbuf, &res_len); + if (retval < 0) + strcpy(filterbuf,"IO error"); + + sprintf(infobuf, "BITE errors: %s, Filters: %s\n", + bitebuf+1, filterbuf); + + return infobuf; +} + + + +/* + * initrigs_racal is called by rig_backend_load + */ +DECLARE_INITRIG_BACKEND(racal) +{ + rig_debug(RIG_DEBUG_VERBOSE, "racal: _init called\n"); + + rig_register(&ra6790_caps); + + return RIG_OK; +} + diff --git a/racal/racal.h b/racal/racal.h new file mode 100644 index 000000000..3d16043a3 --- /dev/null +++ b/racal/racal.h @@ -0,0 +1,57 @@ +/* + * Hamlib Racal backend - main header + * Copyright (c) 2004 by Stephane Fillod + * + * $Id: racal.h,v 1.1 2004-09-12 21:28:26 fillods Exp $ + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _RACAL_H +#define _RACAL_H 1 + +#include "hamlib/rig.h" + +#define TOK_RIGID TOKEN_BACKEND(1) + +extern const struct confparams racal_cfg_params[]; + +struct racal_priv_data { + unsigned receiver_id; + int bfo; + float threshold; /* attenuation */ +}; + +int racal_set_conf(RIG *rig, token_t token, const char *val); +int racal_get_conf(RIG *rig, token_t token, char *val); +int racal_init(RIG *rig); +int racal_cleanup(RIG *rig); +int racal_open(RIG *rig); +int racal_close(RIG *rig); + +int racal_set_freq(RIG *rig, vfo_t vfo, freq_t freq); +int racal_get_freq(RIG *rig, vfo_t vfo, freq_t *freq); +int racal_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width); +int racal_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width); +int racal_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val); +int racal_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val); +int racal_reset(RIG *rig, reset_t reset); +const char* racal_get_info(RIG *rig); + +extern const struct rig_caps ra6790_caps; + + +#endif /* _RACAL_H */ diff --git a/tuner/Makefile.am b/tuner/Makefile.am new file mode 100644 index 000000000..b9b29a139 --- /dev/null +++ b/tuner/Makefile.am @@ -0,0 +1,8 @@ +TUNERSRCLIST = v4l.c + +lib_LTLIBRARIES = hamlib-tuner.la +hamlib_tuner_la_SOURCES = $(TUNERSRCLIST) tuner.c +hamlib_tuner_la_LDFLAGS = -no-undefined -module -avoid-version +hamlib_tuner_la_LIBADD = $(top_builddir)/src/libhamlib.la + +noinst_HEADERS = tuner.h videodev.h diff --git a/tuner/tuner.c b/tuner/tuner.c new file mode 100644 index 000000000..157835343 --- /dev/null +++ b/tuner/tuner.c @@ -0,0 +1,42 @@ +/* + * Hamlib Tuner backend - main file + * Copyright (C) 2004 Stephane Fillodpab@users.sourceforge.net + * + * $Id: tuner.c,v 1.1 2004-09-12 21:30:21 fillods Exp $ + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "tuner.h" /* config.h */ + +#include + +#include "hamlib/rig.h" +#include "register.h" + + +DECLARE_INITRIG_BACKEND(tuner) +{ + rig_debug(RIG_DEBUG_VERBOSE, "tuner: _init called\n"); + +#ifdef V4L_IOCTL + rig_register(&v4l_caps); +#endif + + + return RIG_OK; +} + diff --git a/tuner/tuner.h b/tuner/tuner.h new file mode 100644 index 000000000..e30b51bd2 --- /dev/null +++ b/tuner/tuner.h @@ -0,0 +1,41 @@ +/* + * Hamlib Tuners backend - main header + * Copyright (c) 2004 by Stephane Fillod + * + * $Id: tuner.h,v 1.1 2004-09-12 21:30:21 fillods Exp $ + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _TUNER_H +#define _TUNER_H 1 + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +/* + * So far, only Linux has Video4Linux support through ioctl :) + * until someone port it to some other OS... + */ +#ifdef HAVE_LINUX_IOCTL_H +#define V4L_IOCTL +#endif + +#include "hamlib/rig.h" + +extern const struct rig_caps v4l_caps; + +#endif /* _TUNER_H */ diff --git a/tuner/v4l.c b/tuner/v4l.c new file mode 100644 index 000000000..5c026c61d --- /dev/null +++ b/tuner/v4l.c @@ -0,0 +1,394 @@ +/* + * Hamlib Tuner backend - Video4Linux description + * Copyright (c) 2004 by Stephane Fillod + * + * $Id: v4l.c,v 1.1 2004-09-12 21:30:21 fillods Exp $ + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include /* String function definitions */ +#include /* UNIX standard function definitions */ +#include +#include + +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#include "hamlib/rig.h" +#include "misc.h" + +#include "tuner.h" /* include config.h */ + +#ifdef V4L_IOCTL + +#include +#include "idx_builtin.h" + + +#define V4L_FUNC (RIG_FUNC_MUTE) + +#define V4L_LEVEL_ALL (RIG_LEVEL_AF|RIG_LEVEL_RAWSTR) + +#define V4L_PARM_ALL (RIG_PARM_NONE) + +#define V4L_VFO (RIG_VFO_A) + +/* FIXME: per card measures? */ +#define V4L_STR_CAL { 2, { \ + { 0, -60 }, \ + { 65535, 60 }, \ + } } + +static int v4l_init(RIG *rig); +static int v4l_open(RIG *rig); +static int v4l_set_freq(RIG *rig, vfo_t vfo, freq_t freq); +static int v4l_get_freq(RIG *rig, vfo_t vfo, freq_t *freq); +static int v4l_set_func(RIG *rig, vfo_t vfo, setting_t func, int status); +static int v4l_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status); +static int v4l_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val); +static int v4l_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val); +static const char *v4l_get_info(RIG *rig); + +/* + * v4l rig capabilities. + * + * + */ +const struct rig_caps v4l_caps = { +.rig_model = RIG_MODEL_V4L, +.model_name = "BW/FM radio", +.mfg_name = "Video4Linux", +.version = "0.1", +.copyright = "LGPL", +.status = RIG_STATUS_UNTESTED, +.rig_type = RIG_TYPE_PCRECEIVER, +.ptt_type = RIG_PTT_NONE, +.dcd_type = RIG_DCD_NONE, +.port_type = RIG_PORT_DEVICE, +.serial_rate_min = 1200, +.serial_rate_max = 9600, +.serial_data_bits = 8, +.serial_stop_bits = 1, +.serial_parity = RIG_PARITY_NONE, +.serial_handshake = RIG_HANDSHAKE_NONE, +.write_delay = 0, +.post_write_delay = 0, +.timeout = 2000, +.retry = 1, + +.has_get_func = V4L_FUNC, +.has_set_func = V4L_FUNC, +.has_get_level = V4L_LEVEL_ALL, +.has_set_level = RIG_LEVEL_SET(V4L_LEVEL_ALL), +.has_get_parm = V4L_PARM_ALL, +.has_set_parm = RIG_PARM_SET(V4L_PARM_ALL), +.vfo_ops = RIG_OP_NONE, +.level_gran = { + [LVL_RAWSTR] = { .min = { .i = 0 }, .max = { .i = 65535 } }, +}, +.preamp = { RIG_DBLST_END }, +.attenuator = { RIG_DBLST_END }, +.max_rit = Hz(0), +.max_xit = Hz(0), +.max_ifshift = Hz(0), +.targetable_vfo = 0, +.transceive = RIG_TRN_OFF, +.bank_qty = 0, +.chan_desc_sz = 0, + +.chan_list = { RIG_CHAN_END, }, + + /* will be rewritten at runtime */ +.rx_range_list1 = { + {MHz(87.9),MHz(108.9),RIG_MODE_WFM,-1,-1,V4L_VFO}, + RIG_FRNG_END, + }, +.tx_range_list1 = { RIG_FRNG_END, }, +.rx_range_list2 = { + {MHz(87.9),MHz(108.9),RIG_MODE_WFM,-1,-1,V4L_VFO}, + RIG_FRNG_END, + }, +.tx_range_list2 = { RIG_FRNG_END, }, +.tuning_steps = { + {RIG_MODE_WFM,100}, + RIG_TS_END, + }, + /* mode/filter list, remember: order matters! */ +.filters = { + {RIG_MODE_WFM, kHz(230)}, /* guess */ + {RIG_MODE_AM, kHz(8)}, /* guess */ + RIG_FLT_END, + }, +.str_cal = V4L_STR_CAL, + +.rig_init = v4l_init, +.rig_open = v4l_open, + +.set_freq = v4l_set_freq, +.get_freq = v4l_get_freq, +.set_func = v4l_set_func, +.get_func = v4l_get_func, +.set_level = v4l_set_level, +.get_level = v4l_get_level, + +.get_info = v4l_get_info, + +}; + +/* + * Function definitions below + */ + + +#include "videodev.h" + + +#define DEFAULT_V4L_PATH "/dev/radio0" + +int v4l_init(RIG *rig) +{ + rig->state.rigport.type.rig = RIG_PORT_DEVICE; + strncpy(rig->state.rigport.pathname, DEFAULT_V4L_PATH, FILPATHLEN); + + return RIG_OK; +} + +int v4l_open(RIG *rig) +{ + int ret, i; + struct video_tuner vt; + struct rig_state *rs = &rig->state; + double fact; + + for (i=0; i<8; i++) { + vt.tuner = i; + ret = ioctl(rig->state.rigport.fd, VIDIOCGTUNER, &vt); + if (ret < 0) + break; + + fact = (vt.flags & VIDEO_TUNER_LOW) == 0 ? 16 : 16000; + rs->rx_range_list[i].start = vt.rangelow/fact; + rs->rx_range_list[i].end = vt.rangehigh/fact; + rs->rx_range_list[i].modes = vt.rangehigh/fact < MHz(30) ? RIG_MODE_AM : RIG_MODE_WFM; + /* hack! hack! store the resolution in low_power! */ + rs->rx_range_list[i].low_power = rint(fact); + } + return RIG_OK; +} + + +int v4l_set_freq(RIG *rig, vfo_t vfo, freq_t freq) +{ + struct rig_state *rs = &rig->state; + struct video_tuner vt; + const freq_range_t *range; + unsigned long f; + double fact; + int ret; + + /* AM or WFM */ + range = rig_get_range (rs->rx_range_list, freq, RIG_MODE_AM|RIG_MODE_WFM); + if (!range) + return -RIG_ECONF; + + /* at this point, we are trying to tune to a frequency */ + + vt.tuner = (rs->rx_range_list-range)/sizeof(freq_range_t); + + ret = ioctl(rig->state.rigport.fd, VIDIOCSTUNER, &vt); /* set tuner # */ + if (ret < 0) { + rig_debug(RIG_DEBUG_ERR, "ioctl VIDIOCSTUNER: %s\n", + strerror(errno)); + return -RIG_EIO; + } + fact = range->low_power; + + f = rint(freq * fact); /* rounding to nearest int */ + + ret = ioctl(rig->state.rigport.fd, VIDIOCSFREQ, &freq); + if (ret < 0) { + rig_debug(RIG_DEBUG_ERR, "ioctl VIDIOCSFREQ: %s\n", + strerror(errno)); + return -RIG_EIO; + } + + return RIG_OK; +} + +int v4l_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) +{ + struct rig_state *rs = &rig->state; + const freq_range_t *range; + unsigned long f; + double fact; + int ret; + + ret = ioctl(rig->state.rigport.fd, VIDIOCGFREQ, &f); + if (ret < 0) { + rig_debug(RIG_DEBUG_ERR, "ioctl VIDIOCGFREQ: %s\n", + strerror(errno)); + return -RIG_EIO; + } + + /* FIXME: remember tuner and current *fact* */ + range = rig_get_range (rs->rx_range_list, f/16, RIG_MODE_AM|RIG_MODE_WFM); + if (!range) + return -RIG_ECONF; + fact = range->low_power; + + + *freq = f/fact; + + return RIG_OK; +} + +int v4l_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) +{ + struct video_audio va; + int ret; + + switch ( func ) { + case RIG_FUNC_MUTE: + ret = ioctl(rig->state.rigport.fd, VIDIOCGAUDIO, &va); + if (ret < 0) { + rig_debug(RIG_DEBUG_ERR, "ioctl VIDIOCGAUDIO: %s\n", + strerror(errno)); + return -RIG_EIO; + } + va.flags = status ? VIDEO_AUDIO_MUTE : 0; + ret = ioctl(rig->state.rigport.fd, VIDIOCSAUDIO, &va); + if (ret < 0) { + rig_debug(RIG_DEBUG_ERR, "ioctl VIDIOCSAUDIO: %s\n", + strerror(errno)); + return -RIG_EIO; + } + break; + + default: + return -RIG_EINVAL; + } + return RIG_OK; +} + +int v4l_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) +{ + struct video_audio va; + int ret; + + switch ( func ) { + case RIG_FUNC_MUTE: + ret = ioctl(rig->state.rigport.fd, VIDIOCGAUDIO, &va); + if (ret < 0) { + rig_debug(RIG_DEBUG_ERR, "ioctl VIDIOCGAUDIO: %s\n", + strerror(errno)); + return -RIG_EIO; + } + *status = (va.flags & VIDEO_AUDIO_MUTE) == VIDEO_AUDIO_MUTE ; + break; + default: + return -RIG_EINVAL; + } + return RIG_OK; +} + + +int v4l_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) +{ + struct video_audio va; + int ret; + + ret = ioctl(rig->state.rigport.fd, VIDIOCGAUDIO, &va); + if (ret < 0) { + rig_debug(RIG_DEBUG_ERR, "ioctl VIDIOCGAUDIO: %s\n", + strerror(errno)); + return -RIG_EIO; + } + + switch ( level ) { + case RIG_LEVEL_AF: + va.volume = val.f * 65535; + break; + + default: + return -RIG_EINVAL; + } + + ret = ioctl(rig->state.rigport.fd, VIDIOCSAUDIO, &va); + if (ret < 0) { + rig_debug(RIG_DEBUG_ERR, "ioctl VIDIOCSAUDIO: %s\n", + strerror(errno)); + return -RIG_EIO; + } + return RIG_OK; +} + +int v4l_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) +{ + struct video_audio va; + struct video_tuner vt; + int ret; + + switch ( level ) { + case RIG_LEVEL_AF: + ret = ioctl(rig->state.rigport.fd, VIDIOCGAUDIO, &va); + if (ret < 0) { + rig_debug(RIG_DEBUG_ERR, "ioctl VIDIOCGAUDIO: %s\n", + strerror(errno)); + return -RIG_EIO; + } + val->f = (float)va.volume / 65535.; + break; + + case RIG_LEVEL_RAWSTR: + ret = ioctl(rig->state.rigport.fd, VIDIOCGTUNER, &vt); /* get info */ + if (ret < 0) { + rig_debug(RIG_DEBUG_ERR, "ioctl VIDIOCGTUNER: %s\n", + strerror(errno)); + return -RIG_EIO; + } + val->i = vt.signal; + break; + + default: + return -RIG_EINVAL; + } + + return RIG_OK; +} + +/* + * FIXME: static buf does not allow reentrancy! + */ +const char *v4l_get_info(RIG *rig) +{ + static struct video_tuner vt; + int ret; + + vt.tuner = 0; + ret = ioctl(rig->state.rigport.fd, VIDIOCGTUNER, &vt); + if (ret < 0) { + rig_debug(RIG_DEBUG_ERR, "ioctl VIDIOCGTUNER: %s\n", + strerror(errno)); + return "Get info failed"; + } + return vt.name; +} + +#endif /* V4L_IOCTL */ + diff --git a/tuner/videodev.h b/tuner/videodev.h new file mode 100644 index 000000000..6032b52ed --- /dev/null +++ b/tuner/videodev.h @@ -0,0 +1,348 @@ +/* This header is extracted from linux/videodev.h, approximately + version 2.6.0. We can't use linux/videodev.h directly because + it indirectly defines struct timespec, which is also defined + by the standard C library headers. Argh. -blp */ + +#ifndef FM_VIDEODEV_H +#define FM_VIDEODEV_H 1 + +#include +#include + +#define VID_TYPE_CAPTURE 1 /* Can capture */ +#define VID_TYPE_TUNER 2 /* Can tune */ +#define VID_TYPE_TELETEXT 4 /* Does teletext */ +#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ +#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ +#define VID_TYPE_CLIPPING 32 /* Can clip */ +#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ +#define VID_TYPE_SCALES 128 /* Scalable */ +#define VID_TYPE_MONOCHROME 256 /* Monochrome only */ +#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ +#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ +#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ +#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ +#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ + +struct video_capability +{ + char name[32]; + int type; + int channels; /* Num channels */ + int audios; /* Num audio devices */ + int maxwidth; /* Supported width */ + int maxheight; /* And height */ + int minwidth; /* Supported width */ + int minheight; /* And height */ +}; + + +struct video_channel +{ + int channel; + char name[32]; + int tuners; + uint32_t flags; +#define VIDEO_VC_TUNER 1 /* Channel has a tuner */ +#define VIDEO_VC_AUDIO 2 /* Channel has audio */ + uint16_t type; +#define VIDEO_TYPE_TV 1 +#define VIDEO_TYPE_CAMERA 2 + uint16_t norm; /* Norm set by channel */ +}; + +struct video_tuner +{ + int tuner; + char name[32]; + unsigned long rangelow, rangehigh; /* Tuner range */ + uint32_t flags; +#define VIDEO_TUNER_PAL 1 +#define VIDEO_TUNER_NTSC 2 +#define VIDEO_TUNER_SECAM 4 +#define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */ +#define VIDEO_TUNER_NORM 16 /* Tuner can set norm */ +#define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */ +#define VIDEO_TUNER_RDS_ON 256 /* Tuner is seeing an RDS datastream */ +#define VIDEO_TUNER_MBS_ON 512 /* Tuner is seeing an MBS datastream */ + uint16_t mode; /* PAL/NTSC/SECAM/OTHER */ +#define VIDEO_MODE_PAL 0 +#define VIDEO_MODE_NTSC 1 +#define VIDEO_MODE_SECAM 2 +#define VIDEO_MODE_AUTO 3 + uint16_t signal; /* Signal strength 16bit scale */ +}; + +struct video_picture +{ + uint16_t brightness; + uint16_t hue; + uint16_t colour; + uint16_t contrast; + uint16_t whiteness; /* Black and white only */ + uint16_t depth; /* Capture depth */ + uint16_t palette; /* Palette in use */ +#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */ +#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */ +#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */ +#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */ +#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */ +#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */ +#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */ +#define VIDEO_PALETTE_YUYV 8 +#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */ +#define VIDEO_PALETTE_YUV420 10 +#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */ +#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */ +#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */ +#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */ +#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */ +#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */ +#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */ +#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */ +}; + +struct video_audio +{ + int audio; /* Audio channel */ + uint16_t volume; /* If settable */ + uint16_t bass, treble; + uint32_t flags; +#define VIDEO_AUDIO_MUTE 1 +#define VIDEO_AUDIO_MUTABLE 2 +#define VIDEO_AUDIO_VOLUME 4 +#define VIDEO_AUDIO_BASS 8 +#define VIDEO_AUDIO_TREBLE 16 +#define VIDEO_AUDIO_BALANCE 32 + char name[16]; +#define VIDEO_SOUND_MONO 1 +#define VIDEO_SOUND_STEREO 2 +#define VIDEO_SOUND_LANG1 4 +#define VIDEO_SOUND_LANG2 8 + uint16_t mode; + uint16_t balance; /* Stereo balance */ + uint16_t step; /* Step actual volume uses */ +}; + +struct video_clip +{ + int32_t x,y; + int32_t width, height; + struct video_clip *next; /* For user use/driver use only */ +}; + +struct video_window +{ + uint32_t x,y; /* Position of window */ + uint32_t width,height; /* Its size */ + uint32_t chromakey; + uint32_t flags; + struct video_clip *clips; /* Set only */ + int clipcount; +#define VIDEO_WINDOW_INTERLACE 1 +#define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */ +#define VIDEO_CLIP_BITMAP -1 +/* bitmap is 1024x625, a '1' bit represents a clipped pixel */ +#define VIDEO_CLIPMAP_SIZE (128 * 625) +}; + +struct video_capture +{ + uint32_t x,y; /* Offsets into image */ + uint32_t width, height; /* Area to capture */ + uint16_t decimation; /* Decimation divider */ + uint16_t flags; /* Flags for capture */ +#define VIDEO_CAPTURE_ODD 0 /* Temporal */ +#define VIDEO_CAPTURE_EVEN 1 +}; + +struct video_buffer +{ + void *base; + int height,width; + int depth; + int bytesperline; +}; + +struct video_mmap +{ + unsigned int frame; /* Frame (0 - n) for double buffer */ + int height,width; + unsigned int format; /* should be VIDEO_PALETTE_* */ +}; + +struct video_key +{ + uint8_t key[8]; + uint32_t flags; +}; + + +#define VIDEO_MAX_FRAME 32 + +struct video_mbuf +{ + int size; /* Total memory to map */ + int frames; /* Frames */ + int offsets[VIDEO_MAX_FRAME]; +}; + + +#define VIDEO_NO_UNIT (-1) + + +struct video_unit +{ + int video; /* Video minor */ + int vbi; /* VBI minor */ + int radio; /* Radio minor */ + int audio; /* Audio minor */ + int teletext; /* Teletext minor */ +}; + +struct vbi_format { + uint32_t sampling_rate; /* in Hz */ + uint32_t samples_per_line; + uint32_t sample_format; /* VIDEO_PALETTE_RAW only (1 byte) */ + int32_t start[2]; /* starting line for each frame */ + uint32_t count[2]; /* count of lines for each frame */ + uint32_t flags; +#define VBI_UNSYNC 1 /* can distingues between top/bottom field */ +#define VBI_INTERLACED 2 /* lines are interlaced */ +}; + +/* video_info is biased towards hardware mpeg encode/decode */ +/* but it could apply generically to any hardware compressor/decompressor */ +struct video_info +{ + uint32_t frame_count; /* frames output since decode/encode began */ + uint32_t h_size; /* current unscaled horizontal size */ + uint32_t v_size; /* current unscaled veritcal size */ + uint32_t smpte_timecode; /* current SMPTE timecode (for current GOP) */ + uint32_t picture_type; /* current picture type */ + uint32_t temporal_reference; /* current temporal reference */ + uint8_t user_data[256]; /* user data last found in compressed stream */ + /* user_data[0] contains user data flags, user_data[1] has count */ +}; + +/* generic structure for setting playback modes */ +struct video_play_mode +{ + int mode; + int p1; + int p2; +}; + +/* for loading microcode / fpga programming */ +struct video_code +{ + char loadwhat[16]; /* name or tag of file being passed */ + int datasize; + uint8_t *data; +}; + +#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */ +#define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */ +#define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */ +#define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */ +#define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */ +#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */ +#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */ +#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */ +#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Get the video overlay window */ +#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ +#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */ +#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */ +#define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */ +#define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */ +#define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */ +#define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */ +#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */ +#define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */ +#define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */ +#define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */ +#define VIDIOCGUNIT _IOR('v',21, struct video_unit) /* Get attached units */ +#define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get subcapture */ +#define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set subcapture */ +#define VIDIOCSPLAYMODE _IOW('v',24, struct video_play_mode) /* Set output video mode/feature */ +#define VIDIOCSWRITEMODE _IOW('v',25, int) /* Set write mode */ +#define VIDIOCGPLAYINFO _IOR('v',26, struct video_info) /* Get current playback info from hardware */ +#define VIDIOCSMICROCODE _IOW('v',27, struct video_code) /* Load microcode into hardware */ +#define VIDIOCGVBIFMT _IOR('v',28, struct vbi_format) /* Get VBI information */ +#define VIDIOCSVBIFMT _IOW('v',29, struct vbi_format) /* Set VBI information */ + + +#define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */ + +/* VIDIOCSWRITEMODE */ +#define VID_WRITE_MPEG_AUD 0 +#define VID_WRITE_MPEG_VID 1 +#define VID_WRITE_OSD 2 +#define VID_WRITE_TTX 3 +#define VID_WRITE_CC 4 +#define VID_WRITE_MJPEG 5 + +/* VIDIOCSPLAYMODE */ +#define VID_PLAY_VID_OUT_MODE 0 + /* p1: = VIDEO_MODE_PAL, VIDEO_MODE_NTSC, etc ... */ +#define VID_PLAY_GENLOCK 1 + /* p1: 0 = OFF, 1 = ON */ + /* p2: GENLOCK FINE DELAY value */ +#define VID_PLAY_NORMAL 2 +#define VID_PLAY_PAUSE 3 +#define VID_PLAY_SINGLE_FRAME 4 +#define VID_PLAY_FAST_FORWARD 5 +#define VID_PLAY_SLOW_MOTION 6 +#define VID_PLAY_IMMEDIATE_NORMAL 7 +#define VID_PLAY_SWITCH_CHANNELS 8 +#define VID_PLAY_FREEZE_FRAME 9 +#define VID_PLAY_STILL_MODE 10 +#define VID_PLAY_MASTER_MODE 11 + /* p1: see below */ +#define VID_PLAY_MASTER_NONE 1 +#define VID_PLAY_MASTER_VIDEO 2 +#define VID_PLAY_MASTER_AUDIO 3 +#define VID_PLAY_ACTIVE_SCANLINES 12 + /* p1 = first active; p2 = last active */ +#define VID_PLAY_RESET 13 +#define VID_PLAY_END_MARK 14 + + + +#define VID_HARDWARE_BT848 1 +#define VID_HARDWARE_QCAM_BW 2 +#define VID_HARDWARE_PMS 3 +#define VID_HARDWARE_QCAM_C 4 +#define VID_HARDWARE_PSEUDO 5 +#define VID_HARDWARE_SAA5249 6 +#define VID_HARDWARE_AZTECH 7 +#define VID_HARDWARE_SF16MI 8 +#define VID_HARDWARE_RTRACK 9 +#define VID_HARDWARE_ZOLTRIX 10 +#define VID_HARDWARE_SAA7146 11 +#define VID_HARDWARE_VIDEUM 12 /* Reserved for Winnov videum */ +#define VID_HARDWARE_RTRACK2 13 +#define VID_HARDWARE_PERMEDIA2 14 /* Reserved for Permedia2 */ +#define VID_HARDWARE_RIVA128 15 /* Reserved for RIVA 128 */ +#define VID_HARDWARE_PLANB 16 /* PowerMac motherboard video-in */ +#define VID_HARDWARE_BROADWAY 17 /* Broadway project */ +#define VID_HARDWARE_GEMTEK 18 +#define VID_HARDWARE_TYPHOON 19 +#define VID_HARDWARE_VINO 20 /* SGI Indy Vino */ +#define VID_HARDWARE_CADET 21 /* Cadet radio */ +#define VID_HARDWARE_TRUST 22 /* Trust FM Radio */ +#define VID_HARDWARE_TERRATEC 23 /* TerraTec ActiveRadio */ +#define VID_HARDWARE_CPIA 24 +#define VID_HARDWARE_ZR36120 25 /* Zoran ZR36120/ZR36125 */ +#define VID_HARDWARE_ZR36067 26 /* Zoran ZR36067/36060 */ +#define VID_HARDWARE_OV511 27 +#define VID_HARDWARE_ZR356700 28 /* Zoran 36700 series */ +#define VID_HARDWARE_W9966 29 +#define VID_HARDWARE_SE401 30 /* SE401 USB webcams */ +#define VID_HARDWARE_PWC 31 /* Philips webcams */ +#define VID_HARDWARE_MEYE 32 /* Sony Vaio MotionEye cameras */ +#define VID_HARDWARE_CPIA2 33 +#define VID_HARDWARE_VICAM 34 +#define VID_HARDWARE_SF16FMR2 35 + +#endif /* videodev.h */ diff --git a/wj/Makefile.am b/wj/Makefile.am new file mode 100644 index 000000000..6970dbda0 --- /dev/null +++ b/wj/Makefile.am @@ -0,0 +1,8 @@ +WJSRCLIST = wj8888.c + +lib_LTLIBRARIES = hamlib-wj.la +hamlib_wj_la_SOURCES = $(WJSRCLIST) wj.c +hamlib_wj_la_LDFLAGS = -no-undefined -module -avoid-version +hamlib_wj_la_LIBADD = $(top_builddir)/src/libhamlib.la + +noinst_HEADERS = wj.h diff --git a/wj/wj.c b/wj/wj.c new file mode 100644 index 000000000..b30f86e67 --- /dev/null +++ b/wj/wj.c @@ -0,0 +1,407 @@ +/* + * Hamlib Watkins-Johnson backend - main file + * Copyright (c) 2004 by Stephane Fillod + * + * $Id: wj.c,v 1.1 2004-09-12 21:29:10 fillods Exp $ + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include /* String function definitions */ +#include /* UNIX standard function definitions */ +#include + +#include "hamlib/rig.h" +#include "serial.h" +#include "misc.h" +#include "cal.h" +#include "register.h" +#include "token.h" + +#include "wj.h" + + +#define CMDSZ 10 + +const struct confparams wj_cfg_params[] = { + { TOK_RIGID, "receiver_id", "receiver ID", "receiver ID", + "0", RIG_CONF_NUMERIC, { .n = { 0, 15, 1 } } + }, + { RIG_CONF_END, NULL, } +}; + + +/* + * modes + */ +#define MD_AM 0 +#define MD_FM 1 +#define MD_CW 2 +#define MD_VCW 3 /* BFO variable */ +#define MD_ISB 4 +#define MD_LSB 5 +#define MD_USB 6 +#define MD_AMNL 7 + + +/* + * wj_transaction + * + * I'm not sure how monitor protocol works, whether you have + * to send the full frame, or just the modal byte. --SF + * + * TODO: decode the whole reply, and maybe do some caching + */ +static int wj_transaction(RIG *rig, int monitor) +{ + struct wj_priv_data *priv = (struct wj_priv_data*)rig->state.priv; + + unsigned char buf[CMDSZ] = { 0x8, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + unsigned char rxbuf[CMDSZ]; + unsigned char freqbuf[4]; + unsigned wj_agc, wj_mode, wj_width, wj_bfo, wj_rfgain; + int retval; + + if (monitor) + buf[1] |= 0x40; /* Monitor+AGC dump */ + else + buf[0] |= 0x40; /* Command */ + + buf[0] |= priv->receiver_id & 0x0f; + + /* tuned frequency */ + to_bcd_be(freqbuf, priv->freq/10, 7); + buf[1] |= freqbuf[0] & 0x3f; + buf[2] |= freqbuf[1]>>1; + buf[3] |= ((freqbuf[1]&0x1)<<6) | (freqbuf[2]>>2); + buf[4] |= ((freqbuf[2]&0x2)<<5) | (freqbuf[3]>>3); + + /* gain mode */ + switch (priv->agc.i) { + case RIG_AGC_SLOW: wj_agc = 0; break; /* slow, 2s */ + case RIG_AGC_OFF: wj_agc = 1; break; /* "not used" */ + case RIG_AGC_FAST: wj_agc = 2; break; /* normal, 0.1s */ + case RIG_AGC_USER: wj_agc = 3; break; /* manual */ + default: return -RIG_EINVAL; + } + buf[4] |= wj_agc & 0x1; + buf[5] |= (wj_agc & 0x2)<<5; + + /* IF BW */ + switch (priv->width) { + case 200: + case 1000: wj_width = 0; break; /* spare */ + + case 500: wj_width = 1; break; + case 2000: wj_width = 2; break; + case 4000: wj_width = 3; break; + case 8000: wj_width = 4; break; + + case 3000: + case 6000: + case 12000: + case 16000: wj_width = 5; break; /* spare */ + default: + return -RIG_EINVAL; + } + buf[5] |= (wj_width & 0x2)<<3; + + /* Detection mode */ + switch (priv->mode) { + case RIG_MODE_CW: wj_mode = (priv->ifshift.i!=0) ? MD_VCW:MD_CW; break; + case RIG_MODE_USB: wj_mode = MD_USB; break; + case RIG_MODE_LSB: wj_mode = MD_LSB; break; + case RIG_MODE_FM: wj_mode = MD_FM; break; + case RIG_MODE_AM: wj_mode = MD_AM; break; + case RIG_MODE_AMS: wj_mode = MD_ISB; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported mode %d\n", + __FUNCTION__, priv->mode); + return -RIG_EINVAL; + } + buf[5] |= wj_mode & 0x3; + + /* BFO frequency, not sure though */ + wj_bfo = (priv->ifshift.i/10) + 0x400; /* LSBit is 10Hz, +455kHz */ + buf[6] |= (wj_bfo >> 5) & 0x3f; + buf[7] |= (wj_bfo & 0x1f) << 2; + + /* RF gain */ + wj_rfgain = (unsigned)(priv->rfgain.f * 0x7f); + buf[7] |= (wj_rfgain >> 6) & 0x1; + buf[8] |= (wj_rfgain & 0x3f) << 1; + + /* buf[9]: not used if command byte, but must be transmitted */ + + serial_flush(&rig->state.rigport); + + retval = write_block(&rig->state.rigport, buf, CMDSZ); + if (retval != RIG_OK) + return retval; + + if (monitor) { + /* + * Transceiver sends back ">" + */ + retval = read_block(&rig->state.rigport, rxbuf, CMDSZ); + if (retval < 0 || retval > CMDSZ) + return RIG_ERJCTED; + + /* + * TODO: analyze back the reply, and fill in the priv struct + */ + priv->rawstr.i = rxbuf[9] & 0x7f; + } + + return retval; +} + +int wj_init(RIG *rig) +{ + struct wj_priv_data *priv; + + if (!rig || !rig->caps) + return -RIG_EINVAL; + + priv = (struct wj_priv_data*)malloc(sizeof(struct wj_priv_data)); + if (!priv) { + /* whoops! memory shortage! */ + return -RIG_ENOMEM; + } + + rig->state.priv = (void*)priv; + + priv->receiver_id = 0; + priv->freq = kHz(500); + priv->mode = RIG_MODE_AM; + priv->width = kHz(8); + priv->agc.i = RIG_AGC_SLOW; + priv->rfgain.f = 1; + priv->ifshift.i = 0; + + return RIG_OK; +} + +/* + */ +int wj_cleanup(RIG *rig) +{ + if (!rig) + return -RIG_EINVAL; + + if (rig->state.priv) + free(rig->state.priv); + rig->state.priv = NULL; + + return RIG_OK; +} + + + +/* + * Assumes rig!=NULL, rig->state.priv!=NULL + */ +int wj_set_conf(RIG *rig, token_t token, const char *val) +{ + struct wj_priv_data *priv = (struct wj_priv_data*)rig->state.priv; + + switch (token) { + case TOK_RIGID: + priv->receiver_id = atoi(val); + break; + default: + return -RIG_EINVAL; + } + return RIG_OK; +} + +/* + * assumes rig!=NULL, + * Assumes rig!=NULL, rig->state.priv!=NULL + * and val points to a buffer big enough to hold the conf value. + */ +int wj_get_conf(RIG *rig, token_t token, char *val) +{ + struct wj_priv_data *priv = (struct wj_priv_data*)rig->state.priv; + + switch(token) { + case TOK_RIGID: + sprintf(val, "%d", priv->receiver_id); + break; + default: + return -RIG_EINVAL; + } + return RIG_OK; +} + +/* + * wj_set_freq + * Assumes rig!=NULL + */ +int wj_set_freq(RIG *rig, vfo_t vfo, freq_t freq) +{ + struct wj_priv_data *priv = (struct wj_priv_data*)rig->state.priv; + + priv->freq = freq; + + return wj_transaction (rig, 0); +} + +/* + * wj_get_freq + * Assumes rig!=NULL + */ +int wj_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) +{ + struct wj_priv_data *priv = (struct wj_priv_data*)rig->state.priv; + int retval; + + retval = wj_transaction (rig, 1); + if (retval == RIG_OK) + return retval; + + *freq = priv->freq; + + return RIG_OK; +} + +/* + * wj_set_mode + * Assumes rig!=NULL + */ +int wj_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) +{ + struct wj_priv_data *priv = (struct wj_priv_data*)rig->state.priv; + + priv->mode = mode; + + if (width == RIG_PASSBAND_NORMAL) + width = rig_passband_normal(rig, mode); + + priv->width = width; + + return wj_transaction (rig, 0); +} + +/* + * wj_get_mode + * Assumes rig!=NULL + */ +int wj_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) +{ + struct wj_priv_data *priv = (struct wj_priv_data*)rig->state.priv; + int retval; + + retval = wj_transaction (rig, 1); + if (retval == RIG_OK) + return retval; + + *mode = priv->mode; + *width = priv->width; + + return RIG_OK; +} + + + +/* + * wj_set_level + * Assumes rig!=NULL + */ +int wj_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) +{ + struct wj_priv_data *priv = (struct wj_priv_data*)rig->state.priv; + + switch (level) { + case RIG_LEVEL_IF: + priv->ifshift.i = val.i; + break; + + case RIG_LEVEL_RF: + priv->rfgain.f = val.f; + break; + + case RIG_LEVEL_AGC: + priv->agc.i = val.i; + break; + + default: + rig_debug(RIG_DEBUG_ERR,"%s: unsupported %d\n", __FUNCTION__, level); + return -RIG_EINVAL; + } + + return wj_transaction (rig, 0); +} + +/* + * wj_get_level + * Assumes rig!=NULL + */ +int wj_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) +{ + struct wj_priv_data *priv = (struct wj_priv_data*)rig->state.priv; + int retval = RIG_OK; + + retval = wj_transaction (rig, 1); + if (retval == RIG_OK) + return retval; + + switch (level) { + case RIG_LEVEL_RAWSTR: + val->i = priv->rawstr.i; + break; + + case RIG_LEVEL_IF: + val->i = priv->ifshift.i; + break; + + case RIG_LEVEL_RF: + val->f = priv->rfgain.f; + break; + + case RIG_LEVEL_AGC: + val->i = priv->agc.i; + break; + + + default: + rig_debug(RIG_DEBUG_ERR,"%s: Unsupported %d\n", __FUNCTION__, level); + return -RIG_EINVAL; + } + + return retval; +} + + +/* + * initrigs_wj is called by rig_backend_load + */ +DECLARE_INITRIG_BACKEND(wj) +{ + rig_debug(RIG_DEBUG_VERBOSE, "wj: _init called\n"); + + rig_register(&wj8888_caps); + + return RIG_OK; +} + + diff --git a/wj/wj.h b/wj/wj.h new file mode 100644 index 000000000..c6dd69429 --- /dev/null +++ b/wj/wj.h @@ -0,0 +1,56 @@ +/* + * Hamlib Watkins-Johnson backend - main header + * Copyright (c) 2004 by Stephane Fillod + * + * $Id: wj.h,v 1.1 2004-09-12 21:29:10 fillods Exp $ + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _WJ_H +#define _WJ_H 1 + +#include + +#define TOK_RIGID TOKEN_BACKEND(1) + +extern const struct confparams wj_cfg_params[]; + +struct wj_priv_data { + unsigned receiver_id; + freq_t freq; + rmode_t mode; + pbwidth_t width; + value_t agc; + value_t rfgain; + value_t ifshift; + value_t rawstr; +}; + +int wj_set_conf(RIG *rig, token_t token, const char *val); +int wj_get_conf(RIG *rig, token_t token, char *val); +int wj_init(RIG *rig); +int wj_cleanup(RIG *rig); +int wj_set_freq(RIG *rig, vfo_t vfo, freq_t freq); +int wj_get_freq(RIG *rig, vfo_t vfo, freq_t *freq); +int wj_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width); +int wj_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width); +int wj_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val); +int wj_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val); + +extern const struct rig_caps wj8888_caps; + +#endif /* _WJ_H */ diff --git a/wj/wj8888.c b/wj/wj8888.c new file mode 100644 index 000000000..f70360189 --- /dev/null +++ b/wj/wj8888.c @@ -0,0 +1,153 @@ +/* + * Hamlib Watkins-Johnson backend - WJ-8888 description + * Copyright (c) 2004 by Stephane Fillod + * + * $Id: wj8888.c,v 1.1 2004-09-12 21:29:10 fillods Exp $ + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include "idx_builtin.h" +#include "wj.h" + + +/* modes: what about ISB(Idependant Sideband)? */ +#define WJ8888_MODES (RIG_MODE_AM|RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_FM|RIG_MODE_AMS) + +#define WJ8888_FUNC (RIG_FUNC_NONE) + +#define WJ8888_LEVEL (RIG_LEVEL_RF|RIG_LEVEL_AGC|RIG_LEVEL_IF|RIG_LEVEL_RAWSTR) + +#define WJ8888_VFO (RIG_VFO_A) + +/* FIXME: real measures */ +#define WJ8888_STR_CAL { 2, \ + { \ + { 0x00, -60 }, /* -115.5dBm .. -99.5dBm */ \ + { 0x7f, 60 } \ + } } + +/* + * WJ-8888 receiver capabilities. + * + * Needs async I/O board + * + * + * TODO: BFO + */ +const struct rig_caps wj8888_caps = { +.rig_model = RIG_MODEL_WJ8888, +.model_name = "WJ-8888", +.mfg_name = "Watkins-Johnson", +.version = "0.1", +.copyright = "LGPL", +.status = RIG_STATUS_UNTESTED, +.rig_type = RIG_TYPE_RECEIVER, +.ptt_type = RIG_PTT_NONE, +.dcd_type = RIG_DCD_NONE, +.port_type = RIG_PORT_SERIAL, +.serial_rate_min = 75, /* jumper E26 */ +.serial_rate_max = 9600, /* jumper E19 */ +.serial_data_bits = 8, +.serial_stop_bits = 1, /* jumper between E5 & E6 */ +.serial_parity = RIG_PARITY_NONE, /* no jumper between E3 & E4 */ +.serial_handshake = RIG_HANDSHAKE_NONE, +.write_delay = 0, +.post_write_delay = 5, /* typical 5ms, max 15ms */ +.timeout = 2000, +.retry = 3, + +.has_get_func = WJ8888_FUNC, +.has_set_func = WJ8888_FUNC, +.has_get_level = WJ8888_LEVEL, +.has_set_level = RIG_LEVEL_SET(WJ8888_LEVEL), +.has_get_parm = RIG_PARM_NONE, +.has_set_parm = RIG_PARM_NONE, +.vfo_ops = RIG_OP_NONE, +.preamp = { RIG_DBLST_END }, +.attenuator = { RIG_DBLST_END }, +.level_gran = { + [LVL_RAWSTR] = { .min = { .i = 0 }, .max = { .i = 0x7f } }, +}, +.max_rit = Hz(0), +.max_xit = Hz(0), +.max_ifshift = kHz(8), /* IF at 455kHz */ +.targetable_vfo = 0, +.transceive = RIG_TRN_OFF, +.bank_qty = 0, +.chan_desc_sz = 0, +.str_cal = WJ8888_STR_CAL, + +.cfgparams = wj_cfg_params, + +.chan_list = { RIG_CHAN_END, }, + +.rx_range_list1 = { + {kHz(500),MHz(30),WJ8888_MODES,-1,-1,WJ8888_VFO}, + RIG_FRNG_END, + }, +.tx_range_list1 = { RIG_FRNG_END, }, +.rx_range_list2 = { + {kHz(500),MHz(30),WJ8888_MODES,-1,-1,WJ8888_VFO}, + RIG_FRNG_END, + }, +.tx_range_list2 = { RIG_FRNG_END, }, + +.tuning_steps = { + {WJ8888_MODES,10}, + RIG_TS_END, + }, + /* mode/filter list, remember: order matters! */ +.filters = { + {WJ8888_MODES, kHz(2)}, + {WJ8888_MODES, Hz(500)}, + {WJ8888_MODES, kHz(4)}, + {WJ8888_MODES, kHz(8)}, + /* option (in spare, to be fixed) */ + {WJ8888_MODES, Hz(200)}, + {WJ8888_MODES, kHz(1)}, + {WJ8888_MODES, kHz(3)}, + {WJ8888_MODES, kHz(6)}, + {WJ8888_MODES, kHz(12)}, + {WJ8888_MODES, kHz(16)}, + RIG_FLT_END, + }, + +.rig_init = wj_init, +.rig_cleanup = wj_cleanup, +.set_conf = wj_set_conf, +.get_conf = wj_get_conf, + +.set_freq = wj_set_freq, +.get_freq = wj_get_freq, +.set_mode = wj_set_mode, +.get_mode = wj_get_mode, +.set_level = wj_set_level, +.get_level = wj_get_level, + +}; + +/* + * Function definitions below + */ +