Files
epics-base/src/ca/acctst.c
2000-06-08 14:59:21 +00:00

1501 lines
39 KiB
C

/*
* CA regression test
*/
/*
* ANSI
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <string.h>
/*
* EPICS
*/
#include "epicsAssert.h"
#include "tsStamp.h"
/*
* CA
*/
#include "cadef.h"
#include "caDiagnostics.h"
#define EVENT_ROUTINE null_event
#define CONN_ROUTINE conn
#define NUM 1
int conn_cb_count;
#ifndef min
#define min(A,B) ((A)>(B)?(B):(A))
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef NELEMENTS
#define NELEMENTS(A) ( sizeof (A) / sizeof (A[0]) )
#endif
int doacctst(char *pname);
void test_sync_groups(chid chix);
void multiple_sg_requests(chid chix, CA_SYNC_GID gid);
void null_event(struct event_handler_args args);
void write_event(struct event_handler_args args);
void conn(struct connection_handler_args args);
void get_cb(struct event_handler_args args);
void accessSecurity_cb(struct access_rights_handler_args args);
void pend_event_delay_test(dbr_double_t request);
void performMonitorUpdateTest (chid chan);
void performDeleteTest (chid chan);
void doubleTest(
chid chan,
dbr_double_t beginValue,
dbr_double_t increment,
dbr_double_t epsilon,
unsigned iterations);
void floatTest(
chid chan,
dbr_float_t beginValue,
dbr_float_t increment,
dbr_float_t epsilon,
unsigned iterations);
void performGrEnumTest (chid chan);
void performCtrlDoubleTest (chid chan);
void atLeastOneUpdateTester ( struct event_handler_args args )
{
unsigned *pCtr = (unsigned *) args.usr;
(*pCtr)++;
}
void monitorSubscriptionFirstUpdateTest ( chid chan )
{
int status;
unsigned eventCount = 0u;
unsigned waitCount = 0u;
evid id;
/*
* verify that the first event arrives
*/
status = ca_add_event ( DBR_FLOAT,
chan, atLeastOneUpdateTester, &eventCount, &id );
SEVCHK (status, 0);
while ( eventCount < 1 && waitCount++ < 100 ) {
ca_pend_event ( 0.01 );
}
assert ( eventCount > 0 );
status = ca_clear_event ( id );
SEVCHK (status, 0);
}
int acctst (char *pname)
{
chid chix1;
chid chix2;
chid chix3;
chid chix4;
struct dbr_gr_float *pgrfloat = NULL;
dbr_float_t *pfloat = NULL;
dbr_double_t *pdouble = NULL;
long status;
long i, j;
evid monix;
char pstring[NUM][MAX_STRING_SIZE];
unsigned monCount=0u;
SEVCHK ( ca_task_initialize(), "Unable to initialize" );
conn_cb_count = 0;
printf ( "begin\n" );
printf ( "CA Client V%s\n", ca_version () );
/*
* verify that we dont print a disconnect message when
* we delete the last channel
* (this fails if we see a disconnect message)
*/
status = ca_search ( pname, &chix3 );
SEVCHK ( status, NULL );
status = ca_pend_io ( 1000.0 );
SEVCHK ( status, NULL );
status = ca_clear_channel ( chix3 );
SEVCHK ( status, NULL );
/*
* verify lots of disconnects
* verify channel connected state variables
*/
printf ( "Connect/disconnect test" );
fflush ( stdout );
for ( i = 0; i < 10; i++ ) {
status = ca_search ( pname, &chix3 );
SEVCHK(status, NULL);
status = ca_search ( pname, &chix4 );
SEVCHK(status, NULL);
status = ca_search ( pname, &chix2 );
SEVCHK(status, NULL);
status = ca_search ( pname, &chix1 );
SEVCHK(status, NULL);
if ( ca_test_io() == ECA_IOINPROGRESS ) {
assert(INVALID_DB_REQ(ca_field_type(chix1)) == TRUE);
assert(INVALID_DB_REQ(ca_field_type(chix2)) == TRUE);
assert(INVALID_DB_REQ(ca_field_type(chix3)) == TRUE);
assert(INVALID_DB_REQ(ca_field_type(chix4)) == TRUE);
assert(ca_state(chix1) == cs_never_conn);
assert(ca_state(chix2) == cs_never_conn);
assert(ca_state(chix3) == cs_never_conn);
assert(ca_state(chix4) == cs_never_conn);
}
status = ca_pend_io(1000.0);
SEVCHK(status, NULL);
printf(".");
fflush(stdout);
assert(ca_test_io() == ECA_IODONE);
assert(ca_state(chix1) == cs_conn);
assert(ca_state(chix2) == cs_conn);
assert(ca_state(chix3) == cs_conn);
assert(ca_state(chix4) == cs_conn);
SEVCHK(ca_clear_channel(chix4), NULL);
SEVCHK(ca_clear_channel(chix3), NULL);
SEVCHK(ca_clear_channel(chix2), NULL);
SEVCHK(ca_clear_channel(chix1), NULL);
/*
* verify that connections to IOC's that are
* not in use are dropped
*/
j=0;
do {
ca_pend_event (0.1);
assert (++j<100);
}
while (ca_get_ioc_connection_count()>0u);
}
printf("\n");
/*
* look for problems with ca_search(), ca_clear_channel(),
* ca_change_connection_event(), and ca_pend_io(() combo
*/
status = ca_search ( pname,& chix3 );
SEVCHK ( status, NULL );
status = ca_replace_access_rights_event ( chix3, accessSecurity_cb );
SEVCHK ( status, NULL );
/*
* verify clear before connect
*/
status = ca_search ( pname, &chix4 );
SEVCHK ( status, NULL );
/*
* verify that NULL
* evid does not cause failure
*/
status = ca_add_event ( DBR_FLOAT,
chix4, EVENT_ROUTINE, NULL, NULL );
SEVCHK ( status, NULL );
status = ca_clear_channel ( chix4 );
SEVCHK ( status, NULL );
status = ca_search ( pname, &chix4 );
SEVCHK ( status, NULL );
status = ca_replace_access_rights_event ( chix4, accessSecurity_cb );
SEVCHK ( status, NULL );
status = ca_search ( pname, &chix2 );
SEVCHK (status, NULL);
status = ca_replace_access_rights_event (chix2, accessSecurity_cb);
SEVCHK ( status, NULL );
status = ca_search ( pname, &chix1 );
SEVCHK ( status, NULL );
status = ca_replace_access_rights_event ( chix1, accessSecurity_cb );
SEVCHK ( status, NULL );
status = ca_change_connection_event ( chix1, conn );
SEVCHK ( status, NULL );
status = ca_change_connection_event ( chix1, NULL );
SEVCHK ( status, NULL );
status = ca_change_connection_event ( chix1, conn );
SEVCHK ( status, NULL );
status = ca_change_connection_event ( chix1, NULL );
SEVCHK ( status, NULL );
status = ca_pend_io ( 1000.0 );
SEVCHK ( status, NULL );
assert ( ca_state (chix1) == cs_conn );
assert ( ca_state (chix2) == cs_conn );
assert ( ca_state (chix3) == cs_conn );
assert ( ca_state (chix4) == cs_conn );
assert ( INVALID_DB_REQ (ca_field_type (chix1) ) == FALSE );
assert ( INVALID_DB_REQ (ca_field_type (chix2) ) == FALSE );
assert ( INVALID_DB_REQ (ca_field_type (chix3) ) == FALSE );
assert ( INVALID_DB_REQ (ca_field_type (chix4) ) == FALSE );
printf("%s Read Access=%d Write Access=%d\n",
ca_name(chix1), ca_read_access(chix1), ca_write_access(chix1));
/*
* clear chans before starting another test
*/
status = ca_clear_channel(chix1);
SEVCHK(status, NULL);
status = ca_clear_channel(chix2);
SEVCHK(status, NULL);
status = ca_clear_channel(chix3);
SEVCHK(status, NULL);
status = ca_clear_channel(chix4);
SEVCHK(status, NULL);
/*
* verify ca_pend_io() does not see old search requests
* (that did not specify a connection handler)
*/
status = ca_search_and_connect(pname, &chix1, NULL, NULL);
SEVCHK(status, NULL);
/*
* channel will connect synchronously if on the
* local host
*/
if (ca_state(chix1)==cs_never_conn) {
status = ca_pend_io(1e-16);
if (status==ECA_TIMEOUT) {
printf ("waiting on pend io verify connect...");
fflush (stdout);
while (ca_state(chix1)!=cs_conn) {
ca_pend_event(0.1);
}
printf ("done\n");
/*
* we end up here if the channel isnt on the same host
*/
status = ca_search_and_connect (pname, &chix2, NULL, NULL);
SEVCHK (status, NULL);
status = ca_pend_io(1e-16);
if (status!=ECA_TIMEOUT) {
assert(ca_state(chix2)==cs_conn);
}
status = ca_clear_channel (chix2);
SEVCHK (status, NULL);
}
else {
assert (ca_state(chix1)==cs_conn);
}
}
status = ca_clear_channel(chix1);
SEVCHK (status, NULL);
/*
* verify connection handlers are working
*/
status = ca_search_and_connect(pname, &chix1, conn, NULL);
SEVCHK(status, NULL);
status = ca_search_and_connect(pname, &chix2, conn, NULL);
SEVCHK(status, NULL);
status = ca_search_and_connect(pname, &chix3, conn, NULL);
SEVCHK(status, NULL);
status = ca_search_and_connect(pname, &chix4, conn, NULL);
SEVCHK(status, NULL);
printf("waiting on conn handler call back connect...");
fflush(stdout);
while (conn_cb_count != 4) {
ca_pend_event(0.1);
}
printf("done\n");
monitorSubscriptionFirstUpdateTest ( chix4 );
performGrEnumTest (chix1);
performCtrlDoubleTest (chix1);
/*
* ca_pend_io() must block
*/
if(ca_read_access(chix4)){
dbr_float_t req;
dbr_float_t resp;
printf ("get TMO test ...");
fflush(stdout);
req = 56.57f;
resp = -99.99f;
SEVCHK(ca_put(DBR_FLOAT, chix4, &req),NULL);
SEVCHK(ca_get(DBR_FLOAT, chix4, &resp),NULL);
status = ca_pend_io(1.0e-12);
if (status==ECA_NORMAL) {
if (resp != req) {
printf (
"get block test failed - val written %f\n", req);
printf (
"get block test failed - val read %f\n", resp);
assert(0);
}
}
else if (resp != -99.99f) {
printf (
"CA didnt block for get to return?\n");
}
req = 33.44f;
resp = -99.99f;
SEVCHK (ca_put(DBR_FLOAT, chix4, &req),NULL);
SEVCHK (ca_get(DBR_FLOAT, chix4, &resp),NULL);
SEVCHK (ca_pend_io(2000.0),NULL);
if (resp != req) {
printf (
"get block test failed - val written %f\n", req);
printf (
"get block test failed - val read %f\n", resp);
assert(0);
}
printf ("done\n");
}
/*
* Verify that we can do IO with the new types for ALH
*/
#if 0
if(ca_read_access(chix4)&&ca_write_access(chix4)){
{
dbr_put_ackt_t acktIn=1u;
dbr_put_acks_t acksIn=1u;
struct dbr_stsack_string stsackOut;
SEVCHK (ca_put(DBR_PUT_ACKT, chix4, &acktIn),NULL);
SEVCHK (ca_put(DBR_PUT_ACKS, chix4, &acksIn),NULL);
SEVCHK (ca_get(DBR_STSACK_STRING, chix4, &stsackOut),NULL);
SEVCHK (ca_pend_io(2000.0),NULL);
}
#endif
/*
* Verify that we can write and then read back
* the same analog value (DBR_FLOAT)
*/
if( (ca_field_type(chix1)==DBR_DOUBLE ||
ca_field_type(chix1)==DBR_FLOAT) &&
ca_read_access(chix1) &&
ca_write_access(chix1)){
dbr_float_t incr;
dbr_float_t epsil;
dbr_float_t base;
unsigned long iter;
printf ("dbr_float_t test ");
fflush (stdout);
epsil = FLT_EPSILON*4.0F;
base = FLT_MIN;
for (i=FLT_MIN_EXP; i<FLT_MAX_EXP; i+=FLT_MAX_EXP/10) {
incr = (dbr_float_t) ldexp (0.5F,i);
if (fabs(incr)>FLT_MAX/10.0) {
iter = (unsigned long) (FLT_MAX/fabs(incr));
}
else {
iter = 10ul;
}
floatTest(chix1, base, incr, epsil, iter);
printf (".");
fflush (stdout);
}
base = FLT_MAX;
for (i=FLT_MIN_EXP; i<FLT_MAX_EXP; i+=FLT_MAX_EXP/10) {
incr = (dbr_float_t) - ldexp (0.5F,i);
if (fabs(incr)>FLT_MAX/10.0) {
iter = (unsigned long) (FLT_MAX/fabs(incr));
}
else {
iter = 10ul;
}
floatTest(chix1, base, incr, epsil, iter);
printf (".");
fflush (stdout);
}
base = - FLT_MAX;
for (i=FLT_MIN_EXP; i<FLT_MAX_EXP; i+=FLT_MAX_EXP/10) {
incr = (dbr_float_t) ldexp (0.5F,i);
if (fabs(incr)>FLT_MAX/10.0) {
iter = (unsigned long) (FLT_MAX/fabs(incr));
}
else {
iter = 10ul;
}
floatTest (chix1, base, incr, epsil, iter);
printf (".");
fflush (stdout);
}
printf ("done\n");
}
/*
* Verify that we can write and then read back
* the same analog value (DBR_DOUBLE)
*/
if( ca_field_type(chix1)==DBR_DOUBLE &&
ca_read_access(chix1) &&
ca_write_access(chix1)){
dbr_double_t incr;
dbr_double_t epsil;
dbr_double_t base;
unsigned long iter;
printf ("dbr_double_t test ");
fflush(stdout);
epsil = DBL_EPSILON*4;
base = DBL_MIN;
for (i=DBL_MIN_EXP; i<DBL_MAX_EXP; i+=DBL_MAX_EXP/10) {
incr = ldexp (0.5,i);
if (fabs(incr)>DBL_MAX/10.0) {
iter = (unsigned long) (DBL_MAX/fabs(incr));
}
else {
iter = 10ul;
}
doubleTest(chix1, base, incr, epsil, iter);
printf (".");
fflush (stdout);
}
base = DBL_MAX;
for (i=DBL_MIN_EXP; i<DBL_MAX_EXP; i+=DBL_MAX_EXP/10) {
incr = - ldexp (0.5,i);
if (fabs(incr)>DBL_MAX/10.0) {
iter = (unsigned long) (DBL_MAX/fabs(incr));
}
else {
iter = 10ul;
}
doubleTest(chix1, base, incr, epsil, iter);
printf (".");
fflush (stdout);
}
base = - DBL_MAX;
for (i=DBL_MIN_EXP; i<DBL_MAX_EXP; i+=DBL_MAX_EXP/10) {
incr = ldexp (0.5,i);
if (fabs(incr)>DBL_MAX/10.0) {
iter = (unsigned long) (DBL_MAX/fabs(incr));
}
else {
iter = 10ul;
}
doubleTest(chix1, base, incr, epsil, iter);
printf (".");
fflush (stdout);
}
printf ("done\n");
}
/*
* Verify that we can write and then read back
* the same integer value (DBR_LONG)
*/
if (ca_read_access(chix1) && ca_write_access(chix1)) {
dbr_long_t iter, rdbk, incr;
struct dbr_ctrl_long cl;
status = ca_get (DBR_CTRL_LONG, chix1, &cl);
SEVCHK (status, "graphic long fetch failed\n");
status = ca_pend_io (10.0);
SEVCHK (status, "graphic long pend failed\n");
incr = (cl.upper_ctrl_limit - cl.lower_ctrl_limit);
if (incr>=1) {
incr /= 1000;
if (incr==0) {
incr = 1;
}
printf ("dbr_long_t test ");
fflush (stdout);
for (iter=cl.lower_ctrl_limit;
iter<=cl.upper_ctrl_limit; iter+=incr) {
status = ca_put (DBR_LONG, chix1, &iter);
status = ca_get (DBR_LONG, chix1, &rdbk);
status = ca_pend_io (10.0);
SEVCHK (status, "get pend failed\n");
assert (iter == rdbk);
printf (".");
fflush (stdout);
}
printf ("done\n");
}
}
/*
* verify we dont jam up on many uninterrupted
* solicitations
*/
if(ca_read_access(chix4)){
dbr_float_t temp;
printf("Performing multiple get test...");
fflush(stdout);
for(i=0; i<10000; i++){
SEVCHK(ca_get(DBR_FLOAT, chix4, &temp),NULL);
}
SEVCHK(ca_pend_io(2000.0), NULL);
printf("done.\n");
}
else{
printf("Skipped multiple get test - no read access\n");
}
/*
* verify we dont jam up on many uninterrupted requests
*/
if(ca_write_access(chix4)){
printf("Performing multiple put test...");
fflush(stdout);
for(i=0; i<10000; i++){
dbr_double_t fval = 3.3;
status = ca_put(DBR_DOUBLE, chix4, &fval);
SEVCHK(status, NULL);
}
SEVCHK(ca_pend_io(2000.0), NULL);
printf("done.\n");
}
else{
printf("Skipped multiple put test - no write access\n");
}
/*
* verify we dont jam up on many uninterrupted
* solicitations
*/
if(ca_read_access(chix1)){
unsigned count=0u;
printf("Performing multiple get callback test...");
fflush(stdout);
for(i=0; i<10000; i++){
status = ca_array_get_callback(
DBR_FLOAT, 1, chix1, null_event, &count);
SEVCHK(status, NULL);
}
SEVCHK(ca_flush_io(), NULL);
while (count<10000u) {
ca_pend_event(1.0);
printf("waiting...");
fflush(stdout);
}
printf("done.\n");
}
else{
printf("Skipped multiple get cb test - no read access\n");
}
/*
* verify we dont jam up on many uninterrupted
* put callback solicitations
*/
if ( ca_write_access (chix1) && ca_v42_ok (chix1) ) {
unsigned count = 0u;
printf ( "Performing multiple put callback test..." );
fflush ( stdout );
for ( i=0; i<10000; i++ ) {
dbr_float_t fval = 3.3F;
status = ca_array_put_callback (
DBR_FLOAT, 1, chix1, &fval,
null_event, &count );
SEVCHK ( status, NULL );
}
SEVCHK ( ca_flush_io (), NULL );
while ( count < 10000u ) {
ca_pend_event ( 1.0 );
printf ( "waiting..." );
fflush ( stdout );
}
printf ( "done.\n" );
}
else {
printf ( "Skipped multiple put cb test - no write access\n" );
}
/*
* verify that we detect that a large string has been written
*/
if ( ca_write_access (chix1) ) {
dbr_string_t stimStr;
dbr_string_t respStr;
memset(stimStr, 'a', sizeof(stimStr));
status = ca_array_put(DBR_STRING, 1u, chix1, stimStr);
assert(status!=ECA_NORMAL);
sprintf(stimStr, "%u", 8u);
status = ca_array_put(DBR_STRING, 1u, chix1, stimStr);
assert(status==ECA_NORMAL);
status = ca_array_get(DBR_STRING, 1u, chix1, respStr);
assert(status==ECA_NORMAL);
status = ca_pend_io(0.0);
assert(status==ECA_NORMAL);
printf(
"Test fails if stim \"%s\" isnt roughly equiv to resp \"%s\"\n",
stimStr, respStr);
}
else{
printf("Skipped bad string test - no write access\n");
}
if(ca_v42_ok(chix1)){
test_sync_groups(chix1);
}
/* performMonitorUpdateTest (chix4); */
performDeleteTest (chix2);
if (VALID_DB_REQ(ca_field_type(chix4))) {
status = ca_add_event(
DBR_FLOAT,
chix4,
EVENT_ROUTINE,
&monCount,
&monix);
SEVCHK(status, NULL);
SEVCHK(ca_clear_event(monix), NULL);
status = ca_add_event(
DBR_FLOAT,
chix4,
EVENT_ROUTINE,
&monCount,
&monix);
SEVCHK(status, NULL);
}
if (VALID_DB_REQ(ca_field_type(chix4))) {
status = ca_add_event(
DBR_FLOAT,
chix4,
EVENT_ROUTINE,
&monCount,
&monix);
SEVCHK(status, NULL);
SEVCHK(ca_clear_event(monix), NULL);
}
if (VALID_DB_REQ(ca_field_type(chix3))) {
status = ca_add_event(
DBR_FLOAT,
chix3,
EVENT_ROUTINE,
&monCount,
&monix);
SEVCHK(status, NULL);
status = ca_add_event(
DBR_FLOAT,
chix3,
write_event,
&monCount,
&monix);
SEVCHK(status, NULL);
}
pfloat = (dbr_float_t *) calloc(sizeof(*pfloat),NUM);
assert (pfloat);
pdouble = (dbr_double_t *) calloc(sizeof(*pdouble),NUM);
assert (pdouble);
pgrfloat = (struct dbr_gr_float *) calloc(sizeof(*pgrfloat),NUM);
assert (pgrfloat);
if (VALID_DB_REQ(ca_field_type(chix1))) {
for (i = 0; i < NUM; i++) {
for (j = 0; j < NUM; j++)
sprintf(&pstring[j][0], "%ld", j + 100l);
SEVCHK(ca_array_put(
DBR_STRING,
NUM,
chix1,
pstring),
NULL)
SEVCHK(ca_array_get(
DBR_FLOAT,
NUM,
chix1,
pfloat),
NULL)
SEVCHK(ca_array_get(
DBR_DOUBLE,
NUM,
chix1,
pdouble),
NULL)
SEVCHK(ca_array_get(
DBR_GR_FLOAT,
NUM,
chix1,
pgrfloat),
NULL)
}
}
SEVCHK(ca_pend_io(4000.0), NULL);
/*
* array test
* o verifies that we can at least write and read back the same array
* if multiple elements are present
*/
if (VALID_DB_REQ(ca_field_type(chix1))) {
if (ca_element_count(chix1)>1u && ca_read_access(chix1)) {
dbr_float_t *pRF, *pWF, *pEF, *pT1, *pT2;
printf("Performing %lu element array test...",
ca_element_count(chix1) );
fflush(stdout);
pRF = (dbr_float_t *) calloc(ca_element_count(chix1),
sizeof(*pRF));
assert(pRF!=NULL);
pWF = (dbr_float_t *)calloc(ca_element_count(chix1),
sizeof(*pWF));
assert(pWF!=NULL);
/*
* write some random numbers into the array
*/
if (ca_write_access(chix1)) {
pT1 = pWF;
pEF = &pWF[ca_element_count(chix1)];
while(pT1<pEF) {
*pT1++ = (float) rand();
}
status = ca_array_put(
DBR_FLOAT,
ca_element_count(chix1),
chix1,
pWF);
SEVCHK(status, "array write request failed");
}
/*
* read back the array
*/
if (ca_read_access(chix1)) {
status = ca_array_get(
DBR_FLOAT,
ca_element_count(chix1),
chix1,
pRF);
SEVCHK(status, "array read request failed");
status = ca_pend_io(30.0);
SEVCHK(status, "array read failed");
}
/*
* verify read response matches values written
*/
if (ca_read_access(chix1) && ca_write_access(chix1)) {
pEF = &pRF[ca_element_count(chix1)];
pT1 = pRF;
pT2 = pWF;
while (pT1<pEF) {
assert (*pT1 == *pT2);
pT1++;
pT2++;
}
}
/*
* read back the array as strings
*
* this demonstrates that we can operate close to the N*40<=16k limit
*/
if (ca_read_access(chix1)) {
/* clip to 16k message buffer limit */
unsigned maxElem = ((1<<14)-16)/MAX_STRING_SIZE;
unsigned nElem = min(maxElem, ca_element_count(chix1));
char *pRS = malloc(nElem*MAX_STRING_SIZE);
assert(pRS);
status = ca_array_get(
DBR_STRING,
nElem,
chix1,
pRS);
SEVCHK(status, "array read request failed");
status = ca_pend_io(30.0);
SEVCHK(status, "array read failed");
free(pRS);
}
printf("done\n");
free(pRF);
free(pWF);
}
}
SEVCHK(ca_modify_user_name("Willma"), NULL);
SEVCHK(ca_modify_host_name("Bed Rock"), NULL);
{
TS_STAMP end_time;
TS_STAMP start_time;
dbr_double_t delay;
dbr_double_t request = 15.0;
dbr_double_t accuracy;
tsStampGetCurrent(&start_time);
printf("waiting for events for %f sec\n", request);
status = ca_pend_event(request);
if (status != ECA_TIMEOUT) {
SEVCHK(status, NULL);
}
tsStampGetCurrent(&end_time);
delay = tsStampDiffInSeconds(&end_time,&start_time);
accuracy = 100.0*(delay-request)/request;
printf("CA pend event delay accuracy = %f %%\n",
accuracy);
}
/*
* CA pend event delay accuracy test
* (CA asssumes that search requests can be sent
* at least every 25 mS on all supported os)
*/
pend_event_delay_test ( 1.0 );
pend_event_delay_test ( 0.1 );
pend_event_delay_test ( 0.25 );
{
TS_STAMP end_time;
TS_STAMP start_time;
dbr_double_t delay;
tsStampGetCurrent(&start_time);
printf("entering ca_task_exit()\n");
status = ca_task_exit();
SEVCHK(status,NULL);
tsStampGetCurrent(&end_time);
delay = tsStampDiffInSeconds(&end_time,&start_time);
printf("in ca_task_exit() for %f sec\n", delay);
}
if (pfloat) {
free(pfloat);
}
if (pdouble) {
free(pdouble);
}
if (pgrfloat) {
free(pgrfloat);
}
return(0);
}
/*
* pend_event_delay_test()
*/
void pend_event_delay_test(dbr_double_t request)
{
int status;
TS_STAMP end_time;
TS_STAMP start_time;
dbr_double_t delay;
dbr_double_t accuracy;
tsStampGetCurrent(&start_time);
status = ca_pend_event(request);
if (status != ECA_TIMEOUT) {
SEVCHK(status, NULL);
}
tsStampGetCurrent(&end_time);
delay = tsStampDiffInSeconds(&end_time,&start_time);
accuracy = 100.0*(delay-request)/request;
printf("CA pend event delay = %f sec results in error = %f %%\n",
request, accuracy);
assert (fabs(accuracy) < 10.0);
}
/*
* floatTest ()
*/
void floatTest(
chid chan,
dbr_float_t beginValue,
dbr_float_t increment,
dbr_float_t epsilon,
unsigned iterations)
{
unsigned i;
dbr_float_t fval;
dbr_float_t fretval;
int status;
fval = beginValue;
for (i=0; i<iterations; i++) {
fretval = FLT_MAX;
status = ca_put (DBR_FLOAT, chan, &fval);
SEVCHK (status, NULL);
status = ca_get (DBR_FLOAT, chan, &fretval);
SEVCHK (status, NULL);
status = ca_pend_io (10.0);
SEVCHK (status, NULL);
if (fabs(fval-fretval) > epsilon) {
printf ("float test failed val written %f\n", fval);
printf ("float test failed val read %f\n", fretval);
assert(0);
}
fval += increment;
}
}
/*
* doubleTest ()
*/
void doubleTest(
chid chan,
dbr_double_t beginValue,
dbr_double_t increment,
dbr_double_t epsilon,
unsigned iterations)
{
unsigned i;
dbr_double_t fval;
dbr_double_t fretval;
int status;
fval = beginValue;
for (i=0; i<iterations; i++) {
fretval = DBL_MAX;
status = ca_put (DBR_DOUBLE, chan, &fval);
SEVCHK (status, NULL);
status = ca_get (DBR_DOUBLE, chan, &fretval);
SEVCHK (status, NULL);
status = ca_pend_io (100.0);
SEVCHK (status, NULL);
if (fabs(fval-fretval) > epsilon) {
printf ("float test failed val written %f\n", fval);
printf ("float test failed val read %f\n", fretval);
assert(0);
}
fval += increment;
}
}
/*
* null_event ()
*/
void null_event (struct event_handler_args args)
{
unsigned *pInc = (unsigned *) args.usr;
/*
* no pend event in event call back test
*/
#if 0
int status;
status = ca_pend_event (1e-6);
assert (status==ECA_EVDISALLOW);
#endif
if (pInc) {
(*pInc)++;
}
#if 0
if (ca_state(args.chid)==cs_conn) {
status = ca_put (DBR_FLOAT, args.chid, &fval);
SEVCHK(status, "put failed in null_event()");
}
else {
printf("null_event() called for disconnected %s\n",
ca_name(args.chid));
}
#endif
}
/*
* write_event ()
*/
void write_event (struct event_handler_args args)
{
static unsigned iterations = 100;
int status;
dbr_float_t *pFloat = (dbr_float_t *) args.dbr;
dbr_float_t a;
if ( ! args.dbr ) {
return;
}
if ( iterations > 0 ) {
iterations--;
a = *pFloat;
a += 10.1F;
status = ca_array_put ( DBR_FLOAT, 1, args.chid, &a);
SEVCHK ( status, NULL );
SEVCHK ( ca_flush_io (), NULL );
}
}
void conn (struct connection_handler_args args)
{
int status;
if (args.op == CA_OP_CONN_UP) {
# if 0
printf("Channel On Line [%s]\n", ca_name(args.chid));
# endif
status = ca_get_callback (DBR_GR_FLOAT, args.chid, get_cb, NULL);
SEVCHK (status, "get call back in connection handler");
status = ca_flush_io ();
SEVCHK (status, "get call back flush in connection handler");
}
else if (args.op == CA_OP_CONN_DOWN) {
# if 0
printf("Channel Off Line [%s]\n", ca_name(args.chid));
# endif
}
else {
printf("Ukn conn ev\n");
}
}
void get_cb (struct event_handler_args args)
{
if ( ! ( args.status & CA_M_SUCCESS ) ) {
printf("Get cb failed because \"%s\"\n",
ca_message (args.status) );
}
else {
conn_cb_count++;
}
}
/*
* test_sync_groups()
*/
void test_sync_groups(chid chix)
{
int status;
CA_SYNC_GID gid1=0;
CA_SYNC_GID gid2=0;
printf ("Performing sync group test...");
fflush (stdout);
status = ca_sg_create (&gid1);
SEVCHK (status, NULL);
multiple_sg_requests (chix, gid1);
status = ca_sg_reset (gid1);
SEVCHK (status, NULL);
status = ca_sg_create (&gid2);
SEVCHK (status, NULL);
multiple_sg_requests (chix, gid2);
multiple_sg_requests (chix, gid1);
status = ca_sg_test (gid2);
SEVCHK (status, "SYNC GRP2");
status = ca_sg_test (gid1);
SEVCHK (status, "SYNC GRP1");
status = ca_sg_block (gid1, 500.0);
SEVCHK (status, "SYNC GRP1");
status = ca_sg_block (gid2, 500.0);
SEVCHK (status, "SYNC GRP2");
status = ca_sg_delete (gid2);
SEVCHK (status, NULL);
status = ca_sg_create (&gid2);
SEVCHK (status, NULL);
multiple_sg_requests (chix, gid1);
multiple_sg_requests (chix, gid2);
status = ca_sg_block (gid1, 15.0);
SEVCHK (status, "SYNC GRP1");
status = ca_sg_block (gid2, 15.0);
SEVCHK (status, "SYNC GRP2");
status = ca_sg_delete (gid1);
SEVCHK (status, NULL);
status = ca_sg_delete (gid2);
SEVCHK (status, NULL);
printf ("done\n");
}
/*
* multiple_sg_requests()
*/
void multiple_sg_requests(chid chix, CA_SYNC_GID gid)
{
int status;
unsigned i;
static dbr_float_t fvalput = 3.3F;
static dbr_float_t fvalget;
for(i=0; i<1000; i++){
if(ca_write_access(chix)){
status = ca_sg_array_put(
gid,
DBR_FLOAT,
1,
chix,
&fvalput);
SEVCHK(status, NULL);
}
if(ca_read_access(chix)){
status = ca_sg_array_get(
gid,
DBR_FLOAT,
1,
chix,
&fvalget);
SEVCHK(status, NULL);
}
}
}
/*
* accessSecurity_cb()
*/
void accessSecurity_cb(struct access_rights_handler_args args)
{
# ifdef DEBUG
printf( "%s on %s has %s/%s access\n",
ca_name(args.chid),
ca_host_name(args.chid),
ca_read_access(args.chid)?"read":"noread",
ca_write_access(args.chid)?"write":"nowrite");
# endif
}
/*
* performGrEnumTest
*/
void performGrEnumTest (chid chan)
{
struct dbr_gr_enum ge;
unsigned count;
int status;
unsigned i;
ge.no_str = -1;
status = ca_get (DBR_GR_ENUM, chan, &ge);
SEVCHK (status, "DBR_GR_ENUM ca_get()");
status = ca_pend_io (2.0);
assert (status == ECA_NORMAL);
assert ( ge.no_str >= 0 && ge.no_str < NELEMENTS(ge.strs) );
if ( ge.no_str > 0 ) {
printf ("Enum state str = {");
count = (unsigned) ge.no_str;
for (i=0; i<count; i++) {
printf ("\"%s\" ", ge.strs[i]);
}
printf ("}\n");
}
}
/*
* performCtrlDoubleTest
*/
void performCtrlDoubleTest (chid chan)
{
struct dbr_ctrl_double *pCtrlDbl;
dbr_double_t *pDbl;
unsigned nElem = ca_element_count(chan);
double slice = 3.14159 / nElem;
size_t size;
int status;
unsigned i;
if (!ca_write_access(chan)) {
return;
}
if (dbr_value_class[ca_field_type(chan)]!=dbr_class_float) {
return;
}
size = sizeof (*pDbl)*ca_element_count(chan);
pDbl = malloc (size);
assert (pDbl!=NULL);
/*
* initialize the array
*/
for (i=0; i<nElem; i++) {
pDbl[i] = sin (i*slice);
}
/*
* write the array to the PV
*/
status = ca_array_put (DBR_DOUBLE,
ca_element_count(chan),
chan, pDbl);
SEVCHK (status, "performCtrlDoubleTest, ca_array_put");
size = dbr_size_n(DBR_CTRL_DOUBLE, ca_element_count(chan));
pCtrlDbl = (struct dbr_ctrl_double *) malloc (size);
assert (pCtrlDbl!=NULL);
/*
* read the array from the PV
*/
status = ca_array_get (DBR_CTRL_DOUBLE,
ca_element_count(chan),
chan, pCtrlDbl);
SEVCHK (status, "performCtrlDoubleTest, ca_array_get");
status = ca_pend_io (20.0);
assert (status==ECA_NORMAL);
/*
* verify the result
*/
for (i=0; i<nElem; i++) {
double diff = pDbl[i] - sin (i*slice);
assert (fabs(diff) < DBL_EPSILON*4);
}
free (pCtrlDbl);
free (pDbl);
}
typedef struct {
evid id;
dbr_float_t lastValue;
unsigned count;
} eventTest;
/*
* updateTestEvent ()
*/
void updateTestEvent (struct event_handler_args args)
{
eventTest *pET = (eventTest *) args.usr;
pET->lastValue = * (dbr_float_t *) args.dbr;
pET->count++;
}
/*
* performMonitorUpdateTest
*
* 1) verify we can add many monitors at once
* 2) verify that under heavy load the last monitor
* returned is the last modification sent
*/
void performMonitorUpdateTest ( chid chan )
{
eventTest test[1000];
dbr_float_t temp, getResp;
unsigned i, j;
unsigned flowCtrlCount = 0u;
unsigned tries;
if ( ! ca_read_access(chan) ) {
return;
}
printf ( "Performing event subscription update test..." );
fflush ( stdout );
for ( i=0; i<NELEMENTS(test); i++ ) {
test[i].count = 0;
test[i].lastValue = -1.0;
SEVCHK(ca_add_event(DBR_GR_FLOAT, chan, updateTestEvent,
&test[i], &test[i].id),NULL);
}
/*
* force all of the monitors subscription requests to
* complete
*
* NOTE: this hopefully demonstrates that when the
* server is very busy with monitors the client
* is still able to punch through with a request.
*/
SEVCHK (ca_get(DBR_FLOAT,chan,&getResp),NULL);
SEVCHK (ca_pend_io(1000.0),NULL);
/*
* attempt to uncover problems where the last event isnt sent
* and hopefully get into a flow control situation
*/
for (i=0; i<NELEMENTS(test); i++) {
for (j=0; j<=i; j++) {
temp = (float) j;
SEVCHK ( ca_put (DBR_FLOAT, chan, &temp), NULL);
}
/*
* wait for the above to complete
*/
SEVCHK ( ca_get (DBR_FLOAT,chan,&getResp), NULL);
SEVCHK ( ca_pend_io (1000.0), NULL);
assert (getResp==temp);
/*
* wait for all of the monitors to have correct values
*/
tries = 0;
while (1) {
unsigned passCount = 0;
for (j=0; j<NELEMENTS(test); j++) {
assert (test[i].count<=i);
if (test[i].lastValue==temp) {
if (test[i].count<i) {
flowCtrlCount++;
}
test[i].lastValue = -1.0;
test[i].count = 0;
passCount++;
}
}
if ( passCount==NELEMENTS(test) ) {
break;
}
SEVCHK ( ca_pend_event (0.1), 0);
printf (".");
fflush (stdout);
assert (tries<50);
}
}
/*
* delete the event subscriptions
*/
for ( i=0; i<NELEMENTS(test); i++ ) {
SEVCHK ( ca_clear_event (test[i].id), NULL);
}
/*
* force all of the clear event requests to
* complete
*/
SEVCHK ( ca_get (DBR_FLOAT,chan,&temp), NULL);
SEVCHK ( ca_pend_io (1000.0), NULL);
printf ("done.\n");
printf ("flow control bypassed %u events\n", flowCtrlCount);
}
/*
* performDeleteTest
*
* 1) verify we can add many monitors at once
* 2) verify that under heavy load the last monitor
* returned is the last modification sent
*/
void performDeleteTest (chid chan)
{
unsigned count = 0u;
evid mid[1000];
dbr_float_t temp, getResp;
unsigned i;
printf ( "Performing event subscription delete test..." );
fflush ( stdout );
for ( i=0; i<NELEMENTS(mid); i++ ) {
SEVCHK ( ca_add_event(DBR_GR_FLOAT, chan, null_event,
&count, &mid[i]),NULL );
}
/*
* force all of the monitors subscription requests to
* complete
*
* NOTE: this hopefully demonstrates that when the
* server is very busy with monitors the client
* is still able to punch through with a request.
*/
SEVCHK ( ca_get ( DBR_FLOAT,chan,&getResp ), NULL );
SEVCHK ( ca_pend_io ( 1000.0 ), NULL );
printf ( "writing..." );
fflush ( stdout );
/*
* attempt to generate heavy event traffic before initiating
* the monitor delete
*/
if ( ca_write_access (chan) ) {
for (i=0; i<10; i++) {
temp = (float) i;
SEVCHK ( ca_put (DBR_FLOAT, chan, &temp), NULL);
}
}
printf ( "deleting..." );
fflush ( stdout );
/*
* without pausing begin deleting the event suvbscriptions
* while the queue is full
*/
for ( i=0; i < NELEMENTS (mid); i++ ) {
SEVCHK ( ca_clear_event ( mid[i]), NULL );
}
printf ( "flushing..." );
fflush ( stdout );
/*
* force all of the clear event requests to
* complete
*/
SEVCHK ( ca_get (DBR_FLOAT,chan,&temp), NULL );
SEVCHK ( ca_pend_io (1000.0), NULL );
printf ("done.\n");
}