/** * \file cameradriver.c * \brief This provides the IO layer which feeds inputs from a user or * the camera server to the state machine, and then sends any state machine * output back to SICS or the camera. * * \Author Ferdi Franceschini February 2013 * * Copyright: see file Copyright.txt */ #include #include #include #include #include #include #include #include #include #include "camera.h" #define NAMELEN 32 #define IFMTLEN 4 #define ERRLEN 256 #define MSGLEN 512 #define MAX_META_COUNT 32 #define MAX_SCANVAR_COUNT 16 enum camstates {idle, acquiring, processing, saving}; #define CAMDRIV_ERRTABLE \ TR(ENONE, "OK") \ TR(EFAIL, "command failed") \ TR(EBUSYACQ, "camera busy acquiring image") \ TR(EBUSYSAVE, "camera busy saving image") \ TE(EBUSYPROC, "camera busy processing image") #define TR(a,b) a, #define TE(a,b) a enum errcodes {CAMDRIV_ERRTABLE}; #undef TR #undef TE #define TR(a,b) b, #define TE(a,b) b static char *errmsg[] = {CAMDRIV_ERRTABLE}; #undef TR #undef TE #define CAMDRIV_PARTABLE \ TR(CLOCK, "clock") \ TR(BIN, "bin") \ TR(SIZE, "size") \ TR(GAIN, "gain") \ TR(FLIP, "flip") \ TR(XSTART, "xstart") \ TR(YSTART, "ystart") \ TR(XEND, "xend") \ TR(YEND, "yend") \ TR(EXPOSURE, "exposure") \ TR(TEMP, "temperature") \ TR(THRESH, "threshold") \ TR(SHOPT, "shutteropentime") \ TE(SHCLT, "shutterclosetime") #define TR(a,b) 1+ #define TE(a,b) 1 static int NUMCAMPAR = CAMDRIV_PARTABLE; #undef TR #undef TE #define FLIP_TABLE \ TR(NORMAL, "normal") \ TR(INVINT, "invintensity") \ TR(NORMFH, "normfh") \ TR(NORMFV, "normfv") \ TR(NORMFHV, "normfhv") \ TR(INVFH, "invfh") \ TR(INVFV, "invfv") \ TE(INVFHV, "invfhv") #define TR(a,b) a, #define TE(a,b) a enum campar {CAMDRIV_PARTABLE, MULTI, DEBUG}; enum flipval {FLIP_TABLE}; #undef TR #undef TE #define TR(a,b) b, #define TE(a,b) b static char *cacmdstr[] = {CAMDRIV_PARTABLE, "multi", "debug", NULL}; static char *flipcmdstr[] = {FLIP_TABLE, NULL}; #undef TR #undef TE #define UPDATE_SETTINGS_CFG 1 #define CLEAR_META_CFG 2 #define UPDATE_META_CFG 4 #define UPDATE_SCANVAR_CFG 8 #define UPDATE_FILE_CFG 16 typedef struct { char path[MSGLEN]; char basename[MSGLEN]; long startnumber; char imageformat[IFMTLEN]; char experimentdetail[MSGLEN]; } filecfg_t; typedef struct { float clockMHz; float bin; float size; float gain; enum flipval flip; float xstart; float ystart; float xend; float yend; float exposure; float temp; float thresh; float shopt; float shclt; int updatecfg; filecfg_t file; char meta_list[MAX_META_COUNT][MSGLEN]; char scanvar_list[MAX_SCANVAR_COUNT][NAMELEN]; pDummy scanvar_dummy[MAX_SCANVAR_COUNT]; pIDrivable pscanvar[MAX_SCANVAR_COUNT]; int meta_count; int scanvar_count; } camcfg_t; typedef struct { pObjectDescriptor pDes; int debug; char *asynq; camsm_t state_machine; pNWTimer state_timer; int status; enum errcodes camError; camcfg_t camera; pAsyncUnit asyncUnit; SicsInterp *pSics; } CamObj; /* Camera communications and protocol handlers */ static pAsyncProtocol CAM_Protocol = NULL; static int cb_state_timer(void *ctx, int mode); static int cb_getstate(pAsyncTxn txn); static int CamSet(CounterDriver *cntrData, char *name, int iCter, float fVal); /* if emsg == NULL conversion OK else if emsg == num not an integer else emsg == error message */ long getlong(char *num, char *emsg) { long val = 0; char *endptr; errno = 0; emsg = NULL; val = strtol(num, &endptr, 10); if ( (errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0) ) emsg = strerror(errno); if (endptr == num) emsg = num; return val; } static void CAM_Notify(void* context, int event) { CamObj *self = (CamObj *) context; switch (event) { case AQU_DISCONNECT: SICSLogWrite("CAM:(AQU_DISCONNECT)", eLogError); if (self->state_timer) { NetWatchRemoveTimer(self->state_timer); self->state_timer=0; } break; case AQU_RECONNECT: SICSLogWrite("CAM:(AQU_RECONNECT)", eLogError); NetWatchRegisterTimerPeriodic(&self->state_timer, 2000, 500, cb_state_timer, self); break; } return; } int defaultHandleInput(pAsyncProtocol p, pAsyncTxn txn, int ch); static int CAM_Rx(pAsyncProtocol p, pAsyncTxn txn, int ch) { int ret = 1; if (ch == '\r') ret = 1; else if (ch == '\n') ret = AQU_POP_CMD; else if (txn->inp_idx < txn->inp_len) txn->inp_buf[txn->inp_idx++] = ch; else ret = AQU_POP_CMD; return ret; } static int CAM_Ev(pAsyncProtocol p, pAsyncTxn pTxn, int event) { if (event == AQU_TIMEOUT) { pTxn->txn_status = ATX_TIMEOUT; return AQU_POP_CMD; } return AQU_POP_CMD; } void CameraInitProtocol(SicsInterp *pSics) { if (CAM_Protocol == NULL) { CAM_Protocol = AsyncProtocolCreate(pSics, "CAMERA", NULL, NULL); CAM_Protocol->sendCommand = NULL; CAM_Protocol->handleInput = CAM_Rx; CAM_Protocol->prepareTxn = NULL; CAM_Protocol->killPrivate = NULL; CAM_Protocol->handleEvent = CAM_Ev; #if 0 CAM_Protocol->sendTerminator = strdup("\r\n"); CAM_Protocol->replyTerminator[0] = strdup("\r\n"); #endif } } /* CounterDriver interface functions */ static int CamGetStatus(CounterDriver *cntrData, float *fControl) { CamObj *camdrv= (CamObj *)cntrData->pData; return camdrv->status; } /* \brief run_sm, call the state machine with the given input. * \param self, driver context including current state * \param ev_sym, input event */ static void run_sm(CamObj *self, enum event_codes ev_sym) { char *sscur, *ssnext, *esout, message[MSGLEN+1]; if (self->debug) { sscur = strstate(self->state_machine.Sc); snprintf(message, MSGLEN, "DEBUG:(run_sm) Scurr:%s Ei:%s", sscur,event_names[ev_sym]); SICSLogWrite(message, eLog); } camdriv_input(self, &self->state_machine, ev_sym); if (self->debug) { ssnext = strstate(self->state_machine.Sc), SSLEN; esout = strevent(self->state_machine.Eo), ESLEN; snprintf(message, MSGLEN, "DEBUG:(run_sm) Snext:%s Eo:%s", ssnext, esout); SICSLogWrite(message, eLog); } } /* Called by the scan command and via the count and countnb subcommands of a * counter object. Will update the configuration if necessary. */ static int CamStart(CounterDriver *cntrData) { CamObj *self = NULL; enum event_codes cd_sym; char logmsg[MSGLEN+1]; self = cntrData->pData; if (self->debug) { snprintf(logmsg, MSGLEN, "DEBUG:(CamStart): preset=%f\n",cntrData->fPreset); SICSLogWrite(logmsg, eLog); } CamSet(cntrData, "exposure", 0, cntrData->fPreset); if (self->state_machine.multi) { cd_sym = ECD_MLTI_ON; } else { cd_sym = ECD_TK_SHOT; } run_sm(self, cd_sym); return 1; } static int CamPause(CounterDriver *cntrData) { return 1; } static int CamContinue(CounterDriver *cntrData) { return 1; } static int CamHalt(CounterDriver *cntrData) { CamObj *self = cntrData->pData; state_t start_state = {.cl=SCL_RDY, .cm=SCM_IDLE, .dr=SDR_IDLE}; if (self->state_machine.multi) { run_sm(self, ECD_MLTI_OFF); } else { STset(&self->state_machine.Sc, start_state); EVclr(&self->state_machine.Eo); self->status = HWIdle; } return 1; } /* FIXME what should the counter data be set to? Total intensity? */ static int CamReadValues(CounterDriver *cntrData) { int status, iReplyLen=MSGLEN; char *cmd="TODO ", pReply[MSGLEN]; CamObj *self = NULL; return 1; self = cntrData->pData; status = AsyncUnitTransact(self->asyncUnit, cmd, strlen(cmd), pReply, &iReplyLen); return 1; } static int CamGetError(CounterDriver *cntrData, int *iCode, char *error, int iErrLen) { CamObj *camdrv=NULL; camdrv = (CamObj *) cntrData->pData; *iCode = camdrv->camError; camdrv->camError = ENONE; switch (*iCode) { case EBUSYACQ: snprintf(error, (size_t) iErrLen, "CAM: Can't complete operation, %s", errmsg[EBUSYACQ]); break; case EBUSYSAVE: snprintf(error, (size_t) iErrLen, "CAM: Can't complete operation, %s", errmsg[EBUSYSAVE]); break; case EBUSYPROC: snprintf(error, (size_t) iErrLen, "CAM: Can't complete operation, %s", errmsg[EBUSYPROC]); break; case ENONE: snprintf(error, (size_t) iErrLen, "CAM: Can't complete operation, %s", errmsg[ENONE]); break; case EFAIL: snprintf(error, (size_t) iErrLen, "CAM: %s", errmsg[EFAIL]); break; } return 1; } static int CamTryAndFixIt(CounterDriver *cntrData, int iCode) { return COTERM; } static int CamSet(CounterDriver *cntrData, char *name, int iCter, float fVal) { CamObj *camdriv= (CamObj *)cntrData->pData; int found=0; char *cmd; enum campar id; enum flipval flip; for (id=0; (cmd = cacmdstr[id]) != NULL; id++) { if (strcmp(cmd,name) == 0) { found=1; break; } } if (!found) { return 0; } switch (id) { case DEBUG: if (fVal == 1) camdriv->debug = 1; else camdriv->debug = 0; break; case MULTI: if (fVal != 0 && fVal != 1) { return 0; } else { camdriv->state_machine.multi = fVal; } break; case CLOCK: if (fVal > 0) { camdriv->camera.clockMHz = fVal; camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG; } else { return 0; } break; case BIN: if (fVal > 0) { camdriv->camera.bin = fVal; camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG; } else { return 0; } break; case SIZE: if (fVal > 0) { camdriv->camera.size = fVal; camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG; } else { return 0; } break; case GAIN: if (fVal > 0) { camdriv->camera.gain = fVal; camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG; } else { return 0; } break; case FLIP: flip = fVal; switch (flip) { case NORMAL: case INVINT: case NORMFH: case NORMFV: case NORMFHV: case INVFH: case INVFV: case INVFHV: camdriv->camera.flip = flip; camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG; break; default: return 0; break; } break; case XSTART: if (fVal > 0) { camdriv->camera.xstart = fVal; camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG; } else { return 0; } break; case YSTART: if (fVal > 0) { camdriv->camera.ystart = fVal; camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG; } else { return 0; } break; case XEND: if (fVal > 0) { camdriv->camera.xend = fVal; camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG; } else { return 0; } break; case YEND: if (fVal > 0) { camdriv->camera.yend = fVal; camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG; } else { return 0; } break; case EXPOSURE: if (fVal > 0) { camdriv->camera.exposure = fVal; camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG; } else { return 0; } break; case TEMP: camdriv->camera.temp = fVal; camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG; break; case THRESH: if (fVal > 0) { camdriv->camera.thresh = fVal; camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG; } else { return 0; } break; case SHOPT: if (fVal > 0) { camdriv->camera.shopt = fVal; camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG; } else { return 0; } break; case SHCLT: if (fVal > 0) { camdriv->camera.shclt = fVal; camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG; } else { return 0; } break; default: return 0; } return 1; } static int CamGet(CounterDriver *cntrData, char *name, int iCter, float *fVal) { CamObj *camdriv= (CamObj *)cntrData->pData; int found=0; char *cmd; enum campar id; for (id=0; (cmd = cacmdstr[id]) != NULL; id++) { if (strcmp(cmd,name) == 0) { found=1; break; } } if (!found) { return 0; } switch (id) { case MULTI: *fVal = (float) camdriv->state_machine.multi; break; case CLOCK: *fVal = camdriv->camera.clockMHz; break; case BIN: *fVal = camdriv->camera.bin; break; case SIZE: *fVal = camdriv->camera.size; break; case GAIN: *fVal = camdriv->camera.gain; break; case FLIP: *fVal = camdriv->camera.flip; break; case XSTART: *fVal = camdriv->camera.xstart; break; case YSTART: *fVal = camdriv->camera.ystart; break; case XEND: *fVal = camdriv->camera.xend; break; case YEND: *fVal = camdriv->camera.yend; break; case EXPOSURE: *fVal = camdriv->camera.exposure; break; case TEMP: *fVal = camdriv->camera.temp; break; case THRESH: *fVal = camdriv->camera.thresh; break; case SHOPT: *fVal = camdriv->camera.shopt; break; case SHCLT: *fVal = camdriv->camera.shclt; break; default: return 0; } return 1; } static int CamSend(CounterDriver *cntrData, char *pText, char *pReply, int iReplyLen) { int status; CamObj *self = NULL; self = cntrData->pData; //char *pBuf = (char *)calloc(strlen(pText)+10, sizeof(char)); //sprintf(pBuf, "set meta, %s", pText); //status = AsyncUnitTransact(self->asyncUnit, pBuf, strlen(pBuf), pReply, &iReplyLen); status = AsyncUnitTransact(self->asyncUnit, pText, strlen(pText), pReply, &iReplyLen); //free(pBuf); if (status <= 0) return 0; else return 1; } static int cb_shotcmd(pAsyncTxn txn) { CamObj *self = (CamObj *) txn->cntx; char *resp = txn->inp_buf, message[MSGLEN+1]; if (self->debug) { snprintf(message, MSGLEN, "DEBUG:(cb_shotcmd) Camera reply: %s", resp); SICSLogWrite(message, eLog); } if (strncmp(resp, "OK", 2) != 0) { self->camError = EFAIL; return 0; } return 1; } /** * \brief Decides if an output message is targeted at the camera or SICS or if * it should be fed back into the state transition function. */ int camdriv_out(void *me, event_t Eo) { int i, len, pend=0; char cmd[MSGLEN]="", logmsg[MSGLEN+1]=""; float clock, fVal; CamObj *self = (CamObj *)me; if (Eo.ca) { /* send command to camera */ if (self->debug) { snprintf(logmsg, MSGLEN, "DEBUG:(camdriv_out:Eo.ca): ev=%s, output=%s\n", event_names[Eo.ca], event_signatures[Eo.ca]); SICSLogWrite(logmsg, eLog); } switch (Eo.ca) { case ECA_TK_SHOT: len = strlen(event_signatures[ECA_TK_SHOT]); strncpy(cmd, event_signatures[ECA_TK_SHOT], len); len = strlen(cmd); AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN); break; case ECA_MLTI_ON: len = strlen(event_signatures[ECA_MLTI_ON]); strncpy(cmd, event_signatures[ECA_MLTI_ON], len); len = strlen(cmd); AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN); break; case ECA_MLTI_OFF: len = strlen(event_signatures[ECA_MLTI_OFF]); strncpy(cmd, event_signatures[ECA_MLTI_OFF], len); len = strlen(cmd); AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN); break; case ECA_CFG: /* TODO Should we retry sending a command if AsyncUnitSendTxn fails? * The driver should abort the shot and then try to send the * configuration the next time a shot is taken. */ if( (self->camera.updatecfg & UPDATE_SETTINGS_CFG) == UPDATE_SETTINGS_CFG) { clock = self->camera.clockMHz; snprintf(cmd, MSGLEN, "set camera,clock=%.*fmhz,bin=%dx,size=%d,gain=%dxhs,flip=%s,xstart=%d,ystart=%d,xend=%d,yend=%d,exposure=%f,temperature=%f,threshold=%d,shutteropentime=%d,shutterclosetime=%d", clock>=1 ? 0 : 1, clock, (int)self->camera.bin, (int)self->camera.size, (int)self->camera.gain, flipcmdstr[self->camera.flip], (int)self->camera.xstart, (int)self->camera.ystart, (int)self->camera.xend, (int)self->camera.yend, self->camera.exposure, self->camera.temp, (int)self->camera.thresh, (int)self->camera.shopt, (int)self->camera.shclt ); len = strlen(cmd); self->camera.updatecfg &= ~UPDATE_SETTINGS_CFG; if (self->debug) { snprintf(logmsg, MSGLEN, "DEBUG:(camdriv_out:UPDATE_SETTINGS_CFG): cmd=%s\n", cmd); SICSLogWrite(logmsg, eLog); } AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN); } if( (self->camera.updatecfg & CLEAR_META_CFG) == CLEAR_META_CFG) { snprintf(cmd, MSGLEN, "clear meta"); len = strlen(cmd); if (self->debug) { snprintf(logmsg, MSGLEN, "DEBUG:(camdriv_out:CLEAR_META_CFG): cmd=%s\n", cmd); SICSLogWrite(logmsg, eLog); } AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN); } if( (self->camera.updatecfg & UPDATE_META_CFG) == UPDATE_META_CFG) { //TODO concatenate the meta_list into a comma separated string and send it in MSGLEN chunks. for (i=0; i < self->camera.meta_count && pend < MSGLEN; i++) { pend = sprintf(cmd, "set meta,"); pend += snprintf(&cmd[pend], MSGLEN, "%s", self->camera.meta_list[i]); len = strlen(cmd); if (self->debug) { snprintf(logmsg, MSGLEN, "DEBUG:(camdriv_out:UPDATE_META_CFG): cmd=%s\n", cmd); SICSLogWrite(logmsg, eLog); } AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN); } } if( (self->camera.updatecfg & UPDATE_SCANVAR_CFG) == UPDATE_SCANVAR_CFG) { pend = sprintf(cmd, "set meta"); //TODO Send in MSGLEN chunks even though the string may never exceed MSGLEN for (i=0; i < self->camera.scanvar_count && pend < MSGLEN; i++) { fVal = self->camera.pscanvar[i]->GetValue(self->camera.scanvar_dummy[i], pServ->dummyCon); pend += snprintf(&cmd[pend], MSGLEN, ",%s=%f", self->camera.scanvar_list[i], fVal); } len = strlen(cmd); if (self->debug) { snprintf(logmsg, MSGLEN, "DEBUG:(camdriv_out:UPDATE_SCANVAR_CFG): cmd=%s\n", cmd); SICSLogWrite(logmsg, eLog); } AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN); } if( (self->camera.updatecfg & UPDATE_FILE_CFG) == UPDATE_FILE_CFG) { snprintf(cmd, MSGLEN, "set file,path=%s,basename=%s,startnumber=%ld,imageformat=%s,experimentdetail=%s", self->camera.file.path, self->camera.file.basename, self->camera.file.startnumber, self->camera.file.imageformat,self->camera.file.experimentdetail); len = strlen(cmd); if (self->debug) { snprintf(logmsg, MSGLEN, "DEBUG:(camdriv_out:UPDATE_FILE_CFG): cmd=%s\n", cmd); SICSLogWrite(logmsg, eLog); } AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN); self->camera.updatecfg &= ~UPDATE_FILE_CFG; } break; default: snprintf(logmsg, MSGLEN, "CAM:(camdriv_out) Unhandled event %s", event_names[Eo.ca]); SICSLogWrite(logmsg, eLogError); return -1; } return -1; } if (Eo.cm) { snprintf(logmsg, MSGLEN, "TODO:(camdriv_out:Eo.cm): ev=%s, output=%s\n", event_names[Eo.cm], event_signatures[Eo.cm]); SICSLogWrite(logmsg, eLogError); return -1; } if (Eo.cd) { snprintf(logmsg, MSGLEN, "TODO:(camdriv_out:Eo.cm): ev=%s, output=%s\n", event_names[Eo.cd], event_signatures[Eo.cd]); SICSLogWrite(logmsg, eLogError); return -1; } if (Eo.dr) { /* send msg to SICS */ if (self->debug) { snprintf(logmsg, MSGLEN, "DEBUG:(camdriv_out): ev=%s, output=%s\n", event_names[Eo.dr], event_signatures[Eo.dr]); SICSLogWrite(logmsg, eLog); } switch (Eo.dr) { case EDR_IDLE: self->status = HWIdle; break; case EDR_BUSY: self->status = HWBusy; break; case EDR_FAULT: self->status = HWFault; break; default: snprintf(logmsg, MSGLEN, "CAM:(camdriv_out) Unhandled event %s", event_names[Eo.dr]); SICSLogWrite(logmsg, eLogError); return -1; } return -1; } if (Eo.cl) { switch (Eo.cl) { case ECL_RDY: return ECL_RDY; break; default: snprintf(logmsg, MSGLEN, "CAM:(camdriv_out) Unhandled event %s", event_names[Eo.cl]); SICSLogWrite(logmsg, eLogError); return -1; } return -1; } return -1; } static int cb_state_timer(void *ctx, int mode) { CamObj *self = (CamObj *) ctx; char errmsg[32]=""; char cmd[MSGLEN]; int len, status; len = strlen(event_signatures[ECA_GET_STATE]); strncpy(cmd, event_signatures[ECA_GET_STATE], len); status = AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_getstate, self, MSGLEN); if (status==1) { return 1; } else { snprintf(errmsg, 31, "CAM:(cb_getstate) AsyncUnitSendTxn failed"); SICSLogWrite(errmsg, eLogError); return 0; } } /* Input from camera state feedback */ static int cb_getstate(pAsyncTxn txn) { CamObj *self = (CamObj *) txn->cntx; char *resp = txn->inp_buf, message[MSGLEN+1]; int ret=1, time_rem, time_tot; enum event_codes ca_sym, cm_sym; if (txn->txn_status == ATX_TIMEOUT) { ret = 0; } else if ( cam_parse_status(resp, &ca_sym, &time_rem, &time_tot) == -1) { snprintf(message, MSGLEN, "CAM:(cb_getstate) cam_parse_status failed to parse '%s'",resp); SICSLogWrite(message, eLogError); ret = 0; } else { if (self->debug) { snprintf(message, MSGLEN, "DEBUG:(cb_getstate) Camera reply: %s", resp); SICSLogWrite(message, eLog); } cm_sym = camera_model(ca_sym); run_sm(self, cm_sym); } return ret; } /* Auxiliary Camera Driver commands */ int cmd_code(char **cmd_list, char *cmd) { int i; for (i=0; cmd_list[i] != NULL; i++) if (strcasecmp(cmd_list[i], cmd) == 0) return i; return -1; } int file_cmd(CamObj *camdriv, SConnection *pCon, char *subcmd, char *data) { int i, subcmd_code, retval = 1; long numval; enum file_subcmd_codes {PATH, BASENAME, IMAGEFMT, STARTNUM, EXPDETAIL}; char *file_subcmd_names[] = {"path", "name", "format", "startnumber", "detail", NULL}; char *glemsg = NULL, emsg[MSGLEN]; if ( (subcmd_code = cmd_code(file_subcmd_names, subcmd)) == -1) { return 0; } switch (subcmd_code) { case PATH: snprintf(camdriv->camera.file.path, MSGLEN, "%s", data); break; case BASENAME: snprintf(camdriv->camera.file.basename, MSGLEN, "%s", data); break; case STARTNUM: numval = getlong(data, glemsg); if (glemsg == NULL) { camdriv->camera.file.startnumber = numval; } else if (glemsg == data) { snprintf(emsg, MSGLEN, "CAM:(file_cmd) %s is not an integer", data); SCWrite(pCon, emsg, eError); retval = 0; } else { snprintf(emsg, MSGLEN, "CAM:(file_cmd) %s", glemsg); SCWrite(pCon, emsg, eError); retval = 0; } break; case IMAGEFMT: if (strcasecmp(data, "tif") == 0) { for (i=0; data[i]; i++) { data[i] = tolower(data[i]); } snprintf(camdriv->camera.file.imageformat, IFMTLEN, "%s", data); } else { retval = 0; } break; case EXPDETAIL: snprintf(camdriv->camera.file.experimentdetail, MSGLEN, "%s", data); break; default: retval = 0; } return retval; } /** * \brief Auxiliary command interface which gets around type and string length * limitations of the CountAction command. */ int CamAuxCmd(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { char *cmd = NULL; char message[MSGLEN]; enum auxcmd_codes {CLEAR_META, META, FILECMD, SCANVAR, MOTOR}; char *auxcmd_names[] = {"clearmeta", "meta", "file", "scanvar", "motor", NULL}; int i, code, retval = 1, pend=0; CamObj *camdriv = (CamObj *)pData; CommandList *pCom = NULL; pIDrivable pDriv = NULL; pDummy pDumData = NULL; if (argc < 2) { snprintf(message, MSGLEN, "CAM: You must specify a command"); SCWrite(pCon, message, eError); return 0; } if ( (code = cmd_code(auxcmd_names, argv[1])) == -1 ) { snprintf(message, MSGLEN, "CAM: %s is not a valid command", argv[1]); SCWrite(pCon, message, eError); retval = 0; goto END; } switch (code) { case CLEAR_META: camdriv->camera.meta_count = 0; camdriv->camera.scanvar_count = 0; camdriv->camera.updatecfg |= CLEAR_META_CFG; camdriv->camera.updatecfg &= ~UPDATE_META_CFG; camdriv->camera.updatecfg &= ~UPDATE_SCANVAR_CFG; break; case META: if (argc < 3) { snprintf(message, MSGLEN, "CAM: Insufficient arguments, the META command requires name=val data"); SCWrite(pCon, message, eError); retval = 0; goto END; } if (camdriv->camera.meta_count < MAX_META_COUNT) { for (i=2; i < argc; i++) { pend += snprintf(&(camdriv->camera.meta_list[camdriv->camera.meta_count][pend]), MSGLEN, "%s ", argv[i]); } camdriv->camera.meta_count++; camdriv->camera.updatecfg |= UPDATE_META_CFG; } else { goto END; } break; case SCANVAR: case MOTOR: if (argc < 3) { snprintf(message, MSGLEN, "CAM: Insufficient arguments, the MOTOR/SCANVAR command requires the name of something you can drive like a motor or environment control"); SCWrite(pCon, message, eError); retval = 0; goto END; } if (camdriv->camera.scanvar_count < MAX_SCANVAR_COUNT) { pCom = FindCommand(pSics, argv[2]); if (!pCom) { snprintf(message, MSGLEN, "CAM: There is no command object for a driveable with this name %s", argv[2]); SCWrite(pCon, message, eError); retval = 0; goto END; } pDumData = (pDummy) pCom->pData; if (!pDumData) { snprintf(message, MSGLEN, "CAM: There is no data for the command object of a driveable with this name %s", argv[2]); SCWrite(pCon, message, eError); retval = 0; goto END; } pDriv = (pIDrivable) pDumData->pDescriptor->GetInterface(pDumData, DRIVEID); if (!pDriv) { snprintf(message, MSGLEN, "CAM: %s is not a driveable object", argv[2]); SCWrite(pCon, message, eError); retval = 0; goto END; } camdriv->camera.scanvar_dummy[camdriv->camera.scanvar_count] = pDumData; camdriv->camera.pscanvar[camdriv->camera.scanvar_count] = pDriv; snprintf(camdriv->camera.scanvar_list[camdriv->camera.scanvar_count++], NAMELEN, "%s", argv[2]); camdriv->camera.updatecfg |= UPDATE_SCANVAR_CFG; } else { snprintf(message, MSGLEN, "CAM: Exceeded maximum number (%d) of driveable objects", MAX_SCANVAR_COUNT); SCWrite(pCon, message, eError); retval = 0; goto END; } break; case FILECMD: if (argc < 4) { snprintf(message, MSGLEN, "CAM: Insufficient arguments for the FILE command"); SCWrite(pCon, message, eError); retval = 0; goto END; } if (file_cmd(camdriv, pCon, argv[2], argv[3])) camdriv->camera.updatecfg |= UPDATE_FILE_CFG; else { snprintf(message, MSGLEN, "CAM: Failed to create camera file configuration"); SCWrite(pCon, message, eError); retval = 0; goto END; } break; } END: if (cmd != NULL) free(cmd); return retval; } pCounterDriver CreateCam(SConnection *pCon, char *name, char *asynq) { char msg[ERRLEN], cmd[MSGLEN], auxcmd[NAMELEN]; int len; state_t start_state = {.cl=SCL_RDY, .cm=SCM_IDLE, .dr=SDR_IDLE}; pCounterDriver pCntDriv = NULL; CamObj *pNewCam = NULL; pNewCam = (CamObj *) malloc(sizeof(CamObj)); memset(pNewCam, 0, sizeof(CamObj)); pNewCam->pDes = CreateDescriptor("CameraCommandObject"); STset(&pNewCam->state_machine.Sc, start_state); EVclr(&pNewCam->state_machine.Eo); pNewCam->state_machine.output_fn = camdriv_out; pNewCam->state_machine.multi = 0; pNewCam->state_timer = 0; pNewCam->status = HWIdle; pNewCam->camError = ENONE; pNewCam->debug = 1; pNewCam->camera.updatecfg = 0; pNewCam->camera.meta_count = 0; pNewCam->camera.scanvar_count = 0; pNewCam->camera.file.startnumber = 1; snprintf(pNewCam->camera.file.imageformat, IFMTLEN, "tif"); pNewCam->camera.file.experimentdetail[0] = '\0'; pNewCam->asynq = strdup(asynq); pNewCam->pSics = pServ->pSics; if (!AsyncUnitCreate(asynq, &pNewCam->asyncUnit)) { snprintf(msg, ERRLEN, "CAM:AsyncQueue %s has not been defined", asynq); SCWrite(pCon, msg, eError); return NULL; } AsyncUnitSetTimeout(pNewCam->asyncUnit, 60000); AsyncUnitSetNotify(pNewCam->asyncUnit, pNewCam, CAM_Notify); pCntDriv = CreateCounterDriver(name, "anstocamera"); if (pCntDriv == NULL) return NULL; pCntDriv->GetStatus = CamGetStatus; pCntDriv->Start = CamStart; pCntDriv->Pause = CamPause; pCntDriv->Continue = CamContinue; pCntDriv->Halt = CamHalt; pCntDriv->ReadValues = CamReadValues; pCntDriv->GetError = CamGetError; pCntDriv->TryAndFixIt = CamTryAndFixIt; pCntDriv->Set = CamSet; pCntDriv->Get = CamGet; pCntDriv->Send = CamSend; pCntDriv->iNoOfMonitors = 1; pCntDriv->pData = pNewCam; len = strlen(event_signatures[ECA_GET_STATE]); strncpy(cmd, event_signatures[ECA_GET_STATE], len); NetWatchRegisterTimerPeriodic(&pNewCam->state_timer, 2000, 500, cb_state_timer, pNewCam); snprintf(auxcmd, NAMELEN, "%s_cmd", name); AddCommand(pNewCam->pSics, auxcmd, CamAuxCmd, NULL, pNewCam); return pCntDriv; }