/* * * getConfig() * Get Server Configuration * * */ static int getConfig(void) { int status; char *pstring; long param; status = envGetLongConfigParam( &EPICS_IOC_LOG_PORT, ¶m); if(status>=0){ ioc_log_port = (unsigned short) param; } else { ioc_log_port = 7004U; } status = envGetLongConfigParam( &EPICS_IOC_LOG_FILE_LIMIT, &ioc_log_file_limit); if(status>=0){ if (ioc_log_file_limit<=0) { envFailureNotify (&EPICS_IOC_LOG_FILE_LIMIT); return IOCLS_ERROR; } } else { ioc_log_file_limit = 10000; } pstring = envGetConfigParam( &EPICS_IOC_LOG_FILE_NAME, sizeof ioc_log_file_name, ioc_log_file_name); if(pstring == NULL){ envFailureNotify(&EPICS_IOC_LOG_FILE_NAME); return IOCLS_ERROR; } /* * its ok to not specify the IOC_LOG_FILE_COMMAND */ pstring = envGetConfigParam( &EPICS_IOC_LOG_FILE_COMMAND, sizeof ioc_log_file_command, ioc_log_file_command); return IOCLS_OK; }
long epicsShareAPI envGetBoolConfigParam(const ENV_PARAM *pParam, int *pBool) { char text[20]; if(!envGetConfigParam(pParam, sizeof(text), text)) return -1; *pBool = epicsStrCaseCmp(text, "yes")==0; return 0; }
/*+/subr********************************************************************** * NAME envGetLongConfigParam - get value of an integer config parameter * * DESCRIPTION * Gets the value of a configuration parameter and copies it * into the caller's integer (long) buffer. If the configuration * parameter isn't found in the environment, then the default value for * the parameter is copied. * * If no parameter is found and there is no default, then -1 is * returned and the callers buffer is unmodified. * * RETURNS * 0, or * -1 if an error is encountered * * EXAMPLE * 1. Get the value as a long for the integer environment parameter * EPICS_NUMBER_OF_ITEMS. * * #include "envDefs.h" * long count; * long status; * * status = envGetLongConfigParam(&EPICS_NUMBER_OF_ITEMS, &count); * if (status == 0) { * printf("and the count is: %d\n", count); * } * else { * printf("%s could not be found or was not an integer\n", * EPICS_NUMBER_OF_ITEMS.name); * } * *-*/ long epicsShareAPI envGetLongConfigParam( const ENV_PARAM *pParam,/* I pointer to config param structure */ long *pLong /* O pointer to place to store value */ ) { char text[128]; char *ptext; int count; ptext = envGetConfigParam(pParam, sizeof text, text); if (ptext) { count = sscanf(text, "%ld", pLong); if (count == 1) return 0; (void)fprintf(stderr,"Unable to find an integer in %s=%s\n", pParam->name, text); } return -1; }
/*+/subr********************************************************************** * NAME envGetDoubleConfigParam - get value of a double configuration parameter * * DESCRIPTION * Gets the value of a configuration parameter and copies it into the * caller's real (double) buffer. If the configuration parameter isn't * found in the environment, then the default value for the parameter * is copied. * * If no parameter is found and there is no default, then -1 is * returned and the caller's buffer is unmodified. * * RETURNS * 0, or * -1 if an error is encountered * * EXAMPLE * 1. Get the value for the real environment parameter EPICS_THRESHOLD. * * #include "envDefs.h" * double threshold; * long status; * * status = envGetDoubleConfigParam(&EPICS_THRESHOLD, &threshold); * if (status == 0) { * printf("the threshold is: %lf\n", threshold); * } * else { * printf("%s could not be found or was not a real number\n", * EPICS_THRESHOLD.name); * } * *-*/ long epicsShareAPI envGetDoubleConfigParam( const ENV_PARAM *pParam,/* I pointer to config param structure */ double *pDouble /* O pointer to place to store value */ ) { char text[128]; char *ptext; int count; ptext = envGetConfigParam(pParam, sizeof text, text); if (ptext != NULL) { count = epicsScanDouble(text, pDouble); if (count == 1) { return 0; } (void)fprintf(stderr,"Unable to find a real number in %s=%s\n", pParam->name, text); } return -1; }
/*+/subr********************************************************************** * NAME envGetInetAddrConfigParam - get value of an inet addr config parameter * * DESCRIPTION * Gets the value of a configuration parameter and copies it into * the caller's (struct in_addr) buffer. If the configuration parameter * isn't found in the environment, then the default value for * the parameter is copied. * * If no parameter is found and there is no default, then -1 is * returned and the callers buffer is unmodified. * * RETURNS * 0, or * -1 if an error is encountered * * EXAMPLE * 1. Get the value for the inet address environment parameter EPICS_INET. * * #include "envDefs.h" * struct in_addr addr; * long status; * * status = envGetInetAddrConfigParam(&EPICS_INET, &addr); * if (status == 0) { * printf("the s_addr is: %x\n", addr.s_addr); * } * else { * printf("%s could not be found or was not an inet address\n", * EPICS_INET.name); * } * *-*/ long epicsShareAPI envGetInetAddrConfigParam( const ENV_PARAM *pParam,/* I pointer to config param structure */ struct in_addr *pAddr /* O pointer to struct to receive inet addr */ ) { char text[128]; char *ptext; long status; struct sockaddr_in sin; ptext = envGetConfigParam(pParam, sizeof text, text); if (ptext) { status = aToIPAddr (text, 0u, &sin); if (status == 0) { *pAddr = sin.sin_addr; return 0; } (void)fprintf(stderr,"Unable to find an IP address or valid host name in %s=%s\n", pParam->name, text); } return -1; }
/* * RSRV_ONLINE_NOTIFY_TASK */ void rsrv_online_notify_task(void *pParm) { unsigned priorityOfSelf = epicsThreadGetPrioritySelf (); osiSockAddrNode *pNode; double delay; double maxdelay; long longStatus; double maxPeriod; caHdr msg; int status; SOCKET sock; int intTrue = TRUE; unsigned short port; ca_uint32_t beaconCounter = 0; char * pStr; int autoBeaconAddr; ELLLIST autoAddrList; char buf[16]; unsigned priorityOfUDP; epicsThreadBooleanStatus tbs; epicsThreadId tid; taskwdInsert (epicsThreadGetIdSelf(),NULL,NULL); if ( envGetConfigParamPtr ( & EPICS_CAS_BEACON_PERIOD ) ) { longStatus = envGetDoubleConfigParam ( & EPICS_CAS_BEACON_PERIOD, & maxPeriod ); } else { longStatus = envGetDoubleConfigParam ( & EPICS_CA_BEACON_PERIOD, & maxPeriod ); } if (longStatus || maxPeriod<=0.0) { maxPeriod = 15.0; epicsPrintf ("EPICS \"%s\" float fetch failed\n", EPICS_CAS_BEACON_PERIOD.name); epicsPrintf ("Setting \"%s\" = %f\n", EPICS_CAS_BEACON_PERIOD.name, maxPeriod); } delay = 0.02; /* initial beacon period in sec */ maxdelay = maxPeriod; /* * Open the socket. * Use ARPA Internet address format and datagram socket. * Format described in <sys/socket.h>. */ if ( (sock = epicsSocketCreate (AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) { errlogPrintf ("CAS: online socket creation error\n"); epicsThreadSuspendSelf (); } status = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (char *)&intTrue, sizeof(intTrue)); if (status<0) { errlogPrintf ("CAS: online socket set up error\n"); epicsThreadSuspendSelf (); } { /* * this connect is to supress a warning message on Linux * when we shutdown the read side of the socket. If it * fails (and it will on old ip kernels) we just ignore * the failure. */ osiSockAddr sockAddr; sockAddr.ia.sin_family = AF_UNSPEC; sockAddr.ia.sin_port = htons ( 0 ); sockAddr.ia.sin_addr.s_addr = htonl (0); connect ( sock, & sockAddr.sa, sizeof ( sockAddr.sa ) ); shutdown ( sock, SHUT_RD ); } memset((char *)&msg, 0, sizeof msg); msg.m_cmmd = htons (CA_PROTO_RSRV_IS_UP); msg.m_count = htons (ca_server_port); msg.m_dataType = htons (CA_MINOR_PROTOCOL_REVISION); ellInit ( & beaconAddrList ); ellInit ( & autoAddrList ); pStr = envGetConfigParam(&EPICS_CAS_AUTO_BEACON_ADDR_LIST, sizeof(buf), buf); if ( ! pStr ) { pStr = envGetConfigParam(&EPICS_CA_AUTO_ADDR_LIST, sizeof(buf), buf); } if (pStr) { if (strstr(pStr,"no")||strstr(pStr,"NO")) { autoBeaconAddr = FALSE; } else if (strstr(pStr,"yes")||strstr(pStr,"YES")) { autoBeaconAddr = TRUE; } else { fprintf(stderr, "CAS: EPICS_CA(S)_AUTO_ADDR_LIST = \"%s\"? Assuming \"YES\"\n", pStr); autoBeaconAddr = TRUE; } } else { autoBeaconAddr = TRUE; } /* * load user and auto configured * broadcast address list */ if (envGetConfigParamPtr(&EPICS_CAS_BEACON_PORT)) { port = envGetInetPortConfigParam (&EPICS_CAS_BEACON_PORT, (unsigned short) CA_REPEATER_PORT ); } else { port = envGetInetPortConfigParam (&EPICS_CA_REPEATER_PORT, (unsigned short) CA_REPEATER_PORT ); } /* * discover beacon addresses associated with this interface */ if ( autoBeaconAddr ) { osiSockAddr addr; ELLLIST tmpList; ellInit ( &tmpList ); addr.ia.sin_family = AF_UNSPEC; osiSockDiscoverBroadcastAddresses (&tmpList, sock, &addr); forcePort ( &tmpList, port ); removeDuplicateAddresses ( &autoAddrList, &tmpList, 1 ); } /* * by default use EPICS_CA_ADDR_LIST for the * beacon address list */ { const ENV_PARAM *pParam; if (envGetConfigParamPtr(&EPICS_CAS_INTF_ADDR_LIST) || envGetConfigParamPtr(&EPICS_CAS_BEACON_ADDR_LIST)) { pParam = &EPICS_CAS_BEACON_ADDR_LIST; } else { pParam = &EPICS_CA_ADDR_LIST; } /* * add in the configured addresses */ addAddrToChannelAccessAddressList ( &autoAddrList, pParam, port, pParam == &EPICS_CA_ADDR_LIST ); } removeDuplicateAddresses ( &beaconAddrList, &autoAddrList, 0 ); if ( ellCount ( &beaconAddrList ) == 0 ) { errlogPrintf ("The CA server's beacon address list was empty after initialization?\n"); } # ifdef DEBUG printChannelAccessAddressList (&beaconAddrList); # endif tbs = epicsThreadHighestPriorityLevelBelow ( priorityOfSelf, &priorityOfUDP ); if ( tbs != epicsThreadBooleanStatusSuccess ) { priorityOfUDP = priorityOfSelf; } casudp_startStopEvent = epicsEventMustCreate(epicsEventEmpty); casudp_ctl = ctlPause; tid = epicsThreadCreate ( "CAS-UDP", priorityOfUDP, epicsThreadGetStackSize (epicsThreadStackMedium), cast_server, 0 ); if ( tid == 0 ) { epicsPrintf ( "CAS: unable to start UDP daemon thread\n" ); } epicsEventMustWait(casudp_startStopEvent); epicsEventSignal(beacon_startStopEvent); while (TRUE) { pNode = (osiSockAddrNode *) ellFirst (&beaconAddrList); while (pNode) { char buf[64]; status = connect (sock, &pNode->addr.sa, sizeof(pNode->addr.sa)); if (status<0) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); ipAddrToDottedIP (&pNode->addr.ia, buf, sizeof(buf)); errlogPrintf ( "%s: CA beacon routing (connect to \"%s\") error was \"%s\"\n", __FILE__, buf, sockErrBuf); } else { struct sockaddr_in if_addr; osiSocklen_t size = sizeof (if_addr); status = getsockname (sock, (struct sockaddr *) &if_addr, &size); if (status<0) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); errlogPrintf ( "%s: CA beacon routing (getsockname) error was \"%s\"\n", __FILE__, sockErrBuf); } else if (if_addr.sin_family==AF_INET) { msg.m_available = if_addr.sin_addr.s_addr; msg.m_cid = htonl ( beaconCounter ); status = send (sock, (char *)&msg, sizeof(msg), 0); if (status < 0) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); ipAddrToDottedIP (&pNode->addr.ia, buf, sizeof(buf)); errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\"\n", __FILE__, buf, sockErrBuf); } else { assert (status == sizeof(msg)); } } } pNode = (osiSockAddrNode *) pNode->node.next; } epicsThreadSleep(delay); if (delay<maxdelay) { delay *= 2.0; if (delay>maxdelay) { delay = maxdelay; } } beaconCounter++; /* expected to overflow */ while (beacon_ctl == ctlPause) { epicsThreadSleep(0.1); delay = 0.02; /* Restart beacon timing if paused */ } } }
/* * configureChannelAccessAddressList () */ extern "C" void epicsShareAPI configureChannelAccessAddressList ( ELLLIST *pList, SOCKET sock, unsigned short port ) { ELLLIST tmpList; char *pstr; char yesno[32u]; int yes; /* * dont load the list twice */ assert ( ellCount (pList) == 0 ); // X aCC 392 ellInit ( &tmpList ); // X aCC 392 /* * Check to see if the user has disabled * initializing the search b-cast list * from the interfaces found. */ yes = true; pstr = envGetConfigParam ( &EPICS_CA_AUTO_ADDR_LIST, sizeof (yesno), yesno ); if ( pstr ) { if ( strstr ( pstr, "no" ) || strstr ( pstr, "NO" ) ) { yes = false; } } /* * LOCK is for piiu->destAddr list * (lock outside because this is used by the server also) */ if (yes) { ELLLIST bcastList; osiSockAddr addr; ellInit ( &bcastList ); // X aCC 392 addr.ia.sin_family = AF_UNSPEC; osiSockDiscoverBroadcastAddresses ( &bcastList, sock, &addr ); forcePort ( &bcastList, port ); removeDuplicateAddresses ( &tmpList, &bcastList, 1 ); if ( ellCount ( &tmpList ) == 0 ) { // X aCC 392 osiSockAddrNode *pNewNode; pNewNode = (osiSockAddrNode *) calloc ( 1, sizeof (*pNewNode) ); if ( pNewNode ) { /* * if no interfaces found then look for local channels * with the loop back interface */ pNewNode->addr.ia.sin_family = AF_INET; pNewNode->addr.ia.sin_addr.s_addr = htonl ( INADDR_LOOPBACK ); pNewNode->addr.ia.sin_port = htons ( port ); ellAdd ( &tmpList, &pNewNode->node ); } else { errlogPrintf ( "configureChannelAccessAddressList(): no memory available for configuration\n" ); } } } addAddrToChannelAccessAddressList ( &tmpList, &EPICS_CA_ADDR_LIST, port, false ); removeDuplicateAddresses ( pList, &tmpList, 0 ); }
static void medmUpdateChannelCb(struct event_handler_args args) { Channel *pCh = (Channel *)ca_puser(args.chid); Boolean statusChanged = False; Boolean severityChanged = False; Boolean zeroAndNoneZeroTransition = False; Record *pr; double value; int nBytes; int allocBytes; #if DEBUG_CHANNEL_CB || DEBUG_LARGE_ARRAY const char *pvname=ca_name(args.chid); print("medmUpdateChannelCb: %s\n",pvname); if(args.status != ECA_NORMAL) { char buf[80]; envGetConfigParam(&EPICS_CA_MAX_ARRAY_BYTES,80,buf); buf[79]='\0'; print("EPICS_CA_MAX_ARRAY_BYTES: %s\n",buf); } #endif /* Increment the event counter */ caTask.caEventCount++; /* Check for valid values */ /* Same as for updateGraphicalInfoCb */ /* Don't need to check for read access, checking ECA_NORMAL is enough */ if(globalDisplayListTraversalMode != DL_EXECUTE) return; if(args.status != ECA_NORMAL) { medmPostMsg(0,"medmUpdateChannelCb: Bad status [%d] for %s: %s\n", args.status, ca_name(args.chid)?ca_name(args.chid):"Name Unknown", ca_message(args.status)); return; } if(!args.dbr) { medmPostMsg(0,"medmUpdateChannelCb: Invalid data for [%s]\n", ca_name(args.chid)?ca_name(args.chid):"Name Unknown"); return; } if(!pCh || !pCh->chid || !pCh->pr) { medmPostMsg(0,"medmUpdateChannelCb: " "Invalid channel information for [%s]\n", ca_name(args.chid)?ca_name(args.chid):"Name Unknown"); return; } if(pCh->chid != args.chid) { medmPostMsg(0,"medmUpdateChannelCb: chid from args [%x] " "does not match chid from channel [%x]\n" " [%s]\n", args.chid, pCh->chid, ca_name(args.chid)?ca_name(args.chid):"Name Unknown"); return; } pr = pCh->pr; /* Allocate space for the data */ nBytes = dbr_size_n(args.type, args.count); if(!pCh->data) { /* Allocate maximum space for the variable array data */ if(pr->currentCount == -2) { allocBytes=dbr_size_n(args.type, pr->elementCount); } else { allocBytes=nBytes; } /* No previous data, allocate */ pCh->data = (dataBuf *)malloc(allocBytes); pCh->size = allocBytes; if(!pCh->data) { medmPostMsg(1,"medmUpdateChannelCb: Memory allocation error [%s]\n", ca_name(args.chid)?ca_name(args.chid):"Name Unknown"); return; } } else if(pCh->size < nBytes) { /* Previous data exists but is too small * Free it and allocate it again */ free((char *)pCh->data); pCh->data = (dataBuf *)malloc(nBytes); pCh->size = nBytes; if(pCh->data == NULL) { medmPostMsg(1,"medmUpdateChannelCb: Memory reallocation error" " [%s]\n", ca_name(args.chid)?ca_name(args.chid):"Name Unknown"); return; } } pr->currentCount=args.count; #ifdef __USING_TIME_STAMP__ /* Copy the returned time stamp to the Record */ pr->time = ((dataBuf *)args.dbr)->s.stamp; #endif /* Set the array pointer in the Record to point to the value member of the * appropriate struct stored in the Channel * (The returned data is not stored there yet) */ switch (ca_field_type(args.chid)) { case DBF_STRING: pr->array = (XtPointer)pCh->data->s.value; break; case DBF_ENUM: pr->array = (XtPointer)&(pCh->data->e.value); break; case DBF_CHAR: pr->array = (XtPointer)&(pCh->data->c.value); break; case DBF_INT: pr->array = (XtPointer)&(pCh->data->i.value); break; case DBF_LONG: pr->array = (XtPointer)&(pCh->data->l.value); break; case DBF_FLOAT: pr->array = (XtPointer)&(pCh->data->f.value); break; case DBF_DOUBLE: pr->array = (XtPointer)&(pCh->data->d.value); break; default: break; } /* For strings and arrays copy the returned data to the Channel * (The space is allocated but the data is not stored otherwise) */ if(ca_field_type(args.chid) == DBF_STRING || ca_element_count(args.chid) > 1) { memcpy((void *)pCh->data, args.dbr, nBytes); } /* Copy the value from the returned data to the Record */ switch (ca_field_type(args.chid)) { case DBF_STRING: value = 0.0; break; case DBF_ENUM: value = (double)((dataBuf *)(args.dbr))->e.value; break; case DBF_CHAR: value = (double)((dataBuf *)(args.dbr))->c.value; break; case DBF_INT: value = (double)((dataBuf *)(args.dbr))->i.value; break; case DBF_LONG: value = (double)((dataBuf *)(args.dbr))->l.value; break; case DBF_FLOAT: value = (double)((dataBuf *)(args.dbr))->f.value; break; case DBF_DOUBLE: value = ((dataBuf *)(args.dbr))->d.value; #if DEBUG_SLIDER if(value > 150.0 || value < -150.0) { print("medmUpdateChannelCb: %g\n",value); } #endif break; default: value = 0.0; break; } /* Mark zero to nonzero transition */ if(((value == 0.0) && (pr->value != 0.0)) || ((value != 0.0) && (pr->value == 0.0))) zeroAndNoneZeroTransition = True; /* Mark status changed */ if(pr->status != ((dataBuf *)(args.dbr))->d.status) { pr->status = ((dataBuf *)(args.dbr))->d.status; statusChanged = True; } /* Mark severity changed */ if(pr->severity != ((dataBuf *)(args.dbr))->d.severity) { pr->severity = ((dataBuf *)(args.dbr))->d.severity; severityChanged = True; } /* Set the new value into the record */ pr->value = value; #if DEBUG_ERASE print("medmUpdateChannelCb: [%x]%s %g\n", pr, pr->name, pr->value); #endif /* Call the update value callback if there is a monitored change */ if(pCh->pr->updateValueCb) { if(pr->monitorValueChanged) { pr->updateValueCb((XtPointer)pr); } else if(pr->monitorStatusChanged && statusChanged) { pr->updateValueCb((XtPointer)pr); } else if(pr->monitorSeverityChanged && severityChanged) { pr->updateValueCb((XtPointer)pr); } else if(pr->monitorZeroAndNoneZeroTransition && zeroAndNoneZeroTransition) { pr->updateValueCb((XtPointer)pr); } } }