/* * callback from connection handler: change the state of the channel valid * flag depending on the connection being up or down. * ASSUMPTIONS: chan_id is valid. */ static void connect_callback(struct connection_handler_args args) { Connector *conp; Channel *chan = ca_puser( args.chid); int status; DEBUGP printf("connect callback %p\n", chan); switch( args.op) { case CA_OP_CONN_UP: if( chan->initData == 1) { chan->maxelement = ca_element_count(chan->chan_id); chan->chan_type = ca_field_type(chan->chan_id); chan->initData = 0; } /* * note that a dropped and recreated connection can cause a free and alloc. This * is not always redundant, as software may have restarted with different sizes * for the field! */ if( chan->createData == 1 ) { if( chan->dataval) free( chan->dataval); chan->dataval = calloc(dbr_size[chan->chan_type], chan->maxelement+1); } chan->readAccess = ca_read_access( chan->chan_id); chan->writeAccess = ca_write_access( chan->chan_id); status = ca_array_get_callback( dbf_type_to_DBR_CTRL(ca_field_type(chan->chan_id)), 1, chan->chan_id, getChanInfo, (void*)chan); SEVCHK(status, "connect_callback : ca_get_DBR_CTRL_event failed"); status = ca_replace_access_rights_event( chan->chan_id, getAccessRights); SEVCHK(status, "connect_callback : ca_replace_access_rights_event failed"); chan->valid = 1; chan->outstanding = 0; if( chan->monitor) { chan->status = 100; /* MAGIC: an absurd status */ status = ca_add_array_event(dbf_type_to_DBR_STS(chan->chan_type), chan->maxelement, chan->chan_id, monitorCallback, chan, (double) 0.0, (double) 0.0, (double) 0.0, &(chan->eventId)); SEVCHK(status, "connect_callback : ca_add_event failed"); status = ca_flush_io(); SEVCHK(status, "connect_callback : ca_flush_io failed"); } break; case CA_OP_CONN_DOWN: if( chan->valid && chan->eventId) ca_clear_event(chan->eventId); chan->valid = 0; chan->status = 99; /* * update the access rights and severity for all the connectors */ for(conp=chan->first_connector; conp ; conp=conp->next) { if(conp->newAccess) (*conp->newAccess)(conp); if( conp->newState) (*conp->newState)(conp); } break; default: break; } return; }
static void medmConnectEventCb(struct connection_handler_args args) { int status; Channel *pCh = (Channel *)ca_puser(args.chid); int count; /* Increment the event counter */ caTask.caEventCount++; /* Check for valid values */ if(globalDisplayListTraversalMode != DL_EXECUTE) return; if(!pCh || !pCh->chid || !pCh->pr) { medmPostMsg(0,"medmConnectEventCb: Invalid channel information\n"); return; } /* Do a get every time a channel is connected or reconnected and has * read access. The get will cause the graphical info callback to * be called */ if(args.op == CA_OP_CONN_UP && ca_read_access(pCh->chid)) { status = ca_array_get_callback( dbf_type_to_DBR_CTRL(ca_field_type(args.chid)), 1, args.chid, medmUpdateGraphicalInfoCb, NULL); if(status != ECA_NORMAL) { medmPostMsg(0,"medmConnectEventCb: " "ca_array_get_callback [%s]:\n %s\n", ca_name(pCh->chid)?ca_name(pCh->chid):"Unknown", ca_message(status)); #if DEBUG_CONNECTION # if 0 system("netstat | grep iocacis"); # endif print(" pCh->chid %s args.chid\n", pCh->chid == args.chid?"==":"!="); print( " Channel Name: %s\n" " State: %s\n" " Native Type: %s\n" " Native Count: %hu\n" " Access: %s%s\n" " IOC: %s\n", args.chid?ca_name(args.chid):"Unavailable", args.chid?ca_state(args.chid) == cs_never_conn?"Never": ca_state(args.chid) == cs_prev_conn?"Prev": ca_state(args.chid) == cs_conn?"Conn": ca_state(args.chid) == cs_closed?"Closed":"Unknown":"Unavailable", args.chid?dbf_type_to_text(ca_field_type(args.chid)):"Unavailable", args.chid?ca_element_count(args.chid):0, args.chid?(ca_read_access(args.chid)?"R":"None"):"Unavailable", args.chid?(ca_write_access(args.chid)?"W":""):"", args.chid?ca_host_name(args.chid):"Unavailable"); #endif } } /* Handle four cases: connected or not and previously connected or not */ if(args.op == CA_OP_CONN_UP) { /* Connected */ if(pCh->previouslyConnected == False) { /* Connected and not previously connected */ /* Set these first so they will be right for the updateValueCb */ pCh->pr->elementCount = ca_element_count(pCh->chid); pCh->pr->dataType = ca_field_type(args.chid); pCh->pr->connected = True; caTask.channelConnected++; /* Add the access-rights-change callback and the significant-change (value, alarm or severity) callback. Don't call the updateValueCb because ca_replace_access_rights_event will call it. */ status = ca_replace_access_rights_event( pCh->chid,medmReplaceAccessRightsEventCb); if(status != ECA_NORMAL) { medmPostMsg(0,"medmConnectEventCb: " "ca_replace_access_rights_event [%s]: %s\n", ca_name(pCh->chid)?ca_name(pCh->chid):"Unknown", ca_message(status)); } if(pCh->pr->currentCount == -2) { count=0; } else { count=ca_element_count(pCh->chid); } #ifdef __USING_TIME_STAMP__ status = ca_add_array_event( dbf_type_to_DBR_TIME(ca_field_type(pCh->chid)), count, pCh->chid, medmUpdateChannelCb, pCh, 0.0,0.0,0.0, &(pCh->evid)); #else status = ca_add_array_event( dbf_type_to_DBR_STS(ca_field_type(pCh->chid)), count, pCh->chid, medmUpdateChannelCb, pCh, 0.0,0.0,0.0, &(pCh->evid)); #endif if(status != ECA_NORMAL) { /* Set the pointer to NULL in case CA didn't. We don't want to use it or clear it later. */ #if DEBUG_CONNECTION if(!pCh->evid) { print("medmConnectEventCb: ca_add_array_event: \n" " status[%d] != ECA_NORMAL and pCh->evid != NULL\n", status); } #endif pCh->evid = NULL; medmPostMsg(0,"medmConnectEventCb: " "ca_add_array_event [%s]:\n %s\n", ca_name(pCh->chid)?ca_name(pCh->chid):"Unknown", ca_message(status)); #if DEBUG_CONNECTION # if 0 system("netstat | grep iocacis"); # endif print(" pCh->chid %s args.chid\n", pCh->chid == args.chid?"==":"!="); print( " Channel Name: %s\n" " State: %s\n" " Native Type: %s\n" " Native Count: %hu\n" " Access: %s%s\n" " IOC: %s\n", args.chid?ca_name(args.chid):"Unavailable", args.chid?ca_state(args.chid) == cs_never_conn?"Never": ca_state(args.chid) == cs_prev_conn?"Prev": ca_state(args.chid) == cs_conn?"Conn": ca_state(args.chid) == cs_closed?"Closed":"Unknown":"Unavailable", args.chid?dbf_type_to_text(ca_field_type(args.chid)):"Unavailable", args.chid?ca_element_count(args.chid):0, args.chid?(ca_read_access(args.chid)?"R":"None"):"Unavailable", args.chid?(ca_write_access(args.chid)?"W":""):"", args.chid?ca_host_name(args.chid):"Unavailable"); #endif } /* Set this one last so ca_replace_access_rights_event can use the old value */ pCh->previouslyConnected = True; } else { /* Connected and previously connected */ pCh->pr->connected = True; caTask.channelConnected++; if(pCh->pr->updateValueCb) pCh->pr->updateValueCb((XtPointer)pCh->pr); } } else { /* Not connected */ if(pCh->previouslyConnected == False) { /* Not connected and not previously connected */ /* Probably doesn't happen -- if CA can't connect, this * routine never gets called */ pCh->pr->connected = False; } else { /* Not connected but previously connected */ pCh->pr->connected = False; caTask.channelConnected--; if(pCh->pr->updateValueCb) pCh->pr->updateValueCb((XtPointer)pCh->pr); } } }