Files
sics/site_ansto/hardsup/camera.c
2014-05-16 17:23:44 +10: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}}
};