219 lines
6.4 KiB
C
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}}
|
|
};
|