198 lines
5.8 KiB
C
198 lines
5.8 KiB
C
#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;
|
|
}
|
|
}
|
|
/* NOTE the state is actually of the form (SCL_X,SCM_X,SDR_X)
|
|
* the table only shows the part of the state tuple which must match.
|
|
*/
|
|
|
|
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;
|
|
}
|
|
|
|
void camdriv_input(void *caller, camdriv_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;
|
|
}
|
|
|
|
/* 0 = wildcard for states.
|
|
* 0 = no output for the output events.
|
|
*/
|
|
int START_STATE = SCL_RDY|SCM_IDLE|SDR_IDLE;
|
|
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_TK_MLTI,{.dr=0}, {.cl=SCL_TK_MLTI}},
|
|
{{.cl=SCL_TK_SHOT}, ECM_IDLE, {.ca=ECA_TK_SHOT}, {.cl=SCL_WT_ACQ}},
|
|
{{.cl=SCL_TK_MLTI}, ECM_IDLE, {.ca=ECA_MLTI_ON}, {.cl=SCL_WT_ACQ}},
|
|
{{.cl=SCL_TK_SHOT}, ECD_CLEAR, {.dr=0}, {.cl=SCL_RDY}},
|
|
{{.cl=SCL_TK_MLTI}, ECD_CLEAR, {.dr=0}, {.cl=SCL_RDY}},
|
|
{{.cl=SCL_WT_ACQ}, ECM_ACQ, {.dr=0}, {.cl=SCL_RDY}},
|
|
{{.cl=SCL_WT_ACQ}, ECM_PROC, {.dr=0}, {.cl=SCL_RDY}},
|
|
{{.cl=SCL_WT_ACQ}, ECM_STOP, {.dr=0}, {.cl=SCL_RDY}},
|
|
/* ffr: Uncomment when we're sure that we don't receive "Idle" after "take shot"
|
|
* {{.cl=SCL_WT_ACQ}, 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_TK_MLTI,{.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}}
|
|
};
|