diff --git a/site_ansto/Makefile b/site_ansto/Makefile index b33751d2..a53eb412 100644 --- a/site_ansto/Makefile +++ b/site_ansto/Makefile @@ -167,9 +167,7 @@ OBJ= site_ansto.o anstoutil.o\ hmcontrol_ansto.o\ lssmonitor.o \ beamstopaction.o action.o \ - tclClock.o tclDate.o tclUnixTime.o \ - camera.o\ - cameradriver.o + tclClock.o tclDate.o tclUnixTime.o all: ../matrix/libmatrix.a $(COREOBJ:%=../%) $(EXTRA:%=../%) libansto.a libhardsup $(CC) -g -o SICServer $(COREOBJ:%=../%) $(EXTRA:%=../%) $(SUBLIBS) $(PSI_SLIBS:%=../%) $(PSI_LIBS) $(GHTTP_LIBS) diff --git a/site_ansto/TESTS/dingo_camera/Makefile b/site_ansto/TESTS/dingo_camera/Makefile index 65d18253..c59f4709 100644 --- a/site_ansto/TESTS/dingo_camera/Makefile +++ b/site_ansto/TESTS/dingo_camera/Makefile @@ -1,5 +1,8 @@ # vim: ft=make: ts=8: sw=8: noet: cindent: -all: camera_test.c ../../camera.c ../../camera.h +all: camera_test.c ../../hardsup/camera.c ../../hardsup/camera.h gcc -g -Wall -Wextra -std=c99 -pedantic -I../../ -o camera_test camera_test.c ../../camera.c +clean: + rm camera_test + diff --git a/site_ansto/TESTS/dingo_camera/camera_test.c b/site_ansto/TESTS/dingo_camera/camera_test.c index 20fbbe3b..9b0cf856 100644 --- a/site_ansto/TESTS/dingo_camera/camera_test.c +++ b/site_ansto/TESTS/dingo_camera/camera_test.c @@ -22,7 +22,7 @@ void print_event(event_t E) { printf("%s,%s,%s,%s", ca, cm, cd, dr); } -event_t output(state_t Sc, int Ei) { +event_t output(state_t Sc, enum event_codes Ei) { int i; trans_t tr; event_t Eo; @@ -36,7 +36,8 @@ event_t output(state_t Sc, int Ei) { } int test_camrep2sym(void) { - int i, ca_sym, cm_sym, time_rem, time_tot; + int i, cm_sym, time_rem, time_tot; + enum event_codes ca_sym; char *camrep[] = { "StartTime Remaining= 3907 ms, Total Time=3686 ms,", "Open ShutrTime Remaining= 539454 ms, Total Time=3686 ms,", @@ -88,7 +89,9 @@ int test_trans_fn(void) { return 1; } -int camdriv_out(event_t Eo) { +int camdriv_out(void *me, event_t Eo) { + int *self = me; + *self=0; /* shudduppa your warnings */ if (Eo.ca) { /* send command to camera */ printf("camdriv_out: ev=%s, output=%s\n", event_names[Eo.ca], event_signatures[Eo.ca]); @@ -107,6 +110,7 @@ int camdriv_out(event_t Eo) { } int test_camdriv_input(void) { int Ein=ECD_TK_SHOT; + int self; camdriv_t cdinfo = { .Sc = {.cl=SCL_RDY, .cm=SCM_IDLE, .dr=SDR_IDLE}, .Eo = {.ca=0}, @@ -114,16 +118,45 @@ int test_camdriv_input(void) { .output_fn = camdriv_out, }; - camdriv_input(&cdinfo, Ein); + camdriv_input(&self, &cdinfo, Ein); return 1; } -int main() { - int ret; +char *tests[] = {"camrep2sym", "trans_fn", "camdriv_input"}; +void usage(char *name) { + int i; + printf("Usage: %s [n]\n",name); + printf("default: run all tests\n"); + printf("n is an int whose bits indicate which tests will be executed as follows\n"); + for (i=0; i<3; i++) + printf("n=%d; %s\n",1 << i, tests[i]); + printf("\n"); +} - ret = test_camrep2sym(); - ret = test_trans_fn(); - ret = test_camdriv_input(); +int main(int argc, char *argv[]) { + int ret, test=0, tflag=7; + + if (argc == 1) + test = tflag; + else if (strstr(argv[1], "help")) { + usage(argv[0]); + return 0; + } else + test = atoi(argv[1]); + + if ((test < 1) || (test > tflag)) { + printf("ERROR: Argument must be a positive integer between 1 and %d inclusive\n", tflag); + usage(argv[0]); + return 1; + } + + + if (test & 1) + ret = test_camrep2sym(); + if (test & 2) + ret = test_trans_fn(); + if (test & 4) + ret = test_camdriv_input(); if (ret) return 0; diff --git a/site_ansto/hardsup/camera.c b/site_ansto/hardsup/camera.c new file mode 100644 index 00000000..06148d61 --- /dev/null +++ b/site_ansto/hardsup/camera.c @@ -0,0 +1,197 @@ +#include +#include +#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}} +}; diff --git a/site_ansto/hardsup/camera.h b/site_ansto/hardsup/camera.h new file mode 100644 index 00000000..2cbdde2a --- /dev/null +++ b/site_ansto/hardsup/camera.h @@ -0,0 +1,213 @@ +/* Deterministic Finite State machine transducer (Mealy) + * The system is made up of three commponents, a command latch (CL), a camera + * model (CM) and the driver (DR). The system state machine is considered to be + * made up of the component state machines running in parallel and with some of + * the component stae machine transitions being restricted by system state + * transition rules. + * The sets of states are, + * SCL:Command Latch states, SCM:Camera Model states, SCDR:Driver states. + * Q is the set of system states. + * The sets of event symbols are defined as, + * ECA:Camera events, ECM:Camera model events, ECD:User command events, + * EDR:Driver events. + * + * In the following, '<' means subset + * Q < SCL X SCM X SCDR + * Ein = ECA U ECM U ECD U EDR + * Eo < ECA X ECM X ECD X EDR + * trans fn: QXEin -> Q + * out fn : QXEin -> Eo + * + * In the implementation the transition and output functions are combined in + * TRANS_TABLE. + */ +#ifndef CAMERA_H +#define CAMERA_H +/* TODO + * int output(state, event) return output event code + * int transition(state,event) return next state + * + */ + +/* END_TABLE marks the last row in the transition table */ +#define END_TABLE -1 +/* EVENT CODES */ +/* All event enum constants start with 'EXX_', XX identifies the source + * ECA_ : Camera event stream. Messages destined for or received from the camera. + * ECM_ : Events from the camera model. + * ECD_ : Command input, either directly from a user or via the scan command + * EDR_ : Driver events + */ +#define CAMERA_CMDS_TABLE \ + TR(ECA_TK_SHOT, "take shot") \ + TR(ECA_MLTI_ON, "take multi on") \ + TR(ECA_MLTI_OFF, "take multi off") \ + TR(ECA_GET_STATUS, "get status") \ + TE(ECA_GET_STATE, "get state") + +#define CAMERA_MSGS_TABLE \ + TR(ECA_START, "StartTime") \ + TR(ECA_OK, "OK") \ + TR(ECA_FAIL, "Fail") \ + TR(ECA_IDLE, "Idle") \ + TR(ECA_OPEN_SHUTR, "Open") \ + TR(ECA_CLOSE_SHUTR, "Close") \ + TR(ECA_ACQ_IMAGE, "Acq") \ + TR(ECA_READ_IMAGE, "Read") \ + TR(ECA_SEND_IMAGE, "Send") \ + TE(ECA_STOP, "Stop") + +#define CAM_MOD_EVENT_TABLE \ + TR(ECM_UNKNOWN, "Stop message received from camera") \ + TR(ECM_STOP, "Stop message received from camera") \ + TR(ECM_IDLE, "Camera in idle state") \ + TR(ECM_FAIL, "Command rejected") \ + TR(ECM_ACQ, "catch-all for start of acq phase") \ + TE(ECM_PROC, "catch-all for end of acq phase") + +/* COMMAND EVENTS + * These are events triggered by user input. + * The events can be direct via the 'send' subcommand or + * indirect via the scan command through the counter interface. + */ +#define CMD_EVENT_TABLE \ + TR(ECD_CMD_INPUT, "received a command") \ + TR(ECD_CLEAR, "Clear latched command") \ + TR(ECD_TK_SHOT, "take shot") \ + TR(ECD_TK_MLTI, "take multi on") \ + TR(ECD_GET_STATE, "get state") \ + TE(ECD_GET_STATUS, "get status") + +/* DRIVER EVENT TABLE + */ +#define DRIVER_EVENT_TABLE \ + TR(EDR_IDLE, "HWIDLE") \ + TR(EDR_BUSY, "HWBUSY") \ + TE(EDR_FAULT, "HWFAULT") + +#define ESLEN 32 + +/* STATE CODES + * NOTE: Every state will respond to a timer event and + * SXX_ State code enum constants, XX identifies a component of the system. + * SCL_ Command latch states + * SCM_ Camera model states + * SDR_ Driver states + */ +#define COMMAND_LATCH_STATE_TABLE \ + TR(SCL_RDY, "command latch ready to accept") \ + TR(SCL_TK_SHOT, "latched a take shot command") \ + TR(SCL_TK_MLTI, "latched a multi-shot command") \ + TE(SCL_WT_ACQ, "waiting for camera to start acquisition") + +#define CAMERA_MODEL_STATE_TABLE \ + TR(SCM_IDLE, "Camera is idle") \ + TR(SCM_ACQ, "Camera is acquiring an image") \ + TE(SCM_PROC, "Camera is processing an image") + +#define DRIVER_STATE_TABLE \ + TR(SDR_IDLE, "HWIdle") \ + TR(SDR_BUSY, "HWBusy") \ + TE(SDR_FAULT, "HWFault") + +#define SSLEN 32 + +/* Generate event and state symbols */ +#define TR(a,b) a, +#define TE(a,b) a +enum event_codes {ECA_UNKNOWN, CAMERA_CMDS_TABLE, CAMERA_MSGS_TABLE, CAM_MOD_EVENT_TABLE, DRIVER_EVENT_TABLE, CMD_EVENT_TABLE}; +#undef TR +#undef TE + +#define TR(n,d) n, +#define TE(n,d) n +enum command_latch_states {CL_Z,COMMAND_LATCH_STATE_TABLE}; +enum camera_model_states {CM_Z,CAMERA_MODEL_STATE_TABLE}; +enum driver_states {DR_Z,DRIVER_STATE_TABLE}; +#undef TR +#undef TE + +extern char *SCL_NAMES[]; +extern char *SCM_NAMES[]; +extern char *SDR_NAMES[]; +/* List of names generated from the event_codes. Defined in camera.c. */ +extern char *event_names[]; + +/* The signature array defines the identifying characters at the start of a reply. */ +extern char *event_signatures[]; + + + + +/* Output event channel + * A tuple (Eca,Ecm,Ecd,Edr) in ECA X ECM X ECD X EDR + */ +typedef struct { + enum event_codes ca; + enum event_codes cm; + enum event_codes cd; + enum event_codes dr; +} event_t; +/* A tuple (Scl,Scm,Sdr) in SCL X SCM X SDR */ +typedef struct { + int cl; + int cm; + int dr; +} state_t; +typedef struct { + state_t Sc; + enum event_codes Ei; + event_t Eo; + state_t Sn; +} trans_t; + +typedef struct { + state_t Sc; + event_t Eo; + int multi; + int (*output_fn)(void *caller, event_t Eo); +} camdriv_t; + +/* True if system state Sc is in St. + * St is normally the current state in the transition table + * and describes a range of possible states. + */ +#define INCL(Sc,St) (!St.cl || Sc.cl==St.cl) +#define INCM(Sc,St) (!St.cm || Sc.cm==St.cm) +#define INDR(Sc,St) (!St.dr || Sc.dr==St.dr) +#define INSYS(Sc,St) ( INCL(Sc,St) && INCM(Sc,St) && INDR(Sc,St) ) + + +void EVclr(event_t *E); +void EVset(event_t *E, event_t Ev); +void STset(state_t *Sc, state_t St); + +/* \brief Translates a camera status message to a camera (ECA_) event */ +enum event_codes cam_rep2sym(char *msg); + +/* \brief Converts a camera (ECA_) event to a camera modle (ECM_) event */ +enum event_codes camera_model(enum event_codes event); + +/* \brief Determines camera state from camera status message and reads acquisition + * time if camera is running. + * \param msg camera status message from the "get status" command. + * \param ca_sym symbol for the camera state in the status message, one of ECA_ enums. + * \param time_rem time remaining during while the camera is running. + * \param time_tot total time while the camera is running. + */ +int cam_parse_status(char *msg, enum event_codes *ca_sym, int *time_rem, int *time_tot); + +/* \brief Transition function for the camera system state machine. + * \param Sc the current system state. + * \param Ein input event. + * \param Sn the next system state. + * \param Eo the output events. + */ +int cam_trans_fn(state_t Sc, enum event_codes Ein, state_t *Sn, event_t *Eo); + +void camdriv_input(void *caller, camdriv_t *self, enum event_codes event_sym); + +char *strstate(state_t s); +char *strevent(event_t E); +extern trans_t TRANS_TABLE[]; +#endif diff --git a/site_ansto/hardsup/cameradriver.c b/site_ansto/hardsup/cameradriver.c new file mode 100644 index 00000000..2fe9322e --- /dev/null +++ b/site_ansto/hardsup/cameradriver.c @@ -0,0 +1,630 @@ +/* MGS_ :Message from camera Get Status command + */ +#include +#include +#include +#include +#include +#include "camera.h" + +#define ERRLEN 256 +#define MSGLEN 256 + +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(MULTI, "multi") \ + TR(CLOCK, "clock") \ + TR(BIN, "bin") \ + TR(SIZE, "size") \ + TR(GAIN, "gain") \ + TR(FLIP, "flip") \ + TR(XPOS, "xpos") \ + TR(YPOS, "ypos") \ + TR(TEMP, "temperature") \ + TR(THRESH, "threshold") \ + TR(SHOPT, "shutteropentime") \ + TE(SHCLT, "shutterclosetime") + +#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}; +enum flipval {FLIP_TABLE}; +#undef TR +#undef TE + +#define TR(a,b) b, +#define TE(a,b) b +static char *cacmdstr[] = {CAMDRIV_PARTABLE, NULL}; +static char *flipcmdstr[] = {FLIP_TABLE, NULL}; +#undef TR +#undef TE + +// Camera get/set commands: ['status', 'info', 'state', 'camera', 'meta', 'file'] +#define ECMDSTART 0 +#define EGETSTART 100 +#define ESETSTART 200 +typedef struct { + float clockMHz; + float bin; + float size; + float gain; + enum flipval flip; + float xpos; + float ypos; + float temp; + float thresh; + float shopt; + float shclt; + int updatecfg; +} camcfg_t; + +typedef struct { + int debug; + camdriv_t state_machine; + pNWTimer state_timer; + int status; + enum errcodes camError; + camcfg_t camera; +/* filecfg_t file;*/ + pAsyncUnit asyncUnit; +} CamObj; + +/* Camera communications and protocol handlers */ +static pAsyncProtocol CAM_Protocol = NULL; + +static int CAM_Tx(pAsyncProtocol p, pAsyncTxn txn) { + int ret = 1; + + if (txn) { + txn->txn_status = ATX_ACTIVE; + if (AsyncUnitWrite(txn->unit, txn->out_buf, txn->out_len) < 0) { + if (AsyncUnitReconnect(txn->unit) < 0) + ret = 0; + } + ret = 1; + } else { + ret = 0; + } + return ret; +} +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; +} +/* TODO +static int CAM_Ev(pAsyncProtocol p, pAsyncTxn txn, int event) { +} +*/ + +void CameraInitProtocol(SicsInterp *pSics) { + if (CAM_Protocol == NULL) { + CAM_Protocol = AsyncProtocolCreate(pSics, "CAMERA", NULL, NULL); + CAM_Protocol->sendCommand = CAM_Tx; + CAM_Protocol->handleInput = CAM_Rx; + CAM_Protocol->prepareTxn = NULL; + CAM_Protocol->killPrivate = NULL; + #if 0 + CAM_Protocol->handleEvent = CAM_Ev; + 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; +} + +static void crank_state_machine(CamObj *self, enum event_codes ev_sym) { + char sscur[SSLEN+1], ssnext[SSLEN+1], esout[ESLEN+1], message[MSGLEN+1]; + + if (self->debug) + strncpy(sscur, strstate(self->state_machine.Sc), SSLEN); + + camdriv_input(self, &self->state_machine, ev_sym); + + if (self->debug) { + strncpy(ssnext, strstate(self->state_machine.Sc), SSLEN); + strncpy(esout, strevent(self->state_machine.Eo), ESLEN); + snprintf(message, MSGLEN, + "DEBUG:(%s:%d) Scurr:%s Ein:%s|Snext:%s Eout:%s",__FILE__,__LINE__, + sscur,event_names[ev_sym],ssnext,esout); + SICSLogWrite(message, eLog); + } +} + +int sendcfg(CamObj *self) { + int status, replen=MSGLEN; + char reply[MSGLEN+1]; + char *cfgCmd = "set camera,clock=1MHz"; + + + status = AsyncUnitTransact(self->asyncUnit, cfgCmd, strlen(cfgCmd), reply, &replen); + return 1; +} + +static int CamStart(CounterDriver *cntrData) { + CamObj *self = NULL; + enum event_codes cd_sym; + + self = cntrData->pData; + + if (self->camera.updatecfg) { + if (sendcfg(self) == 0) { + /* ERROR failed to update configuration */ + return 0; + } + } + + if (self->state_machine.multi) { + cd_sym = ECD_TK_MLTI; + } else { + cd_sym = ECD_TK_SHOT; + } + crank_state_machine(self, cd_sym); + return 1; +} +static int CamPause(CounterDriver *cntrData) { + return 1; +} +static int CamContinue(CounterDriver *cntrData) { + return 1; +} +static int CamHalt(CounterDriver *cntrData) { + return 1; +} +static int CamReadValues(CounterDriver *cntrData) { + int status, iReplyLen=MSGLEN; + char *cmd="get imsz", pReply[MSGLEN]; + CamObj *self = NULL; + return 1; + + self = cntrData->pData; + // fTime = [get shtime] + 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, "CAMERR: Can't complete operation, %s", errmsg[EBUSYACQ]); + break; + case EBUSYSAVE: + snprintf(error, (size_t) iErrLen, "CAMERR: Can't complete operation, %s", errmsg[EBUSYSAVE]); + break; + case EBUSYPROC: + snprintf(error, (size_t) iErrLen, "CAMERR: Can't complete operation, %s", errmsg[EBUSYPROC]); + break; + case ENONE: + snprintf(error, (size_t) iErrLen, "CAMERR: Can't complete operation, %s", errmsg[ENONE]); + break; + case EFAIL: + snprintf(error, (size_t) iErrLen, "CAMERR: %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,cacmdstr[id]) == 0) { + found=1; + break; + } + } + + if (!found) { + return 0; + } + switch (id) { + 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 = 1; + } else { + return 0; + } + break; + case BIN: + if (fVal > 0) { + camdriv->camera.bin = fVal; + camdriv->camera.updatecfg = 1; + } else { + return 0; + } + break; + case SIZE: + if (fVal > 0) { + camdriv->camera.size = fVal; + camdriv->camera.updatecfg = 1; + } else { + return 0; + } + break; + case GAIN: + if (fVal > 0) { + camdriv->camera.gain = fVal; + camdriv->camera.updatecfg = 1; + } else { + return 0; + } + break; + case FLIP: + flip = fVal; + switch (flip) { + case NORMAL: + case INVINT: + case NORMFH: + case NORMFHV: + case INVFH: + case INVFV: + case INVFHV: + camdriv->camera.flip = flip; + break; + default: + return 0; + break; + } + break; + case XPOS: + if (fVal > 0) { + camdriv->camera.xpos = fVal; + camdriv->camera.updatecfg = 1; + } else { + return 0; + } + break; + case YPOS: + if (fVal > 0) { + camdriv->camera.ypos = fVal; + camdriv->camera.updatecfg = 1; + } else { + return 0; + } + break; + case TEMP: + if (fVal > 0) { + camdriv->camera.temp = fVal; + camdriv->camera.updatecfg = 1; + } else { + return 0; + } + break; + case THRESH: + if (fVal > 0) { + camdriv->camera.thresh = fVal; + camdriv->camera.updatecfg = 1; + } else { + return 0; + } + break; + case SHOPT: + if (fVal > 0) { + camdriv->camera.shopt = fVal; + camdriv->camera.updatecfg = 1; + } else { + return 0; + } + break; + case SHCLT: + if (fVal > 0) { + camdriv->camera.shclt = fVal; + camdriv->camera.updatecfg = 1; + } 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,cacmdstr[id]) == 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 XPOS: + *fVal = camdriv->camera.xpos; + break; + case YPOS: + *fVal = camdriv->camera.ypos; + 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; + + status = AsyncUnitTransact(self->asyncUnit, pText, strlen(pText), pReply, &iReplyLen); + return 1; +} + +static int cb_shotcmd(pAsyncTxn txn) { + CamObj *self = (CamObj *) txn->cntx; + char *resp = txn->inp_buf, message[MSGLEN+1]; + enum event_codes cd_sym; + + if (strncmp(resp, "OK", 2) != 0) { + self->camError = EFAIL; + return 0; + } + return 1; +} + +int camdriv_out(void *me, event_t Eo) { + int len; + char cmd[MSGLEN], logmsg[MSGLEN]; + CamObj *self = (CamObj *)me; + + if (Eo.ca) { + /* send command to camera */ + switch (Eo.ca) { + case ECA_TK_SHOT: + len = strlen(event_signatures[ECA_TK_SHOT]); + strncpy(cmd, event_signatures[ECA_TK_SHOT], len); + break; + case ECA_MLTI_ON: + len = strlen(event_signatures[ECA_MLTI_ON]); + strncpy(cmd, event_signatures[ECA_MLTI_ON], len); + break; + default: + break; + } + AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN); + if (self->debug) { + snprintf(logmsg, MSGLEN, "DEBUG: camdriv_out: ev=%s, output=%s\n", event_names[Eo.ca], event_signatures[Eo.ca]); + SICSLogWrite(logmsg, eLog); + } + } + if (Eo.cm) { + snprintf(logmsg, MSGLEN, "ERROR: NOT IMPLEMENTED, camdriv_out: ev=%s, output=%s\n", event_names[Eo.cm], event_signatures[Eo.cm]); + SICSLogWrite(logmsg, eLogError); + } + if (Eo.cd) { + snprintf(logmsg, MSGLEN, "ERROR: NOT IMPLEMENTED, camdriv_out: ev=%s, output=%s\n", event_names[Eo.cd], event_signatures[Eo.cd]); + SICSLogWrite(logmsg, eLogError); + } + if (Eo.dr) { + /* send msg to SICS */ + 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: + break; + } + 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); + } + } + return 1; +} +static int cb_getstate(pAsyncTxn txn); +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, "ERROR:(%s) AsyncUnitTransact failed",__FILE__); + 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 len = txn->inp_idx, ret=1, time_rem, time_tot; + enum event_codes ca_sym, cm_sym; + + + if ( cam_parse_status(resp, &ca_sym, &time_rem, &time_tot) == -1) { + snprintf(message, MSGLEN, "ERROR:(%s:%d) cam_parse_status failed on '%s'",__FILE__,__LINE__,resp); + SICSLogWrite(message, eLogError); + ret = 0; + } else { + cm_sym = camera_model(ca_sym); + crank_state_machine(self, cm_sym); + } + if (self->state_timer) { + NetWatchRemoveTimer(self->state_timer); + self->state_timer=0; + } + NetWatchRegisterTimer(&self->state_timer, 500, cb_state_timer, self); + return ret; +} + +pCounterDriver CreateCam(SConnection *pCon, char *name, char *asynq) { + char msg[ERRLEN], cmd[MSGLEN], reply[MSGLEN]; + int len, reply_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)); + 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; + + if (!AsyncUnitCreate(asynq, &pNewCam->asyncUnit)) { + snprintf(msg, ERRLEN, "CAMERR:AsyncQueue %s has not been defined", asynq); + SCWrite(pCon, msg, eError); + return NULL; + } + + 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); + AsyncUnitSendTxn(pNewCam->asyncUnit, cmd, len, cb_getstate, pNewCam, MSGLEN); + return pCntDriv; +} +#if 0 +int CameraAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { +CamObj *pCam = (CamObj *) pData; +} +int CamMakeCmd(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { + CamObj *pNew = NULL; + + pNew = CreateCam(argv[1], argv[2]); + if (pNew == NULL) + return 0; + AddCommand(pSics, argv[1], CameraAction, NULL, pNew); + return 1; +} +#endif diff --git a/site_ansto/hardsup/cameradriver.h b/site_ansto/hardsup/cameradriver.h new file mode 100644 index 00000000..3e0d3a01 --- /dev/null +++ b/site_ansto/hardsup/cameradriver.h @@ -0,0 +1,4 @@ +#ifndef CAMERADRIVER_H +#define CAMERADRIVER_H +void CameraInitProtocol(SicsInterp *pSics); +#endif diff --git a/site_ansto/hardsup/makefile b/site_ansto/hardsup/makefile index 939b3265..310c1070 100644 --- a/site_ansto/hardsup/makefile +++ b/site_ansto/hardsup/makefile @@ -32,7 +32,8 @@ HOBJ += sct_rfamp.o HOBJ += sinqhttpprot.o HOBJ += sct_protek608.o HOBJ += sct_lfprot.o -HOBJ += camserv.o +HOBJ += camera.o +HOBJ += cameradriver.o libhlib.a: $(HOBJ) rm -f libhlib.a