CODA release 2.0 allows application programmers to communicate with a coda run control server through CDEV interface. A device in cdev is regarded as a named entity which can respond to a set of messages. All I/O requests in the system are in the form of messages to devices. In cdev all interface take on the following forms:
cdevData out, result;
cdevCallback callback (userFunc, 0);
cdevDevice& device = cdevDevice::attachRef ("session");
device.send ("message", out, result);
device.sendNoBlock ("message", out, result);
device.sendCallback ("message", out, callback);
In order to communicate with a run control server, an application has to use session name of a run control as a device name in the cdev functions, and to use the following verbs and messages inside those send functions.
verbs: get set monitorOn monitorOff attributes: version startTime endTime runTypeNum clientList runMessage status runNumber time updateInterval components runType allRunTypes database hostName eventLimit dataLimit master messages: load configure download prestart pause end reset go abort state disconnect connect connectedIn addition, an application has to have EXPID environment variable set to appropriate database, has to have DEVSHOBJ pointing to the right cdev library directory and has to have CDEVDDL pointing to coda.ddl came with coda release. The following is a very simple application using cdev interface to communicate with a run control server.
#include <cdevSystem.h>
#include <cdevRequestObject.h>
#include <cdevDevice.h>
#include <cdevGroup.h>
#include <cdevErrCode.h>
#include <unistd.h>
// network file descriptor open/close callback
static void fdCallback (int fd, int opened, void* arg)
{
if (opened == 0) {
fprintf (stderr, "file descriptor %d is closed\n", fd);
}
else {
fprintf (stderr, "file descriptor %d is open\n", fd);
}
}
// command callback
static void comdCallback (int status, void *userarg,
cdevRequestObject &obj, cdevData& result)
{
printf ("command callback called======================\n");
}
// utility for manipulating cdevData
static int insertData (cdevData& out, int type, int count)
{
int dataStatus = 0;
if (count == 1){
switch (type){
case 0:
{
char temp[40];
printf ("Enter char string\n");
scanf ("%s",temp);
dataStatus = out.insert ("value", temp);
}
break;
case 1:
case 5:
{
int val;
printf ("Enter Integer Value \n");
scanf ("%d", &val);
dataStatus = out.insert ("value", val);
}
break;
case 2:
{
float fval;
printf ("Enter double value \n");
scanf ("%f", &fval);
dataStatus = out.insert ("value", fval);
}
case 6:
{
double val;
float fval;
printf ("Enter double value \n");
scanf ("%f", &fval);
val = (double)fval;
dataStatus = out.insert ("value", val);
}
break;
default:
printf ("unsupported data type %d\n", type);
break;
}
}
else {
switch (type){
case 0:
{
static counter = 0;
char **temp = new char* [count];
for (int i = 0; i < count; i++){
temp[i] = new char[40];
sprintf (temp[i], "Hello again there %d", i * counter);
}
dataStatus = out.insert ("value",temp, count);
for (i = 0; i < count; i++)
delete []temp[i];
delete []temp;
counter++;
if (counter > 10)
counter = 0;
}
break;
case 1:
case 5:
{
static counter = 1;
int *temp = new int[count];
for (int i = 0; i < count; i++)
temp[i] = i*counter;
dataStatus = out.insert ("value",temp, count);
delete []temp;
counter++;
if (counter > 3)
counter = 1;
}
break;
case 6:
{
static counter = 1;
double *temp = new double[count];
for (int i = 0; i < count; i++)
temp[i] = i*(counter);
dataStatus = out.insert ("value",temp, count);
delete []temp;
counter++;
if (counter > 3)
counter = 1;
}
break;
default:
break;
}
}
return dataStatus;
}
// print out cdevData
static void printValue (cdevData& result)
{
int type;
int tag;
size_t dim, len1;
result.tagC2I ("value", &tag);
int st = result.getDim (tag, &dim);
if (dim != 0)
{
// ***********************************************************************
// * cdevBounds support added for support of arbitrary dimensional data
// ***********************************************************************
cdevBounds bounds;
st = result.getBounds (tag, &bounds, 1);
len1 = bounds.length;
}
else
len1 = 1;
printf ("Length is %d\n", len1);
type = result.getType (tag);
printf ("data type is %d\n",type);
float lval, hval;
st = result.get ("displayHigh", &hval);
if (st == CDEV_SUCCESS)
printf ("Display High limit is %f\n", hval);
st = result.get ("displayLow", &lval);
if (st == CDEV_SUCCESS)
printf ("Display Low Limit is %f\n", lval);
char *stt;
st = result.get ("status", &stt);
if (st == CDEV_SUCCESS)
printf ("status of value is %s\n", stt);
char *sver;
st = result.get ("severity", &sver);
if (st == CDEV_SUCCESS)
printf ("severity of value is %s\n", sver);
cdev_TS_STAMP tsm;
st = result.get ("time", &tsm);
if (st == CDEV_SUCCESS) {
printf ("time value sec is %d nanosec is %d\n",tsm.secPastEpoch,
tsm.nsec);
printf ("In dat %s\n",ctime ((const time_t *)&tsm.secPastEpoch));
}
switch (type){
case CDEV_INT32:
if (len1 == 1){
int retVal;
result.get (tag, &retVal);
printf ("result is 0x%x %d\n",retVal, retVal);
}
else{
int *retVal = new int[len1];
result.get (tag, retVal);
printf ("result is \n");
for (int i = 0; i < len1; i++)
printf ("%d\n", retVal[i]);
printf ("__________________\n");
delete []retVal;
}
break;
case CDEV_FLOAT:
if (len1 == 1) {
float dval;
result.get (tag, &dval);
printf ("result is %f\n", dval);
}
else {
float *dval = new float[len1];
result.get (tag, dval);
for (int i = 0; i < len1; i++)
printf ("%f\n", dval[i]);
printf ("__________________\n");
delete []dval;
}
break;
case CDEV_DOUBLE:
if (len1 == 1) {
double dval;
result.get (tag, &dval);
printf ("result is %f\n", dval);
}
else {
double *dval = new double[len1];
result.get (tag, dval);
for (int i = 0; i < len1; i++)
printf ("%f\n", dval[i]);
printf ("__________________\n");
delete []dval;
}
break;
case CDEV_STRING:
if (len1 == 1){
char temp[40];
result.get (tag,temp, sizeof (temp));
printf ("result is %s\n", temp);
}
else{
char **temp;
temp = new char* [len1];
result.get (tag, temp);
printf ("Strings are \n");
for (int i = 0; i < len1; i++){
printf ("%s\n",temp[i]);
delete []temp[i];
}
delete []temp;
}
break;
default:
printf ("Something is wrong\n");
break;
}
}
static void myCallback (int status, void *userarg,
cdevRequestObject &obj, cdevData& result);
static void myCallback2 (int status, void *userarg,
cdevRequestObject &obj, cdevData& result);
static void myCallback3 (int status, void *userarg,
cdevRequestObject &obj, cdevData& result);
static void mySetCallback (int status, void *userarg,
cdevRequestObject &obj, cdevData& result);
static int done = 0;
cdevCallback getCallback(myCallback, 0);
cdevCallback getCallback1 (myCallback2, 0);
cdevCallback getCallback2 (myCallback3, 0);
cdevRequestObject* monObj = 0;
main (int argc, char **argv)
{
cdevSystem& system = cdevSystem::defaultSystem ();
cdevCallback setCallback(mySetCallback, (void *)0);
system.addFdChangedCallback (fdCallback, 0);
char command[40];
char deviceName[40], messageName[64], attname[30];
char msgPtr[32], message[128];
cdevData result;
cdevData cxt;
if (argc < 2) {
fprintf (stderr, "Usage: %s codaSession\n", argv[0]);
exit (1);
}
// the following is to notify the cdev directory service to add
// the session as a device
cdevDevice& ns = cdevDevice::attachRef ("cdevDirectory");
cdevData out;
char ddlstr[80];
sprintf (ddlstr, "RCS : %s;", argv[1]);
out.insert ("value", ddlstr);
int stt = ns.send ("update", out, result);
while (!done){
fprintf (stdout, "cdevTest Command>");
scanf ("%s", command);
if (::strcmp (command, "get") == 0){
printf ("cdevTest devicename attribute> \n");
scanf ("%s %s",deviceName, attname);
::strcpy (messageName, command);
::strcat (messageName, " ");
::strcat (messageName, attname);
printf ("device: %s message: %s\n",deviceName, messageName);
cdevRequestObject *req = cdevRequestObject::attachPtr (deviceName,
messageName);
result.remove ();
int st = req->send (0, result);
if (st == CDEV_SUCCESS)
printValue (result);
else{
printf("send failed-----\n");
}
cdevRequestObject::detach (req);
}
else if (::strcmp (command, "set") == 0){
printf ("cdevTest devicename attribute> \n");
scanf ("%s %s",deviceName, attname);
::strcpy (messageName, command);
::strcat (messageName, " ");
::strcat (messageName, attname);
cdevRequestObject& req =
cdevRequestObject::attachRef (deviceName, messageName);
int type, count;
printf ("Supported type are: \n");
printf ("0: string. 1: short. 2: float, 5: long, 6: double\n");
printf ("Enter type and count for this channel\n");
scanf ("%d %d",&type, &count);
cdevData out;
int dataStatus = insertData (out, type, count);
if (dataStatus == CDEV_SUCCESS){
int st = req.send (out, 0);
if (st == CDEV_SUCCESS)
printf ("Set success\n");
else
printf ("Set failed\n");
cdevRequestObject::detach (req);
}
else
printf ("Data Insersion Error\n");
}
else if (::strcmp (command, "monitorOn") == 0){
printf ("cdevTest devicename attribute> \n");
scanf ("%s %s",deviceName, attname);
::strcpy (messageName, command);
::strcat (messageName, " ");
::strcat (messageName, attname);
monObj = cdevRequestObject::attachPtr (deviceName, messageName);
int st;
cdevGroup grp;
grp.start ();
st = monObj->sendCallback (0, getCallback);
grp.end ();
st = grp.pend (10.0);
if (grp.allFinished ())
printf ("Monitor On success\n");
else
printf ("MonitorOn failed\n");
// system is doing monitoring for 20 seconds
system.pend (20.0);
cdevRequestObject::detach (monObj);
monObj = 0;
}
else if (::strcmp (command, "load") == 0) {
printf ("device: %s message: %s\n",deviceName, command);
cdevRequestObject *req = cdevRequestObject::attachPtr (deviceName,
command);
cdevData out;
char *extra[2];
extra[0] = ::getenv ("EXPID");
extra[1] = deviceName;
out.insert ("value", extra, 2);
cdevCallback commandCallback(comdCallback, (void *)0);
int st = req->sendCallback (out, commandCallback);
if (st == CDEV_SUCCESS)
printf ("Send successful-----\n");
else
printf("send failed-----\n");
system.pend (2.0);
cdevRequestObject::detach (req);
}
else if (::strcmp (command, "configure") == 0) {
printf ("cdevTest runtype> \n");
scanf ("%s",message);
printf ("device: %s message: %s\n",deviceName, command);
cdevRequestObject *req = cdevRequestObject::attachPtr (deviceName,
command);
cdevData out;
out.insert ("value", message);
int st = req->send (out, 0);
if (st == CDEV_SUCCESS)
printf ("Send successful-----\n");
else
printf("send failed-----\n");
cdevRequestObject::detach (req);
}
else if (::strcmp (command, "download") == 0) {
cdevRequestObject *req = cdevRequestObject::attachPtr (deviceName,
command);
int st = req->send (0, 0);
if (st == CDEV_SUCCESS)
printf ("Send successful-----\n");
else
printf("send failed-----\n");
cdevRequestObject::detach (req);
}
else if (::strcmp (command, "prestart") == 0) {
cdevRequestObject *req = cdevRequestObject::attachPtr (deviceName,
command);
int st = req->send (0, 0);
if (st == CDEV_SUCCESS)
printf ("Send successful-----\n");
else
printf("send failed-----\n");
cdevRequestObject::detach (req);
}
else if (::strcmp (command, "pause") == 0) {
cdevRequestObject *req = cdevRequestObject::attachPtr (deviceName,
command);
int st = req->send (0, 0);
if (st == CDEV_SUCCESS)
printf ("Send successful-----\n");
else
printf("send failed-----\n");
cdevRequestObject::detach (req);
}
else if (::strcmp (command, "end") == 0) {
cdevRequestObject *req = cdevRequestObject::attachPtr (deviceName,
command);
int st = req->send (0, 0);
if (st == CDEV_SUCCESS)
printf ("Send successful-----\n");
else
printf("send failed-----\n");
cdevRequestObject::detach (req);
}
else if (::strcmp (command, "reset") == 0) {
cdevRequestObject *req = cdevRequestObject::attachPtr (deviceName,
command);
int st = req->send (0, 0);
if (st == CDEV_SUCCESS)
printf ("Send successful-----\n");
else
printf("send failed-----\n");
cdevRequestObject::detach (req);
}
else if (::strcmp (command, "go") == 0) {
cdevRequestObject *req = cdevRequestObject::attachPtr (deviceName,
command);
int st = req->send (0, 0);
if (st == CDEV_SUCCESS)
printf ("Send successful-----\n");
else
printf("send failed-----\n");
cdevRequestObject::detach (req);
}
else if (::strcmp (command, "abort") == 0) {
cdevRequestObject *req = cdevRequestObject::attachPtr (deviceName,
command);
int st = req->send (0, 0);
if (st == CDEV_SUCCESS)
printf ("Send successful-----\n");
else
printf("send failed-----\n");
cdevRequestObject::detach (req);
}
else if (::strcmp (command, "state") == 0) {
cdevRequestObject *req = cdevRequestObject::attachPtr (deviceName,
command);
int st = req->send (0, result);
void *temp;
result.find ("value", temp);
if (st == CDEV_SUCCESS)
printf ("result is %s\n", (char *)temp);
else
printf("send failed-----\n");
cdevRequestObject::detach (req);
}
else if (::strcmp (command, "quit") == 0)
done = 1;
else {
printf ("Legal commands are: get, quit\n");
}
}
}
static void myCallback (int status, void *userarg,
cdevRequestObject &obj, cdevData& result)
{
printf ("user get callback called++++++++\n");
printValue (result);
}
static void myCallback2 (int status, void *userarg,
cdevRequestObject &obj, cdevData& result)
{
printf ("user get callback2 called ##############################\n");
printValue (result);
if (monObj) {
cdevRequestObject& reqObj = cdevRequestObject::attachRef (monObj->device(),
"monitorOff nevents");
reqObj.sendCallback (0, getCallback1);
cdevRequestObject::detach (reqObj);
}
}
static void myCallback3 (int status, void *userarg,
cdevRequestObject &obj, cdevData& result)
{
printf ("user get callback3 called++++++++++++++++\n");
printValue (result);
}
static void mySetCallback (int status, void *userarg,
cdevRequestObject &obj, cdevData& result)
{
printf ("user set callback called======================\n");
}
Of course, applications may use cdev to communicate not only with a run control server
but also with epics through channel access service released with standard cdev
distribution. For further information about using multiple cdev services, please check
with CDEV references.