Although not directly related to this thread, an issue I've encountered when attempting to write StreamDevice support for devices with "esoteric" command/reply formats is the inability to provide a custom conversion routine as provided by devGpib.
I went digging through my (very) old e-mail messages and recovered this one proposing an addition to StreamDevice that would allow for user-supplied conversion code. It's still not quite as general a solution as that provided by the devGpib GPIBCVTIO support but it does allow for message format conversions beyond those provided by StreamDevice.
Perhaps others might find this useful enough that it could be made part of the StreamDevice distribution.
===============================================================================
New format string modifier <function_name>. For example,
%<function_name>ld
%<function_name>f
%<function_name>lf
Where function_name is the name of a conversion function with prototype:
int func (char *msgBuf, int msgLen, dbCommon *record, format_t *format, void *value);
Arguments:
msgBuf - Pointer to next character to be consumed or stored.
msgLen - Remaining characters in input message or space in output buffer.
record - EPICS record being read/written.
format - Pointer to streams format structure.
value - Pointer to value to be converted.
Return Value:
Number of bytes consumed/produced by the conversion function.
-1 on error (I/O mismatch, not enough space in output buffer, etc.)
===============================================================================
Here's an example function to perform a conversion not possible by any existing
streams conversion format character. This is for a video multiplexor with a
particularly horrible command set.
/*
* Custom conversion routine
* Handle messages of the form:
* ....SL0O#T( )
* ....SL0O#T( # )
*/
static int
autoPatchConversion (char *msgBuf, int msgLen, dbCommon *record, format_t *format, void *value)
{
int len;
int match;
int chan;
long ltmp;
char *cp;
if ((format->type != DBF_LONG)
|| (format->conversion != 'd'))
return -1;
/*
* Find the last 'S' in the message
*/
cp = msgBuf + msgLen;
for (;;) {
if (cp == msgBuf)
return -1;
if (*--cp == 'S')
break;
}
/*
* Parse the message
*/
if (((match = sscanf(cp,"SL0O%dT( %ld )%n", &chan, <mp, &len)) == 2)
|| ((match = sscanf(cp,"SL0O%dT( )%n", &chan, &len)) == 1)) {
/* Could put check here that 'chan' matches record */
*(long *)value = (match == 2) ? ltmp : 0;
return len + (cp - msgBuf);
}
return -1;
}
/* Called by registerRecordDeviceDriver */
void autoPatchRegistrar (void)
{
streamFormatCalloutAdd("autoPatch", autoPatchConversion)
}
===============================================================================
Here are the changes I made to implement this. As you can see, they're pretty
small but I think they do most of the job.
diff -ubrN orig/streamDeviceApp/src/devStream.c
libStream/streamDevice/src/devStream.c
--- orig/streamDeviceApp/src/devStream.c 2003-01-31
04:23:40.000000000 -0600
+++ libStream/streamDevice/src/devStream.c 2003-02-14
15:34:54.000000000 -0600
@@ -554,6 +554,13 @@
unsigned char bcd1, bcd10;
int status;
+ if (format->flags & FORMAT_FLAG_CALLOUT) {
+ StreamFormatCallout callout;
+ memcpy(&callout, format->callout, sizeof callout);
+ len = (*callout)(source, stream->length-stream->processed,
record, format, value);
+ }
+ else
+ {
switch (format->conversion)
{
case 'd':
@@ -782,6 +789,7 @@
stream->status = SOFT_ALARM;
return ERROR;
}
+ }
if (len < 0)
{
stream->status = CALC_ALARM;
diff -ubrN orig/streamDeviceApp/src/devStreamFormatCalloutRegistry.c
libStream/streamDevice/src/devStreamFormatCalloutRegistry.c
--- orig/streamDeviceApp/src/devStreamFormatCalloutRegistry.c 1969-12-31 18:00:00.000000000 -0600
+++ libStream/streamDevice/src/devStreamFormatCalloutRegistry.c 2003-02-14 14:44:33.000000000 -0600
@@ -0,0 +1,18 @@
+#include <registry.h>
+#include "devStreamProtocol.h"
+
+static const char *streamFormatCalloutRegistry =
"streamFormatCalloutRegistry";
+static void *registryID = (void *)&streamFormatCalloutRegistry;
+
+int
+streamFormatCalloutAdd(const char *name, StreamFormatCallout callout)
+{
+ return registryAdd(registryID, name, (void *)callout);
+}
+
+StreamFormatCallout
+streamFormatCalloutFind(const char *name)
+{
+ return (StreamFormatCallout)registryFind(registryID, name);
+}
+
diff -ubrN orig/streamDeviceApp/src/devStreamProtocol.c
libStream/streamDevice/src/devStreamProtocol.c
--- orig/streamDeviceApp/src/devStreamProtocol.c 2003-01-31 02:50:31.000000000 -0600
+++ libStream/streamDevice/src/devStreamProtocol.c 2003-02-14 14:41:49.000000000 -0600
@@ -628,6 +628,22 @@
case '*':
format->flags |= FORMAT_FLAG_SKIP;
break;
+ case '<':
+ {
+ StreamFormatCallout callout;
+ char *functionName = ++ptr;
+ ptr = strchr(ptr, '>');
+ if (ptr == NULL)
+ return ERROR;
+ *ptr = '\0';
+ callout = (int(*)())streamFormatCalloutFind(functionName);
+ memcpy(format->callout, &callout, sizeof callout);
+ *ptr = '>';
+ if (format->callout == NULL)
+ return ERROR;
+ format->flags |= FORMAT_FLAG_CALLOUT;
+ }
+ break;
default:
loop = 0;
}
@@ -639,7 +655,8 @@
/* optional precision */
if (*ptr == '.')
{
- size = strtol(++ptr, &ptr, 10);
+ ptr++;
+ size = strtol(ptr, &ptr, 10);
if (size >= 128) return ERROR;
format->prec = size;
}
diff -ubrN orig/streamDeviceApp/src/devStreamProtocol.h
libStream/streamDevice/src/devStreamProtocol.h
--- orig/streamDeviceApp/src/devStreamProtocol.h 2003-01-29 10:29:22.000000000 -0600
+++ libStream/streamDevice/src/devStreamProtocol.h 2003-02-14 15:33:27.000000000 -0600
@@ -29,6 +29,7 @@
#define FORMAT_FLAG_ALT (0x08)
#define FORMAT_FLAG_ZERO (0x10)
#define FORMAT_FLAG_SKIP (0x20)
+#define FORMAT_FLAG_CALLOUT (0x40)
typedef struct {
unsigned short bufferSize;
@@ -50,9 +51,15 @@
char flags;
signed char prec;
unsigned char width;
+ char callout[sizeof(int(*)())];
char string [1];
} format_t;
+struct dbCommon;
+typedef int (*StreamFormatCallout)(char *msgBuf, int msgLen, struct dbCommon *record, format_t *format, void *value);
+int streamFormatCalloutAdd(const char *name, StreamFormatCallout);
+StreamFormatCallout streamFormatCalloutFind(const char *name);
+
/*****************************************
* parseProtocol
*
On Nov 8, 2012, at 5:50 AM, Dirk Zimoch <[email protected]> wrote:
> …….
> Yes.
>
> The problem is writeMsgString(gpibDpvt *pgpibDpvt,const char *str) from devGpib/devSupportGpib.c which does not have any length parameter.
>
> The lower level asynOctet function write() as well as all implementations I have seen have (and use) a length parameter. StreamDevice uses this function and passes the correct length.
>
> Do not use devGpib for any new project!
>
--
Eric Norum
[email protected]
- Replies:
- Re: Problems sending \x0 with devGpib driver Dirk Zimoch
- References:
- Problems sending \x0 with devGpib driver Andrew Wagner
- Re: Problems sending \x0 with devGpib driver Eric Norum
- Re: Problems sending \x0 with devGpib driver Andrew Wagner
- Re: Problems sending \x0 with devGpib driver Eric Norum
- Re: Problems sending \x0 with devGpib driver Dirk Zimoch
- Navigate by Date:
- Prev:
EPICS Position Available careers
- Next:
compile EPICS base on Mac OS (Snow Leopard) using GCC from macport Shen, Guobao
- Index:
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
<2012>
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
Re: Problems sending \x0 with devGpib driver Dirk Zimoch
- Next:
Re: Problems sending \x0 with devGpib driver Dirk Zimoch
- Index:
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
<2012>
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
|