/*
* Cascade DataHub point writer: writept
*
* (C) Copyright Cogent Real-Time Systems Inc., 1997. All rights reserved.
*
* This program writes a point to the Cascade DataHub.
*
* This program is supplied with the Cascade DataHub programming API. It
* may be copied or modified, in whole or in part, for the sole purpose of
* creating applications to be used with the Cascade DataHub.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <cogent.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
const char* UT_USAGE =
"Usage: %s [-d domain] [-r|-f|-i|-l|-s] [-S security] pointname pointvalue\n"
;
const char* UT_HELP =
"\n"
"Help:\n"
" -d domain Set the domain for the operation.\n"
" -r Write as a real (floating point) number.\n"
" -i Write as a short integer.\n"
" -l Write as a long integer.\n"
" -s Write as a character string.\n"
" -S Set security level for write.\n"
"\n"
"Write a point to the Cascade datahub in the given domain.\n"
"\n"
"Notes:\n"
"- Strings containing spaces and special characters must be escaped\n"
" from the shell appropriately.\n"
"\n"
"- The type will be guessed if not specified, the order of guessing is:\n"
" 1) long\n"
" 2) float\n"
" 3) string (the default)\n"
" The guess is considered correct if the entire argument is converted.\n"
"\n"
"- A long can be given in standard C style, 0x5f (hex), 0647 (oct), etc.\n"
;
int main (int argc, char** argv)
{
IP_Msg *hmsg;
ST_STATUS status;
PT_stCPOINT point;
char *ptname = NULL, *ptvalue = NULL, *domain=NULL, *myname;
short type = PT_TYPE_VOID;
int security=0;
IP_Task *htask;
int opt;
/*
* Parse the command line
*/
while((opt = getopt(argc, argv, "hd:rilsS:")) != -1)
{
switch (opt)
{
case 'h':
UT_Help(argv[0], UT_USAGE, UT_HELP);
exit(0);
case 'd':
domain = optarg;
if (strlen(domain) > 15)
domain[15] = '\0';
break;
case 'r':
type = PT_TYPE_REAL;
break;
case 'i':
case 'l':
type = PT_TYPE_INT32;
break;
case 's':
type = PT_TYPE_STRING;
break;
case 'S':
security = atoi (optarg);
break;
default:
UT_Usage (argv[0], UT_USAGE, stderr);
exit (1);
break;
}
}
/* the last two args better be the point and value */
if (!argv[optind] || !argv[optind+1])
{
UT_Usage(argv[0], UT_USAGE, stderr);
exit(1);
}
ptname = argv[optind];
ptvalue = argv[optind+1];
/*
* Initialize communication through the Cascade IPC library. We do
* not want other tasks to be notified of the start and stop of
* this task, so we do not use IP_NserveInit. The name server
* will never know about this task, so notifications will not be
* passed on. Tasks that attempt to look up their clients in the
* name server will treat this task as non-existent. For example,
* Cascade DataHub would not be able to send point exceptions to
* this task.
*/
if ((myname = strrchr(argv[0], '/')))
myname++;
else
myname = argv[0];
if (!(htask = IP_TaskCreateMe (IP_GetChannelID(), myname, domain,
NULL, 0)))
{
fprintf (stderr, "Could not initialize Cascade IPC subsystem\n");
exit (1);
}
/*
* Set this task's security level. This level must be greater than or
* equal to the security level of the point in the datahub in order
* for the write to succeed. The datahub does not know whether this
* task has the right to claim this security level. That enforcement
* is up to the programmer of the user task.
*/
IP_TaskSetSecurity (htask, security);
/*
* Create a pre-allocated message structure for use with all
* IPC calls. This includes the DH_* functions. The API could have
* created its own internal message structure, but this would have
* left us with no way to control its size or be efficient about
* allocation. This way we do a little more work, but have more
* control of what is being allocated.
*/
hmsg = IP_MsgCreate (NULL, IP_MsgDefaultSize(), 0);
/*
* Zero the point structure. If we do not do this, the address
* field could be non-zero, and then the API will take that to be a
* cached datahub address. That might cause a crash.
*/
memset (&point, 0, sizeof(point));
/*
* Provide a point name buffer separately from the rest of the point
* structure. There is no way for the API to know what the allocation
* status of a point name is, so it will never attempt to free this
* buffer, nor write into it.
*/
point.name = ptname;
point.type = type;
point.conf = 100;
/*
* Set the time on the point. If this is not set, then the datahub
* will show a zero time.
*/
#ifdef __QNX__
{
struct timespec tp;
clock_gettime (CLOCK_REALTIME, &tp);
point.seconds = tp.tv_sec;
point.nanoseconds = tp.tv_nsec;
}
#else
{
struct timeval tp;
gettimeofday (&tp, NULL);
point.seconds = tp.tv_sec;
point.nanoseconds = tp.tv_usec * 1000;
}
#endif /* __QNX__ */
/*
* Set the value of the point based on the type.
*/
switch (point.type)
{
case PT_TYPE_INT32:
point.value.i = strtol(ptvalue, 0, 0);
break;
case PT_TYPE_REAL:
point.value.r = strtod (ptvalue, NULL);
break;
case PT_TYPE_STRING:
point.value.s = ptvalue;
break;
case PT_TYPE_VOID:
default:
{
/* try to autodetect type of point */
char* eos = 0;
/* it's a long if conversion goes to end of string */
eos = 0;
point.value.i = strtol(ptvalue, &eos, 0);
if(*eos == '\0')
{
point.type = PT_TYPE_INT32;
break;
}
/* it's a double if conversion goes to end of string */
eos = 0;
point.value.r = strtod(ptvalue, &eos);
if(*eos == '\0')
{
point.type = PT_TYPE_REAL;
break;
}
/* else it's a string */
point.type = PT_TYPE_STRING;
point.value.s = ptvalue;
break;
}
}
/*
* Write the point. We need a IP_Msg structure and a IP_hTASK in
* to provide buffer space and sender identification respectively.
*/
if ((status = DH_WritePoint (htask, &point, hmsg, NULL)) != ST_OK)
printf ("Write point failed: %s\n", ST_StatusName (status));
return (0);
}
Copyright © 1995-2006 by Cogent Real-Time Systems, Inc. All rights reserved.