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
136 changes: 117 additions & 19 deletions camerad/archon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ namespace Archon {
this->frame.next_index = 0;
this->abort = false;
this->taplines = 0;
this->configlines = 0;
this->logwconfig = false;
this->image_data = nullptr;
this->image_data_bytes = 0;
this->image_data_allocated = 0;
Expand Down Expand Up @@ -865,11 +867,11 @@ namespace Archon {
* @return ERROR, BUSY or NO_ERROR
*
*/
long Interface::archon_cmd(const std::string& cmd) { // use this form when the calling
long Interface::archon_cmd(std::string cmd) { // use this form when the calling
std::string reply; // function doesn't need to look at the reply
return( archon_cmd(cmd, reply) );
}
long Interface::archon_cmd(const std::string& cmd, std::string &reply) {
long Interface::archon_cmd(std::string cmd, std::string &reply) {
std::string function = "Archon::Interface::archon_cmd";
std::stringstream message;
int retval;
Expand Down Expand Up @@ -914,6 +916,15 @@ namespace Archon {
return ERROR;
}

// This allows sending commands that don't get logged,
// by prepending QUIET, which gets removed here if present.
//
bool quiet=false;
if ( cmd.find(QUIET)==0 ) {
cmd.erase(0, QUIET.length());
quiet=true;
}

std::stringstream sscmd; // sscmd = stringstream, building command
sscmd << prefix << cmd << "\n";
std::string scmd = sscmd.str(); // scmd = string, command to send
Expand All @@ -924,10 +935,10 @@ namespace Archon {

// log the command as long as it's not a STATUS, TIMER, WCONFIG or FRAME command
//
if ( (cmd.compare(0,7,"WCONFIG") != 0) &&
(cmd.compare(0,5,"TIMER") != 0) &&
(cmd.compare(0,6,"STATUS") != 0) &&
(cmd.compare(0,5,"FRAME") != 0) ) {
if ( !quiet && (cmd.compare(0,7,"WCONFIG") != 0) &&
(cmd.compare(0,5,"TIMER") != 0) &&
(cmd.compare(0,6,"STATUS") != 0) &&
(cmd.compare(0,5,"FRAME") != 0) ) {
// erase newline for logging purposes
std::string fcmd = scmd;
try {
Expand All @@ -937,6 +948,10 @@ namespace Archon {
logwrite(function, message.str());
}

// optionally log WCONFIG commands
//
if ( this->logwconfig && cmd.find("WCONFIG")!=std::string::npos ) logwrite( function, strip_newline(cmd) );

// send the command
//
if ( (this->archon.Write(scmd)) == -1) {
Expand Down Expand Up @@ -1011,10 +1026,10 @@ namespace Archon {
error = NO_ERROR;

// log the command as long as it's not a STATUS, TIMER, WCONFIG or FRAME command
if ( (cmd.compare(0,7,"WCONFIG") != 0) &&
(cmd.compare(0,5,"TIMER") != 0) &&
(cmd.compare(0,6,"STATUS") != 0) &&
(cmd.compare(0,5,"FRAME") != 0) ) {
if ( !quiet && (cmd.compare(0,7,"WCONFIG") != 0) &&
(cmd.compare(0,5,"TIMER") != 0) &&
(cmd.compare(0,6,"STATUS") != 0) &&
(cmd.compare(0,5,"FRAME") != 0) ) {
message.str("");
message << "command 0x" << std::setfill('0') << std::setw(2) << std::uppercase << std::hex << this->msgref << " success";
logwrite(function, message.str());
Expand Down Expand Up @@ -1679,20 +1694,27 @@ namespace Archon {
if (line.find_first_of('=', 0) == std::string::npos) {
continue;
}

Tokenize(line, tokens, "="); // separate into KEY, VALUE tokens
if (tokens.empty()) {
continue; // nothing to do here if no tokens (ie no "=")
}
if (!tokens.empty() ) { // at least one token is the key
key = tokens[0]; // KEY
value = ""; // VALUE can be empty (e.g. labels not required)
this->configmap[ tokens[0] ].line = linecount;
this->configmap[ tokens[0] ].value = value;
}
if (tokens.size() > 1 ) { // if a second token then that's the value

key = tokens[0]; // not empty so at least one token is the KEY
value.clear(); // VALUE can be empty (e.g. labels not required)

if ( tokens.size() > 1 ) { // at least one more token is the value
value = tokens[1]; // VALUE (there is a second token)
this->configmap[ tokens[0] ].value = tokens[1];
}

if ( tokens.size() > 2 ) { // more tokens are possible
for ( size_t i=2; i<tokens.size(); ++i ) { // loop through remaining tokens
value += "=" + tokens[i]; // and put them back together as the VALUE
}
}

this->configmap[ tokens[0] ].line = linecount;
this->configmap[ tokens[0] ].value = value;
} // end else

// Form the WCONFIG command to Archon and
Expand All @@ -1706,10 +1728,12 @@ namespace Archon {
<< key << "=" << value << "\n";
// send the WCONFIG command here
if (error == NO_ERROR) error = this->archon_cmd(sscmd.str());
linecount++;
} // end if ( !key.empty() && !value.empty() )
linecount++;
} // end while ( getline(filestream, line) )

this->configlines = linecount; // save the number of configuration lines

// re-enable background polling
//
if (error == NO_ERROR) error = this->archon_cmd(POLLON);
Expand Down Expand Up @@ -8041,6 +8065,80 @@ namespace Archon {
retstring = "delta=" + std::to_string( m ) + " stddev=" + std::to_string( stdev );
// end if (testname==timer)

} else if (testname == "rconfigmap") {
// ----------------------------------------------------
// rconfigmap <filter>
// reports the configmap (what should have been written)
// ----------------------------------------------------
std::string filter;
if ( tokens.size() > 1 ) {
if ( tokens[1] == "line" ) filter="LINE";
else
if ( tokens[1] == "mod" ) filter="MOD";
else
if ( tokens[1] == "param" ) filter="PARAMETER";
else
if ( tokens[1] == "state" ) filter="STATE";
else
if ( tokens[1] == "vcpu" ) filter="VCPU";
}
for ( const auto &[k,v] : this->configmap ) {
if ( k.find(filter)!=std::string::npos ) {
message.str(""); message << "RCONFIG"
<< std::uppercase << std::setfill('0') << std::setw(4) << std::hex
<< v.line << ": " << k << "=" << v.value;
logwrite( function, message.str() );
}
}
error = NO_ERROR;
} else if (testname == "rconfig") {
// ----------------------------------------------------
// rconfig <filter>
// reads config directly from Archon
// ----------------------------------------------------
std::string filter;
if ( tokens.size() > 1 ) {
if ( tokens[1] == "line" ) filter="LINE";
else
if ( tokens[1] == "mod" ) filter="MOD";
else
if ( tokens[1] == "param" ) filter="PARAMETER";
else
if ( tokens[1] == "state" ) filter="STATE";
else
if ( tokens[1] == "vcpu" ) filter="VCPU";
}
for ( int line=0; line < this->configlines; line++ ) {
// form the RCONFIG command to send to Archon (without logging each command)
//
std::stringstream cmd;
cmd.str(""); cmd << QUIET
<< "RCONFIG"
<< std::uppercase << std::setfill('0') << std::setw(4) << std::hex << line;
std::string reply;
error = this->archon_cmd(cmd.str(), reply); // send RCONFIG command here
if ( reply.find(filter)!=std::string::npos ) {
message.str(""); message << "RCONFIG"
<< std::uppercase << std::setfill('0') << std::setw(4) << std::hex << line
<< ": " << strip_newline(reply);
logwrite( function, message.str() );
}
}
error = NO_ERROR;
} else if (testname == "logwconfig") {
// ----------------------------------------------------
// logwconfig [ <state> ]
// set/get state of logwconfig, to optionally log WCONFIG commands
// ----------------------------------------------------
if ( tokens.size() > 1 ) {
if ( tokens[1] == "true" ) this->logwconfig=true;
else
if ( tokens[1] == "false" ) this->logwconfig=false;
}
retstring = ( this->logwconfig ? "true" : "false" );
message.str(""); message << "logwconfig " << retstring;
logwrite( function, message.str() );
error = NO_ERROR;
} else {
// ----------------------------------------------------
// invalid test name
Expand Down
10 changes: 8 additions & 2 deletions camerad/archon.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <chrono>
#include <numeric>
#include <fenv.h>
#include <string_view>

#include "utilities.h"
#include "common.h"
Expand Down Expand Up @@ -57,6 +58,9 @@
#define REV_VCPU std::string("1.0.784")

namespace Archon {

constexpr std::string_view QUIET = "quiet"; // allows sending commands without logging

// Archon hardware-based constants.
// These shouldn't change unless there is a significant hardware change.
//
Expand Down Expand Up @@ -101,6 +105,8 @@ namespace Archon {
int msgref; //!< Archon message reference identifier, matches reply to command
bool abort;
int taplines;
int configlines; //!< number of configuration lines
bool logwconfig; //!< optionally log WCONFIG commands
std::vector<int> gain; //!< digital CDS gain (from TAPLINE definition)
std::vector<int> offset; //!< digital CDS offset (from TAPLINE definition)
bool modeselected; //!< true if a valid mode has been selected, false otherwise
Expand Down Expand Up @@ -172,9 +178,9 @@ namespace Archon {

long native(const std::string &cmd);

long archon_cmd(const std::string &cmd);
long archon_cmd(std::string cmd);

long archon_cmd(const std::string &cmd, std::string &reply);
long archon_cmd(std::string cmd, std::string &reply);

long read_parameter(const std::string &paramname, std::string &valstring);

Expand Down
11 changes: 6 additions & 5 deletions common/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@

#include "logentry.h"

const long NOTHING = -1;
const long NO_ERROR = 0;
const long ERROR = 1;
const long BUSY = 2;
const long TIMEOUT = 3;
constexpr long NOTHING = -1;
constexpr long NO_ERROR = 0;
constexpr long ERROR = 1;
constexpr long BUSY = 2;
constexpr long TIMEOUT = 3;
constexpr long HELP = 4;

namespace Common {
/**************** Common::FitsKeys ******************************************/
Expand Down
17 changes: 17 additions & 0 deletions utils/utilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,23 @@ const std::string &tchar(const std::string &str) {
/***** tchar ****************************************************************/


/***** strip_newline **********************************************************/
/**
* @brief strip newline and cr chars from a string
* @details this makes a local copy of the original string which is not changed
* @param[in] str_in reference to input string
* @return string
*
*/
const std::string strip_newline( const std::string &str_in ) {
std::string str = str_in;
str.erase( std::remove( str.begin(), str.end(), '\n' ), str.end() );
str.erase( std::remove( str.begin(), str.end(), '\r' ), str.end() );
return str;
}
/***** strip_newline **********************************************************/


/***** strip_control_characters *********************************************/
/**
* @brief strip all leading and trailing control chars from a string
Expand Down
2 changes: 2 additions & 0 deletions utils/utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ bool has_write_permission(const std::filesystem::path &filename);

const std::string &tchar(const std::string &str);

const std::string strip_newline( const std::string &str_in );

std::string strip_control_characters(const std::string &str);

bool starts_with(const std::string &str, std::string_view prefix);
Expand Down