Files
sics/site_ansto/hardsup/camera.c
Ferdi Franceschini ad27488d3d Initial implementation of Dingo Camera driver.
Takes a single shot or a multishot.
If the user changes the camera configuration in SICS the new config will
be uploaded when the next take shot/multishot command is sent.
This driver allows the scan object in SICS to drive the scan variable to
the next target while the camera is processing and saving data after
acquiring an image.
TODO
Implement "set file,..." command.
2013-02-26 01:20:02 +11:00

219 lines
6.4 KiB
C

/**
* \file camera.c
* \brief Defines the state transition table and implements the state transition function
*
* \Author Ferdi Franceschini February 2013
*
* Copyright: see file Copyright.txt
*/
#include <stdio.h>
#include <string.h>
#include "camera.h"
#define TR(a,b) #a,
#define TE(a,b) #a
char *event_names[] = { "0", CAMERA_CMDS_TABLE, CAMERA_MSGS_TABLE, CAM_MOD_EVENT_TABLE, DRIVER_EVENT_TABLE, CMD_EVENT_TABLE };
#undef TR
#undef TE
/* The signature array defines the identifying characters at the start of a reply. */
#define TR(a,b) b,
#define TE(a,b) b
char *event_signatures[] = { "0", CAMERA_CMDS_TABLE, CAMERA_MSGS_TABLE, CAM_MOD_EVENT_TABLE, DRIVER_EVENT_TABLE, CMD_EVENT_TABLE };
#undef TR
#undef TE
#define TR(a,b) #a,
#define TE(a,b) #a
char *SCL_NAMES[] = {"0", COMMAND_LATCH_STATE_TABLE};
char *SCM_NAMES[] = {"0", CAMERA_MODEL_STATE_TABLE};
char *SDR_NAMES[] = {"0", DRIVER_STATE_TABLE};
#undef TR
#undef TE
#define TR(a,b) b,
#define TE(a,b) b
char *COMMAND_LATCH_STATE_DESCRIPTION[] = {"0", COMMAND_LATCH_STATE_TABLE};
char *CAMERA_MODEL_STATE_DESCRIPTION[] = {"0", CAMERA_MODEL_STATE_TABLE};
char *DRIVER_STATE_DESCRIPTION[] = {"0", DRIVER_STATE_TABLE};
#undef TR
#undef TE
char state_str[SSLEN+1];
char event_str[ESLEN+1];
/* Clear event channel */
void EVclr(event_t *E) {
E->ca=0;
E->cm=0;
E->cd=0;
E->dr=0;
}
/* Set event channel */
void EVset(event_t *E, event_t Ev) {
if (Ev.ca) E->ca = Ev.ca;
if (Ev.cm) E->cm = Ev.cm;
if (Ev.cd) E->cd = Ev.cd;
if (Ev.dr) E->dr = Ev.dr;
}
/* Set system state */
void STset(state_t *Sc, state_t St) {
if (St.cl) Sc->cl = St.cl;
if (St.cm) Sc->cm = St.cm;
if (St.dr) Sc->dr = St.dr;
}
enum event_codes camera_model(enum event_codes event) {
switch (event) {
case ECA_START:
case ECA_OPEN_SHUTR:
case ECA_ACQ_IMAGE:
return ECM_ACQ;
case ECA_CLOSE_SHUTR:
case ECA_READ_IMAGE:
case ECA_SEND_IMAGE:
return ECM_PROC;
case ECA_STOP:
return ECM_STOP;
case ECA_IDLE:
return ECM_IDLE;
case ECA_FAIL:
return ECM_FAIL;
default:
return ECM_UNKNOWN;
}
}
int cam_parse_status(char *msg, enum event_codes *ca_sym, int *time_rem, int *time_tot) {
char *delim=" ,";
char str[100], *tok;
int ret = 1;
strcpy(str,msg);
tok=strtok(str,delim);
ret = cam_rep2sym(tok);
if (ret != -1) {
*ca_sym = ret;
if (ECA_IDLE == *ca_sym) {
*time_rem = *time_tot = -1;
} else {
tok=strstr(msg, "Remaining");
sscanf(tok, " Remaining= %d ms, Total Time= %d ms, ", time_rem, time_tot);
}
}
return ret;
}
/* return -1 if message is unknown
* NOTE: 0 has meaning in the transition table
*/
enum event_codes cam_rep2sym(char *msg) {
int i;
for (i = ECA_START; i <= ECA_STOP; i++) {
if (0 == strcmp(msg, event_signatures[i])) {
return i;
}
}
return -1;
}
/* return 0 = no transition,
* return 1 = transition
*/
int cam_trans_fn(state_t Sc, enum event_codes Ein, state_t *Sn, event_t *Eo) {
trans_t tt;
int i, ret=0;
STset(Sn, Sc);
EVclr(Eo);
for (i=0; tt=TRANS_TABLE[i], tt.Sc.dr != END_TABLE; i++) {
if ( Ein == tt.Ei && INSYS(Sc,tt.Sc)) {
STset(Sn, tt.Sn);
EVset(Eo, tt.Eo);
ret = 1;
}
}
return ret;
}
/* TODO Do we need Eo in self, should camsm_t be refactored to remove it? */
void camdriv_input(void *caller, camsm_t *self, enum event_codes event_sym) {
state_t Sn;
cam_trans_fn(self->Sc, event_sym, &Sn, &self->Eo);
self->output_fn(caller, self->Eo);
self->Sc = Sn;
}
char *strstate(state_t s) {
char *cl, *cm, *dr;
cm = SCM_NAMES[s.cm];
cl = SCL_NAMES[s.cl];
dr = SDR_NAMES[s.dr];
snprintf(state_str, SSLEN, "%s,%s,%s", cm, cl, dr);
return state_str;
}
char *strevent(event_t E) {
char *ca, *cm, *cd, *dr;
ca = event_names[E.ca];
cm = event_names[E.cm];
cd = event_names[E.cd];
dr = event_names[E.dr];
snprintf(event_str, ESLEN, "%s,%s,%s,%s", ca, cm, cd, dr);
return event_str;
}
/* The transition table has four columns,
* {current state}, input_event, {output events}, {next state}
*
* Each state is actually a 3-tuple (cl,cm,dr) where
* cl = command latch state
* cm = camera model state
* dr = driver state
*
* There is only one stream in the input event channel.
*
* The output event channel is a 4-tuple (ca,cm,cd,dr) where
* ca = camera event stream
* cm = cameram model event stream
* cd = command event stream
* dr = driver event stream
*
* The next state is a 3-tuple as above.
*
* 0 = wildcard for components of current state.
* 0 = no output for the output events.
* 0 = no change for components of next state.
*/
trans_t TRANS_TABLE[] = {
{{.cl=SCL_RDY, .dr=SDR_IDLE}, ECD_TK_SHOT, {.dr=0}, {.cl=SCL_TK_SHOT}},
{{.cl=SCL_RDY, .dr=SDR_IDLE}, ECD_MLTI_ON, {.dr=0}, {.cl=SCL_TK_MLTI}},
{{.cl=SCL_TK_SHOT}, ECM_IDLE, {.ca=ECA_TK_SHOT}, {.cl=SCL_WT}},
{{.cl=SCL_TK_MLTI}, ECD_MLTI_OFF,{.dr=0}, {.cl=SCL_RDY}},
{{.cl=SCL_TK_MLTI}, ECM_IDLE, {.ca=ECA_MLTI_ON}, {.cl=SCL_MLTI_ON}},
{{.cl=SCL_MLTI_ON}, ECD_MLTI_OFF,{.ca=ECA_MLTI_OFF},{.cl=SCL_WT}},
{{.cl=SCL_WT}, ECM_ACQ, {.dr=0}, {.cl=SCL_RDY}},
{{.cl=SCL_WT}, ECM_PROC, {.dr=0}, {.cl=SCL_RDY}},
{{.cl=SCL_WT}, ECM_STOP, {.dr=0}, {.cl=SCL_RDY}},
{{.cl=SCL_WT}, ECM_IDLE, {.dr=0}, {.cl=SCL_RDY}},
{{.cm=SCM_IDLE}, ECM_ACQ, {.dr=0}, {.cm=SCM_ACQ}},
{{.cm=SCM_IDLE}, ECM_PROC, {.dr=0}, {.cm=SCM_PROC}},
{{.cm=SCM_ACQ}, ECM_PROC, {.dr=0}, {.cm=SCM_PROC}},
{{.cm=SCM_ACQ}, ECM_STOP, {.dr=0}, {.cm=SCM_IDLE}},
{{.cm=SCM_PROC}, ECM_STOP, {.dr=0}, {.cm=SCM_IDLE}},
{{.cm=SCM_ACQ}, ECM_IDLE, {.dr=0}, {.cm=SCM_IDLE}},
{{.cm=SCM_PROC}, ECM_IDLE, {.dr=0}, {.cm=SCM_IDLE}},
{{.dr=SDR_IDLE}, ECD_TK_SHOT, {.dr=EDR_BUSY}, {.dr=SDR_BUSY}},
{{.dr=SDR_IDLE}, ECD_MLTI_ON, {.dr=EDR_BUSY}, {.dr=SDR_BUSY}},
{{.dr=SDR_BUSY, .cl=SCL_RDY}, ECM_PROC, {.dr=EDR_IDLE}, {.dr=SDR_IDLE}},
{{.dr=SDR_BUSY, .cl=SCL_RDY}, ECM_STOP, {.dr=EDR_IDLE}, {.dr=SDR_IDLE}},
{{.dr=SDR_BUSY, .cl=SCL_RDY}, ECM_IDLE, {.dr=EDR_IDLE}, {.dr=SDR_IDLE}},
{{.dr=END_TABLE}, END_TABLE, {.dr=END_TABLE}, {.dr=END_TABLE}}
};