Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions .github/workflows/emulator-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,12 @@ jobs:
echo "$resp" | grep -q "$2" || { echo "expected \"$2\""; exit 1; }
}

expect "open" "DONE"
expect "load" "DONE"
expect "power on" "DONE"
expect "exptime 0.1" "DONE"
expect "expose 1" "DONE"
expect "open" "DONE"
expect "load" "DONE"
expect "power on" "DONE"
expect "exposuremode SINGLE" "^SINGLE DONE"
expect "exptime 0.1" "DONE"
expect "expose 1" "DONE"

# instrument command, replying with the value configure_instrument() read
expect "refvalue" "^reference-cfg-value DONE"
Expand All @@ -163,8 +164,25 @@ jobs:
expect "exposuremode REFERENCE" "^REFERENCE DONE"
expect "expose 1" "DONE"
expect "exposuremode" "^REFERENCE DONE"

# applying an ACF mode section leaves the exposure mode alone
expect "acfmode DEFAULT" "^DONE"
expect "exposuremode" "^REFERENCE"

expect "exposuremode SINGLE" "^SINGLE DONE"
expect "expose 1" "DONE"

# acfmode and getp are the Archon interface's own commands, reached
# through controller_cmd; a name nobody claims is an error
expect "acfmode DEFAULT" "^DONE"
expect "getp nRowsQuad" "^[0-9]"
expect "nosuchcommand" "^not_supported ERROR"

# a load leaves no exposure mode selected, so an exposure is refused
expect "load" "DONE"
expect "power on" "DONE"
expect "exposuremode" "^undefined ERROR"
expect "expose 1" "^exposure mode not set"

- name: Reference module import test
run: ctest --test-dir build-reference --output-on-failure
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ camera.instrument_cmd("roi", "51 60 51 60")
print(camera.output_status()) # frames written, dropped, last file
```

Every command `camerad` accepts is reachable: the base commands are bound as methods, instrument-specific ones go through `instrument_cmd()` (enumerable with `instrument_commands()`), and controller-specific ones such as `mode`, `raw`, `readacf`, `loadtiming`, `heater` and `sensor` go through `controller_cmd()`. Only `exit` is omitted, since the process belongs to the caller.
Every command `camerad` accepts is reachable: the base commands are bound as methods, instrument-specific ones go through `instrument_cmd()` (enumerable with `instrument_commands()`), and controller-specific ones such as `raw`, `readacf`, `loadtiming`, `heater` and `sensor` go through `controller_cmd()`, which forwards any other name to the instrument as `camerad` does. Only `exit` is omitted, since the process belongs to the caller.

The controller and instrument are fixed at CMake configure time, so `instrument_name()` and `controller_name()` report which build was loaded. A failed command raises `RuntimeError`.

Expand Down
50 changes: 23 additions & 27 deletions camerad/archon_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,9 @@ namespace Camera {
/***** Camera::ArchonInterface::controller_cmd ******************************/
/**
* @brief dispatcher for Archon-specific commands
* @details This allows dispatching Archon controller specific commands by
* receiving the commands and args and calling the appropriate
* controller-specific function. This should be calling
* ArchonInterface functions.
* @details The server calls this for every name the core does not
* recognize centrally. It handles the commands unique to the
* Archon and passes any other name to instrument_cmd.
* @param[in] cmd command
* @param[in] args argument list
* @param[out] retstring return string
Expand Down Expand Up @@ -102,8 +101,8 @@ namespace Camera {
return this->set_parameter(args, retstring);
}
else
if ( cmd == CAMERAD_MODE ) {
return this->set_camera_mode(args, retstring);
if ( cmd == CAMERAD_ACFMODE ) {
return this->acfmode(args, retstring);
}
else
if ( cmd == CAMERAD_RAW ) {
Expand All @@ -122,8 +121,7 @@ namespace Camera {
return this->sensor(args, retstring);
}
else {
retstring="unrecognized command";
return ERROR;
return this->instrument_cmd(cmd, args, retstring);
}
}
/***** Camera::ArchonInterface::controller_cmd ******************************/
Expand Down Expand Up @@ -722,6 +720,10 @@ namespace Camera {
const std::string function("Camera::ArchonInterface::load_firmware");
logwrite(function, acffile);

// clear the exposure mode, so that none is selected after a load
//
this->exposuremode.reset();

// load the ACF file and write to Archon configuration memory
//
long error = this->controller->load_acf(acffile);
Expand All @@ -735,7 +737,7 @@ namespace Camera {
//
if (error != NO_ERROR) this->controller->fetchlog();

// set the mode to DEFAULT
// set the acfmode to DEFAULT
//
if (error == NO_ERROR) error = this->set_camera_mode(std::string("DEFAULT"));

Expand Down Expand Up @@ -802,27 +804,24 @@ namespace Camera {
/***** Camera::ArchonInterface::load_timing *********************************/


/***** Camera::ArchonInterface::set_camera_mode *****************************/
/***** Camera::ArchonInterface::acfmode *************************************/
/**
* @brief set a camera "mode"
* @details Allowable camera modes are defined in the ACF file and specify
* a set of camera settings which can be used to change camera
* settings.
* This version fits the general description of all virtual functions
* inherited by the Camera::Interface base class and is overridden
* by an Archon-specific implementation.
* @brief applies an ACF mode section directly
* @details Applies the settings in the ACF file's [MODE_<name>] section.
* It does not select an exposure mode.
* @param[in] args requested mode name (case-insensitive)
* @param[out retstring current mode name
* @return ERROR|NO_ERROR
*
*/
long ArchonInterface::set_camera_mode(std::string args, std::string &retstring) {
const std::string function("Camera::ArchonInterface::set_camera_mode");
long ArchonInterface::acfmode(const std::string &args, std::string &retstring) {
const std::string function("Camera::ArchonInterface::acfmode");
// Help
if (args=="?" || args=="help") {
retstring = CAMERAD_MODE;
retstring = CAMERAD_ACFMODE;
retstring.append( " <name>\n" );
retstring.append( " Applies camera settings associated with MODE_<name> specified in the ACF file.\n");
retstring.append( " Applies the settings of [MODE_<name>] in the ACF file.\n" );
retstring.append( " Does not select an exposure mode.\n" );
retstring.append( " Valid modes are: {" );
for (const auto &mode : this->controller->modemap) {
retstring.append(" "); retstring.append(mode.first);
Expand All @@ -833,6 +832,9 @@ namespace Camera {
// call the work function
return( this->set_camera_mode(args) );
}
/***** Camera::ArchonInterface::acfmode *************************************/


/***** Camera::ArchonInterface::set_camera_mode *****************************/
/**
* @brief set a camera "mode"
Expand Down Expand Up @@ -876,12 +878,6 @@ namespace Camera {
// if we made it all the way to the end then this is the selected mode
this->controller->selectedmode = modeselect;

std::string target = this->default_exposure_mode_name();
for (const auto &m : this->get_exposure_modes()) {
if (m == modeselect) { target = modeselect; break; }
}
this->set_exposure_mode(target, {});

return NO_ERROR;
}
/***** Camera::ArchonInterface::set_camera_mode *****************************/
Expand Down
11 changes: 5 additions & 6 deletions camerad/archon_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@ namespace Camera {

long do_expose() override;

// Archon controller command dispatcher
// Archon controller command dispatcher. The server calls it for every
// name the core does not recognize centrally; it handles the Archon
// commands and passes any other name to instrument_cmd
//
long controller_cmd(const std::string &cmd,
const std::string &args,
std::string &retstring) override;
std::string &retstring) final;

// These functions are specific to the Archon Interface and are not
// found in the base class.
Expand All @@ -64,15 +66,12 @@ namespace Camera {
long load_timing(std::string cmd, std::string &reply);
long read_acf(const std::string &filename);
long set_parameter(const std::string &args, std::string &retstring);
long set_camera_mode(std::string args, std::string &retstring);
long set_camera_mode(std::string modeselect);
long set_vcpu_inreg(const std::string &args, std::string &retstring);
long heater(const std::string &args, std::string &retstring);
long sensor(const std::string &args, std::string &retstring);
long autofetch_mode(const std::string &args, std::string &retstring);

// Fallback for set_camera_mode when the camera-mode name is unknown
virtual std::string default_exposure_mode_name() const { return "SINGLE"; }
long acfmode(const std::string &args, std::string &retstring);

char* get_framebuf() { return controller->framebuf; }

Expand Down
16 changes: 9 additions & 7 deletions camerad/camera_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,30 +128,32 @@ namespace Camera {

virtual long do_expose() = 0;

/** @brief returns true if cmd is an instrument-specific command
*/
virtual bool is_instrument_command(const std::string &cmd) { return false; }

// Names this instrument handles, so a caller can enumerate rather than
// guess. CAMERAD_SYNTAX lists none of them
virtual std::vector<std::string> instrument_commands() const { return {}; }

/** @brief returns error if not overridden
* @details The end of the dispatch chain. A name that reaches this
* default is claimed by no handler.
*/
virtual long instrument_cmd(const std::string &cmd,
const std::string &args,
std::string &retstring) {
const std::string function("Camera::Interface::instrument_cmd");
logwrite(function, "ERROR unknown command: "+cmd);
retstring="not_supported";
return ERROR;
}

/** @brief returns error if not overridden
/** @brief handles commands unique to the controller
* @details The server calls this for every name the core does not
* recognize centrally. A controller interface handles its own
* commands and passes any other name to instrument_cmd.
*/
virtual long controller_cmd(const std::string &cmd,
const std::string &args,
std::string &retstring) {
retstring="not_supported";
return ERROR;
return this->instrument_cmd(cmd, args, retstring);
}
};

Expand Down
65 changes: 4 additions & 61 deletions camerad/camera_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,6 @@ namespace Camera {
}
ret = HELP;
}
/**
* instrument-specific commands
*/
else
if (interface->is_instrument_command(cmd))
{
ret = interface->instrument_cmd(cmd, args, retstring);
}
else
if ( cmd == CAMERAD_ABORT ) {
ret = interface->abort(args, retstring);
Expand All @@ -252,7 +244,7 @@ namespace Camera {
}
else
if ( cmd == CAMERAD_BIN ) {
ret = interface->bias(args, retstring);
ret = interface->bin(args, retstring);
}
else
if ( cmd == CAMERAD_CLOSE ) {
Expand Down Expand Up @@ -304,60 +296,11 @@ namespace Camera {
ret = interface->datacube(args, retstring);
}

/**
* controller-specific commands
*/
else
if ( cmd == CAMERAD_LOADTIMING ) {
ret = interface->controller_cmd(cmd, args, retstring);
}
else
if ( cmd == CAMERAD_READACF ) {
ret = interface->controller_cmd(cmd, args, retstring);
}
else
if ( cmd == "getp" ) {
ret = interface->controller_cmd(cmd, args, retstring);
}
else
if ( cmd == "inreg" ) {
ret = interface->controller_cmd(cmd, args, retstring);
}
else
if ( cmd == "setp" ) {
ret = interface->controller_cmd(cmd, args, retstring);
}
else
if ( cmd == CAMERAD_MODE ) {
ret = interface->controller_cmd(cmd, args, retstring);
}
else
if ( cmd == CAMERAD_RAW ) {
ret = interface->controller_cmd(cmd, args, retstring);
}
else
if ( cmd == "bob" ) {
ret = interface->controller_cmd(cmd, args, retstring);
}
else
if ( cmd == "autofetch_mode" ) {
ret = interface->controller_cmd(cmd, args, retstring);
}
else
if ( cmd == CAMERAD_HEATER ) {
ret = interface->controller_cmd(cmd, args, retstring);
}
else
if ( cmd == CAMERAD_SENSOR ) {
ret = interface->controller_cmd(cmd, args, retstring);
}

// unknown commands generate an error
// any other name goes to the controller interface, which forwards
// what it does not handle to the instrument
//
else {
message.str(""); message << "ERROR unknown command: " << cmd;
logwrite(function, message.str());
ret = ERROR;
ret = interface->controller_cmd(cmd, args, retstring);
}

// If retstring not empty then append "DONE" or "ERROR" depending on value of ret,
Expand Down
4 changes: 2 additions & 2 deletions common/camerad_commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#pragma once

const std::string CAMERAD_ABORT("abort");
const std::string CAMERAD_ACFMODE("acfmode");
const std::string CAMERAD_AUTODIR("autodir");
const std::string CAMERAD_BASENAME("basename");
const std::string CAMERAD_BIAS("bias");
Expand Down Expand Up @@ -39,7 +40,6 @@ const std::string CAMERAD_LOADTIMING("loadtiming");
const std::string CAMERAD_LONGERROR("longerror");
const std::string CAMERAD_MEX("mex");
const std::string CAMERAD_MEXAMPS("mexamps");
const std::string CAMERAD_MODE("mode");
const std::string CAMERAD_MODEXPTIME("modexptime");
const std::string CAMERAD_NATIVE("native");
const std::string CAMERAD_OPEN("open"); const int CAMERAD_OPEN_TIMEOUT(10000);
Expand All @@ -58,6 +58,7 @@ const std::string CAMERAD_USEFRAMES("useframes");
const std::string CAMERAD_WRITEKEYS("writekeys");
const std::vector<std::string> CAMERAD_SYNTAX = {
CAMERAD_ABORT,
CAMERAD_ACFMODE+" [ ? | <name> ]",
CAMERAD_AUTODIR,
CAMERAD_BASENAME,
CAMERAD_BIAS,
Expand Down Expand Up @@ -88,7 +89,6 @@ const std::vector<std::string> CAMERAD_SYNTAX = {
CAMERAD_LONGERROR,
CAMERAD_MEX,
CAMERAD_MEXAMPS,
CAMERAD_MODE+" [ ? | <mode> ]",
CAMERAD_MODEXPTIME,
CAMERAD_NATIVE+" ? | [<DEV>|<CHAN>] <CMD> [ <ARG1> [ < ARG2> [ <ARG3> [ <ARG4> ] ] ] ]",
CAMERAD_OPEN+" [ ? | <devlist> ]",
Expand Down
Loading
Loading