Merge 3.16 into 7.0

This commit is contained in:
Andrew Johnson
2018-07-14 18:29:33 -05:00
9 changed files with 205 additions and 31 deletions
+14 -7
View File
@@ -784,11 +784,16 @@ static void connectionCallback(struct connection_handler_args arg)
if (pca->gotFirstConnection) {
if (pca->nelements != ca_element_count(arg.chid) ||
pca->dbrType != ca_field_type(arg.chid)) {
/* BUG: We have no way to clear any old subscription with the
* originally chosen data type/size. That will continue
* to send us data and will result in an assert() fail.
*/
/* Let next dbCaGetLink and/or dbCaPutLink determine options */
/* Size or type changed, clear everything and let the next call
to dbCaGetLink() and/or dbCaPutLink() reset everything */
if (pca->evidNative) {
ca_clear_event(pca->evidNative);
pca->evidNative = 0;
}
if (pca->evidString) {
ca_clear_event(pca->evidString);
pca->evidString = 0;
}
plink->value.pv_link.pvlMask &=
~(pvlOptInpNative | pvlOptInpString |
pvlOptOutNative | pvlOptOutString);
@@ -1149,7 +1154,8 @@ static void dbCaTask(void *arg)
status = ca_add_array_event(
dbf_type_to_DBR_TIME(ca_field_type(pca->chid)),
0, /* dynamic size */
pca->chid, eventCallback, pca, 0.0, 0.0, 0.0, 0);
pca->chid, eventCallback, pca, 0.0, 0.0, 0.0,
&pca->evidNative);
if (status != ECA_NORMAL) {
errlogPrintf("dbCaTask ca_add_array_event %s\n",
ca_message(status));
@@ -1161,7 +1167,8 @@ static void dbCaTask(void *arg)
pca->pgetString = dbCalloc(1, MAX_STRING_SIZE);
epicsMutexUnlock(pca->lock);
status = ca_add_array_event(DBR_TIME_STRING, 1,
pca->chid, eventCallback, pca, 0.0, 0.0, 0.0, 0);
pca->chid, eventCallback, pca, 0.0, 0.0, 0.0,
&pca->evidString);
if (status != ECA_NORMAL) {
errlogPrintf("dbCaTask ca_add_array_event %s\n",
ca_message(status));
+2
View File
@@ -80,6 +80,8 @@ typedef struct caLink
char *pgetString;
void *pputNative;
char *pputString;
evid evidNative;
evid evidString;
char gotInNative;
char gotInString;
char gotOutNative;
+26 -18
View File
@@ -42,12 +42,13 @@
#include "special.h"
#define MAXLINE 80
#define MAXMESS 128
struct msgBuff { /* line output structure */
char out_buff[MAXLINE + 1];
char *pNext;
char *pLast;
char *pNexTab;
char message[128];
char message[MAXMESS];
};
typedef struct msgBuff TAB_BUFFER;
@@ -963,7 +964,7 @@ static void printBuffer(
int chunk = (len > MAXLINE - 5) ? MAXLINE - 5 : len;
sprintf(pmsg, "\"%.*s\"", chunk, (char *)pbuffer + i);
len -= chunk;
len -= chunk; i += chunk;
if (len > 0)
strcat(pmsg, " +");
dbpr_msgOut(pMsgBuff, tab_size);
@@ -1129,7 +1130,7 @@ static int dbpr_report(
case DBF_DEVICE:
status = dbFindField(pdbentry,pfield_name);
pfield_value = dbGetString(pdbentry);
sprintf(pmsg, "%s: %s", pfield_name,
sprintf(pmsg, "%-4s: %s", pfield_name,
(pfield_value ? pfield_value : "<nil>"));
dbpr_msgOut(pMsgBuff, tab_size);
break;
@@ -1139,19 +1140,18 @@ static int dbpr_report(
case DBF_FWDLINK: {
DBLINK *plink = (DBLINK *)pfield;
int ind;
const char *type = "LINK";
status = dbFindField(pdbentry,pfield_name);
for (ind=0; ind<LINK_NTYPES; ind++) {
if (pamaplinkType[ind].value == plink->type)
break;
}
if (ind>=LINK_NTYPES) {
sprintf(pmsg,"%s: Illegal Link Type", pfield_name);
}
else {
sprintf(pmsg,"%s:%s %s", pfield_name,
pamaplinkType[ind].strvalue,dbGetString(pdbentry));
}
if (!plink->text)
for (ind=0; ind<LINK_NTYPES; ind++) {
if (pamaplinkType[ind].value == plink->type) {
type = pamaplinkType[ind].strvalue;
break;
}
}
epicsSnprintf(pmsg, MAXMESS, "%-4s: %s %s", pfield_name,
type, dbGetString(pdbentry));
dbpr_msgOut(pMsgBuff, tab_size);
}
break;
@@ -1162,13 +1162,21 @@ static int dbpr_report(
char time_buf[40];
epicsTimeToStrftime(time_buf, 40, "%Y-%m-%d %H:%M:%S.%09f",
&paddr->precord->time);
sprintf(pmsg, "%s: %s", pfield_name, time_buf);
sprintf(pmsg, "%-4s: %s", pfield_name, time_buf);
dbpr_msgOut(pMsgBuff, tab_size);
}
else if (pdbFldDes->size == sizeof(void *) &&
strchr(pdbFldDes->extra, '*')) {
/* Special for pointers, needed on little-endian CPUs */
sprintf(pmsg, "%s: %p", pfield_name, *(void **)pfield);
/* Special for pointers */
sprintf(pmsg, "%-4s: PTR %p", pfield_name, *(void **)pfield);
dbpr_msgOut(pMsgBuff, tab_size);
}
else if (pdbFldDes->size == sizeof(ELLLIST) &&
!strncmp(pdbFldDes->extra, "ELLLIST", 7)) {
/* Special for linked lists */
ELLLIST *plist = (ELLLIST *)pfield;
sprintf(pmsg, "%-4s: ELL %d [%p .. %p]", pfield_name,
ellCount(plist), ellFirst(plist), ellLast(plist));
dbpr_msgOut(pMsgBuff, tab_size);
}
else { /* just print field as hex bytes */
@@ -1184,7 +1192,7 @@ static int dbpr_report(
value = (unsigned int)*pchar;
sprintf(ptemp_buf, "%02x ", value);
}
sprintf(pmsg, "%s: %s", pfield_name,temp_buf);
sprintf(pmsg, "%-4s: %s", pfield_name,temp_buf);
dbpr_msgOut(pMsgBuff, tab_size);
}
break;
+2
View File
@@ -35,4 +35,6 @@ PERL_SCRIPTS += dbExpand.pl
PERL_SCRIPTS += dbdToHtml.pl
PERL_SCRIPTS += registerRecordDeviceDriver.pl
HTMLS += dbdToHtml.html
include $(TOP)/configure/RULES
+140 -5
View File
@@ -44,17 +44,67 @@ BEGIN {
}
}
my $tool = 'dbdToHtml';
use Pod::Usage;
our ($opt_D, @opt_I, $opt_o);
getopts('DI@o:') or
die "Usage: $tool [-D] [-I dir] [-o file.html] file.dbd.pod\n";
=head1 NAME
dbdToHtml.pl - Convert DBD file with POD to HTML
=head1 SYNOPSIS
B<dbdToHtml.pl> [B<-h>] [B<-D>] [B<-I> dir] [B<-o> file] file.dbd.pod
=head1 DESCRIPTION
Generates HTML documentation from a B<.dbd.pod> file.
=head1 OPTIONS
B<dbdToHtml.pl> understands the following options:
=over 4
=item B<-h>
Help, display usage information.
=item B<-H>
Conversion help, display information about converting reference documentation
from the EPICS Wiki into a B<.dbd.pod> file for use with this tool.
=item B<-D>
Instead of creating the output file as described, read the input file(s) and
print a B<Makefile> dependency rule for the output file(s) to stdout.
=item B<-o> file
Name of the output file to be created.
=back
If no output filename is set, the file created will be named after the input
file, removing any directory components in the path and replacing any
B<.dbd.pod> file extension with B<.html>.
=cut
our ($opt_h, $opt_H, $opt_D, @opt_I, $opt_o);
my $tool = 'dbdToHtml.pl';
getopts('hHDI@o:') or
pod2usage(2);
pod2usage(-verbose => 2) if $opt_H;
pod2usage(1) if $opt_h;
pod2usage("$tool: No input file given.\n") if @ARGV != 1;
my $dbd = DBD->new();
my $infile = shift @ARGV;
$infile =~ m/\.dbd.pod$/ or
die "$tool: Input file '$infile' must have '.dbd.pod' extension\n";
pod2usage("$tool: Input file '$infile' must have '.dbd.pod' extension.\n");
ParseDBD($dbd, Readfile($infile, 0, \@opt_I));
@@ -245,3 +295,88 @@ sub DBD::Recfield::writable {
if $special eq "SPC_DBADDR";
return $fld->dbf_type eq "DBF_NOACCESS" ? 'No' : 'Yes';
}
=pod
=head1 Converting Wiki Record Reference to POD
If you open the src/std/rec/aiRecord.dbd.pod file in your favourite plain text
editor you'll see what input was required to generate the aiRecord.html file.
The text markup language we're using is a standard called POD (Plain Old
Documentation) which is used by Perl developers, but you don't need to know Perl
at all to be able to use it.
When we add POD markup to a record type, we rename its *Record.dbd file to
.dbd.pod in the src/std/rec directory; no other changes are needed for the build
system to find it by its new name. The POD content is effectively just a new
kind of comment that appears in .dbd.pod files, which the formatter knows how to
convert into HTML. The build also generates a plain *Record.dbd file from this
same input file by stripping out all of the POD markup.
Documentation for Perl's POD markup standard can be found online at
L<https://perldoc.perl.org/perlpod.html> or you may be able to type 'perldoc
perlpod' into a Linux command-line to see the same text. We added a few POD
keywords of our own to handle the table generation, and I'll cover those briefly
below.
POD text can appear almost anywhere in a dbd.pod file. It always starts with a
line "=[keyword] [additional text...]" where [keyword] is "title", "head1"
through "head4" etc.. The POD text ends with a line "=cut". There must be a
blank line above every POD line, and in many cases below it as well.
The POD keywords we have added are "title", "recordtype", "menu", "fields",
"type", "read" and "write". The last 3 are less common but are used in some of
the other record types such as the waveform and aSub records.
The most interesting of our new keywords is "fields", which takes a list of
record field names on the same line after the keyword and generates an HTML
Table describing those fields based on the field description found in the DBD
parts. In the ai documentation the first such table covers the DTYP and INP
fields, so the line
=fields DTYP, INP
generates all this in the output:
<blockquote><table border="1">
<tr>
<th>Field</th><th>Summary</th><th>Type</th><th>DCT</th>
<th>Default</th><th>Read</th><th>Write</th><th>CA PP</th>
</tr>
<tr>
<td class="cell">DTYP</td><td class="cell">Device Type</td>
<td class="cell">DEVICE</td>
<td class="cell">Yes</td>
<td class="cell">&nbsp;</td>
<td class="cell">Yes</td>
<td class="cell">Yes</td>
<td class="cell">No</td>
</tr>
<tr>
<td class="cell">INP</td>
<td class="cell">Input Specification</td>
<td class="cell">INLINK</td>
<td class="cell">Yes</td>
<td class="cell">&nbsp;</td>
<td class="cell">Yes</td>
<td class="cell">Yes</td>
<td class="cell">No</td>
</tr>
</table></blockquote>
Note that the "=fields" line must appear inside the DBD's declaration of the
record type, i.e. after the line
recordtype(ai) {
The "type", "read" and "write" POD keywords are used inside an individual record
field declaration and provide information for the "Type", "Read" and "Write"
columns of the field's table output for fields where this information is
normally supplied by the record support code. Usage examples for these keywords
can be found in the aai and aSub record types.
If you look at the L<aoRecord.dbd.pod> file you'll see that the POD there starts
by documenting a record-specific menu definition. The "menu" keyword generates a
table that lists all the choices found in the named menu.
=cut