Table of Contents
These code examples are provided in source form as part of the Cascade DataHub API, normally installed in the /usr/cogent/src/datahub directory. They are provided here so that you can see what is involved in communicating with the DataHub using your own C programs. The Gamma programming language also contains many 'hooks' into the DataHub. For more information about using Gamma with the DataHub see the DataHub demo program that is available for download from the Cogent web site. The Cascade DataHub demo uses Gamma to show the features of the DataHub. If you download and run the Gamma demo for the DataHub you will have to reinstall your commercial version of the DataHub, because the version that comes with the Gamma demo contains a time limited license.
/*
* Cascade DataHub point reader: readpt
*
* (C) Copyright Cogent Real-Time Systems Inc., 1997. All rights reserved.
*
* This program reads a point from the Cascade DataHub and displays the
* result on the standard output.
*
* 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 <unistd.h>
#include <string.h>
#include <time.h>
#include <cogent.h>
/*
* A point is one of three types. We discover which one we have and
* print the appropriate name, value, confidence factor, lock status
* and security level.
*/
void print_point (PT_pCPOINT ppoint, int brief)
{
char *t;
printf ("Point: %s\n", ppoint->name);
switch (ppoint->type)
{
case PT_TYPE_INT32:
printf ("Value: %ld\n", (long)ppoint->value.i);
break;
case PT_TYPE_REAL:
printf ("Value: %g\n", ppoint->value.r);
break;
case PT_TYPE_STRING:
printf ("Value: %s\n", ppoint->value.s);
break;
default:
printf ("Value: ...unknown point type!\n");
break;
}
if(!brief)
{
t = ctime ((time_t*)&ppoint->seconds);
t[19] = '\0';
printf ("Time: %s.%03ld\n", &t[4],
(long)ppoint->nanoseconds / 1000000);
printf ("Conf: %d\n", ppoint->conf);
printf ("Lock: %d\n", ppoint->locked);
printf ("Secur: %d\n", ppoint->security);
}
}
#ifdef __USAGE
Copyright (C) Cogent Real-Time Systems Inc., 1996-1997
%C [-b] [-d domain] pointname
-b brief output (only the point name and value)
-d domain, replaces the default
Read pointname from the Cascade datahub, the domain
can be specified with -d, or by qualifying the pointname,
as in "domain:thepointname" (the latter technique overriding
the former).
#endif
const char* UT_USAGE =
"Usage: %s [-b] [-d domain] pointname\n"
;
const char* UT_HELP =
"\n"
"Help:\n"
" -b Brief output (only the point name and value).\n"
" -d Domain, replaces the default.\n"
"\n"
"Read pointname from the Cascade datahub, the domain\n"
"can be specified with -d, or by qualifying the pointname,\n"
"as in \"domain:thepointname\" (the latter technique overriding\n"
"the former).\n"
;
int main (int argc, char** argv)
{
IP_Msg *hmsg;
ST_STATUS status;
PT_stCPOINT point;
char *ptname = NULL, *domain = NULL, *myname;
int opt;
int brief = 0;
IP_Task *htask;
/*
* Parse the input arguments. The only interesting argument is an
* alternate datahub domain name. We really do not need this, as
* we could specify the point name as domain:name
*/
while ((opt = getopt(argc, argv, "hbd:")) != -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 'b':
brief = 1;
break;
default:
UT_Usage (argv[0], UT_USAGE, stderr);
exit(1);
}
}
if (!argv[optind])
{
UT_Usage(argv[0], UT_USAGE, stderr);
exit(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);
}
/*
* 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);
while((ptname = argv[optind++]))
{
/*
* 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;
if ((status = DH_ReadPoint (htask, &point, hmsg, NULL)) != ST_OK)
{
fprintf (stderr, "Read \"%s\" failed: %s\n",
point.name, ST_StatusName (status));
exit(1);
}
else
{
print_point (&point, brief);
}
}
return 0;
}
Copyright © 1995-2006 by Cogent Real-Time Systems, Inc. All rights reserved.