Merge branch 'dingo' into merge-replace
This commit is contained in:
218
site_ansto/hardsup/camera.c
Normal file
218
site_ansto/hardsup/camera.c
Normal file
@@ -0,0 +1,218 @@
|
||||
/**
|
||||
* \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}}
|
||||
};
|
||||
247
site_ansto/hardsup/camera.h
Normal file
247
site_ansto/hardsup/camera.h
Normal file
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* \file camera.h
|
||||
* \brief Enumerates event codes and states, and defines the abstract
|
||||
* types used in the state machine.
|
||||
*
|
||||
* \Author Ferdi Franceschini February 2013
|
||||
*
|
||||
* Copyright: see file Copyright.txt
|
||||
*
|
||||
* Deterministic Finite State machine transducer (Mealy)
|
||||
* The idea is to synthesize a state machine which handles the union of input
|
||||
* events for a given set state machines in a system.
|
||||
*
|
||||
* The system is made up of three components, 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 state 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.
|
||||
*
|
||||
* The system state machine for the camera driver is defined as follows.
|
||||
* 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
|
||||
|
||||
/* 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_SET_CAM, "set camera") \
|
||||
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_CLEAR, "Clear latched command") \
|
||||
TR(ECD_TK_SHOT, "take shot") \
|
||||
TR(ECD_MLTI_ON, "take multi on") \
|
||||
TR(ECD_MLTI_OFF, "take multi off") \
|
||||
TR(ECD_GET_STATE, "get state") \
|
||||
TE(ECD_GET_STATUS, "get status")
|
||||
|
||||
/* DRIVER EVENT TABLE
|
||||
* These events are of interest to SICS.
|
||||
*/
|
||||
#define DRIVER_EVENT_TABLE \
|
||||
TR(EDR_IDLE, "HWIDLE") \
|
||||
TR(EDR_BUSY, "HWBUSY") \
|
||||
TE(EDR_FAULT, "HWFAULT")
|
||||
|
||||
#define ESLEN 32
|
||||
|
||||
/* STATE CODES
|
||||
* 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") \
|
||||
TR(SCL_MLTI_ON, "multi-shot is running") \
|
||||
TE(SCL_WT, "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
|
||||
|
||||
/* Enumerate 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. */
|
||||
extern char *event_names[];
|
||||
|
||||
/* The signature array includes the identifying characters at the start of a reply.
|
||||
* as well as camera commands or just describes the corresponding symbols.
|
||||
*/
|
||||
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;
|
||||
|
||||
/* Defines a row in the transition table */
|
||||
typedef struct {
|
||||
state_t Sc;
|
||||
enum event_codes Ei;
|
||||
event_t Eo;
|
||||
state_t Sn;
|
||||
} trans_t;
|
||||
|
||||
/* Transfer object for state machine IO and transitions
|
||||
* output_fn: This is the output function callback. It must be defined by the
|
||||
* IO layer (ie cameradriver.c).
|
||||
*/
|
||||
typedef struct {
|
||||
state_t Sc;
|
||||
event_t Eo;
|
||||
int multi;
|
||||
int debug;
|
||||
int (*output_fn)(void *caller, event_t Eo);
|
||||
} camsm_t;
|
||||
|
||||
/* Are we in the SCL_XX, SCM_ or SDR_ state?
|
||||
* NOTE: 0 is a wildcard so any Sc.cl value matches St.cl==0
|
||||
*/
|
||||
#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)
|
||||
/* INSYS is 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 INSYS(Sc,St) ( INCL(Sc,St) && INCM(Sc,St) && INDR(Sc,St) )
|
||||
|
||||
|
||||
/* Clear the given event */
|
||||
void EVclr(event_t *E);
|
||||
/* Set E to Ev */
|
||||
void EVset(event_t *E, event_t Ev);
|
||||
/* Set Sc to St */
|
||||
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);
|
||||
|
||||
/* \brief This is the state machine input function called by the IO layer (ie cameradriver.c)
|
||||
*
|
||||
* \param caller, Provides context info for the ouput function callback.
|
||||
* \param self, Provides current state on input and next state and output event on return.
|
||||
*/
|
||||
void camdriv_input(void *caller, camsm_t *self, enum event_codes event_sym);
|
||||
|
||||
/* Convenience functions to convert a state or event to a descriptive string */
|
||||
char *strstate(state_t s);
|
||||
char *strevent(event_t E);
|
||||
|
||||
/* The transition table */
|
||||
extern trans_t TRANS_TABLE[];
|
||||
#endif
|
||||
798
site_ansto/hardsup/cameradriver.c
Normal file
798
site_ansto/hardsup/cameradriver.c
Normal file
@@ -0,0 +1,798 @@
|
||||
/**
|
||||
* \file cameradriver.c
|
||||
* \brief This provides the IO layer which feeds inputs from a user or
|
||||
* the camera server to the state machine, and then sends any state machine
|
||||
* output back to SICS or the camera.
|
||||
*
|
||||
* \Author Ferdi Franceschini February 2013
|
||||
*
|
||||
* Copyright: see file Copyright.txt
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <sics.h>
|
||||
#include <obdes.h>
|
||||
#include <countdriv.h>
|
||||
#include <nwatch.h>
|
||||
#include <asyncqueue.h>
|
||||
#include <math.h>
|
||||
#include "camera.h"
|
||||
|
||||
#define ERRLEN 256
|
||||
#define MSGLEN 512
|
||||
|
||||
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(CLOCK, "clock") \
|
||||
TR(BIN, "bin") \
|
||||
TR(SIZE, "size") \
|
||||
TR(GAIN, "gain") \
|
||||
TR(FLIP, "flip") \
|
||||
TR(XSTART, "xstart") \
|
||||
TR(YSTART, "ystart") \
|
||||
TR(XEND, "xend") \
|
||||
TR(YEND, "yend") \
|
||||
TR(EXPOSURE, "exposure") \
|
||||
TR(TEMP, "temperature") \
|
||||
TR(THRESH, "threshold") \
|
||||
TR(SHOPT, "shutteropentime") \
|
||||
TE(SHCLT, "shutterclosetime")
|
||||
#define TR(a,b) 1+
|
||||
#define TE(a,b) 1
|
||||
static int NUMCAMPAR = CAMDRIV_PARTABLE;
|
||||
#undef TR
|
||||
#undef TE
|
||||
|
||||
#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, MULTI};
|
||||
enum flipval {FLIP_TABLE};
|
||||
#undef TR
|
||||
#undef TE
|
||||
|
||||
#define TR(a,b) b,
|
||||
#define TE(a,b) b
|
||||
static char *cacmdstr[] = {CAMDRIV_PARTABLE, "multi", 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 xstart;
|
||||
float ystart;
|
||||
float xend;
|
||||
float yend;
|
||||
float exposure;
|
||||
float temp;
|
||||
float thresh;
|
||||
float shopt;
|
||||
float shclt;
|
||||
int updatecfg;
|
||||
} camcfg_t;
|
||||
|
||||
typedef struct {
|
||||
char path[MSGLEN];
|
||||
char basename[MSGLEN];
|
||||
int startnumber;
|
||||
char imageformat[MSGLEN];
|
||||
char experimentdetail[MSGLEN];
|
||||
int updatecfg;
|
||||
} filecfg_t;
|
||||
|
||||
typedef struct {
|
||||
int debug;
|
||||
char *asynq;
|
||||
camsm_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 cb_state_timer(void *ctx, int mode);
|
||||
static int cb_getstate(pAsyncTxn txn);
|
||||
|
||||
static void CAM_Notify(void* context, int event) {
|
||||
CamObj *self = (CamObj *) context;
|
||||
|
||||
switch (event) {
|
||||
case AQU_DISCONNECT:
|
||||
SICSLogWrite("CAM:(AQU_DISCONNECT)", eLogError);
|
||||
break;
|
||||
case AQU_RECONNECT:
|
||||
SICSLogWrite("CAM:(AQU_RECONNECT)", eLogError);
|
||||
if (self->state_timer) {
|
||||
NetWatchRemoveTimer(self->state_timer);
|
||||
self->state_timer=0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int CAM_Tx(pAsyncProtocol p, pAsyncTxn txn) {
|
||||
|
||||
if (txn == NULL) {
|
||||
return 0;
|
||||
}
|
||||
txn->txn_status = ATX_ACTIVE;
|
||||
if (AsyncUnitWrite(txn->unit, txn->out_buf, txn->out_len) < 0) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
static int CAM_Ev(pAsyncProtocol p, pAsyncTxn pTxn, int event) {
|
||||
if (event == AQU_TIMEOUT) {
|
||||
pTxn->txn_status = ATX_TIMEOUT;
|
||||
return AQU_POP_CMD;
|
||||
}
|
||||
return AQU_POP_CMD;
|
||||
}
|
||||
|
||||
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;
|
||||
CAM_Protocol->handleEvent = CAM_Ev;
|
||||
#if 0
|
||||
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;
|
||||
}
|
||||
|
||||
/* \brief run_sm, call the state machine with the given input.
|
||||
* \param self, driver context including current state
|
||||
* \param ev_sym, input event
|
||||
*/
|
||||
static void run_sm(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:(run_sm) Scurr:%s Ei:%s",
|
||||
sscur,event_names[ev_sym]);
|
||||
SICSLogWrite(message, eLog);
|
||||
snprintf(message, MSGLEN, "DEBUG:(run_sm) Snext:%s Eo:%s", ssnext,esout);
|
||||
SICSLogWrite(message, eLog);
|
||||
}
|
||||
}
|
||||
|
||||
/* \brief sendcfg, Send the camera configuration to the camera server
|
||||
*/
|
||||
int sendcfg(CamObj *self) {
|
||||
int status, replen=MSGLEN;
|
||||
char reply[MSGLEN+1], logmsg[MSGLEN+1];
|
||||
char cfgCmd[MSGLEN+1];
|
||||
float clock = self->camera.clockMHz;
|
||||
|
||||
if(self->camera.updatecfg) {
|
||||
sprintf(cfgCmd,
|
||||
"set camera,clock=%.*fmhz,bin=%dx,size=%d,gain=%dxhs,flip=%s,xstart=%d,ystart=%d,xend=%d,yend=%d,exposure=%f,temperature=%f,threshold=%d,shutteropentime=%d,shutterclosetime=%d",
|
||||
clock>=1 ? 0 : 1, clock, (int)self->camera.bin, (int)self->camera.size,
|
||||
(int)self->camera.gain, flipcmdstr[self->camera.flip],
|
||||
(int)self->camera.xstart, (int)self->camera.ystart,
|
||||
(int)self->camera.xend, (int)self->camera.yend, self->camera.exposure,
|
||||
self->camera.temp, (int)self->camera.thresh, (int)self->camera.shopt,
|
||||
(int)self->camera.shclt
|
||||
);
|
||||
|
||||
status = AsyncUnitTransact(self->asyncUnit, cfgCmd, strlen(cfgCmd), reply, &replen);
|
||||
if (status <= 0)
|
||||
return 0;
|
||||
else
|
||||
if (strncmp("OK", reply, 2) == 0)
|
||||
return 1;
|
||||
else {
|
||||
snprintf(logmsg, MSGLEN, "CAM:(sendcfg) set camera reply=%s", reply);
|
||||
SICSLogWrite(logmsg, eLogError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* TBD, other fields to be set
|
||||
if(self->file.updatecfg) {
|
||||
sprintf(cfgCmd, "set camera, path=%s,basename=%s,startnumber=%d,imageformat=%s,experimentdetail=%s",
|
||||
self->file.path,
|
||||
self->file.basename,
|
||||
self->file.startnumber,
|
||||
self->file.imageformat, self->file.experimentdetail);
|
||||
status = AsyncUnitTransact(self->asyncUnit, cfgCmd, strlen(cfgCmd), reply, &replen);
|
||||
if (status <= 0)
|
||||
return 0;
|
||||
else
|
||||
if (strncmp("OK", reply, 2) == 0)
|
||||
return 1;
|
||||
else {
|
||||
snprintf(logmsg, MSGLEN, "CAM:(sendcfg) set file reply=%s", reply);
|
||||
SICSLogWrite(logmsg, eLogError);
|
||||
return 0;
|
||||
}
|
||||
} */
|
||||
|
||||
}
|
||||
|
||||
/* Called by the scan command and via the count and countnb subcommands of a
|
||||
* counter object. Will update the configuration if necessary.
|
||||
*/
|
||||
static int CamStart(CounterDriver *cntrData) {
|
||||
CamObj *self = NULL;
|
||||
enum event_codes cd_sym;
|
||||
char logmsg[MSGLEN+1];
|
||||
|
||||
self = cntrData->pData;
|
||||
|
||||
/* Send the updated configuration to the camera server if it has been changed
|
||||
* on SICS since the last shot was taken. */
|
||||
if (self->camera.updatecfg) {
|
||||
if (sendcfg(self) == 0) {
|
||||
snprintf(logmsg, MSGLEN, "CAM:(CamStart) Failed to upload configuration");
|
||||
SICSLogWrite(logmsg, eLogError);
|
||||
return 0;
|
||||
}
|
||||
self->camera.updatecfg = 0;
|
||||
}
|
||||
|
||||
if (self->state_machine.multi) {
|
||||
cd_sym = ECD_MLTI_ON;
|
||||
} else {
|
||||
cd_sym = ECD_TK_SHOT;
|
||||
}
|
||||
run_sm(self, cd_sym);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int CamPause(CounterDriver *cntrData) {
|
||||
return 1;
|
||||
}
|
||||
static int CamContinue(CounterDriver *cntrData) {
|
||||
return 1;
|
||||
}
|
||||
static int CamHalt(CounterDriver *cntrData) {
|
||||
CamObj *self = cntrData->pData;
|
||||
|
||||
if (self->state_machine.multi) {
|
||||
run_sm(self, ECD_MLTI_OFF);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/* TODO what should the counter data be set to? Total intensity? */
|
||||
static int CamReadValues(CounterDriver *cntrData) {
|
||||
int status, iReplyLen=MSGLEN;
|
||||
char *cmd="TODO ", pReply[MSGLEN];
|
||||
CamObj *self = NULL;
|
||||
return 1;
|
||||
|
||||
self = cntrData->pData;
|
||||
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,
|
||||
"CAM: Can't complete operation, %s", errmsg[EBUSYACQ]);
|
||||
break;
|
||||
case EBUSYSAVE:
|
||||
snprintf(error, (size_t) iErrLen,
|
||||
"CAM: Can't complete operation, %s", errmsg[EBUSYSAVE]);
|
||||
break;
|
||||
case EBUSYPROC:
|
||||
snprintf(error, (size_t) iErrLen,
|
||||
"CAM: Can't complete operation, %s", errmsg[EBUSYPROC]);
|
||||
break;
|
||||
case ENONE:
|
||||
snprintf(error, (size_t) iErrLen,
|
||||
"CAM: Can't complete operation, %s", errmsg[ENONE]);
|
||||
break;
|
||||
case EFAIL:
|
||||
snprintf(error, (size_t) iErrLen, "CAM: %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,name) == 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 NORMFV:
|
||||
case NORMFHV:
|
||||
case INVFH:
|
||||
case INVFV:
|
||||
case INVFHV:
|
||||
camdriv->camera.flip = flip;
|
||||
camdriv->camera.updatecfg = 1;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case XSTART:
|
||||
if (fVal > 0) {
|
||||
camdriv->camera.xstart = fVal;
|
||||
camdriv->camera.updatecfg = 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case YSTART:
|
||||
if (fVal > 0) {
|
||||
camdriv->camera.ystart = fVal;
|
||||
camdriv->camera.updatecfg = 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case XEND:
|
||||
if (fVal > 0) {
|
||||
camdriv->camera.xend = fVal;
|
||||
camdriv->camera.updatecfg = 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case YEND:
|
||||
if (fVal > 0) {
|
||||
camdriv->camera.yend = fVal;
|
||||
camdriv->camera.updatecfg = 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case EXPOSURE:
|
||||
if (fVal > 0) {
|
||||
camdriv->camera.exposure = fVal;
|
||||
camdriv->camera.updatecfg = 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case TEMP:
|
||||
camdriv->camera.temp = fVal;
|
||||
camdriv->camera.updatecfg = 1;
|
||||
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,name) == 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 XSTART:
|
||||
*fVal = camdriv->camera.xstart;
|
||||
break;
|
||||
case YSTART:
|
||||
*fVal = camdriv->camera.ystart;
|
||||
break;
|
||||
case XEND:
|
||||
*fVal = camdriv->camera.xend;
|
||||
break;
|
||||
case YEND:
|
||||
*fVal = camdriv->camera.yend;
|
||||
break;
|
||||
case EXPOSURE:
|
||||
*fVal = camdriv->camera.exposure;
|
||||
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;
|
||||
|
||||
//char *pBuf = (char *)calloc(strlen(pText)+10, sizeof(char));
|
||||
//sprintf(pBuf, "set meta, %s", pText);
|
||||
//status = AsyncUnitTransact(self->asyncUnit, pBuf, strlen(pBuf), pReply, &iReplyLen);
|
||||
status = AsyncUnitTransact(self->asyncUnit, pText, strlen(pText), pReply, &iReplyLen);
|
||||
//free(pBuf);
|
||||
if (status <= 0)
|
||||
return 0;
|
||||
else
|
||||
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+1]="";
|
||||
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;
|
||||
case ECA_MLTI_OFF:
|
||||
len = strlen(event_signatures[ECA_MLTI_OFF]);
|
||||
strncpy(cmd, event_signatures[ECA_MLTI_OFF], len);
|
||||
break;
|
||||
default:
|
||||
snprintf(logmsg, MSGLEN, "CAM:(camdriv_out) Unhandled event %s", event_names[Eo.ca]);
|
||||
SICSLogWrite(logmsg, eLogError);
|
||||
return 0;
|
||||
}
|
||||
AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN);
|
||||
if (self->debug) {
|
||||
snprintf(logmsg, MSGLEN, "DEBUG:(camdriv_out:Eo.ca): ev=%s, output=%s\n",
|
||||
event_names[Eo.ca], event_signatures[Eo.ca]);
|
||||
SICSLogWrite(logmsg, eLog);
|
||||
}
|
||||
}
|
||||
if (Eo.cm) {
|
||||
snprintf(logmsg, MSGLEN, "TODO:(camdriv_out:Eo.cm): ev=%s, output=%s\n",
|
||||
event_names[Eo.cm], event_signatures[Eo.cm]);
|
||||
SICSLogWrite(logmsg, eLogError);
|
||||
}
|
||||
if (Eo.cd) {
|
||||
snprintf(logmsg, MSGLEN, "TODO:(camdriv_out:Eo.cm): 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:
|
||||
snprintf(logmsg, MSGLEN, "CAM:(camdriv_out) Unhandled event %s", event_names[Eo.dr]);
|
||||
SICSLogWrite(logmsg, eLogError);
|
||||
return 0;
|
||||
}
|
||||
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_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, "CAM:(cb_getstate) AsyncUnitSendTxn failed");
|
||||
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 (txn->txn_status == ATX_TIMEOUT) {
|
||||
ret = 0;
|
||||
} else if ( cam_parse_status(resp, &ca_sym, &time_rem, &time_tot) == -1) {
|
||||
snprintf(message, MSGLEN,
|
||||
"CAM:(cb_getstate) cam_parse_status failed to parse '%s'",resp);
|
||||
SICSLogWrite(message, eLogError);
|
||||
ret = 0;
|
||||
} else {
|
||||
cm_sym = camera_model(ca_sym);
|
||||
run_sm(self, cm_sym);
|
||||
}
|
||||
if (self->state_timer) {
|
||||
NetWatchRemoveTimer(self->state_timer);
|
||||
self->state_timer=0;
|
||||
}
|
||||
char logmsg[MSGLEN+1]="";
|
||||
snprintf(logmsg, MSGLEN,"CAM:(cb_getstate) Entering NetWatchRegisterTimer");
|
||||
SICSLogWrite(logmsg, eLog);
|
||||
NetWatchRegisterTimer(&self->state_timer, 500, cb_state_timer, self);
|
||||
snprintf(logmsg, MSGLEN,"CAM:(cb_getstate) Leaving NetWatchRegisterTimer");
|
||||
SICSLogWrite(logmsg, eLog);
|
||||
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 = 1;
|
||||
pNewCam->asynq = strdup(asynq);
|
||||
|
||||
if (!AsyncUnitCreate(asynq, &pNewCam->asyncUnit)) {
|
||||
snprintf(msg, ERRLEN, "CAM:AsyncQueue %s has not been defined", asynq);
|
||||
SCWrite(pCon, msg, eError);
|
||||
return NULL;
|
||||
}
|
||||
AsyncUnitSetTimeout(pNewCam->asyncUnit, 1000);
|
||||
AsyncUnitSetNotify(pNewCam->asyncUnit, pNewCam, CAM_Notify);
|
||||
|
||||
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;
|
||||
}
|
||||
4
site_ansto/hardsup/cameradriver.h
Normal file
4
site_ansto/hardsup/cameradriver.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#ifndef CAMERADRIVER_H
|
||||
#define CAMERADRIVER_H
|
||||
void CameraInitProtocol(SicsInterp *pSics);
|
||||
#endif
|
||||
@@ -32,6 +32,8 @@ HOBJ += sct_rfamp.o
|
||||
HOBJ += sinqhttpprot.o
|
||||
HOBJ += sct_protek608.o
|
||||
HOBJ += sct_lfprot.o
|
||||
HOBJ += camera.o
|
||||
HOBJ += cameradriver.o
|
||||
|
||||
libhlib.a: $(HOBJ)
|
||||
rm -f libhlib.a
|
||||
|
||||
Reference in New Issue
Block a user