installed spectrum record
This commit is contained in:
@@ -33,6 +33,7 @@ include "stringoutRecord.dbd"
|
||||
include "subRecord.dbd"
|
||||
include "subArrayRecord.dbd"
|
||||
include "waveformRecord.dbd"
|
||||
include "spectrumRecord.dbd"
|
||||
|
||||
# "Soft Channel", "Raw Soft Channel", and "Async Soft Channel" device support
|
||||
include "devSoft.dbd"
|
||||
|
||||
@@ -46,6 +46,7 @@ DBDINC += stringoutRecord
|
||||
DBDINC += subRecord
|
||||
DBDINC += subArrayRecord
|
||||
DBDINC += waveformRecord
|
||||
DBDINC += spectrumRecord
|
||||
|
||||
LIBSRCS += aaiRecord.c
|
||||
LIBSRCS += aaoRecord.c
|
||||
@@ -79,6 +80,7 @@ LIBSRCS += stringoutRecord.c
|
||||
LIBSRCS += subRecord.c
|
||||
LIBSRCS += subArrayRecord.c
|
||||
LIBSRCS += waveformRecord.c
|
||||
LIBSRCS += spectrumRecord.c
|
||||
|
||||
LIBRARY_IOC += recIoc
|
||||
|
||||
|
||||
437
src/rec/spectrumRecord.cpp
Normal file
437
src/rec/spectrumRecord.cpp
Normal file
@@ -0,0 +1,437 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* Subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* base/src/rec $Id$ */
|
||||
|
||||
/*
|
||||
* spectrum analyzer record support routines
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
* Ancestry: Based on the waveform record by Bob Dalesio and Marty Kraimer
|
||||
* Date: 9-29-03
|
||||
*/
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <complex>
|
||||
#include <iostream>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "epicsPrint.h"
|
||||
#include "alarm.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbEvent.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "dbScan.h"
|
||||
#include "devSup.h"
|
||||
#include "errMdef.h"
|
||||
#include "recSup.h"
|
||||
#include "recGbl.h"
|
||||
#include "special.h"
|
||||
#include "epicsDSP.h"
|
||||
|
||||
typedef double fft_t;
|
||||
|
||||
#define GEN_SIZE_OFFSET
|
||||
#include "spectrumRecord.h"
|
||||
#undef GEN_SIZE_OFFSET
|
||||
|
||||
static const fft_t one = 1.0;
|
||||
static const fft_t four = 4.0;
|
||||
static const fft_t PI = four * atan ( one );
|
||||
|
||||
static void changeFrequencies ( struct spectrumRecord * pwf )
|
||||
{
|
||||
unsigned long L = 1ul << pwf->logl;
|
||||
|
||||
// freq change is unsuccessful if improper input parameters
|
||||
if ( pwf->hfrq <= pwf->lfrq ) {
|
||||
pwf->frok = 0;
|
||||
return;
|
||||
}
|
||||
if ( pwf->hfrq > pwf->ifrq / 2.0 ) {
|
||||
pwf->frok = 0;
|
||||
return;
|
||||
}
|
||||
if ( pwf->ifrq <= 0.0 ) {
|
||||
pwf->frok = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! ( pwf->g && pwf->h && pwf->ival &&
|
||||
pwf->mag && pwf->ang && pwf->hamw ) ) {
|
||||
pwf->frok = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const fft_t phi0d2 = ( PI / 2.0 / pwf->nelm ) *
|
||||
( pwf->hfrq - pwf->lfrq ) / pwf->ifrq ;
|
||||
for ( unsigned n = 0; n < pwf->nelm; n++ )
|
||||
{
|
||||
const fft_t nd = n;
|
||||
const fft_t radians = nd * nd * phi0d2;
|
||||
pwf->h[n] = std::polar ( one, radians );
|
||||
}
|
||||
for ( unsigned n = pwf->nelm; n < L-pwf->nin; n++ )
|
||||
{
|
||||
pwf->h[n] = std::complex < fft_t > ( 0.0, 0.0 );
|
||||
}
|
||||
for ( unsigned n = L-pwf->nin; n < L; n++ )
|
||||
{
|
||||
const fft_t index = L - n;
|
||||
const fft_t radians = index * index * phi0d2;
|
||||
pwf->h[n] = std::polar ( one, radians );
|
||||
}
|
||||
epicsOneDimFFT ( pwf->h, pwf->logl, false );
|
||||
pwf->frok = true;
|
||||
}
|
||||
|
||||
static void changeResolution ( struct spectrumRecord * pwf )
|
||||
{
|
||||
{
|
||||
long nElemInTmp;
|
||||
long status = dbGetNelements (
|
||||
& pwf->inpw, & nElemInTmp );
|
||||
if ( status ) {
|
||||
pwf->nin = 1;
|
||||
}
|
||||
else {
|
||||
if ( nElemInTmp < 1 ) {
|
||||
pwf->nin = 1;
|
||||
}
|
||||
else {
|
||||
pwf->nin = static_cast < unsigned long >
|
||||
( nElemInTmp );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( pwf->nelm <= 0 )
|
||||
pwf->nelm = 1;
|
||||
|
||||
{
|
||||
double tot = pwf->nin + pwf->nelm;
|
||||
double dblL = 1.0 + log ( tot ) / log ( 2.0 );
|
||||
pwf->logl = static_cast < unsigned long > ( dblL + 0.5 );
|
||||
}
|
||||
|
||||
unsigned long L = 1ul << pwf->logl;
|
||||
assert ( L >= pwf->nin + pwf->nelm );
|
||||
delete pwf->g;
|
||||
delete pwf->h;
|
||||
delete pwf->ival;
|
||||
delete pwf->hamw;
|
||||
delete pwf->mag;
|
||||
delete pwf->ang;
|
||||
try {
|
||||
pwf->g = new std::complex < fft_t > [L];
|
||||
pwf->h = new std::complex < fft_t > [L];
|
||||
pwf->ival = new fft_t [pwf->nin];
|
||||
pwf->hamw = new fft_t [pwf->nin];
|
||||
pwf->mag = new fft_t [pwf->nelm];
|
||||
pwf->ang = new fft_t [pwf->nelm];
|
||||
// initialize hamming window
|
||||
// see Oppenhiem and Schafer figure 5.33
|
||||
for ( unsigned long n = 0; n < pwf->nin; n++ )
|
||||
{
|
||||
pwf->hamw[n] = 0.54 - 0.46 *
|
||||
cos ( 2 * PI * n / ( pwf->nin - 1 ) );
|
||||
}
|
||||
}
|
||||
catch (... ) {
|
||||
recGblSetSevr ( pwf, CALC_ALARM, INVALID_ALARM );
|
||||
pwf->frok = false;
|
||||
return;
|
||||
}
|
||||
changeFrequencies ( pwf );
|
||||
}
|
||||
|
||||
static long init_record ( struct spectrumRecord * pwf, int pass )
|
||||
{
|
||||
if ( pass == 1 ) {
|
||||
changeResolution ( pwf );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long special ( struct dbAddr * paddr, int after )
|
||||
{
|
||||
struct spectrumRecord * pwf =
|
||||
reinterpret_cast < struct spectrumRecord * > ( paddr->precord );
|
||||
long status = 0;
|
||||
if ( after ) {
|
||||
switch ( paddr->special ) {
|
||||
case ( SPC_MOD ):
|
||||
if ( paddr->pfield == (void *) & pwf->nelm ||
|
||||
paddr->pfield == (void *) & pwf->inpw ) {
|
||||
changeResolution ( pwf );
|
||||
}
|
||||
else {
|
||||
changeFrequencies ( pwf );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
recGblDbaddrError ( S_db_badChoice, paddr, "spectrum: special" );
|
||||
status = S_db_badChoice;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static void monitor ( struct spectrumRecord *pwf )
|
||||
{
|
||||
unsigned short monitor_mask;
|
||||
|
||||
monitor_mask = recGblResetAlarms(pwf);
|
||||
monitor_mask |= ( DBE_LOG | DBE_VALUE );
|
||||
if ( monitor_mask ) {
|
||||
db_post_events ( pwf, pwf->mag, monitor_mask );
|
||||
db_post_events ( pwf, pwf->ang, monitor_mask );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static long process ( struct spectrumRecord * pwf )
|
||||
{
|
||||
if ( ! pwf->frok ) {
|
||||
recGblSetSevr ( pwf, CALC_ALARM, INVALID_ALARM );
|
||||
return 0;
|
||||
}
|
||||
long nRequest = static_cast < long > ( pwf->nin );
|
||||
long status = dbGetLink ( & pwf->inpw, DBR_DOUBLE,
|
||||
pwf->ival, 0, & nRequest );
|
||||
if ( status ) {
|
||||
recGblSetSevr ( pwf, CALC_ALARM, INVALID_ALARM );
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long nActual;
|
||||
if ( nRequest < 0 ) {
|
||||
recGblSetSevr ( pwf, CALC_ALARM, INVALID_ALARM );
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
nActual = static_cast < unsigned long > ( nRequest );
|
||||
}
|
||||
|
||||
//epicsTime begin = epicsTime::getCurrent();
|
||||
|
||||
const unsigned L = 1 << pwf->logl;
|
||||
|
||||
const fft_t phi0d2 = ( PI / 2.0 / pwf->nelm ) *
|
||||
( pwf->hfrq - pwf->lfrq ) / pwf->ifrq ;
|
||||
const fft_t theta0 = PI * pwf->lfrq / pwf->ifrq;
|
||||
|
||||
for ( unsigned long n = 0; n < nActual; n++ )
|
||||
{
|
||||
const fft_t nd = n;
|
||||
const fft_t psi = nd * theta0 +
|
||||
nd * nd * phi0d2;
|
||||
pwf->g[n] = pwf->ival[n] * pwf->hamw[n] *
|
||||
std::polar ( one, - psi );
|
||||
}
|
||||
for( unsigned long n = nActual ; n < L; n++ )
|
||||
{
|
||||
pwf->g[n] = 0.0;
|
||||
}
|
||||
|
||||
epicsOneDimFFT ( pwf->g, pwf->logl, false );
|
||||
|
||||
for( unsigned n = 0; n < L; n++ )
|
||||
{
|
||||
pwf->g[n] = pwf->g[n] * pwf->h[n];
|
||||
// epicsOneDimFFT does not scale
|
||||
pwf->g[n] /= L;
|
||||
}
|
||||
|
||||
epicsOneDimFFT ( pwf->g, pwf->logl, true );
|
||||
|
||||
for ( unsigned k = 0; k < pwf->nelm; k++ )
|
||||
{
|
||||
const fft_t kd = k;
|
||||
const fft_t psi = kd * kd * phi0d2;
|
||||
pwf->g[k] = pwf->g[k] * std::polar ( one, - psi );
|
||||
pwf->mag[k] = abs ( pwf->g[k] );
|
||||
pwf->ang[k] = arg ( pwf->g[k] );
|
||||
}
|
||||
|
||||
//epicsTime end = epicsTime::getCurrent();
|
||||
|
||||
//cout << "delay per spectrum point " <<
|
||||
// ((end - begin) / pwf->nelm ) * 1e6 << " uS " << endl;
|
||||
|
||||
//for ( unsigned i = 0; i < pwf->nelm; i++ ) {
|
||||
// cout << i << g[i] << endl;
|
||||
//}
|
||||
|
||||
pwf->udf = FALSE;
|
||||
recGblGetTimeStamp ( pwf) ;
|
||||
|
||||
monitor ( pwf );
|
||||
// process the forward scan link record
|
||||
recGblFwdLink ( pwf );
|
||||
|
||||
pwf->pact=FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long cvt_dbaddr( struct dbAddr * paddr )
|
||||
{
|
||||
struct spectrumRecord * pwf =
|
||||
reinterpret_cast < struct spectrumRecord * >
|
||||
( paddr->precord );
|
||||
|
||||
if ( paddr->pfield == (void *) & pwf->val ) {
|
||||
paddr->pfield = pwf->mag;
|
||||
paddr->no_elements = pwf->nelm;
|
||||
paddr->field_type = DBF_DOUBLE;
|
||||
paddr->field_size = 8;
|
||||
paddr->dbr_field_type = DBF_DOUBLE;
|
||||
}
|
||||
else if ( paddr->pfield == (void *) & pwf->mag ) {
|
||||
paddr->pfield = pwf->mag;
|
||||
paddr->no_elements = pwf->nelm;
|
||||
paddr->field_type = DBF_DOUBLE;
|
||||
paddr->field_size = 8;
|
||||
paddr->dbr_field_type = DBF_DOUBLE;
|
||||
}
|
||||
else if ( paddr->pfield == (void *) & pwf->ang ) {
|
||||
paddr->pfield = pwf->ang;
|
||||
paddr->no_elements = pwf->nelm;
|
||||
paddr->field_type = DBF_DOUBLE;
|
||||
paddr->field_size = 8;
|
||||
paddr->dbr_field_type = DBF_DOUBLE;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_array_info ( struct dbAddr * paddr, long * no_elements, long * offset )
|
||||
{
|
||||
struct spectrumRecord * pwf = ( struct spectrumRecord * ) paddr->precord;
|
||||
*no_elements = pwf->nelm;
|
||||
*offset = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long put_array_info ( struct dbAddr * paddr, long nNew )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long get_units ( struct dbAddr * paddr, char * units )
|
||||
{
|
||||
struct spectrumRecord * pwf = ( struct spectrumRecord * ) paddr->precord;
|
||||
strncpy ( units,pwf->egu, DB_UNITS_SIZE );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long get_precision ( struct dbAddr * paddr, long * precision )
|
||||
{
|
||||
struct spectrumRecord * pwf = ( struct spectrumRecord * ) paddr->precord;
|
||||
|
||||
if ( paddr->pfield == (void *) pwf->mag ) {
|
||||
*precision = pwf->prec;
|
||||
}
|
||||
else if ( paddr->pfield == (void *) pwf->ang ) {
|
||||
*precision = pwf->prec;
|
||||
}
|
||||
else {
|
||||
recGblGetPrec ( paddr, precision );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long get_graphic_double ( struct dbAddr * paddr, struct dbr_grDouble *pgd )
|
||||
{
|
||||
struct spectrumRecord * pwf = (struct spectrumRecord *) paddr->precord;
|
||||
if ( paddr->pfield == (void *) pwf->mag ) {
|
||||
pgd->upper_disp_limit = pwf->hopr;
|
||||
pgd->lower_disp_limit = pwf->lopr;
|
||||
}
|
||||
else if ( paddr->pfield == (void *) pwf->ang ) {
|
||||
pgd->upper_disp_limit = +PI;
|
||||
pgd->lower_disp_limit = -PI;
|
||||
}
|
||||
else if ( paddr->pfield == (void *) & pwf->hfrq ) {
|
||||
pgd->upper_disp_limit = pwf->ifrq / 2.0;
|
||||
pgd->lower_disp_limit = 0;
|
||||
}
|
||||
else if ( paddr->pfield == (void *) & pwf->lfrq ) {
|
||||
pgd->upper_disp_limit = pwf->ifrq / 2.0;
|
||||
pgd->lower_disp_limit = 0;
|
||||
}
|
||||
else {
|
||||
recGblGetGraphicDouble ( paddr, pgd ) ;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long get_control_double ( struct dbAddr * paddr, struct dbr_ctrlDouble * pcd )
|
||||
{
|
||||
struct spectrumRecord * pwf = ( struct spectrumRecord * ) paddr->precord;
|
||||
|
||||
if ( paddr->pfield == (void *) pwf->mag ) {
|
||||
pcd->upper_ctrl_limit = pwf->hopr;
|
||||
pcd->lower_ctrl_limit = pwf->lopr;
|
||||
}
|
||||
else if ( paddr->pfield == (void *) pwf->ang ) {
|
||||
pcd->upper_ctrl_limit = +PI;
|
||||
pcd->lower_ctrl_limit = -PI;
|
||||
}
|
||||
else if ( paddr->pfield == (void *) & pwf->hfrq ) {
|
||||
pcd->upper_ctrl_limit = pwf->ifrq / 2.0;
|
||||
pcd->lower_ctrl_limit = 0;
|
||||
}
|
||||
else if ( paddr->pfield == (void *) & pwf->lfrq ) {
|
||||
pcd->upper_ctrl_limit = pwf->ifrq / 2.0;
|
||||
pcd->lower_ctrl_limit = 0;
|
||||
}
|
||||
else {
|
||||
recGblGetControlDouble ( paddr, pcd );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
#define report NULL
|
||||
#define initialize NULL
|
||||
#define get_value NULL
|
||||
#define get_enum_str NULL
|
||||
#define get_enum_strs NULL
|
||||
#define put_enum_str NULL
|
||||
#define get_alarm_double NULL
|
||||
rset spectrumRSET={
|
||||
RSETNUMBER,
|
||||
(RECSUPFUN) report,
|
||||
(RECSUPFUN) initialize,
|
||||
(RECSUPFUN) init_record,
|
||||
(RECSUPFUN) process,
|
||||
(RECSUPFUN) special,
|
||||
(RECSUPFUN) get_value,
|
||||
(RECSUPFUN) cvt_dbaddr,
|
||||
(RECSUPFUN) get_array_info,
|
||||
(RECSUPFUN) put_array_info,
|
||||
(RECSUPFUN) get_units,
|
||||
(RECSUPFUN) get_precision,
|
||||
(RECSUPFUN) get_enum_str,
|
||||
(RECSUPFUN) get_enum_strs,
|
||||
(RECSUPFUN) put_enum_str,
|
||||
(RECSUPFUN) get_graphic_double,
|
||||
(RECSUPFUN) get_control_double,
|
||||
(RECSUPFUN) get_alarm_double
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
epicsExportAddress ( rset, spectrumRSET );
|
||||
}
|
||||
|
||||
|
||||
116
src/rec/spectrumRecord.dbd
Normal file
116
src/rec/spectrumRecord.dbd
Normal file
@@ -0,0 +1,116 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE Versions 3.13.7
|
||||
# and higher are distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
recordtype(spectrum) {
|
||||
include "dbCommon.dbd"
|
||||
field(VAL,DBF_DOUBLE) {
|
||||
prompt("Power Spectral Density")
|
||||
asl(ASL0)
|
||||
special(SPC_DBADDR)
|
||||
extra("fft_t * val")
|
||||
}
|
||||
field(MAG,DBF_NOACCESS) {
|
||||
prompt("Power Spectral Density Magnitude Pointer")
|
||||
special(SPC_DBADDR)
|
||||
extra("fft_t * mag")
|
||||
}
|
||||
field(ANG,DBF_NOACCESS) {
|
||||
prompt("Power Spectral Density Phase Pointer")
|
||||
special(SPC_DBADDR)
|
||||
extra("fft_t * ang")
|
||||
}
|
||||
field(IVAL,DBF_NOACCESS) {
|
||||
prompt("Input Array Pointer")
|
||||
special(SPC_NOMOD)
|
||||
extra("fft_t * ival")
|
||||
}
|
||||
field(hamw,DBF_NOACCESS) {
|
||||
prompt("Hamming window")
|
||||
special(SPC_NOMOD)
|
||||
extra("fft_t * hamw")
|
||||
}
|
||||
field(G,DBF_NOACCESS) {
|
||||
prompt("Complex Array Pointer")
|
||||
special(SPC_NOMOD)
|
||||
extra("std::complex < fft_t > * g")
|
||||
}
|
||||
field(H,DBF_NOACCESS) {
|
||||
prompt("Complex Array Pointer")
|
||||
special(SPC_NOMOD)
|
||||
extra("std::complex < fft_t > * h")
|
||||
}
|
||||
field(LFRQ,DBF_DOUBLE) {
|
||||
prompt("Lowest frequency of interest (Hz)")
|
||||
promptgroup(GUI_DISPLAY)
|
||||
interest(1)
|
||||
pp(TRUE)
|
||||
special(SPC_MOD)
|
||||
}
|
||||
field(HFRQ,DBF_DOUBLE) {
|
||||
prompt("Highest frequency of interest (Hz)")
|
||||
promptgroup(GUI_DISPLAY)
|
||||
interest(1)
|
||||
pp(TRUE)
|
||||
special(SPC_MOD)
|
||||
}
|
||||
field(IFRQ,DBF_DOUBLE) {
|
||||
prompt("Input INPW samples per second (Hz)")
|
||||
promptgroup(GUI_DISPLAY)
|
||||
interest(1)
|
||||
pp(TRUE)
|
||||
special(SPC_MOD)
|
||||
}
|
||||
field(PREC,DBF_SHORT) {
|
||||
prompt("Display Precision")
|
||||
promptgroup(GUI_DISPLAY)
|
||||
interest(1)
|
||||
}
|
||||
field(INPW,DBF_INLINK) {
|
||||
prompt("Input Specification")
|
||||
promptgroup(GUI_INPUTS)
|
||||
interest(1)
|
||||
special(SPC_MOD)
|
||||
}
|
||||
field(EGU,DBF_STRING) {
|
||||
prompt("Engineering Units Name")
|
||||
promptgroup(GUI_DISPLAY)
|
||||
interest(1)
|
||||
size(16)
|
||||
}
|
||||
field(HOPR,DBF_DOUBLE) {
|
||||
prompt("High Operating Range")
|
||||
promptgroup(GUI_DISPLAY)
|
||||
interest(1)
|
||||
}
|
||||
field(LOPR,DBF_DOUBLE) {
|
||||
prompt("Low Operating Range")
|
||||
promptgroup(GUI_DISPLAY)
|
||||
interest(1)
|
||||
}
|
||||
field(NELM,DBF_ULONG) {
|
||||
prompt("Number of Elements")
|
||||
promptgroup(GUI_WAVE)
|
||||
special(SPC_MOD)
|
||||
}
|
||||
field(NIN,DBF_ULONG) {
|
||||
prompt("Max number of Input Elements")
|
||||
promptgroup(GUI_WAVE)
|
||||
special(SPC_NOMOD)
|
||||
}
|
||||
field(LOGL,DBF_ULONG) {
|
||||
prompt("Log of Number of Computational Elements")
|
||||
promptgroup(GUI_WAVE)
|
||||
special(SPC_NOMOD)
|
||||
}
|
||||
field(FROK,DBF_USHORT) {
|
||||
prompt("Freq parameters are valid")
|
||||
promptgroup(GUI_WAVE)
|
||||
special(SPC_NOMOD)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user