diff --git a/src/ca/gsd_sync_subr.c b/src/ca/gsd_sync_subr.c new file mode 100644 index 000000000..030dc8c39 --- /dev/null +++ b/src/ca/gsd_sync_subr.c @@ -0,0 +1,1147 @@ +/* +*************************************************** +* File: /home/lando/slentz/sync/unix_gsd_sync.c +* Modifications: +* 09/18/90 ges creation +* 09/21/90 ges desk check +* 10/15/90 ges add gsd_copy_buffer routine +* 10/17/90 ges clean-up and add to documentation +* add timeout parameter to gsd_sync_read +* 11/01/90 ges add gsd_sync_clear function +* 11/05/90 ges add linked list event data approach +* 11/16/90 ges make special UNIX version for OPI +* 11/20/90 ges make gsd_sync_init return VOID * for consistency +* between UNIX and VxWorks versions +* 11/26/90 ges use ca_build_and_connect in gsd_sync_init +* 11/27/90 ges add NULL ptr return 0 to gsd_tss_eq +* add NULL ptr return 0 to gsd_tss_gtr +* change from (gsd_tss_gtr) to (gsd_tss_gtr || +* gsd_tss_eq) in gsd_findlargest_ts +* 12/14/90 ges add events at gsd_sync_read instead of gsd_sync_init +* return most recent chan data if chan failed to +* produce data with the associated time stamp +* Compile: +* for Unix: +* compile: +* make +* execute: +* unix_gsd_sync +*------------------------------------------------- +* Usage: +* 1) A single initial call to gsd_sync_init must be made before +* any additional calls to gsd_sync_read". +* 2) Calls to UNIX version of "gsd_sync_read": +* 1) returns 1 if done, either timed out or has valid +* synchronous data on all channels of interest +* returns 0 if not done, allowing the calling program +* to continue polling for done by repeated +* calls to gsd_sync_read +* 2) with NEXTSET_SYNC_DATA: Pushes any currently saved valid +* event data down to the "previous" level store. +* At invocation, time stamp data monitors are established +* for each channel named. +* All event data is then received and stored in sequence +* until either: +* 1) event data containg identical time stamps has been +* received from all channels named (this time stamp +* is selected to be associated with this sync +* data call) or +* 2) time out occurs (in this case the most recent +* time stamp of all the collected event data +* is selected as the time stamp associated with +* this sync data call) +* Data that has the associated time stamp +* will be marked as valid and will be copied to the +* synchronous data buffers. If a channel has no data with +* the associated time stamp, then its most recent received +* data will be copied to the synchronous data buffers and +* will be marked not valid. +* 3) with PREVIOUS_SYNC_DATA: yields the collected and +* saved data that currently reside in the "previous" +* level store. +* 3) Interpretation of flags: +* 1) gsd_sync_data.svalid: is 1 if new sync event data has come in +* over that channel during its synchronous read window. +* The pointer gsd_sync_data.pSdata points to the +* DBR_TIME_XXXX structure containing this new data. +* : is 0 if no new synchronous +* event data has come in +* over that channel during its synchronous read window. +* The pointer gsd_sync_data.pSdata points the the +* DBR_TIME_XXXX structure and will contain the remaining +* old residual data unchanged from the most recent +* successful synchronous event. +* 2) gsd_sync_data.pSdata: is 0 (i.e. NULL) if that channel +* has never established network connection. If NULL then +* no DBR_TIME_XXXX data is yet available. +*************************************************** +*/ + +#define VOID void +#define logMsg printf +#include +#include +#include +#include +#include +#include +#include +#include + + +/* +*-------------------------------------------- +* Function prototypes +*-------------------------------------------- +*/ +VOID gsd_fd_register(); +VOID gsd_ca_service(); + +VOID gsd_ca_task_initialize(); +VOID gsd_ca_pend_event(); +VOID *gsd_sync_init(); +VOID gsd_connevent_handler(); +VOID gsd_event_handler(); +int gsd_sync_read(); +TS_STAMP *gsd_complete_set(); +VOID gsd_copy_buffer(); +int gsd_timeout(); +VOID gsd_sync_clear(); +int gsd_tss_within_delta(); +int gsd_tss_eq(); +int gsd_tss_gtr(); +TS_STAMP *gsd_findlargest_ts(); +VOID gsd_freeevent_mem(); +VOID gsd_syncset_findcopy(); +TS_STAMP *gsd_get_ts(); + + +/*-------------------------------------------*/ + +struct gsd_sync_linked { + struct gsd_sync_linked *pNstruct; /* ptr to next gsd_sync_linked struct */ + VOID *pNdata; /* ptr to event TBR_TIME_xxxx data */ +}; + +struct gsd_sync_ctrl { + struct gsd_sync_data *pDstruct; /* ptr to assoc gsd_sync_data struc */ + int nvalid; /* next data's valid flag */ + int avalid; /* already data's valid flag */ + VOID *pNdata; /* ptr to next data set */ + VOID *pAdata; /* ptr to immediately previous (already) data set */ + struct gsd_sync_linked *pNstruct; /* ptr to head linked data sets */ + int en_event; /* enable the storage of event data */ + evid event_id; /* event id storage for this channel */ +}; + +struct gsd_sync_compctrl { + struct timeval start_time; /* sys time store at initial call */ + struct gsd_sync_ctrl *pCtrl; /* ptr to gsd_sync_ctrl array */ +}; + +/*---------------------------------------------*/ +#define ONESEC_IN_TICKS 60 +#define PEND_EVENT_DELAY 0.0001 /* standard 0.0001sec event delay */ +#define USEC_TIME_OUT 100 /* 100 usec timeval's timeout */ + + + + +/* test only !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ +/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ +/* +*------------------------------------------------------ +* For stand-alone operation remove the comments that bracket this +* mainline driver and call: +* main() +*------------------------------------------------------ +*/ +#define CHAN_COUNT 4 /* 4 channels for this example test code */ +#define SYNC_TIMEOUT 1.0 /* timeout for data reception in float secs */ + +struct gsd_sync_data sync_data_array[CHAN_COUNT]; +struct gsd_sync_data *pSync_data_array = &sync_data_array[0]; +/* +main() +{ + VOID *pfdctx = NULL; + struct gsd_sync_compctrl *pSync_compctrl; + struct gsd_sync_ctrl *pSync_ctrl; + int i; + + sync_data_array[0].pName = "IOC21:CALC:S00:00"; + sync_data_array[1].pName = "IOC21:CALC:S00:01"; + sync_data_array[2].pName = "BSD_41N:00:00"; + sync_data_array[3].pName = "BSD_21:00:00"; + + SEVCHK(ca_task_initialize(), + "main: C.A. initialize failure.\n"); + pSync_compctrl = (struct gsd_sync_compctrl *) + gsd_sync_init(pSync_data_array, CHAN_COUNT, &pfdctx, NULL); + if(NULL == pSync_compctrl) { + logMsg("unable to continue, gsd_sync_init failed\n"); + return 1; + } + pSync_ctrl = pSync_compctrl->pCtrl; + + + gsd_sync_read(PREVIOUS_SYNC_DATA, pSync_compctrl, CHAN_COUNT, &pfdctx, + SYNC_TIMEOUT); + logMsg("result of sync_read(PREVIOUS_SYNC_DATA)\n"); + for (i = 0; i < CHAN_COUNT; ++i) { + logMsg("%s valid = %d ptr = %d \n", + (pSync_ctrl->pDstruct)->pName, (pSync_ctrl->pDstruct)->svalid, + (pSync_ctrl->pDstruct)->pSdata); + if((pSync_ctrl->pDstruct)->pSdata) { + logMsg("ts sec = %ld ts nsec = %ld value = %f\n", + ((struct dbr_time_float *) + ((pSync_ctrl->pDstruct)->pSdata))->stamp.secPastEpoch, + ((struct dbr_time_float *) + ((pSync_ctrl->pDstruct)->pSdata))->stamp.nsec, + ((struct dbr_time_float*) + ((pSync_ctrl->pDstruct)->pSdata))->value); + } + ++pSync_ctrl; + } + pSync_ctrl = pSync_compctrl->pCtrl; + logMsg("\n"); + + + while(!gsd_sync_read(NEXTSET_SYNC_DATA, pSync_compctrl, CHAN_COUNT, &pfdctx, + SYNC_TIMEOUT)) { + ; + } + logMsg("result of sync_read(NEXTSET_SYNC_DATA)\n"); + for (i = 0; i < CHAN_COUNT; ++i) { + logMsg("%s valid = %d ptr = %d \n", + (pSync_ctrl->pDstruct)->pName, (pSync_ctrl->pDstruct)->svalid, + (pSync_ctrl->pDstruct)->pSdata); + if((pSync_ctrl->pDstruct)->pSdata) { + logMsg("ts sec = %ld ts nsec = %ld value = %f\n", + ((struct dbr_time_float *) + ((pSync_ctrl->pDstruct)->pSdata))->stamp.secPastEpoch, + ((struct dbr_time_float *) + ((pSync_ctrl->pDstruct)->pSdata))->stamp.nsec, + ((struct dbr_time_float*) + ((pSync_ctrl->pDstruct)->pSdata))->value); + } + ++pSync_ctrl; + } + pSync_ctrl = pSync_compctrl->pCtrl; + logMsg("\n"); + + + gsd_sync_read(PREVIOUS_SYNC_DATA, pSync_compctrl, CHAN_COUNT, &pfdctx, + SYNC_TIMEOUT); + logMsg("result of sync_read(PREVIOUS_SYNC_DATA)\n"); + for (i = 0; i < CHAN_COUNT; ++i) { + logMsg("%s valid = %d ptr = %d \n", + (pSync_ctrl->pDstruct)->pName, (pSync_ctrl->pDstruct)->svalid, + (pSync_ctrl->pDstruct)->pSdata); + if((pSync_ctrl->pDstruct)->pSdata) { + logMsg("ts sec = %ld ts nsec = %ld value = %f\n", + ((struct dbr_time_float *) + ((pSync_ctrl->pDstruct)->pSdata))->stamp.secPastEpoch, + ((struct dbr_time_float *) + ((pSync_ctrl->pDstruct)->pSdata))->stamp.nsec, + ((struct dbr_time_float*) + ((pSync_ctrl->pDstruct)->pSdata))->value); + } + ++pSync_ctrl; + } + pSync_ctrl = pSync_compctrl->pCtrl; + logMsg("\n"); + + + while(!gsd_sync_read(NEXTSET_SYNC_DATA, pSync_compctrl, CHAN_COUNT, &pfdctx, + SYNC_TIMEOUT)) { + ; + } + logMsg("result of sync_read(NEXTSET_SYNC_DATA)\n"); + for (i = 0; i < CHAN_COUNT; ++i) { + logMsg("%s valid = %d ptr = %d \n", + (pSync_ctrl->pDstruct)->pName, (pSync_ctrl->pDstruct)->svalid, + (pSync_ctrl->pDstruct)->pSdata); + if((pSync_ctrl->pDstruct)->pSdata) { + logMsg("ts sec = %ld ts nsec = %ld value = %f\n", + ((struct dbr_time_float *) + ((pSync_ctrl->pDstruct)->pSdata))->stamp.secPastEpoch, + ((struct dbr_time_float *) + ((pSync_ctrl->pDstruct)->pSdata))->stamp.nsec, + ((struct dbr_time_float*) + ((pSync_ctrl->pDstruct)->pSdata))->value); + } + ++pSync_ctrl; + } + pSync_ctrl = pSync_compctrl->pCtrl; + logMsg("\n"); + + + gsd_sync_read(PREVIOUS_SYNC_DATA, pSync_compctrl, CHAN_COUNT, &pfdctx, + SYNC_TIMEOUT); + logMsg("result of sync_read(PREVIOUS_SYNC_DATA)\n"); + for (i = 0; i < CHAN_COUNT; ++i) { + logMsg("%s valid = %d ptr = %d \n", + (pSync_ctrl->pDstruct)->pName, (pSync_ctrl->pDstruct)->svalid, + (pSync_ctrl->pDstruct)->pSdata); + if((pSync_ctrl->pDstruct)->pSdata) { + logMsg("ts sec = %ld ts nsec = %ld value = %f\n", + ((struct dbr_time_float *) + ((pSync_ctrl->pDstruct)->pSdata))->stamp.secPastEpoch, + ((struct dbr_time_float *) + ((pSync_ctrl->pDstruct)->pSdata))->stamp.nsec, + ((struct dbr_time_float*) + ((pSync_ctrl->pDstruct)->pSdata))->value); + } + ++pSync_ctrl; + } + pSync_ctrl = pSync_compctrl->pCtrl; + logMsg("\n"); + + + gsd_sync_clear(pSync_compctrl, CHAN_COUNT); + logMsg("End of test and demo.\n\n"); + + return 0; +} +*/ +/* end test!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ +/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ + +/* +******************************************************* +* Description: +* 1) Entry with pSync containing the base address of the array of +* gsd_sync_data structures (chan_count of these) +* 2) Alloc memory for a composite control structure instance and +* an array of gsd_sync_ctrl structures, +* one for each gsd_sync_data structure +* 3) Establish a connection event handler +* 4) For each gsd_sync_ctrl structure +* 1) init pCtrl->Dstruct to point to its associated +* gsd_sync_data structure +* 2) init to NULL the pSdata ptr in associated pSync +* (this is used as a flag to indicate if channel has +* ever been up in function "gsd_connevent_handler") +* 3) broadcast chan access search +* 5) Flush i/o for channel access +* 6) Returns pCompctrl, the address of the composite control struct +* which must be used for any subsequent gsd_sync_read(flag,pCtrl, +* chan_count) calls +* pCompctrl == NULL: error, unable to allocate memory. +* pCompctrl != NULL: success, normal execution. +******************************************************* +*/ + + +VOID *gsd_sync_init(pSync, chan_count, pfdctx, pMac_pairs) +struct gsd_sync_data *pSync; +unsigned int chan_count; +VOID **pfdctx; +char *pMac_pairs[]; +{ + int i; + struct gsd_sync_compctrl *pCompctrl; + struct gsd_sync_ctrl *pCtrl; + + if(*pfdctx == NULL) { + gsd_ca_task_initialize(pfdctx); + } + + pCompctrl = (struct gsd_sync_compctrl *) + calloc(1, sizeof(struct gsd_sync_compctrl)); + if(pCompctrl == NULL) { + logMsg("gsd_sync_init: mem alloc failed\n"); + return NULL; + } + + pCtrl = (struct gsd_sync_ctrl *) calloc(chan_count, sizeof(struct gsd_sync_ctrl)); + if(pCtrl == NULL) { + logMsg("gsd_sync_init: mem alloc failed\n"); + free(pCompctrl); + return NULL; + } + pCompctrl->pCtrl = pCtrl; + + for(i = 0; i < chan_count; i++) { + pCtrl->pDstruct = pSync; + pSync->pSdata = NULL; + if(strlen(pSync->pName) > 0){ + char name_str[db_name_dim]; + gsdl_main_macro(name_str, pSync->pName, pMac_pairs); + strcpy(pSync->pName, name_str); +/* printf("new_str = %s\n", pSync->pName);*/ + SEVCHK(ca_build_and_connect(pSync->pName, TYPENOTCONN, 0, + &(pSync->pChid), (VOID *) NULL, + gsd_connevent_handler, (VOID *) pCtrl), + "gs_sync_init: broadcast search failed\n"); + ca_flush_io(); + } + ++pSync; + ++pCtrl; + } + + gsd_ca_pend_event(pfdctx); + return (VOID *) pCompctrl; +} +/* +**************************************************** +* Description: +* 1) If first time channel connect has been up (i.e. no valid +* memory address for pSdata) then +* 1) Allocate memory for the sync data and fill pSdata +* with its address. If fail, return. (no monitor started) +* 2) Allocate memory for the next data. If fail, +* free memory gotten so far, and return. +* (no monitor started) +* 3) Allocate memory for the already data. If fail, +* free memory gotten so far, and return. +* (no monitor started) +* 4) Start event monitor on channel +* 5) Flush i/o for channel access +***************************************************** +*/ +VOID gsd_connevent_handler(args) +struct connection_handler_args args; +{ + struct gsd_sync_ctrl *pCtrl = ca_puser(args.chid); + struct gsd_sync_data *pSync = pCtrl->pDstruct; + + if(args.op == CA_OP_CONN_UP) { + if(pSync->pSdata == NULL) { + + pSync->pSdata = (VOID *) calloc(1, dbr_size_n( + dbf_type_to_DBR_TIME(ca_field_type(args.chid)), + ca_element_count(args.chid))); + if(pSync->pSdata == NULL) { + logMsg("gsd_connevent_handler: mem alloc fail\n"); + return; + } + pCtrl->pNdata = (VOID *) calloc(1, dbr_size_n( + dbf_type_to_DBR_TIME(ca_field_type(args.chid)), + ca_element_count(args.chid))); + if(pCtrl->pNdata == NULL) { + free(pSync->pSdata); + pSync->pSdata = NULL; + logMsg("gsd_connevent_handler: mem alloc fail\n"); + return; + } + pCtrl->pAdata = (VOID *) calloc(1, dbr_size_n( + dbf_type_to_DBR_TIME(ca_field_type(args.chid)), + ca_element_count(args.chid))); + if(pCtrl->pAdata == NULL) { + free(pSync->pSdata); + pSync->pSdata = NULL; + free(pCtrl->pNdata); + pCtrl->pNdata = NULL; + logMsg("gsd_connevent_handler: mem alloc fail\n"); + return; + } + + pSync->time_type = dbf_type_to_DBR_TIME( + ca_field_type(pSync->pChid)); + pSync->count = ca_element_count(pSync->pChid); + +/* + logMsg("%s type = %d count = %d\n", + pSync->pName, pSync->time_type, pSync->count); +*/ + } + } + return; +} +/* +*********************************************************** +* Description: +* 1) if (event is enabled) then +* 1) if (event is the 1st for this channel (pN == NULL)) then +* 1) alloc mem for a gsd_sync_linked structure and +* place its addr into the pN ptr +* else +* 1) traverse linked list until pN points to last +* gsd_sync_linked structure +* 2) allocate memory for a new gsd_sync_linked +* structure and append it to end of linked list +* 3) Update pN to point to this new last structure +* 2) allocate memory to hold the data +* 3) copy the data into this buffer +*********************************************************** +*/ +VOID gsd_event_handler(args) +struct event_handler_args args; +{ + struct gsd_sync_ctrl *pCtrl = args.usr; + struct gsd_sync_linked *pN = pCtrl->pNstruct; + struct gsd_sync_linked *pAlloc_linked; + VOID *pAlloc_data; + + if(pCtrl->en_event) { + pAlloc_linked = (struct gsd_sync_linked *) calloc(1, + sizeof(struct gsd_sync_linked)); + pAlloc_data = (VOID *) calloc(1, dbr_size_n(args.type,args.count)); + if((NULL == pAlloc_linked) || (NULL == pAlloc_data)) { + logMsg("gsd_event_handler: mem alloc failed.\n"); + /* clean-up unused memory */ + if(pAlloc_linked != NULL) free(pAlloc_linked); + if(pAlloc_data != NULL) free(pAlloc_data); + return; + } + + if(pN == NULL) { + pCtrl->pNstruct = pAlloc_linked; + pN = pAlloc_linked; + } + else { + while(pN->pNstruct) pN = pN->pNstruct; + pN->pNstruct = pAlloc_linked; + pN = pN->pNstruct; + } + + pN->pNdata = pAlloc_data; + + gsd_copy_buffer(args.dbr, pN->pNdata, dbr_size_n(args.type, + args.count)); + +/* + logMsg("%s ts sec = %ld ts nsec = %ld value = %f\n", + (pCtrl->pDstruct)->pName, + ((struct dbr_time_float *) (pN->pNdata))->stamp.secPastEpoch, + ((struct dbr_time_float *) (pN->pNdata))->stamp.nsec, + ((struct dbr_time_float *) (pN->pNdata))->value); +*/ + + } + + return; +} + +/* +***************************************************** +* Description: +* 1) if (PREVIOUS_SYNC_DATA) then +* 1) for each channel +* 1) if channel has ever been up then +* 1) copy already data to sync data +* 2) copy already valid flag to sync valid flag +* else +* 1) place NULL in sync data ptr +* 2) clear sync valid flag to zero +* 2) if (NEXTSET_SYNC_DATA) then +* 1) if first call indicated by 0 start time then +* 1) for each channel +* 1) if channel has ever been up then +* 1) copy old next data to already level data +* copy old next valid flags to already +* level valid flags +* 2) clear next valid flags +* 3) enable capture of monitor data until +* a full set is acquired or timeout +* 4) add monitor event +* 2) fill with system time +* 3) return 0 indicating not done +* 2) if complete set received or timed out then +* 1) clear start time to 0 to prepare for +* possible next call +* 2) for each channel +* 1) disable further capture of data +* 2) clear monitor event +* 3) copy chosen time stamp data to next level +* (if no data received, don't over copy to +* next level, but clear valid flag on next levl +* 4) for each channel +* 1) if channel has ever been up then +* 1) copy next level data to sync data +* 2) copy next level valid flag to +* sync valid flag +* 3) free memory of linked list and +* its associated data buffer +* else +* 1) place NULL in sync data ptr +* 2) set sync valid flag to zero +* 5) return 1 indicating done +* 3) return 0 indicating not done +* 3) return 1 indicating done with unknown request +***************************************************** +*/ + + +int gsd_sync_read(flag, pCompctrl,chan_count, pfdctx, timeout_secs) +char flag; +struct gsd_sync_compctrl *pCompctrl; +unsigned int chan_count; +VOID *pfdctx; +float timeout_secs; +{ + struct gsd_sync_ctrl *pCtrl = pCompctrl->pCtrl; + TS_STAMP *pTs; + struct timezone zone; + int i; + + if(NULL == pCompctrl) { + logMsg("gsd_sync_read: error NULL arg for pCompctrl\n"); + return; + } + + if(flag == PREVIOUS_SYNC_DATA) { + for (i = 0; i < chan_count; i++) { + if(pCtrl->pAdata != NULL) { + gsd_copy_buffer(pCtrl->pAdata, + (pCtrl->pDstruct)->pSdata, + dbr_size_n((pCtrl->pDstruct)->time_type, + (pCtrl->pDstruct)->count)); + (pCtrl->pDstruct)->svalid = pCtrl->avalid; + } + else { + (pCtrl->pDstruct)->pSdata = NULL; + (pCtrl->pDstruct)->svalid = 0; + } + ++pCtrl; + } + return 1; /* done with PREVIOUS_SYNC_DATA request */ + } + + if(flag == NEXTSET_SYNC_DATA) { + if(((pCompctrl->start_time).tv_sec == 0) && + ((pCompctrl->start_time).tv_usec == 0)) { + for (i = 0; i < chan_count; i++) { + if(pCtrl->pNdata != NULL) { + gsd_copy_buffer(pCtrl->pNdata, + pCtrl->pAdata, + dbr_size_n((pCtrl->pDstruct)->time_type, + (pCtrl->pDstruct)->count)); + pCtrl->avalid = pCtrl->nvalid; + pCtrl->nvalid = 0; + pCtrl->en_event = 1; + + SEVCHK(ca_add_array_event( + (pCtrl->pDstruct)->time_type, + (pCtrl->pDstruct)->count, + (pCtrl->pDstruct)->pChid, gsd_event_handler, + pCtrl, (float) 0, (float) 0, (float) 0, + &(pCtrl->event_id)), + "gsd_connevent_handler: add event failed\n"); + } + ++pCtrl; + } + ca_flush_io(); + gettimeofday(&(pCompctrl->start_time), &zone); + return 0; /* not done */ + } + + if((pTs = gsd_complete_set(pCompctrl->pCtrl, chan_count)) || + (gsd_timeout(pCompctrl, timeout_secs, pfdctx))) { + + (pCompctrl->start_time).tv_sec = 0; + (pCompctrl->start_time).tv_usec = 0; + + pCtrl = pCompctrl->pCtrl; + for (i = 0; i < chan_count; ++i) { + pCtrl->en_event = 0; + if(pCtrl->event_id) ca_clear_event(pCtrl->event_id); + ++pCtrl; + } + ca_flush_io(); + + pCtrl = pCompctrl->pCtrl; + + if(pTs != NULL) { +/* + logMsg("got sync data set\n"); +*/ + gsd_syncset_findcopy(pCtrl, + chan_count, pTs); + } + else { +/* + logMsg("settle for last \n"); +*/ + pTs = gsd_findlargest_ts(pCtrl, + chan_count); + gsd_syncset_findcopy(pCtrl, chan_count, + pTs); + } + + for(i = 0; i < chan_count; i++) { + if(pCtrl->pNdata != NULL) { + gsd_copy_buffer(pCtrl->pNdata, + (pCtrl->pDstruct)->pSdata, + dbr_size_n((pCtrl->pDstruct)->time_type, + (pCtrl->pDstruct)->count)); + (pCtrl->pDstruct)->svalid = pCtrl->nvalid; + gsd_freeevent_mem(pCtrl); + } + else { + (pCtrl->pDstruct)->pSdata = NULL; + (pCtrl->pDstruct)->svalid = 0; + } + ++pCtrl; + } + return 1; /* done with NEXT_SYNC_DATA request, */ + /* either fullset or timeout */ + } + + return 0; /* not done with NEXT_SYNC_DATA request */ + } + return 1; /* done, unknown request */ +} +/* +************************************************ +* Description: +* 1) If a set of identically time stamped data is found in +* each channel of interest then +* 1) return a ptr to one of the identical time stamps +* 2) Otherwise return NULL ptr +************************************************ +*/ +TS_STAMP *gsd_complete_set(pCtrl, chan_count) +struct gsd_sync_ctrl *pCtrl; +unsigned int chan_count; +{ + struct gsd_sync_linked *pNfirst_chan = pCtrl->pNstruct; + struct gsd_sync_linked *pNchan = NULL; + TS_STAMP *pEqual = NULL; + + int i; + struct gsd_sync_ctrl *pCtrl_copy; + + while(pNfirst_chan != NULL) { /* for every data rec receiv in 1st chn*/ + pCtrl_copy = pCtrl; + for(i = 0; i < chan_count; ++i) { /* for every channel in chan array */ + pEqual = NULL; + + pNchan = pCtrl_copy->pNstruct; + while(pNchan != NULL) { + /* for every data record received by this channel */ + /* may want to use gsd_tss_within_delta instead of eq */ + if(gsd_tss_eq( + gsd_get_ts((pCtrl->pDstruct)->time_type, + pNfirst_chan->pNdata), + gsd_get_ts((pCtrl_copy->pDstruct)->time_type, + pNchan->pNdata))) { + pEqual = gsd_get_ts( + (pCtrl->pDstruct)->time_type, + pNfirst_chan->pNdata); + break; + } + pNchan = pNchan->pNstruct; + } + if(NULL == pEqual) break; + /* no ts match in this chan, exit the for, */ + /* and try next 1st channel time stamp */ + pCtrl_copy++; + } + if(pEqual != NULL) return pEqual; /* success */ + pNfirst_chan = pNfirst_chan->pNstruct; + /* try next data record of 1st channel */ + } + return NULL; /* failed, returning NULL ptr */ +} +/* +*************************** +* Description: +* 1) returns ptr to the time stamp structure within the data buffer of +* types DBR_TIME_xxxx (an accessor routine) +****************************** +*/ +TS_STAMP *gsd_get_ts(time_type, pNdata) +int time_type; +void *pNdata; +{ + switch(time_type) { + case DBR_TIME_STRING: + return &(((struct dbr_time_string *) pNdata)->stamp); + case DBR_TIME_SHORT: + return &(((struct dbr_time_short *) pNdata)->stamp); + case DBR_TIME_FLOAT: + return &(((struct dbr_time_float *) pNdata)->stamp); + case DBR_TIME_ENUM: + return &(((struct dbr_time_enum *) pNdata)->stamp); + case DBR_TIME_CHAR: + return &(((struct dbr_time_char *) pNdata)->stamp); + case DBR_TIME_LONG: + return &(((struct dbr_time_long *) pNdata)->stamp); + case DBR_TIME_DOUBLE: + return &(((struct dbr_time_double *) pNdata)->stamp); + default: + return NULL; + } +} + +/* +************************************************ +* Description: +* 1) returns ptr to the largest time stamp found in +* all of the channel data collected. If no data then +* returns NULL. +************************************************ +*/ +TS_STAMP *gsd_findlargest_ts(pCtrl, chan_count) +struct gsd_sync_ctrl *pCtrl; +int chan_count; +{ + TS_STAMP ts; + TS_STAMP *pTs = &ts; + struct gsd_sync_linked *pNchan; + int i; + + ts.secPastEpoch = 0; + ts.nsec = 0; + for (i = 0; i < chan_count; ++i) { + pNchan = pCtrl->pNstruct; + while(pNchan != NULL) { +/* + logMsg(" %ld %ld >? %ld %ld\n", + (gsd_get_ts((pCtrl->pDstruct)->time_type, + pNchan->pNdata))->secPastEpoch, + (gsd_get_ts((pCtrl->pDstruct)->time_type, + pNchan->pNdata))->nsec, + pTs->secPastEpoch, pTs->nsec); +*/ + if(gsd_tss_gtr( + gsd_get_ts((pCtrl->pDstruct)->time_type,pNchan->pNdata), + pTs) || + gsd_tss_eq( + gsd_get_ts((pCtrl->pDstruct)->time_type, + pNchan->pNdata), pTs)) { + pTs = gsd_get_ts((pCtrl->pDstruct)->time_type,pNchan->pNdata); + } + pNchan = pNchan->pNstruct; + } + pCtrl++; + } + if(pTs == &ts) { + return NULL; + } + else { + return pTs; + } +} +/* +******************************************* +* Description: +* 1) Frees all event memory that was allocated on the fly by +* following each channel's linked list of gsd_sync_linked structures +******************************************* +*/ +VOID gsd_freeevent_mem(pCtrl) +struct gsd_sync_ctrl *pCtrl; +{ + struct gsd_sync_linked *pN; + struct gsd_sync_linked *pN_copy; + + pN = pCtrl->pNstruct; + + while(pN != NULL) { + if(pN->pNdata != NULL) { +/* + logMsg("free %s %ld %ld\n", (pCtrl->pDstruct)->pName, + ((struct dbr_time_float *) (pN->pNdata))->stamp.secPastEpoch, + ((struct dbr_time_float *) (pN->pNdata))->stamp.nsec); +*/ + free(pN->pNdata); + } + pN_copy = pN; + pN = pN->pNstruct; + free(pN_copy); + } + pCtrl->pNstruct = NULL; + return; +} + +/* +******************************************* +* Description: +* 1) for every channel +* 1) If finds linked list data that is time stamped the +* same as pTs. +* 1) copies this data to the Next data buffer of +* the gsd_sync_ctrl structure +* 2) sets nvalid = 1 +* else +* 1) copies most recently received data to the +* Next data buffer of the gsd_sync_ctrl structure +* 2) clears nvalid = 0 +******************************************* +*/ +VOID gsd_syncset_findcopy(pCtrl, chan_count, pTs) +struct gsd_sync_ctrl *pCtrl; +int chan_count; +TS_STAMP *pTs; +{ + struct gsd_sync_linked *pNchan; + int i; + + for (i = 0; i < chan_count; ++i) { + pCtrl->nvalid = 0; + pNchan = pCtrl->pNstruct; + while(pNchan != NULL) { + if(gsd_tss_eq(gsd_get_ts((pCtrl->pDstruct)->time_type, + pNchan->pNdata), pTs)) { + gsd_copy_buffer(pNchan->pNdata, pCtrl->pNdata, + dbr_size_n((pCtrl->pDstruct)->time_type, + (pCtrl->pDstruct)->count)); + pCtrl->nvalid = 1; + break; + } + pNchan = pNchan->pNstruct; + } + + if((pCtrl->nvalid) != 1) { + if(pNchan = pCtrl->pNstruct) { + while(pNchan->pNstruct) pNchan = pNchan->pNstruct; + gsd_copy_buffer(pNchan->pNdata, pCtrl->pNdata, + dbr_size_n((pCtrl->pDstruct)->time_type, + (pCtrl->pDstruct)->count)); + } + } + + pCtrl++; + } + return; +} + +/* +************************************************* +* Description: +* 1) byte block transfer +************************************************* +*/ +VOID gsd_copy_buffer(pFrom, pTo, byte_count) +char *pFrom; +char *pTo; +unsigned int byte_count; +{ + unsigned int i; + for(i = 0; i < byte_count; ++i) { + *pTo++ = *pFrom++; + } + return; +} +/* +********************************************** +* Description: +* 1) Frees all allocated memory which resulted from calls to +* gsd_sync_init +* gsd_sync_read +********************************************** +*/ +VOID gsd_sync_clear(pSync_compctrl, chan_count) +struct gsd_sync_compctrl *pSync_compctrl; +unsigned int chan_count; +{ + int i; + struct gsd_sync_ctrl *pSync_ctrl = pSync_compctrl->pCtrl; + + if(NULL == pSync_compctrl) { + logMsg("gsd_sync_clear: error NULL pSync_compctrl\n"); + return; + } + if(NULL == pSync_ctrl) { + free(pSync_compctrl); + logMsg("gsd_sync_clear: error NULL pSync_ctrl\n"); + return; + } + + for(i = 0; i < chan_count; ++i) { + ca_clear_channel((pSync_ctrl->pDstruct)->pChid); + ca_flush_io(); + + if(pSync_ctrl->pNdata != NULL) free(pSync_ctrl->pNdata); + if(pSync_ctrl->pAdata != NULL) free(pSync_ctrl->pAdata); + if((pSync_ctrl->pDstruct)->pSdata != NULL) + free((pSync_ctrl->pDstruct)->pSdata); + (pSync_ctrl->pDstruct)->pSdata = NULL; + + pSync_ctrl++; + } + + free(pSync_compctrl->pCtrl); + free(pSync_compctrl); + + return; +} +/* +********************************************** +* Description: +* 1) if the two time stamps are within delta of each other then +* 1) return 1 +* 2) otherwise return 0 +********************************************** +*/ +int gsd_tss_within_delta(pTs_s, pTs_l, pDelta) +TS_STAMP *pTs_s; +TS_STAMP *pTs_l; +TS_STAMP *pDelta; +{ + TS_STAMP temp; + TS_STAMP *pTemp; + + if(gsd_tss_eq(pTs_s, pTs_l)) return 1; /* equal, so within delta */ + /* ensure that *pTs_l is the larger time stamp */ + if(gsd_tss_gtr(pTs_s, pTs_l)) { + pTemp = pTs_l; + pTs_l = pTs_s; + pTs_s = pTemp; + } + + temp.secPastEpoch = pTs_s->secPastEpoch + pDelta->secPastEpoch; + temp.nsec = pTs_s->nsec + pDelta->nsec; + + if((gsd_tss_gtr(&temp, pTs_l)) || (gsd_tss_eq(&temp, pTs_l))) + return 1; /* within delta */ + return 0; /* not within delta */ +} +/* +********************************************** +* Description: +* 1) if the two time stamps are equal then +* 1) return 1 +* 2) otherwise return 0 +********************************************** +*/ +int gsd_tss_eq(pTs_s, pTs_l) +TS_STAMP *pTs_s; +TS_STAMP *pTs_l; +{ + if((pTs_s == NULL) || (pTs_l == NULL)) return 0; /* not equal ts */ + if((pTs_s->secPastEpoch == pTs_l->secPastEpoch) && + (pTs_s->nsec == pTs_l->nsec)) return 1; /* equal time stamps */ + return 0; /* not equal time stamps */ +} +/* +********************************************** +* Description: +* 1) if time stamp 1 > time stamp 2 then +* 1) return 1 +* 2) otherwise return 0 +********************************************** +*/ +int gsd_tss_gtr(pTs_l, pTs_s) +TS_STAMP *pTs_l; +TS_STAMP *pTs_s; +{ + if((pTs_l == NULL) || (pTs_s == NULL)) return 0; /* not gtr than */ + if(pTs_l->secPastEpoch > pTs_s->secPastEpoch) return 1; /* gtr than */ + if((pTs_l->secPastEpoch == pTs_s->secPastEpoch) && + (pTs_l->nsec > pTs_s->nsec)) return 1; /* greater than */ + return 0; /* not greater than */ +} + + + +/* +* Note: UNIX specific routines below: !!!!!!!!!!!!!!!!!!!!!!!!! +*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +*/ +/* +************************************************ +* Description: +* 1) indicate when timeout occurs +* Note: UNIX gettimeofday apparently is the only C/system time +* routine to yield resolution below 1 second, but it is +* represented as being inaccurate in its usec element +* (see man gettimeofday) +************************************************ +*/ +int gsd_timeout(pCompctrl, timeout_secs, pfdctx) +struct gsd_sync_compctrl *pCompctrl; +float timeout_secs; +VOID **pfdctx; +{ + struct gsd_sync_ctrl *pCtrl = pCompctrl->pCtrl; + struct timeval new_gmt; + struct timezone zone; + + float dif_secs; + + gsd_ca_pend_event(pfdctx); /* allow C.A. events to occur */ + /* in the Unix environment */ + + gettimeofday(&new_gmt, &zone); + + if(new_gmt.tv_usec >= (pCompctrl->start_time).tv_usec) { + /* no borrow */ + dif_secs = ((float) (new_gmt.tv_sec - (pCompctrl->start_time).tv_sec)) + + (((float) (new_gmt.tv_usec - (pCompctrl->start_time).tv_usec)) / + 1000000.0); + } + else { + /* borrow */ + dif_secs = ((float) (new_gmt.tv_sec - (pCompctrl->start_time).tv_sec - 1)) + + (((float) (1000000 + new_gmt.tv_usec - (pCompctrl->start_time).tv_usec)) / + 1000000.0); + } + + if(dif_secs > timeout_secs) { + return 1; + } + + + return 0; +} +/* +********************************************** +********************************************** +*/ +void gsd_ca_task_initialize(pfdctx) +void **pfdctx; +{ + *pfdctx = (void *) fdmgr_init(); + if(!(*pfdctx)) { + logMsg("gsd_ca_task_initialize: fdmgr_init failed.\n"); + abort(); + } + SEVCHK(ca_add_fd_registration(gsd_fd_register, *pfdctx), + "gsd_ca_task_initialize: Fd registration failed.\n"); + return; +} +/* +********************************************** +********************************************** +*/ +void gsd_ca_pend_event(pfdctx) +void **pfdctx; +{ + static struct timeval timeout = {0, USEC_TIME_OUT}; + fdmgr_pend_event(*pfdctx, &timeout); + return; +} + + +/* +************************************************ +* NAME +* gsd_fd_register(pfdcts, fd, condition) +* DESCRIPTION +* 1) if (condition is true) then +* 1) add file descriptor to fd manager +* else +* 1) delete file descriptor from fd manager +************************************************ +*/ +void gsd_fd_register(pfdctx, fd, condition) +void **pfdctx; +int fd; +int condition; +{ + if(condition) { + fdmgr_add_fd(pfdctx, fd, gsd_ca_service, NULL); + } + else { + fdmgr_clear_fd(pfdctx, fd); + } +} + +/* +************************************************* +* NAME +* gsd_ca_service() +* DESCRIPTION +* 1) call ca_pend_event to allow event handler execution +*************************************************** +*/ +void gsd_ca_service() +{ + ca_pend_event(PEND_EVENT_DELAY); +} +