[Hamlib-developer] VFO proposal for peer review. (Initial draft)
Library to control radio transceivers and receivers
Brought to you by:
n0nb
|
From: Dale E. E. <de...@w-...> - 2002-06-28 20:54:36
|
*******************
Hamlib Standard VFO
*******************
-----------------------------------------------------------------
Author: Dale E. Edmons, KD7ENI
Date: June 28, 2002
Rev: 0.1
Revision date: June 28, 2002
(C) Copyright 2002 by Dale E. Edmons. All rights reserved.
This document may be freely distributed with Hamlib. For other
uses contact the author at: de...@us...
Hamlib developers may modify this document at their discretion.
No permission from the author is required.
-----------------------------------------------------------------
Introduction:
So far Hamlib doesn't seem to have a standardized method of
using
the vfo_t. Almost anything will work as long as the backend is
paying attention and does the right thing. I've glanced at
*all*
the backends and the mainline code searching specifically
for instances of RIG_VFO.
Blah blah...:
(I recognize that much effort is being made to treat the vfo_t
in an appropriate manner. It's just 0400 local and I didn't
start out too well. Later revisions will sound a little more
pleasant. This is currently first draft with zero revisions.
FIXME: author tend to get long winded.)
My work with the TS-2000 (I call it the ts2k) has shown me how
the current structure needs improvement and restructuring.
Here are some examples of inconsistant uses of this type:
1) Some backends use RIG_VFO_VFO as a "target" whereas
some use RIG_VFO_CURR. (aor/aor.c, icom/icom.c,
kenwood/th.c
src/misc.c) (I am vague on these two so feel free
to correct me here and elsewhere.)
2) Some code uses vfo_t in a bitmask manner (rig.h,
tests/dumpcaps.c) while others use integer constants
in certain instances (rig.h, kylix/hamlib_rigapi.pas)
3) Most commonly, all that is used is some unique
constant
to differentiate between cases in a switch statement or
logical compare (==).
Example:
With a rig and/or software that has many possible "targets" it
is
difficult to tell what we're supposed to do in a function. My
rig
is quite simple to control. However, it is not always simple to
know what is being requested compared to the current status of
the
rig. For example, say the mmelter_set_freq() gets called as
follows:
retval = mmelter_set_freq(rig, RIG_VFO_CURR, 147330000);
The mmelter_set_freq() tries to do the right thing by calling
mmelter_get_vfo() and receives RIG_VFO_C. So, the right thing
to
do is obviously continue as if parameter 2 had been RIG_VFO_C
and change that freq to 147330000. Not trusting the comm link
we call:
retval = mmelter_get_freq(rig, RIG_VFO_CURR, &vfo_tmp);
and when we compare we find they don't match. This contrived
example is when some sort of scan mode is in effect. Yes, we
should check this and half a dozen other modes. The fact is,
that as we are currently using the vfo_t, each function must
perform its own checks. Even after mmelter_get_vfo() does its
checks and determines the proper state, and passes on what the
current vfo is, mmelter_set_freq() must check again, and the
mmelter_get_freq(), must check it yet again! You almost want
to start creating global status variables!
Blah blah...:
Even though this example is a bit contrived, it comes
from doing development on my rig while the rig is active!
Thus "contrived" is almost "simple". It gets worse when the
rig is right next to some Ham's armchair and he/she can just
reach right over and start twisting dials any time he/she
pleases (guilty).
So, obviously, I'm either long winded and like to
complain (I am a Ham) or I think I've got a solution I'd like
to impose on everbody (I am a Ham).
:)
Important stuff:
Here begins my proposal. Later revisions will begin around
here.
-------------------------------------------------------------
The following RIG_VFO types are rather generic and
somewhat undefined. First, we establish what each is used
for and how they are treated, and finally "when" they should
*not* be used. (All of this should be subjected to and
revised by the developers list.) (These are *as proposed*
not *as used*.)
RIG_VFO_CURR: This should be treated as an explicit request
to call rig_get_vfo() or mmelter_get_vfo() by any
function (except rig_get_vfo()) that receives it.
No function should ever output this value. It
may only be used for comparison or as a parameter
to rig_get_vfo().
RIG_VFO_VFO: This is similar to RIG_VFO_CURR except that
it eliminates special modes such as MEM, SCAN, and
anything else. Which ever *single* VFO may be
considered current will be the target. For example,
rig_set_vfo(rig, RIG_VFO_VFO) will be considered
an explicit request to turn off (or temporarily
disable) MEM, SCAN, SAT, etc... and act the same
as RIG_VFO_CURR after other potential targets are
ruled out. Functions should never output RIG_VFO_VFO.
RIG_VFO_ALL: This should never be used. It is ambiguous
at best. (See RIG_VFO_MASK, RIG_VFO_VALID, and
RIG_CTRL_MASK, for good uses of a similiar psuedo
target.)
RIG_VFO_NONE: I'm unfamiliar with a use or need for this.
Any feedback would be appreciated.
The previous #define's are already in use in Hamlib code.
If we decide to adopt the above usage, some code may require
minor change.
The following masks and definitions are new. Actual running
code is available (works for me) and seems to require few if
any modifications to compile (runtime may vary depending upon
which backend is used).
Definitions:
Rig Major: Upper segment [N:n+1] of an N-bit word
defined by the vfo_t type definiton. This
field currently has three used bits: Main,
Sub, MEM. These are consistant with the current
Hamlib code.
VFO minor: Lower segment [n:0] of an N-bit word
defined by the vfo_t type definition. This
contains the bits which specify the actual VFO.
Currently, bits 0:1 are reserved, and three
additional bits for VFO_A to VFO_C are used.
(I have good reason for reserving the first
two bits. They will be two bits which are
normally treated as a unit but may in many
instances be different. Thus treating them
as an integer may at times be desireable and
much much simpler if these two bits are kept
available.)
#define's:
RIG_SET_VFO(M,m): This macro sets the rig Major (M) and
the VFO minor bits in a vfo_t. It is intended only for
use within rig.h but other uses are allowed. Remember
that M is shifted n+1 times which could have undesirable
effects. This macro replaces RIG_CTRL_MODE(a,b) which
is made obsolete in this proposal. These two
definitions
are incompatible and cannot coexist. This macro is
required for this proposal.
RIG_MINOR: Sets the shift count for rig Major field.
RIG_VFO_TEST(v): This macro is expected to be used any
where a need to verify a valid vfo arises. It is the
only Logical macro defined in this proposal (programmers
are encouraged to create their own aside from this one
test). It simply verifies that (v) has the same mask
as RIG_VFO_VALID and is defined as:
( ((v) & ~(RIG_VFO_VALID)) == 0 )
Thus, you could perform the following error check:
if( RIG_VFO_TEST(vfo) )
return -RIG_EINVAL;
to guarantee that a received vfo_t contains valid bits.
This macro is expected to be available to Hamlib users
and Hamlib Developers alike.
RIG_VFO_VALID: This is defined as (RIG_CTRL_MASK |
RIG_VFO_MASK)
and is used for testing whether a valid value in
a vfo_t has been received. Any type of comparison
or mask may use this value. Functions should never
output this value. It tests both the rig Major and
VFO minor simultaneously (more on this later).
RIG_CTRL_MASK: This is the rig Major portion of the previous
mask. It has all zero bits in the VFO minor field.
It is used for comparison and masks but never output.
RIG_VFO_MASK: Same as previous two except is is only the
VFO minor portion of the mask. Also used only for
masks and comparison but never output.
RIG_VFOn: As in the existing code, these are the actual
VFO's availble as targets. However, these macros
are intended for use within rig.h and are not for
general use (though not specifically prohibited,
general use is highly discouraged). These are
strictly VFO minor portions of a vfo_t.
RIG_CTRL_MAIN: In dual transceivers (very common nowadays)
this refers to the primary transceiver. It is not
required that this transceiver has any special
characteristics only that is be distinguishable
from RIG_CTRL_SUB. They may in fact be identical
and simple be left or right etc.... This is strictly
a Rig Major portion of a vfo_t.
RIG_CTRL_SUB: This is the other transceiver. It may have
identical or completely unique features compared to
RIG_CTRL_MAIN. Generally, it may be considered to
match RIG_CTRL_MAIN in several respects. This is
strictly a Rig Major portion of a vfo_t.
RIG_CTRL_MEM: This also is a part of of the Rig
Major portion of a vfo_t. It is not as strict as
MAIN or SUB. This will be further developed at a
later date.
There are are a number of definitions which are standard
in Hamlib. These are constants which combine both the upper
and lower and fully specify a vfo_t:
RIG_VFO_A:
RIG_VFO_B: These two are (RIG_CTRL_MAIN | RIG_VFOn) where
n is 1 or 2.
RIG_VFO_C: Same same as previous except the definition is:
(RIG_CTRL_MAIN | RIG_VFOn). Also n is either
1 or 3. I prefer 3 but 1 "should" be okay.
RIG_VFO_MEM: Directly access the rigs memories if this is
available. If the main or sub receivers have their
own memory pointer (mine does) which may be accessed
(mine can) then ORing RIG_CTRL_MAIN will change this
from direct memory access to Main memory pointer.
If Main has more than one such pointer use the VFOn
to select which, otherwise no VFO minor is required
but not specifically disallowed if used in a con-
sistant manner (VFO1, then VFO2, etc...) An example
of multiple pointers would be regular memory, CALL
channel memory, temporary memory etc.... (I have
standard definitions I use and this will be discussed
at a later date and added to this document.)
RIG_VFO_CURR: Defined as RIG_VFO_VALID. This value is
not guaranteed to be RIG_VFO_VALID but is guaranteed
to be unique and distinguishable from other constants
and "actual" vfo's. Thus, it is not permitted to
use RIG_VFO_VALID instead.
RIG_VFO_NONE: If kept for regular use in hamlib this will
have the definition initial(~RIG_VFO_VALID). This
value
is subject to change.
RIG_VFO_VFO: This is to be defined as (RIG_VFO_MASK) to
be consistant with RIG_VFO_CURR. Likewise, this is
subject to change and using RIG_VFO_MASK to replace
this value is strictly forbidden. This value is
guaranteed to be unique. When testing valid, always
use RIG_VFO_TEST(). This way, changes will not
affect the program. Using RIG_VFO_VALID is only
correct for *real* VFO targets. It may become
necessary to use other bits above the rig Major
to specify this type of constant. This can easily
be incorporated into RIG_VFO_TEST but can never
be guaranteed to work with RIG_VFO_VALID. (As a
specific example: if we later define RIG_MAJOR to
be the last bit in the major a third field will
be available for other constants. RIG_VFO_VALID
is (RIG_CTRL_MASK | RIG_VFO_MASK) and will cause
these "reserved field" bits to be nulled. However,
RIG_VFO_TEST may be extended to include the third
or more new fields where RIG_VFO_VALID never can.)
RIG_VFO_MAIN: defined as RIG_CTRL_MAIN. These terms are
synonomous. RIG_VFO_MAIN is is less obvious. Use
RIG_CTRL_MAIN for new code.
RIG_VFO_SUB: same as RIG_VFO_MAIN except it is the sub
receiver.
This completes this initial draft. My primary concern now
is making this available quickly for peer review. Later
drafts will shorten the length (I hope) and add any changes
that are suggested.
I ask for two types of response: 1) quick initial reaction
and 2) specific detailed or well thought responses. Unless
otherwise noted (e.g. by Stephane) you may post responses
to the developers list. You may also e-mail me directly
with your response.
The following last item is my much revised exerpt from rig.h
which I wish to check into CVS. It is very recent (about
2+1/2 days old. Compare it with your own copy in:
include/hamlib/rig.h
and post any comments. (Thank you all in advance.)
(I've already noticed the difference in RIG_VFO_TEST(v),
please find more!)
start rig.h exerpt
-----------------------------------------------------------------
/*
* I've cleaned up the VFO definition to make it easier to change
* when the MoonMelter is finally released. Essentially, I've
* done nothing. --Dale :)
*/
/*
* Upper segment: "rig Major"
* Lower segment: "VFO minor"
*
* MSB LSB
* N n+1 n 0
* +-+-+-+-+-+-+-+-+-+-+-+
* | | |
* Rig VFO
* Major minor
*/
typedef unsigned int vfo_t;
#define BIT(a) ( ((vfo_t) 1) << (a))
//#define BIT(a) (1L << (a))
#define RIG_MINOR 4
/* M=Major, m=minor */
#define RIG_SET_VFO(M,m) ((vfo_t) ( ((M) << (RIG_MINOR+1)) | (m)
))
/* Note: prior definition exibited exponential growth in bit count */
#define RIG_VFO_RESERVED RIG_SET_VFO(0, BIT(0))
#define RIG_VFO_RESERVED2 RIG_SET_VFO(0, BIT(1))
/* VFO Minor */
#define RIG_VFO1 RIG_SET_VFO(0, BIT(2))
#define RIG_VFO2 RIG_SET_VFO(0, BIT(3))
#define RIG_VFO3 RIG_SET_VFO(0, BIT(4))
/* |
* RIG_MINOR = n :== MAX >-----------------'
*/
/* Rig Major */
#define RIG_CTRL_MAIN RIG_SET_VFO(BIT(0), 0)
#define RIG_CTRL_SUB RIG_SET_VFO(BIT(1), 0)
#define RIG_CTRL_MEM RIG_SET_VFO(BIT(2), 0)
/* Standard VFO's for common use */
#define RIG_VFO_A (RIG_CTRL_MAIN | RIG_VFO1)
#define RIG_VFO_B (RIG_CTRL_MAIN | RIG_VFO2)
#define RIG_VFO_C (RIG_CTRL_SUB | RIG_VFO1)
#define RIG_VFO_MEM RIG_CTRL_MEM
/* VFOC should be VFO3 because ambiguities may arise someday */
/* VFO stuff that may be handy. */
#define RIG_VFO_MASK (RIG_VFO1 | RIG_VFO2 | RIG_VFO3)
#define RIG_CTRL_MASK (RIG_CTRL_MAIN | RIG_CTRL_SUB | RIG_CTRL_MEM)
#define RIG_VFO_VALID (RIG_CTRL_MASK | RIG_VFO_MASK)
#define RIG_VFO_TEST(v) (((v) & RIG_VFO_VALID) != 0)
/* The following are for compatibility with existing code! */
#define RIG_VFO_NONE (~RIG_VFO_VALID)
#define RIG_VFO_CURR RIG_SET_VFO(0,0)
#define RIG_VFO_ALL RIG_VFO_MASK
#define RIG_VFO_MAIN RIG_CTRL_MAIN
#define RIG_VFO_SUB RIG_CTRL_SUB
#define RIG_VFO_VFO (RIG_VFO_VALID & ~RIG_VFO_MEM)
/*
* Ahhh. Now I can live happy and die free! --Dale
*/
----------------------------------------------------------
end rig.h exerpt
|