Compare commits

...

12 Commits

12 changed files with 369 additions and 140 deletions

1
.ci Submodule

Submodule .ci added at 93062ba941

12
.ci-local/defaults.set Normal file
View File

@ -0,0 +1,12 @@
MODULES=calc asyn
# EPICS Base
BASE_DIRNAME=base
BASE_REPONAME=epics-base
BASE_REPOOWNER=epics-base
BASE_VARNAME=EPICS_BASE
BASE_RECURSIVE=no
ASYN_REPOOWNER=epics-modules
CALC_REPOOWNER=epics-modules

164
.github/workflows/ci-scripts-build.yml vendored Normal file
View File

@ -0,0 +1,164 @@
# .github/workflows/ci-scripts-build.yml for use with EPICS Base ci-scripts
# (see: https://github.com/epics-base/ci-scripts)
# This is YAML - indentation levels are crucial
# Workflow name, shared by all branches
name: StreamDevice
# Trigger on pushes and PRs to any branch
on:
push:
paths-ignore:
- 'docs/*'
- '.gitattributes'
- '.gitignore'
- '**/*.html'
- '**/*.md'
pull_request:
paths-ignore:
- 'docs/*'
- '.gitattributes'
- '.gitignore'
- '**/*.html'
- '**/*.md'
env:
SETUP_PATH: .ci-local:.ci
EPICS_TEST_IMPRECISE_TIMING: YES
jobs:
native:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
# Set environment variables from matrix parameters
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
BASE: ${{ matrix.base }}
WINE: ${{ matrix.wine }}
RTEMS: ${{ matrix.rtems }}
RTEMS_TARGET: ${{ matrix.rtems_target }}
TEST: ${{ matrix.test }}
EXTRA: ${{ matrix.extra }}
VV: "1"
strategy:
fail-fast: false
matrix:
include:
- name: Native Linux (WError)
os: ubuntu-20.04
cmp: gcc
configuration: default
base: "7.0"
extra: "CMD_CPPFLAGS=-Werror"
pcre: apt
- name: Cross mingw64 DLL
os: ubuntu-20.04
cmp: gcc
configuration: default
base: "7.0"
wine: "64"
pcre: no
- name: Cross mingw64 static
os: ubuntu-20.04
cmp: gcc
configuration: static
base: "7.0"
wine: "64"
pcre: no
- name: RTEMS 4.10
os: ubuntu-20.04
cmp: gcc
configuration: default
base: "7.0"
rtems: "4.10"
rtems_target: RTEMS-pc386-qemu
pcre: no
- name: Native Linux with clang
os: ubuntu-20.04
cmp: clang
configuration: default
base: "7.0"
pcre: apt
- name: Native Linux with 3.15
os: ubuntu-20.04
cmp: gcc
configuration: default
base: "3.15"
pcre: apt
- name: Native Linux with 3.14
os: ubuntu-20.04
cmp: gcc
configuration: default
base: "3.14"
pcre: apt
- name: OSX
os: macos-latest
cmp: clang
configuration: default
base: "7.0"
pcre: no
- name: vs2019 DLL
os: windows-2019
cmp: vs2019
configuration: debug
base: "7.0"
pcre: no
extra: "CMD_CFLAGS=-analysis CMD_CXXFLAGS=-analysis"
- name: vs2019 static
os: windows-2019
cmp: vs2019
configuration: static-debug
base: "7.0"
pcre: no
extra: "CMD_CFLAGS=-analysis CMD_CXXFLAGS=-analysis"
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Automatic core dumper analysis
uses: mdavidsaver/ci-core-dumper@master
- name: "apt-get install"
run: |
sudo apt-get update
sudo apt-get -y install qemu-system-x86 g++-mingw-w64-x86-64 gdb
if: runner.os == 'Linux'
- name: Reset RELEASE
shell: bash
# 'make' on Mac doesn't understand "undefine PCRE"
# so replace the whole file
run: |
cat <<EOF > configure/RELEASE
-include \$(TOP)/../RELEASE.local
-include \$(TOP)/../RELEASE.\$(EPICS_HOST_ARCH).local
-include \$(TOP)/configure/RELEASE.local
EOF
- name: Prepare and compile dependencies
run: python .ci/cue.py prepare
- name: "apt-get install pcre"
if: matrix.pcre == 'apt'
shell: bash
run: |
sudo apt-get -y install libpcre3-dev
cat <<EOF >> configure/CONFIG_SITE.local
PCRE_INCLUDE=/usr/include
PCRE_LIB=/usr/lib
EOF
- name: Build main module
run: python .ci/cue.py build

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule ".ci"]
path = .ci
url = https://github.com/epics-base/ci-scripts.git

View File

@ -4,10 +4,6 @@ TOP=..
include $(TOP)/configure/CONFIG include $(TOP)/configure/CONFIG
# Set the following to NO to disable consistency checking of
# the support applications defined in $(TOP)/configure/RELEASE
CHECK_RELEASE = YES
TARGETS = $(CONFIG_TARGETS) TARGETS = $(CONFIG_TARGETS)
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))

View File

@ -594,6 +594,18 @@ In input, the next byte or bytes must match the checksum.
href="https://en.wikipedia.org/wiki/Longitudinal_redundancy_check">Wikipedia</a>.</dd> href="https://en.wikipedia.org/wiki/Longitudinal_redundancy_check">Wikipedia</a>.</dd>
<dt><code>%&lt;hexlrc&gt;</code></dt> <dt><code>%&lt;hexlrc&gt;</code></dt>
<dd>One byte. The LRC for the hex digits. (Other characters are ignored.)</dd> <dd>One byte. The LRC for the hex digits. (Other characters are ignored.)</dd>
<dt><code>%&lt;leybold&gt;</code></dt>
<dd>One byte. Used by some Leybold products. 255-bytesum%255 (+32 if result would be <32)</dd>
<dt><code>%&lt;brksCryo&gt;</code></dt>
<dd>One byte. Used by Brooks Cryopumps.</dd>
<dt><code>%&lt;CPI&gt;</code></dt>
<dd>One byte. Used by TRIUMF CPI RF amplifier.</dd>
<dt><code>%&lt;bitsum&gt;</code> or <code>%&lt;bitsum8&gt;</code></dt>
<dd>One byte. Number of 1 bits in all characters.</dd>
<dt><code>%&lt;bitsum16&gt;</code></dt>
<dd>Two bytes. Number of 1 bits in all characters.</dd>
<dt><code>%&lt;bitsum32&gt;</code></dt>
<dd>Four bytes. Number of 1 bits in all characters.</dd>
</dl> </dl>
<a name="regex"></a> <a name="regex"></a>

View File

@ -1,10 +1,22 @@
#/bin/sh #/bin/sh
if ! wkhtmltopdf -V >/dev/null 2>&1 wkhtmltopdf --enable-local-file-access -V >/dev/null 2>&1
then case $? in
127)
echo "wkhtmltopdf not installed." >&2 echo "wkhtmltopdf not installed." >&2
echo "See https://wkhtmltopdf.org" >&2 echo "See https://wkhtmltopdf.org" >&2
exit 1 exit 1
fi ;;
0)
# have (and need) --enable-local-file-access
ENABLE_FILE_ACCESS=--enable-local-file-access
;;
1)
# have no (and need no) --enable-local-file-access
;;
*)
# Some error but I don't know what it means. Try anyway.
;;
esac
PAGES=" PAGES="
index.html index.html
@ -43,5 +55,5 @@ osinterface.html
" "
rm -f stream.pdf rm -f stream.pdf
wkhtmltopdf --print-media-type --dpi 1200 --zoom 0.85 --page-size Letter \ wkhtmltopdf --print-media-type --page-size Letter \
$PAGES stream.pdf $ENABLE_FILE_ACCESS $PAGES stream.pdf

View File

@ -1,90 +1,104 @@
a:link {color: #0000D0;} a:link { color: #0000D0; }
a:visited {color: #0000D0;} a:visited { color: #0000D0; }
a:hover {color: #FF0000;} a:hover { color: #FF0000; }
body { body {
margin-right:1em; margin-right: 1em;
margin-left:15em; margin-left: 15em;
margin-top:75px; margin-top: 75px;
padding-top:1px; padding-top: 1px;
font-family: Helvetica, Arial, sans-serif; font-family: Helvetica, Arial, sans-serif;
font-size: 100%; font-size: 100%;
background-color:#ffffff; background-color: #ffffff;
} }
a[name] { position:relative; top:-11ex;} a[name] {
position: relative;
top: -11ex;
}
pre, tt, kbd, code {
font-size: 95%;
font-family: Mono, "Lucida Console", Courier, monospace;
}
pre { pre {
background-color:#f4f4f4; background-color: #f4f4f4;
padding:1ex; padding: 1ex;
border:1px solid #000000; border: 1px solid #000000;
white-space:pre; white-space: pre;
margin:2ex; margin: 2ex;
page-break-inside:avoid; page-break-inside: avoid;
font-size: 85%;
white-space: pre-wrap;
} }
kbd { kbd {
font-weight:bold; font-weight: bold;
}
code {
color: #008000;
} }
dt { dt {
margin-top:0.5ex; margin-top: 0.5ex;
} }
h1 { h1 {
font-size:250%; font-size: 250%;
margin-top:0; margin-top: 0;
font-style:italic; font-style: italic;
font-weight:bold; font-weight: bold;
font-family:"Times New Roman", serif; font-family: "Times New Roman", Times, serif;
text-align:center; text-align: center;
position:fixed; position: fixed;
top:0; top: 0;
left:0; left: 0;
width:100%; width: 100%;
line-height:190%; line-height: 190%;
background-color:white; background-color: white;
border-width:0; border-width: 0;
border-bottom:3px solid #1b4486; border-bottom: 3px solid #1b4486;
white-space:nowrap; white-space: nowrap;
background-image:url(PSI.png); background-image: url(PSI.png);
background-repeat:no-repeat; background-repeat: no-repeat;
background-position:10px 5px; background-position: 10px 5px;
text-shadow:.1em .1em .1em darkgray; text-shadow: .1em .1em .1em lightgray;
box-shadow:0 .3em .1em -.2em darkgray; box-shadow: 0 .3em .1em -.2em darkgray;
} }
h2 { h2 {
font-size:150%; font-size: 140%;
margin-bottom:0.5ex; margin-bottom: 0.5ex;
} }
h3 { h3 {
font-size:120%; font-size: 120%;
margin-bottom:0.25ex; margin-bottom: 0.25ex;
} }
h4 { h4 {
font-size:100%; font-size: 100%;
margin-bottom:0.25ex; margin-bottom: 0.25ex;
} }
h1, h2, h3, h4 { h1, h2, h3, h4 {
page-break-after:avoid; page-break-after: avoid;
} }
p { p {
margin-top:0.75ex; margin-top: 0.75ex;
margin-bottom:0.75ex; margin-bottom: 0.75ex;
} }
body h1 + p { body h1 + p {
margin-top:1.5ex; margin-top: 1.5ex;
margin-bottom:0.75ex; margin-bottom: 0.75ex;
} }
footer { footer {
font-size:75%; font-size: 75%;
margin-top: 1em; margin-top: 1em;
border-top: 1px solid darkgray; border-top: 1px solid darkgray;
padding-top: 1em; padding-top: 1em;
@ -97,44 +111,40 @@ footer a:only-of-type {
} }
small { small {
font-size:75%; font-size: 75%;
}
code {
font-size: 125%;
color: #008000;
} }
.indent { .indent {
text-indent:-4ex; text-indent: -4ex;
margin-left:4ex; margin-left: 4ex;
margin-top:0.5ex; margin-top: 0.5ex;
text-align:left; text-align: left;
} }
.box { .box {
margin-left:1ex; margin-left: 1ex;
margin-right:1ex; margin-right: 1ex;
margin-top:0.5ex; margin-top: 0.5ex;
padding: 0 1ex; padding: 0 1ex;
border: 1px solid black; border: thin solid black;
text-align:left; text-align: left;
background-color:#f0f0f0; background-color: #f0f0f0;
page-break-inside: avoid;
} }
#navleft { #navleft {
position:fixed; position: fixed;
left:0; left: 0;
top:0; top: 0;
padding-top:70px; padding-top: 70px;
width:14em; width: 14em;
height:100%; height: 100%;
border-style:solid; border-style: solid;
border-color:black; border-color: black;
border-width:0 1px 0 0; border-width: 0 1px 0 0;
background-color:#e3eaf6; background-color: #e3eaf6;
overflow:hidden; overflow: hidden;
z-index:0; z-index: 0;
} }
.new { .new {
@ -142,17 +152,18 @@ code {
} }
a[target=ex]:after { a[target=ex]:after {
content:" " url(ex.png); content: " " url(ex.png);
} }
a[target=ex]:hover:after { a[target=ex]:hover:after {
content: " " url(exr.png); content: " " url(exr.png);
} }
@media print { @media print {
a:link {text-decoration:none;} a:link { text-decoration: none; }
a[target=ex]:after {content:" [" attr(href) "]";} a[target=ex]:after { content:" [" attr(href) "]"; font-size: 75%; }
body {margin:0 4em;} body { margin: 0 4em; }
h1 {position:relative; background-position:0 0;} h1 { position: relative; background-position: 0 0; }
#navleft {display:none;} #navleft { display: none; }
footer { display: none; }
} }

View File

@ -293,9 +293,10 @@ record (stringout, "$(DEVICE):clean_2") {<br>
<a name="web"></a> <a name="web"></a>
<h2>I need to read a web page</h2> <h2>I need to read a web page</h2>
<p> <p>
First you have to send a correctly formatted HTML request. First you have to send a correctly formatted HTML header for a GET request.
Note that this request must contain the full URL like Note that this header must contain the full URL like
"http://server/page" and must be terminated with <u>two</u> newlines. "http://server/page" and must be terminated with <u>two</u>
CR LF sequences (<code>"\r\n\r\n"</code> or <code>CR LF CR LF</code>).
The server should be the same as in the The server should be the same as in the
<a href="setup.html#sta"><code>drvAsynIPPortConfigure</code></a> <a href="setup.html#sta"><code>drvAsynIPPortConfigure</code></a>
command (if not using a http proxy). command (if not using a http proxy).
@ -313,17 +314,18 @@ Read the title of a web page.
get_title {<br> get_title {<br>
&nbsp;&nbsp;extrainput = ignore;<br> &nbsp;&nbsp;extrainput = ignore;<br>
&nbsp;&nbsp;replyTimeout = 1000;<br> &nbsp;&nbsp;replyTimeout = 1000;<br>
&nbsp;&nbsp;out "GET http://\$1\n\n";<br> &nbsp;&nbsp;out "GET http://\$1\r\n\r\n";<br>
&nbsp;&nbsp;in "%+.1/(?im)&lt;title&gt(.*)&lt\/title&gt;/";<br> &nbsp;&nbsp;in "%+.1/(?im)&lt;title&gt(.*)&lt\/title&gt;/";<br>
} }
</code> </code>
</p> </p>
<p> <p>
Terminate the request with two newlines, either explicit like here Terminate the request with two carriage return + newlines, either explicit
<u>or</u> using an like here <u>or</u> using an
<a href="protocol.html#sysvar"><code>outTerminator</code></a>. <a href="protocol.html#sysvar"><code>outTerminator</code></a>.
The URI (without http:// but including the web server host name) The URI (without http:// but including the web server host name)
is passed as <a href="protocol.html#argvar">argument</a> 1 to <code>\$1</code>. is passed as <a href="protocol.html#argvar">argument</a> 1 to <code>\$1</code>
in this example.
Note that web servers may be slow, so allow some Note that web servers may be slow, so allow some
<a href="protocol.html#argvar"><code>replyTimeout</code></a>. <a href="protocol.html#argvar"><code>replyTimeout</code></a>.
</p> </p>
@ -390,7 +392,7 @@ Then we read the number.
get_title {<br> get_title {<br>
&nbsp;&nbsp;extrainput = ignore;<br> &nbsp;&nbsp;extrainput = ignore;<br>
&nbsp;&nbsp;replyTimeout = 1000;<br> &nbsp;&nbsp;replyTimeout = 1000;<br>
&nbsp;&nbsp;out "GET http://\$1\n\n";<br> &nbsp;&nbsp;out "GET http://\$1\r\n\r\n";<br>
&nbsp;&nbsp;in "%*/Interesting value:/%f more text";<br> &nbsp;&nbsp;in "%*/Interesting value:/%f more text";<br>
} }
</code> </code>

View File

@ -20,43 +20,57 @@
* along with StreamDevice. If not, see https://www.gnu.org/licenses/. * along with StreamDevice. If not, see https://www.gnu.org/licenses/.
*************************************************************************/ *************************************************************************/
#if defined(vxWorks) #ifdef vxWorks
#include <version.h> #include <version.h>
#if defined(_WRS_VXWORKS_MAJOR) && _WRS_VXWORKS_MAJOR > 6 || (_WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR > 8) /* VxWorks has strncasecmp since version 6
#include <stdint.h> but availability depends on configuration.
#define PRIX32 "X" We cannot know.
#define PRIu32 "u" */
#define NEED_strncasecmp
/* VxWorks does not have inttypes.h and uint32_t differs between versions */
#if defined(_WRS_VXWORKS_MAJOR) && (_WRS_VXWORKS_MAJOR > 6 || (_WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR >= 9))
#define PRIX32 "X"
#define PRIu32 "u"
#else
#define PRIX32 "lX"
#define PRIu32 "lu"
#endif
#define PRIX8 "X"
#elif defined(_MSC_VER) && _MSC_VER < 1700
/* Visual Studio 2010 does not have inttypes.h */
#define PRIX32 "X"
#define PRIu32 "u"
#define PRIX8 "X"
#else #else
#define PRIX32 "lX" #define __STDC_FORMAT_MACROS
#define PRIu32 "lu" #include <inttypes.h>
#endif
#define PRIX8 "X"
#define uint_fast8_t uint8_t
#define int_fast8_t int8_t
#elif defined(_MSC_VER) && _MSC_VER < 1700 /* Visual Studio 2010 does not have inttypes.h */
#include <stdint.h>
#define PRIX32 "X"
#define PRIu32 "u"
#define PRIX8 "X"
#else
#define __STDC_FORMAT_MACROS
#include <stdint.h>
#include <inttypes.h>
#endif #endif
#include <ctype.h> #include <ctype.h>
#include <stdlib.h>
#if defined(__rtems__)
#include <rtems.h>
#if __RTEMS_MAJOR__ < 5
/* RTEMS has strncasecmp since version 5 */
#define NEED_strncasecmp
#endif
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
#define strncasecmp _strnicmp /* Windows strncasecmp has a different name. */
#define strncasecmp _strnicmp
#endif #endif
#if defined(vxWorks) || defined(__rtems__) #ifdef NEED_strncasecmp
// These systems have no strncasecmp at the moment // Have no strncasecmp but avoid compiler errors in case it exists in future versions
// But avoid compiler errors in case strncasecmp exists in future versions extern "C" {
static int mystrncasecmp(const char *s1, const char *s2, size_t n) static int mystrncasecmp(const char *s1, const char *s2, size_t n)
{ {
int r=0; int r=0;
while (n && (r = toupper(*s1)-toupper(*s2)) == 0) { n--; s1++; s2++; }; while (n && (r = toupper(*s1)-toupper(*s2)) == 0) { n--; s1++; s2++; };
return r; return r;
}
} }
#define strncasecmp mystrncasecmp #define strncasecmp mystrncasecmp
#endif #endif
@ -534,6 +548,7 @@ static uint32_t leybold(const uint8_t* data, size_t len, uint32_t sum)
sum += *data++; sum += *data++;
} }
sum = ~sum; sum = ~sum;
sum &= 0xff;
if (sum < 32) sum+=32; if (sum < 32) sum+=32;
return sum; return sum;
} }
@ -731,7 +746,7 @@ printPseudo(const StreamFormat& format, StreamBuffer& output)
const char* info = format.info; const char* info = format.info;
uint32_t init = extract<uint32_t>(info); uint32_t init = extract<uint32_t>(info);
uint32_t xorout = extract<uint32_t>(info); uint32_t xorout = extract<uint32_t>(info);
uint_fast8_t fnum = extract<uint8_t>(info); uint8_t fnum = extract<uint8_t>(info);
size_t start = format.width; size_t start = format.width;
size_t length = output.length(); size_t length = output.length();
@ -752,8 +767,8 @@ printPseudo(const StreamFormat& format, StreamBuffer& output)
debug("ChecksumConverter %s: output checksum is 0x%" PRIX32 "\n", debug("ChecksumConverter %s: output checksum is 0x%" PRIX32 "\n",
checksumMap[fnum].name, sum); checksumMap[fnum].name, sum);
uint_fast8_t i; uint8_t i;
uint_fast8_t outchar; uint8_t outchar;
if (format.flags & sign_flag) // decimal if (format.flags & sign_flag) // decimal
{ {
@ -812,7 +827,7 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, size_t& cursor)
uint32_t init = extract<uint32_t>(info); uint32_t init = extract<uint32_t>(info);
uint32_t xorout = extract<uint32_t>(info); uint32_t xorout = extract<uint32_t>(info);
size_t start = format.width; size_t start = format.width;
uint_fast8_t fnum = extract<uint8_t>(info); uint8_t fnum = extract<uint8_t>(info);
size_t length = cursor; size_t length = cursor;
if (length >= start) length -= start; if (length >= start) length -= start;
else length = 0; else length = 0;
@ -824,7 +839,7 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, size_t& cursor)
debug("ChecksumConverter %s: input to check: \"%s\n", debug("ChecksumConverter %s: input to check: \"%s\n",
checksumMap[fnum].name, input.expand(start,length)()); checksumMap[fnum].name, input.expand(start,length)());
uint_fast8_t nDigits = uint8_t nDigits =
// get number of decimal digits from number of bytes: ceil(bytes*2.5) // get number of decimal digits from number of bytes: ceil(bytes*2.5)
format.flags & sign_flag ? (checksumMap[fnum].bytes + 1) * 25 / 10 - 2 : format.flags & sign_flag ? (checksumMap[fnum].bytes + 1) * 25 / 10 - 2 :
format.flags & (zero_flag|left_flag) ? 2 * checksumMap[fnum].bytes : format.flags & (zero_flag|left_flag) ? 2 * checksumMap[fnum].bytes :
@ -867,7 +882,7 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, size_t& cursor)
else else
if (format.flags & alt_flag) // lsb first (little endian) if (format.flags & alt_flag) // lsb first (little endian)
{ {
uint_fast8_t i; uint8_t i;
for (i = 0; i < checksumMap[fnum].bytes; i++) for (i = 0; i < checksumMap[fnum].bytes; i++)
{ {
if (format.flags & zero_flag) // ASCII if (format.flags & zero_flag) // ASCII
@ -910,8 +925,8 @@ scanPseudo(const StreamFormat& format, StreamBuffer& input, size_t& cursor)
} }
else // msb first (big endian) else // msb first (big endian)
{ {
int_fast8_t i; int8_t i;
uint_fast8_t j; uint8_t j;
for (i = checksumMap[fnum].bytes-1, j = 0; i >= 0; i--, j++) for (i = checksumMap[fnum].bytes-1, j = 0; i >= 0; i--, j++)
{ {
if (format.flags & zero_flag) // ASCII if (format.flags & zero_flag) // ASCII

View File

@ -358,7 +358,7 @@ dump() const
StreamBuffer result; StreamBuffer result;
size_t i; size_t i;
result.print("%" P "d,%" P "d,%" P "d:", offs, len, cap); result.print("%" P "d,%" P "d,%" P "d:", offs, len, cap);
if (offs) result.print(ansiEscape(ANSI_BG_WHITE)); if (offs) result.print("%s", ansiEscape(ANSI_BG_WHITE));
char c; char c;
for (i = 0; i < cap; i++) for (i = 0; i < cap; i++)
{ {

View File

@ -25,6 +25,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#if defined(vxWorks) #if defined(vxWorks)
#include <symLib.h> #include <symLib.h>