This program is going to receive the command and process it in a large case statement. The particular case code for the command will perform any parameter checking, conversions, etc. and pass it on to the rocs front end for processing. Since this is a simple test, it will do the minimum, viz.
case ROCS_CALLMOD: /* Call sample Module */ if(!qflag) printf("Got CALLMOD of %d bytes\n", len); SendRocs(toRocsQueue, &toRocs, mintorocs+len); nrlen = sizeof(struct fromRocs); RecvRocs(fromRocsQueue, &fromRocs, &nrlen); break;
Note that most of the setting up of the message is done in common code before the case statement.
This program contains another case statement to process incoming commands from equipserver.c (or others). This program is definitely running on the crate and has access to NV Ram, shared memory segments, etc. Most of the interfacing will be done by the code in the case statement (though it can be assumed that the parameters, etc. are correct) with a separate routine (called Do_XXXX()) being used to form the action. Notice that if there is any real work to be done, it should be done in the action routine not here.
This is the code in the case statement:
case ROCS_CALLMOD: /* Command to call a module*/ sp = (short *)fromMug.cmddata; if(Do_CallMod((short *)fromMug.cmddata, len) != 0) { printf("Whoops Do_CallMod returned %d (%s)\n", toMug.errnum, toMug.errmsg); adp->flags = 0; break; } /* The command has been done successfully. Get the * result data from the shared memory segment and send * it back. */ sp1 = (short *)toMug.cmddata; sp2 = adp->adata; n = adp->nsamples; for(i=0; i<n; i++) *sp1++ = *sp2++; toMug.dlen = n * 2; /* Ok all finished now, clear the flags in the DPM * structure and return the state to 0. */ adp->flags = 0; break;
And here is the routine to form the action and send it off:
/* Create the action for the CALLMOD command. Takes a pointer to * the data and the length in bytes. */ int Do_CallMod(short *inpdata, int len) { struct Action *ap; short *sp; int mpx; ap =(struct Action *)shm_malloc(sizeof(struct Action)); sp = (short *)shm_malloc(len); memcpy((void *)sp, (void *)inpdata, len); ap->type = AT_CALLMOD; ap->actdata = sp; ap->datalen = len; mpx = MakeMpx(); ap->mpx = mpx; ap->logevent = NOW; AddAction(ap); SendLogicalEvent(NOW); toMug.errnum=GetReturn(mpx, toMug.errmsg, sizeof(toMug.errmsg)); return(toMug.errnum); }
Note that the event is usually NOW and both the action structure and the data is allocated by the
shm_alloc() routines. An action structure is allocated and also data if necessary.So that actions can be put on the queue from anywhere (particularly from action routines) a multiplexing mechanism is built into the
UIReturn() and GetReturn() routines. The way it works is in the example, a routine MakeMpx() is provided to generate a unique number. This is stored in the member ap->mpx (for use in the action routine) and is provided as the first argument to GetReturn(). In this way, the action routine will always return to the correct place.The data is attached to the action structure with
ap->data. The action is put on the queue with the AddAction() routine. The SendLogicalEvent() routine is used to insert an action (NOW in this case) into the queue which will cause the action to be executed. This program will wait for the action to finish with the GetReturn() routine which will return with an error number (0 for success, else negative) and an appropriate message. The error information is put straight into the message structure to be returned.