From 75de970a31e721ffb04eea5d2169789d68ed825f Mon Sep 17 00:00:00 2001 From: David Hale Date: Fri, 13 Jun 2025 15:04:00 -0700 Subject: [PATCH 01/19] adds Flexure::Compensator class, and starts to add Matt's functions --- Config/flexured.cfg.in | 14 ++++ common/common.h | 1 + flexured/CMakeLists.txt | 1 + flexured/flexure_interface.h | 3 + flexured/flexure_server.cpp | 132 +++++++++++++++++++++++++++++------ 5 files changed, 128 insertions(+), 23 deletions(-) diff --git a/Config/flexured.cfg.in b/Config/flexured.cfg.in index 3cacb429..e1e9e200 100644 --- a/Config/flexured.cfg.in +++ b/Config/flexured.cfg.in @@ -13,6 +13,20 @@ PUBLISHER_PORT="tcp://127.0.0.1:@FLEXURED_PUB_PORT@" # my zeromq pub port # EMULATOR_PORT=@FLEXURED_EMULATOR@ +# COLLIMATOR_POSITION +# +COLLIMATOR_POSITION_RXE=(21.2591 -0.275957 1.29479) +COLLIMATOR_POSITION_RYE=(0.266115 22.3092 -0.821104) +COLLIMATOR_POSITION_IXE=(19.2199 0.149826 -0.159326) +COLLIMATOR_POSITION_IYE=(0.123447 -20.5831 0.307648) + +# Flexure polynomial data +# +FLEXURE_POLY_IX=( 0.0135162 -0.00447609 -6.48415e-05 6.43345e-06 -4.00865e-08 0.0415762 -0.0701252 0.000227690 0 0 0.288840 -0.00161429 0 0 0 -0.0112647 -0.00343684 0.000147780 -1.68025e-06 7.84644e-09) +FLEXURE_POLY_IY=( -0.00694281 0.00341489 -0.000852294 6.95515e-06 -6.85542e-08 0.00583450 -0.00415384 -5.64805e-05 0 0 2.30189 -0.0106356 0 0 0 -0.163970 0.000321176 8.95876e-06 0 0 ) +FLEXURE_POLY_RX=( 0.00 0.00 0.0 0.0 0.0 -0.0641885 -0.0317361 -0.000197792 0 0 2.57404 -0.00327556 0 0 0 0.000445881 0.0107193 -0.000509618 9.11488e-6 -4.74720e-8) +FLEXURE_POLY_RY=( -0.00644079 0.00907213 -0.000377799 1.49786e-05 -3.50103e-08 -0.0180188 -0.0165204 8.40640e-05 0 0 2.61190 -0.00353314 0 0 0 -0.00104779 0.000841425 4.02491e-06 0 0) + # For each actuator's controller specify: # MOTOR_CONTROLLER=" " # name of controller diff --git a/common/common.h b/common/common.h index d1bd0ef6..2207ad1c 100644 --- a/common/common.h +++ b/common/common.h @@ -7,6 +7,7 @@ #pragma once +#include #include #include #include diff --git a/flexured/CMakeLists.txt b/flexured/CMakeLists.txt index 8522b400..068c0000 100644 --- a/flexured/CMakeLists.txt +++ b/flexured/CMakeLists.txt @@ -20,6 +20,7 @@ add_executable(flexured ${FLEXURED_DIR}/flexured.cpp ${FLEXURED_DIR}/flexure_server.cpp ${FLEXURED_DIR}/flexure_interface.cpp + ${FLEXURED_DIR}/flexure_compensator.cpp ) target_link_libraries(flexured diff --git a/flexured/flexure_interface.h b/flexured/flexure_interface.h index 291f22e9..70569188 100644 --- a/flexured/flexure_interface.h +++ b/flexured/flexure_interface.h @@ -13,6 +13,7 @@ #include "logentry.h" #include "common.h" #include "flexured_commands.h" +#include "flexure_compensator.h" #include #include #include @@ -52,6 +53,8 @@ namespace Flexure { Common::Queue async; + Compensator compensator; + // PI Interface class for the Piezo type // Physik_Instrumente::Interface motorinterface; diff --git a/flexured/flexure_server.cpp b/flexured/flexure_server.cpp index f7365737..f80f9270 100644 --- a/flexured/flexure_server.cpp +++ b/flexured/flexure_server.cpp @@ -33,7 +33,7 @@ namespace Flexure { long Server::configure_flexured() { std::string function = "Flexure::Server::configure_flexured"; std::stringstream message; - int applied=0; + int numapplied=0, lastapplied=0; long error; // Clear the motormap map before loading new information from the config file @@ -44,6 +44,8 @@ namespace Flexure { // for (int entry=0; entry < this->config.n_entries; entry++) { + lastapplied=numapplied; + // NBPORT -- nonblocking listening port for the flexure daemon // if ( config.param[entry].find( "NBPORT" ) == 0 ) { @@ -60,10 +62,9 @@ namespace Flexure { return(ERROR); } this->nbport = port; - message.str(""); message << "FLEXURED:config:" << config.param[entry] << "=" << config.arg[entry]; - this->interface.async.enqueue_and_log( function, message.str() ); - applied++; + numapplied++; } + else // BLKPORT -- blocking listening port for the flexure daemon // @@ -81,10 +82,9 @@ namespace Flexure { return(ERROR); } this->blkport = port; - message.str(""); message << "FLEXURED:config:" << config.param[entry] << "=" << config.arg[entry]; - this->interface.async.enqueue_and_log( function, message.str() ); - applied++; + numapplied++; } + else // ASYNCPORT -- asynchronous broadcast message port for the flexure daemon // @@ -102,30 +102,27 @@ namespace Flexure { return(ERROR); } this->asyncport = port; - message.str(""); message << "FLEXURED:config:" << config.param[entry] << "=" << config.arg[entry]; - this->interface.async.enqueue_and_log( function, message.str() ); - applied++; + numapplied++; } + else // ASYNCGROUP -- asynchronous broadcast group for the flexure daemon // if ( config.param[entry].find( "ASYNCGROUP" ) == 0 ) { this->asyncgroup = config.arg[entry]; - message.str(""); message << "FLEXURED:config:" << config.param[entry] << "=" << config.arg[entry]; - this->interface.async.enqueue_and_log( function, message.str() ); - applied++; + numapplied++; } + else // MOTOR_CONTROLLER -- address and name of each PI motor controller in daisy-chain // Each CONTROLLER is stored in an STL map indexed by motorname // if ( config.param[entry].find( "MOTOR_CONTROLLER" ) == 0 ) { if ( this->interface.motorinterface.load_controller_config( config.arg[entry] ) == NO_ERROR ) { - message.str(""); message << "FLEXURED:config:" << config.param[entry] << "=" << config.arg[entry]; - this->interface.async.enqueue_and_log( function, message.str() ); - applied++; + numapplied++; } } + else // MOTOR_AXIS -- axis info for specified MOTOR_CONTROLLER // @@ -145,9 +142,7 @@ namespace Flexure { if ( loc != _motormap.end() ) { this->interface.motorinterface.add_axis( AXIS ); - message.str(""); message << "FLEXURED:config:" << config.param[entry] << "=" << config.arg[entry]; - this->interface.async.enqueue_and_log( function, message.str() ); - applied++; + numapplied++; } else { message.str(""); message << "ERROR motor name \"" << AXIS.motorname << "\" " @@ -160,6 +155,95 @@ namespace Flexure { break; } } + else + + // COLLIMATOR_POSITION_RXE + // + if ( config.param[entry] == "COLLIMATOR_POSITION_RXE" ) { + error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::RXE, 3 ); + if (error==NO_ERROR) { + numapplied++; + } + else return ERROR; + } + else + + // COLLIMATOR_POSITION_RYE + // + if ( config.param[entry] == "COLLIMATOR_POSITION_RYE" ) { + error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::RYE, 3 ); + if (error==NO_ERROR) { + numapplied++; + } + else return ERROR; + } + else + + // COLLIMATOR_POSITION_IXE + // + if ( config.param[entry] == "COLLIMATOR_POSITION_IXE" ) { + error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::IXE, 3 ); + if (error==NO_ERROR) { + numapplied++; + } + else return ERROR; + } + else + + // COLLIMATOR_POSITION_IYE + // + if ( config.param[entry] == "COLLIMATOR_POSITION_IYE" ) { + error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::IYE, 3 ); + if (error==NO_ERROR) { + numapplied++; + } + else return ERROR; + } + else + + // FLEXURE_POLY_IX + // + if ( config.param[entry] == "FLEXURE_POLY_IX" ) { + error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::IX, 20 ); + if (error==NO_ERROR) { + numapplied++; + } + else return ERROR; + } + else + + // FLEXURE_POLY_IY + // + if ( config.param[entry] == "FLEXURE_POLY_IY" ) { + error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::IY, 20 ); + if (error==NO_ERROR) { + numapplied++; + } + else return ERROR; + } + else + + // FLEXURE_POLY_RX + // + if ( config.param[entry] == "FLEXURE_POLY_RX" ) { + error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::RX, 20 ); + if (error==NO_ERROR) { + numapplied++; + } + else return ERROR; + } + else + + // FLEXURE_POLY_RY + // + if ( config.param[entry] == "FLEXURE_POLY_RY" ) { + error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::RY, 20 ); + if (error==NO_ERROR) { + numapplied++; + } + else return ERROR; + } + else // TELEM_PROVIDER : contains daemon name and port to contact for header telemetry info // @@ -181,22 +265,24 @@ namespace Flexure { logwrite( function, message.str() ); return ERROR; } + numapplied++; + } + + if (numapplied>lastapplied) { message.str(""); message << "config:" << config.param[entry] << "=" << config.arg[entry]; this->interface.async.enqueue_and_log( to_uppercase(DAEMON_NAME), function, message.str() ); - applied++; } - } // end loop through the entries in the configuration file message.str(""); - if (applied==0) { + if (numapplied==0) { message << "ERROR: "; error = ERROR; } else { error = NO_ERROR; } - message << "applied " << applied << " configuration lines to flexured"; + message << "applied " << numapplied << " configuration lines to flexured"; logwrite(function, message.str()); if ( error == NO_ERROR ) error = this->interface.initialize_class(); From b417df50e4f6ba2006ed330d9280b6ba719cab2e Mon Sep 17 00:00:00 2001 From: David Hale Date: Fri, 25 Jul 2025 17:05:49 -0700 Subject: [PATCH 02/19] improves FITS keyword value type detection and allows forcing keyword datatypes addresses issue 321 --- acamd/acam_interface.cpp | 4 +- camerad/astrocam.cpp | 64 ++++++----- common/common.cpp | 81 +++++++++---- common/common.h | 189 +++++++++++++++++++++++-------- slicecamd/slicecam_interface.cpp | 4 +- 5 files changed, 232 insertions(+), 110 deletions(-) diff --git a/acamd/acam_interface.cpp b/acamd/acam_interface.cpp index 8e26f15d..6faba489 100644 --- a/acamd/acam_interface.cpp +++ b/acamd/acam_interface.cpp @@ -1606,8 +1606,8 @@ namespace Acam { std::lock_guard lock(snapshot_mtx); snapshot_status["slitd"]=true; } - this->telemkeys.add_json_key(jmessage, "SLITO", "SLITO", "slit offset in arcsec", false); - this->telemkeys.add_json_key(jmessage, "SLITW", "SLITW", "slit width in arcsec", false); + this->telemkeys.add_json_key(jmessage, "SLITO", "SLITO", "slit offset in arcsec", "FLOAT", false); + this->telemkeys.add_json_key(jmessage, "SLITW", "SLITW", "slit width in arcsec", "FLOAT", false); } /***** Acam::Interface::handletopic_slitd ***********************************/ diff --git a/camerad/astrocam.cpp b/camerad/astrocam.cpp index ad9e37e2..f114d0a2 100644 --- a/camerad/astrocam.cpp +++ b/camerad/astrocam.cpp @@ -3010,6 +3010,7 @@ namespace AstroCam { std::string jkey; // key to extract from jmessage std::string keyword; // optional FITS keyword (uses jkey if not specified) std::string comment; // FITS key comment + std::string type=""; // optional keyword datatype }; /** @@ -3024,6 +3025,7 @@ namespace AstroCam { std::string jkey; // key to extract from jmessage std::string keyword; // optional FITS keyword (uses jkey if not specified) std::string comment; // FITS key comment + std::string type=""; // optional keyword datatype }; auto &telemkeys = this->camera_info.telemkeys; @@ -3074,7 +3076,7 @@ namespace AstroCam { {"CALDOOR", "", "calib door state"} }; for ( const auto &keyinfo : keyarray ) { - telemkeys.add_json_key(jmessage, keyinfo.jkey, keyinfo.jkey, keyinfo.comment, pri); + telemkeys.add_json_key(jmessage, keyinfo.jkey, keyinfo.jkey, keyinfo.comment, keyinfo.type, pri); } } else @@ -3097,7 +3099,7 @@ namespace AstroCam { {"U", "FLXPIS_U", "FLXPIS", "U flexure piston axis 1 (Z) in um"} }; for ( const auto &keyinfo : keyarray ) { - telemkeys.add_json_key(jmessage, keyinfo.jkey, keyinfo.keyword, keyinfo.comment, ext, keyinfo.chan); + telemkeys.add_json_key(jmessage, keyinfo.jkey, keyinfo.keyword, keyinfo.comment, keyinfo.type, ext, keyinfo.chan); } } else @@ -3112,7 +3114,7 @@ namespace AstroCam { {"U", "FOCUSU", "FOCUS", "science camera U focus position in mm" } }; for ( const auto &keyinfo : keyarray ) { - telemkeys.add_json_key(jmessage, keyinfo.jkey, keyinfo.keyword, keyinfo.comment, ext, keyinfo.chan); + telemkeys.add_json_key(jmessage, keyinfo.jkey, keyinfo.keyword, keyinfo.comment, keyinfo.type, ext, keyinfo.chan); } } else @@ -3129,7 +3131,7 @@ namespace AstroCam { {"LAMPINCA", "", "is Incandescent lamp on"} }; for ( const auto &keyinfo : keyarray ) { - telemkeys.add_json_key(jmessage, keyinfo.jkey, keyinfo.jkey, keyinfo.comment, pri); + telemkeys.add_json_key(jmessage, keyinfo.jkey, keyinfo.jkey, keyinfo.comment, keyinfo.type, pri); } } else @@ -3145,7 +3147,7 @@ namespace AstroCam { {"SLITPOSB", "", "slit actuator B position in mm"} }; for ( const auto &keyinfo : keyarray ) { - telemkeys.add_json_key(jmessage, keyinfo.jkey, keyinfo.jkey, keyinfo.comment, pri); + telemkeys.add_json_key(jmessage, keyinfo.jkey, keyinfo.jkey, keyinfo.comment, keyinfo.type, pri); } } else @@ -3154,19 +3156,19 @@ namespace AstroCam { // if ( messagetype == "targetinfo" ) { const PrimaryInfo keyarray[] = { - {"OBS_ID", "", "Observation ID"}, - {"NAME", "", "target name"}, + {"OBS_ID", "", "Observation ID", "INT"}, + {"NAME", "", "target name", "STRING"}, // {"BINSPECT", "", "binning in spectral direction"}, // {"BINSPAT", "", "binning in spatial direction"}, - {"SLITA", "", "slit angle in deg"}, - {"POINTMDE", "", "pointing mode"}, - {"RA", "", "requested Right Ascension in J2000"}, - {"DECL", "", "requested Declination in J2000"} + {"SLITA", "", "slit angle in deg", "FLOAT"}, + {"POINTMDE", "", "pointing mode", "STRING"}, + {"RA", "", "requested Right Ascension in J2000", "STRING"}, + {"DECL", "", "requested Declination in J2000", "STRING"} }; for ( const auto &keyinfo : keyarray ) { message.str(""); message << "[DEBUG] targetinfo key " << keyinfo.jkey << "=" << jmessage[keyinfo.jkey]; logwrite(function,message.str()); - telemkeys.add_json_key(jmessage, keyinfo.jkey, keyinfo.jkey, keyinfo.comment, pri); + telemkeys.add_json_key(jmessage, keyinfo.jkey, keyinfo.jkey, keyinfo.comment, keyinfo.type, pri); } } else @@ -3176,20 +3178,20 @@ namespace AstroCam { // if ( messagetype == "tcsinfo" ) { const PrimaryInfo keyarray[] = { - {"CASANGLE", "", "TCS reported Cassegrain angle in deg"}, + {"CASANGLE", "", "TCS reported Cassegrain angle in deg", "FLOAT"}, {"HA", "", "hour angle"}, {"RAOFFSET", "", "offset Right Ascension"}, {"DECLOFFSET", "", "offset Declination"}, {"TELRA", "", "TCS reported Right Ascension"}, {"TELDEC", "", "TCS reported Declination"}, {"AZ", "", "TCS reported azimuth"}, - {"ZENANGLE", "", "TCS reported Zenith angle"}, - {"DOMEAZ", "", "TCS reported dome azimuth"}, + {"ZENANGLE", "", "TCS reported Zenith angle", "FLOAT"}, + {"DOMEAZ", "", "TCS reported dome azimuth", "FLOAT"}, {"DOMESHUT", "", "dome shutters"}, - {"TELFOCUS", "", "TCS reported telescope focus position in mm"} + {"TELFOCUS", "", "TCS reported telescope focus position in mm", "FLOAT"} }; for ( const auto &keyinfo : keyarray ) { - telemkeys.add_json_key(jmessage, keyinfo.jkey, keyinfo.jkey, keyinfo.comment, pri); + telemkeys.add_json_key(jmessage, keyinfo.jkey, keyinfo.jkey, keyinfo.comment, keyinfo.type, pri); } } else @@ -3198,22 +3200,22 @@ namespace AstroCam { // if ( messagetype == "thermalinfo" ) { const ExtensionInfo keyarray[] = { - {"I", "TCCD_I", "CCDTEMP", "I CCD temperature in Kelvin"}, - {"R", "TCCD_R", "CCDTEMP", "R CCD temperature in Kelvin"}, - {"G", "TCCD_G", "CCDTEMP", "G CCD temperature in Kelvin"}, - {"U", "TCCD_U", "CCDTEMP", "U CCD temperature in Kelvin"}, - - {"I", "TCOLL_I", "COLTEMP", "I collimator temp in deg C"}, - {"R", "TCOLL_R", "COLTEMP", "R collimator temp in deg C"}, - {"G", "TCOLL_G", "COLTEMP", "G collimator temp in deg C"}, - - {"I", "TFOCUS_I", "FOCTEMP", "I focus temp in deg C"}, - {"R", "TFOCUS_R", "FOCTEMP", "R focus temp in deg C"}, - {"G", "TFOCUS_G", "FOCTEMP", "G focus temp in deg C"}, - {"U", "TFOCUS_U", "FOCTEMP", "U focus temp in deg C"} + {"I", "TCCD_I", "CCDTEMP", "I CCD temperature in Kelvin", "FLOAT"}, + {"R", "TCCD_R", "CCDTEMP", "R CCD temperature in Kelvin", "FLOAT"}, + {"G", "TCCD_G", "CCDTEMP", "G CCD temperature in Kelvin", "FLOAT"}, + {"U", "TCCD_U", "CCDTEMP", "U CCD temperature in Kelvin", "FLOAT"}, + + {"I", "TCOLL_I", "COLTEMP", "I collimator temp in deg C", "FLOAT"}, + {"R", "TCOLL_R", "COLTEMP", "R collimator temp in deg C", "FLOAT"}, + {"G", "TCOLL_G", "COLTEMP", "G collimator temp in deg C", "FLOAT"}, + + {"I", "TFOCUS_I", "FOCTEMP", "I focus temp in deg C", "FLOAT"}, + {"R", "TFOCUS_R", "FOCTEMP", "R focus temp in deg C", "FLOAT"}, + {"G", "TFOCUS_G", "FOCTEMP", "G focus temp in deg C", "FLOAT"}, + {"U", "TFOCUS_U", "FOCTEMP", "U focus temp in deg C", "FLOAT"} }; for ( const auto &keyinfo : keyarray ) { - telemkeys.add_json_key(jmessage, keyinfo.jkey, keyinfo.keyword, keyinfo.comment, ext, keyinfo.chan); + telemkeys.add_json_key(jmessage, keyinfo.jkey, keyinfo.keyword, keyinfo.comment, keyinfo.type, ext, keyinfo.chan); } } else diff --git a/common/common.cpp b/common/common.cpp index 398c4a1d..3fc176eb 100644 --- a/common/common.cpp +++ b/common/common.cpp @@ -122,10 +122,12 @@ namespace Common { * */ std::string FitsKeys::get_keytype(std::string keyvalue) { - std::size_t pos(0); + + // strip leading and trailing spaces + keyvalue.erase(0, keyvalue.find_first_not_of(' ')); + keyvalue.erase(keyvalue.find_last_not_of(' ')+1); // If it's empty then what else can it be but string - // if ( keyvalue.empty() ) return std::string( "STRING" ); // if the entire string is either (exactly) T or F then it's a boolean @@ -133,35 +135,58 @@ namespace Common { return std::string( "BOOL" ); } - // skip the whitespaces - pos = keyvalue.find_first_not_of(' '); - if (pos == keyvalue.size()) return std::string("STRING"); // all spaces, so it's a string - // check the significand + std::size_t pos(0); if (keyvalue[pos] == '+' || keyvalue[pos] == '-') ++pos; // skip the sign if exist - // count the number of digits and number of decimal points - int n_nm, n_pt; - for (n_nm = 0, n_pt = 0; std::isdigit(keyvalue[pos]) || keyvalue[pos] == '.'; ++pos) { - keyvalue[pos] == '.' ? ++n_pt : ++n_nm; + // count the number of numbers and number of decimal points + // stops early if any other character is found, which makes the type STRING + int numnum, numpts; + for (numnum=0, numpts=0; + pos1 || n_nm<1 || pos1 || // more than one decimal point + numnum<1 ) { // no numbers + return std::string("STRING"); // then it's a string } - - // skip the trailing whitespaces - while (keyvalue[pos] == ' ') { - ++pos; + else + // one decimal is float or double... + if (numpts==1 && numnum>0) { + size_t loc = keyvalue.find('.'); + // get the integer and fractional parts of the number + std::string intpart = (loc==std::string::npos) ? keyvalue : keyvalue.substr(0, loc); + std::string fracpart = (loc==std::string::npos) ? "" : keyvalue.substr(loc+1); + + // remove leading and trailing zeros + intpart.erase(0, intpart.find_first_not_of('0')); + fracpart.erase(fracpart.find_last_not_of('0')); + + // number of significant figures + size_t sigfigs = intpart.length() + fracpart.length(); + + // more than 7 significant figures requires a double + return (sigfigs > 7 ? std::string("DOUBLE") : std::string("FLOAT")); } - - if (pos == keyvalue.size()) { - if (keyvalue.find(".") == std::string::npos) // all numbers and no decimals, it's an integer - return std::string("INT"); - else // otherwise numbers with a decimal, it's a double - return std::string("DOUBLE"); + else + // no decimal must be int or long + if (numpts==0 && numnum>0) { + try { + // safely convert to long + long long val = std::stoll(keyvalue); + // if in range of int then use int, otherwise long + if (val >= INT_MIN && val <= INT_MAX) return std::string("INT"); + else return std::string("LONG"); + } + // failed conversion returns string + catch (...) { return std::string("STRING"); } } - else return std::string("STRING"); // lastly, must be a string + + // if this somehow falls through then return string + return std::string("STRING"); } /***** Common::FitsKeys::get_keytype ****************************************/ @@ -255,8 +280,14 @@ namespace Common { size_t pos = keystring.find(comment_separator); // location of the comment separator keyvalue = keystring.substr(0, pos); // keyvalue is everything up to comment - keyvalue = keyvalue.erase(0, keyvalue.find_first_not_of(" ")); // remove leading spaces from keyvalue - keyvalue = keyvalue.erase(keyvalue.find_last_not_of(" ")+1); // remove trailing spaces from keyvalue + + size_t first = keyvalue.find_first_not_of(' '); + if (first==std::string::npos) keyvalue.clear(); + else { + size_t last = keyvalue.find_last_not_of(' '); + keyvalue = keyvalue.substr(first, last-first+1); // substr removes leading/trailing spaces + } + if (pos != std::string::npos) { keycomment = keystring.erase(0, pos + comment_separator.length()); keycomment = keycomment.erase(0, keycomment.find_first_not_of(" ")); // remove leading spaces from keycomment diff --git a/common/common.h b/common/common.h index 2207ad1c..562d6ada 100644 --- a/common/common.h +++ b/common/common.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include #include @@ -40,6 +41,8 @@ const std::string SNAPSHOT = "snapshot"; ///< common daemon command forces constexpr bool EXT = true; ///< constant for use_extension arg of Common::Header::add_key() constexpr bool PRI = !EXT; ///< constant for use_extension arg of Common::Header::add_key() +constexpr int DEFAULTPRECISION = 8; ///< default precision for floating point keywords + /***** Common *****************************************************************/ /** * @namespace Common @@ -538,6 +541,64 @@ namespace Common { long addkey( const std::string &arg ); ///< add FITS key to the internal database long addkey( const std::vector &vec ); ///< add FITS key to the internal database + private: + + /***** Common::FitsKeys::resolve_type_and_value *************************/ + /** + * @brief determine type of tval and format as necessary into value string + * @details This determines the type of the template type tval and formats + * it into string value, applying requested floating point precision. + * @param[in] tval templated value + * @param[in] prec precision for floating point + * @param[out] type reference to type string + * @param[out] value reference to formatted value string + * + */ + template void resolve_type_and_value(T tval, int prec, std::string &type, std::string &value) { + // Set the type based on type T of tval. + // The use of constexpr() ensures that the compiler discards branches + // that are not valid for the given T. + // + if constexpr (std::is_same_v) type = "BOOL"; + else + if constexpr (std::is_same_v) type = "DOUBLE"; + else + if constexpr (std::is_same_v) type = "FLOAT"; + else + if constexpr (std::is_same_v) type = "INT"; + else + if constexpr (std::is_same_v) type = "LONG"; + + std::stringstream valstr; + + // If floating point value is NAN then change to string "NaN" + if constexpr (std::is_floating_point_v) { + if (std::isnan(tval)) { + valstr << "NaN"; + type = "STRING"; + } + else { + // floating points are formatted with requested precision + valstr << std::fixed << std::setprecision(prec) << tval; + } + } + else { + // If type was unresolved then try to infer it + valstr << tval; + if constexpr (!std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v) { + type = get_keytype(valstr.str()); // content-based inference + } + } + value = valstr.str(); + } + /***** Common::FitsKeys::resolve_type_and_value *************************/ + + public: + /***** Common::FitsKeys::addkey *****************************************/ /** * @brief template function adds FITS keyword to internal database @@ -569,60 +630,57 @@ namespace Common { * */ inline long addkey( const std::string &key, bool bval, const std::string &comment ) { - return addkey( key, (bval?"T":"F"), comment, 0 ); + return do_addkey( key, (bval?"T":"F"), comment, 0, "" ); } template long addkey( const std::string &key, T tval, const std::string &comment ) { - return addkey( key, tval, comment, 8 ); + return do_addkey( key, tval, comment, DEFAULTPRECISION, "" ); + } + template long addkey( const std::string &key, T tval, const std::string &comment, const char* type ) { + const std::string _type = type ? std::string(type) : std::string(); + return do_addkey( key, tval, comment, DEFAULTPRECISION, _type ); + } + template long addkey( const std::string &key, T tval, const std::string &comment, std::string type ) { + return do_addkey( key, tval, comment, DEFAULTPRECISION, type ); } template long addkey( const std::string &key, T tval, const std::string &comment, int prec ) { + return do_addkey( key, tval, comment, prec, "" ); + } + template long do_addkey( const std::string &key, + T tval, + const std::string &comment, + int prec, + std::string type_in ) { std::stringstream val; - std::string type; + std::string type, value; - // "convert" the type value into a string via the appropriate stream - // and set the type string. - // - // The use of constexpr() ensures that the compiler discards brances - // that are not valid for the given T. + if ( key.empty() || ( key.find(" ") != std::string::npos ) ) return NO_ERROR; + + // this determines the type based on the templated tval + // and formats the value if needed (for floating point precision) // - if constexpr( std::is_same::value ) { - val << std::fixed << std::setprecision( prec ); - if ( !std::isnan(tval) ) val << tval; else val << "NaN"; - type = ( !std::isnan(tval) ? "DOUBLE" : "STRING" ); - } - else - if constexpr( std::is_same::value ) { - val << std::fixed << std::setprecision( prec ); - if ( !std::isnan(tval) ) val << tval; else val << "NaN"; - type = ( !std::isnan(tval) ? "FLOAT" : "STRING" ); - } - else - if constexpr( std::is_same::value ) { - val << tval; - type = "INT"; - } - else - if constexpr( std::is_same::value ) { - val << tval; - type = "LONG"; - } - else { - val << tval; - type = this->get_keytype( val.str() ); // try to infer the type from any string - } + resolve_type_and_value(tval, prec, type, value); - if ( key.empty() || ( key.find(" ") != std::string::npos ) ) return NO_ERROR; + // if requested type_in not a recognized type then ignore it + // + if ( !type_in.empty() && (type_in != "DOUBLE" || + type_in != "FLOAT" || + type_in != "INT" || + type_in != "LONG" || + type_in != "BOOL" || + type_in != "STRING" ) ) type_in.clear(); // insert new entry into the database // this->keydb[key].keyword = key; - this->keydb[key].keytype = type; - this->keydb[key].keyvalue = val.str(); + this->keydb[key].keytype = type_in.empty() ? type : type_in; // allow override detected type + this->keydb[key].keyvalue = value; this->keydb[key].keycomment = comment; #ifdef LOGLEVEL_DEBUG std::string function = "Common::FitsKeys::addkey"; std::stringstream message; - message << "[DEBUG] added key type " << type << ": " << key << "=" << tval << " (" << this->keydb[key].keytype << ") // " << comment; + message << "[DEBUG] added key " << key << "=" << value << " (" << type << ") // " << comment; + if (!type_in.empty()) message << " *** override type as " << type_in << " ***"; logwrite( function, message.str() ); #endif return( NO_ERROR ); @@ -826,6 +884,7 @@ namespace Common { const std::string &jkey, const std::string &keyword, const std::string &comment, + const std::string &type, bool use_extension, const std::string &chan="") { const std::string function="Common::Header::add_json_key"; @@ -838,6 +897,8 @@ namespace Common { logwrite( function, message.str() ); } + const std::string &keyname = (!keyword.empty() ? keyword : jkey); + try { // extract the value from the JSON message using jkey as the key // @@ -853,39 +914,67 @@ namespace Common { // FitsKeys &keydb = ( use_extension ? elmo(chan) : primary() ); - // type-check each value to call add_key with the correct type - // keyword is the header keyword if not empty, otherwise use jkey + // if a type was explicitly specified then use that + // + if (type=="DOUBLE" && jvalue.is_number()) { + this->add_key( keydb, keyname, jvalue.template get(), comment ); + return; + } + else + if (type=="FLOAT" && jvalue.is_number()) { + this->add_key( keydb, keyname, jvalue.template get(), comment ); + return; + } + else + if (type=="LONG" && jvalue.is_number()) { + this->add_key( keydb, keyname, jvalue.template get(), comment ); + return; + } + else + if (type=="INT" && jvalue.is_number()) { + this->add_key( keydb, keyname, jvalue.template get(), comment ); + return; + } + else + if (type=="BOOL") { + this->add_key( keydb, keyname, jvalue.template get(), comment ); + return; + } + else + if (type=="STRING") { + this->add_key( keydb, keyname, jvalue.template get(), comment ); + return; + } + + // if we're still here, type-check each value to call add_key with the + // correct type // if ( jvalue.type() == json::value_t::boolean ) { - this->add_key( keydb, (!keyword.empty()?keyword:jkey), jvalue.template get(), comment ); + this->add_key( keydb, keyname, jvalue.template get(), comment ); } else if ( jvalue.type() == json::value_t::number_integer ) { - this->add_key( keydb, (!keyword.empty()?keyword:jkey), jvalue.template get(), comment ); + this->add_key( keydb, keyname, jvalue.template get(), comment ); } else if ( jvalue.type() == json::value_t::number_unsigned ) { - this->add_key( keydb, (!keyword.empty()?keyword:jkey), jvalue.template get(), comment ); + this->add_key( keydb, keyname, jvalue.template get(), comment ); } else if ( jvalue.type() == json::value_t::number_float ) { - this->add_key( keydb, (!keyword.empty()?keyword:jkey), jvalue.template get(), comment ); + this->add_key( keydb, keyname, jvalue.template get(), comment ); } else if ( jvalue.type() == json::value_t::string ) { - this->add_key( keydb, (!keyword.empty()?keyword:jkey), jvalue.template get(), comment ); + this->add_key( keydb, keyname, jvalue.template get(), comment ); } else { - message << "ERROR unknown type for keyword " << (!keyword.empty()?keyword:jkey) << "=" << jvalue; + message << "ERROR unknown type for keyword " << keyname << "=" << jvalue; logwrite( function, message.str() ); } } - catch( const json::exception &e ) { - message.str(""); message << "JSON exception adding keyword " << (!keyword.empty()?keyword:jkey) << ": " << e.what(); - logwrite( function, message.str() ); - } catch( const std::exception &e ) { - message.str(""); message << "ERROR exception adding keyword " << (!keyword.empty()?keyword:jkey) << ": " << e.what(); + message.str(""); message << "ERROR adding keyword " << keyname << ": " << e.what(); logwrite( function, message.str() ); } } diff --git a/slicecamd/slicecam_interface.cpp b/slicecamd/slicecam_interface.cpp index 272f18c6..64a56644 100644 --- a/slicecamd/slicecam_interface.cpp +++ b/slicecamd/slicecam_interface.cpp @@ -1120,8 +1120,8 @@ namespace Slicecam { Common::extract_telemetry_value( jmessage, "SLITO", telem.slitoffset ); Common::extract_telemetry_value( jmessage, "SLITW", telem.slitwidth ); - this->telemkeys.add_json_key(jmessage, "SLITO", "SLITO", "slit offset in arcsec", false); - this->telemkeys.add_json_key(jmessage, "SLITW", "SLITW", "slit width in arcsec", false); + this->telemkeys.add_json_key(jmessage, "SLITO", "SLITO", "slit offset in arcsec", "FLOAT", false); + this->telemkeys.add_json_key(jmessage, "SLITW", "SLITW", "slit width in arcsec", "FLOAT", false); } From 6d1156219ec64546597e43325df9cb72d6e5a482 Mon Sep 17 00:00:00 2001 From: David Hale Date: Mon, 16 Jun 2025 09:39:14 -0700 Subject: [PATCH 03/19] sequencer sends binning commands to camera --- sequencerd/sequence.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/sequencerd/sequence.cpp b/sequencerd/sequence.cpp index 00175e34..f8312389 100644 --- a/sequencerd/sequence.cpp +++ b/sequencerd/sequence.cpp @@ -709,6 +709,9 @@ namespace Sequencer { const std::string function("Sequencer::Sequence::camera_set"); std::string reply; std::stringstream camcmd; + long error=NO_ERROR; + + logwrite( function, "setting camera parameters"); ScopedState thr_state( thread_state_manager, Sequencer::THR_CAMERA_SET ); ScopedState wait_state( wait_state_manager, Sequencer::SEQ_WAIT_CAMERA ); @@ -720,16 +723,23 @@ namespace Sequencer { // long exptime_msec = (long)( this->target.exptime_req * 1000 ); camcmd.str(""); camcmd << CAMERAD_EXPTIME << " " << exptime_msec; + error |= this->camerad.send( camcmd.str(), reply ); - logwrite( function, "sending "+camcmd.str() ); + // send binning parameters + // this is only good for I/R and will have to change to be more general + // because not all detectors will be oriented the same! + // + camcmd.str(""); camcmd << CAMERAD_BIN << " row " << this->target.binspat; + error |= this->camerad.send( camcmd.str(), reply ); + camcmd.str(""); camcmd << CAMERAD_BIN << " col " << this->target.binspect; + error |= this->camerad.send( camcmd.str(), reply ); - if ( this->camerad.send( camcmd.str(), reply ) != NO_ERROR ) { - this->async.enqueue_and_log( function, "ERROR setting exptime" ); + if ( error != NO_ERROR ) { + this->async.enqueue_and_log( function, "ERROR setting camera" ); this->thread_error_manager.set( THR_CAMERA_SET ); - return ERROR; } - return NO_ERROR; + return error; } /***** Sequencer::Sequence::camera_set **************************************/ From a084d36f693b5b803aaef0d5b56cfab42501bb58 Mon Sep 17 00:00:00 2001 From: David Hale Date: Mon, 23 Jun 2025 17:01:09 -0700 Subject: [PATCH 04/19] Fixes bug in commit 2f2cff0a04131d2861221610ca94d2930731dca9 to address issue 321 --- common/common.h | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/common/common.h b/common/common.h index 562d6ada..b65669af 100644 --- a/common/common.h +++ b/common/common.h @@ -662,12 +662,12 @@ namespace Common { // if requested type_in not a recognized type then ignore it // - if ( !type_in.empty() && (type_in != "DOUBLE" || - type_in != "FLOAT" || - type_in != "INT" || - type_in != "LONG" || - type_in != "BOOL" || - type_in != "STRING" ) ) type_in.clear(); + if ( type_in != "DOUBLE" && + type_in != "FLOAT" && + type_in != "INT" && + type_in != "LONG" && + type_in != "BOOL" && + type_in != "STRING" ) type_in.clear(); // insert new entry into the database // @@ -679,8 +679,8 @@ namespace Common { #ifdef LOGLEVEL_DEBUG std::string function = "Common::FitsKeys::addkey"; std::stringstream message; - message << "[DEBUG] added key " << key << "=" << value << " (" << type << ") // " << comment; - if (!type_in.empty()) message << " *** override type as " << type_in << " ***"; + message << "[DEBUG] added key " << key << "=" << value << " (" << this->keydb[key].keytype << ") // " << comment + << " type_in=" << type_in << " resolved type=" << type; logwrite( function, message.str() ); #endif return( NO_ERROR ); @@ -837,6 +837,12 @@ namespace Common { * @param[in] comment comment string for header keyword * */ + template + void add_key_t( FitsKeys &keydb, + const std::string &keyword, const T &value, const std::string &comment, std::string type_override ) { + keydb.addkey( keyword, value, comment, type_override ); + } + template void add_key( FitsKeys &keydb, const std::string &keyword, const T &value, const std::string &comment ) { @@ -917,32 +923,32 @@ namespace Common { // if a type was explicitly specified then use that // if (type=="DOUBLE" && jvalue.is_number()) { - this->add_key( keydb, keyname, jvalue.template get(), comment ); + this->add_key_t( keydb, keyname, jvalue.template get(), comment, type ); return; } else if (type=="FLOAT" && jvalue.is_number()) { - this->add_key( keydb, keyname, jvalue.template get(), comment ); + this->add_key_t( keydb, keyname, jvalue.template get(), comment, type ); return; } else if (type=="LONG" && jvalue.is_number()) { - this->add_key( keydb, keyname, jvalue.template get(), comment ); + this->add_key_t( keydb, keyname, jvalue.template get(), comment, type ); return; } else if (type=="INT" && jvalue.is_number()) { - this->add_key( keydb, keyname, jvalue.template get(), comment ); + this->add_key_t( keydb, keyname, jvalue.template get(), comment, type ); return; } else if (type=="BOOL") { - this->add_key( keydb, keyname, jvalue.template get(), comment ); + this->add_key_t( keydb, keyname, jvalue.template get(), comment, type ); return; } else if (type=="STRING") { - this->add_key( keydb, keyname, jvalue.template get(), comment ); + this->add_key_t( keydb, keyname, jvalue.template get(), comment, type ); return; } From e9044a9bf2d0d08e0a0a12c72e94564517629935 Mon Sep 17 00:00:00 2001 From: David Hale Date: Tue, 15 Jul 2025 12:57:54 -0700 Subject: [PATCH 05/19] fixes connection to MySQL database Adds SessionPool class, which on construction creates a pool of connected database sessions using a queue. Modifies the existing Database class to make use of SessionPool, retrieving/returning connections from/to the pool. Clients don't know anything about a pool. Adds helper functions to Database to insert, update and read database records. Updates database clients (sequencerd, acamd, thermald) to make use of this. This addresses Issue #314 --- acamd/acam_interface.cpp | 19 +- sequencerd/sequencer_interface.cpp | 480 ++++++--------------- sequencerd/sequencer_interface.h | 37 +- thermald/thermal_server.cpp | 8 +- utils/database.cpp | 669 ++++++++++++++++++++++------- utils/database.h | 176 ++++++-- 6 files changed, 796 insertions(+), 593 deletions(-) diff --git a/acamd/acam_interface.cpp b/acamd/acam_interface.cpp index 6faba489..3abf8955 100644 --- a/acamd/acam_interface.cpp +++ b/acamd/acam_interface.cpp @@ -2302,16 +2302,6 @@ namespace Acam { // close the Andor // error |= this->camera.close(); - - // close the database connection - // this may throw an exception - // - try { this->database.close(); } - catch ( const std::exception &e ) { - message.str(""); message << "ERROR " << e.what(); - logwrite( function, message.str() ); - return ERROR; - } } // close connection to tcsd @@ -3801,11 +3791,10 @@ logwrite( function, message.str() ); // then will clear the map object once they are written. // try { - iface->database.write(); + iface->database.insert(); } - catch ( ... ) { - logwrite( function, "ERROR writing to database" ); -// error=ERROR; removed 12/12/2024 -- don't let database errors stop anything + catch ( const std::exception &e ) { + logwrite( function, "ERROR writing to database: "+std::string(e.what()) ); } return error; @@ -4627,7 +4616,7 @@ logwrite( function, message.str() ); this->database.add_key_val( "obs_id", 123 ); this->database.add_key_val( "airmass", 1.23 ); this->database.add_key_val( "acquired", true ); - this->database.write(); + this->database.insert(); } catch ( const std::exception &e ) { message.str(""); message << "ERROR adding keys to database: " << e.what(); diff --git a/sequencerd/sequencer_interface.cpp b/sequencerd/sequencer_interface.cpp index 17bcc625..e85740d9 100644 --- a/sequencerd/sequencer_interface.cpp +++ b/sequencerd/sequencer_interface.cpp @@ -169,18 +169,11 @@ namespace Sequencer { logwrite( function, message.str() ); #endif try { - this->dbManager = std::make_unique(this->db_host, this->db_port, - this->db_user, this->db_pass, - this->db_schema, this->db_active); - } - catch (const mysqlx::Error& e) { - message.str(""); message << "ERROR starting database: " << e.what(); - logwrite( function, message.str() ); - return error; + // configure database object to use active targets table unless otherwise specified + database = std::make_unique(db_host, db_port, db_user, db_pass, db_schema, db_active); } catch( const std::exception &e ) { - message.str(""); message << "ERROR starting database: " << e.what(); - logwrite( function, message.str() ); + logwrite( function, "ERROR: "+std::string(e.what()) ); return error; } this->db_configured = true; @@ -222,12 +215,12 @@ namespace Sequencer { if ( args.empty() && this->setid < 0 ) { logwrite( function, "ERROR: set ID has not been set and no ID or name provided" ); - return( ERROR ); + return ERROR; } if ( !is_db_configured() ) { logwrite( function, "ERROR: database not configured (check .cfg file)" ); - return( ERROR ); + return ERROR; } try { @@ -247,38 +240,27 @@ namespace Sequencer { setname_in = ( use_id ? "" : args ); // get the provided setname } - // create a session for accessing the database - // - mysqlx::Session mySession( mysqlx::SessionOption::HOST, this->db_host, - mysqlx::SessionOption::PORT, this->db_port, - mysqlx::SessionOption::USER, this->db_user, - mysqlx::SessionOption::PWD, this->db_pass ); - - // connect to database - // - mysqlx::Schema db( mySession, this->db_schema ); - - // create a table object - // - mysqlx::Table targetsets = db.getTable( this->db_sets ); - // Find a row in the SQL table where either SET_ID is setid_in or SET_NAME is setname_in, // depending on if a number or a string was provided above. // - mysqlx::RowResult result; + std::string condition; + std::map bindings; + if ( use_id ) { - result = targetsets.select( this->targetset_cols ) - .where( "SET_ID like :setid" ) - .bind( "setid", setid_in ) - .execute(); + condition = "SET_ID like :setid"; + bindings = { { "setid", mysqlx::Value(setid_in) } }; } else { - result = targetsets.select( this->targetset_cols ) - .where( "SET_NAME like :setname" ) - .bind( "setname", setname_in ) - .execute(); + condition = "SET_NAME like :setname"; + bindings = { { "setname", mysqlx::Value(setname_in) } }; } + // read from active targets table + mysqlx::RowResult result = database->read(this->db_sets, + this->targetset_cols, + condition, + bindings); + rowcount = result.count(); colcount = result.getColumnCount(); @@ -288,7 +270,7 @@ namespace Sequencer { message.str(""); message << "ERROR no target sets found with requested "; if ( use_id ) message << "ID = " << setid_in; else message << "name = " << setname_in; logwrite( function, message.str() ); - return( ERROR ); + return ERROR; } // fetch the current row @@ -308,33 +290,14 @@ namespace Sequencer { retstream.str(""); retstream << this->setid << " " << this->setname; retstring = retstream.str(); } - catch ( std::invalid_argument & ) { - message.str(""); message << "ERROR invalid argument: args=" << args << " col=" << col; - logwrite(function, message.str() ); - return( ERROR ); - } - catch ( std::out_of_range & ) { - message.str(""); message << "ERROR out of range: args=" << args << " col=" << col; - logwrite(function, message.str() ); - return( ERROR ); - } - catch ( const mysqlx::Error &err ) { /// catch errors thrown from mysqlx connector/C++ X DEV API - message.str(""); message << "ERROR from mySQL "; - if ( col >= 0 && col < colcount ) { message << "(reading " << this->targetset_cols.at(col) << ")"; } - else { message << "( col = " << col << " )"; } - message << ": " << err; - logwrite( function, message.str() ); - init_record(); // ensures that any previous record's info is not mistaken for this one - return( ERROR ); - } - catch ( std::exception &ex ) { /// catch std::exceptions. This could be if this->colnum() returns a -1 - message.str(""); message << "ERROR std exception "; + catch ( const std::exception &ex ) { /// catch std::exceptions. This could be if this->colnum() returns a -1 + message.str(""); message << "ERROR:"; if ( col >= 0 && col < colcount ) { message << "(reading " << this->targetset_cols.at(col) << ")"; } else { message << "( col = " << col << " )"; } message << ": " << ex.what(); logwrite( function, message.str() ); init_record(); // ensures that any previous record's info is not mistaken for this one - return( ERROR ); + return ERROR; } catch ( const char *ex ) { /// catch everything else message.str(""); message << "ERROR other exception "; @@ -343,7 +306,7 @@ namespace Sequencer { message << ": " << ex; logwrite( function, message.str() ); init_record(); // ensures that any previous record's info is not mistaken for this one - return( ERROR ); + return ERROR; } message.str(""); message << "current target set " << retstream.str(); @@ -372,105 +335,62 @@ namespace Sequencer { */ long TargetInfo::add_row( int number_in, std::string name_in, std::string ra_hms_in, std::string dec_dms_in, double slita_in, double slitw_in, double exptime_in, std::string pointmode_in ) { - std::string function = "Sequencer::TargetInfo::add_row"; + const std::string function("Sequencer::TargetInfo::add_row"); std::stringstream message; if ( !is_db_configured() ) { logwrite( function, "ERROR: database not configured (check .cfg file)" ); - return( ERROR ); + return ERROR; } if ( this->setid < 0 ) { logwrite( function, "ERROR: targetset has not been provided" ); - return( ERROR ); + return ERROR; } try { - // create a session for accessing the database - // - mysqlx::Session mySession( mysqlx::SessionOption::HOST, this->db_host, - mysqlx::SessionOption::PORT, this->db_port, - mysqlx::SessionOption::USER, this->db_user, - mysqlx::SessionOption::PWD, this->db_pass ); - - // connect to database - // - mysqlx::Schema db( mySession, this->db_schema ); - - // create a table object - // - mysqlx::Table targettable = db.getTable( this->db_active ); + std::map record; + + record = { { "OBSERVATION_ID", mysqlx::Value( number_in ) }, // OBSERVATION_ID + { "OBS_ORDER", mysqlx::Value( number_in ) }, // OBS_ORDER + { "SET_ID", mysqlx::Value( this->setid ) }, // SET_ID + { "STATE", mysqlx::Value( Sequencer::TARGET_PENDING ) }, // STATE + { "NAME", mysqlx::Value( name_in ) }, // NAME + { "RA", mysqlx::Value( ra_hms_in ) }, // RA + { "DECL", mysqlx::Value( dec_dms_in ) }, // DECL + { "EPOCH", mysqlx::Value( "J2000" ) }, // EPOCH + { "EXPTIME", mysqlx::Value( exptime_in ) }, // EXPTIME + { "OTMexpt", mysqlx::Value( exptime_in ) }, // OTMexpt + { "TARGET_NUMBER", mysqlx::Value( 1 ) }, // TARGET_NUMBER + { "SEQUENCE_NUMBER", mysqlx::Value( 1 ) }, // SEQUENCE_NUMBER + { "CASANGLE", mysqlx::Value( 0. ) }, // CASANGLE + { "OTMcass", mysqlx::Value( 0. ) }, // OTMcass + { "OTMslitangle", mysqlx::Value( slita_in ) }, // OTMslitangle + { "OTMslitwidth", mysqlx::Value( slitw_in ) }, // OTMslitwidth + { "SLITWIDTH", mysqlx::Value( slitw_in ) }, // SLITWIDTH + { "SLITOFFSET", mysqlx::Value( 1 ) }, // SLITOFFSET + { "BINSPECT", mysqlx::Value( 1 ) }, // BINSPECT + { "BINSPAT", mysqlx::Value( 1 ) }, // BINSPAT + { "POINTMODE", mysqlx::Value( pointmode_in ) } // POINTMODE + }; - // add the row - // - targettable.insert( "OBSERVATION_ID", - "OBS_ORDER", - "SET_ID", - "STATE", - "NAME", - "RA", - "DECL", - "EPOCH", - "EXPTIME", - "OTMexpt", - "TARGET_NUMBER", - "SEQUENCE_NUMBER", - "CASANGLE", - "OTMcass", - "OTMslitangle", - "OTMslitwidth", - "SLITWIDTH", - "SLITOFFSET", - "BINSPECT", - "BINSPAT", - "POINTMODE" - ) - .values( number_in, // OBSERVATION_ID - number_in, // OBS_ORDER - this->setid, // SET_ID - Sequencer::TARGET_PENDING, // STATE - name_in, // NAME - ra_hms_in, // RA - dec_dms_in, // DECL - "J2000", // EPOCH - exptime_in, // EXPTIME - exptime_in, // OTMexpt - 1, // TARGET_NUMBER - 1, // SEQUENCE_NUMBER - 0., // CASANGLE - 0., // OTMcass - slita_in, // OTMslitangle - slitw_in, // OTMslitwidth - slitw_in, // SLITWIDTH - 1, // SLITOFFSET - 1, // BINSPECT - 1, // BINSPAT - pointmode_in // POINTMODE - ) - .execute(); + database->insert(record); // into active targets table } - catch ( const mysqlx::Error &err ) { - message.str(""); message << "ERROR from mySQL: " << err; - logwrite( function, message.str() ); - return( ERROR ); - } - catch ( std::exception &ex ) { - message.str(""); message << "ERROR std exception: " << ex.what(); - logwrite( function, message.str() ); - return( ERROR ); + catch ( const std::exception &ex ) { + logwrite( function, "ERROR: "+std::string(ex.what()) ); + return ERROR; } catch ( const char *ex ) { - message.str(""); message << "ERROR other exception: " << ex; - logwrite( function, message.str() ); - return( ERROR ); + logwrite( function, "ERROR: "+std::string(ex) ); + return ERROR; } - return( NO_ERROR ); + return NO_ERROR; } /***** Sequencer::TargetInfo::add_row ***************************************/ - TargetInfo::TargetState TargetInfo::get_specified_target( std::string args, std::string &retstring ) { + TargetInfo::TargetState TargetInfo::get_specified_target( std::string obsid, std::string &retstring ) { const std::string function="Sequencer::TargetInfo::get_specified_target"; std::stringstream message; @@ -483,13 +403,15 @@ namespace Sequencer { } try { - int _obsid = std::stoi(args); + const std::string condition("OBSERVATION_ID like :obsid"); + const std::string order("OBSERVATION_ID"); + std::map bindings = { { "obsid", mysqlx::Value(obsid) } }; - std::string condition = "OBSERVATION_ID like :obsid"; - std::string order = "OBSERVATION_ID"; - std::map bindings = { {"obsid", args} }; - - mysqlx::RowResult result = dbManager->do_query(condition, order, bindings, this->targetlist_cols); + // read from active targets table + mysqlx::RowResult result = database->read(targetlist_cols, + condition, + bindings, + order); mysqlx::row_count_t rowcount = result.count(); mysqlx::col_count_t colcount = result.getColumnCount(); @@ -498,7 +420,7 @@ namespace Sequencer { logwrite( function, message.str() ); if ( result.count() < 1 ) { - message.str(""); message << "no matching target found for obsid " << _obsid; + message.str(""); message << "no matching target found for obsid " << obsid; retstring = message.str(); logwrite( function, message.str() ); init_record(); // ensures that any previous record's info is not mistaken for this one @@ -519,15 +441,8 @@ namespace Sequencer { if ( this->parse_target_from_row( row ) != NO_ERROR ) return TARGET_ERROR; } - catch ( const mysqlx::Error &err ) { /// catch errors thrown from mysqlx connector/C++ X DEV API - message.str(""); message << "ERROR mySQL exception: " << err; - retstring = message.str(); - logwrite( function, message.str() ); - init_record(); // ensures that any previous record's info is not mistaken for this one - return TARGET_ERROR; - } catch ( std::exception &ex ) { /// catch std::exceptions. This could be if this->colnum() returns a -1 - message.str(""); message << "ERROR exception: " << ex.what(); + message.str(""); message << "ERROR: " << ex.what(); retstring = message.str(); logwrite( function, message.str() ); init_record(); // ensures that any previous record's info is not mistaken for this one @@ -615,31 +530,19 @@ namespace Sequencer { } try { - // create a session for accessing the database - // - mysqlx::Session mySession( mysqlx::SessionOption::HOST, this->db_host, - mysqlx::SessionOption::PORT, this->db_port, - mysqlx::SessionOption::USER, this->db_user, - mysqlx::SessionOption::PWD, this->db_pass ); - - // connect to database - // - mysqlx::Schema db( mySession, this->db_schema ); - - // create a table object - // - mysqlx::Table targettable = db.getTable( this->db_active ); - // Find a row in the SQL active observations table, // the next one (in order) where state is state_in. // - mysqlx::RowResult result = targettable.select( this->targetlist_cols ) - .where( "SET_ID like :setid && STATE like :state" ) - .orderBy( "OBS_ORDER" ) - .bind( "state", state_in ) - .bind( "setid", this->setid ) - .execute(); + const std::string condition("SET_ID like :setid && STATE like :state"); + const std::string order("OBS_ORDER"); + std::map bindings = { { "state", mysqlx::Value(state_in) }, + { "setid", mysqlx::Value(this->setid) } }; + // read from active targets table + mysqlx::RowResult result = database->read(this->targetlist_cols, + condition, + bindings, + order); rowcount = result.count(); colcount = result.getColumnCount(); @@ -668,18 +571,8 @@ namespace Sequencer { error = this->parse_target_from_row( row ); } - catch ( const mysqlx::Error &err ) { /// catch errors thrown from mysqlx connector/C++ X DEV API - message.str(""); message << "ERROR mySQL exception "; - if ( col >= 0 && col < colcount ) { message << "(reading " << this->targetlist_cols.at(col) << ")"; } - else { message << "( col = " << col << " )"; } - message << ": " << err; - status = message.str(); - logwrite( function, message.str() ); - init_record(); // ensures that any previous record's info is not mistaken for this one - return TARGET_ERROR; - } - catch ( std::exception &ex ) { /// catch std::exceptions. This could be if this->colnum() returns a -1 - message.str(""); message << "ERROR exception "; + catch ( std::exception &ex ) { + message.str(""); message << "ERROR "; if ( col >= 0 && col < colcount ) { message << "(reading " << this->targetlist_cols.at(col) << ")"; } else { message << "( col = " << col << " )"; } message << ": " << ex.what(); @@ -870,30 +763,18 @@ namespace Sequencer { } try { - // create a session for accessing the database - // - mysqlx::Session mySession( mysqlx::SessionOption::HOST, this->db_host, - mysqlx::SessionOption::PORT, this->db_port, - mysqlx::SessionOption::USER, this->db_user, - mysqlx::SessionOption::PWD, this->db_pass ); - - // connect to database + // To ensure there's only one matching record, find the row in the SQL active + // observations table which matches the current observation ID. The targetlist_cols + // vector identifies the fields to retrieve and is initialized by the TargetInfo() + // class initializer list. // - mysqlx::Schema db( mySession, this->db_schema ); + const std::string condition("OBSERVATION_ID like :obsid"); + std::map bindings = { { "obsid", mysqlx::Value(this->obsid) } }; - // create a table object - // - mysqlx::Table targettable = db.getTable( this->db_active ); - - // Find the row in the SQL active observations table - // which matches the current observation ID. The targetlist_cols - // vector identifies the fields to retrieve and is initialized - // by the TargetInfo() class initializer list. - // - mysqlx::RowResult result = targettable.select( this->targetlist_cols ) - .where( "OBSERVATION_ID like :obsid" ) - .bind( "obsid", this->obsid ) - .execute(); + // read from active targets table + mysqlx::RowResult result = database->read(this->targetlist_cols, + condition, + bindings); rowcount = result.count(); /// number or rows that match the select criteria @@ -906,26 +787,21 @@ namespace Sequencer { return( ERROR ); } - // update the state here + // update state in the active targets table // - targettable.update( ) - .set( "STATE", newstate ) - .where( "OBSERVATION_ID like :obsid" ) - .bind( "obsid", this->obsid ) - .execute(); + std::map setdata = { { "STATE", mysqlx::Value(newstate) } }; + + database->update(setdata, + condition, + bindings); message.str(""); message << "target " << this->name << " id " << this->obsid << " state " << newstate; logwrite( function, message.str() ); this->state = newstate; // on success, save the new state to the class so that it can be accessed by enqueue } - catch ( const mysqlx::Error &err ) { /// catch errors thrown from mysqlx connector/C++ X DEV API - message.str(""); message << "ERROR from mySQL: " << err; - logwrite( function, message.str() ); - return( ERROR ); - } - catch ( std::exception &ex ) { /// catch std::exceptions. This could be if this->colnum() returns a -1 - message.str(""); message << "ERROR std exception: " << ex.what(); + catch ( const std::exception &ex ) { + message.str(""); message << "ERROR: " << ex.what(); logwrite( function, message.str() ); return( ERROR ); } @@ -954,106 +830,38 @@ namespace Sequencer { return ERROR; } - if ( this->name.empty() ) { - logwrite( function, "ERROR no record selected" ); - return ERROR; - } - try { - // create a session for accessing the database - // - mysqlx::Session mySession( mysqlx::SessionOption::HOST, this->db_host, - mysqlx::SessionOption::PORT, this->db_port, - mysqlx::SessionOption::USER, this->db_user, - mysqlx::SessionOption::PWD, this->db_pass ); - - // connect to database - // - mysqlx::Schema db( mySession, this->db_schema ); - - // create a table object - // - mysqlx::Table targettable = db.getTable( this->db_completed ); - - // create a vector of column names - // - std::vector columns; - columns = { "OWNER", // target table - "OBSERVATION_ID", // target table - "SET_ID", // target table - "TARGET_NUMBER", // target table - "SEQUENCE_NUMBER", // target table - "NAME", // target table - "FITSFILE", // internal from ___ - "RA", // target table - "DECL", // target table - "SLITANGLE_REQ", // target table col = SLITANGLE - "POINTMODE", // target table - "NOTBEFORE", // target table - "SLEW_START", // from Sequence::dothread_move_to_target() - "SLEW_END", // from Sequence::dothread_move_to_target() - "EXPTIME_REQ", // target table col = OTMexpt - "EXP_START", // from Sequence::dothread_trigger_exposure() - "EXP_END", // from Sequence::dothread_sequencer_async_listener() ? - "SLITWIDTH_REQ", // target table col = SLITWIDTH - "BINSPECT", // target table - "BINSPAT", // target table - "OBSMODE", // target table - "NOTE", // target table - "OTMFLAG" // target table - }; - - // and a vector of corresponding values for those columns - // - std::vector values; - values = { this->owner, // OWNER - this->obsid, // OBSERVATION_ID - this->setid, // SET_ID - this->targetnum, // TARGET_NUMBER - this->sequencenum, // SEQUENCER_NUMBER - this->name, // NAME - this->fitsfile, // FITSFILE - this->ra_hms, // RA - this->dec_dms, // DECL - this->slitangle_req, // SLITANGLE_REQ - this->pointmode, // POINTMODE - this->notbefore, // NOTBEFORE - this->slewstart, // SLEW_START - this->slewend, // SLEW_END - this->exptime_req, // EXPTIME_REQ <-- came in as OTMexpt - this->expstart, // EXP_START - this->expend, // EXP_END - this->slitwidth_req, // SLITWIDTH_REQ - this->binspect, // BINSPECT - this->binspat, // BINSPAT - this->obsmode, // OBSMODE - this->note, // NOTE - this->otmflag // OTMFLAG + std::map record; + + record = { { "OWNER", mysqlx::Value( this->owner ) }, // from target table + { "OBSERVATION_ID", mysqlx::Value( this->obsid ) }, // from target table + { "SET_ID", mysqlx::Value( this->setid ) }, // from target table + { "TARGET_NUMBER", mysqlx::Value( this->targetnum ) }, // from target table + { "SEQUENCE_NUMBER",mysqlx::Value( this->sequencenum ) }, // from target table + { "NAME", mysqlx::Value( this->name ) }, // from target table + { "FITSFILE", mysqlx::Value( this->fitsfile ) }, // internal from ___ + { "RA", mysqlx::Value( this->ra_hms ) }, // from target table + { "DECL", mysqlx::Value( this->dec_dms ) }, // from target table + { "SLITANGLE_REQ", mysqlx::Value( this->slitangle_req ) }, // from target table col = SLITANGLE + { "POINTMODE", mysqlx::Value( this->pointmode ) }, // from target table + { "NOTBEFORE", mysqlx::Value( this->notbefore ) }, // from target table + { "SLEW_START", mysqlx::Value( this->slewstart ) }, // from Sequence::dothread_move_to_target() + { "SLEW_END", mysqlx::Value( this->slewend ) }, // from Sequence::dothread_move_to_target() + { "EXPTIME_REQ", mysqlx::Value( this->exptime_req ) }, // came in as OTMexpt from target table col = OTMexpt + { "EXP_START", mysqlx::Value( this->expstart ) }, // from Sequence::dothread_trigger_exposure() + { "EXP_END", mysqlx::Value( this->expend ) }, // from Sequence::dothread_sequencer_async_listener() ? + { "SLITWIDTH_REQ", mysqlx::Value( this->slitwidth_req) }, // from target table col = SLITWIDTH + { "BINSPECT", mysqlx::Value( this->binspect ) }, // from target table + { "BINSPAT", mysqlx::Value( this->binspat ) }, // from target table + { "OBSMODE", mysqlx::Value( this->obsmode ) }, // from target table + { "NOTE", mysqlx::Value( this->note ) }, // from target table + { "OTMFLAG", mysqlx::Value( this->otmflag ) } // from target table }; - // The entries in the above "columns" and "values" vectors are fixed. - // Now add additional columns/values to each which come from external - // telemetry sources, but only add them if they have a valid value. - // - for ( const auto &[name, data] : this->external_telemetry ) { - if ( data.valid ) { - columns.push_back( name ); - values.push_back( data.value ); - } - } - - // add the row -- - // - targettable.insert( columns).values( values ).execute(); - } - catch ( const mysqlx::Error &err ) { - message.str(""); message << "ERROR mySQL exception: " << err; - logwrite( function, message.str() ); - return ERROR; + database->insert( this->db_completed, record ); // into completed targets table } catch ( const std::exception &e ) { - message.str(""); message << "ERROR std exception: " << e.what(); - logwrite( function, message.str() ); + logwrite( function, "ERROR: "+std::string(e.what()) ); return ERROR; } @@ -1071,50 +879,32 @@ namespace Sequencer { * */ long TargetInfo::get_table_names() { - std::string function = "Sequencer::TargetInfo::get_table_names"; - std::stringstream message; + const std::string function("Sequencer::TargetInfo::get_table_names"); std::list tablenames; if ( !is_db_configured() ) { logwrite( function, "ERROR: database not configured (check .cfg file)" ); - return( ERROR ); + return ERROR; } try { - // create a session for accessing the database - // - mysqlx::Session mySession( mysqlx::SessionOption::HOST, this->db_host, - mysqlx::SessionOption::PORT, this->db_port, - mysqlx::SessionOption::USER, this->db_user, - mysqlx::SessionOption::PWD, this->db_pass ); - - // connect to database - // - mysqlx::Schema db( mySession, this->db_schema ); - - tablenames = db.getTableNames(); - } - catch ( const mysqlx::Error &err ) { /// catch errors thrown from mysqlx connector/C++ X DEV API - message.str(""); message << "ERROR from mySQL: " << err; - logwrite( function, message.str() ); - return( ERROR ); + tablenames = database->get_tablenames(); } - catch ( std::exception &ex ) { /// catch std::exceptions. This could be if this->colnum() returns a -1 - message.str(""); message << "ERROR std exception: " << ex.what(); - logwrite( function, message.str() ); - return( ERROR ); + catch ( const std::exception &ex ) { /// catch std::exceptions. This could be if this->colnum() returns a -1 + logwrite( function, "ERROR: "+std::string(ex.what()) ); + return ERROR; } catch ( const char *ex ) { /// catch everything else - message.str(""); message << "ERROR other exception: " << ex; - logwrite( function, message.str() ); - return( ERROR ); + logwrite( function, "ERROR: "+std::string(ex) ); + return ERROR; } - message.str(""); message << "TableNames: "; + std::stringstream message; + message << "TableNames: "; for ( const auto &name : tablenames ) message << name << " "; logwrite( function, message.str() ); - return( NO_ERROR ); + return NO_ERROR; } /***** Sequencer::TargetInfo::get_table_names *******************************/ diff --git a/sequencerd/sequencer_interface.h b/sequencerd/sequencer_interface.h index cb2a8489..473b7ef8 100644 --- a/sequencerd/sequencer_interface.h +++ b/sequencerd/sequencer_interface.h @@ -165,41 +165,6 @@ namespace Sequencer { /***** Sequencer::CalibrationTarget *****************************************/ - /***** Sequencer::DatabaseManager *******************************************/ - /** - * @class DatabaseManager - * - */ - class DatabaseManager { - private: - mysqlx::Session session; - mysqlx::Schema db; - mysqlx::Table table; - - public: - DatabaseManager( const std::string &host, int port, - const std::string &user, const std::string &password, - const std::string &schema, const std::string tablename ) - : session( mysqlx::SessionOption::HOST, host, - mysqlx::SessionOption::PORT, port, - mysqlx::SessionOption::USER, user, - mysqlx::SessionOption::PWD, password ), - db( session.getSchema(schema) ), - table( db.getTable(tablename) ) { } - - mysqlx::RowResult do_query( const std::string &condition, const std::string &order, - const std::map &bindings, - const std::vector &columns={"*"} ) { - auto query = table.select(columns).where(condition).orderBy(order); - for ( const auto &[key, value] : bindings ) { - query.bind(key, value); - } - return query.execute(); - } - }; - /***** Sequencer::DatabaseManager *******************************************/ - - /***** Sequencer::TargetInfo ************************************************/ /** * @class TargetInfo @@ -252,7 +217,7 @@ namespace Sequencer { "SET_NAME" }, offset_threshold(0), max_tcs_offset(0) { init_record(); } - std::unique_ptr dbManager; + std::unique_ptr database; SkyInfo::FPOffsets fpoffsets; ///< for calling Python fpoffsets, defined in ~/Software/common/skyinfo.h diff --git a/thermald/thermal_server.cpp b/thermald/thermal_server.cpp index 76115f97..6876f6cb 100644 --- a/thermald/thermal_server.cpp +++ b/thermald/thermal_server.cpp @@ -623,18 +623,14 @@ namespace Thermal { server.interface.telemdata.merge( server.interface.campbell.datamap ); server.interface.telemdata.merge( server.interface.lakeshoredata ); - // write the telemdata map to the database + // insert the telemdata map to the database // - database.write( server.interface.telemdata ); + database.insert( server.interface.telemdata ); server.telem_sleeptimer.sleepFor( std::chrono::seconds( duration ) ); timeout( 0, "sec" ); } - // Database is destructed when it leaves scope, and the destructor - // will close it, but this is tidy. close can throw an exception. - // - database.close(); logwrite( function, "telemetry database closed" ); } catch ( const mysqlx::Error &err ) { diff --git a/utils/database.cpp b/utils/database.cpp index e513059c..14e5f42d 100644 --- a/utils/database.cpp +++ b/utils/database.cpp @@ -10,6 +10,286 @@ namespace Database { + /***** SessionPool::SessionPool *********************************************/ + /** + * @brief SessionPool class constructor + * @details creates a pool (queue) of connected database sessions on construction + * + */ + SessionPool::SessionPool(const std::string &host, int port, const std::string &user, const std::string &pass): + _dbhost(host), _dbport(port), _dbuser(user), _dbpass(pass) { + // create the pool of sessions + for (int i = 0; i < DBPOOLSIZE; ++i) { _queue.push(_create_session()); } + } + /***** SessionPool::SessionPool *********************************************/ + + + /***** SessionPool::~SessionPool ********************************************/ + /** + * @brief SessionPool class destructor + * @details connections will be automatically closed and queue emptied + * when the object is destroyed + * + */ + SessionPool::~SessionPool() { + // Don't want to re-throw anything on exception because no one will be catching + // it on destruction, but catch here to avoid a potential problem on destruction. + // + std::lock_guard lock(_mtx); + while (!_queue.empty()) { + auto db = _queue.front(); + _queue.pop(); + try { db->close(); } + catch (...) { } + } + } + /***** SessionPool::~SessionPool ********************************************/ + + + /***** SessionPool::_create_session *****************************************/ + /** + * @brief private function to create a single mysqlx database connection + * @details Creating a session establishes a connection to the MySQL server. + * The DB info comes from the class contruction. + * @return shared pointer to a mysqlx::Session + * + */ + std::shared_ptr SessionPool::_create_session() { + try { + return std::make_shared(mysqlx::SessionOption::HOST, _dbhost, + mysqlx::SessionOption::PORT, _dbport, + mysqlx::SessionOption::USER, _dbuser, + mysqlx::SessionOption::PWD, _dbpass); + } + catch (const mysqlx::Error& err) { + return nullptr; + } + } + /***** SessionPool::_create_session *****************************************/ + + + /***** SessionPool::_test_session *******************************************/ + /** + * @brief tests db connection using a simple table query + * @paramm[in] db database handle + * @return true|false + * + */ + bool SessionPool::_test_session(std::shared_ptr db) { + // pass-fail + try { + db->sql("SELECT 1").execute(); + return true; // it either works, + } + catch (...) { return false; } // or it doesn't. + } + /***** SessionPool::_test_session *******************************************/ + + + /***** SessionPool::_borrow_session *****************************************/ + /** + * @brief get a db session from the pool + * @details Database connections are always tested before given out, and + * if bad/stale then a new one is opened. + * @return shared pointer to a mysqlx::Session + * + */ + std::shared_ptr SessionPool::_borrow_session(int timeout_ms) { + std::unique_lock lock(_mtx); + if (!_cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), [this] {return !_queue.empty(); })) { + throw std::runtime_error("timeout waiting for database connection"); + } + auto db = _queue.front(); + _queue.pop(); + + // make a new session if this one is bad + if (!_test_session(db)) db = _create_session(); + + return db; + } + /***** SessionPool::_borrow_session *****************************************/ + + + /***** SessionPool::_return_session *****************************************/ + /** + * @brief returns a db session back to the pool + * @param[in] db shared pointer to a mysqlx::Session + * + */ + void SessionPool::_return_session(std::shared_ptr db) { + { + std::lock_guard lock(_mtx); + _queue.push(db); + } + _cv.notify_one(); + } + /***** SessionPool::_return_session *****************************************/ + + + /***** SessionPool::insert **************************************************/ + /** + * @brief insert a record into the database + * @param[in] schemaname database schema name + * @param[in] tablename database table name + * @param[in] data reference to map of column/value data + * + * This can throw an exception. + * + */ + void SessionPool::insert(const std::string &schemaname, const std::string &tablename, const std::map &data) { + + if ( data.empty() ) throw std::runtime_error("no data"); + + // Create vectors from the supplied STL map, pre-allocating memory for them. + // Vectors are easily passed directly to the mysqlx API. + // + size_t ncols = data.size(); + std::vector cols; cols.reserve( ncols ); + std::vector vals; vals.reserve( ncols ); + + for ( const auto &dat : data ) { + cols.push_back( dat.first ); // database columns + vals.push_back( dat.second ); // value for that column + } + + if ( cols.empty() || vals.empty() || cols.size() != vals.size() ) { + throw std::runtime_error( "data empty or improperly formatted" ); + } + + // Insert a row into the database table + // + try { + // safely get a DB session from the pool + SessionGuard session(this); + auto db = session.get(); + + auto schema = std::make_unique( *(db), schemaname ); + auto table = std::make_unique( schema->getTable( tablename ) ); + + table->insert( cols ).values( vals ).execute(); + } + catch ( const std::exception &err ) { + throw; + } + } + /***** SessionPool::insert **************************************************/ + + + /***** SessionPool::update **************************************************/ + /** + * @brief update an existing record + * @details may throw an exception + * @param[in] schemaname schema name (optional) + * @param[in] tablename table name (optional) + * @param[in] setdata STL map containing mysqlx data indexed by DB column name + * + */ + void SessionPool::update(const std::string &schemaname, const std::string &tablename, + const std::map &setdata, + const std::string &condition, + const std::map &bindings) { + + if ( setdata.empty() ) throw std::runtime_error("no data to update"); + + // Update the database table + // + try { + // safely get a DB session from the pool + SessionGuard session(this); + auto db = session.get(); + + auto schema = std::make_unique( *(db), schemaname ); + auto table = std::make_unique( schema->getTable( tablename ) ); + + // create an updater + auto updater = table->update(); + + // apply .set() calls for each column-data pair + for ( const auto &[column, data] : setdata ) updater.set( column, data ); + + updater.where(condition); + + // apply .bindings() + for ( const auto &[key, val] : bindings ) updater.bind( key, val ); + + // perform the update + updater.execute(); + } + catch ( const std::exception &err ) { + throw; + } + } + /***** SessionPool::update **************************************************/ + + + /***** SessionPool::read ****************************************************/ + /** + * @brief read from the database + * @param[in] schemaname + * @param[in] tablename + * @param[in] columns + * @param[in] where_clause + * @param[in] bind_params + * @param[in] order_by + * @param[in] limit + * @param[in] offset + * @return mysqlx::RowResult + * + * This can throw an exception. + * + */ + mysqlx::RowResult SessionPool::read(const std::string &schemaname, const std::string &tablename, + const std::vector &columns, + const std::string &where_clause, + const std::map &bind_params, + const std::string &order_by, + std::optional limit, + std::optional offset) { + try { + // safely get a DB session from the pool + SessionGuard session(this); + auto db = session.get(); + + auto schema = std::make_unique( *(db), schemaname ); + auto table = std::make_unique( schema->getTable( tablename ) ); + + mysqlx::TableSelect select = table->select(columns); + + if ( !where_clause.empty() ) select = select.where(where_clause); + if ( !order_by.empty() ) select = select.orderBy(order_by); + + for (const auto &[key, val] : bind_params) select.bind(key, val); + + if (limit) select = select.limit(*limit); + if (offset) select = select.offset(*offset); + + return select.execute(); + } + catch (const std::exception &e) { throw; } + } + /***** SessionPool::read ****************************************************/ + + + /***** SessionPool::get_tablenames ******************************************/ + /** + * @brief return a list of database tablenames + * @param[in] schemaname schema name + * @return list of strings + * + */ + std::list SessionPool::get_tablenames(const std::string &schemaname) { + try { + // safely get a DB session from the pool + SessionGuard session(this); + auto db = session.get(); + auto schema = std::make_unique( *(db), schemaname ); + return schema->getTableNames(); + } + catch (const std::exception &e) { throw; } + } + /***** SessionPool::get_tablenames ******************************************/ + + /***** Database::get_mysql_type *********************************************/ /** * @brief gets a string representation of the type of mysqlx value @@ -74,8 +354,9 @@ namespace Database { * @param[in] info vector of database parameters: {host,port,user,pass,schema,table} * */ - Database::Database( std::vector info ) { - this->initialize_class( info ); + Database::Database( std::vector info ) : + _dbconfigured(false), _pool(nullptr) { + initialize_class(info); } /***** Database::Database ***************************************************/ @@ -98,226 +379,292 @@ namespace Database { std::string pass, std::string schema, std::string table ) : - _dbhost( host ), _dbport( port ), _dbuser( user ), _dbpass( pass ), _dbschema( schema ), _dbtable( table ) { + _dbhost( host ), _dbport( port ), _dbuser( user ), _dbpass( pass ), _dbschema( schema ), _dbtable( table ), + _dbconfigured(false), _pool(nullptr) { - _dbconnected = false; - _dbconfigured = true; + initialize_class(); + } + /***** Database::Database ***************************************************/ - _create_connection(); // may throw exception - return; + Database::~Database() { + try { + if (_pool) _pool.reset(); + } + catch (...) { } } - /***** Database::Database ***************************************************/ /***** Database::initialize_class *******************************************/ /** - * @brief initialize database class object + * @brief initialize database class object using stored class information * @details may throw an exception on error - * @param[in] info vector of database parameters: {host,port,user,pass,schema,table} * */ - void Database::initialize_class( std::vector info ) { - std::string function = "Database::Database::initialize_class"; - _dbconfigured = false; - _dbconnected = false; // set true in _create_connection() - - if ( info.size() != 6 ) { - logwrite( function, "ERROR constructing: bad info vector. check config file" ); - throw std::invalid_argument( "constructing Database object: bad info vector. check config file" ); + void Database::initialize_class() { + try { + if (!_dbhost.empty() && !_dbuser.empty() && !_dbpass.empty() && _dbport>0) { + _dbconfigured = true; + _initialize_pool(); + } + else throw std::runtime_error("bad or missing database info"); } - + catch( const std::exception &e ) { + throw; + } + } + /***** Database::initialize_class *******************************************/ + /** + * @brief initialize database class object using supplied information + * @details may throw an exception on error + * @param[in] info vector of database parameters: {host,port,user,pass,schema,table} + * + */ + void Database::initialize_class(std::vector dbinfo) { try { - _dbhost = info.at(0); - _dbport = std::stoi( info.at(1) ); - _dbuser = info.at(2); - _dbpass = info.at(3); - _dbschema = info.at(4); - _dbtable = info.at(5); + switch ( dbinfo.size() ) { + case 6: + _dbtable = dbinfo.at(5); // optional at construction + case 5: + _dbschema = dbinfo.at(4); // optional at construction + case 4: + _dbpass = dbinfo.at(3); + _dbuser = dbinfo.at(2); + _dbport = std::stoi( dbinfo.at(1) ); + _dbhost = dbinfo.at(0); + break; + default: + throw std::invalid_argument( "bad info vector size constructing Database object" ); + } + initialize_class(); } - catch( std::exception &e ) { - std::stringstream message; - message << "ERROR constructing Database object (check config file): " << e.what(); - logwrite( function, message.str() ); - throw std::exception( e ); + catch( const std::exception &e ) { + throw; } - - _dbconfigured = true; // configured now - - _create_connection(); // may throw exception - - return; } /***** Database::initialize_class *******************************************/ - /***** Database::_create_connection *****************************************/ + /***** Database::initialize_pool ********************************************/ /** - * @brief private function to create a single mysqlx database connection - * @details The DB info comes from the class contruction. - * This function will throw an exception on error. + * @brief initialize database pool + * @details may throw an exception on error * */ - void Database::_create_connection() { - std::string function = "Database::Database::_create_connection"; - std::stringstream message; - - try { - _session = std::make_unique ( mysqlx::SessionOption::HOST, _dbhost, - mysqlx::SessionOption::PORT, _dbport, - mysqlx::SessionOption::USER, _dbuser, - mysqlx::SessionOption::PWD, _dbpass ); + void Database::_initialize_pool() { + if (!_dbconfigured) throw std::runtime_error("database not configured"); - _sessionopen = true; + // create a pool which will own all DB connections + _pool = std::make_unique(_dbhost, _dbport, _dbuser, _dbpass); + } + /***** Database::initialize_pool ********************************************/ - _schema = std::make_unique( *_session, _dbschema ); - _table = std::make_unique( _schema->getTable( _dbtable ) ); + /***** SessionPool::read ****************************************************/ + /** + * @brief read from the database + * @details may throw an exception + * @param[in] schemaname optional + * @param[in] tablename optional + * @param[in] columns + * @param[in] where_clause + * @param[in] bind_params + * @param[in] order_by + * @param[in] limit + * @param[in] offset + * @return mysqlx::RowResult + * + */ + mysqlx::RowResult Database::read(const std::vector &columns, + const std::string &where_clause, + const std::map &bind_params, + const std::string &order_by, + std::optional limit, + std::optional offset) { + if ( _dbschema.empty() || _dbtable.empty() ) throw std::runtime_error("missing schema or table"); + try { + if (!_pool) throw std::runtime_error("not connected to database"); + return _pool->read( _dbschema, _dbtable, columns, where_clause, bind_params, order_by, limit, offset ); + } + catch (const std::exception &e) { + logwrite("Database::Database::read", "ERROR reading: "+std::string(e.what())); + throw; } - catch ( const mysqlx::Error &err ) { - message << "ERROR: " << err; - logwrite( function, message.str() ); - throw mysqlx::Error( err ); + } + /***** SessionPool::read ****************************************************/ + mysqlx::RowResult Database::read(const std::string &tablename, + const std::vector &columns, + const std::string &where_clause, + const std::map &bind_params, + const std::string &order_by, + std::optional limit, + std::optional offset) { + if ( _dbschema.empty() ) throw std::runtime_error("missing schema"); + try { + if (!_pool) throw std::runtime_error("not connected to database"); + return _pool->read( _dbschema, tablename, columns, where_clause, bind_params, order_by, limit, offset ); } - catch ( std::exception &e ) { - message << "ERROR: " << e.what(); - logwrite( function, message.str() ); - throw std::exception( e ); + catch (const std::exception &e) { + logwrite("Database::Database::read", "ERROR reading: "+std::string(e.what())); + throw; } - - _dbconnected = true; - - return; } - /***** Database::_create_connection *****************************************/ + /***** SessionPool::read ****************************************************/ + mysqlx::RowResult Database::read(const std::string &schemaname, const std::string &tablename, + const std::vector &columns, + const std::string &where_clause, + const std::map &bind_params, + const std::string &order_by, + std::optional limit, + std::optional offset) { + try { + if (!_pool) throw std::runtime_error("not connected to database"); + return _pool->read( schemaname, tablename, columns, where_clause, bind_params, order_by, limit, offset ); + } + catch (const std::exception &e) { + logwrite("Database::Database::read", "ERROR reading: "+std::string(e.what())); + throw; + } + } + /***** SessionPool::read ****************************************************/ - /***** Database::close ******************************************************/ + /***** Database::insert *****************************************************/ /** - * @brief close a database connection - * @brief may throw an exception + * @brief insert the supplied data to the indicated database table + * @details may throw an exception + * @param[in] schemaname schema name (optional) + * @param[in] tablename table name (optional) + * @param[in] data STL map containing mysqlx data indexed by DB column name * */ - void Database::close() { - std::string function = "Database::Database::close"; - std::stringstream message; - + void Database::insert(const std::map &data) { + // schema or table names must come from the class + if ( _dbschema.empty() || _dbtable.empty() ) throw std::runtime_error("missing schema or table"); + insert(_dbschema, _dbtable, data); + } + /***** Database::insert *****************************************************/ + void Database::insert(const std::string &tablename, + const std::map &data) { + // schema name must come from the class + if ( _dbschema.empty() ) throw std::runtime_error("missing schema"); + insert(_dbschema, tablename, data); + } + /***** Database::insert *****************************************************/ + void Database::insert(const std::string &schemaname, const std::string &tablename, + const std::map &data) { try { - if ( _sessionopen ) _session->close(); - _sessionopen = false; - - _table.reset(); - _schema.reset(); - _session.reset(); - - _dbconnected = false; + if (!_pool) throw std::runtime_error("not connected to database"); + _pool->insert(schemaname, tablename, data); } - catch ( const mysqlx::Error &err ) { - message.str(""); message << "ERROR from mySQL: " << err; - logwrite( function, message.str() ); - throw std::runtime_error("closing database: " + std::string(err.what())); + catch (const std::exception &e) { + logwrite("Database::Database::insert", + "ERROR writing data: "+std::string(e.what())); + throw; } - - return; } - /***** Database::close ******************************************************/ + /***** Database::insert *****************************************************/ - /***** Database::~Database **************************************************/ + /***** Database::insert *****************************************************/ /** - * @brief Database class destructor - * @details connection will be automatically closed when the object is destroyed + * @brief insert the class private _data to the MySQL database + * @details may throw an exception + * This function overloads the version which accepts a map, + * by passing it the class map * */ - Database::~Database() { - // Don't want to re-throw anything on exception because no one will be catching - // it on destruction, but catch here to avoid a potential problem on destruction. - // - try { if ( _sessionopen ) _session->close(); } - catch ( const mysqlx::Error &err ) { } + void Database::insert() { + std::lock_guard lock(_data_mtx); + this->insert( this->_data ); // insert the record stored in the class, + this->_data.clear(); // then erase it. } - /***** Database::~Database **************************************************/ + /***** Database::insert *****************************************************/ - /***** Database::write ******************************************************/ + /***** Database::update *****************************************************/ /** - * @brief write the supplied data to the indicated database table - * @details may throw an exception - * @param[in] data STL map containing mysqlx data indexed by DB column name - * - * This function is overloaded by a version that writes the data stored - * in the class. + * @brief update column(s) in existing database record + * @details Gets database session from pool. Schema and Table come from + * the class. may throw an exception + * @param[in] data map of data + * @param[in] condition + * @param[in] bindings * */ - void Database::write( std::map data ) { - std::string function = "Database::Database::write"; - std::stringstream message; - - if ( ! _dbconnected || ! _session || ! _sessionopen ) { - logwrite( function, "ERROR not connected to database or session not open" ); - throw std::runtime_error( "not connected to database or session not open" ); - } - - if ( ! _table || ! _schema ) { - logwrite( function, "ERROR table or schema not initialized" ); - throw std::runtime_error( "table or schema not initialized" ); - } - - // Create vectors from the supplied STL map, pre-allocating memory for them. - // Vectors are easily passed directly to the mysqlx API. - // - int ncols = data.size(); - std::vector cols; cols.reserve( ncols ); - std::vector vals; vals.reserve( ncols ); - - for ( const auto &dat : data ) { - cols.push_back( dat.first ); // database columns - vals.push_back( dat.second ); // value for that column - } - - if ( cols.empty() || vals.empty() || cols.size() != vals.size() ) { - logwrite( function, "ERROR data empty or improperly formatted" ); - throw std::runtime_error( "data empty or improperly formatted" ); - } - - // Insert a row into the database table - // + void Database::update(const std::map &data, + const std::string &condition, + const std::map &bindings) { + // schema or table names must come from the class + if ( _dbschema.empty() || _dbtable.empty() ) throw std::runtime_error("missing schema or table"); try { - _table->insert( cols ).values( vals ).execute(); + if (!_pool) throw std::runtime_error("not connected to database"); + _pool->update(_dbschema, _dbtable, data, condition, bindings); } - catch ( const mysqlx::Error &err ) { - message.str(""); message << "ERROR from mySQL: " << err.what(); - logwrite( function, message.str() ); + catch (const std::exception &e) { + logwrite("Database::Database::get_tablenames", + "ERROR: "+std::string(e.what())); throw; } - catch ( const std::exception &err ) { - message.str(""); message << "ERROR: " << err.what(); - logwrite( function, message.str() ); - throw; + } + /***** Database::update *****************************************************/ + /** + * @brief update column(s) in existing database record + * @details Gets database session from pool. may throw an exception + * @param[in] schemaname name of schema + * @param[in] tablename name of table + * @param[in] data map of data + * @param[in] condition + * @param[in] bindings + * + */ + void Database::update(const std::string &schemaname, const std::string &tablename, + const std::map &data, + const std::string &condition, + const std::map &bindings) { + // schema or table names come from args + if ( schemaname.empty() || tablename.empty() ) throw std::runtime_error("missing schema or table"); + try { + if (!_pool) throw std::runtime_error("not connected to database"); + _pool->update(schemaname, tablename, data, condition, bindings); } - catch ( ... ) { - logwrite( function, "ERROR unknown exception" ); + catch (const std::exception &e) { + logwrite("Database::Database::get_tablenames", + "ERROR: "+std::string(e.what())); throw; } - - return; } - /***** Database::write ******************************************************/ + /***** Database::update *****************************************************/ - /***** Database::write ******************************************************/ + /***** Database::get_tablenames *********************************************/ /** - * @brief write the class private _data to the MySQL database - * @details may throw an exception - * This function overloads the version which accepts a map, - * by passing it the class map + * @brief return a list of database tablenames + * @return list of strings * */ - void Database::write() { - std::lock_guard lock(_data_mtx); - this->write( this->_data ); // Write the record stored in the class, - this->_data.clear(); // then erase it. + std::list Database::get_tablenames() { + // schema must come from the class + if ( _dbschema.empty() ) throw std::runtime_error("missing schema"); + return get_tablenames(_dbschema); } - /***** Database::write ******************************************************/ - + /***** Database::get_tablenames *********************************************/ + /** + * @brief return a list of database tablenames + * @param[in] schemaname schema name + * @return list of strings + * + */ + std::list Database::get_tablenames(const std::string &schemaname) { + try { + if (!_pool) throw std::runtime_error("not connected to database"); + return _pool->get_tablenames(schemaname); + } + catch (const std::exception &e) { + logwrite("Database::Database::get_tablenames", + "ERROR: "+std::string(e.what())); + throw; + } + } + /***** Database::get_tablenames *********************************************/ } diff --git a/utils/database.h b/utils/database.h index fcfa5920..3761aa2c 100644 --- a/utils/database.h +++ b/utils/database.h @@ -11,6 +11,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "logentry.h" @@ -21,12 +27,91 @@ */ namespace Database { + constexpr int DBPOOLSIZE = 10; + void get_mysql_type( mysqlx::Value value, std::string &type ); + /***** Database::SessionPool ************************************************/ + /** + * @class SessionPool + * @brief manages a pool of database sessions + * @details This uses a queue object to create a pool of database sessions, + * to provides for safe multi-threaded access to a MySQL database by + * returning a unique connection for each request. A mutex and + * condition variable are used for thread synchronization. A pool + * of established connections improves performance. Only the session + * is pooled; the schema and table names must be provided. + * + */ + class SessionPool { + private: + std::queue> _queue; ///< pool of database sessions is a queue + + std::shared_ptr _create_session(); /// create a single mysqlx database session + std::shared_ptr _borrow_session(int timeout_ms=5000); ///< get a session from pool + void _return_session(std::shared_ptr db); ///< return a session to pool + bool _test_session(std::shared_ptr db); ///< test a session + + // This is the minimum info needed to create a database session/connection. + std::string _dbhost; + int _dbport; + std::string _dbuser; + std::string _dbpass; + + std::mutex _mtx; ///< protects access to the pool + std::condition_variable _cv; + + /** + * @brief helper class to ensure sessions are always returned + * @details By wrapping the session pool in this class, if something + * causes the class to go out of scope, this class's destructor + * guarantees the session is returned to the pool. + */ + class SessionGuard { + private: + SessionPool* _pool; // pointer to pool to manage + std::shared_ptr _session; // borrowed database session + public: + /// borrows a session from the pool on construction + SessionGuard(SessionPool* pool) : _pool(pool), _session(pool->_borrow_session()) { } + + /// when destructed the session is returned + ~SessionGuard() { if (_session) _pool->_return_session(_session); } + + /// returns the session that was borrowed on construction + std::shared_ptr get() { return _session; } + }; + + public: + SessionPool(const std::string &host, int port, const std::string &user, const std::string &pass); + ~SessionPool(); + + void insert(const std::string &schemaname, const std::string &tablename, + const std::map &data); + + void update(const std::string &schemaname, const std::string &tablename, + const std::map &data, + const std::string &condition, + const std::map &bindings); + + mysqlx::RowResult read(const std::string &schemaname, const std::string &tablename, + const std::vector &columns, + const std::string &where_clause, + const std::map &bind_params={}, + const std::string &order_by = "", + std::optional limit = std::nullopt, + std::optional offset = std::nullopt); + + std::list get_tablenames(const std::string &schemaname); + }; + /***** Database::SessionPool ************************************************/ + + /***** Database::Database ***************************************************/ /** - * @class Database - * @brief constructs a MySQL database object + * @class Database + * @brief provides an interface to a MySQL database + * @details Makes use of SessionPool for safe multi-threaded access. * */ class Database { @@ -39,21 +124,11 @@ namespace Database { int _dbport; std::string _dbuser; std::string _dbpass; - std::string _dbschema; - std::string _dbtable; - - std::atomic _dbconfigured; - std::atomic _dbconnected; - std::atomic _sessionopen; - // For these mysqlx objects an instance cannot be directly created - // so instead create pointers. - // - std::unique_ptr _session; - std::unique_ptr _table; - std::unique_ptr _schema; + std::string _dbschema; ///< optional on construction + std::string _dbtable; ///< optional on construction - void _create_connection(); + std::atomic _dbconfigured; // These map stores in memory the record to be written to // the database. The data is essentially a variant type so @@ -63,25 +138,69 @@ namespace Database { std::mutex _data_mtx; ///< protecs _data map access + std::unique_ptr _pool; ///< this is the pool of database connections + void _initialize_pool(); + public: - Database() : _dbconfigured(false), _dbconnected(false), _sessionopen(false), - _session(nullptr), _table(nullptr), _schema(nullptr) { } + Database() : _dbconfigured(false) { } Database( std::vector info ); + // schema and table are optional at construction, + // specify both, neither, or schema only. Database( std::string host, int port, std::string user, std::string pass, - std::string schema, - std::string table ); + std::string schema="", + std::string table="" ); ~Database(); - inline bool dbconfigured() { return _dbconfigured; } - inline bool dbconnected() { return _dbconnected; } - inline bool sessionopen() { return _sessionopen; } + void initialize_class(); + void initialize_class(std::vector dbinfo); + + // read() is overloaded + mysqlx::RowResult read(const std::vector &columns, + const std::string &where_clause, + const std::map &bind_params, + const std::string &order_by = "", + std::optional limit = std::nullopt, + std::optional offset = std::nullopt); + mysqlx::RowResult read(const std::string &tablename, + const std::vector &columns, + const std::string &where_clause, + const std::map &bind_params, + const std::string &order_by = "", + std::optional limit = std::nullopt, + std::optional offset = std::nullopt); + mysqlx::RowResult read(const std::string &schemaname, const std::string &tablename, + const std::vector &columns, + const std::string &where_clause, + const std::map &bind_params={}, + const std::string &order_by = "", + std::optional limit = std::nullopt, + std::optional offset = std::nullopt); - void initialize_class( std::vector info ); - void close(); + // insert() is overloaded + void insert(); + void insert(const std::map &data); + void insert(const std::string &tablename, + const std::map &data); + void insert(const std::string &schemaname, const std::string &tablename, + const std::map &data); + + // update() is overloaded + void update(const std::map &data, + const std::string &condition, + const std::map &bindings); + void update(const std::string &schemaname, const std::string &tablename, + const std::map &data, + const std::string &condition, + const std::map &bindings); + + + // get_tablenames() is overloaded + std::list get_tablenames(); + std::list get_tablenames(const std::string &schemaname); /***** Database::Database::add_key_val **********************************/ /** @@ -133,16 +252,13 @@ namespace Database { } /***** Database::Database::add_from_json ********************************/ - void write( std::map data ); ///< write passed map - void write(); ///< write class map - /** - * @brief writes an STL map of any single type rather than mysqlx::Value + * @brief insert an STL map of any single type rather than mysqlx::Value * @param[in] data map of data of any single type, indexed by field name */ template - void write( std::map data ) { - this->write(data); + void insert( std::map data ) { + this->insert(data); } }; /***** Database::Database ***************************************************/ From f07931684534dfd70e4d3dc51da5aa9c4b4dddc7 Mon Sep 17 00:00:00 2001 From: David Hale Date: Wed, 23 Jul 2025 10:12:40 -0700 Subject: [PATCH 06/19] issue-328 * sequencer threads can throw exceptions * sequence_start waits for readout if not using frame transfer * omits virtual slit mode for CAL targets --- camerad/astrocam.cpp | 22 ++- common/camerad_commands.h | 2 +- common/common.h | 13 +- sequencerd/sequence.cpp | 374 +++++++++++++++++++++++++------------- sequencerd/sequence.h | 19 ++ 5 files changed, 296 insertions(+), 134 deletions(-) diff --git a/camerad/astrocam.cpp b/camerad/astrocam.cpp index f114d0a2..a1a6c8b0 100644 --- a/camerad/astrocam.cpp +++ b/camerad/astrocam.cpp @@ -2995,7 +2995,7 @@ namespace AstroCam { // nothing to do if the message is empty // if ( message_in.empty() ) { - logwrite( function, "ERROR empty JSON message" ); + logwrite( function, "empty JSON message" ); return ERROR; } @@ -4542,8 +4542,9 @@ logwrite(function, message.str()); // if ( args == "?" ) { retstring = CAMERAD_FRAMETRANSFER; - retstring.append( " | [ yes | no ]\n" ); + retstring.append( " | | all [ yes | no ]\n" ); retstring.append( " Set or get frame transfer mode for specified device.\n" ); + retstring.append( " If \"all\" instead of device then return yes only if all devices are yes." ); retstring.append( " If optional yes|no is omitted then current state is returned.\n" ); retstring.append( " Specify from { " ); message.str(""); @@ -4564,6 +4565,23 @@ logwrite(function, message.str()); return HELP; } + // return and-state of all cameras, + // I.E. if all are true, return true, otherwise false + // + if (args=="all") { + bool all_true = true; + for ( const auto &dev : this->devnums ) { + if ( !this->controller[dev].have_ft ) { + all_true=false; + break; + } + } + retstring = all_true ? "yes" : "no"; + message.str(""); message << (all_true?"all":"not all") << " cameras use frame transfer"; + logwrite(function, message.str()); + return NO_ERROR; + } + // Get the devnum and channel from args. // Borrow retstring temporarily to carry the state, if supplied. // diff --git a/common/camerad_commands.h b/common/camerad_commands.h index 8399e07f..2411bdc7 100644 --- a/common/camerad_commands.h +++ b/common/camerad_commands.h @@ -61,7 +61,7 @@ const std::vector CAMERAD_SYNTAX = { CAMERAD_EXPTIME+" [ ]", CAMERAD_FITSNAME, CAMERAD_FITSNAMING+" [ time | number ]", - CAMERAD_FRAMETRANSFER+" ? | | [ yes | no ]", + CAMERAD_FRAMETRANSFER+" ? | | | all [ yes | no ]", CAMERAD_GEOMETRY+" ? | | [ | ]", CAMERAD_IMDIR+" [ ]", CAMERAD_IMNUM, diff --git a/common/common.h b/common/common.h index b65669af..aa9a91c7 100644 --- a/common/common.h +++ b/common/common.h @@ -677,11 +677,11 @@ namespace Common { this->keydb[key].keycomment = comment; #ifdef LOGLEVEL_DEBUG - std::string function = "Common::FitsKeys::addkey"; - std::stringstream message; - message << "[DEBUG] added key " << key << "=" << value << " (" << this->keydb[key].keytype << ") // " << comment - << " type_in=" << type_in << " resolved type=" << type; - logwrite( function, message.str() ); +// std::string function = "Common::FitsKeys::addkey"; +// std::stringstream message; +// message << "[DEBUG] added key " << key << "=" << value << " (" << this->keydb[key].keytype << ") // " << comment +// << " type_in=" << type_in << " resolved type=" << type; +// logwrite( function, message.str() ); #endif return( NO_ERROR ); } @@ -979,6 +979,9 @@ namespace Common { logwrite( function, message.str() ); } } + catch( const nlohmann::json::out_of_range &e ) { + logwrite( function, std::string(e.what()) ); + } catch( const std::exception &e ) { message.str(""); message << "ERROR adding keyword " << keyname << ": " << e.what(); logwrite( function, message.str() ); diff --git a/sequencerd/sequence.cpp b/sequencerd/sequence.cpp index f8312389..adc983cd 100644 --- a/sequencerd/sequence.cpp +++ b/sequencerd/sequence.cpp @@ -506,11 +506,12 @@ namespace Sequencer { // worker_threads = { { THR_MOVE_TO_TARGET, std::bind(&Sequence::move_to_target, this) }, { THR_CAMERA_SET, std::bind(&Sequence::camera_set, this) }, - { THR_SLIT_SET, std::bind(&Sequence::slit_set, this, - Sequencer::VSM_ACQUIRE) }, { THR_FOCUS_SET, std::bind(&Sequence::focus_set, this) }, { THR_FLEXURE_SET, std::bind(&Sequence::flexure_set, this) }, - { THR_CALIB_SET, std::bind(&Sequence::calib_set, this) } + { THR_CALIB_SET, std::bind(&Sequence::calib_set, this) }, + // for CAL targets, slit comes from database, otherwise use VSM acquire position + { THR_SLIT_SET, std::bind(&Sequence::slit_set, this, + this->target.iscal ? Sequencer::VSM_DATABASE : Sequencer::VSM_ACQUIRE) } }; } @@ -593,17 +594,17 @@ namespace Sequencer { this->is_usercontinue.store(false); this->async.enqueue_and_log( function, "NOTICE: received USER continue signal!" ); - } - // Ensure slit offset is in "expose" position - // - auto slitset = std::async(std::launch::async, &Sequence::slit_set, this, Sequencer::VSM_EXPOSE); - try { - error |= slitset.get(); - } - catch (const std::exception& e) { - logwrite( function, "ERROR slit offset exception: "+std::string(e.what()) ); - return; + // Ensure slit offset is in "expose" position + // + auto slitset = std::async(std::launch::async, &Sequence::slit_set, this, Sequencer::VSM_EXPOSE); + try { + error |= slitset.get(); + } + catch (const std::exception& e) { + logwrite( function, "ERROR slit offset exception: "+std::string(e.what()) ); + return; + } } logwrite( function, "starting exposure" ); ///< TODO @todo log to telemetry! @@ -647,6 +648,16 @@ namespace Sequencer { << " id " << this->target.obsid << " order " << this->target.obsorder; logwrite( function, message.str() ); + // If not using frame transfer then wait for readout, too + // + if (!this->is_science_frame_transfer) { + logwrite( function, "waiting for readout" ); + while ( !this->cancel_flag.load() && wait_state_manager.is_set( Sequencer::SEQ_WAIT_READOUT ) ) { + std::unique_lock lock(cv_mutex); + this->cv.wait( lock, [this]() { return( !wait_state_manager.is_set(SEQ_WAIT_READOUT) || this->cancel_flag.load() ); } ); + } + } + // Now that we're done waiting, check for errors or abort // if ( this->thread_error_manager.are_any_set() ) { @@ -700,7 +711,8 @@ namespace Sequencer { /***** Sequencer::Sequence::camera_set **************************************/ /** * @brief sets the camera according to the parameters in the target entry - * @return ERROR | NO_ERROR + * @return NO_ERROR + * @throws std::runtime_error * * At the moment, this is only exposure time. * @@ -716,6 +728,8 @@ namespace Sequencer { ScopedState thr_state( thread_state_manager, Sequencer::THR_CAMERA_SET ); ScopedState wait_state( wait_state_manager, Sequencer::SEQ_WAIT_CAMERA ); + this->thread_error_manager.set( THR_CAMERA_SET ); // assume the worse, clear on success + // send the EXPTIME command to camerad // // Everywhere is maintained that exptime is specified in sec except @@ -723,23 +737,29 @@ namespace Sequencer { // long exptime_msec = (long)( this->target.exptime_req * 1000 ); camcmd.str(""); camcmd << CAMERAD_EXPTIME << " " << exptime_msec; - error |= this->camerad.send( camcmd.str(), reply ); + if (error==NO_ERROR && (error=this->camerad.send( camcmd.str(), reply ))!=NO_ERROR) { + this->async.enqueue_and_log( function, "ERROR sending \""+camcmd.str()+"\": "+reply ); + throw std::runtime_error( "camera returned "+reply ); + } // send binning parameters // this is only good for I/R and will have to change to be more general // because not all detectors will be oriented the same! // camcmd.str(""); camcmd << CAMERAD_BIN << " row " << this->target.binspat; - error |= this->camerad.send( camcmd.str(), reply ); + if (error==NO_ERROR && (error=this->camerad.send( camcmd.str(), reply ))!=NO_ERROR) { + this->async.enqueue_and_log( function, "ERROR sending \""+camcmd.str()+"\": "+reply ); + throw std::runtime_error( "camera returned "+reply ); + } camcmd.str(""); camcmd << CAMERAD_BIN << " col " << this->target.binspect; - error |= this->camerad.send( camcmd.str(), reply ); - - if ( error != NO_ERROR ) { - this->async.enqueue_and_log( function, "ERROR setting camera" ); - this->thread_error_manager.set( THR_CAMERA_SET ); + if (error==NO_ERROR && (error=this->camerad.send( camcmd.str(), reply ))!=NO_ERROR) { + this->async.enqueue_and_log( function, "ERROR sending \""+camcmd.str()+"\": "+reply ); + throw std::runtime_error( "camera returned "+reply ); } - return error; + this->thread_error_manager.clear( THR_CAMERA_SET ); // success + + return NO_ERROR; } /***** Sequencer::Sequence::camera_set **************************************/ @@ -750,7 +770,8 @@ namespace Sequencer { * @details Slit width is always set according to the value in the target * database entry, offset set according to mode. * @param[in] mode selects source of slit offset - * @return ERROR | NO_ERROR + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::slit_set(VirtualSlitMode mode) { @@ -790,7 +811,7 @@ namespace Sequencer { if ( this->slitd.command_timeout( slitcmd.str(), reply, SLITD_SET_TIMEOUT ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR setting slit" ); this->thread_error_manager.set( THR_SLIT_SET ); - return ERROR; + throw std::runtime_error("slit returned: "+reply); } return NO_ERROR; @@ -801,7 +822,8 @@ namespace Sequencer { /***** Sequencer::Sequence::power_init **************************************/ /** * @brief initializes the power system for control from the Sequencer - * @return ERROR | NO_ERROR + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::power_init() { @@ -814,7 +836,7 @@ namespace Sequencer { if ( this->reopen_hardware(this->powerd, POWERD_REOPEN, 10000 ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR initializing power control" ); - return ERROR; + throw std::runtime_error("could not initialize power control"); } this->daemon_manager.set( Sequencer::DAEMON_POWER ); // powerd ready @@ -828,6 +850,7 @@ namespace Sequencer { /** * @brief disconnects from powerd * @details There's nothing with powerd that needs to be shut down. + * @return NO_ERROR * */ long Sequence::power_shutdown() { @@ -849,7 +872,8 @@ namespace Sequencer { /***** Sequencer::Sequence::slit_init ***************************************/ /** * @brief initializes the slit for control from the Sequencer - * @return ERROR | NO_ERROR + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::slit_init() { @@ -860,15 +884,17 @@ namespace Sequencer { this->daemon_manager.clear( Sequencer::DAEMON_SLIT ); // slitd not ready + this->thread_error_manager.set( THR_SLIT_INIT ); // assume the worst, clear on success + if ( this->set_power_switch(ON, POWER_SLIT, std::chrono::seconds(5)) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR powering slit hardware" ); - return ERROR; + throw std::runtime_error("could not power slit hardware"); } bool was_opened=false; if ( this->open_hardware(this->slitd, was_opened) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR connecting to slit" ); - return ERROR; + throw std::runtime_error("could not open connection to slit hardware"); } // Ask slitd if the slit motors are homed, @@ -877,7 +903,7 @@ namespace Sequencer { std::string reply; if ( this->slitd.command( SLITD_ISHOME, reply ) ) { this->async.enqueue_and_log( function, "ERROR communicating with slit hardware" ); - return ERROR; + throw std::runtime_error("could not communicate with slit hardware: "+reply); } this->parse_state( function, reply, ishomed ); @@ -887,7 +913,7 @@ namespace Sequencer { logwrite( function, "sending home command" ); if ( this->slitd.command_timeout( SLITD_HOME, reply, SLITD_HOME_TIMEOUT ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR communicating with slit hardware" ); - return ERROR; + throw std::runtime_error("could not home slit hardware: "+reply); } } @@ -897,10 +923,11 @@ namespace Sequencer { std::string cmd = SLITD_SET+" "+this->config_init["SLIT"]; if ( this->slitd.command_timeout( cmd, reply, SLITD_SET_TIMEOUT ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR sending \""+cmd+"\" to slit" ); - return ERROR; + throw std::runtime_error("slit "+cmd+" returned: "+reply); } } + this->thread_error_manager.clear( THR_SLIT_INIT ); // success this->daemon_manager.set( Sequencer::DAEMON_SLIT ); // slitd ready return NO_ERROR; @@ -911,6 +938,8 @@ namespace Sequencer { /***** Sequencer::Sequence::slit_shutdown ***********************************/ /** * @brief shuts down the slit system + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::slit_shutdown() { @@ -923,12 +952,14 @@ namespace Sequencer { ScopedState wait_state( this->wait_state_manager, Sequencer::SEQ_WAIT_SLIT ); ScopedState daemon_state( this->daemon_manager, Sequencer::DAEMON_SLIT ); + this->thread_error_manager.set( THR_SLIT_SHUTDOWN ); // assume the worst, clear on success + // already off? // bool poweron=false; if ( check_power_switch(ON, POWER_SLIT, poweron ) != NO_ERROR ) { logwrite( function, "ERROR checking power switch" ); - return ERROR; + throw std::runtime_error("checking slit power switch"); } // if already off then get out now, don't turn them back on @@ -946,7 +977,7 @@ namespace Sequencer { std::string cmd = SLITD_SET+" "+this->config_shutdown["SLIT"]; if ( this->slitd.command_timeout( cmd, reply, SLITD_SET_TIMEOUT ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR sending \""+cmd+"\" to slit" ); - return ERROR; + throw std::runtime_error(cmd+" returned: "+reply); } } @@ -954,13 +985,18 @@ namespace Sequencer { // logwrite( function, "closing slit hardware" ); error = this->slitd.command( SLITD_CLOSE, reply ); - if ( error != NO_ERROR ) this->async.enqueue_and_log( function, "ERROR closing connection to slit hardware" ); + if ( error != NO_ERROR ) { + this->async.enqueue_and_log( function, "ERROR closing connection to slit hardware" ); + throw std::runtime_error("closing slit connection returned: "+reply); + } // disconnect me from slitd, irrespective of any previous error // logwrite( function, "disconnecting from slitd" ); this->slitd.disconnect(); + this->thread_error_manager.clear( THR_SLIT_SHUTDOWN ); // success + return NO_ERROR; } /***** Sequencer::Sequence::slit_shutdown ***********************************/ @@ -969,7 +1005,8 @@ namespace Sequencer { /***** Sequencer::Sequence::slicecam_init ***********************************/ /** * @brief initializes the slicecam system for control from the Sequencer - * @return ERROR | NO_ERROR + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::slicecam_init() { @@ -980,21 +1017,24 @@ namespace Sequencer { ScopedState thr_state( thread_state_manager, Sequencer::THR_SLICECAM_INIT ); ScopedState wait_state( wait_state_manager, Sequencer::SEQ_WAIT_SLICECAM ); + this->thread_error_manager.set( THR_SLICECAM_INIT ); // assume the worst, clear on success + // make sure hardware is powered on // if ( this->set_power_switch(ON, POWER_SLICECAM, std::chrono::seconds(10)) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR initializing slicecam control" ); - return ERROR; + throw std::runtime_error("could not power slicecam hardware"); } // open connection is all that is needed, slicecamd takes care of everything // if ( this->open_hardware(this->slicecamd, SLICECAMD_OPEN, SLICECAMD_OPEN_TIMEOUT) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR starting slicecam" ); - return ERROR; + throw std::runtime_error("could not start slicecam"); } - this->daemon_manager.set( Sequencer::DAEMON_SLICECAM ); // slicecamd ready + this->daemon_manager.set( Sequencer::DAEMON_SLICECAM ); // slicecamd ready + this->thread_error_manager.clear( THR_SLICECAM_INIT ); // success return NO_ERROR; } @@ -1004,7 +1044,8 @@ namespace Sequencer { /***** Sequencer::Sequence::acam_init ***************************************/ /** * @brief initializes the slicecam system for control from the Sequencer - * @return ERROR | NO_ERROR + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::acam_init() { @@ -1015,11 +1056,13 @@ namespace Sequencer { ScopedState thr_state( thread_state_manager, Sequencer::THR_ACAM_INIT ); ScopedState wait_state( wait_state_manager, Sequencer::SEQ_WAIT_ACAM ); + this->thread_error_manager.set( THR_ACAM_INIT ); // assume the worst, clear on success + // make sure hardware is powered on // if ( this->set_power_switch(ON, POWER_ACAM, std::chrono::seconds(10)) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR powering acam hardware" ); - return ERROR; + throw std::runtime_error("could not power acam hardware"); } // open connection is all that is needed, acamd takes care of everything @@ -1027,7 +1070,7 @@ namespace Sequencer { bool was_opened=false; if ( this->open_hardware(this->acamd, ACAMD_OPEN, ACAMD_OPEN_TIMEOUT, was_opened) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR starting acam" ); - return ERROR; + throw std::runtime_error("could not start acam"); } // send init values only if connection was just opened now @@ -1038,18 +1081,19 @@ namespace Sequencer { cmd = ACAMD_FILTER+" "+this->config_init["ACAM_FILTER"]; if ( this->acamd.command_timeout( cmd, reply, ACAMD_MOVE_TIMEOUT ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR sending \""+cmd+"\" to acamd: "+reply ); - return ERROR; + throw std::runtime_error("acam "+cmd+" returned: "+reply); } } if ( ! this->config_init["ACAM_COVER"].empty() ) { cmd = ACAMD_COVER+" "+this->config_init["ACAM_COVER"]; if ( this->acamd.command_timeout( cmd, reply, ACAMD_MOVE_TIMEOUT ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR sending \""+cmd+"\" to acamd: "+reply ); - return ERROR; + throw std::runtime_error("acam "+cmd+" returned: "+reply); } } } + this->thread_error_manager.clear( THR_ACAM_INIT ); // success this->daemon_manager.set( Sequencer::DAEMON_ACAM ); // acamd ready return NO_ERROR; @@ -1060,6 +1104,8 @@ namespace Sequencer { /***** Sequencer::Sequence::slicecam_shutdown *******************************/ /** * @brief shuts down the slicecam system + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::slicecam_shutdown() { @@ -1072,12 +1118,14 @@ namespace Sequencer { ScopedState wait_state( this->wait_state_manager, Sequencer::SEQ_WAIT_SLICECAM ); ScopedState daemon_state( this->daemon_manager, Sequencer::DAEMON_SLICECAM ); + this->thread_error_manager.set( THR_SLICECAM_SHUTDOWN ); // assume the worst, clear on success + // already off? // bool poweron=false; if ( check_power_switch(ON, POWER_SLICECAM, poweron ) != NO_ERROR ) { logwrite( function, "ERROR checking power switch" ); - return ERROR; + throw std::runtime_error("checking slicecam power switch"); } // if already off then get out now, don't turn them back on @@ -1087,13 +1135,16 @@ namespace Sequencer { return NO_ERROR; } - if ( this->connect_to_daemon(this->slicecamd) != NO_ERROR ) return ERROR; + if ( (error=this->connect_to_daemon(this->slicecamd)) != NO_ERROR ) { + this->async.enqueue_and_log(function, "ERROR connecting to slicecamd"); + } // close connections between slicecamd and the hardware with which it communicates // logwrite( function, "closing slicecam hardware" ); - error = this->slicecamd.command_timeout( SLICECAMD_SHUTDOWN, reply, SLICECAMD_SHUTDOWN_TIMEOUT ); - if ( error != NO_ERROR ) this->async.enqueue_and_log( function, "ERROR closing connection to slicecam hardware" ); + if ( (error=this->slicecamd.command_timeout( SLICECAMD_SHUTDOWN, reply, SLICECAMD_SHUTDOWN_TIMEOUT )) != NO_ERROR ) { + this->async.enqueue_and_log( function, "ERROR closing connection to slicecam hardware" ); + } // disconnect me from slicecamd, irrespective of any previous error // @@ -1104,9 +1155,10 @@ namespace Sequencer { // if ( this->set_power_switch(OFF, POWER_SLICECAM, std::chrono::seconds(0)) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR switching off slicecam" ); - error=ERROR; + throw std::runtime_error("could not power off slicecam hardware"); } + this->thread_error_manager.clear( THR_SLICECAM_SHUTDOWN ); // success return NO_ERROR; } /***** Sequencer::Sequence::slicecam_shutdown *******************************/ @@ -1115,6 +1167,8 @@ namespace Sequencer { /***** Sequencer::Sequence::acam_shutdown ***********************************/ /** * @brief shuts down the acam system + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::acam_shutdown() { @@ -1127,6 +1181,8 @@ namespace Sequencer { ScopedState wait_state( this->wait_state_manager, Sequencer::SEQ_WAIT_ACAM ); ScopedState daemon_state( this->daemon_manager, Sequencer::DAEMON_ACAM ); + this->thread_error_manager.set( THR_ACAM_SHUTDOWN ); // assume the worst, clear on success + // ensure a connection to the daemon // error = this->connect_to_daemon(this->acamd); @@ -1139,20 +1195,21 @@ namespace Sequencer { cmd = ACAMD_FILTER+" "+this->config_shutdown["ACAM_FILTER"]; if ( this->acamd.command_timeout( cmd, reply, ACAMD_MOVE_TIMEOUT ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR sending \""+cmd+"\" to acamd: "+reply ); - return ERROR; + throw std::runtime_error("acam "+cmd+" returned: "+reply); } } if ( ! this->config_shutdown["ACAM_COVER"].empty() ) { cmd = ACAMD_COVER+" "+this->config_shutdown["ACAM_COVER"]; if ( this->acamd.command_timeout( cmd, reply, ACAMD_MOVE_TIMEOUT ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR sending \""+cmd+"\" to acamd: "+reply ); - return ERROR; + throw std::runtime_error("acam "+cmd+" returned: "+reply); } } } // send ACAMD_SHUTDOWN command to acamd -- this will cause it to nicely // close connections between acamd and the hardware with which it communicates + // Don't throw here, okay to turn off power if close fails. // if ( error==NO_ERROR ) { logwrite( function, "closing acam hardware" ); @@ -1166,18 +1223,15 @@ namespace Sequencer { this->acamd.disconnect(); // Turn off power to acam hardware. - // Any error here is added to thread_error_manager. // if ( this->set_power_switch(OFF, POWER_ACAM, std::chrono::seconds(0)) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR switching off acam" ); - error=ERROR; + throw std::runtime_error("could not switch off acam"); } - // set this thread's error status - // - if (error!=NO_ERROR) this->thread_error_manager.set( THR_ACAM_SHUTDOWN ); + this->thread_error_manager.clear( THR_ACAM_SHUTDOWN ); // success - return error; + return NO_ERROR; } /***** Sequencer::Sequence::acam_shutdown ***********************************/ @@ -1185,7 +1239,8 @@ namespace Sequencer { /***** Sequencer::Sequence::calib_init **************************************/ /** * @brief initializes the calibrator system for control from the Sequencer - * @return ERROR | NO_ERROR + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::calib_init() { @@ -1196,18 +1251,19 @@ namespace Sequencer { ScopedState thr_state( thread_state_manager, Sequencer::THR_CALIB_INIT ); ScopedState wait_state( wait_state_manager, Sequencer::SEQ_WAIT_CALIB ); + this->thread_error_manager.set( THR_CALIB_INIT ); // assume the worst, clear on success + // make sure calib hardware is powered if ( this->set_power_switch(ON, POWER_CALIB, std::chrono::seconds(5)) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR powering focus control" ); - return ERROR; + throw std::runtime_error("could not power focus control"); } // connect to calibd bool was_opened=false; if ( this->open_hardware(this->calibd, was_opened) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR initializing calib control" ); - this->thread_error_manager.set( THR_CALIB_INIT ); - return ERROR; + throw std::runtime_error("could not power calib control"); } // if calibd was just opened, home if needed, @@ -1219,14 +1275,14 @@ namespace Sequencer { long error = this->calibd.command( CALIBD_ISHOME, reply ); if ( error!=NO_ERROR || this->parse_state( function, reply, ishomed ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR communicating with calib hardware" ); - return ERROR; + throw std::runtime_error("could not communicate with calib hardware: "+reply); } // home calib actuators if not already homed if ( !ishomed ) { logwrite( function, "sending home command" ); if ( this->calibd.command_timeout( CALIBD_HOME, reply, CALIBD_HOME_TIMEOUT ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR communicating with calib hardware" ); - return ERROR; + throw std::runtime_error("could not communicate with calib hardware: "+reply); } } // set init values @@ -1239,7 +1295,7 @@ namespace Sequencer { logwrite( function, "calib default: "+cmd.str() ); if ( this->calibd.command_timeout( cmd.str(), CALIBD_SET_TIMEOUT ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR moving calib door and/or cover" ); - return ERROR; + throw std::runtime_error("could not move calib door and/or cover"); } } } @@ -1247,6 +1303,8 @@ namespace Sequencer { // calibd is ready this->daemon_manager.set( Sequencer::DAEMON_CALIB ); + this->thread_error_manager.clear( THR_CALIB_INIT ); + return NO_ERROR; } /***** Sequencer::Sequence::calib_init **************************************/ @@ -1255,6 +1313,8 @@ namespace Sequencer { /***** Sequencer::Sequence::calib_shutdown **********************************/ /** * @brief shuts down the calibrator system + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::calib_shutdown() { @@ -1265,12 +1325,14 @@ namespace Sequencer { ScopedState wait_state( this->wait_state_manager, Sequencer::SEQ_WAIT_CALIB ); ScopedState daemon_state( this->daemon_manager, Sequencer::DAEMON_CALIB ); + this->thread_error_manager.set( THR_CALIB_SHUTDOWN ); // assume the worst, clear on success + // is calib hardware powered? // bool poweron=false; if ( check_power_switch(ON, POWER_CALIB, poweron ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR checking calib power switch" ); - error=ERROR; + throw std::runtime_error("checking calib power switch"); } // ensure a connection to the daemon @@ -1288,12 +1350,13 @@ namespace Sequencer { logwrite( function, "calib default: "+cmd.str() ); if ( this->calibd.command_timeout( cmd.str(), CALIBD_SET_TIMEOUT ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR moving calib door and/or cover" ); - error=ERROR; + throw std::runtime_error("moving calib door and/or cover"); } } } // close connections between calibd and the hardware with which it communicates + // no throw here, okay to turn off power if this fails // if ( error==NO_ERROR ) { std::string reply; @@ -1323,9 +1386,13 @@ namespace Sequencer { // set this thread's error status // - if (error!=NO_ERROR) this->thread_error_manager.set( THR_CALIB_SHUTDOWN ); + if (error!=NO_ERROR) { + this->thread_error_manager.set( THR_CALIB_SHUTDOWN ); + throw std::runtime_error("shutting down calib control"); + } - return error; + this->thread_error_manager.clear( THR_CALIB_SHUTDOWN ); // success + return NO_ERROR; } /***** Sequencer::Sequence::calib_shutdown **********************************/ @@ -1336,7 +1403,8 @@ namespace Sequencer { * @details This opens a connection to tcsd, then instructs tcsd to open * a connection to the TCS. The default TCS is opened, as specified * in the tcsd config file. - * @return ERROR | NO_ERROR + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::tcs_init() { @@ -1348,7 +1416,7 @@ namespace Sequencer { if ( this->open_hardware(this->tcsd) != NO_ERROR ) { this->async.enqueue_and_log( "Sequencer::Sequence::tcs_init", "ERROR initializing TCS" ); this->thread_error_manager.set( THR_TCS_INIT ); - return ERROR; + throw std::runtime_error("could not initialize TCS"); } ///< @TODO Use a long 300 s timeout here until I implement a better way. @@ -1367,6 +1435,8 @@ namespace Sequencer { /***** Sequencer::Sequence::tcs_shutdown ************************************/ /** * @brief shuts down the tcs connection + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::tcs_shutdown() { @@ -1387,8 +1457,12 @@ namespace Sequencer { logwrite( function, "closing connection to TCS" ); std::string reply; error = this->tcsd.send( TCSD_CLOSE, reply ); - if ( error != NO_ERROR ) this->async.enqueue_and_log( function, "ERROR: closing connection to TCS" ); + if ( error != NO_ERROR ) { + this->async.enqueue_and_log( function, "ERROR: closing connection to TCS" ); + throw std::runtime_error("closing TCS connection: "+reply); + } } + else throw std::runtime_error("no connection to TCS daemon"); // disconnect me from tcsd, irrespective of any previous error // @@ -1403,7 +1477,8 @@ namespace Sequencer { /***** Sequencer::Sequence::flexure_init ************************************/ /** * @brief initializes the flexure system for control from the Sequencer - * @return ERROR | NO_ERROR + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::flexure_init() { @@ -1418,12 +1493,14 @@ namespace Sequencer { // if ( this->set_power_switch(ON, POWER_FLEXURE, std::chrono::seconds(21)) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR powering flexure control" ); - return ERROR; + this->thread_error_manager.set( THR_FLEXURE_INIT ); + throw std::runtime_error("could not power flexure control"); } if ( this->open_hardware(this->flexured) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR initializing flexure control" ); - return ERROR; + this->thread_error_manager.set( THR_FLEXURE_INIT ); + throw std::runtime_error("could not initialize flexure control"); } // default actuator positions are defined in ~/Software/Config/flexured.cfg @@ -1439,6 +1516,8 @@ namespace Sequencer { /***** Sequencer::Sequence::flexure_shutdown ********************************/ /** * @brief shuts down the flexure system + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::flexure_shutdown() { @@ -1455,7 +1534,7 @@ namespace Sequencer { bool poweron=false; if ( check_power_switch(ON, POWER_FLEXURE, poweron ) != NO_ERROR ) { logwrite( function, "ERROR checking power switch" ); - return ERROR; + throw std::runtime_error("checking flexure power switch"); } // if already off then get out now, don't turn them back on @@ -1465,13 +1544,18 @@ namespace Sequencer { return NO_ERROR; } - if ( this->connect_to_daemon(this->flexured) != NO_ERROR ) return ERROR; + if ( this->connect_to_daemon(this->flexured) != NO_ERROR ) { + this->async.enqueue_and_log( function, "ERROR connecting to flexure hardware" ); + error=ERROR; + } // close connections between flexured and the hardware with which it communicates + // don't throw here, okay to shut off power if this fails // logwrite( function, "closing flexure hardware" ); - error = this->flexured.command( FLEXURED_CLOSE, reply ); - if ( error != NO_ERROR ) this->async.enqueue_and_log( function, "ERROR: closing connection to flexure hardware" ); + if (error==NO_ERROR && (error=this->flexured.command( FLEXURED_CLOSE, reply )) != NO_ERROR) { + this->async.enqueue_and_log( function, "ERROR closing connection to flexure hardware" ); + } // disconnect me from flexured, irrespective of any previous error // @@ -1482,7 +1566,7 @@ namespace Sequencer { // if ( this->set_power_switch(OFF, POWER_FLEXURE, std::chrono::seconds(0)) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR switching off flexure" ); - error=ERROR; + throw std::runtime_error("switching off flexure hardware"); } return NO_ERROR; @@ -1493,7 +1577,8 @@ namespace Sequencer { /***** Sequencer::Sequence::focus_init **************************************/ /** * @brief initializes the focus system for control from the Sequencer - * @return ERROR | NO_ERROR + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::focus_init() { @@ -1504,17 +1589,18 @@ namespace Sequencer { this->daemon_manager.clear( Sequencer::DAEMON_FOCUS ); // focusd not ready + this->thread_error_manager.set( THR_FOCUS_INIT ); // assume failure, clear on success + if ( this->set_power_switch(ON, POWER_FOCUS, std::chrono::seconds(5)) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR powering focus control" ); - return ERROR; + throw std::runtime_error("could not power focus control"); } // connect to focusd bool was_opened=false; if ( this->open_hardware(this->focusd, was_opened) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR initializing focus control" ); - this->thread_error_manager.set( THR_FOCUS_INIT ); - return ERROR; + throw std::runtime_error("could not open focus hardware"); } // if focusd was just opened, home if needed, @@ -1526,14 +1612,14 @@ namespace Sequencer { long error = this->focusd.command( FOCUSD_ISHOME, reply ); if ( error!=NO_ERROR || this->parse_state( function, reply, ishomed ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR communicating with focus hardware" ); - return ERROR; + throw std::runtime_error("focus "+FOCUSD_ISHOME+" returned: "+reply); } // home focus actuators if not already homed if ( !ishomed ) { logwrite( function, "sending home command" ); if ( this->focusd.command_timeout( FOCUSD_HOME, reply, FOCUSD_HOME_TIMEOUT ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR communicating with focus hardware" ); - return ERROR; + throw std::runtime_error("focus "+FOCUSD_HOME+" returned: "+reply); } } // send actuators to nominal positions @@ -1543,11 +1629,12 @@ namespace Sequencer { std::string command = "set " + chan + " nominal"; if ( this->focusd.command_timeout( command, reply, FOCUSD_SET_TIMEOUT ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR setting focus "+chan ); - return ERROR; + throw std::runtime_error("focus "+command+" returned: "+reply); } } } + this->thread_error_manager.clear( THR_FOCUS_INIT ); // success this->daemon_manager.set( Sequencer::DAEMON_FOCUS ); // focusd is ready return NO_ERROR; @@ -1558,10 +1645,14 @@ namespace Sequencer { /***** Sequencer::Sequence::focus_shutdown **********************************/ /** * @brief shuts down the focus system + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::focus_shutdown() { const std::string function("Sequencer::Sequence::focus_shutdown"); + std::string reply; + long error=NO_ERROR; ScopedState thr_state( this->thread_state_manager, Sequencer::THR_FOCUS_SHUTDOWN ); ScopedState wait_state( this->wait_state_manager, Sequencer::SEQ_WAIT_FOCUS ); @@ -1572,7 +1663,7 @@ namespace Sequencer { bool poweron=false; if ( check_power_switch(ON, POWER_FOCUS, poweron ) != NO_ERROR ) { logwrite( function, "ERROR checking power switch" ); - return ERROR; + throw std::runtime_error("checking focus power switch"); } // if already off then get out now, don't turn them back on @@ -1582,20 +1673,31 @@ namespace Sequencer { return NO_ERROR; } - if ( this->connect_to_daemon(this->focusd) != NO_ERROR ) return ERROR; + if ( this->connect_to_daemon(this->focusd) != NO_ERROR ) { + this->async.enqueue_and_log( function, "ERROR connecting to focus hardware" ); + error=ERROR; + } // close connections between focusd and the hardware with which it communicates + // don't throw here, okay to shut off power if this fails // logwrite( function, "closing focus hardware" ); - std::string reply; - long error = this->focusd.command( FOCUSD_CLOSE, reply ); - if ( error != NO_ERROR ) this->async.enqueue_and_log( function, "ERROR closing connection to focus hardware" ); + if (error==NO_ERROR && (error=this->focusd.command( FOCUSD_CLOSE, reply )) != NO_ERROR) { + this->async.enqueue_and_log( function, "ERROR closing connection to focus hardware" ); + } // disconnect me from focusd, irrespective of any previous error // logwrite( function, "disconnecting from focusd" ); this->focusd.disconnect(); + // Turn off power to focus hardware. + // + if ( this->set_power_switch(OFF, POWER_FOCUS, std::chrono::seconds(0)) != NO_ERROR ) { + this->async.enqueue_and_log( function, "ERROR switching off focus" ); + throw std::runtime_error("switching off focus hardware"); + } + return NO_ERROR; } /***** Sequencer::Sequence::focus_shutdown **********************************/ @@ -1604,7 +1706,8 @@ namespace Sequencer { /***** Sequencer::Sequence::camera_init *************************************/ /** * @brief initializes the camera system for control from the Sequencer - * @return ERROR | NO_ERROR + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::camera_init() { @@ -1614,32 +1717,39 @@ namespace Sequencer { ScopedState wait_state( wait_state_manager, Sequencer::SEQ_WAIT_CAMERA ); this->daemon_manager.clear( Sequencer::DAEMON_CAMERA ); // camerad not ready + this->thread_error_manager.set( THR_CAMERA_INIT ); // assume failure, clear on success // make sure hardware is powered on // if ( this->set_power_switch(ON, POWER_CAMERA, std::chrono::seconds(5)) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR powering camera" ); - return ERROR; + throw std::runtime_error("switching on camera"); } bool was_opened=false; if ( this->open_hardware(this->camerad, "open", 12000, was_opened) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR initializing camera" ); - return ERROR; + throw std::runtime_error("initializing camera"); } // send all of the prologue commands only if camera was just opened now // + std::string reply; if ( was_opened) { - std::string reply; for ( const auto &cmd : this->camera_prologue ) { if ( this->camerad.command_timeout( cmd, reply, CAMERA_PROLOG_TIMEOUT ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR sending \""+cmd+"\" to camera" ); - return ERROR; + throw std::runtime_error("sending \""+cmd+"\" to camera"); } } } + // Ask if all devices use frame transfer + // + this->camerad.send( CAMERAD_FRAMETRANSFER+" all", reply ); + this->is_science_frame_transfer = ( reply.find("yes") != std::string::npos ); + + this->thread_error_manager.clear( THR_CAMERA_INIT ); // success this->daemon_manager.set( Sequencer::DAEMON_CAMERA ); // camerad ready return NO_ERROR; @@ -1650,6 +1760,8 @@ namespace Sequencer { /***** Sequencer::Sequence::camera_shutdown *********************************/ /** * @brief shuts down the camera system from the Sequencer + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::camera_shutdown() { @@ -1659,12 +1771,14 @@ namespace Sequencer { ScopedState wait_state( this->wait_state_manager, Sequencer::SEQ_WAIT_CAMERA ); ScopedState daemon_state( this->daemon_manager, Sequencer::DAEMON_CAMERA ); + this->thread_error_manager.set( THR_CAMERA_SHUTDOWN ); // assume failure, clear on success + // Are any cameras on? // bool poweron=false; if ( check_power_switch(ON, POWER_CAMERA, poweron ) != NO_ERROR ) { logwrite( function, "ERROR checking power switch" ); - return ERROR; + throw std::runtime_error("checking camera power switch"); } // if already off then get out now, don't turn them back on @@ -1678,7 +1792,7 @@ namespace Sequencer { // if ( this->open_hardware(this->camerad, CAMERAD_OPEN, CAMERAD_OPEN_TIMEOUT) != NO_ERROR ) { logwrite( function, "ERROR opening camera(s)" ); - return ERROR; + throw std::runtime_error("no connection to camera"); } // send all of the epilogue commands @@ -1696,9 +1810,10 @@ namespace Sequencer { // if ( this->set_power_switch(OFF, POWER_CAMERA, std::chrono::seconds(5)) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR powering off camera" ); - return ERROR; + throw std::runtime_error("switching off camera"); } + this->thread_error_manager.clear( THR_CAMERA_SHUTDOWN ); // success return NO_ERROR; } /***** Sequencer::Sequence::camera_shutdown *********************************/ @@ -1707,6 +1822,8 @@ namespace Sequencer { /***** Sequencer::Sequence::move_to_target **********************************/ /** * @brief send request to TCS to move to target coordinates + * @return NO_ERROR + * @throws std::runtime_error * * Disable guiding and send the new target coordinates to the TCS with * the instruction to move immediately. @@ -1751,13 +1868,13 @@ namespace Sequencer { bool dec_isnan = std::isnan( dec_in ); if ( ra_isnan || dec_isnan ) { - message.str(""); message << "ERROR: converting"; + message.str(""); message << "converting"; if ( ra_isnan ) { message << " RA=\"" << this->target.ra_hms << "\""; } if ( dec_isnan ) { message << " DEC=\"" << this->target.dec_dms << "\""; } message << " to decimal"; - this->async.enqueue_and_log( function, message.str() ); + this->async.enqueue_and_log( function, "ERROR "+message.str() ); this->thread_error_manager.set( THR_MOVE_TO_TARGET ); - return ERROR; + throw std::runtime_error(message.str()); } // Before sending the target coords to the TCS, @@ -1826,7 +1943,7 @@ namespace Sequencer { message.str(""); message << "ERROR sending COORDS command. TCS reply: " << coords_reply; this->async.enqueue_and_log( function, message.str() ); this->thread_error_manager.set( THR_MOVE_TO_TARGET ); - return ERROR; + throw std::runtime_error("sending COORDS to TCS: "+coords_reply); } } @@ -1941,7 +2058,7 @@ namespace Sequencer { /***** Sequencer::Sequence::focus_set ***************************************/ /** * @brief set the focus - * @return ERROR | NO_ERROR + * @return NO_ERROR * @todo focus not yet implemented * */ @@ -1950,7 +2067,7 @@ namespace Sequencer { ScopedState thr_state( thread_state_manager, Sequencer::THR_FOCUS_SET ); - logwrite( function, "[TODO] focus not yet implemented." ); + logwrite( function, "focus not yet implemented." ); return NO_ERROR; } @@ -1960,7 +2077,7 @@ namespace Sequencer { /***** Sequencer::Sequence::flexure_set *************************************/ /** * @brief set the flexure - * @return ERROR | NO_ERROR + * @return NO_ERROR * @todo flexure not yet implemented * */ @@ -1969,7 +2086,7 @@ namespace Sequencer { ScopedState thr_state( thread_state_manager, Sequencer::THR_FLEXURE_SET ); - logwrite( function, "[TODO] flexure not yet implemented." ); + logwrite( function, "flexure not yet implemented." ); return NO_ERROR; } @@ -1979,18 +2096,19 @@ namespace Sequencer { /***** Sequencer::Sequence::calib_set ***************************************/ /** * @brief set the calibrator - * @return ERROR | NO_ERROR - * @todo calibrator not yet implemented + * @return NO_ERROR + * @throws std::runtime_error * */ long Sequence::calib_set() { const std::string function("Sequencer::Sequence::calib_set"); std::stringstream message; - long error=NO_ERROR; ScopedState thr_state( thread_state_manager, Sequencer::THR_CALIBRATOR_SET ); ScopedState wait_state( wait_state_manager, Sequencer::SEQ_WAIT_CALIB ); + this->thread_error_manager.set( THR_CALIBRATOR_SET ); // assume the worse, clear on success + // name will index the caltarget map // std::string name(this->target.name); @@ -2010,7 +2128,7 @@ namespace Sequencer { auto calinfo = this->caltarget.get_info(name); if (!calinfo) { logwrite( function, "ERROR unrecognized calibration target: "+name ); - return ERROR; + throw std::runtime_error("unrecognized calibration target: "+name); } // set the calib door and cover @@ -2024,7 +2142,7 @@ namespace Sequencer { if ( !this->cancel_flag.load() && this->calibd.command_timeout( cmd.str(), CALIBD_SET_TIMEOUT ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR moving calib door and/or cover" ); - error=ERROR; + throw std::runtime_error("moving calib door and/or cover"); } // set the internal calibration lamps @@ -2037,7 +2155,7 @@ namespace Sequencer { std::string reply; if ( this->powerd.send( cmd.str(), reply ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR "+message.str() ); - error=ERROR; + throw std::runtime_error("setting lamp "+message.str()); } } @@ -2050,7 +2168,7 @@ namespace Sequencer { // cmd.str(""); cmd << TCSD_NATIVE << " NPS " << lamp << " " << (state?1:0); // if ( this->tcsd.command( cmd.str() ) != NO_ERROR ) { // this->async.enqueue_and_log( function, "ERROR "+cmd.str() ); -// error=ERROR; +// throw std::runtime_error("setting dome lamp: "+cmd.str()); // } // } @@ -2061,7 +2179,7 @@ namespace Sequencer { cmd.str(""); cmd << CALIBD_LAMPMOD << " " << mod << " " << (state?1:0) << " 1000"; if ( this->calibd.command( cmd.str() ) != NO_ERROR ) { this->async.enqueue_and_log( function, "ERROR "+cmd.str() ); - error=ERROR; + throw std::runtime_error("setting lamp modulator "+cmd.str()); } } @@ -2069,7 +2187,8 @@ namespace Sequencer { this->async.enqueue_and_log( function, "NOTICE: abort may have left calib system partially set" ); } - return error; + this->thread_error_manager.clear( THR_CALIBRATOR_SET ); // success + return NO_ERROR; } /***** Sequencer::Sequence::calib_set ***************************************/ @@ -3611,6 +3730,9 @@ namespace Sequencer { std::vector tokens; long error = NO_ERROR; + // lambda to safely start a detached thread with exception catching + auto _safe_thread = [this, &function](auto method) { this->safe_thread(method, function); }; + Tokenize( args, tokens, " " ); if ( tokens.size() < 1 ) { @@ -4220,7 +4342,7 @@ namespace Sequencer { this->is_usercontinue.store(false); logwrite( function, "spawning move_to_target..." ); - std::thread( &Sequencer::Sequence::move_to_target, this ).detach(); + _safe_thread(&Sequencer::Sequence::move_to_target); } else @@ -4442,39 +4564,39 @@ namespace Sequencer { if ( testname == "startup" ) isinit=true; else if ( testname == "shutdown" ) isinit=false; if ( tokens[1] == "power" ) { - std::thread( &Sequencer::Sequence::power_init, this ).detach(); + _safe_thread(&Sequencer::Sequence::power_init); } else if ( tokens[1] == "acam" ) { - std::thread( isinit ? &Sequencer::Sequence::acam_init : &Sequencer::Sequence::acam_shutdown, this ).detach(); + _safe_thread(isinit ? &Sequencer::Sequence::acam_init : &Sequencer::Sequence::acam_shutdown); } else if ( tokens[1] == "calib" ) { - std::thread( isinit ? &Sequencer::Sequence::calib_init : &Sequencer::Sequence::calib_shutdown, this ).detach(); + _safe_thread(isinit ? &Sequencer::Sequence::calib_init : &Sequencer::Sequence::calib_shutdown); } else if ( tokens[1] == "camera" ) { - std::thread( isinit ? &Sequencer::Sequence::camera_init : &Sequencer::Sequence::camera_shutdown, this ).detach(); + _safe_thread(isinit ? &Sequencer::Sequence::camera_init : &Sequencer::Sequence::camera_shutdown); } else if ( tokens[1] == "flexure" ) { - std::thread( isinit ? &Sequencer::Sequence::flexure_init : &Sequencer::Sequence::flexure_shutdown, this ).detach(); + _safe_thread(isinit ? &Sequencer::Sequence::flexure_init : &Sequencer::Sequence::flexure_shutdown); } else if ( tokens[1] == "focus" ) { - std::thread( isinit ? &Sequencer::Sequence::focus_init : &Sequencer::Sequence::focus_shutdown, this ).detach(); + _safe_thread(isinit ? &Sequencer::Sequence::focus_init : &Sequencer::Sequence::focus_shutdown); } else if ( tokens[1] == "slicecam" ) { - std::thread( isinit ? &Sequencer::Sequence::slicecam_init : &Sequencer::Sequence::slicecam_shutdown, this ).detach(); + _safe_thread(isinit ? &Sequencer::Sequence::slicecam_init : &Sequencer::Sequence::slicecam_shutdown); } else if ( tokens[1] == "slit" ) { - std::thread( isinit ? &Sequencer::Sequence::slit_init : &Sequencer::Sequence::slit_shutdown, this ).detach(); + _safe_thread(isinit ? &Sequencer::Sequence::slit_init : &Sequencer::Sequence::slit_shutdown); } else if ( tokens[1] == "tcs" ) { - std::thread( isinit ? &Sequencer::Sequence::tcs_init : &Sequencer::Sequence::tcs_shutdown, this ).detach(); + _safe_thread(isinit ? &Sequencer::Sequence::tcs_init : &Sequencer::Sequence::tcs_shutdown); } else { logwrite( function, "ERROR invalid module \""+tokens[1]+"\"" ); diff --git a/sequencerd/sequence.h b/sequencerd/sequence.h index c7eceb68..cb31390a 100644 --- a/sequencerd/sequence.h +++ b/sequencerd/sequence.h @@ -260,15 +260,34 @@ namespace Sequencer { private: zmqpp::context context; bool ready_to_start; ///< set on nightly startup success, used to return seqstate to READY after an abort + std::atomic is_science_frame_transfer; ///< is frame transfer enabled for science cameras std::atomic notify_tcs_next_target; ///< notify TCS of next target when remaining time within TCS_PREAUTH_TIME std::atomic arm_readout_flag; ///< std::atomic cancel_flag{false}; std::atomic is_ontarget{false}; ///< remotely set by the TCS operator to indicate that the target is ready std::atomic is_usercontinue{false}; ///< remotely set by the user to continue + + /** @brief safely runs function in a detached thread using lambda to catch exceptions + */ + void safe_thread(long (Sequence::*method)(), const std::string &function) { + std::thread([this, method, function]() { + try { + (this->*method)(); + } + catch (const std::exception &e) { + logwrite(function, "ERROR: "+std::string(e.what())); + } + catch (...) { + logwrite(function, "ERROR unknown exception"); + } + }).detach(); + } + public: Sequence() : context(), ready_to_start(false), + is_science_frame_transfer(false), notify_tcs_next_target(false), arm_readout_flag(false), acquisition_timeout(0), From 274fee1d35223df8d43c306458302519f82ac838 Mon Sep 17 00:00:00 2001 From: David Hale Date: Wed, 23 Jul 2025 10:13:21 -0700 Subject: [PATCH 07/19] updates for RealVNC and xfce --- GuiderGUI/launch_gui.sh | 35 ++++++++++++++++++++++++++++++++++- run/runvnc_observer | 6 +++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/GuiderGUI/launch_gui.sh b/GuiderGUI/launch_gui.sh index 32583e5e..e3bafd1f 100755 --- a/GuiderGUI/launch_gui.sh +++ b/GuiderGUI/launch_gui.sh @@ -35,7 +35,40 @@ else -preserve pan yes -preserve regions yes \ -view filename no -view object no -view colorbar no -view frame no -view physical no \ -prefs theme awbreezedark -geometry $geometry \ - -analysis load $anstemplate -analysis task startsync + -analysis load $anstemplate -analysis task startsync & # -region command "$region_cmd" \ fi + +# wait for window to appear then move to preferred position + +window_title="" +if [ "$camera" = "guider" ]; then + window_title="SAOImage GUIDER" +elif [ "$camera" = "slicev" ]; then + window_title="SAOImage SLICEVIEW" +fi + +# wait up to 15 sec + +timeout=15 +elapsed=0 + +while ! wmctrl -l | grep -q "$window_title"; do + sleep 0.5 + elapsed=$((elapsed + 1)) + if [ "$elapsed" -ge $((timeout *2)) ]; then + echo "timeout waiting for $window_title window" + exit 1 + fi +done + +# position the window + +if [ "$camera" = "guider" ]; then + sleep 0.5 + wmctrl -r "SAOImage GUIDER" -e 0,110,50,625,880 +elif [ "$camera" = "slicev" ]; then + sleep 0.5 + wmctrl -r "SAOImage SLICEVIEW" -e 0,770,50,625,880 +fi diff --git a/run/runvnc_observer b/run/runvnc_observer index 77c4fb35..fe569e6a 100755 --- a/run/runvnc_observer +++ b/run/runvnc_observer @@ -4,6 +4,6 @@ source /etc/profile source ~/.bash_profile source ~/.bashrc -/usr/bin/vncserver -Authentication=None -SecurityTypes=None :2 -/usr/bin/vncserver -Authentication=None -SecurityTypes=None :3 -/usr/bin/vncserver -Authentication=None -SecurityTypes=None :4 +/usr/bin/vncserver-virtual -Authentication=None -SecurityTypes=None :2 +/usr/bin/vncserver-virtual -Authentication=None -SecurityTypes=None :3 +/usr/bin/vncserver-virtual -Authentication=None -SecurityTypes=None :4 From 6522e3de1695a52849c49c07b8b02665ec7f750d Mon Sep 17 00:00:00 2001 From: David Hale Date: Fri, 13 Jun 2025 15:04:00 -0700 Subject: [PATCH 08/19] adds Flexure::Compensator class, and starts to add Matt's functions resolve merge conflict --- common/common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/common/common.h b/common/common.h index aa9a91c7..9ed10dba 100644 --- a/common/common.h +++ b/common/common.h @@ -9,6 +9,7 @@ #include #include +#include #include #include #include From 98cd69cffa955f9b13a9ee9bf4d7361d5c20fe0f Mon Sep 17 00:00:00 2001 From: David Hale Date: Fri, 25 Jul 2025 17:04:10 -0700 Subject: [PATCH 09/19] adds more code, C++ versions of Matt's C code --- flexured/flexure_compensator.cpp | 210 +++++++++++++++++++++++++++++++ flexured/flexure_compensator.h | 66 ++++++++++ 2 files changed, 276 insertions(+) create mode 100644 flexured/flexure_compensator.cpp create mode 100644 flexured/flexure_compensator.h diff --git a/flexured/flexure_compensator.cpp b/flexured/flexure_compensator.cpp new file mode 100644 index 00000000..ea9b8920 --- /dev/null +++ b/flexured/flexure_compensator.cpp @@ -0,0 +1,210 @@ +/** + * @file flexure_compensator.cpp + * @brief this contains the flexure compensator code + * @author David Hale & Matt + * + */ + +#include "flexure_compensator.h" + +namespace Flexure { + + /***** Flexure::Compensator::datavec_name ***********************************/ + /** + * @brief returns the name of a vector type + * @param[in] vectype DataVectorType + * @return string + */ + std::string Compensator::datavec_name(DataVectorType vectype) { + switch (vectype) { + case RXE: return "RXE"; + case RYE: return "RYE"; + case IXE: return "IXE"; + case IYE: return "IYE"; + case IX: return "IY"; + case IY: return "IY"; + case RX: return "RX"; + case RY: return "RY"; + default: return "UNKNOWN"; + } + } + /***** Flexure::Compensator::datavec_name ***********************************/ + + + /***** Flexure::Compensator::load_vector_from_config ************************/ + /** + * @brief loads data from Config file into the appropriate vector + * @param[in] config configuration line + * @param[in] vectype DataVectorType specifies which vector to load + * @param[in] vecsize number of elements in this vector + * + */ + long Compensator::load_vector_from_config(std::string &config, DataVectorType vectype, size_t vecsize) { + const std::string function("Flexure::Compensator::load_vector_from_config"); + + if (vecsize<1) { + logwrite(function, "ERROR requested zero vector size for "+datavec_name(vectype)); + return ERROR; + } + + std::vector* vec=nullptr; // reference to specified class vector + + // select which vector to load + switch (vectype) { + case DataVectorType::RXE: vec = &this->rxe; + break; + case DataVectorType::RYE: vec = &this->rye; + break; + case DataVectorType::IXE: vec = &this->ixe; + break; + case DataVectorType::IYE: vec = &this->iye; + break; + case DataVectorType::IX: vec = &this->ix; + break; + case DataVectorType::IY: vec = &this->iy; + break; + case DataVectorType::RX: vec = &this->rx; + break; + case DataVectorType::RY: vec = &this->ry; + break; + default: + logwrite(function, "ERROR invalid vector type"); + return ERROR; + } + + std::vector tokens; + Tokenize(config, tokens, " "); + + if (tokens.size() != vecsize) { + logwrite(function, "ERROR "+std::to_string(tokens.size()) + +" tokens do not match vector size "+std::to_string(vecsize) + +" for "+datavec_name(vectype)); + return ERROR; + } + + // erase and load vector + try { + vec->clear(); + for (const auto &tok : tokens) vec->push_back( std::stod(tok) ); + } + catch (const std::exception &e) { + logwrite(function, "ERROR parsing data from "+datavec_name(vectype)+" data: "+std::string(e.what())); + return ERROR; + } + + return NO_ERROR; + } + /***** Flexure::Compensator::load_vector_from_config ************************/ + + + /***** Flexure::Compensator::flexure_polynomial_fit *************************/ + /** + * @brief fits a 4th order polynomial to inputvar + * @details Uses inputvar for the fitting variable and 4 coefficients from + * supplied vector starting with offset. Requires that vector have + * at least 5 coefficients. + * @param[in] vec vector of coefficients + * @param[in] inputvar independent input variable for the polynomial fit + * @param[in] offset offset in vector to start reading coefficients + * + */ + double Compensator::flexure_polynomial_fit(double vec, double inputvar, size_t offset) { + const std::string function("Flexure::Compensator::flexure_polynomial_fit"); + if (offset+5 > vec.size()) { + logwrite(function, "ERROR not enough coefficients in vector for requested offset"); + throw std::out_of_range("not enough coefficients in vector"); + } + return vec[offset + 0] + + vec[offset + 1] * inputvar + + vec[offset + 2] * std::pow(inputvar, 2.0) + + vec[offset + 3] * std::pow(inputvar, 3.0) + + vec[offset + 4] * std::pow(inputvar, 4.0); + } + /***** Flexure::Compensator::flexure_polynomial_fit *************************/ + + + /***** Flexure::Compensator::flexure_fit ************************************/ + /** + * @brief + * @param[in] func type of trig function to use, Sine or Cosine + * @return + * + */ + double Compensator::flexure_fit(TrigFunction func) { + const std::string function("Flexure::Compensator::flexure_fit"); + try { + double c = flexure_polynomial_fit(rx, zenith, 0); + double a1 = flexure_polynomial_fit(rx, zenith, 5); + double theta = flexure_polynomial_fit(rx, zenith, 10); + double a2 = flexure_polynomial_fit(rx, zenith, 15); + + switch (func) { + case TrigFunction::Sine: + return c + a1 * std::sin( (equivalent_cass * DEGTORAD - theta)) + + a2 * std::sin(2*(equivalent_cass * DEGTORAD - theta)); + case TrigFunction::Cosine: + default: + return c + a1 * std::cos( (equivalent_cass * DEGTORAD - theta)) + + a2 * std::cos(2*(equivalent_cass * DEGTORAD - theta)); + } + } + catch (const std::exception &e) { + logwrite(function, "ERROR: "+std::string(e.what())); + throw; + } + } + /***** Flexure::Compensator::flexure_fit ************************************/ + + + /***** Flexure::Compensator::compute_flexure_compensation ******************/ + /** + * @brief + * @details + * + * @param[in] ha hour angle in decimal degrees. + * @param[in] dec declination in decimal degrees. + * @param[in] cassring + * @param[in] exptime exposure time in seconds for future calculation + * @param[in] prx, pry, pix, piy -- polynomial coefficients to compute fit parameters + * @param[in] nrx, nry, nix, niy -- nominal stage positions + * @param[out] arx-- adjusted stage positions + * @param[out] ary-- adjusted stage positions + * @param[out] aix-- adjusted stage positions + * @param[out] aiy -- adjusted stage positions + * + */ + void Compensator::compute_flexure_compensation(double ha, double dec, double cassring, double exptime, + double *prx, double *pry, double *pix, double *piy, + double nrx, double nry, double nix, double niy, + double *arx, double *ary, double *aix, double *aiy) { + + double alt, az, pa; // elevation, azimuth, and parallactic angle from TCS + double zenith; // zenith angle + double srx, sry, six, siy; // intermediate computation step -- expected flexure + double drx, dry, dix,diy; // computed correction deltas + double tx, ty; // temporary. + + // adjust hour angle for exposure time midpoint + double adjusted_hour_angle = ha + exptime / 2.0 / 3600.0 * 15.0; + + double equivalent_cass = (-(pa + cassring) + 180) % 360 - 180; + + // calculate flexure of each axis + srx = flexure_fit(equivalent_cass, alt, prx); + sry = flexure_fit(equivalent_cass, alt, pry); + six = flexure_fit_cos(equivalent_cass, alt, pix); + siy = flexure_fit_cos(equivalent_cass, alt, piy); + + + collimator_position(srx, sry, &drx, &dry, &tx, &ty); + collimator_position(six, siy, &tx, &ty, &dix, &diy); + + // ajusted stage positions + *arx = drx + nrx; + *ary = -dry + nry; + *aix = dix + nix; + *aiy = -diy + niy; + } + /***** Flexure::Compensator::compute_flexure_compensation ******************/ + +} diff --git a/flexured/flexure_compensator.h b/flexured/flexure_compensator.h new file mode 100644 index 00000000..adcf9f55 --- /dev/null +++ b/flexured/flexure_compensator.h @@ -0,0 +1,66 @@ +/** --------------------------------------------------------------------------- + * @file flexure_interface.h + * @brief flexure interface include + * @details defines the classes used by the flexure hardware interface + * @author David Hale + * + */ + +#pragma once + +#include "common.h" + +namespace Flexure { + + constexpr double PI = 3.14159265358979323846; + constexpr double DEGTORAD = PI/180.0; + + enum class TrigFunction { + Sine, + Cosine + }; + + /** + * @brief + */ + enum DataVectorType : size_t { + RXE, + RYE, + IXE, + IYE, + IX, + IY, + RX, + RY + }; + + /***** Flexure::Compensator *************************************************/ + /** + * @brief contains functions and data for performing compensation + * @details this does not compensate anything, just informs how to compensate + * + */ + class Compensator { + private: + std::vector rxe, rye, ixe, iye, ix, rx, iy, ry; + + // From Matt Matuszewski + // + void collimator_position(double x, double y, double *rx, double *ry, double *ix, double *iy); + double flexure_polynomial_fit(double elevation, double *p); + double flexure_fit(double modified_cass, double elevation, double *p); + double flexure_fit_cos(double modified_cass, double elevation, double *p); + void compute_flexure_compensation(double ha, double dec, double cassring, double exptime, + double *prx, double *pry, double *pix, double *piy, + double nrx, double nry, double nix, double niy, + double *arx, double *ary, double *aix, double *aiy); + + public: + static std::string datavec_name(DataVectorType vectype); + long load_vector_from_config(std::string &config, DataVectorType vectype, size_t vecsize); + + long calculate(/* TBD */); // presumably the equivalent of Matt's main() + }; + /***** Flexure::Compensator *************************************************/ + +} From dcb52f2cfa36dae047748432c650ef9f43ecd18b Mon Sep 17 00:00:00 2001 From: David Hale Date: Mon, 11 Aug 2025 15:35:09 -0700 Subject: [PATCH 10/19] small changes --- flexured/flexure_compensator.cpp | 55 +++++++++++++++++--------------- flexured/flexure_compensator.h | 10 +++--- flexured/flexure_server.cpp | 8 ++--- 3 files changed, 39 insertions(+), 34 deletions(-) diff --git a/flexured/flexure_compensator.cpp b/flexured/flexure_compensator.cpp index ea9b8920..45e26f8a 100644 --- a/flexured/flexure_compensator.cpp +++ b/flexured/flexure_compensator.cpp @@ -21,10 +21,10 @@ namespace Flexure { case RYE: return "RYE"; case IXE: return "IXE"; case IYE: return "IYE"; - case IX: return "IY"; - case IY: return "IY"; - case RX: return "RX"; - case RY: return "RY"; + case PIX: return "PIY"; + case PIY: return "PIY"; + case PRX: return "PRX"; + case PRY: return "PRY"; default: return "UNKNOWN"; } } @@ -59,13 +59,13 @@ namespace Flexure { break; case DataVectorType::IYE: vec = &this->iye; break; - case DataVectorType::IX: vec = &this->ix; + case DataVectorType::PIX: vec = &this->pix; break; - case DataVectorType::IY: vec = &this->iy; + case DataVectorType::PIY: vec = &this->piy; break; - case DataVectorType::RX: vec = &this->rx; + case DataVectorType::PRX: vec = &this->prx; break; - case DataVectorType::RY: vec = &this->ry; + case DataVectorType::PRY: vec = &this->pry; break; default: logwrite(function, "ERROR invalid vector type"); @@ -106,6 +106,7 @@ namespace Flexure { * @param[in] vec vector of coefficients * @param[in] inputvar independent input variable for the polynomial fit * @param[in] offset offset in vector to start reading coefficients + * @throws std::out_of_range * */ double Compensator::flexure_polynomial_fit(double vec, double inputvar, size_t offset) { @@ -125,18 +126,22 @@ namespace Flexure { /***** Flexure::Compensator::flexure_fit ************************************/ /** - * @brief + * @brief calculates fit + * @details C + A1 * sin(cass-theta) + A2 * sin(2*(cass-theta)) or + * C + A1 * cos(cass-theta) + A2 * cos(2*(cass-theta)) + * @param[in] poly vector of polynomial data * @param[in] func type of trig function to use, Sine or Cosine - * @return + * @return fitted value + * @throws std::exception * */ - double Compensator::flexure_fit(TrigFunction func) { + double Compensator::flexure_fit(double poly, TrigFunction func) { const std::string function("Flexure::Compensator::flexure_fit"); try { - double c = flexure_polynomial_fit(rx, zenith, 0); - double a1 = flexure_polynomial_fit(rx, zenith, 5); - double theta = flexure_polynomial_fit(rx, zenith, 10); - double a2 = flexure_polynomial_fit(rx, zenith, 15); + double c = flexure_polynomial_fit(poly, zenith, 0); + double a1 = flexure_polynomial_fit(poly, zenith, 5); + double theta = flexure_polynomial_fit(poly, zenith, 10); + double a2 = flexure_polynomial_fit(poly, zenith, 15); switch (func) { case TrigFunction::Sine: @@ -174,9 +179,9 @@ namespace Flexure { * */ void Compensator::compute_flexure_compensation(double ha, double dec, double cassring, double exptime, - double *prx, double *pry, double *pix, double *piy, + double &prx, double &pry, double &pix, double &piy, double nrx, double nry, double nix, double niy, - double *arx, double *ary, double *aix, double *aiy) { + double &arx, double &ary, double &aix, double &aiy) { double alt, az, pa; // elevation, azimuth, and parallactic angle from TCS double zenith; // zenith angle @@ -190,20 +195,20 @@ namespace Flexure { double equivalent_cass = (-(pa + cassring) + 180) % 360 - 180; // calculate flexure of each axis - srx = flexure_fit(equivalent_cass, alt, prx); - sry = flexure_fit(equivalent_cass, alt, pry); - six = flexure_fit_cos(equivalent_cass, alt, pix); - siy = flexure_fit_cos(equivalent_cass, alt, piy); + srx = flexure_fit(this->prx, Sine); + sry = flexure_fit(this->pry, Sine); + six = flexure_fit(this->pix, Cosine); + siy = flexure_fit(this->piy, Cosine); collimator_position(srx, sry, &drx, &dry, &tx, &ty); collimator_position(six, siy, &tx, &ty, &dix, &diy); // ajusted stage positions - *arx = drx + nrx; - *ary = -dry + nry; - *aix = dix + nix; - *aiy = -diy + niy; + arx = drx + nrx; + ary = -dry + nry; + aix = dix + nix; + aiy = -diy + niy; } /***** Flexure::Compensator::compute_flexure_compensation ******************/ diff --git a/flexured/flexure_compensator.h b/flexured/flexure_compensator.h index adcf9f55..0bfc6c61 100644 --- a/flexured/flexure_compensator.h +++ b/flexured/flexure_compensator.h @@ -28,10 +28,10 @@ namespace Flexure { RYE, IXE, IYE, - IX, - IY, - RX, - RY + PIX, + PIY, + PRX, + PRY }; /***** Flexure::Compensator *************************************************/ @@ -42,7 +42,7 @@ namespace Flexure { */ class Compensator { private: - std::vector rxe, rye, ixe, iye, ix, rx, iy, ry; + std::vector rxe, rye, ixe, iye, pix, prx, piy, pry; // From Matt Matuszewski // diff --git a/flexured/flexure_server.cpp b/flexured/flexure_server.cpp index f80f9270..14df892a 100644 --- a/flexured/flexure_server.cpp +++ b/flexured/flexure_server.cpp @@ -204,7 +204,7 @@ namespace Flexure { // FLEXURE_POLY_IX // if ( config.param[entry] == "FLEXURE_POLY_IX" ) { - error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::IX, 20 ); + error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::PIX, 20 ); if (error==NO_ERROR) { numapplied++; } @@ -215,7 +215,7 @@ namespace Flexure { // FLEXURE_POLY_IY // if ( config.param[entry] == "FLEXURE_POLY_IY" ) { - error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::IY, 20 ); + error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::PIY, 20 ); if (error==NO_ERROR) { numapplied++; } @@ -226,7 +226,7 @@ namespace Flexure { // FLEXURE_POLY_RX // if ( config.param[entry] == "FLEXURE_POLY_RX" ) { - error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::RX, 20 ); + error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::PRX, 20 ); if (error==NO_ERROR) { numapplied++; } @@ -237,7 +237,7 @@ namespace Flexure { // FLEXURE_POLY_RY // if ( config.param[entry] == "FLEXURE_POLY_RY" ) { - error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::RY, 20 ); + error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::PRY, 20 ); if (error==NO_ERROR) { numapplied++; } From 1c3981503d7a1c07ff86ccf18375d9a065296298 Mon Sep 17 00:00:00 2001 From: David Hale Date: Fri, 24 Oct 2025 13:37:13 -0700 Subject: [PATCH 11/19] replaces old DSP directory with submodule reference --- .gitmodules | 3 + DSP | 1 + DSP/DBSP-blue/CCD44-82.waveforms | 328 --- DSP/DBSP-blue/tim | 24 - DSP/DBSP-blue/tim.asm | 470 ---- DSP/DBSP-blue/tim.lod | 601 ---- DSP/DBSP-blue/tim.ls | 2672 ------------------ DSP/DBSP-blue/timCCDmisc.asm | 690 ----- DSP/DBSP-blue/timboot.asm | 554 ---- DSP/DBSP-blue/timhdr.asm | 222 -- DSP/DBSP-red/LBNL_2Kx4K.waveforms | 1079 -------- DSP/DBSP-red/tim | 35 - DSP/DBSP-red/tim.asm | 348 --- DSP/DBSP-red/tim.lod | 1027 ------- DSP/DBSP-red/tim.ls | 4310 ----------------------------- DSP/DBSP-red/timCCDmisc.asm | 1160 -------- DSP/DBSP-red/timboot.asm | 690 ----- DSP/DBSP-red/timhdr.asm | 229 -- 18 files changed, 4 insertions(+), 14439 deletions(-) create mode 100644 .gitmodules create mode 160000 DSP delete mode 100644 DSP/DBSP-blue/CCD44-82.waveforms delete mode 100755 DSP/DBSP-blue/tim delete mode 100644 DSP/DBSP-blue/tim.asm delete mode 100644 DSP/DBSP-blue/tim.lod delete mode 100644 DSP/DBSP-blue/tim.ls delete mode 100644 DSP/DBSP-blue/timCCDmisc.asm delete mode 100644 DSP/DBSP-blue/timboot.asm delete mode 100644 DSP/DBSP-blue/timhdr.asm delete mode 100755 DSP/DBSP-red/LBNL_2Kx4K.waveforms delete mode 100755 DSP/DBSP-red/tim delete mode 100755 DSP/DBSP-red/tim.asm delete mode 100644 DSP/DBSP-red/tim.lod delete mode 100644 DSP/DBSP-red/tim.ls delete mode 100755 DSP/DBSP-red/timCCDmisc.asm delete mode 100755 DSP/DBSP-red/timboot.asm delete mode 100755 DSP/DBSP-red/timhdr.asm diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..d8fd257e --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "DSP"] + path = DSP + url = https://github.com/CaltechOpticalObservatories/NGPS-DSP.git diff --git a/DSP b/DSP new file mode 160000 index 00000000..e61d6ecb --- /dev/null +++ b/DSP @@ -0,0 +1 @@ +Subproject commit e61d6ecbd36e00aa1196f1db65c10d044c507649 diff --git a/DSP/DBSP-blue/CCD44-82.waveforms b/DSP/DBSP-blue/CCD44-82.waveforms deleted file mode 100644 index 71369276..00000000 --- a/DSP/DBSP-blue/CCD44-82.waveforms +++ /dev/null @@ -1,328 +0,0 @@ - COMMENT * - - * - -; LEFT CHANNEL READOUT - -; Miscellaneous definitions -CLKAD EQU $200000 -VIDEO EQU $000000 ; Video processor board select = 0 -CLK2 EQU $002000 ; Clock driver board lower half -CLK3 EQU $003000 ; Clock driver board upper half - -; Delay numbers for clocking -P_DLY EQU $B80000 ; Parallel clock delay -S_DLY EQU $090000 ; Serial shift time per state. - ; Gets noisy if shorter (or is it the shorter dwell?) -;SS_DLY EQU $310000 ; Serial skip time per state -SS_DLY EQU $030000 ; Serial skip time per state -SW_DLY EQU $040000 ; summing well settling time. 2 may be ok. -NS_CLR EQU 2100 ; Serial clocks to clear -NP_CLR EQU 1024 ; Parallel clocks to clear (per amplifier) -SH_DEL EQU 50 ; Shutter delay in milliseconds -ADC_DLY EQU $070000 ; ADC sample time = 300 ns, but some slew occurs during integration. -RG_DLY EQU $040000 ; reset gate settling before DC restore - -CNV_DLY EQU $110000 ; RG_DLY+CNV_DLY+40ns >> 815 ns, say 880ns. -DCR_DLY EQU $030000 ; DC Restore, settle time after xmit > 160ns - -;INT_DLY EQU $000000 ; integration delay -> measured 2.48 usecs/pix -;INT_DLY EQU $140000 ; adjust to extend dwell time -> measured 3.28 usecs/pix -;INT_DLY EQU $260000 ; adjust to extend dwell time -> measured 4.00 usecs/pix -INT_DLY EQU $3F0000 ; adjust to extend dwell time -> measured 5.00 usecs/pix -;INT_DLY EQU $580000 ; adjust to extend dwell time -> measured 6.00 usecs/pix -;INT_DLY EQU $7D0000 ; adjust to extend dwell time -> measured 7.00 usecs/pix -;INT_DLY2 EQU $310000 ; add to 7us dwell time to get 9.00 usecs/pix -;INT_DLY EQU $130000 ; -;INT_DLY2 EQU $130000 ; - -; clocking voltages -P_HI EQU +1.0 ; Parallel clock ; datasheet +10 -P_LO EQU -9.0 ; datasheet 0.0 -RG_HI EQU +3.0 ; Reset Gate ; datasheet +12.0 -RG_LO EQU -3.0 ; datasheet 0.0 -S_HI EQU +2.0 ; Serial clocks ; datasheet +11.0 -S_LO EQU -8.0 ; datasheet 1.0 -SW_HI EQU +2.0 ; Summing well ; datasheet +11.0 -SW_LO EQU -9.0 ; datasheet 0.0 -DG_HI EQU 3.0 ; Dump Gate -DG_LO EQU -9.0 ; Dump Gate -ZERO EQU -9.0 -CLKmax EQU +12.4 - -; DC Bias definition, in volts -BOD EQU +20.0 ; Output Drain both ; datasheet +29 -BJD EQU +22 ; Jfet Drain both ; datasheet +31 -BRDL EQU +8.0 ; Reset Drain ; datasheet +17 -BRDR EQU +8.0 -BDD EQU +15.0 ; Dump Drain ; datasheet +24 -BOG1 EQU -6.0 ; Output gate 1 ; datasheet +3 -BOG2 EQU -3.0 ; Output gate 2 ; datasheet +4 - -; Output video offset parameters -OFFSET0 EQU 1503 -OFFSET1 EQU 1601 - -; ****************************************************** -; ****************************************************** - -; Define switch state bits for the CCD clocks - CLK2, which is lower bank -P1 EQU 1 ; Parallel shift register phase #1, L & R amps -P2 EQU 2 ; Parallel shift register phase #2, L & R amps -P3 EQU 4 ; Parallel shift register phase #3, L & R amps -H_DG EQU 8 ; Dump Gate -L_DG EQU 0 ; Dump Gate - -; Define switch state bits for the CCD clocks - CLK3, which is upper bank -S1L EQU 1 ; Serial shift register phase #1, left quadrant -S2L EQU 2 ; Serial shift register phase #2, left -SWL EQU 4 ; Summing well, Left quadrant -S1R EQU 8 ; Serial shift register phase #1, right quadrant -S2R EQU $10 ; Serial shift register phase #2, right -SWR EQU $20 ; Summing well, Right quadrant -S3 EQU $40 ; Serial shift register phase #3, both -RGL EQU $80 ; Reset Gate left -RGR EQU $100 ; Reset Gate right - - -; *** Definitions for Y: memory waveform tables ***** - -; waveforms para el borrado paralelo (ie parallel erase.) -PARALLEL_CLEAR - DC END_PARALLEL_CLEAR-PARALLEL_CLEAR-1 - DC CLK2+P_DLY+00+P2+P3+H_DG - DC CLK2+P_DLY+00+00+P3+H_DG - DC CLK2+P_DLY+P1+00+P3+H_DG - DC CLK2+P_DLY+P1+00+00+H_DG - DC CLK2+P_DLY+P1+P2+00+H_DG - DC CLK2+P_DLY+00+P2+00+H_DG -END_PARALLEL_CLEAR - -; Clock the image down -PARALLEL_SHIFT - DC END_PARALLEL_SHIFT-PARALLEL_SHIFT-1 - DC CLK3+S_DLY+S1L+S1R+S2L+S2R+00+RGL+RGR+SWR+SWL - DC CLK2+P_DLY+00+P2+P3+L_DG - DC CLK2+P_DLY+00+00+P3+L_DG - DC CLK2+P_DLY+P1+00+P3+L_DG - DC CLK2+P_DLY+P1+00+00+L_DG - DC CLK2+P_DLY+P1+P2+00+L_DG - DC CLK2+P_DLY+00+P2+00+L_DG -END_PARALLEL_SHIFT - -PREPARE_DUMP - DC END_PREPARE_DUMP-PREPARE_DUMP-1 - DC CLK3+S_DLY+S1L+S1R+S2L+S2R+00+RGL+RGR+SWR+SWL -END_PREPARE_DUMP - -PARALLEL_DUMP - DC END_PARALLEL_DUMP-PARALLEL_DUMP-1 - DC CLK2+P_DLY+00+P2+P3+H_DG - DC CLK2+P_DLY+00+00+P3+H_DG - DC CLK2+P_DLY+P1+00+P3+H_DG - DC CLK2+P_DLY+P1+00+00+H_DG - DC CLK2+P_DLY+P1+P2+00+H_DG - DC CLK2+P_DLY+00+P2+00+H_DG -END_PARALLEL_DUMP - -CLEAR_READ_REGISTER - DC END_CLEAR_READ_REGISTER-CLEAR_READ_REGISTER-1 - DC CLK3+S_DLY+000+000+000+000+00+RGL+RGR+000+000 - DC CLK2+P_DLY+00+P2+00+L_DG -END_CLEAR_READ_REGISTER - -; Serial clocking waveform for skipping -SERIAL_SKIP - DC END_SERIAL_SKIP-SERIAL_SKIP-1 - DC VIDEO+$000000+%1110100 ; DC Restore(!b1) - DC CLK3+SS_DLY+S1L+S2R+S2L+S1R+00+000+000+000+000 - DC CLK3+SS_DLY+000+000+S2L+S1R+00+000+000+000+000 - DC VIDEO+$000000+%1110110 ; end DC restore - DC CLK3+SS_DLY+000+000+S2L+S1R+S3+RGL+RGR+SWL+SWR - DC CLK3+SS_DLY+000+000+000+000+S3+RGL+RGR+SWL+SWR - DC CLK3+SS_DLY+S1L+S2R+000+000+S3+RGL+RGR+SWL+SWR - DC CLK3+SS_DLY+S1L+S2R+000+000+00+000+000+000+000 -END_SERIAL_SKIP - -; Serial clocking waveform for binning (shift only) (SW high and RG low) -SERIAL_SHIFT - DC END_SERIAL_SHIFT-SERIAL_SHIFT-1 - DC CLK3+S_DLY+S1L+S2R+S2L+S1R+00+000+000+SWR+SWL - DC CLK3+S_DLY+000+000+S2L+S1R+00+000+000+SWR+SWL - DC CLK3+S_DLY+000+000+S2L+S1R+S3+000+000+SWL+SWR - DC CLK3+S_DLY+000+000+000+000+S3+000+000+SWL+SWR - DC CLK3+S_DLY+S1L+S2R+000+000+S3+000+000+SWL+SWR - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -END_SERIAL_SHIFT - -; Serial clocking waveform for reading (shift plus video proc) -; CLK3 = Delay+S1L+S1R+S2L+S2L+S3+RGL+RGR+SWL+SWR -; -SERIAL_READ - DC END_SERIAL_READ-SERIAL_READ-1 - DC VIDEO+$000000+%0010111 ; Stop resetting integrator - - DC VIDEO+000000+%0000111 ; Integrate - DC CLK3+S_DLY+S1L+S2R+S2L+S1R+00+000+000+SWR+SWL - DC CLK3+S_DLY+000+000+S2L+S1R+00+000+000+SWR+SWL - DC CLK3+S_DLY+000+000+S2L+S1R+S3+000+000+SWL+SWR - DC CLK3+S_DLY+000+000+000+000+S3+000+000+SWL+SWR - DC CLK3+S_DLY+S1L+S2R+000+000+S3+000+000+SWL+SWR - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR - DC CLK3+INT_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -; DC CLK3+INT_DLY2+S1L+S2R+000+000+00+000+000+SWL+SWR - DC VIDEO+$000000+%0011011 ; Stop Integrate - - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+000+000 - DC CLK3+SW_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR - - DC VIDEO+$00000+%0001011 ; Integrate - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR - DC CLK3+INT_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -; DC CLK3+INT_DLY2+S1L+S2R+000+000+00+000+000+SWL+SWR - DC VIDEO+$000000+%0011011 ; Stop integrator - - DC CLK3+ADC_DLY+S1L+S2R+000+000+00+RGL+RGR+SWL+SWR ; Reset Gate, ADC sample>300 ns - DC VIDEO+$000000+%0111011 ; Start convert=hold (lo to hi on bit 5 -SS5-) - DC VIDEO+$000000+%0111011 ; redundant write manage beat frequencies - DC VIDEO+$000000+%0111011 ; redundant write manage beat frequencies - DC CLK3+$000000+S1L+S2R+000+000+00+000+000+SWR+SWL ; end of RG pulse - DC VIDEO+RG_DLY+%1110110 ; Reset Integrator(!b0), RG settling - DC VIDEO+CNV_DLY+%1110100 ; DC Restore(!b1) - DC $00F000 ; Transmit A/D data to host - DC CLK3+DCR_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR ; DC restore & settle after xmit -END_SERIAL_READ - -DUMMY_READ - DC END_DUMMY_READ-DUMMY_READ-1 - DC VIDEO+$000000+%0010111 ; Stop resetting integrator - ; DC VIDEO+$000000+%0010111 ; Stop resetting integrator (unnecessary?) - - DC VIDEO+00000+%0000111 ; Integrate - DC CLK3+S_DLY+S1L+S2R+S2L+S1R+00+000+000+SWR+SWL - DC CLK3+S_DLY+000+000+S2L+S1R+00+000+000+SWR+SWL - DC CLK3+S_DLY+000+000+S2L+S1R+S3+000+000+SWL+SWR - DC CLK3+S_DLY+000+000+000+000+S3+000+000+SWL+SWR - DC CLK3+S_DLY+S1L+S2R+000+000+S3+000+000+SWL+SWR - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR - DC CLK3+INT_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -; DC CLK3+INT_DLY2+S1L+S2R+000+000+00+000+000+SWL+SWR - DC VIDEO+$000000+%0011011 ; Stop Integrate - - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+000+000 - DC CLK3+SW_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR - - DC VIDEO+$000000+%0001011 ; Integrate - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR - DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR - DC CLK3+INT_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -; DC CLK3+INT_DLY2+S1L+S2R+000+000+00+000+000+SWL+SWR - DC VIDEO+$00000+%0011011 ; Stop integrator - - DC CLK3+ADC_DLY+S1L+S2R+000+000+00+RGL+RGR+SWL+SWR ; Reset Gate, ADC sample>300 ns - DC VIDEO+$000000+%0111011 ; Start convert=hold (lo to hi on bit 5 -SS5-) - DC CLK3+$000000+S1L+S2R+000+000+00+000+000+SWR+SWL ; end of RG pulse - DC VIDEO+RG_DLY+%1110110 ; Reset Integrator(!b0), RG settling - DC VIDEO+CNV_DLY+%1110100 ; DC Restore(!b1) - ; transmit >>815 ns after start convert. - DC CLK3+DCR_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR ; DC restore & settle after xmit -END_DUMMY_READ - - - -; Initialization of clock driver and video processor DACs and switches -DACS DC END_DACS-DACS-1 - DC CLKAD+$0A0080 - DC CLKAD+$000100+@CVI((P_HI+CLKmax)/(2*CLKmax)*255) ; Pin #1, P1 - DC CLKAD+$000200+@CVI((P_LO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$000400+@CVI((P_HI+CLKmax)/(2*CLKmax)*255) ; Pin #2, P2 - DC CLKAD+$000800+@CVI((P_LO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$002000+@CVI((P_HI+CLKmax)/(2*CLKmax)*255) ; Pin #3, P3 - DC CLKAD+$004000+@CVI((P_LO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$008000+@CVI((DG_HI+CLKmax)/(2*CLKmax)*255) ; Pin #4, DG - DC CLKAD+$010000+@CVI((DG_LO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$020100+@CVI((P_HI+CLKmax)/(2*CLKmax)*255) ; Pin #5, ?? - DC CLKAD+$020200+@CVI((P_LO+CLKmax)/(2*CLKmax)*255) - - - DC CLKAD+$020400+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #6, Unused - DC CLKAD+$020800+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$022000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #7, Unused - DC CLKAD+$024000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$028000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #8, Unused - DC CLKAD+$030000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$040100+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #9, Unused - DC CLKAD+$040200+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$040400+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #10, Unused - DC CLKAD+$040800+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$042000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #11, Unused - DC CLKAD+$044000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$048000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #12, Unused - DC CLKAD+$050000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) - - - DC CLKAD+$060100+@CVI((S_HI+CLKmax)/(2*CLKmax)*255) ; Pin #13, S1L - DC CLKAD+$060200+@CVI((S_LO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$060400+@CVI((S_HI+CLKmax)/(2*CLKmax)*255) ; Pin #14, S2L - DC CLKAD+$060800+@CVI((S_LO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$062000+@CVI((SW_HI+CLKmax)/(2*CLKmax)*255) ; Pin #15, SWL - DC CLKAD+$064000+@CVI((SW_LO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$068000+@CVI((S_HI+CLKmax)/(2*CLKmax)*255) ; Pin #16, S1R - DC CLKAD+$070000+@CVI((S_LO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$080100+@CVI((S_HI+CLKmax)/(2*CLKmax)*255) ; Pin #17, S2R - DC CLKAD+$080200+@CVI((S_LO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$080400+@CVI((SW_HI+CLKmax)/(2*CLKmax)*255) ; Pin #18, SWR - DC CLKAD+$080800+@CVI((SW_LO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$082000+@CVI((S_HI+CLKmax)/(2*CLKmax)*255) ; Pin #19, S3 - DC CLKAD+$084000+@CVI((S_LO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$088000+@CVI((RG_HI+CLKmax)/(2*CLKmax)*255) ; Pin #33, RGL - DC CLKAD+$090000+@CVI((RG_LO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$0A0100+@CVI((RG_HI+CLKmax)/(2*CLKmax)*255) ; Pin #34, RGR - DC CLKAD+$0A0200+@CVI((RG_LO+CLKmax)/(2*CLKmax)*255) - - - DC CLKAD+$0A0400+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #35, Unused - DC CLKAD+$0A0800+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$0A2000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #36, Unused - DC CLKAD+$0A4000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) - DC CLKAD+$0A8000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #37, Unused - DC CLKAD+$0B0000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) - - - -; Set gain and integrator speed. (77, bb, dd, ee; low gain to high) -; DC $0c3c77 ; Gain x1, slow integ. speed, board #0 - DC $0c3f77 ; Gain x1, fast integrate speed -; DC $0c3fbb ; Gain x2 -; DC $0c3fdd ; Gain x4.75 -; DC $0c3fee ; Gain x9.50 - -; DC $0c3fbb ; Default x2 gain, fast integration -; DC $0c33bb ; Default x2 gain, fast integration (to read the sawtooth waveform) - -; Output offset voltages - DC $0c4000+OFFSET0 ; Output video offset, channel 0 - DC $0cc000+OFFSET1 - -; DC bias voltages. Gain and offsets adjusted for video boards SN205 and SN304. Feb. 24, 2005 -; (if it is wrong, blame on DG, if it is right, applauses to MB) - - DC $0d0000+@CVI((BOD-6.3)/23.7*4095) ; pin #1, VID0 - DC $0d4000+@CVI((BJD-6.3)/23.7*4095) ; pin #2, VID0 - DC $0d8000+@CVI((BRDL-3.9)/16.1*4095) ; pin #3, VID0 - DC $0dc000+@CVI((BRDR-3.9)/16.1*4095) ; pin #4, VID0 - DC $0e0000+@CVI((BDD-3.9)/16.1*4095) ; pin #5, VID0 - - DC $0f8000+@CVI((BOG1+10.0)/20.0*4095) ; pin #11, VID0 - DC $0fc000+@CVI((BOG2+10.0)/20.0*4095) ; pin #12, VID0 - -END_DACS diff --git a/DSP/DBSP-blue/tim b/DSP/DBSP-blue/tim deleted file mode 100755 index 56bf23bf..00000000 --- a/DSP/DBSP-blue/tim +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# - echo "" - echo "Assembling DSP code for the 8x IR video processor" - echo "" -# -# DOWNLOAD selects application code to be loaded from EEPROM or -# downloaded from the host over the fiber optic link -# -# DOWNLOAD = HOST or ROM - -DOWNLOAD=HOST -WAVEFORM_FILE=CCD44-82.waveforms -DST_FILE=tim - -wine /opt/CLAS563/BIN/ASM56300 -b -ltim.ls -d DOWNLOAD $DOWNLOAD -d WAVEFORM_FILE "$WAVEFORM_FILE" tim.asm -wine /opt/CLAS563/BIN/DSPLNK -btim.cld -v tim.cln -rm -f "$DST_FILE".lod -wine /opt/CLAS563/BIN/CLDLOD tim.cld > "$DST_FILE".lod -rm tim.cln ; rm tim.cld - - echo "" - echo "Created file 'tim.lod' for downloading over optical fiber" - echo "" diff --git a/DSP/DBSP-blue/tim.asm b/DSP/DBSP-blue/tim.asm deleted file mode 100644 index 259f0245..00000000 --- a/DSP/DBSP-blue/tim.asm +++ /dev/null @@ -1,470 +0,0 @@ - COMMENT * - This file is used to generate boot DSP code for - the 250 MHz fiber optic timing board, SDSU GenII TIMII, - processor = DSP56303. - -Revision History: --- 0.00: 10 Jun 2004 - CRO. - Original code from Dani Guzman. - --- 1.10: 11 Jun 2004 - CRO. - a.) Cleanup. Some spanish-english comment translation. - b.) Y:00000B memory location reserved for NPSHF, the number - of rows to parallel shift for the PSH command (which - is new). This is implimented as part of a focus loop - in which a series of exposures are made at different - telescope (or spectrograph) focus positions and the CCD - charge is shifted some number of rows (NPSHF) between - each exposure. At the end of the loop an image with a - sequence of star images at different telescope focus - positions is read out. - --- 1.20: 23 Jun 2004 - CRO - a.) Added nested do loops in RDCCD for parallel and serial - binning. Added NSBINM1 to Y: memory. This is the - serial binning factor minus one, used because he serial - binning and readout is split into two parts, one - for serial shift only and the last for a serial shift - and video processing. So, the first part is executed - NSBINM1 times; the last part, once. - --- 1.30: 24 Jun 2004 - CRO - a.) Added version number to Y memory so that it is possible - to check which version of code is downloaded into - the timing board DSP by reading that memory location - Y:00000D. - b.) Added NPSKP (Y:00000E) and NSSKP (Y:00000F) to Y memory, - the number of parallel and serial skips for ROI readout. - c.) Added ROI parallel skipping code just before the start - of the binned readout. - - In order to specify the number of parallel skips, - the program looks at the NPSKP value. If it is - zero, no skips are performed. If the NPSKP value - is greater than zero, that many parallel skips will - be performed before the code will then read out - NPR rows. - - So, if it is desired to read out a ROI with ystart=512 - and ylength=1024, NPSKP should be set to 512 and - NPR should be set to 1024 (divided by the binning - factor, of course). - --- 1.40 29 Jun 2004 - CRO - a.) Changed serial (binned)read to subroutine called - from main program getting the serial part of the - Region of Interest. - b.) Added subroutine for serial skips, SSKIP. - c.) To support serial ROI readout, added the following - parameters to Y: memory: - NSUND - Number of pixels in the CCD underscan - region. - NSSKP - Number of pixels to skip to the ROI - start pixel. - NSRD - Number of pixels to read in the ROI. - NSSKP2 - Number of pixels to skip from the end. - of the ROI to the end of the CCD. - NSOCK - Number of pixels of overscan to read. - - In order to read out a region of interest (ROI) - something like the following must be done, for example: - - setroi xstart=512 xlen=1024 ystart=512 ylen=1024 - - Then the ROI parameters in Y memory should be set according to the - following: - - NPSKP = ystart - NPR = ylen/(binning factor) - NSSKP = xstart - NSRD = xlen/(binning factor) - NSSKP2 = (CCD size in X) - (xstart + xlen) - - (Question: should we just use NSR for NSRD and just get rid - of NSRD?) - - Also, it one wishes to change the number of post or over- - scan pixels for each row to read, one must update the - NSOCK parameter for a ROI readout to be correct. - (Probably could fix the code so that this is not - necessary.) --- 1.41 10 Aug 2004 - MB - Added the variable NP2READ (NUmber of Pixels to read), which - replaces the R5 (or R0) register for storing the amount of pixels - to be read inside the SREAD and SSKIP subroutines --- 1.42 16 Jan 2005 - MB - Copied to DBSP directory - - * - PAGE 132 ; Printronix page width - 132 columns - -; Include the boot and header files so addressing is easy - INCLUDE "timhdr.asm" - INCLUDE "timboot.asm" - - ORG P:,P: - -CC EQU CCDVIDREV5+TIMREV5+UTILREV3+SHUTTER_CC+TEMP_POLY - -; Put number of words of application in P: for loading application from EEPROM - DC TIMBOOT_X_MEMORY-@LCV(L)-1 - -; senal de control out0 -; BSET #EXT_OUT0,X:HDR ; sube pata de control out0 -; BCLR #EXT_OUT0,X:HDR ; baja pata de control out0 - -; Set software to IDLE mode -START_IDLE_CLOCKING - MOVE #IDLE,R0 ; Exercise clocks when idling - MOVE R0,X: NO ROI -; -; This is a serial ROI read so here we go -; The (binned) pre pixels first -; -ROI - MOVE Y: R0 -; The binning appears here only to make up the total amount of skips, since -; the skip calculation is based upon binned detector coordinates -; Note that the waveform called inside the binning loop is the same skip -; routine -SSKIP - MOVE A1,Y:1.4) -NPSKP DC 0 ; number of lines to skip to get to ROI -NSUND DC 24 ; number of underscan (prescan) pixels -NSSKP DC 0 ; number of pixels to skip to get to ROI -NSRD DC 2048 ; number of pixels to read in the ROI -NSSKP2 DC 0 ; number of pixels to skip to get to overscan -NSOCK DC 64 ; number of overscan (bias) pixels -NP2READ DC 0 ; number of overscan (bias) pixels -NSDATA DC 2048 ; number of data (bias) pixels -NSTST DC 0 ; number of data (bias) pixels -NPTST DC 0 ; number of data (bias) pixels -; -; Note: NSR = 2048 + NSUND (default=24) + NSOCK (default=64) -; - -; Include the waveform table for the designated type of CCD - INCLUDE "CCD44-82.waveforms" ; Readout and clocking waveform file - -END_APPLICATON_Y_MEMORY EQU @LCV(L) - -; End of program - END diff --git a/DSP/DBSP-blue/tim.lod b/DSP/DBSP-blue/tim.lod deleted file mode 100644 index a4bae293..00000000 --- a/DSP/DBSP-blue/tim.lod +++ /dev/null @@ -1,601 +0,0 @@ -_START TIM 0000 0000 0000 DSP56300 6.3.4 - -_DATA P 000000 -0C0115 000000 609E00 018FA0 0002D3 0A00A4 0001D0 0AE080 -330700 0D003D 0E0009 03FBD6 0D007F 0E8028 578600 000000 -01418C 000000 06CF00 000016 0D003D 0E0014 000000 63F400 -000007 000000 000000 0203DF 205B00 205B00 302200 062180 -000026 47D800 62E07D 0E2026 00008C 0AE280 205800 0C0028 -479C00 0C002B 479700 578500 469B00 330700 46925E 0C1ED1 -460600 469858 200058 000000 575B00 475B00 330700 060600 -00003B 57DB00 0D006B 000000 0C0002 0A8989 000067 0A8989 -000042 0C0045 0A8989 000067 0C003F 0A8989 00003F 08F4BB -028FE2 000000 000000 5FF000 FFFFF1 2B0000 0140CE 0000FF -0140CD 0000AC 0E2067 4EF000 FFFFF1 0C1951 008010 4EF000 -FFFFF1 0C1951 008008 4EF000 FFFFF1 0C1951 008000 000000 -515B00 000000 000000 0AF960 08F4BB 028FE1 00000C 0AF940 -08F4BB 028FE1 00000C 08F4BB 028FE2 60F400 000002 060380 -000073 0C1D91 000000 535800 60F400 000001 61F400 FFFFF2 -060480 00007B 46D800 4E6100 08F4BB 028FE1 00000C 579500 -20005E 0E208F 579600 20005E 0EA08F 579400 20005E 0EA08F -460500 550600 000000 000000 0AF940 000000 00000C 0AF960 -000000 00000C 47DB00 0C002B 47DB00 20EF00 0140CE 0FFFFF -21B000 20EF00 000000 0ACF14 00009F 07E087 0C002B 0ACF15 -0000A3 47E000 0C002B 0ACF16 0000A7 4FE000 0C002B 0ACF17 -000028 479300 220600 2000B8 20002A 213000 0AD06F 0D00FD -21A700 0C002B 47DB00 20EF00 0140CE 0FFFFF 21B000 20EF00 -46DB00 0ACF14 0000BD 076086 0C002A 0ACF15 0000C1 466000 -0C002A 0ACF16 0000C5 4E6000 0C002A 0ACF17 000028 013D02 -460E00 479300 220600 2000B8 20002A 213000 0AD06F 558E00 -060380 0000D9 07588D 0C1C91 469D00 06C600 0000D8 060CA0 -000000 000000 013D22 0C002A 47DB00 0D00DF 0C002A 60F400 -008000 0D00FD 21A600 479300 2000B8 20002A 213000 0AD06F -0D00FD 61F400 000193 06CD00 0000EE 0D00FD 07598D 0D00FD -61F400 000030 06CD00 0000F5 0D00FD 555900 0D00FD 310100 -06CD00 0000FB 0D00FD 5D5900 00000C 060380 000100 07D88B -0C1C91 00000C 300800 601E00 0A0002 0C002A 300800 601E00 -44F400 00C350 06C400 00010D 06E8A3 000000 57F400 020002 -0D006B 57F400 535952 0D006B 0C0002 08F4BD 050003 000000 -0500BA 0500BB 08F4B9 FFFC21 08F4B8 008909 08F4B7 010C11 -08F4B6 080621 08F4BB 028FE2 08F484 000001 08F489 00010C -08F488 00B10E 07F43F 000000 07F435 000809 07F436 010130 -07F43F 000000 07F43E 000017 07F43D 000005 07F42F 000000 -07F425 000809 07F426 000030 07F42F 000020 07F42E 000004 -07F42D 000004 07F42C 000000 000000 000000 012630 07F41F -000000 07F41E 000002 07F41D 000002 07F403 00C34F 07F40F -208000 07F40E 000000 08F4BF 000000 05F439 000300 061480 -00015C 5FF000 FFFFF1 0605A0 000000 44F400 0F4240 06C400 -000161 000000 0A8908 0614A0 000000 0A8928 012F23 56F400 -0C3000 20001B 241000 45F400 001000 060F80 000175 0D017C -200040 5F7000 FFFFF3 0620A3 000000 200068 0A0F00 0A0F02 -09F0B5 00000F 012F03 0C0190 547000 00000E 01A786 00017E -07F42C 010000 060380 000188 01A786 000184 04CCCC 0C1E90 -000000 01A786 000189 07F42C 000000 54F000 00000E 00000C -44F400 0000AC 440100 0C0106 -_DATA X 000000 -001064 -_DATA X 00000F -00007A 000000 000001 000002 000003 000007 FCFCF8 030300 -444F4E 020000 000200 00FF00 FF0000 455252 0186A0 000008 -000000 000000 000000 -_DATA X 000022 -54444C 000092 52444D 000094 57524D 0000B2 4C4441 0000DC -535450 000102 444F4E 000002 455252 000002 -_DATA P 000194 -0002B2 60F400 00019A 601E00 0A0022 0C002A 302700 0D037A -060240 0001A5 302900 0D037A 330700 0D003D 0E01A5 00008C -0C000B 000000 303000 0D037A 0C019A 5E8600 449100 200044 -000000 5C0C00 060540 0001B2 303300 0D037A 000000 5E8E00 -200003 0EA1BF 302700 0D037A 06CC00 0001BC 302900 0D037A -000000 303000 0D037A 5E8200 000000 06CC00 0001ED 060740 -0001C7 301F00 0D037A 000000 330700 0D003D 0E01D0 0C0312 -0A0084 000334 00008C 0C0321 5E9000 200003 0AF0AA 0001D6 -0AF080 0001DA 5E9200 200003 0AF0AA 0001EB 5E8F00 0D01F9 -000000 5E9000 0D020F 000000 5E9100 0D01F9 000000 5E9200 -0D020F 000000 5E9300 0D01F9 000000 0AF080 0001ED 5E8100 -0D01F9 000000 0A0082 0001F4 60F400 00019A 601E00 0C01F6 -300800 601E00 0D0377 0A0004 0C0002 5C1400 5E8C00 200003 -0EA209 061440 000207 060C40 000203 303C00 0D037A 000000 -304300 0D037A 000000 000000 0C020E 061440 00020D 304300 -0D037A 000000 00000C 5C1400 5E8C00 200003 0EA21E 061440 -00021C 060C40 000219 303300 0D037A 000000 303300 0D037A -000000 0C0223 061440 000222 303300 0D037A 000000 00000C -_DATA P 000224 -47DB00 4F0F00 47DB00 4F1500 47DB00 4F1300 0D023A 0C002A -56DB00 449100 200044 000000 5C1000 56DB00 200044 000000 -5C0E00 56DB00 000000 5E1100 0D023A 0C002A 5E9500 4C9000 -200044 4C9100 200044 000000 5C1200 00000C 47DB00 4F0600 -47DB00 4F0700 0C002A 5E8B00 200023 000000 06CC00 00024E -301F00 0D037A 000000 000000 0C002A 0D0287 0A8922 0A8923 -0C002A 0D0287 0A8902 44F400 1E8480 06C400 00025B 000000 -0A8903 44F400 1E8480 06C400 000261 000000 0A8980 000269 -0D026C 60F400 00019A 601E00 0C002A 0A8922 0A8923 0C0028 -012F23 0A0F01 0A0F20 0A0F22 09F0B5 00000F 0D0385 60F400 -00007E 000000 000000 065840 00027B 5ED800 0D017C 000000 -44F400 061A80 06C400 000280 000000 012F03 00000C 0D026C -0C002A 0D0287 0C002A 0A0F00 0A0F02 09F0B5 00000F 012F23 -56F400 0C3000 20001B 241000 45F400 001000 060F80 000299 -0D017C 200040 5F7000 FFFFF3 0D0385 200068 012F03 00000C -568F00 0140C6 00FFEF 200042 000000 540F00 09CC35 00000C -240000 0D029C 0C002A 44F400 000010 0D029C 0C002A 240000 -0D029C 00000C 44F400 000010 0D029C 00000C 0D02B4 0C002A -4C8400 06C400 0002BA 60F400 000018 0D037A 000000 060540 -0002BF 303300 0D037A 000000 0D003D 00000C 07F40E 000000 -579000 20000B 0EA2D7 0A008B 0002CA 0D02AB 01418C 010F20 -577000 FFFF8D 330700 0A8989 0002D3 0D003D 0E800B 018F95 -0002CE 010F00 0AE780 44F400 004E20 06C400 0002DB 000000 -0C02D5 57F400 020102 0D006B 57F400 494941 0D006B 0D023A -0A00A8 0002E7 0D02B4 300800 601E00 67F400 0002EC 0C02C2 -0D036A 0A0024 0A008B 0002FC 0D02AE 5E8900 200003 0EF2FC -44F400 0186A0 06CE00 0002FB 06C400 0002FA 000000 000000 -0A00AA 000337 0C01A9 46DB00 461000 07F00D 000010 0C002A -47F000 FFFF8C 0C002B 010F00 0D02AE 0C002A 010F29 07700C -FFFF8E 010F20 0A008B 000311 0D02AB 0C002A 44DB00 56F400 -000202 200045 0E231E 0D003D 0E0317 44DB00 56F400 414252 -200045 0EA1CC 330700 227400 0C01D0 44F400 0186A0 06C400 -000325 000000 0A0082 00032C 60F400 00019A 601E00 0C032E -300800 601E00 0D0377 0A0004 44F400 000202 440500 0C002A -010F00 0D02AE 0C01EE 200013 060240 000343 060140 000342 -0614A0 000000 014180 000000 21CF00 0D0345 000000 000000 -0C01EE 0C1DA1 000000 216500 0C1D91 000000 216400 000000 -09C532 09C432 00000C 57F000 010002 0C1DA1 000000 216500 -0C1D91 000000 216400 000000 09C532 09C432 060AA0 000000 -57F000 010003 0C1DA1 000000 216500 0C1D91 000000 216400 -000000 09C532 09C432 060AA0 000000 00000C 57F400 020104 -0D006B 57F400 524441 0D006B 5FF000 000001 0D006B 5FF000 -000002 0D006B 00000C 01ADA1 000377 00000C 0A898E 00037A -000000 0A898E 00037A 4CD800 06C400 000382 09D8F3 000000 -00000C 062083 000387 000000 000000 00000C 4F8A00 0C002B -012F23 56DB00 44F400 000001 200045 0E2395 57F400 000077 -0C03A9 44F400 000002 200045 0E239C 57F400 0000BB 0C03A9 -44F400 000005 200045 0E23A3 57F400 0000DD 0C03A9 44F400 -00000A 200045 0E2028 57F400 0000EE 56DB00 000000 0ACC00 -0003B0 0ACD68 000000 0ACD69 44F400 0C3C00 20004A 000000 -5F0000 241000 21EE00 060F80 0003BB 0D017C 0D0385 200048 -012F03 0C002A 56DB00 0C0028 012F23 44DB00 0AC420 0003C7 -0A004A 0A004B 0C03C9 0A006A 0A006B 241000 060F80 0003CF -5E8000 0D017C 0D0385 200048 012F03 0C002A 012F23 56DB00 -0614A0 200033 000000 21C400 56DB00 060EA0 200033 200042 -57DB00 44F400 564944 20004D 0E23E5 0ACC73 000000 0ACC72 -0C03E9 44F400 434C4B 20004D 0E23F3 21C400 56DB00 46F400 -000FFF 200056 200042 0D017C 0D0385 012F03 0C002A 56DB00 -012F03 0C0028 012F23 56DB00 0614A0 200033 44F400 003000 -200042 000000 21C500 56DB00 0AF0A9 000444 44F400 000018 -200045 0AF0A1 000444 21CF00 44F400 000007 20004E 44F400 -000018 200046 0E2411 0ACD63 0C041C 44F400 000008 200045 -0E2417 0ACD64 0C041C 44F400 000010 200045 0E2444 0ACD65 -20006A 000000 21A700 56DB00 0E9028 44F400 000018 200045 -0E1028 0606A0 200033 000000 21CF00 44F400 0001C0 20004E -44F400 000600 200046 0E2432 0ACD69 0C043D 44F400 000200 -200045 0E2438 0ACD6A 0C043D 44F400 000400 200045 0E2028 -0ACD6B 200078 000000 21AE00 0D017C 0D0385 012F03 0C002A -56DB00 012F03 0C0028 -_DATA X 000030 -504F4E 000255 504F46 000251 534256 000283 49444C 000195 -4F5348 0002A4 435348 0002A7 524443 0002EC 434C52 0002B2 -505348 000247 42494E 000242 47454F 000224 524F49 00022C -534554 0002FF 524554 000304 534558 0002DD 504558 000307 -524558 00030A 414558 000334 414252 0001CC 435244 0001D0 -53474E 00038C 534443 0003C0 53424E 0003D2 534D58 0003F6 -435357 000285 524343 00038A -_DATA Y 000000 -0000B9 000858 000800 00003C 000400 000834 000001 000001 -000000 000032 0001B4 000040 000000 00008C 000000 000018 -000000 000800 000000 000040 000000 000800 000000 000000 -_DATA Y 000018 -000006 B8200E B8200C B8200D B82009 B8200B B8200A 000007 -0931BF B82006 B82004 B82005 B82001 B82003 B82002 000001 -0931BF 000006 B8200E B8200C B8200D B82009 B8200B B8200A -000002 093180 B82002 000008 000074 03301B 03300A 000076 -0331EE 0331E4 0331F5 033011 000006 09303F 09302E 09306E -093064 093075 093035 00001E 000017 000007 09303F 09302E -09306E 093064 093075 093035 3F3035 00001B 093011 043035 -00000B 093035 093035 093035 093035 093035 093035 3F3035 -00001B 0731B5 00003B 00003B 00003B 003035 040076 110074 -00F000 033035 00001B 000017 000007 09303F 09302E 09306E -093064 093075 093035 3F3035 00001B 093011 043035 00000B -093035 093035 093035 093035 093035 093035 3F3035 00001B -0731B5 00003B 003035 040076 110074 033035 00003B 2A0080 -200189 200222 200489 200822 202089 204022 20809E 210022 -220189 220222 220422 220822 222022 224022 228022 230022 -240122 240222 240422 240822 242022 244022 248022 250022 -260194 26022D 260494 26082D 262094 264022 268094 27002D -280194 28022D 280494 280822 282094 28402D 28809E 290060 -2A019E 2A0260 2A0422 2A0822 2A2022 2A4022 2A8022 2B0022 -0C3F77 0C45DF 0CC641 0D093F 0D4A98 0D8412 0DC412 0E0B07 -0F8333 0FC599 -_SYMBOL P -START I 000002 -TST_RCV I 000008 -PRC_RCV I 00000B -L_GET_COMMAND I 000017 -COMMAND I 000017 -NOT_COM I 000026 -END_COM I 000027 -ERROR I 000028 -FINISH I 00002A -FINISH1 I 00002B -DON_FFO I 00003C -GET_RCV I 00003D -TST1 I 00003F -TST2 I 000042 -TST3 I 000045 -CLR_RTS I 000067 -XMT_WRD I 00006B -XMT_WRD1 I 000074 -XMT_WRD2 I 00007C -CHK_HDR I 00007F -CHK_ERR I 00008F -TDL I 000092 -RDMEM I 000094 -RDX I 00009F -RDY I 0000A3 -RDR I 0000A7 -WRMEM I 0000B2 -WRX I 0000BD -WRY I 0000C1 -WRR I 0000C5 -L2WRR I 0000D9 -L1WRR I 0000DA -LDAPPL I 0000DC -LOAD_APPLICATION I 0000DF -RD_APPL_P I 0000EF -RD_APPL_X I 0000F6 -RD_APPL_Y I 0000FC -RD_WORD I 0000FD -L_RDBYTE I 000101 -STOP_IDLE_CLOCKING I 000102 -STARTUP I 000106 -L_DELAY I 00010E -INIT I 000115 -L_FO_INIT I 00015D -L_ANALOG I 000176 -XMIT_A_WORD I 00017C -L_XMIT I 000189 -SKIP I 000190 -X_BOOT_START I 000192 -START_IDLE_CLOCKING I 000195 -IDLE I 00019A -NO_COM1 I 0001A5 -END_DUMP I 0001A6 -RDCCD I 0001A9 -LPSKP I 0001BD -NOSKIP I 0001BF -LPBIN I 0001C8 -ABR_RDC I 0001CC -CONT_RD I 0001D0 -NOPRESKP I 0001D6 -ROI I 0001DA -NOROI I 0001EB -ENDLINE I 0001ED -LPR I 0001EE -RDC_END I 0001EE -NO_IDL I 0001F4 -RDC_E I 0001F6 -SREAD I 0001F9 -LSBIN I 000204 -LSR1 I 000208 -NOTBIN I 000209 -LSR2 I 00020E -NEXTROW I 00020E -SSKIP I 00020F -LSBIN2 I 00021A -LSK I 00021D -NOTBINSKP I 00021E -LKS2 I 000223 -SET_GEOMETRY I 000224 -SET_ROI I 00022C -CALC_GEOM I 00023A -SBINN I 000242 -P_SHIFT I 000247 -LSH I 00024F -POWER_OFF I 000251 -POWER_ON I 000255 -PWR_ERR I 000269 -SET_BIASES I 00026C -L_DAC I 00027C -SET_BIAS_VOLTAGES I 000283 -CLR_SWS I 000285 -CLEAR_SWITCHES_AND_DACS I 000287 -L_VIDEO I 00029A -SET_SHUTTER_STATE I 00029C -OPEN_SHUTTER I 0002A4 -CLOSE_SHUTTER I 0002A7 -OSHUT I 0002AB -CSHUT I 0002AE -CLEAR I 0002B2 -CLR_CCD I 0002B4 -LPCLR2 I 0002BB -LSCLR2 I 0002C0 -EXPOSE I 0002C2 -L_SEX0 I 0002CA -CHK_RCV I 0002CE -EXP1 I 0002D3 -CHK_TIM I 0002D3 -END_EXP I 0002D5 -ZERO_EXP I 0002D7 -END_DELAY I 0002DC -START_EXPOSURE I 0002DD -NOT_CLR_ARRAY I 0002E7 -L_SEX1 I 0002EC -STR_RDC I 0002EC -S_DEL1 I 0002FB -S_DEL0 I 0002FC -SET_EXPOSURE_TIME I 0002FF -READ_EXPOSURE_TIME I 000304 -PAUSE_EXPOSURE I 000307 -RESUME_EXPOSURE I 00030A -L_RES I 000311 -CHK_ABORT_COMMAND I 000312 -WT_COM I 000317 -RD_CONT I 00031E -RDCCD_END_ABORT I 000321 -NO_IDL2 I 00032C -RDC_E2 I 00032E -ABORT_EXPOSURE I 000334 -SYNTHETIC_IMAGE I 000337 -LSR_TST I 000343 -LPR_TST I 000344 -XMT_PIX I 000345 -READ_AD I 00034F -PCI_READ_IMAGE I 00036A -WAIT_TO_FINISH_CLOCKING I 000377 -CLOCK I 00037A -CLK1 I 000383 -PAL_DLY I 000385 -DLY I 000388 -READ_CONTROLLER_CONFIGURATION I 00038A -ST_GAIN I 00038C -STG2 I 000395 -STG5 I 00039C -STG10 I 0003A3 -STG_A I 0003A9 -STG_B I 0003B0 -STG_LOOP I 0003BC -ERR_SGN I 0003BE -SET_DC I 0003C0 -SDC_1 I 0003C7 -SDC_A I 0003C9 -SDC_LOOP I 0003D0 -SET_BIAS_NUMBER I 0003D2 -CLK_DRV I 0003E5 -VID_BRD I 0003E9 -ERR_SBN I 0003F3 -SET_MUX I 0003F6 -SMX_1 I 000411 -SMX_2 I 000417 -SMX_A I 00041C -SMX_3 I 000432 -SMX_4 I 000438 -SMX_B I 00043D -ERR_SM1 I 000444 -TIMBOOT_X_MEMORY I 000447 -EXPOSING I 0002D3 -CONTINUE_READING I 0001D0 -_SYMBOL N -BCR I FFFFFB -AAR0 I FFFFF9 -AAR1 I FFFFF8 -AAR2 I FFFFF7 -AAR3 I FFFFF6 -PCTL I FFFFFD -IPRP I FFFFFE -IPRC I FFFFFF -PCRE I FFFF9F -PRRE I FFFF9E -PDRE I FFFF9D -SCR I FFFF9C -SCCR I FFFF9B -SRXH I FFFF9A -SRXM I FFFF99 -SRXL I FFFF98 -STXH I FFFF97 -STXM I FFFF96 -STXL I FFFF95 -STXA I FFFF94 -SSR I FFFF93 -SCITE I 000009 -SCIRE I 000008 -TRNE I 000000 -TDRE I 000001 -RDRF I 000002 -SELSCI I 00000F -TDE I 000006 -RDF I 000007 -TE I 000010 -PLL_INIT I 050003 -HPCR I FFFFC4 -HDR I FFFFC9 -HDDR I FFFFC8 -PCRC I FFFFBF -PRRC I FFFFBE -PDRC I FFFFBD -TX00 I FFFFBC -RX0 I FFFFB8 -SSISR0 I FFFFB7 -CRB0 I FFFFB6 -CRA0 I FFFFB5 -PCRD I FFFFAF -PRRD I FFFFAE -PDRD I FFFFAD -TX10 I FFFFAC -SSISR1 I FFFFA7 -CRB1 I FFFFA6 -CRA1 I FFFFA5 -TCSR0 I FFFF8F -TLR0 I FFFF8E -TCPR0 I FFFF8D -TCR0 I FFFF8C -TPLR I FFFF83 -TPCR I FFFF82 -TIM_BIT I 000000 -TRM I 000009 -TCF I 000015 -RDFO I FFFFF1 -WRFO I FFFFF2 -WRSS I FFFFF3 -WRLATCH I FFFFF5 -RDAD I 010000 -EF I 000009 -PWROK I 000000 -LED1 I 000001 -LVEN I 000002 -HVEN I 000003 -SSFHF I 00000E -EXT_IN0 I 00000A -EXT_IN1 I 00000B -EXT_OUT0 I 00000C -EXT_OUT1 I 00000D -SSFEF I 000001 -WRENA I 000002 -CDAC I 000000 -ENCK I 000002 -SHUTTER I 000004 -TIM_U_RST I 000005 -ST_RCV I 000000 -IDLMODE I 000002 -ST_SHUT I 000003 -ST_RDC I 000004 -SPLIT_S I 000005 -SPLIT_P I 000006 -MPP I 000007 -NOT_CLR I 000008 -TST_IMG I 00000A -SHUT I 00000B -ST_DITH I 00000C -SCI_TABLE I 000400 -CCDVIDREV3B I 000000 -VIDGENI I 000001 -IRREV4 I 000002 -COADDER I 000003 -CCDVIDREV5 I 000004 -TIMREV4 I 000000 -TIMGENI I 000008 -TIMREV5 I 000010 -UTILREV3 I 000020 -SHUTTER_CC I 000080 -TEMP_POLY I 000100 -TEMP_LINEAR I 000200 -SUBARRAY I 000400 -BINNING I 000800 -SPLIT_SERIAL I 001000 -SPLIT_PARALLEL I 002000 -MPP_CC I 004000 -CLKDRVGENI I 018000 -MLO I 020000 -NGST I 040000 -_SYMBOL X -STATUS I 000000 -FO_HDR I 000001 -HEADER I 000005 -NWORDS I 000006 -COM_BUF I 000007 -SV_A1 I 00000E -LATCH I 00000F -EXPOSURE_TIME I 000010 -ONE I 000011 -TWO I 000012 -THREE I 000013 -SEVEN I 000014 -MASK1 I 000015 -MASK2 I 000016 -DONE I 000017 -SBRD I 000018 -DBRD I 000019 -DMASK I 00001A -SMASK I 00001B -ERR I 00001C -C100K I 00001D -IDL_ADR I 00001E -EXP_ADR I 00001F -COM_TBL_R I 000022 -COM_TBL I 000022 -END_COMMAND_TABLE I 000030 -END_ADR I 000030 -_SYMBOL N -CC I 0001B4 -_SYMBOL X -END_APPLICATON_COMMAND_TABLE I 000064 -_SYMBOL N -NUM_COM I 000021 -_SYMBOL Y -GAIN I 000000 -NSR I 000001 -NPR I 000002 -NS_DEL I 000003 -NPCLR I 000004 -NSCLR I 000005 -NSBIN I 000006 -NPBIN I 000007 -TST_DAT I 000008 -SHDEL I 000009 -CONFIG I 00000A -NPSHF I 00000B -NSBINM1 I 00000C -VERSION I 00000D -NPSKP I 00000E -NSUND I 00000F -NSSKP I 000010 -NSRD I 000011 -NSSKP2 I 000012 -NSOCK I 000013 -NP2READ I 000014 -NSDATA I 000015 -NSTST I 000016 -NPTST I 000017 -_SYMBOL N -CLKAD I 200000 -VIDEO I 000000 -CLK2 I 002000 -CLK3 I 003000 -P_DLY I B80000 -S_DLY I 090000 -SS_DLY I 030000 -SW_DLY I 040000 -NS_CLR I 000834 -NP_CLR I 000400 -SH_DEL I 000032 -ADC_DLY I 070000 -RG_DLY I 040000 -CNV_DLY I 110000 -DCR_DLY I 030000 -INT_DLY I 3F0000 -P_HI F 1.000000E+000 -P_LO F -9.000000E+000 -RG_HI F 3.000000E+000 -RG_LO F -3.000000E+000 -S_HI F 2.000000E+000 -S_LO F -8.000000E+000 -SW_HI F 2.000000E+000 -SW_LO F -9.000000E+000 -DG_HI F 3.000000E+000 -DG_LO F -9.000000E+000 -ZERO F -9.000000E+000 -CLKmax F 1.240000E+001 -BOD F 2.000000E+001 -BJD I 000016 -BRDL F 8.000000E+000 -BRDR F 8.000000E+000 -BDD F 1.500000E+001 -BOG1 F -6.000000E+000 -BOG2 F -3.000000E+000 -OFFSET0 I 0005DF -OFFSET1 I 000641 -P1 I 000001 -P2 I 000002 -P3 I 000004 -H_DG I 000008 -L_DG I 000000 -S1L I 000001 -S2L I 000002 -SWL I 000004 -S1R I 000008 -S2R I 000010 -SWR I 000020 -S3 I 000040 -RGL I 000080 -RGR I 000100 -_SYMBOL Y -PARALLEL_CLEAR I 000018 -END_PARALLEL_CLEAR I 00001F -PARALLEL_SHIFT I 00001F -END_PARALLEL_SHIFT I 000027 -PREPARE_DUMP I 000027 -END_PREPARE_DUMP I 000029 -PARALLEL_DUMP I 000029 -END_PARALLEL_DUMP I 000030 -CLEAR_READ_REGISTER I 000030 -END_CLEAR_READ_REGISTER I 000033 -SERIAL_SKIP I 000033 -END_SERIAL_SKIP I 00003C -SERIAL_SHIFT I 00003C -END_SERIAL_SHIFT I 000043 -SERIAL_READ I 000043 -END_SERIAL_READ I 000062 -DUMMY_READ I 000062 -END_DUMMY_READ I 00007E -DACS I 00007E -END_DACS I 0000BA -END_APPLICATON_Y_MEMORY I 0000BA - -_END 000000 diff --git a/DSP/DBSP-blue/tim.ls b/DSP/DBSP-blue/tim.ls deleted file mode 100644 index 5533b70e..00000000 --- a/DSP/DBSP-blue/tim.ls +++ /dev/null @@ -1,2672 +0,0 @@ -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 12:03:41 tim.asm Page 1 - - - -1 COMMENT * -2 This file is used to generate boot DSP code for -3 the 250 MHz fiber optic timing board, SDSU GenII TIMII, -4 processor = DSP56303. -5 -6 Revision History: -7 -- 0.00: 10 Jun 2004 - CRO. -8 Original code from Dani Guzman. -9 -10 -- 1.10: 11 Jun 2004 - CRO. -11 a.) Cleanup. Some spanish-english comment translation. -12 b.) Y:00000B memory location reserved for NPSHF, the number -13 of rows to parallel shift for the PSH command (which -14 is new). This is implimented as part of a focus loop -15 in which a series of exposures are made at different -16 telescope (or spectrograph) focus positions and the CCD -17 charge is shifted some number of rows (NPSHF) between -18 each exposure. At the end of the loop an image with a -19 sequence of star images at different telescope focus -20 positions is read out. -21 -22 -- 1.20: 23 Jun 2004 - CRO -23 a.) Added nested do loops in RDCCD for parallel and serial -24 binning. Added NSBINM1 to Y: memory. This is the -25 serial binning factor minus one, used because he serial -26 binning and readout is split into two parts, one -27 for serial shift only and the last for a serial shift -28 and video processing. So, the first part is executed -29 NSBINM1 times; the last part, once. -30 -31 -- 1.30: 24 Jun 2004 - CRO -32 a.) Added version number to Y memory so that it is possible -33 to check which version of code is downloaded into -34 the timing board DSP by reading that memory location -35 Y:00000D. -36 b.) Added NPSKP (Y:00000E) and NSSKP (Y:00000F) to Y memory, -37 the number of parallel and serial skips for ROI readout. -38 c.) Added ROI parallel skipping code just before the start -39 of the binned readout. -40 -41 In order to specify the number of parallel skips, -42 the program looks at the NPSKP value. If it is -43 zero, no skips are performed. If the NPSKP value -44 is greater than zero, that many parallel skips will -45 be performed before the code will then read out -46 NPR rows. -47 -48 So, if it is desired to read out a ROI with ystart=512 -49 and ylength=1024, NPSKP should be set to 512 and -50 NPR should be set to 1024 (divided by the binning -51 factor, of course). -52 -53 -- 1.40 29 Jun 2004 - CRO -54 a.) Changed serial (binned)read to subroutine called -55 from main program getting the serial part of the -56 Region of Interest. -57 b.) Added subroutine for serial skips, SSKIP. -58 c.) To support serial ROI readout, added the following -59 parameters to Y: memory: -60 NSUND - Number of pixels in the CCD underscan -61 region. -62 NSSKP - Number of pixels to skip to the ROI -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 12:03:41 tim.asm Page 2 - - - -63 start pixel. -64 NSRD - Number of pixels to read in the ROI. -65 NSSKP2 - Number of pixels to skip from the end. -66 of the ROI to the end of the CCD. -67 NSOCK - Number of pixels of overscan to read. -68 -69 In order to read out a region of interest (ROI) -70 something like the following must be done, for example: -71 -72 setroi xstart=512 xlen=1024 ystart=512 ylen=1024 -73 -74 Then the ROI parameters in Y memory should be set according to the -75 following: -76 -77 NPSKP = ystart -78 NPR = ylen/(binning factor) -79 NSSKP = xstart -80 NSRD = xlen/(binning factor) -81 NSSKP2 = (CCD size in X) - (xstart + xlen) -82 -83 (Question: should we just use NSR for NSRD and just get rid -84 of NSRD?) -85 -86 Also, it one wishes to change the number of post or over- -87 scan pixels for each row to read, one must update the -88 NSOCK parameter for a ROI readout to be correct. -89 (Probably could fix the code so that this is not -90 necessary.) -91 -- 1.41 10 Aug 2004 - MB -92 Added the variable NP2READ (NUmber of Pixels to read), which -93 replaces the R5 (or R0) register for storing the amount of pixels -94 to be read inside the SREAD and SSKIP subroutines -95 -- 1.42 16 Jan 2005 - MB -96 Copied to DBSP directory -97 -98 * -99 PAGE 132 ; Printronix page width - 132 columns -100 -101 ; Include the boot and header files so addressing is easy -102 INCLUDE "timhdr.asm" -103 COMMENT * -104 -105 This is a header file that is shared between the fiber optic timing board -106 boot and application code files for Rev. 5 = 250 MHz timing boards -107 * -108 -109 PAGE 132 ; Printronix page width - 132 columns -110 -111 ; Various addressing control registers -112 FFFFFB BCR EQU $FFFFFB ; Bus Control Register -113 FFFFF9 AAR0 EQU $FFFFF9 ; Address Attribute Register, channel 0 -114 FFFFF8 AAR1 EQU $FFFFF8 ; Address Attribute Register, channel 1 -115 FFFFF7 AAR2 EQU $FFFFF7 ; Address Attribute Register, channel 2 -116 FFFFF6 AAR3 EQU $FFFFF6 ; Address Attribute Register, channel 3 -117 FFFFFD PCTL EQU $FFFFFD ; PLL control register -118 FFFFFE IPRP EQU $FFFFFE ; Interrupt Priority register - Peripheral -119 FFFFFF IPRC EQU $FFFFFF ; Interrupt Priority register - Core -120 -121 ; Port E is the Synchronous Communications Interface (SCI) port -122 FFFF9F PCRE EQU $FFFF9F ; Port Control Register -123 FFFF9E PRRE EQU $FFFF9E ; Port Direction Register -124 FFFF9D PDRE EQU $FFFF9D ; Port Data Register -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 12:03:41 timhdr.asm Page 3 - - - -125 FFFF9C SCR EQU $FFFF9C ; SCI Control Register -126 FFFF9B SCCR EQU $FFFF9B ; SCI Clock Control Register -127 -128 FFFF9A SRXH EQU $FFFF9A ; SCI Receive Data Register, High byte -129 FFFF99 SRXM EQU $FFFF99 ; SCI Receive Data Register, Middle byte -130 FFFF98 SRXL EQU $FFFF98 ; SCI Receive Data Register, Low byte -131 -132 FFFF97 STXH EQU $FFFF97 ; SCI Transmit Data register, High byte -133 FFFF96 STXM EQU $FFFF96 ; SCI Transmit Data register, Middle byte -134 FFFF95 STXL EQU $FFFF95 ; SCI Transmit Data register, Low byte -135 -136 FFFF94 STXA EQU $FFFF94 ; SCI Transmit Address Register -137 FFFF93 SSR EQU $FFFF93 ; SCI Status Register -138 -139 000009 SCITE EQU 9 ; X:SCR bit set to enable the SCI transmitter -140 000008 SCIRE EQU 8 ; X:SCR bit set to enable the SCI receiver -141 000000 TRNE EQU 0 ; This is set in X:SSR when the transmitter -142 ; shift and data registers are both empty -143 000001 TDRE EQU 1 ; This is set in X:SSR when the transmitter -144 ; data register is empty -145 000002 RDRF EQU 2 ; X:SSR bit set when receiver register is full -146 00000F SELSCI EQU 15 ; 1 for SCI to backplane, 0 to front connector -147 -148 -149 ; ESSI Flags -150 000006 TDE EQU 6 ; Set when transmitter data register is empty -151 000007 RDF EQU 7 ; Set when receiver is full of data -152 000010 TE EQU 16 ; Transmitter enable -153 -154 ; Phase Locked Loop initialization -155 050003 PLL_INIT EQU $050003 ; PLL = 25 MHz x 2 = 100 MHz -156 -157 ; Port B general purpose I/O -158 FFFFC4 HPCR EQU $FFFFC4 ; Control register (bits 1-6 cleared for GPIO) -159 FFFFC9 HDR EQU $FFFFC9 ; Data register -160 FFFFC8 HDDR EQU $FFFFC8 ; Data Direction Register bits (=1 for output) -161 -162 ; Port C is Enhanced Synchronous Serial Port 0 = ESSI0 -163 FFFFBF PCRC EQU $FFFFBF ; Port C Control Register -164 FFFFBE PRRC EQU $FFFFBE ; Port C Data direction Register -165 FFFFBD PDRC EQU $FFFFBD ; Port C GPIO Data Register -166 FFFFBC TX00 EQU $FFFFBC ; Transmit Data Register #0 -167 FFFFB8 RX0 EQU $FFFFB8 ; Receive data register -168 FFFFB7 SSISR0 EQU $FFFFB7 ; Status Register -169 FFFFB6 CRB0 EQU $FFFFB6 ; Control Register B -170 FFFFB5 CRA0 EQU $FFFFB5 ; Control Register A -171 -172 ; Port D is Enhanced Synchronous Serial Port 1 = ESSI1 -173 FFFFAF PCRD EQU $FFFFAF ; Port D Control Register -174 FFFFAE PRRD EQU $FFFFAE ; Port D Data direction Register -175 FFFFAD PDRD EQU $FFFFAD ; Port D GPIO Data Register -176 FFFFAC TX10 EQU $FFFFAC ; Transmit Data Register 0 -177 FFFFA7 SSISR1 EQU $FFFFA7 ; Status Register -178 FFFFA6 CRB1 EQU $FFFFA6 ; Control Register B -179 FFFFA5 CRA1 EQU $FFFFA5 ; Control Register A -180 -181 ; Timer module addresses -182 FFFF8F TCSR0 EQU $FFFF8F ; Timer control and status register -183 FFFF8E TLR0 EQU $FFFF8E ; Timer load register = 0 -184 FFFF8D TCPR0 EQU $FFFF8D ; Timer compare register = exposure time -185 FFFF8C TCR0 EQU $FFFF8C ; Timer count register = elapsed time -186 FFFF83 TPLR EQU $FFFF83 ; Timer prescaler load register => milliseconds -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 12:03:41 timhdr.asm Page 4 - - - -187 FFFF82 TPCR EQU $FFFF82 ; Timer prescaler count register -188 000000 TIM_BIT EQU 0 ; Set to enable the timer -189 000009 TRM EQU 9 ; Set to enable the timer preloading -190 000015 TCF EQU 21 ; Set when timer counter = compare register -191 -192 ; Board specific addresses and constants -193 FFFFF1 RDFO EQU $FFFFF1 ; Read incoming fiber optic data byte -194 FFFFF2 WRFO EQU $FFFFF2 ; Write fiber optic data replies -195 FFFFF3 WRSS EQU $FFFFF3 ; Write switch state -196 FFFFF5 WRLATCH EQU $FFFFF5 ; Write to a latch -197 010000 RDAD EQU $010000 ; Read A/D values into the DSP -198 000009 EF EQU 9 ; Serial receiver empty flag -199 -200 ; DSP port A bit equates -201 000000 PWROK EQU 0 ; Power control board says power is OK -202 000001 LED1 EQU 1 ; Control one of two LEDs -203 000002 LVEN EQU 2 ; Low voltage power enable -204 000003 HVEN EQU 3 ; High voltage power enable -205 00000E SSFHF EQU 14 ; Switch state FIFO half full flag -206 00000A EXT_IN0 EQU 10 -207 00000B EXT_IN1 EQU 11 -208 00000C EXT_OUT0 EQU 12 -209 00000D EXT_OUT1 EQU 13 -210 -211 ; Port D equate -212 000001 SSFEF EQU 1 ; Switch state FIFO empty flag -213 -214 ; Other equates -215 000002 WRENA EQU 2 ; Enable writing to the EEPROM -216 -217 ; Latch U12 bit equates -218 000000 CDAC EQU 0 ; Clear the analog board DACs -219 000002 ENCK EQU 2 ; Enable the clock outputs -220 000004 SHUTTER EQU 4 ; Control the shutter -221 000005 TIM_U_RST EQU 5 ; Reset the utility board -222 -223 ; Software status bits, defined at X: CLR_RTS - 000042 -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 12:03:41 timboot.asm Page 8 - - - -429 P:000041 P:000041 0C0045 JMP try again -430 P:000042 P:000042 0A8989 TST2 JCLR #EF,X:HDR,CLR_RTS ; Low, High => try again - 000067 -431 P:000044 P:000044 0C003F JMP read FIFO -432 P:000045 P:000045 0A8989 TST3 JCLR #EF,X:HDR,TST1 - 00003F -433 -434 P:000047 P:000047 08F4BB MOVEP #$028FE2,X:BCR ; Slow down RDFO access - 028FE2 -435 P:000049 P:000049 000000 NOP -436 P:00004A P:00004A 000000 NOP -437 P:00004B P:00004B 5FF000 MOVE Y:RDFO,B - FFFFF1 -438 P:00004D P:00004D 2B0000 MOVE #0,B2 -439 P:00004E P:00004E 0140CE AND #$FF,B - 0000FF -440 P:000050 P:000050 0140CD CMP #>$AC,B ; It must be $AC to be a valid word - 0000AC -441 P:000052 P:000052 0E2067 JNE SR carry = 1 -453 P:000064 P:000064 08F4BB MOVEP #$028FE1,X:BCR ; Restore RDFO access - 028FE1 -454 P:000066 P:000066 00000C RTS -455 P:000067 P:000067 0AF940 CLR_RTS BCLR #0,SR ; Not valid FIFO word => SR carry = 0 -456 P:000068 P:000068 08F4BB MOVEP #$028FE1,X:BCR ; Restore RDFO access - 028FE1 -457 P:00006A P:00006A 00000C RTS -458 -459 ; Transmit the word in B1 to the host computer -460 P:00006B P:00006B 08F4BB XMT_WRD MOVEP #$028FE2,X:BCR ; Slow down RDFO access - 028FE2 -461 P:00006D P:00006D 60F400 MOVE #FO_HDR+1,R0 - 000002 -462 P:00006F P:00006F 060380 DO #3,XMT_WRD1 - 000073 -463 P:000071 P:000071 0C1D91 ASL #8,B,B -464 P:000072 P:000072 000000 NOP -465 P:000073 P:000073 535800 MOVE B2,X:(R0)+ -466 XMT_WRD1 -467 P:000074 P:000074 60F400 MOVE #FO_HDR,R0 - 000001 -468 P:000076 P:000076 61F400 MOVE #WRFO,R1 - FFFFF2 -469 P:000078 P:000078 060480 DO #4,XMT_WRD2 - 00007B -470 P:00007A P:00007A 46D800 MOVE X:(R0)+,Y0 ; Should be MOVEP X:(R0)+,Y:WRFO -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 12:03:41 timboot.asm Page 9 - - - -471 P:00007B P:00007B 4E6100 MOVE Y0,Y:(R1) -472 XMT_WRD2 -473 P:00007C P:00007C 08F4BB MOVEP #$028FE1,X:BCR ; Restore RDFO access - 028FE1 -474 P:00007E P:00007E 00000C RTS -475 -476 ; Check the command or reply header in Y0 for self-consistency -477 P:00007F P:00007F 579500 CHK_HDR MOVE X: 0 -485 P:000087 P:000087 0EA08F JEQ when not -614 P:000103 P:000103 601E00 MOVE R0,X: when not -620 P:000107 P:000107 601E00 MOVE R0,X:1,X:HPCR ; All pins enabled as GPIO - 000001 -655 P:000126 P:000126 08F489 MOVEP #$010C,X:HDR - 00010C -656 P:000128 P:000128 08F488 MOVEP #$B10E,X:HDDR ; Data Direction Register - 00B10E -657 ; (1 for Output, 0 for Input) -658 -659 ; Port B conversion from software bits to schematic labels -660 ; PB0 = PWROK PB08 = PRSFIFO* -661 ; PB1 = LED1 PB09 = EF* -662 ; PB2 = LVEN PB10 = EXT-IN0 -663 ; PB3 = HVEN PB11 = EXT-IN1 -664 ; PB4 = STATUS0 PB12 = EXT-OUT0 -665 ; PB5 = STATUS1 PB13 = EXT-OUT1 -666 ; PB6 = STATUS2 PB14 = SSFHF* -667 ; PB7 = STATUS3 PB15 = SELSCI -668 -669 ; Program the serial port ESSI0 = Port C for serial communication with -670 ; the utility board -671 P:00012A P:00012A 07F43F MOVEP #>0,X:PCRC ; Software reset of ESSI0 - 000000 -672 P:00012C P:00012C 07F435 MOVEP #$000809,X:CRA0 ; Divide 100 MHz by 20 to get 5.0 MHz - 000809 -673 ; DC[4:0] = 0 for non-network operation -674 ; WL0-WL2 = ALC = 0 for 2-bit data words -675 ; ALC = 0, SSC1 = 0 for SC1 not used -676 P:00012E P:00012E 07F436 MOVEP #$010130,X:CRB0 ; SCKD = 1 for internally generated clock - 010130 -677 ; SHFD = 0 for MSB shifted first -678 ; CKP = 0 for rising clock edge transitions -679 ; TE0 = 1 to enable transmitter #0 -680 ; MOD = 0 for normal, non-networked mode -681 ; FSL1 = 1, FSL0 = 0 for on-demand transmit -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 12:03:41 timboot.asm Page 13 - - - -682 P:000130 P:000130 07F43F MOVEP #%000000,X:PCRC ; Control Register (0 for GPIO, 1 for ESSI) - 000000 -683 ; SCK0 = P3, STD0 = P5 are ESSI0, turned OFF -684 P:000132 P:000132 07F43E MOVEP #%010111,X:PRRC ; Data Direction Register (0 for In, 1 for O -ut) - 000017 -685 P:000134 P:000134 07F43D MOVEP #%000101,X:PDRC ; Data Register - ROM/FIFO* = 0, WR_ENA* = 1 -, - 000005 -686 ; AUX1 = 0, AUX2 = AUX3 = 1 -687 -688 ; Conversion from software bits to schematic labels for Port C -689 ; PC0 = SC00 = UTL-T-SCK -690 ; PC1 = SC01 = 2_XMT = SYNC on prototype -691 ; PC2 = SC02 = WR_ENA* -692 ; PC3 = SCK0 = TIM-U-SCK -693 ; PC4 = SRD0 = UTL-T-SCD -694 ; PC5 = STD0 = TIM-U-STD -695 -696 ; Program the serial port ESSI1 = Port D for serial transmission to -697 ; the analog boards and two parallel I/O input pins -698 P:000136 P:000136 07F42F MOVEP #>0,X:PCRD ; Software reset of ESSI0 - 000000 -699 P:000138 P:000138 07F425 MOVEP #$000809,X:CRA1 ; Divide 100 MHz by 20 to get 5.0 MHz - 000809 -700 ; DC[4:0] = 0 -701 ; WL[2:0] = 000 for 8-bit data words -702 ; SSC1 = 0 for SC1 not used -703 P:00013A P:00013A 07F426 MOVEP #$000030,X:CRB1 ; SCKD = 1 for internally generated clock - 000030 -704 ; SCD2 = 1 so frame sync SC2 is an output -705 ; SHFD = 0 for MSB shifted first -706 ; CKP = 0 for rising clock edge transitions -707 ; TE0 = 0 to NOT enable transmitter #0 yet -708 ; MOD = 0 so its not networked mode -709 P:00013C P:00013C 07F42F MOVEP #%100000,X:PCRD ; Control Register (0 for GPIO, 1 for ESSI) - 000020 -710 ; PD3 = SCK1, PD5 = STD1 for ESSI -711 P:00013E P:00013E 07F42E MOVEP #%000100,X:PRRD ; Data Direction Register (0 for In, 1 for O -ut) - 000004 -712 P:000140 P:000140 07F42D MOVEP #%000100,X:PDRD ; Data Register: 'not used' = 0 outputs - 000004 -713 P:000142 P:000142 07F42C MOVEP #0,X:TX10 ; Initialize the transmitter to zero - 000000 -714 P:000144 P:000144 000000 NOP -715 P:000145 P:000145 000000 NOP -716 P:000146 P:000146 012630 BSET #TE,X:CRB1 ; Enable the SSI transmitter -717 -718 ; Conversion from software bits to schematic labels for Port D -719 ; PD0 = SC10 = 2_XMT_? input -720 ; PD1 = SC11 = SSFEF* input -721 ; PD2 = SC12 = PWR_EN -722 ; PD3 = SCK1 = TIM-A-SCK -723 ; PD4 = SRD1 = PWRRST -724 ; PD5 = STD1 = TIM-A-STD -725 -726 ; Program the SCI port to benign values -727 P:000147 P:000147 07F41F MOVEP #%000,X:PCRE ; Port Control Register = GPIO - 000000 -728 P:000149 P:000149 07F41E MOVEP #%010,X:PRRE ; Port Direction Register (0 = Input) - 000002 -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 12:03:41 timboot.asm Page 14 - - - -729 P:00014B P:00014B 07F41D MOVEP #%010,X:PDRE ; Port Data Register - 000002 -730 ; PE0 = RXD -731 ; PE1 = TXD -732 ; PE2 = SCLK -733 -734 ; Program one of the three timers as an exposure timer -735 P:00014D P:00014D 07F403 MOVEP #$C34F,X:TPLR ; Prescaler to generate millisecond timer, - 00C34F -736 ; counting from the system clock / 2 = 50 M -Hz -737 P:00014F P:00014F 07F40F MOVEP #$208000,X:TCSR0 ; Clear timer complete bit and enable presca -ler - 208000 -738 P:000151 P:000151 07F40E MOVEP #0,X:TLR0 ; Timer load register - 000000 -739 -740 ; Enable no interrupts -741 P:000153 P:000153 08F4BF MOVEP #$000000,X:IPRC ; No interrupts allowed - 000000 -742 P:000155 P:000155 05F439 MOVE #$300,SR ; Mask all interrupts - 000300 -743 -744 ; Initialize the fiber optic serial receiver circuitry -745 P:000157 P:000157 061480 DO #20,L_FO_INIT - 00015C -746 P:000159 P:000159 5FF000 MOVE Y:RDFO,B - FFFFF1 -747 P:00015B P:00015B 0605A0 REP #5 -748 P:00015C P:00015C 000000 NOP -749 L_FO_INIT -750 -751 ; Pulse PRSFIFO* low to revive the CMDRST* instruction and reset the FIFO -752 P:00015D P:00015D 44F400 MOVE #1000000,X0 ; Delay by 10 milliseconds - 0F4240 -753 P:00015F P:00015F 06C400 DO X0,*+3 - 000161 -754 P:000161 P:000161 000000 NOP -755 P:000162 P:000162 0A8908 BCLR #8,X:HDR -756 P:000163 P:000163 0614A0 REP #20 -757 P:000164 P:000164 000000 NOP -758 P:000165 P:000165 0A8928 BSET #8,X:HDR -759 -760 ; Put all the analog switch inputs to low so they draw minimum current -761 P:000166 P:000166 012F23 BSET #3,X:PCRD ; Turn the serial clock on -762 P:000167 P:000167 56F400 MOVE #$0C3000,A ; Value of integrate speed and gain switches - 0C3000 -763 P:000169 P:000169 20001B CLR B -764 P:00016A P:00016A 241000 MOVE #$100000,X0 ; Increment over board numbers for DAC write -s -765 P:00016B P:00016B 45F400 MOVE #$001000,X1 ; Increment over board numbers for WRSS writ -es - 001000 -766 P:00016D P:00016D 060F80 DO #15,L_ANALOG ; Fifteen video processor boards maximum - 000175 -767 P:00016F P:00016F 0D017C JSR $AC,X0 - 0000AC -809 P:000192 P:000192 440100 MOVE X0,X: NO ROI -1025 ; -1026 ; This is a serial ROI read so here we go -1027 ; The (binned) pre pixels first -1028 ; -1029 ROI -1030 P:0001DA P:0001DA 5E8F00 MOVE Y: R0 -1119 ; The binning appears here only to make up the total amount of skips, since -1120 ; the skip calculation is based upon binned detector coordinates -1121 ; Note that the waveform called inside the binning loop is the same skip -1122 ; routine -1123 SSKIP -1124 P:00020F P:00020F 5C1400 MOVE A1,Y: Turn on +36V -1253 P:00025D P:00025D 44F400 MOVE #2000000,X0 - 1E8480 -1254 P:00025F P:00025F 06C400 DO X0,*+3 ; Wait 20 millisec for settling - 000261 -1255 P:000261 P:000261 000000 NOP -1256 -1257 P:000262 P:000262 0A8980 JCLR #PWROK,X:HDR,PWR_ERR ; Test if the power turned on properly - 000269 -1258 P:000264 P:000264 0D026C JSR $10,X0 - 000010 -1341 P:0002A9 P:0002A9 0D029C JSR $10,X0 -1347 ; JSR $10,X0 - 000010 -1365 P:0002B0 P:0002B0 0D029C JSR $10,X0 -1370 ; JSR 1.0 microsec per pixel -1543 P:00033D P:00033D 000000 NOP -1544 P:00033E P:00033E 014180 ADD #1,A ; Pixel data = Pixel data + 1 -1545 P:00033F P:00033F 000000 NOP -1546 P:000340 P:000340 21CF00 MOVE A,B -1547 P:000341 P:000341 0D0345 JSR 1,X0 - 000001 -1654 P:000390 P:000390 200045 CMP X0,A ; Check for gain = x1 -1655 P:000391 P:000391 0E2395 JNE $77,B - 000077 -1657 P:000394 P:000394 0C03A9 JMP 2,X0 ; Check for gain = x2 - 000002 -1659 P:000397 P:000397 200045 CMP X0,A -1660 P:000398 P:000398 0E239C JNE $BB,B - 0000BB -1662 P:00039B P:00039B 0C03A9 JMP 5,X0 ; Check for gain = x5 - 000005 -1664 P:00039E P:00039E 200045 CMP X0,A -1665 P:00039F P:00039F 0E23A3 JNE $DD,B - 0000DD -1667 P:0003A2 P:0003A2 0C03A9 JMP 10,X0 ; Check for gain = x10 - 00000A -1669 P:0003A5 P:0003A5 200045 CMP X0,A -1670 P:0003A6 P:0003A6 0E2028 JNE $EE,B - 0000EE -1672 -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 12:03:41 timCCDmisc.asm Page 31 - - - -1673 P:0003A9 P:0003A9 56DB00 STG_A MOVE X:(R3)+,A ; Integrator Speed (0 for slow, 1 for fast) -1674 P:0003AA P:0003AA 000000 NOP -1675 P:0003AB P:0003AB 0ACC00 JCLR #0,A1,STG_B - 0003B0 -1676 P:0003AD P:0003AD 0ACD68 BSET #8,B1 -1677 P:0003AE P:0003AE 000000 NOP -1678 P:0003AF P:0003AF 0ACD69 BSET #9,B1 -1679 P:0003B0 P:0003B0 44F400 STG_B MOVE #$0C3C00,X0 - 0C3C00 -1680 P:0003B2 P:0003B2 20004A OR X0,B -1681 P:0003B3 P:0003B3 000000 NOP -1682 P:0003B4 P:0003B4 5F0000 MOVE B,Y:24,X0 ; Check for argument less than 32 - 000018 -1780 P:000404 P:000404 200045 CMP X0,A -1781 P:000405 P:000405 0AF0A1 JGE ERR_SM1 - 000444 -1782 P:000407 P:000407 21CF00 MOVE A,B -1783 P:000408 P:000408 44F400 MOVE #>7,X0 -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 12:03:41 timCCDmisc.asm Page 33 - - - - 000007 -1784 P:00040A P:00040A 20004E AND X0,B -1785 P:00040B P:00040B 44F400 MOVE #>$18,X0 - 000018 -1786 P:00040D P:00040D 200046 AND X0,A -1787 P:00040E P:00040E 0E2411 JNE $08,X0 - 000008 -1791 P:000413 P:000413 200045 CMP X0,A ; Test for 8 <= MUX number <= 15 -1792 P:000414 P:000414 0E2417 JNE $10,X0 - 000010 -1796 P:000419 P:000419 200045 CMP X0,A ; Test for 16 <= MUX number <= 23 -1797 P:00041A P:00041A 0E2444 JNE 24,X0 ; Check for argument less than 32 - 000018 -1807 P:000423 P:000423 200045 CMP X0,A -1808 P:000424 P:000424 0E1028 JGE $600,X0 - 000600 -1816 P:00042E P:00042E 200046 AND X0,A -1817 P:00042F P:00042F 0E2432 JNE $200,X0 - 000200 -1821 P:000434 P:000434 200045 CMP X0,A ; Test for 8 <= MUX number <= 15 -1822 P:000435 P:000435 0E2438 JNE $400,X0 - 000400 -1826 P:00043A P:00043A 200045 CMP X0,A ; Test for 16 <= MUX number <= 23 -1827 P:00043B P:00043B 0E2028 JNE 1 -.4) -1926 Y:00000E Y:00000E NPSKP DC 0 ; number of lines to skip to get to ROI -1927 Y:00000F Y:00000F NSUND DC 24 ; number of underscan (prescan) pixels -1928 Y:000010 Y:000010 NSSKP DC 0 ; number of pixels to skip to get to ROI -1929 Y:000011 Y:000011 NSRD DC 2048 ; number of pixels to read in the ROI -1930 Y:000012 Y:000012 NSSKP2 DC 0 ; number of pixels to skip to get to oversca -n -1931 Y:000013 Y:000013 NSOCK DC 64 ; number of overscan (bias) pixels -1932 Y:000014 Y:000014 NP2READ DC 0 ; number of overscan (bias) pixels -1933 Y:000015 Y:000015 NSDATA DC 2048 ; number of data (bias) pixels -1934 Y:000016 Y:000016 NSTST DC 0 ; number of data (bias) pixels -1935 Y:000017 Y:000017 NPTST DC 0 ; number of data (bias) pixels -1936 ; -1937 ; Note: NSR = 2048 + NSUND (default=24) + NSOCK (default=64) -1938 ; -1939 -1940 ; Include the waveform table for the designated type of CCD -1941 INCLUDE "CCD44-82.waveforms" ; Readout and clocking waveform file -1942 COMMENT * -1943 -1944 * -1945 -1946 ; LEFT CHANNEL READOUT -1947 -1948 ; Miscellaneous definitions -1949 200000 CLKAD EQU $200000 -1950 000000 VIDEO EQU $000000 ; Video processor board select = 0 -1951 002000 CLK2 EQU $002000 ; Clock driver board lower half -1952 003000 CLK3 EQU $003000 ; Clock driver board upper half -1953 -1954 ; Delay numbers for clocking -1955 B80000 P_DLY EQU $B80000 ; Parallel clock delay -1956 090000 S_DLY EQU $090000 ; Serial shift time per state. -1957 ; Gets noisy if shorter (or is it the shorte -r dwell?) -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 12:03:41 CCD44-82.waveforms Page 36 - - - -1958 ;SS_DLY EQU $310000 ; Serial skip time per state -1959 030000 SS_DLY EQU $030000 ; Serial skip time per state -1960 040000 SW_DLY EQU $040000 ; summing well settling time. 2 may be ok. -1961 000834 NS_CLR EQU 2100 ; Serial clocks to clear -1962 000400 NP_CLR EQU 1024 ; Parallel clocks to clear (per amplifier) -1963 000032 SH_DEL EQU 50 ; Shutter delay in milliseconds -1964 070000 ADC_DLY EQU $070000 ; ADC sample time = 300 ns, but some slew oc -curs during integration. -1965 040000 RG_DLY EQU $040000 ; reset gate settling before DC restore -1966 -1967 110000 CNV_DLY EQU $110000 ; RG_DLY+CNV_DLY+40ns >> 815 ns, say 880ns. -1968 030000 DCR_DLY EQU $030000 ; DC Restore, settle time after xmit > 160ns -1969 -1970 ;INT_DLY EQU $000000 ; integration delay -> measured 2.48 usecs/pix -1971 ;INT_DLY EQU $140000 ; adjust to extend dwell time -> measured 3.28 usecs/pix -1972 ;INT_DLY EQU $260000 ; adjust to extend dwell time -> measured 4.00 usecs/pix -1973 3F0000 INT_DLY EQU $3F0000 ; adjust to extend dwell time -> measured 5 -.00 usecs/pix -1974 ;INT_DLY EQU $580000 ; adjust to extend dwell time -> measured 6.00 usecs/pix -1975 ;INT_DLY EQU $7D0000 ; adjust to extend dwell time -> measured 7.00 usecs/pix -1976 ;INT_DLY2 EQU $310000 ; add to 7us dwell time to get 9.00 usecs/pix -1977 ;INT_DLY EQU $130000 ; -1978 ;INT_DLY2 EQU $130000 ; -1979 -1980 ; clocking voltages -1981 1.000000E+000 P_HI EQU +1.0 ; Parallel clock ; datasheet +10 -1982 -9.000000E+000 P_LO EQU -9.0 ; datasheet 0.0 -1983 3.000000E+000 RG_HI EQU +3.0 ; Reset Gate ; datasheet +12.0 -1984 -3.000000E+000 RG_LO EQU -3.0 ; datasheet 0.0 -1985 2.000000E+000 S_HI EQU +2.0 ; Serial clocks ; datasheet +11.0 -1986 -8.000000E+000 S_LO EQU -8.0 ; datasheet 1.0 -1987 2.000000E+000 SW_HI EQU +2.0 ; Summing well ; datasheet +11.0 -1988 -9.000000E+000 SW_LO EQU -9.0 ; datasheet 0.0 -1989 3.000000E+000 DG_HI EQU 3.0 ; Dump Gate -1990 -9.000000E+000 DG_LO EQU -9.0 ; Dump Gate -1991 -9.000000E+000 ZERO EQU -9.0 -1992 1.240000E+001 CLKmax EQU +12.4 -1993 -1994 ; DC Bias definition, in volts -1995 2.000000E+001 BOD EQU +20.0 ; Output Drain both ; datasheet +29 -1996 000016 BJD EQU +22 ; Jfet Drain both ; datasheet +31 -1997 8.000000E+000 BRDL EQU +8.0 ; Reset Drain ; datasheet +17 -1998 8.000000E+000 BRDR EQU +8.0 -1999 1.500000E+001 BDD EQU +15.0 ; Dump Drain ; datasheet +24 -2000 -6.000000E+000 BOG1 EQU -6.0 ; Output gate 1 ; datasheet +3 -2001 -3.000000E+000 BOG2 EQU -3.0 ; Output gate 2 ; datasheet +4 -2002 -2003 ; Output video offset parameters -2004 0005DF OFFSET0 EQU 1503 -2005 000641 OFFSET1 EQU 1601 -2006 -2007 ; ****************************************************** -2008 ; ****************************************************** -2009 -2010 ; Define switch state bits for the CCD clocks - CLK2, which is lower bank -2011 000001 P1 EQU 1 ; Parallel shift register phase #1, L & R am -ps -2012 000002 P2 EQU 2 ; Parallel shift register phase #2, L & R am -ps -2013 000004 P3 EQU 4 ; Parallel shift register phase #3, L & R am -ps -2014 000008 H_DG EQU 8 ; Dump Gate -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 12:03:41 CCD44-82.waveforms Page 37 - - - -2015 000000 L_DG EQU 0 ; Dump Gate -2016 -2017 ; Define switch state bits for the CCD clocks - CLK3, which is upper bank -2018 000001 S1L EQU 1 ; Serial shift register phase #1, left quadr -ant -2019 000002 S2L EQU 2 ; Serial shift register phase #2, left -2020 000004 SWL EQU 4 ; Summing well, Left quadrant -2021 000008 S1R EQU 8 ; Serial shift register phase #1, right quad -rant -2022 000010 S2R EQU $10 ; Serial shift register phase #2, right -2023 000020 SWR EQU $20 ; Summing well, Right quadrant -2024 000040 S3 EQU $40 ; Serial shift register phase #3, both -2025 000080 RGL EQU $80 ; Reset Gate left -2026 000100 RGR EQU $100 ; Reset Gate right -2027 -2028 -2029 ; *** Definitions for Y: memory waveform tables ***** -2030 -2031 ; waveforms para el borrado paralelo (ie parallel erase.) -2032 PARALLEL_CLEAR -2033 Y:000018 Y:000018 DC END_PARALLEL_CLEAR-PARALLEL_CLEAR-1 -2034 Y:000019 Y:000019 DC CLK2+P_DLY+00+P2+P3+H_DG -2035 Y:00001A Y:00001A DC CLK2+P_DLY+00+00+P3+H_DG -2036 Y:00001B Y:00001B DC CLK2+P_DLY+P1+00+P3+H_DG -2037 Y:00001C Y:00001C DC CLK2+P_DLY+P1+00+00+H_DG -2038 Y:00001D Y:00001D DC CLK2+P_DLY+P1+P2+00+H_DG -2039 Y:00001E Y:00001E DC CLK2+P_DLY+00+P2+00+H_DG -2040 END_PARALLEL_CLEAR -2041 -2042 ; Clock the image down -2043 PARALLEL_SHIFT -2044 Y:00001F Y:00001F DC END_PARALLEL_SHIFT-PARALLEL_SHIFT-1 -2045 Y:000020 Y:000020 DC CLK3+S_DLY+S1L+S1R+S2L+S2R+00+RGL+RGR+SWR+SWL -2046 Y:000021 Y:000021 DC CLK2+P_DLY+00+P2+P3+L_DG -2047 Y:000022 Y:000022 DC CLK2+P_DLY+00+00+P3+L_DG -2048 Y:000023 Y:000023 DC CLK2+P_DLY+P1+00+P3+L_DG -2049 Y:000024 Y:000024 DC CLK2+P_DLY+P1+00+00+L_DG -2050 Y:000025 Y:000025 DC CLK2+P_DLY+P1+P2+00+L_DG -2051 Y:000026 Y:000026 DC CLK2+P_DLY+00+P2+00+L_DG -2052 END_PARALLEL_SHIFT -2053 -2054 PREPARE_DUMP -2055 Y:000027 Y:000027 DC END_PREPARE_DUMP-PREPARE_DUMP-1 -2056 Y:000028 Y:000028 DC CLK3+S_DLY+S1L+S1R+S2L+S2R+00+RGL+RGR+SWR+SWL -2057 END_PREPARE_DUMP -2058 -2059 PARALLEL_DUMP -2060 Y:000029 Y:000029 DC END_PARALLEL_DUMP-PARALLEL_DUMP-1 -2061 Y:00002A Y:00002A DC CLK2+P_DLY+00+P2+P3+H_DG -2062 Y:00002B Y:00002B DC CLK2+P_DLY+00+00+P3+H_DG -2063 Y:00002C Y:00002C DC CLK2+P_DLY+P1+00+P3+H_DG -2064 Y:00002D Y:00002D DC CLK2+P_DLY+P1+00+00+H_DG -2065 Y:00002E Y:00002E DC CLK2+P_DLY+P1+P2+00+H_DG -2066 Y:00002F Y:00002F DC CLK2+P_DLY+00+P2+00+H_DG -2067 END_PARALLEL_DUMP -2068 -2069 CLEAR_READ_REGISTER -2070 Y:000030 Y:000030 DC END_CLEAR_READ_REGISTER-CLEAR_READ_REGISTER-1 -2071 Y:000031 Y:000031 DC CLK3+S_DLY+000+000+000+000+00+RGL+RGR+000+000 -2072 Y:000032 Y:000032 DC CLK2+P_DLY+00+P2+00+L_DG -2073 END_CLEAR_READ_REGISTER -2074 -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 12:03:41 CCD44-82.waveforms Page 38 - - - -2075 ; Serial clocking waveform for skipping -2076 SERIAL_SKIP -2077 Y:000033 Y:000033 DC END_SERIAL_SKIP-SERIAL_SKIP-1 -2078 Y:000034 Y:000034 DC VIDEO+$000000+%1110100 ; DC Restore(!b1) -2079 Y:000035 Y:000035 DC CLK3+SS_DLY+S1L+S2R+S2L+S1R+00+000+000+000+000 -2080 Y:000036 Y:000036 DC CLK3+SS_DLY+000+000+S2L+S1R+00+000+000+000+000 -2081 Y:000037 Y:000037 DC VIDEO+$000000+%1110110 ; end DC restore -2082 Y:000038 Y:000038 DC CLK3+SS_DLY+000+000+S2L+S1R+S3+RGL+RGR+SWL+SWR -2083 Y:000039 Y:000039 DC CLK3+SS_DLY+000+000+000+000+S3+RGL+RGR+SWL+SWR -2084 Y:00003A Y:00003A DC CLK3+SS_DLY+S1L+S2R+000+000+S3+RGL+RGR+SWL+SWR -2085 Y:00003B Y:00003B DC CLK3+SS_DLY+S1L+S2R+000+000+00+000+000+000+000 -2086 END_SERIAL_SKIP -2087 -2088 ; Serial clocking waveform for binning (shift only) (SW high and RG low) -2089 SERIAL_SHIFT -2090 Y:00003C Y:00003C DC END_SERIAL_SHIFT-SERIAL_SHIFT-1 -2091 Y:00003D Y:00003D DC CLK3+S_DLY+S1L+S2R+S2L+S1R+00+000+000+SWR+SWL -2092 Y:00003E Y:00003E DC CLK3+S_DLY+000+000+S2L+S1R+00+000+000+SWR+SWL -2093 Y:00003F Y:00003F DC CLK3+S_DLY+000+000+S2L+S1R+S3+000+000+SWL+SWR -2094 Y:000040 Y:000040 DC CLK3+S_DLY+000+000+000+000+S3+000+000+SWL+SWR -2095 Y:000041 Y:000041 DC CLK3+S_DLY+S1L+S2R+000+000+S3+000+000+SWL+SWR -2096 Y:000042 Y:000042 DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2097 END_SERIAL_SHIFT -2098 -2099 ; Serial clocking waveform for reading (shift plus video proc) -2100 ; CLK3 = Delay+S1L+S1R+S2L+S2L+S3+RGL+RGR+SWL+SWR -2101 ; -2102 SERIAL_READ -2103 Y:000043 Y:000043 DC END_SERIAL_READ-SERIAL_READ-1 -2104 Y:000044 Y:000044 DC VIDEO+$000000+%0010111 ; Stop resetting integrator -2105 -2106 Y:000045 Y:000045 DC VIDEO+000000+%0000111 ; Integrate -2107 Y:000046 Y:000046 DC CLK3+S_DLY+S1L+S2R+S2L+S1R+00+000+000+SWR+SWL -2108 Y:000047 Y:000047 DC CLK3+S_DLY+000+000+S2L+S1R+00+000+000+SWR+SWL -2109 Y:000048 Y:000048 DC CLK3+S_DLY+000+000+S2L+S1R+S3+000+000+SWL+SWR -2110 Y:000049 Y:000049 DC CLK3+S_DLY+000+000+000+000+S3+000+000+SWL+SWR -2111 Y:00004A Y:00004A DC CLK3+S_DLY+S1L+S2R+000+000+S3+000+000+SWL+SWR -2112 Y:00004B Y:00004B DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2113 Y:00004C Y:00004C DC CLK3+INT_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2114 ; DC CLK3+INT_DLY2+S1L+S2R+000+000+00+000+000+SWL+SWR -2115 Y:00004D Y:00004D DC VIDEO+$000000+%0011011 ; Stop Integrate -2116 -2117 Y:00004E Y:00004E DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+000+000 -2118 Y:00004F Y:00004F DC CLK3+SW_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2119 -2120 Y:000050 Y:000050 DC VIDEO+$00000+%0001011 ; Integrate -2121 Y:000051 Y:000051 DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2122 Y:000052 Y:000052 DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2123 Y:000053 Y:000053 DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2124 Y:000054 Y:000054 DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2125 Y:000055 Y:000055 DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2126 Y:000056 Y:000056 DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2127 Y:000057 Y:000057 DC CLK3+INT_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2128 ; DC CLK3+INT_DLY2+S1L+S2R+000+000+00+000+000+SWL+SWR -2129 Y:000058 Y:000058 DC VIDEO+$000000+%0011011 ; Stop integrator -2130 -2131 Y:000059 Y:000059 DC CLK3+ADC_DLY+S1L+S2R+000+000+00+RGL+RGR+SWL+SWR ; Reset Gate, ADC sample>300 n -s -2132 Y:00005A Y:00005A DC VIDEO+$000000+%0111011 ; Start convert=hold (lo to hi on bit 5 -SS5 --) -2133 Y:00005B Y:00005B DC VIDEO+$000000+%0111011 ; redundant write manage beat frequencies -2134 Y:00005C Y:00005C DC VIDEO+$000000+%0111011 ; redundant write manage beat frequencies -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 12:03:41 CCD44-82.waveforms Page 39 - - - -2135 Y:00005D Y:00005D DC CLK3+$000000+S1L+S2R+000+000+00+000+000+SWR+SWL ; end of RG pulse -2136 Y:00005E Y:00005E DC VIDEO+RG_DLY+%1110110 ; Reset Integrator(!b0), RG settling -2137 Y:00005F Y:00005F DC VIDEO+CNV_DLY+%1110100 ; DC Restore(!b1) -2138 Y:000060 Y:000060 DC $00F000 ; Transmit A/D data to host -2139 Y:000061 Y:000061 DC CLK3+DCR_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR ; DC restore & settle after xm -it -2140 END_SERIAL_READ -2141 -2142 DUMMY_READ -2143 Y:000062 Y:000062 DC END_DUMMY_READ-DUMMY_READ-1 -2144 Y:000063 Y:000063 DC VIDEO+$000000+%0010111 ; Stop resetting integrator -2145 ; DC VIDEO+$000000+%0010111 - ; Stop resetting integrator (unnecessary?) -2146 -2147 Y:000064 Y:000064 DC VIDEO+00000+%0000111 ; Integrate -2148 Y:000065 Y:000065 DC CLK3+S_DLY+S1L+S2R+S2L+S1R+00+000+000+SWR+SWL -2149 Y:000066 Y:000066 DC CLK3+S_DLY+000+000+S2L+S1R+00+000+000+SWR+SWL -2150 Y:000067 Y:000067 DC CLK3+S_DLY+000+000+S2L+S1R+S3+000+000+SWL+SWR -2151 Y:000068 Y:000068 DC CLK3+S_DLY+000+000+000+000+S3+000+000+SWL+SWR -2152 Y:000069 Y:000069 DC CLK3+S_DLY+S1L+S2R+000+000+S3+000+000+SWL+SWR -2153 Y:00006A Y:00006A DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2154 Y:00006B Y:00006B DC CLK3+INT_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2155 ; DC CLK3+INT_DLY2+S1L+S2R+000+000+00+000+000+SWL+SWR -2156 Y:00006C Y:00006C DC VIDEO+$000000+%0011011 ; Stop Integrate -2157 -2158 Y:00006D Y:00006D DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+000+000 -2159 Y:00006E Y:00006E DC CLK3+SW_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2160 -2161 Y:00006F Y:00006F DC VIDEO+$000000+%0001011 ; Integrate -2162 Y:000070 Y:000070 DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2163 Y:000071 Y:000071 DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2164 Y:000072 Y:000072 DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2165 Y:000073 Y:000073 DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2166 Y:000074 Y:000074 DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2167 Y:000075 Y:000075 DC CLK3+S_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2168 Y:000076 Y:000076 DC CLK3+INT_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR -2169 ; DC CLK3+INT_DLY2+S1L+S2R+000+000+00+000+000+SWL+SWR -2170 Y:000077 Y:000077 DC VIDEO+$00000+%0011011 ; Stop integrator -2171 -2172 Y:000078 Y:000078 DC CLK3+ADC_DLY+S1L+S2R+000+000+00+RGL+RGR+SWL+SWR ; Reset Gate, ADC sample>300 n -s -2173 Y:000079 Y:000079 DC VIDEO+$000000+%0111011 ; Start convert=hold (lo to hi on bit 5 -SS5 --) -2174 Y:00007A Y:00007A DC CLK3+$000000+S1L+S2R+000+000+00+000+000+SWR+SWL ; end of RG pulse -2175 Y:00007B Y:00007B DC VIDEO+RG_DLY+%1110110 ; Reset Integrator(!b0), RG settling -2176 Y:00007C Y:00007C DC VIDEO+CNV_DLY+%1110100 ; DC Restore(!b1) -2177 ; transmit >>815 ns after start convert. -2178 Y:00007D Y:00007D DC CLK3+DCR_DLY+S1L+S2R+000+000+00+000+000+SWL+SWR ; DC restore & settle after xm -it -2179 END_DUMMY_READ -2180 -2181 -2182 -2183 ; Initialization of clock driver and video processor DACs and switches -2184 Y:00007E Y:00007E DACS DC END_DACS-DACS-1 -2185 Y:00007F Y:00007F DC CLKAD+$0A0080 -2186 Y:000080 Y:000080 DC CLKAD+$000100+@CVI((P_HI+CLKmax)/(2*CLKmax)*255) ; Pin #1, P1 -2187 Y:000081 Y:000081 DC CLKAD+$000200+@CVI((P_LO+CLKmax)/(2*CLKmax)*255) -2188 Y:000082 Y:000082 DC CLKAD+$000400+@CVI((P_HI+CLKmax)/(2*CLKmax)*255) ; Pin #2, P2 -2189 Y:000083 Y:000083 DC CLKAD+$000800+@CVI((P_LO+CLKmax)/(2*CLKmax)*255) -2190 Y:000084 Y:000084 DC CLKAD+$002000+@CVI((P_HI+CLKmax)/(2*CLKmax)*255) ; Pin #3, P3 -2191 Y:000085 Y:000085 DC CLKAD+$004000+@CVI((P_LO+CLKmax)/(2*CLKmax)*255) -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 12:03:41 CCD44-82.waveforms Page 40 - - - -2192 Y:000086 Y:000086 DC CLKAD+$008000+@CVI((DG_HI+CLKmax)/(2*CLKmax)*255) ; Pin #4, DG -2193 Y:000087 Y:000087 DC CLKAD+$010000+@CVI((DG_LO+CLKmax)/(2*CLKmax)*255) -2194 Y:000088 Y:000088 DC CLKAD+$020100+@CVI((P_HI+CLKmax)/(2*CLKmax)*255) ; Pin #5, ?? -2195 Y:000089 Y:000089 DC CLKAD+$020200+@CVI((P_LO+CLKmax)/(2*CLKmax)*255) -2196 -2197 -2198 Y:00008A Y:00008A DC CLKAD+$020400+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #6, Unused -2199 Y:00008B Y:00008B DC CLKAD+$020800+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) -2200 Y:00008C Y:00008C DC CLKAD+$022000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #7, Unused -2201 Y:00008D Y:00008D DC CLKAD+$024000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) -2202 Y:00008E Y:00008E DC CLKAD+$028000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #8, Unused -2203 Y:00008F Y:00008F DC CLKAD+$030000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) -2204 Y:000090 Y:000090 DC CLKAD+$040100+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #9, Unused -2205 Y:000091 Y:000091 DC CLKAD+$040200+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) -2206 Y:000092 Y:000092 DC CLKAD+$040400+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #10, Unused -2207 Y:000093 Y:000093 DC CLKAD+$040800+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) -2208 Y:000094 Y:000094 DC CLKAD+$042000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #11, Unused -2209 Y:000095 Y:000095 DC CLKAD+$044000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) -2210 Y:000096 Y:000096 DC CLKAD+$048000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #12, Unused -2211 Y:000097 Y:000097 DC CLKAD+$050000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) -2212 -2213 -2214 Y:000098 Y:000098 DC CLKAD+$060100+@CVI((S_HI+CLKmax)/(2*CLKmax)*255) ; Pin #13, S1L -2215 Y:000099 Y:000099 DC CLKAD+$060200+@CVI((S_LO+CLKmax)/(2*CLKmax)*255) -2216 Y:00009A Y:00009A DC CLKAD+$060400+@CVI((S_HI+CLKmax)/(2*CLKmax)*255) ; Pin #14, S2L -2217 Y:00009B Y:00009B DC CLKAD+$060800+@CVI((S_LO+CLKmax)/(2*CLKmax)*255) -2218 Y:00009C Y:00009C DC CLKAD+$062000+@CVI((SW_HI+CLKmax)/(2*CLKmax)*255) ; Pin #15, SWL -2219 Y:00009D Y:00009D DC CLKAD+$064000+@CVI((SW_LO+CLKmax)/(2*CLKmax)*255) -2220 Y:00009E Y:00009E DC CLKAD+$068000+@CVI((S_HI+CLKmax)/(2*CLKmax)*255) ; Pin #16, S1R -2221 Y:00009F Y:00009F DC CLKAD+$070000+@CVI((S_LO+CLKmax)/(2*CLKmax)*255) -2222 Y:0000A0 Y:0000A0 DC CLKAD+$080100+@CVI((S_HI+CLKmax)/(2*CLKmax)*255) ; Pin #17, S2R -2223 Y:0000A1 Y:0000A1 DC CLKAD+$080200+@CVI((S_LO+CLKmax)/(2*CLKmax)*255) -2224 Y:0000A2 Y:0000A2 DC CLKAD+$080400+@CVI((SW_HI+CLKmax)/(2*CLKmax)*255) ; Pin #18, SWR -2225 Y:0000A3 Y:0000A3 DC CLKAD+$080800+@CVI((SW_LO+CLKmax)/(2*CLKmax)*255) -2226 Y:0000A4 Y:0000A4 DC CLKAD+$082000+@CVI((S_HI+CLKmax)/(2*CLKmax)*255) ; Pin #19, S3 -2227 Y:0000A5 Y:0000A5 DC CLKAD+$084000+@CVI((S_LO+CLKmax)/(2*CLKmax)*255) -2228 Y:0000A6 Y:0000A6 DC CLKAD+$088000+@CVI((RG_HI+CLKmax)/(2*CLKmax)*255) ; Pin #33, RGL -2229 Y:0000A7 Y:0000A7 DC CLKAD+$090000+@CVI((RG_LO+CLKmax)/(2*CLKmax)*255) -2230 Y:0000A8 Y:0000A8 DC CLKAD+$0A0100+@CVI((RG_HI+CLKmax)/(2*CLKmax)*255) ; Pin #34, RGR -2231 Y:0000A9 Y:0000A9 DC CLKAD+$0A0200+@CVI((RG_LO+CLKmax)/(2*CLKmax)*255) -2232 -2233 -2234 Y:0000AA Y:0000AA DC CLKAD+$0A0400+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #35, Unused -2235 Y:0000AB Y:0000AB DC CLKAD+$0A0800+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) -2236 Y:0000AC Y:0000AC DC CLKAD+$0A2000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #36, Unused -2237 Y:0000AD Y:0000AD DC CLKAD+$0A4000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) -2238 Y:0000AE Y:0000AE DC CLKAD+$0A8000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) ; Pin #37, Unused -2239 Y:0000AF Y:0000AF DC CLKAD+$0B0000+@CVI((ZERO+CLKmax)/(2*CLKmax)*255) -2240 -2241 -2242 -2243 ; Set gain and integrator speed. (77, bb, dd, ee; low gain to high) -2244 ; DC $0c3c77 ; Gain x1, slow integ. speed, board #0 -2245 Y:0000B0 Y:0000B0 DC $0c3f77 ; Gain x1, fast integrate speed -2246 ; DC $0c3fbb ; Gain x2 -2247 ; DC $0c3fdd ; Gain x4.75 -2248 ; DC $0c3fee ; Gain x9.50 -2249 -2250 ; DC $0c3fbb ; Default x2 gain, fast integration -2251 ; DC $0c33bb ; Default x2 gain, fast integration (to read the sawtoot -h waveform) -2252 -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 12:03:41 CCD44-82.waveforms Page 41 - - - -2253 ; Output offset voltages -2254 Y:0000B1 Y:0000B1 DC $0c4000+OFFSET0 ; Output video offset, channel 0 -2255 Y:0000B2 Y:0000B2 DC $0cc000+OFFSET1 -2256 -2257 ; DC bias voltages. Gain and offsets adjusted for video boards SN205 and SN304. Feb. 24, 2005 -2258 ; (if it is wrong, blame on DG, if it is right, applauses to MB) -2259 -2260 Y:0000B3 Y:0000B3 DC $0d0000+@CVI((BOD-6.3)/23.7*4095) ; pin #1, VID0 -2261 Y:0000B4 Y:0000B4 DC $0d4000+@CVI((BJD-6.3)/23.7*4095) ; pin #2, VID0 -2262 Y:0000B5 Y:0000B5 DC $0d8000+@CVI((BRDL-3.9)/16.1*4095) ; pin #3, VID0 -2263 Y:0000B6 Y:0000B6 DC $0dc000+@CVI((BRDR-3.9)/16.1*4095) ; pin #4, VID0 -2264 Y:0000B7 Y:0000B7 DC $0e0000+@CVI((BDD-3.9)/16.1*4095) ; pin #5, VID0 -2265 -2266 Y:0000B8 Y:0000B8 DC $0f8000+@CVI((BOG1+10.0)/20.0*4095) ; pin #11, VID0 -2267 Y:0000B9 Y:0000B9 DC $0fc000+@CVI((BOG2+10.0)/20.0*4095) ; pin #12, VID0 -2268 -2269 END_DACS -2270 -2271 END_APPLICATON_Y_MEMORY -2272 0000BA EQU @LCV(L) -2273 -2274 ; End of program -2275 END - -0 Errors -0 Warnings - - diff --git a/DSP/DBSP-blue/timCCDmisc.asm b/DSP/DBSP-blue/timCCDmisc.asm deleted file mode 100644 index 71df9d1a..00000000 --- a/DSP/DBSP-blue/timCCDmisc.asm +++ /dev/null @@ -1,690 +0,0 @@ - COMMENT * -Miscellaneous CCD control routines, common to all detector types - -Revision History: --- 0.01: 11 Jun 2004 - CRO. - P_SHIFT routine added. Shifts the CDD charge by NPSHF rows. - NPSHF is stored in Y: memory and can be changed before a shift. --- 0.02: 29 Jul 2004 - CRO. - SBINN - set binning routine added. --- 0.03: 8 Aug 2004 - MB - SET_GEOMETRY - set geometry routine added. - SET_ROI - set ROI routine added. - CAL_GEOM - Calculate Geometry routine added (calculates NSSKP2) --- 0.04: 10 Aug 2004 - MB - Taken out the command processing inside CLR_CCD, as well as the - call to "GET_RCV" after the CLR_CCD routine call inside - START_EXPOSURE - Added the status bit condition for clearing the array automatically - during the exposure (inside START_EXPOSURE). Now the host will need - to set the bit NOT_CLR to 1 before doing a focus frame --- 0.05: 12 Aug 2004 - MB - Added SET_GEOMETRY, CALC_GEOM, and SET_ROI subroutines - - * -; we are not using the last two args: ypre and yov, because in this case -; we are not using y extra scans (only data) -SET_GEOMETRY - MOVE X:(R3)+,Y1 ; Get first parameter XPRE - MOVE Y1,Y: Turn on +36V - MOVE #2000000,X0 - DO X0,*+3 ; Wait 20 millisec for settling - NOP - - JCLR #PWROK,X:HDR,PWR_ERR ; Test if the power turned on properly - JSR $10,X0 - JSR $10,X0 -; JSR $10,X0 - JSR $10,X0 -; JSR 1.0 microsec per pixel - NOP - ADD #1,A ; Pixel data = Pixel data + 1 - NOP - MOVE A,B - JSR 1,X0 - CMP X0,A ; Check for gain = x1 - JNE $77,B - JMP 2,X0 ; Check for gain = x2 - CMP X0,A - JNE $BB,B - JMP 5,X0 ; Check for gain = x5 - CMP X0,A - JNE $DD,B - JMP 10,X0 ; Check for gain = x10 - CMP X0,A - JNE $EE,B - -STG_A MOVE X:(R3)+,A ; Integrator Speed (0 for slow, 1 for fast) - NOP - JCLR #0,A1,STG_B - BSET #8,B1 - NOP - BSET #9,B1 -STG_B MOVE #$0C3C00,X0 - OR X0,B - NOP - MOVE B,Y:24,X0 ; Check for argument less than 32 - CMP X0,A - JGE ERR_SM1 - MOVE A,B - MOVE #>7,X0 - AND X0,B - MOVE #>$18,X0 - AND X0,A - JNE $08,X0 - CMP X0,A ; Test for 8 <= MUX number <= 15 - JNE $10,X0 - CMP X0,A ; Test for 16 <= MUX number <= 23 - JNE 24,X0 ; Check for argument less than 32 - CMP X0,A - JGE $600,X0 - AND X0,A - JNE $200,X0 - CMP X0,A ; Test for 8 <= MUX number <= 15 - JNE $400,X0 - CMP X0,A ; Test for 16 <= MUX number <= 23 - JNE CLR_RTS - JMP try again -TST2 JCLR #EF,X:HDR,CLR_RTS ; Low, High => try again - JMP read FIFO -TST3 JCLR #EF,X:HDR,TST1 - - MOVEP #$028FE2,X:BCR ; Slow down RDFO access - NOP - NOP - MOVE Y:RDFO,B - MOVE #0,B2 - AND #$FF,B - CMP #>$AC,B ; It must be $AC to be a valid word - JNE SR carry = 1 - MOVEP #$028FE1,X:BCR ; Restore RDFO access - RTS -CLR_RTS BCLR #0,SR ; Not valid FIFO word => SR carry = 0 - MOVEP #$028FE1,X:BCR ; Restore RDFO access - RTS - -; Transmit the word in B1 to the host computer -XMT_WRD MOVEP #$028FE2,X:BCR ; Slow down RDFO access - MOVE #FO_HDR+1,R0 - DO #3,XMT_WRD1 - ASL #8,B,B - NOP - MOVE B2,X:(R0)+ -XMT_WRD1 - MOVE #FO_HDR,R0 - MOVE #WRFO,R1 - DO #4,XMT_WRD2 - MOVE X:(R0)+,Y0 ; Should be MOVEP X:(R0)+,Y:WRFO - MOVE Y0,Y:(R1) -XMT_WRD2 - MOVEP #$028FE1,X:BCR ; Restore RDFO access - RTS - -; Check the command or reply header in Y0 for self-consistency -CHK_HDR MOVE X: 0 - JEQ when not - MOVE R0,X: when not - MOVE R0,X:1,X:HPCR ; All pins enabled as GPIO - MOVEP #$010C,X:HDR - MOVEP #$B10E,X:HDDR ; Data Direction Register - ; (1 for Output, 0 for Input) - -; Port B conversion from software bits to schematic labels -; PB0 = PWROK PB08 = PRSFIFO* -; PB1 = LED1 PB09 = EF* -; PB2 = LVEN PB10 = EXT-IN0 -; PB3 = HVEN PB11 = EXT-IN1 -; PB4 = STATUS0 PB12 = EXT-OUT0 -; PB5 = STATUS1 PB13 = EXT-OUT1 -; PB6 = STATUS2 PB14 = SSFHF* -; PB7 = STATUS3 PB15 = SELSCI - -; Program the serial port ESSI0 = Port C for serial communication with -; the utility board - MOVEP #>0,X:PCRC ; Software reset of ESSI0 - MOVEP #$000809,X:CRA0 ; Divide 100 MHz by 20 to get 5.0 MHz - ; DC[4:0] = 0 for non-network operation - ; WL0-WL2 = ALC = 0 for 2-bit data words - ; ALC = 0, SSC1 = 0 for SC1 not used - MOVEP #$010130,X:CRB0 ; SCKD = 1 for internally generated clock - ; SHFD = 0 for MSB shifted first - ; CKP = 0 for rising clock edge transitions - ; TE0 = 1 to enable transmitter #0 - ; MOD = 0 for normal, non-networked mode - ; FSL1 = 1, FSL0 = 0 for on-demand transmit - MOVEP #%000000,X:PCRC ; Control Register (0 for GPIO, 1 for ESSI) - ; SCK0 = P3, STD0 = P5 are ESSI0, turned OFF - MOVEP #%010111,X:PRRC ; Data Direction Register (0 for In, 1 for Out) - MOVEP #%000101,X:PDRC ; Data Register - ROM/FIFO* = 0, WR_ENA* = 1, - ; AUX1 = 0, AUX2 = AUX3 = 1 - -; Conversion from software bits to schematic labels for Port C -; PC0 = SC00 = UTL-T-SCK -; PC1 = SC01 = 2_XMT = SYNC on prototype -; PC2 = SC02 = WR_ENA* -; PC3 = SCK0 = TIM-U-SCK -; PC4 = SRD0 = UTL-T-SCD -; PC5 = STD0 = TIM-U-STD - -; Program the serial port ESSI1 = Port D for serial transmission to -; the analog boards and two parallel I/O input pins - MOVEP #>0,X:PCRD ; Software reset of ESSI0 - MOVEP #$000809,X:CRA1 ; Divide 100 MHz by 20 to get 5.0 MHz - ; DC[4:0] = 0 - ; WL[2:0] = 000 for 8-bit data words - ; SSC1 = 0 for SC1 not used - MOVEP #$000030,X:CRB1 ; SCKD = 1 for internally generated clock - ; SCD2 = 1 so frame sync SC2 is an output - ; SHFD = 0 for MSB shifted first - ; CKP = 0 for rising clock edge transitions - ; TE0 = 0 to NOT enable transmitter #0 yet - ; MOD = 0 so its not networked mode - MOVEP #%100000,X:PCRD ; Control Register (0 for GPIO, 1 for ESSI) - ; PD3 = SCK1, PD5 = STD1 for ESSI - MOVEP #%000100,X:PRRD ; Data Direction Register (0 for In, 1 for Out) - MOVEP #%000100,X:PDRD ; Data Register: 'not used' = 0 outputs - MOVEP #0,X:TX10 ; Initialize the transmitter to zero - NOP - NOP - BSET #TE,X:CRB1 ; Enable the SSI transmitter - -; Conversion from software bits to schematic labels for Port D -; PD0 = SC10 = 2_XMT_? input -; PD1 = SC11 = SSFEF* input -; PD2 = SC12 = PWR_EN -; PD3 = SCK1 = TIM-A-SCK -; PD4 = SRD1 = PWRRST -; PD5 = STD1 = TIM-A-STD - -; Program the SCI port to benign values - MOVEP #%000,X:PCRE ; Port Control Register = GPIO - MOVEP #%010,X:PRRE ; Port Direction Register (0 = Input) - MOVEP #%010,X:PDRE ; Port Data Register -; PE0 = RXD -; PE1 = TXD -; PE2 = SCLK - -; Program one of the three timers as an exposure timer - MOVEP #$C34F,X:TPLR ; Prescaler to generate millisecond timer, - ; counting from the system clock / 2 = 50 MHz - MOVEP #$208000,X:TCSR0 ; Clear timer complete bit and enable prescaler - MOVEP #0,X:TLR0 ; Timer load register - -; Enable no interrupts - MOVEP #$000000,X:IPRC ; No interrupts allowed - MOVE #$300,SR ; Mask all interrupts - -; Initialize the fiber optic serial receiver circuitry - DO #20,L_FO_INIT - MOVE Y:RDFO,B - REP #5 - NOP -L_FO_INIT - -; Pulse PRSFIFO* low to revive the CMDRST* instruction and reset the FIFO - MOVE #1000000,X0 ; Delay by 10 milliseconds - DO X0,*+3 - NOP - BCLR #8,X:HDR - REP #20 - NOP - BSET #8,X:HDR - -; Put all the analog switch inputs to low so they draw minimum current - BSET #3,X:PCRD ; Turn the serial clock on - MOVE #$0C3000,A ; Value of integrate speed and gain switches - CLR B - MOVE #$100000,X0 ; Increment over board numbers for DAC writes - MOVE #$001000,X1 ; Increment over board numbers for WRSS writes - DO #15,L_ANALOG ; Fifteen video processor boards maximum - JSR $AC,X0 - MOVE X0,X: milliseconds -TPCR EQU $FFFF82 ; Timer prescaler count register -TIM_BIT EQU 0 ; Set to enable the timer -TRM EQU 9 ; Set to enable the timer preloading -TCF EQU 21 ; Set when timer counter = compare register - -; Board specific addresses and constants -RDFO EQU $FFFFF1 ; Read incoming fiber optic data byte -WRFO EQU $FFFFF2 ; Write fiber optic data replies -WRSS EQU $FFFFF3 ; Write switch state -WRLATCH EQU $FFFFF5 ; Write to a latch -RDAD EQU $010000 ; Read A/D values into the DSP -EF EQU 9 ; Serial receiver empty flag - -; DSP port A bit equates -PWROK EQU 0 ; Power control board says power is OK -LED1 EQU 1 ; Control one of two LEDs -LVEN EQU 2 ; Low voltage power enable -HVEN EQU 3 ; High voltage power enable -SSFHF EQU 14 ; Switch state FIFO half full flag -EXT_IN0 EQU 10 -EXT_IN1 EQU 11 -EXT_OUT0 EQU 12 -EXT_OUT1 EQU 13 - -; Port D equate -SSFEF EQU 1 ; Switch state FIFO empty flag - -; Other equates -WRENA EQU 2 ; Enable writing to the EEPROM - -; Latch U12 bit equates -CDAC EQU 0 ; Clear the analog board DACs -ENCK EQU 2 ; Enable the clock outputs -SHUTTER EQU 4 ; Control the shutter -TIM_U_RST EQU 5 ; Reset the utility board - -; Software status bits, defined at X:lo - DC CLK2|P_DELAY|FS1_1H|FS2_1L|FS3_1H|FS1_2H|FS2_2L|FS3_2H - DC CLK2|P_DELAY|FS1_1L|FS2_1L|FS3_1H|FS1_2H|FS2_2L|FS3_2L - DC CLK2|P_DELAY|FS1_1L|FS2_1H|FS3_1H|FS1_2H|FS2_2H|FS3_2L - DC CLK2|P_DELAY|FS1_1L|FS2_1H|FS3_1L|FS1_2L|FS2_2H|FS3_2L - DC CLK2|P_DELAY|FS1_1H|FS2_1H|FS3_1L|FS1_2L|FS2_2H|FS3_2H - DC CLK2|$000000|FS1_1H|FS2_1L|FS3_1L|FS1_2L|FS2_2L|FS3_2H - - DC CLK3|P_DELAY|RL|H2_1L|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH - ; wfk - Next line: Add DCRestore,StrtRstInt to machine state at end of CLEAR to stabilize baseline (04/04/07) - DC VIDEO+$000000+%0011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - wfk add DCRestore,StrtRstInt -END_CLEAR_FS - - -PARALLEL_SPLIT DC END_PARALLEL_SPLIT-PARALLEL_SPLIT-1 - DC CLK3|$000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo - DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1H|V1_2H|V2_2L|V3_2H - DC CLK2|P_DELAY|V1_1L|V2_1L|V3_1H|V1_2H|V2_2L|V3_2L - DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1H|V1_2H|V2_2H|V3_2L - DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1L|V1_2L|V2_2H|V3_2L - DC CLK2|P_DELAY|V1_1H|V2_1H|V3_1L|V1_2L|V2_2H|V3_2H - DC CLK2|$000000|V1_1H|V2_1L|V3_1L|V1_2L|V2_2L|V3_2H - DC CLK3|P_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Shut the transfer gate - DC VIDEO+$000000+%0011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - wfk add DCRestore,StrtRstInt - -END_PARALLEL_SPLIT - - -;Shift towards register 2 -PARALLEL_2 DC END_PARALLEL_2-PARALLEL_2-1 - DC CLK3|$000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo - DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1H|V1_2H|V2_2L|V3_2H - DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1L|V1_2H|V2_2L|V3_2L - DC CLK2|P_DELAY|V1_1H|V2_1H|V3_1L|V1_2H|V2_2H|V3_2L - DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1L|V1_2L|V2_2H|V3_2L - DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1H|V1_2L|V2_2H|V3_2H - DC CLK2|$000000|V1_1L|V2_1L|V3_1H|V1_2L|V2_2L|V3_2H ; shut TG - DC CLK3|P_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Shut the transfer gate - DC VIDEO+$000000+%0011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - wfk add DCRestore,StrtRstInt -END_PARALLEL_2 - -;Shift towards register 1 -;charge stored under 2&3. Issue with switching between which register to go to. -PARALLEL_1 DC END_PARALLEL_1-PARALLEL_1-1 -; DC CLK3|$000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo - DC CLK3|$000000|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo - DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1H|V1_2H|V2_2L|V3_2H - DC CLK2|P_DELAY|V1_1L|V2_1L|V3_1H|V1_2L|V2_2L|V3_2H - DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1H|V1_2L|V2_2H|V3_2H - DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1L|V1_2L|V2_2H|V3_2L - DC CLK2|P_DELAY|V1_1H|V2_1H|V3_1L|V1_2H|V2_2H|V3_2L - DC CLK2|$000000|V1_1H|V2_1L|V3_1L|V1_2H|V2_2L|V3_2L - DC CLK3|P_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Shut the transfer gate - DC VIDEO+$000000+%0011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - wfk add DCRestore,StrtRstInt -END_PARALLEL_1 - - -PARALLEL_CLEAR_1 - DC END_PARALLEL_CLEAR_1-PARALLEL_CLEAR_1-1 - DC CLK3|$000000|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo - - DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1H|V1_2H|V2_2L|V3_2H - DC CLK2|P_DELAY|V1_1L|V2_1L|V3_1H|V1_2L|V2_2L|V3_2H - DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1H|V1_2L|V2_2H|V3_2H - DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1L|V1_2L|V2_2H|V3_2L - DC CLK2|P_DELAY|V1_1H|V2_1H|V3_1L|V1_2H|V2_2H|V3_2L - DC CLK2|$000000|V1_1H|V2_1L|V3_1L|V1_2H|V2_2L|V3_2L - - DC CLK3|P_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Shut the transfer gate - ; wfk - Next line: Add DCRestore,StrtRstInt to machine state at end of CLEAR to stabilize baseline (04/04/07) - DC VIDEO+$000000+%0011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - wfk add DCRestore,StrtRstInt -END_PARALLEL_CLEAR_1 - -PARALLEL_CLEAR_2 - DC END_PARALLEL_CLEAR_2-PARALLEL_CLEAR_2-1 - DC CLK3|$000000|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo - - DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1H|V1_2H|V2_2L|V3_2H - DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1L|V1_2H|V2_2L|V3_2L - DC CLK2|P_DELAY|V1_1H|V2_1H|V3_1L|V1_2H|V2_2H|V3_2L - DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1L|V1_2L|V2_2H|V3_2L - DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1H|V1_2L|V2_2H|V3_2H - DC CLK2|$000000|V1_1L|V2_1L|V3_1H|V1_2L|V2_2L|V3_2H - DC CLK3|P_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Shut the transfer gate - - - ; wfk - Next line: Add DCRestore,StrtRstInt to machine state at end of CLEAR to stabilize baseline (04/04/07) - DC VIDEO+$000000+%0011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - wfk add DCRestore,StrtRstInt -END_PARALLEL_CLEAR_2 - -; this parallel split mixes two central rows on the CCD. -PARALLEL_CLEAR_SPLIT - DC END_PARALLEL_CLEAR_SPLIT-PARALLEL_CLEAR_SPLIT-1 -; DC CLK3|$000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo - DC CLK3|$000000|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo - - DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1H|V1_2H|V2_2L|V3_2H - DC CLK2|P_DELAY|V1_1L|V2_1L|V3_1H|V1_2H|V2_2L|V3_2L - DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1H|V1_2H|V2_2H|V3_2L - DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1L|V1_2L|V2_2H|V3_2L - DC CLK2|P_DELAY|V1_1H|V2_1H|V3_1L|V1_2L|V2_2H|V3_2H - DC CLK2|$000000|V1_1H|V2_1L|V3_1L|V1_2L|V2_2L|V3_2H - - DC CLK3|P_DELAY|RL|H2_1L|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH - ; wfk - Next line: Add DCRestore,StrtRstInt to machine state at end of CLEAR to stabilize baseline (04/04/07) - DC VIDEO+$000000+%0011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - wfk add DCRestore,StrtRstInt -END_PARALLEL_CLEAR_SPLIT - - - -;; this parallel split does not mix central rows -;PARALLEL_CLEAR_SPLIT -; DC END_PARALLEL_CLEAR_SPLIT-PARALLEL_CLEAR_SPLIT-1 -; DC CLK3|$000000|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo -; -; DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1H|V1_2H|V2_2L|V3_2H -; DC CLK2|P_DELAY|V1_1L|V2_1L|V3_1H|V1_2H|V2_2L|V3_2L -; DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1H|V1_2H|V2_2H|V3_2L -; DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1L|V1_2L|V2_2H|V3_2L -; DC CLK2|P_DELAY|V1_1H|V2_1H|V3_1L|V1_2L|V2_2H|V3_2H -; DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1L|V1_2L|V2_2L|V3_2H -; DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1H|V1_2L|V2_2L|V3_2H -; DC CLK2|$000000|V1_1L|V2_1L|V3_1H|V1_2L|V2_2L|V3_2H -; -; DC CLK3|P_DELAY|RL|H2_1L|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH -; ; wfk - Next line: Add DCRestore,StrtRstInt to machine state at end of CLEAR to stabilize baseline (04/04/07) -; DC VIDEO+$000000+%1110000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - wfk add DCRestore,StrtRstInt -;END_PARALLEL_CLEAR_SPLIT - -; ARC47: |xfer|A/D|integ|polarity|not used|not used|rst| (1 => switch open) -SERIAL_IDLE_LEFT ; Clock serial charge from both L and R ends - DC END_SERIAL_IDLE_LEFT-SERIAL_IDLE_LEFT-1 - DC VIDEO+$000000+%1111000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. -; L2 idle version -; 2->3->1->2->3 - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset_On - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi - DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo - DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi - DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay - - - DC CLK3|$0000000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;dummy for transmit delay - DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator - DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. - DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi - DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo - DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec - DC VIDEO+DCRST_DELAY+%0010111 ; Now sit around for at least 520ns while the conversion happens -END_SERIAL_IDLE_LEFT - - -; ARC47: |xfer|A/D|integ|polarity|not used|not used|rst| (1 => switch open) -SERIAL_IDLE_LEFT_NO_POL ; Clock serial charge from both L and R ends - DC END_SERIAL_IDLE_LEFT_NO_POL-SERIAL_IDLE_LEFT_NO_POL-1 - DC VIDEO+$000000+%1111000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - -; L2 idle version -; 2->3->1->2->3 - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset_On - DC CLK3|S_DELAY|RH|H1_1H|H1_2L|H1_3L|H2_1H|H2_2L|H2_3L|WL|TH ;h2->hi - DC CLK3|S_DELAY|RH|H1_1H|H1_2H|H1_3L|H2_1H|H2_2H|H2_3L|WL|TH ;h1->lo - DC CLK3|S_DELAY|RH|H1_1L|H1_2H|H1_3L|H2_1L|H2_2H|H2_3L|WL|TH ;h3->hi - DC CLK3|S_DELAY|RH|H1_1L|H1_2H|H1_3H|H2_1L|H2_2H|H2_3H|WL|TH ;h2->lo - DC CLK3|S_DELAY|RH|H1_1L|H1_2L|H1_3H|H2_1L|H2_2L|H2_3H|WL|TH ;h1->hi - - DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay - - - DC CLK3|$0000000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;dummy for transmit delay - DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator - DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. - DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -- charge dump - - ;SW going low here suggests that no charge will leak over OG barrier onto sense node. - DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo - DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec - DC VIDEO+DCRST_DELAY+%0011011 ; ,NonInv ;mF to do ADC sampling before resetting - -; DC CLK3|POST_SET_DLY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL ;SW->lo -END_SERIAL_IDLE_LEFT_NO_POL - -SERIAL_IDLE_RIGHT ; Clock serial charge from both L and R ends - DC END_SERIAL_IDLE_RIGHT-SERIAL_IDLE_RIGHT-1 - DC VIDEO+$000000+%1011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - -; L2 read version -; 2->3->1->2->3 - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h2->lo,SW->lo,Reset_On - DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h2->hi - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->l - DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h1->hi - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h2->lo - DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->hi, Reset_Off|Delay - - - DC CLK3|$0000000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;dummy for transmit delay - DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator - DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. - DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -- charge dump - - ;SW going low here suggests that no charge will leak over OG barrier onto sense node. - DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo - DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0110111 ; StopIntegrator - DC VIDEO+DCRST_DELAY+%0110111 ; ADCLatch,NonInv ;mF to do ADC sampling before resetting - -; DC CLK3|POST_SET_DLY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL ;SW->lo - -END_SERIAL_IDLE_RIGHT - - -SERIAL_IDLE_RIGHT_NO_POL ; Clock serial charge from both L and R ends - DC END_SERIAL_IDLE_RIGHT_NO_POL-SERIAL_IDLE_RIGHT_NO_POL-1 - DC VIDEO+$000000+%1011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - -; L2 read version -; 2->3->1->2->3 - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h2->lo,SW->lo,Reset_On - DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h2->hi - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->l - DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h1->hi - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h2->lo - DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->hi, Reset_Off|Delay - - - DC CLK3|$0000000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;dummy for transmit delay - DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator - DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. - DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -- charge dump - - ;SW going low here suggests that no charge will leak over OG barrier onto sense node. - DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo - DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0010111 ; StopIntegrator - DC VIDEO+DCRST_DELAY+%0111011 ; ADCLatch,NonInv ;mF to do ADC sampling before resetting - -; DC CLK3|POST_SET_DLY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL ;SW->lo - -END_SERIAL_IDLE_RIGHT_NO_POL - -SERIAL_IDLE_SPLIT - DC END_SERIAL_IDLE_SPLIT-SERIAL_IDLE_SPLIT-1 - DC VIDEO+$000000+%1011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - -; split read version: - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset_On - -; DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi -; DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo -; DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi -; DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo -; DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi - - DC CLK3|S_DELAY|RH|H1_1L|H1_2L|H1_3H|H2_1H|H2_2L|H2_3L|WL|TH ;h2->hi - DC CLK3|S_DELAY|RH|H1_1L|H1_2H|H1_3H|H2_1H|H2_2H|H2_3L|WL|TH ;h1->lo - DC CLK3|S_DELAY|RH|H1_1L|H1_2H|H1_3L|H2_1L|H2_2H|H2_3L|WL|TH ;h3->hi - DC CLK3|S_DELAY|RH|H1_1H|H1_2H|H1_3L|H2_1L|H2_2H|H2_3H|WL|TH ;h2->lo - DC CLK3|S_DELAY|RH|H1_1H|H1_2L|H1_3L|H2_1L|H2_2L|H2_3H|WL|TH ;h1->hi - - - DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay - - DC CLK3|$000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;dummy for transmit delay - DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator - DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. - DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi - DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo - DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0010111 ; StopIntegrator - DC VIDEO+DCRST_DELAY+%0110111 ; ADCLatch,NonInv ;mF to do ADC sampling before resetting -END_SERIAL_IDLE_SPLIT - -; ARC47: |xfer|A/D|integ|polarity|not used|not used|rst| (1 => switch open) -SERIAL_IDLE_SPLIT_NO_POL - DC END_SERIAL_IDLE_SPLIT_NO_POL-SERIAL_IDLE_SPLIT_NO_POL-1 - DC VIDEO+$000000+%1011001 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - -; split read version: - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset_On - DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi - DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi - DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay - - DC CLK3|$000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;dummy for transmit delay - DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator - DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. - DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi - DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo - DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0010111 ; StopIntegrator - DC VIDEO+DCRST_DELAY+%0111011 ; ADCLatch,NonInv ;mF to do ADC sampling before resetting -END_SERIAL_IDLE_SPLIT_NO_POL - - -;start binning waveforms -CCD_RESET ;Used for binning only - DC END_CCD_RESET-CCD_RESET-1 - DC VIDEO+$000000+%1011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. -END_CCD_RESET - -SERIAL_CLOCK_L ;"NORMAL" clocking - DC END_SERIAL_CLOCK_L-SERIAL_CLOCK_L-1 - DC VIDEO+$000000+%1011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset_On - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi - DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo - DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi - DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -END_SERIAL_CLOCK_L - -SERIAL_CLOCK_R ;"REVERSE" clocking - DC END_SERIAL_CLOCK_R-SERIAL_CLOCK_R-1 - DC VIDEO+$000000+%1011000 ; NonInv,DCRestore,StrtRstInt. - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset_On - DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h2->hi - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h1->lo - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi - DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h2->lo - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h1->hi - DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -END_SERIAL_CLOCK_R - -SERIAL_CLOCK_SPLIT ;"SPLIT" clocking - DC END_SERIAL_CLOCK_SPLIT-SERIAL_CLOCK_SPLIT-1 - DC VIDEO+$000000+%1011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset_On - DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi - DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi - DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -END_SERIAL_CLOCK_SPLIT - - -VIDEO_PROCESS - DC END_VIDEO_PROCESS-VIDEO_PROCESS-1 -;SXMIT DC $00F000 ; Transmit A/D data to host - DC VIDEO+$000000+%1011011 ; StopDCRestore and StopResetIntegrator - DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. - DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi - DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo - DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0010111 ; StopResetIntegrator - DC VIDEO+DCRST_DELAY+%0110111 ; ADCLatch,NonInv ;mF to do ADC sampeling bevore resetting -END_VIDEO_PROCESS -;end binning waveforms - - -; Video processor bit definition -; xfer, A/D, integ, Pol+, Pol-, DCrestore, rst (1 => switch open) - -; These are the three reading tables. Make sure they're all the same length -; 2->3->1->2 -SERIAL_READ_LEFT - DC END_SERIAL_READ_LEFT-SERIAL_READ_LEFT-1 - DC VIDEO+$000000+%1111000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset_On - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi - DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo - DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi - DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -SXL DC $00F000 ;Transmit a/d data to host - DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator - DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. - DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi - DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo - DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec - DC VIDEO+DCRST_DELAY+%0010111 ; Now sit around for at least 520ns while the conversion happens - DC VIDEO+$40000+%0010111 ; Now sit around for at least 520ns while the conversion happens -END_SERIAL_READ_LEFT - -SERIAL_READ_SPLIT - DC END_SERIAL_READ_SPLIT-SERIAL_READ_SPLIT-1 - DC VIDEO+$000000+%1111000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - DC CLK3|S_DELAY|RH|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WL|TH ;h3->lo,SW->lo,Reset_On - - DC CLK3|S_DELAY|RH|H1_1L|H1_2L|H1_3H|H2_1H|H2_2L|H2_3L|WL|TH ;h2->hi - DC CLK3|S_DELAY|RH|H1_1L|H1_2H|H1_3H|H2_1H|H2_2H|H2_3L|WL|TH ;h1->lo - DC CLK3|S_DELAY|RH|H1_1L|H1_2H|H1_3L|H2_1L|H2_2H|H2_3L|WL|TH ;h3->hi - DC CLK3|S_DELAY|RH|H1_1H|H1_2H|H1_3L|H2_1L|H2_2H|H2_3H|WL|TH ;h2->lo - DC CLK3|S_DELAY|RH|H1_1H|H1_2L|H1_3L|H2_1L|H2_2L|H2_3H|WL|TH ;h1->hi - -; DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi -; DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo -; DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi -; DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo -; DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi - - - DC CLK3|PRE_SET_DLY|RL|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WL|TH ;Reset_Off|Delay -SXRL DC $00F0C2 ;Transmit a/d data to host - DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator - DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. - DC CLK3|SW_DELAY|RL|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WH|TH ;SW->hi - DC CLK3|POST_SET_DLY|RL|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WL|TH ;SW->lo - DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec - DC VIDEO+DCRST_DELAY+%0010111 ; Sit around whilst sampling. - DC VIDEO+$50000+%0010111 ; Now sit around for at least 520ns while the conversion happens -END_SERIAL_READ_SPLIT - - -SERIAL_READ_SPLIT_SPECIAL - DC END_SERIAL_READ_SPLIT_SPECIAL-SERIAL_READ_SPLIT_SPECIAL-1 - DC VIDEO+$000000+%1111000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - DC CLK3|S_DELAY|RH|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WL|TH ;h3->lo,SW->lo,Reset_On - - DC CLK3|S_DELAY|RH|H1_1L|H1_2L|H1_3H|H2_1H|H2_2L|H2_3L|WL|TH ;h2->hi - DC CLK3|S_DELAY|RH|H1_1L|H1_2H|H1_3H|H2_1H|H2_2H|H2_3L|WL|TH ;h1->lo - DC CLK3|S_DELAY|RH|H1_1L|H1_2H|H1_3L|H2_1L|H2_2H|H2_3L|WL|TH ;h3->hi - DC CLK3|S_DELAY|RH|H1_1H|H1_2H|H1_3L|H2_1L|H2_2H|H2_3H|WL|TH ;h2->lo - DC CLK3|S_DELAY|RH|H1_1H|H1_2L|H1_3L|H2_1L|H2_2L|H2_3H|WL|TH ;h1->hi - - DC CLK3|PRE_SET_DLY|RL|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WL|TH ;Reset_Off|Delay - DC $00F041 ;Transmit a/d data to host - DC CLK3|$20000|RL|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WL|TH ;Reset_Off|Delay - DC $00F082 ; get the other ADC - DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator - DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. - DC CLK3|SW_DELAY|RL|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WH|TH ;SW->hi - DC CLK3|POST_SET_DLY|RL|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WL|TH ;SW->lo - DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec - DC VIDEO+DCRST_DELAY+%0010111 ; Sit around whilst sampling. - DC VIDEO+$50000+%0010111 ; Now sit around for at least 520ns while the conversion happens -END_SERIAL_READ_SPLIT_SPECIAL - - -; 2->1->3->2 -SERIAL_READ_RIGHT - DC END_SERIAL_READ_RIGHT-SERIAL_READ_RIGHT-1 - DC VIDEO+$000000+%1111000 ; NonInv,DCRestore,StrtRstInt. - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset_On - DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h2->hi - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h1->lo - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi - DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h2->lo - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h1->hi - DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -SXR DC $00F041 ;Transmit a/d data to host - DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator - DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. - DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi - DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo - DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec - DC VIDEO+DCRST_DELAY+%0010111 ; Wait for sampling - DC VIDEO+$30000+%0010111 ; -END_SERIAL_READ_RIGHT - -; This waveforms for test only. Video is left under permamnet reset -SERIAL_READ_LEFT_NULL - DC END_SERIAL_READ_LEFT_NULL-SERIAL_READ_LEFT_NULL-1 - DC VIDEO+$000000+%1111000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset_On - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi - DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo - DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi - DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay - DC $00F000 ;Transmit a/d data to host - DC VIDEO+$000000+%0011010 ; StopDCRestore and StopResetIntegrator - DC VIDEO+I_DELAY+%0001010 ; Integrate for I_DELAY microsec - DC VIDEO+$000000+%0010110 ; Stop Integrate and sel inverting int. - DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi - DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo - DC VIDEO+I_DELAY+%0000110 ; Integrate for I_DELAY microsec - DC VIDEO+DCRST_DELAY+%0010110 ; Now sit around for at least 520ns while the conversion happens - DC VIDEO+$40000+%0010110 ; Now sit around for at least 520ns while the conversion happens -END_SERIAL_READ_LEFT_NULL - - -; These are the three skipping tables. Make sure they're all the same length -SERIAL_SKIP_LEFT ; Serial clocking waveform for skipping left - DC END_SERIAL_SKIP_LEFT-SERIAL_SKIP_LEFT-1 - DC VIDEO+$000000+%1011000 ; Change nearly everything - DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h2->hi - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h1->lo - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi - DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h2->lo - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h1->hi - DC CLK3|S_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay - DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -END_SERIAL_SKIP_LEFT - -SERIAL_SKIP_RIGHT ; Serial clocking waveform for skipping right - DC END_SERIAL_SKIP_RIGHT-SERIAL_SKIP_RIGHT-1 - DC VIDEO+$000000+%1011000 ; Change nearly everything - DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi - DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi - DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo - DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi - DC CLK3|S_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay - DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -END_SERIAL_SKIP_RIGHT - -SERIAL_SKIP_SPLIT ; Serial clocking waveform for skipping both ends - DC END_SERIAL_SKIP_SPLIT-SERIAL_SKIP_SPLIT-1 - DC VIDEO+$000000+%1011000 ; Change nearly everything - DC CLK3|S_DELAY_SKIP|RH|H2_1H|H2_2L|H2_3L|H1_1L|H1_2L|H1_3H|WL|TH ;h2->hi - DC CLK3|S_DELAY_SKIP|RH|H2_1H|H2_2H|H2_3L|H1_1L|H1_2H|H1_3H|WL|TH ;h1->lo - DC CLK3|S_DELAY_SKIP|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi - DC CLK3|S_DELAY_SKIP|RH|H2_1L|H2_2H|H2_3H|H1_1H|H1_2H|H1_3L|WL|TH ;h2->lo - DC CLK3|S_DELAY_SKIP|RH|H2_1L|H2_2L|H2_3H|H1_1H|H1_2L|H1_3L|WL|TH ;h1->hi - DC CLK3|S_DELAY_SKIP|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay - DC CLK3|SW_DELAY_SKIP|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -END_SERIAL_SKIP_SPLIT - -;; Put all the following code in SRAM. -; ORG Y:$1C0,Y:$1C0 ; Download address -;; persistent immage erase voltage tables -VSUBN - VOLTS VSUB,60.0 ; Vsub 0.0 140 V, pin # -ERHI DC ERHI_END-ERHI-1 - VOLTS VSUB,0 ; Vsub 0.0 140 V, pin # -; VOLTS V1_HI,9 ; Vertical High -; VOLTS V1_LO,9 ; Vertical Low -; VOLTS V2_HI,9 ; Vertical High -; VOLTS V2_LO,9 ; Vertical Low -; VOLTS V3_HI,9 ; Vertical High -; VOLTS V3_LO,9 ; Vertical Low -; VOLTS FS1_HI,9 ; Vertical High -; VOLTS FS1_LO,9 ; Vertical Low -; VOLTS FS2_HI,9 ; Vertical High -; VOLTS FS2_LO,9 ; Vertical Low -; VOLTS FS3_HI,9 ; Vertical High -; VOLTS FS3_LO,9 ; Vertical Low - DC $200100+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #1, Vertical Clock 1 - DC $200200+@CVI((9+Vmax)/(2*Vmax)*255) - DC $200400+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #2, Vertical Clock 2 - DC $200800+@CVI((9+Vmax)/(2*Vmax)*255) - DC $202000+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #3, Vertical Clock 3 - DC $204000+@CVI((9+Vmax)/(2*Vmax)*255) - DC $208000+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #4, Frame Store 1 - DC $210000+@CVI((9+Vmax)/(2*Vmax)*255) - DC $220100+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #5, Frame Store 2 - DC $220200+@CVI((9+Vmax)/(2*Vmax)*255) - DC $220400+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #6, Frame Store 3 - DC $220800+@CVI((9+Vmax)/(2*Vmax)*255) - DC $222000+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #7, Transfer Gate 2 - DC $224000+@CVI((9+Vmax)/(2*Vmax)*255) - DC $228000+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #8, Transger Gate 1 - DC $230000+@CVI((9+Vmax)/(2*Vmax)*255) - DC $240100+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #9, Unused - DC $240200+@CVI((9+Vmax)/(2*Vmax)*255) - DC $240400+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #10, Unused - DC $240800+@CVI((9+Vmax)/(2*Vmax)*255) - DC $242000+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #11, Unused - DC $244000+@CVI((9+Vmax)/(2*Vmax)*255) - DC $248000+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #12, Unused - DC $250000+@CVI((9+Vmax)/(2*Vmax)*255) -ERHI_END DC EPUR-ERHI_END-1 -; VOLTS V1_HI,5.0 ; Vertical High -; VOLTS V1_LO,-3.0 ; Vertical Low -; VOLTS V2_HI,5.0 ; Vertical High -; VOLTS V2_LO,-3.0 ; Vertical Low -; VOLTS V3_HI,5.0 ; Vertical High -; VOLTS V3_LO,-3.0 ; Vertical Low -; VOLTS FS1_HI,5.0 ; Vertical High -; VOLTS FS1_LO,-3.0 ; Vertical Low -; VOLTS FS2_HI,5.0 ; Vertical High -; VOLTS FS2_LO,-3.0 ; Vertical Low -; VOLTS FS3_HI,5.0 ; Vertical High -; VOLTS FS3_LO,-3.0 ; Vertical Low -;Return to normal voltages - DC $200100+@CVI((V1_HI+Vmax)/(2*Vmax)*255) ; Pin #1, Vertical Clock 1 - DC $200200+@CVI((V1_LO+Vmax)/(2*Vmax)*255) - DC $200400+@CVI((V2_HI+Vmax)/(2*Vmax)*255) ; Pin #2, Vertical Clock 2 - DC $200800+@CVI((V2_LO+Vmax)/(2*Vmax)*255) - DC $202000+@CVI((V3_HI+Vmax)/(2*Vmax)*255) ; Pin #3, Vertical Clock 3 - DC $204000+@CVI((V3_LO+Vmax)/(2*Vmax)*255) - DC $208000+@CVI((V1_HI+Vmax)/(2*Vmax)*255) ; Pin #4, Frame Store 1 - DC $210000+@CVI((V1_LO+Vmax)/(2*Vmax)*255) - DC $220100+@CVI((V2_HI+Vmax)/(2*Vmax)*255) ; Pin #5, Frame Store 2 - DC $220200+@CVI((V2_LO+Vmax)/(2*Vmax)*255) - DC $220400+@CVI((V3_HI+Vmax)/(2*Vmax)*255) ; Pin #6, Frame Store 3 - DC $220800+@CVI((V3_LO+Vmax)/(2*Vmax)*255) - DC $222000+@CVI((V1_HI+Vmax)/(2*Vmax)*255) ; Pin #7, Transfer Gate 2 - DC $224000+@CVI((V1_LO+Vmax)/(2*Vmax)*255) - DC $228000+@CVI((V2_HI+Vmax)/(2*Vmax)*255) ; Pin #8, Transger Gate 1 - DC $230000+@CVI((V2_LO+Vmax)/(2*Vmax)*255) - DC $240100+@CVI((V3_HI+Vmax)/(2*Vmax)*255) ; Pin #9, Unused - DC $240200+@CVI((V3_LO+Vmax)/(2*Vmax)*255) - DC $240400+@CVI((FS1_HI+Vmax)/(2*Vmax)*255) ; Pin #10, Unused - DC $240800+@CVI((FS1_LO+Vmax)/(2*Vmax)*255) - DC $242000+@CVI((FS2_HI+Vmax)/(2*Vmax)*255) ; Pin #11, Unused - DC $244000+@CVI((FS2_LO+Vmax)/(2*Vmax)*255) - DC $248000+@CVI((FS3_HI+Vmax)/(2*Vmax)*255) ; Pin #12, Unused - DC $250000+@CVI((FS3_LO+Vmax)/(2*Vmax)*255) - - DC $2A0100+@CVI((RL_HI+Vmax)/(2*Vmax)*255) ; Pin #34, Reset Gate Upper - DC $2A0200+@CVI((RL_LO+Vmax)/(2*Vmax)*255) - DC $2A0400+@CVI((RU_HI+Vmax)/(2*Vmax)*255) ; Pin #35, Reset Gate Lower - DC $2A0800+@CVI((RU_LO+Vmax)/(2*Vmax)*255) - -EPUR DC EPUR_END-EPUR-1 - DC $200100+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #1, Vertical Clock 1 - DC $200200+@CVI((-9+Vmax)/(2*Vmax)*255) - DC $200400+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #2, Vertical Clock 2 - DC $200800+@CVI((-9+Vmax)/(2*Vmax)*255) - DC $202000+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #3, Vertical Clock 3 - DC $204000+@CVI((-9+Vmax)/(2*Vmax)*255) - DC $208000+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #4, Frame Store 1 - DC $210000+@CVI((-9+Vmax)/(2*Vmax)*255) - DC $220100+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #5, Frame Store 2 - DC $220200+@CVI((-9+Vmax)/(2*Vmax)*255) - DC $220400+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #6, Frame Store 3 - DC $220800+@CVI((-9+Vmax)/(2*Vmax)*255) - DC $222000+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #7, Transfer Gate 2 - DC $224000+@CVI((-9+Vmax)/(2*Vmax)*255) - DC $228000+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #8, Transger Gate 1 - DC $230000+@CVI((-9+Vmax)/(2*Vmax)*255) - DC $240100+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #9, Unused - DC $240200+@CVI((-9+Vmax)/(2*Vmax)*255) - DC $240400+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #10, Unused - DC $240800+@CVI((-9+Vmax)/(2*Vmax)*255) - DC $242000+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #11, Unused - DC $244000+@CVI((-9+Vmax)/(2*Vmax)*255) - DC $248000+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #12, Unused - DC $250000+@CVI((-9+Vmax)/(2*Vmax)*255) - - DC $2A0100+@CVI((-6+Vmax)/(2*Vmax)*255) ; Pin #34, Reset Gate Upper - DC $2A0200+@CVI((-6+Vmax)/(2*Vmax)*255) - DC $2A0400+@CVI((-6+Vmax)/(2*Vmax)*255) ; Pin #35, Reset Gate Lower - DC $2A0800+@CVI((-6+Vmax)/(2*Vmax)*255) - -EPUR_END - -; Code for ARC32 = universal clock driver board -DACS DC END_DACS-DACS-1 - DC $2A0080 ; DAC = unbuffered mode - - DC $200100+@CVI((V1_HI+Vmax)/(2*Vmax)*255) ; Pin #1, Vertical Clock 1 - DC $200200+@CVI((V1_LO+Vmax)/(2*Vmax)*255) - DC $200400+@CVI((V2_HI+Vmax)/(2*Vmax)*255) ; Pin #2, Vertical Clock 2 - DC $200800+@CVI((V2_LO+Vmax)/(2*Vmax)*255) - DC $202000+@CVI((V3_HI+Vmax)/(2*Vmax)*255) ; Pin #3, Vertical Clock 3 - DC $204000+@CVI((V3_LO+Vmax)/(2*Vmax)*255) - DC $208000+@CVI((V1_HI+Vmax)/(2*Vmax)*255) ; Pin #4, Frame Store 1 - DC $210000+@CVI((V1_LO+Vmax)/(2*Vmax)*255) - DC $220100+@CVI((V2_HI+Vmax)/(2*Vmax)*255) ; Pin #5, Frame Store 2 - DC $220200+@CVI((V2_LO+Vmax)/(2*Vmax)*255) - DC $220400+@CVI((V3_HI+Vmax)/(2*Vmax)*255) ; Pin #6, Frame Store 3 - DC $220800+@CVI((V3_LO+Vmax)/(2*Vmax)*255) - DC $222000+@CVI((V1_HI+Vmax)/(2*Vmax)*255) ; Pin #7, Vertical Clock 1 - DC $224000+@CVI((V1_LO+Vmax)/(2*Vmax)*255) - DC $228000+@CVI((V2_HI+Vmax)/(2*Vmax)*255) ; Pin #8, Vertical Clock 2 - DC $230000+@CVI((V2_LO+Vmax)/(2*Vmax)*255) - - DC $240100+@CVI((V3_HI+Vmax)/(2*Vmax)*255) ; Pin #9, Vertical Clock 3 - DC $240200+@CVI((V3_LO+Vmax)/(2*Vmax)*255) - DC $240400+@CVI((FS1_HI+Vmax)/(2*Vmax)*255) ; Pin #10, Frame Store 1 - DC $240800+@CVI((FS1_LO+Vmax)/(2*Vmax)*255) - DC $242000+@CVI((FS2_HI+Vmax)/(2*Vmax)*255) ; Pin #11, Frame Store 2 - DC $244000+@CVI((FS2_LO+Vmax)/(2*Vmax)*255) - DC $248000+@CVI((FS3_HI+Vmax)/(2*Vmax)*255) ; Pin #12, Frame Store 3 - DC $250000+@CVI((FS3_LO+Vmax)/(2*Vmax)*255) - - DC $260100+@CVI((H1U2_L1_HI+Vmax)/(2*Vmax)*255) ; Pin #13, Horizontal 1 Upper - DC $260200+@CVI((H1U2_L1_LO+Vmax)/(2*Vmax)*255) - DC $260400+@CVI((H2U2_L1_HI+Vmax)/(2*Vmax)*255) ; Pin #14, Horizontal 2 Upper - DC $260800+@CVI((H2U2_L1_LO+Vmax)/(2*Vmax)*255) - DC $262000+@CVI((H3U2_L1_HI+Vmax)/(2*Vmax)*255) ; Pin #15, Horizontal 3 Upper - DC $264000+@CVI((H3U2_L1_LO+Vmax)/(2*Vmax)*255) - DC $268000+@CVI((H1U1_L2_HI+Vmax)/(2*Vmax)*255) ; Pin #16, Horizontal 1 Lower - DC $270000+@CVI((H1U1_L2_LO+Vmax)/(2*Vmax)*255) - DC $280100+@CVI((H2U1_L2_HI+Vmax)/(2*Vmax)*255) ; Pin #17, Horizontal 2 Lower - DC $280200+@CVI((H2U1_L2_LO+Vmax)/(2*Vmax)*255) - DC $280400+@CVI((H3U1_L2_HI+Vmax)/(2*Vmax)*255) ; Pin #18, Horizontal 3 Lower - DC $280800+@CVI((H3U1_L2_LO+Vmax)/(2*Vmax)*255) - DC $282000+@CVI((SWL_HI+Vmax)/(2*Vmax)*255) ; Pin #19, Summing Well Upper - DC $284000+@CVI((SWL_LO+Vmax)/(2*Vmax)*255) - DC $288000+@CVI((SWU_HI+Vmax)/(2*Vmax)*255) ; Pin #33, Summing Well Lower - DC $290000+@CVI((SWU_LO+Vmax)/(2*Vmax)*255) - DC $2A0100+@CVI((RL_HI+Vmax)/(2*Vmax)*255) ; Pin #34, Reset Gate Upper - DC $2A0200+@CVI((RL_LO+Vmax)/(2*Vmax)*255) - DC $2A0400+@CVI((RU_HI+Vmax)/(2*Vmax)*255) ; Pin #35, Reset Gate Lower - DC $2A0800+@CVI((RU_LO+Vmax)/(2*Vmax)*255) - DC $2A2000+@CVI((T1_HI+Vmax)/(2*Vmax)*255) ; Pin #36, Transfer Gate 1 - DC $2A4000+@CVI((T1_LO+Vmax)/(2*Vmax)*255) - DC $2A8000+@CVI((T2_HI+Vmax)/(2*Vmax)*255) ; Pin #37, Transfer Gate 2 - DC $2B0000+@CVI((T2_LO+Vmax)/(2*Vmax)*255) - - -; DC bias voltages for the LBL CCD chip - VOLTS VSUB,60.0 ; Vsub 0.0 140 V - VOLTS RAMP,5.0 ; Vsub AVG RAMP RATE - VOLTS VDDL2,-22.0 ; Vdd -5.1 -25V - VOLTS VDDU2,-22.0 ; Vdd -5.1 -25V - VOLTS VDDL1,-22.0 ; Vdd -5.1 -25V - VOLTS VDDU1,-22.0 ; Vdd -5.1 -25V - VOLTS VRL2,-12.5 ; Vr -5.1 -25V - VOLTS VRU2,-12.5 ; Vr -5.1 -25V - VOLTS VRL1,-12.5 ; Vr -5.1 -25V - VOLTS VRU1,-12.5 ; Vr -5.1 -25V - VOLTS VOGL2,2.50 ; Vopg -10 10 V - VOLTS VOGU2,2.50 ; Vopg -10 10 V - VOLTS VOGL1,2.50 ; Vopg -10 10 V - VOLTS VOGU1,3.50 ; Vopg -10 10 V - - -; Set gain and integrator speed. (77, bb, dd, ee; low gain to high) - -; Board #0 -; DC $0c3c77 ; Gain x1, slow integ. speed, board #0 -; DC $0c3f77 ; Gain x1, fast integrate speed - DC $0c3cbb ; Gain x2 -; DC $0c3cdd ; Gain x4.75, slow -; DC $0c3fee ; Gain x9.50 -; DC $0c3cee ; Gain x9.50, slow - -; Board #1 -; DC $1c3c77 ; Gain x1, slow integ. speed, board #1 -; DC $1c3f77 ; Gain x1, fast integrate speed - DC $1c3cbb ; Gain x2, slow -; DC $1c3cdd ; Gain x4.75, slow -; DC $1c3cee ; Gain x9.50, slow - -GAIN_SETTING DC VID0+$0D000E - -; Set offset voltages in Video boards - -; Board #0 - DC $0C8000+OFFSET0 - DC $0CC000+OFFSET1 - -; Board #1 - DC $1C8000+OFFSET2 - DC $1CC000+OFFSET3 - -; Bias voltages in the Video Boards used only for diagnostics (not connected to CCD) -; Bias range = -10V to +10V -BIAS_TST EQU $700 ; -1.25V - -; Board #0 - DC $0E0000+BIAS_TST ; DB-25 Pin 9 - DC $0E4000+BIAS_TST ; DB-25 Pin 10 - -; Board #1 - DC $1E0000+BIAS_TST ; DB-25 Pin 9 - DC $1E4000+BIAS_TST ; DB-25 Pin 10 - -END_DACS - - -; Pixel table generated in "timCCD.asm" -PXL_TBL DC 0 - - diff --git a/DSP/DBSP-red/tim b/DSP/DBSP-red/tim deleted file mode 100755 index 6b363c7a..00000000 --- a/DSP/DBSP-red/tim +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh -# - echo "" - echo "Assembling DSP code for the LBNL 2k x 4k CCD" - echo "" -# -# DOWNLOAD selects application code to be loaded from EEPROM or -# downloaded from the host over the fiber optic link -# -# DOWNLOAD = HOST or ROM - -DOWNLOAD=HOST -WAVEFORM_FILE=LBNL_2Kx4K.waveforms -DST_FILE=tim - -echo "Compiling...." -wine /opt/CLAS563/BIN/ASM56300 -b -ltim.ls -d DOWNLOAD $DOWNLOAD -d WAVEFORM_FILE "$WAVEFORM_FILE" tim.asm -wine /opt/CLAS563/BIN/DSPLNK -btim.cld -v tim.cln -rm -f "$DST_FILE".lod -wine /opt/CLAS563/BIN/CLDLOD tim.cld > "$DST_FILE".lod -rm tim.cln ; rm tim.cld - -if [ "$DOWNLOAD" = "HOST" ] ; then - echo "" - echo "Created file 'tim.lod' for downloading over optical fiber" - echo "" -fi - -if [ "$DOWNLOAD" = "ROM" ] ; then - echo "" - echo "Created Motorola S-record file 'tim.s' for EEPROM burning" - echo "" - srec -bs tim.lod - rm tim.lod -fi diff --git a/DSP/DBSP-red/tim.asm b/DSP/DBSP-red/tim.asm deleted file mode 100755 index 2d094303..00000000 --- a/DSP/DBSP-red/tim.asm +++ /dev/null @@ -1,348 +0,0 @@ - COMMENT * - -This file is used to generate boot DSP code for the 250 MHz fiber optic - timing board using a DSP56303 as its main processor. It supports - split serial and frame transfer, but not split parallel nor binning. - * - PAGE 132 ; Printronix page width - 132 columns - -; Change history: -; 2011-10-23 (GR): Moved the serial register flush after each parallel skip (was after all parallel skips) to prevent overflowing of the serial reg. - - -; Include the boot and header files so addressing is easy - INCLUDE "timhdr.asm" - INCLUDE "timboot.asm" - - ORG P:,P: - -CC EQU CCDVIDREV5+TIMREV5+TEMP_POLY+UTILREV3+SPLIT_SERIAL+SUBARRAY+BINNING+SHUTTER_CC - -; Put number of words of application in P: for loading application from EEPROM - DC TIMBOOT_X_MEMORY-@LCV(L)-1 - -; Define CLOCK as a macro to produce in-line code to reduce execution time -CLOCK MACRO - JCLR #SSFHF,X:HDR,* ; Don't overfill the WRSS FIFO - REP Y:(R0)+ ; Repeat # of times at address Y:(R0)+ - MOVEP Y:(R0)+,Y:WRSS ; Write the waveform to the FIFO - ENDM - -; Set software to IDLE mode -START_IDLE_CLOCKING - MOVE #IDLE,R0 - NOP - MOVE R0,X: full image readout - NOP - TST A - JNE no prescan pixels - TST A - JLE no bias pixels - TST A - JLE milliseconds -99 FFFF82 TPCR EQU $FFFF82 ; Timer prescaler count register -100 000000 TIM_BIT EQU 0 ; Set to enable the timer -101 000009 TRM EQU 9 ; Set to enable the timer preloading -102 000015 TCF EQU 21 ; Set when timer counter = compare register -103 -104 ; Board specific addresses and constants -105 FFFFF1 RDFO EQU $FFFFF1 ; Read incoming fiber optic data byte -106 FFFFF2 WRFO EQU $FFFFF2 ; Write fiber optic data replies -107 FFFFF3 WRSS EQU $FFFFF3 ; Write switch state -108 FFFFF5 WRLATCH EQU $FFFFF5 ; Write to a latch -109 010000 RDAD EQU $010000 ; Read A/D values into the DSP -110 000009 EF EQU 9 ; Serial receiver empty flag -111 -112 ; DSP port A bit equates -113 000000 PWROK EQU 0 ; Power control board says power is OK -114 000001 LED1 EQU 1 ; Control one of two LEDs -115 000002 LVEN EQU 2 ; Low voltage power enable -116 000003 HVEN EQU 3 ; High voltage power enable -117 00000E SSFHF EQU 14 ; Switch state FIFO half full flag -118 00000A EXT_IN0 EQU 10 ; External digital I/O to the timing board -119 00000B EXT_IN1 EQU 11 -120 00000C EXT_OUT0 EQU 12 -121 00000D EXT_OUT1 EQU 13 -122 -123 ; Port D equate -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 timhdr.asm Page 3 - - - -124 000000 SLAVE EQU 0 ; Set if not a master by having jumper 2 not installe -d -125 000001 SSFEF EQU 1 ; Switch state FIFO empty flag -126 -127 ; Other equates -128 000002 WRENA EQU 2 ; Enable writing to the EEPROM -129 -130 ; Latch U25 bit equates -131 000000 CDAC EQU 0 ; Clear the analog board DACs -132 000002 ENCK EQU 2 ; Enable the clock outputs -133 000004 SHUTTER EQU 4 ; Control the shutter -134 000005 TIM_U_RST EQU 5 ; Reset the utility board -135 -136 ; Software status bits, defined at X: only restore register -s -288 P:00000F P:00000F 545C00 END_BYT MOVE A1,X:(R4)+ ; Put the 24-bit word into the SCI buffer -289 P:000010 P:000010 60F400 MOVE #SRXL,R0 ; Re-establish first address of SCI interfac -e - FFFF98 -290 P:000012 P:000012 2C0000 MOVE #0,A1 ; For zeroing out SCI_A1 -291 P:000013 P:000013 602700 MID_BYT MOVE R0,X: CLR SR, return - 0000AC -414 P:0000AB P:0000AB 0C00AF JMP try again -415 P:0000AC P:0000AC 0A8989 TST2 JCLR #EF,X:HDR,CLR_CC ; Low, High => try again -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 timboot.asm Page 8 - - - - 0000D1 -416 P:0000AE P:0000AE 0C00A9 JMP read FIFO -417 P:0000AF P:0000AF 0A8989 TST3 JCLR #EF,X:HDR,CHK_FO - 0000A9 -418 -419 P:0000B1 P:0000B1 08F4BB MOVEP #$028FE2,X:BCR ; Slow down RDFO access - 028FE2 -420 P:0000B3 P:0000B3 000000 NOP -421 P:0000B4 P:0000B4 000000 NOP -422 P:0000B5 P:0000B5 5FF000 MOVE Y:RDFO,B - FFFFF1 -423 P:0000B7 P:0000B7 2B0000 MOVE #0,B2 -424 P:0000B8 P:0000B8 0140CE AND #$FF,B - 0000FF -425 P:0000BA P:0000BA 0140CD CMP #>$AC,B ; It must be $AC to be a valid word - 0000AC -426 P:0000BC P:0000BC 0E20D1 JNE SR carry bit = 1 -438 P:0000CE P:0000CE 08F4BB MOVEP #$028FE1,X:BCR ; Restore RDFO access - 028FE1 -439 P:0000D0 P:0000D0 00000C RTS -440 P:0000D1 P:0000D1 0AF940 CLR_CC BCLR #0,SR ; Not valid word => SR carry bit = 0 -441 P:0000D2 P:0000D2 08F4BB MOVEP #$028FE1,X:BCR ; Restore RDFO access - 028FE1 -442 P:0000D4 P:0000D4 00000C RTS -443 -444 ; Test the SCI (= synchronous communications interface) for new words -445 P:0000D5 P:0000D5 44F000 CHK_SCI MOVE X:(SCI_TABLE+33),X0 - 000421 -446 P:0000D7 P:0000D7 228E00 MOVE R4,A -447 P:0000D8 P:0000D8 209000 MOVE X0,R0 -448 P:0000D9 P:0000D9 200045 CMP X0,A -449 P:0000DA P:0000DA 0EA0D1 JEQ 0 -492 P:000108 P:000108 0EA08D JEQ when not -615 P:00017E P:00017E 601F00 MOVE R0,X: when not -621 P:000182 P:000182 601F00 MOVE R0,X:1,X:HPCR ; All pins enabled as GPIO - 000001 -655 P:0001A1 P:0001A1 08F489 MOVEP #$810C,X:HDR - 00810C -656 P:0001A3 P:0001A3 08F488 MOVEP #$B10E,X:HDDR ; Data Direction Register - 00B10E -657 ; (1 for Output, 0 for Input) -658 -659 ; Port B conversion from software bits to schematic labels -660 ; PB0 = PWROK PB08 = PRSFIFO* -661 ; PB1 = LED1 PB09 = EF* -662 ; PB2 = LVEN PB10 = EXT-IN0 -663 ; PB3 = HVEN PB11 = EXT-IN1 -664 ; PB4 = STATUS0 PB12 = EXT-OUT0 -665 ; PB5 = STATUS1 PB13 = EXT-OUT1 -666 ; PB6 = STATUS2 PB14 = SSFHF* -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 timboot.asm Page 13 - - - -667 ; PB7 = STATUS3 PB15 = SELSCI -668 -669 ; Program the serial port ESSI0 = Port C for serial communication with -670 ; the utility board -671 P:0001A5 P:0001A5 07F43F MOVEP #>0,X:PCRC ; Software reset of ESSI0 - 000000 -672 P:0001A7 P:0001A7 07F435 MOVEP #$180809,X:CRA0 ; Divide 100 MHz by 20 to get 5.0 MHz - 180809 -673 ; DC[4:0] = 0 for non-network operation -674 ; WL0-WL2 = 3 for 24-bit data words -675 ; SSC1 = 0 for SC1 not used -676 P:0001A9 P:0001A9 07F436 MOVEP #$020020,X:CRB0 ; SCKD = 1 for internally generated clock - 020020 -677 ; SCD2 = 0 so frame sync SC2 is an output -678 ; SHFD = 0 for MSB shifted first -679 ; FSL = 0, frame sync length not used -680 ; CKP = 0 for rising clock edge transitions -681 ; SYN = 0 for asynchronous -682 ; TE0 = 1 to enable transmitter #0 -683 ; MOD = 0 for normal, non-networked mode -684 ; TE0 = 0 to NOT enable transmitter #0 yet -685 ; RE = 1 to enable receiver -686 P:0001AB P:0001AB 07F43F MOVEP #%111001,X:PCRC ; Control Register (0 for GPIO, 1 for ESSI) - 000039 -687 P:0001AD P:0001AD 07F43E MOVEP #%000110,X:PRRC ; Data Direction Register (0 for In, 1 for O -ut) - 000006 -688 P:0001AF P:0001AF 07F43D MOVEP #%000100,X:PDRC ; Data Register - WR_ENA* = 1 - 000004 -689 -690 ; Port C version = Analog boards -691 ; MOVEP #$000809,X:CRA0 ; Divide 100 MHz by 20 to get 5.0 MHz -692 ; MOVEP #$000030,X:CRB0 ; SCKD = 1 for internally generated clock -693 ; MOVEP #%100000,X:PCRC ; Control Register (0 for GPIO, 1 for ESSI) -694 ; MOVEP #%000100,X:PRRC ; Data Direction Register (0 for In, 1 for Out) -695 ; MOVEP #%000000,X:PDRC ; Data Register: 'not used' = 0 outputs -696 -697 P:0001B1 P:0001B1 07F43C MOVEP #0,X:TX00 ; Initialize the transmitter to zero - 000000 -698 P:0001B3 P:0001B3 000000 NOP -699 P:0001B4 P:0001B4 000000 NOP -700 P:0001B5 P:0001B5 013630 BSET #TE,X:CRB0 ; Enable the SSI transmitter -701 -702 ; Conversion from software bits to schematic labels for Port C -703 ; PC0 = SC00 = UTL-T-SCK -704 ; PC1 = SC01 = 2_XMT = SYNC on prototype -705 ; PC2 = SC02 = WR_ENA* -706 ; PC3 = SCK0 = TIM-U-SCK -707 ; PC4 = SRD0 = UTL-T-STD -708 ; PC5 = STD0 = TIM-U-STD -709 -710 ; Program the serial port ESSI1 = Port D for serial transmission to -711 ; the analog boards and two parallel I/O input pins -712 P:0001B6 P:0001B6 07F42F MOVEP #>0,X:PCRD ; Software reset of ESSI0 - 000000 -713 P:0001B8 P:0001B8 07F425 MOVEP #$000809,X:CRA1 ; Divide 100 MHz by 20 to get 5.0 MHz - 000809 -714 ; DC[4:0] = 0 -715 ; WL[2:0] = ALC = 0 for 8-bit data words -716 ; SSC1 = 0 for SC1 not used -717 P:0001BA P:0001BA 07F426 MOVEP #$000030,X:CRB1 ; SCKD = 1 for internally generated clock - 000030 -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 timboot.asm Page 14 - - - -718 ; SCD2 = 1 so frame sync SC2 is an output -719 ; SHFD = 0 for MSB shifted first -720 ; CKP = 0 for rising clock edge transitions -721 ; TE0 = 0 to NOT enable transmitter #0 yet -722 ; MOD = 0 so its not networked mode -723 P:0001BC P:0001BC 07F42F MOVEP #%100000,X:PCRD ; Control Register (0 for GPIO, 1 for ESSI) - 000020 -724 ; PD3 = SCK1, PD5 = STD1 for ESSI -725 P:0001BE P:0001BE 07F42E MOVEP #%000100,X:PRRD ; Data Direction Register (0 for In, 1 for O -ut) - 000004 -726 P:0001C0 P:0001C0 07F42D MOVEP #%000100,X:PDRD ; Data Register: 'not used' = 0 outputs - 000004 -727 P:0001C2 P:0001C2 07F42C MOVEP #0,X:TX10 ; Initialize the transmitter to zero - 000000 -728 P:0001C4 P:0001C4 000000 NOP -729 P:0001C5 P:0001C5 000000 NOP -730 P:0001C6 P:0001C6 012630 BSET #TE,X:CRB1 ; Enable the SSI transmitter -731 -732 ; Conversion from software bits to schematic labels for Port D -733 ; PD0 = SC10 = 2_XMT_? input -734 ; PD1 = SC11 = SSFEF* input -735 ; PD2 = SC12 = PWR_EN -736 ; PD3 = SCK1 = TIM-A-SCK -737 ; PD4 = SRD1 = PWRRST -738 ; PD5 = STD1 = TIM-A-STD -739 -740 ; Program the SCI port to communicate with the utility board -741 P:0001C7 P:0001C7 07F41C MOVEP #$0B04,X:SCR ; SCI programming: 11-bit asynchronous - 000B04 -742 ; protocol (1 start, 8 data, 1 even parity -, -743 ; 1 stop); LSB before MSB; enable receiver -744 ; and its interrupts; transmitter interrup -ts -745 ; disabled. -746 P:0001C9 P:0001C9 07F41B MOVEP #$0003,X:SCCR ; SCI clock: utility board data rate = - 000003 -747 ; (390,625 kbits/sec); internal clock. -748 P:0001CB P:0001CB 07F41F MOVEP #%011,X:PCRE ; Port Control Register = RXD, TXD enabled - 000003 -749 P:0001CD P:0001CD 07F41E MOVEP #%000,X:PRRE ; Port Direction Register (0 = Input) - 000000 -750 -751 ; PE0 = RXD -752 ; PE1 = TXD -753 ; PE2 = SCLK -754 -755 ; Program one of the three timers as an exposure timer -756 P:0001CF P:0001CF 07F403 MOVEP #$C34F,X:TPLR ; Prescaler to generate millisecond timer, - 00C34F -757 ; counting from the system clock / 2 = 50 M -Hz -758 P:0001D1 P:0001D1 07F40F MOVEP #$208200,X:TCSR0 ; Clear timer complete bit and enable presca -ler - 208200 -759 P:0001D3 P:0001D3 07F40E MOVEP #0,X:TLR0 ; Timer load register - 000000 -760 -761 ; Enable interrupts for the SCI port only -762 P:0001D5 P:0001D5 08F4BF MOVEP #$000000,X:IPRC ; No interrupts allowed - 000000 -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 timboot.asm Page 15 - - - -763 P:0001D7 P:0001D7 08F4BE MOVEP #>$80,X:IPRP ; Enable SCI interrupt only, IPR = 1 - 000080 -764 P:0001D9 P:0001D9 00FCB8 ANDI #$FC,MR ; Unmask all interrupt levels -765 -766 ; Initialize the fiber optic serial receiver circuitry -767 P:0001DA P:0001DA 061480 DO #20,L_FO_INIT - 0001DF -768 P:0001DC P:0001DC 5FF000 MOVE Y:RDFO,B - FFFFF1 -769 P:0001DE P:0001DE 0605A0 REP #5 -770 P:0001DF P:0001DF 000000 NOP -771 L_FO_INIT -772 -773 ; Pulse PRSFIFO* low to revive the CMDRST* instruction and reset the FIFO -774 P:0001E0 P:0001E0 44F400 MOVE #1000000,X0 ; Delay by 10 milliseconds - 0F4240 -775 P:0001E2 P:0001E2 06C400 DO X0,*+3 - 0001E4 -776 P:0001E4 P:0001E4 000000 NOP -777 P:0001E5 P:0001E5 0A8908 BCLR #8,X:HDR -778 P:0001E6 P:0001E6 0614A0 REP #20 -779 P:0001E7 P:0001E7 000000 NOP -780 P:0001E8 P:0001E8 0A8928 BSET #8,X:HDR -781 -782 ; Reset the utility board -783 P:0001E9 P:0001E9 0A0F05 BCLR #5,X:$AC,X0 - 0000AC -849 P:00022A P:00022A 440100 MOVE X0,X: full image readout -1003 P:00024F P:00024F 000000 NOP -1004 P:000250 P:000250 200003 TST A -1005 P:000251 P:000251 0E2259 JNE no prescan pixels -1081 P:00028C P:00028C 200003 TST A -1082 P:00028D P:00028D 0EF296 JLE no bias pixels -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 tim.asm Page 21 - - - -1127 P:0002B3 P:0002B3 200003 TST A -1128 P:0002B4 P:0002B4 0EF2BD JLE Turn on +36V -1199 P:0002EB P:0002EB 44F400 MOVE #10000000,X0 - 989680 -1200 P:0002ED P:0002ED 06C400 DO X0,*+3 ; Wait 100 millisec for settling - 0002EF -1201 P:0002EF P:0002EF 000000 NOP -1202 P:0002F0 P:0002F0 00000C RTS -1203 -1204 -1205 RAW_COMMAND -1206 P:0002F1 P:0002F1 012F23 BSET #3,X:PCRD ; Turn on the serial clock -1207 P:0002F2 P:0002F2 56DB00 MOVE X:(R3)+,A ; Get the command which should just be a wor -d -1208 P:0002F3 P:0002F3 0D020C JSR $10,X0 - 000010 -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 timCCDmisc.asm Page 24 - - - -1287 P:000336 P:000336 0D0327 JSR $10,X0 - 000010 -1298 P:00033F P:00033F 0D0327 JSR 1.0 microsec per pixel -1459 P:0003D1 P:0003D1 000000 NOP -1460 P:0003D2 P:0003D2 014180 ADD #1,A ; Pixel data = Pixel data + 1 -1461 P:0003D3 P:0003D3 000000 NOP -1462 P:0003D4 P:0003D4 21CF00 MOVE A,B -1463 P:0003D5 P:0003D5 0D03D9 JSR 1,X0 - 000001 -1542 P:000418 P:000418 20001B CLR B -1543 -1544 P:000419 P:000419 060F80 DO #15,CHK_GAIN - 00041E -1545 P:00041B P:00041B 200005 CMP B,A -1546 P:00041C P:00041C 0EA420 JEQ 7,X0 - 000007 -1615 P:000449 P:000449 20004E AND X0,B ; Get 3 least significant bits of clock # -1616 P:00044A P:00044A 01408D CMP #0,B -1617 P:00044B P:00044B 0E244E JNE $FF,Y0 ; Mask off just 8 bits - 0000FF -1658 P:000475 P:000475 200056 AND Y0,A -1659 P:000476 P:000476 200042 OR X0,A -1660 P:000477 P:000477 0C047A JMP 24,X0 ; Check for argument less than 32 - 000018 -1691 P:00048F P:00048F 200045 CMP X0,A -1692 P:000490 P:000490 0AF0A1 JGE ERR_SM1 - 0004CF -1693 P:000492 P:000492 21CF00 MOVE A,B -1694 P:000493 P:000493 44F400 MOVE #>7,X0 - 000007 -1695 P:000495 P:000495 20004E AND X0,B -1696 P:000496 P:000496 44F400 MOVE #>$18,X0 - 000018 -1697 P:000498 P:000498 200046 AND X0,A -1698 P:000499 P:000499 0E249C JNE $08,X0 - 000008 -1702 P:00049E P:00049E 200045 CMP X0,A ; Test for 8 <= MUX number <= 15 -1703 P:00049F P:00049F 0E24A2 JNE $10,X0 - 000010 -1707 P:0004A4 P:0004A4 200045 CMP X0,A ; Test for 16 <= MUX number <= 23 -1708 P:0004A5 P:0004A5 0E24CF JNE 24,X0 ; Check for argument less than 32 - 000018 -1718 P:0004AE P:0004AE 200045 CMP X0,A -1719 P:0004AF P:0004AF 0E108D JGE $600,X0 - 000600 -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 timCCDmisc.asm Page 32 - - - -1727 P:0004B9 P:0004B9 200046 AND X0,A -1728 P:0004BA P:0004BA 0E24BD JNE $200,X0 - 000200 -1732 P:0004BF P:0004BF 200045 CMP X0,A ; Test for 8 <= MUX number <= 15 -1733 P:0004C0 P:0004C0 0E24C3 JNE $400,X0 - 000400 -1737 P:0004C5 P:0004C5 200045 CMP X0,A ; Test for 16 <= MUX number <= 23 -1738 P:0004C6 P:0004C6 0E208D JNE lo -2956 Y:00002F Y:00002F DC CLK2|P_DELAY|FS1_1H|FS2_1L|FS3_1H|FS1_2H|FS2_2L|FS3_2H -2957 Y:000030 Y:000030 DC CLK2|P_DELAY|FS1_1L|FS2_1L|FS3_1H|FS1_2H|FS2_2L|FS3_2L -2958 Y:000031 Y:000031 DC CLK2|P_DELAY|FS1_1L|FS2_1H|FS3_1H|FS1_2H|FS2_2H|FS3_2L -2959 Y:000032 Y:000032 DC CLK2|P_DELAY|FS1_1L|FS2_1H|FS3_1L|FS1_2L|FS2_2H|FS3_2L -2960 Y:000033 Y:000033 DC CLK2|P_DELAY|FS1_1H|FS2_1H|FS3_1L|FS1_2L|FS2_2H|FS3_2H -2961 Y:000034 Y:000034 DC CLK2|$000000|FS1_1H|FS2_1L|FS3_1L|FS1_2L|FS2_2L|FS3_2H -2962 -2963 Y:000035 Y:000035 DC CLK3|P_DELAY|RL|H2_1L|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH -2964 ; wfk - Next line: Add DCRestore,StrtRstInt - to machine state at end of CLEAR to stabilize baseline (04/04/07) -2965 Y:000036 Y:000036 DC VIDEO+$000000+%0011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - wf -k add DCRestore,StrtRstInt -2966 END_CLEAR_FS -2967 -2968 -2969 PARALLEL_SPLIT -2970 Y:000037 Y:000037 DC END_PARALLEL_SPLIT-PARALLEL_SPLIT-1 -2971 Y:000038 Y:000038 DC CLK3|$000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo -2972 Y:000039 Y:000039 DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1H|V1_2H|V2_2L|V3_2H -2973 Y:00003A Y:00003A DC CLK2|P_DELAY|V1_1L|V2_1L|V3_1H|V1_2H|V2_2L|V3_2L -2974 Y:00003B Y:00003B DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1H|V1_2H|V2_2H|V3_2L -2975 Y:00003C Y:00003C DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1L|V1_2L|V2_2H|V3_2L -2976 Y:00003D Y:00003D DC CLK2|P_DELAY|V1_1H|V2_1H|V3_1L|V1_2L|V2_2H|V3_2H -2977 Y:00003E Y:00003E DC CLK2|$000000|V1_1H|V2_1L|V3_1L|V1_2L|V2_2L|V3_2H -2978 Y:00003F Y:00003F DC CLK3|P_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Shut the transfer g -ate -2979 Y:000040 Y:000040 DC VIDEO+$000000+%0011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - wf -k add DCRestore,StrtRstInt -2980 -2981 END_PARALLEL_SPLIT -2982 -2983 -2984 ;Shift towards register 2 -2985 Y:000041 Y:000041 PARALLEL_2 DC END_PARALLEL_2-PARALLEL_2-1 -2986 Y:000042 Y:000042 DC CLK3|$000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo -2987 Y:000043 Y:000043 DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1H|V1_2H|V2_2L|V3_2H -2988 Y:000044 Y:000044 DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1L|V1_2H|V2_2L|V3_2L -2989 Y:000045 Y:000045 DC CLK2|P_DELAY|V1_1H|V2_1H|V3_1L|V1_2H|V2_2H|V3_2L -2990 Y:000046 Y:000046 DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1L|V1_2L|V2_2H|V3_2L -2991 Y:000047 Y:000047 DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1H|V1_2L|V2_2H|V3_2H -2992 Y:000048 Y:000048 DC CLK2|$000000|V1_1L|V2_1L|V3_1H|V1_2L|V2_2L|V3_2H ; shut TG -2993 Y:000049 Y:000049 DC CLK3|P_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Shut the transfer g -ate -2994 Y:00004A Y:00004A DC VIDEO+$000000+%0011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - wf -k add DCRestore,StrtRstInt -2995 END_PARALLEL_2 -2996 -2997 ;Shift towards register 1 -2998 ;charge stored under 2&3. Issue with switching between which register to go to. -2999 Y:00004B Y:00004B PARALLEL_1 DC END_PARALLEL_1-PARALLEL_1-1 -3000 ; DC CLK3|$000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo -3001 Y:00004C Y:00004C DC CLK3|$000000|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo -3002 Y:00004D Y:00004D DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1H|V1_2H|V2_2L|V3_2H -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 LBNL_2Kx4K.waveforms Page 53 - - - -3003 Y:00004E Y:00004E DC CLK2|P_DELAY|V1_1L|V2_1L|V3_1H|V1_2L|V2_2L|V3_2H -3004 Y:00004F Y:00004F DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1H|V1_2L|V2_2H|V3_2H -3005 Y:000050 Y:000050 DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1L|V1_2L|V2_2H|V3_2L -3006 Y:000051 Y:000051 DC CLK2|P_DELAY|V1_1H|V2_1H|V3_1L|V1_2H|V2_2H|V3_2L -3007 Y:000052 Y:000052 DC CLK2|$000000|V1_1H|V2_1L|V3_1L|V1_2H|V2_2L|V3_2L -3008 Y:000053 Y:000053 DC CLK3|P_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Shut the transfer g -ate -3009 Y:000054 Y:000054 DC VIDEO+$000000+%0011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - wf -k add DCRestore,StrtRstInt -3010 END_PARALLEL_1 -3011 -3012 -3013 PARALLEL_CLEAR_1 -3014 Y:000055 Y:000055 DC END_PARALLEL_CLEAR_1-PARALLEL_CLEAR_1-1 -3015 Y:000056 Y:000056 DC CLK3|$000000|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo -3016 -3017 Y:000057 Y:000057 DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1H|V1_2H|V2_2L|V3_2H -3018 Y:000058 Y:000058 DC CLK2|P_DELAY|V1_1L|V2_1L|V3_1H|V1_2L|V2_2L|V3_2H -3019 Y:000059 Y:000059 DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1H|V1_2L|V2_2H|V3_2H -3020 Y:00005A Y:00005A DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1L|V1_2L|V2_2H|V3_2L -3021 Y:00005B Y:00005B DC CLK2|P_DELAY|V1_1H|V2_1H|V3_1L|V1_2H|V2_2H|V3_2L -3022 Y:00005C Y:00005C DC CLK2|$000000|V1_1H|V2_1L|V3_1L|V1_2H|V2_2L|V3_2L -3023 -3024 Y:00005D Y:00005D DC CLK3|P_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Shut the transfer g -ate -3025 ; wfk - Next line: Add DCRestore,StrtRstInt - to machine state at end of CLEAR to stabilize baseline (04/04/07) -3026 Y:00005E Y:00005E DC VIDEO+$000000+%0011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - wf -k add DCRestore,StrtRstInt -3027 END_PARALLEL_CLEAR_1 -3028 -3029 PARALLEL_CLEAR_2 -3030 Y:00005F Y:00005F DC END_PARALLEL_CLEAR_2-PARALLEL_CLEAR_2-1 -3031 Y:000060 Y:000060 DC CLK3|$000000|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo -3032 -3033 Y:000061 Y:000061 DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1H|V1_2H|V2_2L|V3_2H -3034 Y:000062 Y:000062 DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1L|V1_2H|V2_2L|V3_2L -3035 Y:000063 Y:000063 DC CLK2|P_DELAY|V1_1H|V2_1H|V3_1L|V1_2H|V2_2H|V3_2L -3036 Y:000064 Y:000064 DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1L|V1_2L|V2_2H|V3_2L -3037 Y:000065 Y:000065 DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1H|V1_2L|V2_2H|V3_2H -3038 Y:000066 Y:000066 DC CLK2|$000000|V1_1L|V2_1L|V3_1H|V1_2L|V2_2L|V3_2H -3039 Y:000067 Y:000067 DC CLK3|P_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Shut the transfer g -ate -3040 -3041 -3042 ; wfk - Next line: Add DCRestore,StrtRstInt - to machine state at end of CLEAR to stabilize baseline (04/04/07) -3043 Y:000068 Y:000068 DC VIDEO+$000000+%0011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - wf -k add DCRestore,StrtRstInt -3044 END_PARALLEL_CLEAR_2 -3045 -3046 ; this parallel split mixes two central rows on the CCD. -3047 PARALLEL_CLEAR_SPLIT -3048 Y:000069 Y:000069 DC END_PARALLEL_CLEAR_SPLIT-PARALLEL_CLEAR_SPLIT-1 -3049 ; DC CLK3|$000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo -3050 Y:00006A Y:00006A DC CLK3|$000000|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo -3051 -3052 Y:00006B Y:00006B DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1H|V1_2H|V2_2L|V3_2H -3053 Y:00006C Y:00006C DC CLK2|P_DELAY|V1_1L|V2_1L|V3_1H|V1_2H|V2_2L|V3_2L -3054 Y:00006D Y:00006D DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1H|V1_2H|V2_2H|V3_2L -3055 Y:00006E Y:00006E DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1L|V1_2L|V2_2H|V3_2L -3056 Y:00006F Y:00006F DC CLK2|P_DELAY|V1_1H|V2_1H|V3_1L|V1_2L|V2_2H|V3_2H -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 LBNL_2Kx4K.waveforms Page 54 - - - -3057 Y:000070 Y:000070 DC CLK2|$000000|V1_1H|V2_1L|V3_1L|V1_2L|V2_2L|V3_2H -3058 -3059 Y:000071 Y:000071 DC CLK3|P_DELAY|RL|H2_1L|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH -3060 ; wfk - Next line: Add DCRestore,StrtRstInt - to machine state at end of CLEAR to stabilize baseline (04/04/07) -3061 Y:000072 Y:000072 DC VIDEO+$000000+%0011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - wf -k add DCRestore,StrtRstInt -3062 END_PARALLEL_CLEAR_SPLIT -3063 -3064 -3065 -3067 ;PARALLEL_CLEAR_SPLIT -3068 ; DC END_PARALLEL_CLEAR_SPLIT-PARALLEL_CLEAR_SPLIT-1 -3069 ; DC CLK3|$000000|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TL ;SW->lo -3070 ; -3071 ; DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1H|V1_2H|V2_2L|V3_2H -3072 ; DC CLK2|P_DELAY|V1_1L|V2_1L|V3_1H|V1_2H|V2_2L|V3_2L -3073 ; DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1H|V1_2H|V2_2H|V3_2L -3074 ; DC CLK2|P_DELAY|V1_1L|V2_1H|V3_1L|V1_2L|V2_2H|V3_2L -3075 ; DC CLK2|P_DELAY|V1_1H|V2_1H|V3_1L|V1_2L|V2_2H|V3_2H -3076 ; DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1L|V1_2L|V2_2L|V3_2H -3077 ; DC CLK2|P_DELAY|V1_1H|V2_1L|V3_1H|V1_2L|V2_2L|V3_2H -3078 ; DC CLK2|$000000|V1_1L|V2_1L|V3_1H|V1_2L|V2_2L|V3_2H -3079 ; -3080 ; DC CLK3|P_DELAY|RL|H2_1L|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH -3081 ; ; wfk - Next line: Add DCRestore,StrtRstInt to machine state at end of CLEAR to stabilize ba -seline (04/04/07) -3082 ; DC VIDEO+$000000+%1110000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. - wfk add DCRestore,StrtR -stInt -3083 ;END_PARALLEL_CLEAR_SPLIT -3084 -3085 ; ARC47: |xfer|A/D|integ|polarity|not used|not used|rst| (1 => switch open) -3086 SERIAL_IDLE_LEFT ; Clock serial charge from both L and R ends -3087 Y:000073 Y:000073 DC END_SERIAL_IDLE_LEFT-SERIAL_IDLE_LEFT-1 -3088 Y:000074 Y:000074 DC VIDEO+$000000+%1111000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. -3089 ; L2 idle version -3090 ; 2->3->1->2->3 -3091 Y:000075 Y:000075 DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset -_On -3092 Y:000076 Y:000076 DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi -3093 Y:000077 Y:000077 DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo -3094 Y:000078 Y:000078 DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi -3095 Y:000079 Y:000079 DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo -3096 Y:00007A Y:00007A DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi -3097 Y:00007B Y:00007B DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -3098 -3099 -3100 Y:00007C Y:00007C DC CLK3|$0000000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;dummy for trans -mit delay -3101 Y:00007D Y:00007D DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator -3102 Y:00007E Y:00007E DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec -3103 Y:00007F Y:00007F DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. -3104 Y:000080 Y:000080 DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -3105 Y:000081 Y:000081 DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo -3106 Y:000082 Y:000082 DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec -3107 Y:000083 Y:000083 DC VIDEO+DCRST_DELAY+%0010111 ; Now sit around for at least 520ns while t -he conversion happens -3108 END_SERIAL_IDLE_LEFT -3109 -3110 -3111 ; ARC47: |xfer|A/D|integ|polarity|not used|not used|rst| (1 => switch open) -3112 SERIAL_IDLE_LEFT_NO_POL ; Clock serial charge from both L and R ends -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 LBNL_2Kx4K.waveforms Page 55 - - - -3113 Y:000084 Y:000084 DC END_SERIAL_IDLE_LEFT_NO_POL-SERIAL_IDLE_LEFT_NO_POL-1 -3114 Y:000085 Y:000085 DC VIDEO+$000000+%1111000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. -3115 -3116 ; L2 idle version -3117 ; 2->3->1->2->3 -3118 Y:000086 Y:000086 DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset -_On -3119 Y:000087 Y:000087 DC CLK3|S_DELAY|RH|H1_1H|H1_2L|H1_3L|H2_1H|H2_2L|H2_3L|WL|TH ;h2->hi -3120 Y:000088 Y:000088 DC CLK3|S_DELAY|RH|H1_1H|H1_2H|H1_3L|H2_1H|H2_2H|H2_3L|WL|TH ;h1->lo -3121 Y:000089 Y:000089 DC CLK3|S_DELAY|RH|H1_1L|H1_2H|H1_3L|H2_1L|H2_2H|H2_3L|WL|TH ;h3->hi -3122 Y:00008A Y:00008A DC CLK3|S_DELAY|RH|H1_1L|H1_2H|H1_3H|H2_1L|H2_2H|H2_3H|WL|TH ;h2->lo -3123 Y:00008B Y:00008B DC CLK3|S_DELAY|RH|H1_1L|H1_2L|H1_3H|H2_1L|H2_2L|H2_3H|WL|TH ;h1->hi -3124 -3125 Y:00008C Y:00008C DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -3126 -3127 -3128 Y:00008D Y:00008D DC CLK3|$0000000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;dummy for trans -mit delay -3129 Y:00008E Y:00008E DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator -3130 Y:00008F Y:00008F DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec -3131 Y:000090 Y:000090 DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. -3132 Y:000091 Y:000091 DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -- charge d -ump -3133 -3134 ;SW going low here suggests that no charge w -ill leak over OG barrier onto sense node. -3135 Y:000092 Y:000092 DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo -3136 Y:000093 Y:000093 DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec -3137 Y:000094 Y:000094 DC VIDEO+DCRST_DELAY+%0011011 ; ,NonInv ;mF to do ADC sampling before res -etting -3138 -3139 ; DC CLK3|POST_SET_DLY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL ;SW->lo -3140 END_SERIAL_IDLE_LEFT_NO_POL -3141 -3142 SERIAL_IDLE_RIGHT ; Clock serial charge from both L and R ends -3143 Y:000095 Y:000095 DC END_SERIAL_IDLE_RIGHT-SERIAL_IDLE_RIGHT-1 -3144 Y:000096 Y:000096 DC VIDEO+$000000+%1011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. -3145 -3146 ; L2 read version -3147 ; 2->3->1->2->3 -3148 Y:000097 Y:000097 DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h2->lo,SW->lo,Reset -_On -3149 Y:000098 Y:000098 DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi -3150 Y:000099 Y:000099 DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h2->hi -3151 Y:00009A Y:00009A DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->l -3152 Y:00009B Y:00009B DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h1->hi -3153 Y:00009C Y:00009C DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h2->lo -3154 Y:00009D Y:00009D DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->hi, Reset_O -ff|Delay -3155 -3156 -3157 Y:00009E Y:00009E DC CLK3|$0000000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;dummy for trans -mit delay -3158 Y:00009F Y:00009F DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator -3159 Y:0000A0 Y:0000A0 DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec -3160 Y:0000A1 Y:0000A1 DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. -3161 Y:0000A2 Y:0000A2 DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -- charge d -ump -3162 -3163 ;SW going low here suggests that no charge w -ill leak over OG barrier onto sense node. -3164 Y:0000A3 Y:0000A3 DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 LBNL_2Kx4K.waveforms Page 56 - - - -3165 Y:0000A4 Y:0000A4 DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec -3166 Y:0000A5 Y:0000A5 DC VIDEO+$000000+%0110111 ; StopIntegrator -3167 Y:0000A6 Y:0000A6 DC VIDEO+DCRST_DELAY+%0110111 ; ADCLatch,NonInv ;mF to do ADC sampling be -fore resetting -3168 -3169 ; DC CLK3|POST_SET_DLY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL ;SW->lo -3170 -3171 END_SERIAL_IDLE_RIGHT -3172 -3173 -3174 SERIAL_IDLE_RIGHT_NO_POL ; Clock serial charge from both L and R ends -3175 Y:0000A7 Y:0000A7 DC END_SERIAL_IDLE_RIGHT_NO_POL-SERIAL_IDLE_RIGHT_NO_POL-1 -3176 Y:0000A8 Y:0000A8 DC VIDEO+$000000+%1011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. -3177 -3178 ; L2 read version -3179 ; 2->3->1->2->3 -3180 Y:0000A9 Y:0000A9 DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h2->lo,SW->lo,Reset -_On -3181 Y:0000AA Y:0000AA DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi -3182 Y:0000AB Y:0000AB DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h2->hi -3183 Y:0000AC Y:0000AC DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->l -3184 Y:0000AD Y:0000AD DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h1->hi -3185 Y:0000AE Y:0000AE DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h2->lo -3186 Y:0000AF Y:0000AF DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->hi, Reset_O -ff|Delay -3187 -3188 -3189 Y:0000B0 Y:0000B0 DC CLK3|$0000000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;dummy for trans -mit delay -3190 Y:0000B1 Y:0000B1 DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator -3191 Y:0000B2 Y:0000B2 DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec -3192 Y:0000B3 Y:0000B3 DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. -3193 Y:0000B4 Y:0000B4 DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -- charge d -ump -3194 -3195 ;SW going low here suggests that no charge w -ill leak over OG barrier onto sense node. -3196 Y:0000B5 Y:0000B5 DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo -3197 Y:0000B6 Y:0000B6 DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec -3198 Y:0000B7 Y:0000B7 DC VIDEO+$000000+%0010111 ; StopIntegrator -3199 Y:0000B8 Y:0000B8 DC VIDEO+DCRST_DELAY+%0111011 ; ADCLatch,NonInv ;mF to do ADC sampling be -fore resetting -3200 -3201 ; DC CLK3|POST_SET_DLY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL ;SW->lo -3202 -3203 END_SERIAL_IDLE_RIGHT_NO_POL -3204 -3205 SERIAL_IDLE_SPLIT -3206 Y:0000B9 Y:0000B9 DC END_SERIAL_IDLE_SPLIT-SERIAL_IDLE_SPLIT-1 -3207 Y:0000BA Y:0000BA DC VIDEO+$000000+%1011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. -3208 -3209 ; split read version: -3210 Y:0000BB Y:0000BB DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset -_On -3211 -3212 ; DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi -3213 ; DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo -3214 ; DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi -3215 ; DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo -3216 ; DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi -3217 -3218 Y:0000BC Y:0000BC DC CLK3|S_DELAY|RH|H1_1L|H1_2L|H1_3H|H2_1H|H2_2L|H2_3L|WL|TH ;h2->hi -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 LBNL_2Kx4K.waveforms Page 57 - - - -3219 Y:0000BD Y:0000BD DC CLK3|S_DELAY|RH|H1_1L|H1_2H|H1_3H|H2_1H|H2_2H|H2_3L|WL|TH ;h1->lo -3220 Y:0000BE Y:0000BE DC CLK3|S_DELAY|RH|H1_1L|H1_2H|H1_3L|H2_1L|H2_2H|H2_3L|WL|TH ;h3->hi -3221 Y:0000BF Y:0000BF DC CLK3|S_DELAY|RH|H1_1H|H1_2H|H1_3L|H2_1L|H2_2H|H2_3H|WL|TH ;h2->lo -3222 Y:0000C0 Y:0000C0 DC CLK3|S_DELAY|RH|H1_1H|H1_2L|H1_3L|H2_1L|H2_2L|H2_3H|WL|TH ;h1->hi -3223 -3224 -3225 Y:0000C1 Y:0000C1 DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -3226 -3227 Y:0000C2 Y:0000C2 DC CLK3|$000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;dummy for transmit -delay -3228 Y:0000C3 Y:0000C3 DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator -3229 Y:0000C4 Y:0000C4 DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec -3230 Y:0000C5 Y:0000C5 DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. -3231 Y:0000C6 Y:0000C6 DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -3232 Y:0000C7 Y:0000C7 DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo -3233 Y:0000C8 Y:0000C8 DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec -3234 Y:0000C9 Y:0000C9 DC VIDEO+$000000+%0010111 ; StopIntegrator -3235 Y:0000CA Y:0000CA DC VIDEO+DCRST_DELAY+%0110111 ; ADCLatch,NonInv ;mF to do ADC sampling be -fore resetting -3236 END_SERIAL_IDLE_SPLIT -3237 -3238 ; ARC47: |xfer|A/D|integ|polarity|not used|not used|rst| (1 => switch open) -3239 SERIAL_IDLE_SPLIT_NO_POL -3240 Y:0000CB Y:0000CB DC END_SERIAL_IDLE_SPLIT_NO_POL-SERIAL_IDLE_SPLIT_NO_POL-1 -3241 Y:0000CC Y:0000CC DC VIDEO+$000000+%1011001 ; ADCLatch,NonInv,DCRestore,StrtRstInt. -3242 -3243 ; split read version: -3244 Y:0000CD Y:0000CD DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset -_On -3245 Y:0000CE Y:0000CE DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi -3246 Y:0000CF Y:0000CF DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo -3247 Y:0000D0 Y:0000D0 DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi -3248 Y:0000D1 Y:0000D1 DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo -3249 Y:0000D2 Y:0000D2 DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi -3250 Y:0000D3 Y:0000D3 DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -3251 -3252 Y:0000D4 Y:0000D4 DC CLK3|$000000|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;dummy for transmit -delay -3253 Y:0000D5 Y:0000D5 DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator -3254 Y:0000D6 Y:0000D6 DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec -3255 Y:0000D7 Y:0000D7 DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. -3256 Y:0000D8 Y:0000D8 DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -3257 Y:0000D9 Y:0000D9 DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo -3258 Y:0000DA Y:0000DA DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec -3259 Y:0000DB Y:0000DB DC VIDEO+$000000+%0010111 ; StopIntegrator -3260 Y:0000DC Y:0000DC DC VIDEO+DCRST_DELAY+%0111011 ; ADCLatch,NonInv ;mF to do ADC sampling be -fore resetting -3261 END_SERIAL_IDLE_SPLIT_NO_POL -3262 -3263 -3264 ;start binning waveforms -3265 CCD_RESET ;Used for binning only -3266 Y:0000DD Y:0000DD DC END_CCD_RESET-CCD_RESET-1 -3267 Y:0000DE Y:0000DE DC VIDEO+$000000+%1011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. -3268 END_CCD_RESET -3269 -3270 SERIAL_CLOCK_L ;"NORMAL" clocking -3271 Y:0000DF Y:0000DF DC END_SERIAL_CLOCK_L-SERIAL_CLOCK_L-1 -3272 Y:0000E0 Y:0000E0 DC VIDEO+$000000+%1011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. -3273 Y:0000E1 Y:0000E1 DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset -_On -3274 Y:0000E2 Y:0000E2 DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 LBNL_2Kx4K.waveforms Page 58 - - - -3275 Y:0000E3 Y:0000E3 DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo -3276 Y:0000E4 Y:0000E4 DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi -3277 Y:0000E5 Y:0000E5 DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo -3278 Y:0000E6 Y:0000E6 DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi -3279 Y:0000E7 Y:0000E7 DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -3280 END_SERIAL_CLOCK_L -3281 -3282 SERIAL_CLOCK_R ;"REVERSE" clocking -3283 Y:0000E8 Y:0000E8 DC END_SERIAL_CLOCK_R-SERIAL_CLOCK_R-1 -3284 Y:0000E9 Y:0000E9 DC VIDEO+$000000+%1011000 ; NonInv,DCRestore,StrtRstInt. -3285 Y:0000EA Y:0000EA DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset -_On -3286 Y:0000EB Y:0000EB DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h2->hi -3287 Y:0000EC Y:0000EC DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h1->lo -3288 Y:0000ED Y:0000ED DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi -3289 Y:0000EE Y:0000EE DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h2->lo -3290 Y:0000EF Y:0000EF DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h1->hi -3291 Y:0000F0 Y:0000F0 DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -3292 END_SERIAL_CLOCK_R -3293 -3294 SERIAL_CLOCK_SPLIT ;"SPLIT" clocking -3295 Y:0000F1 Y:0000F1 DC END_SERIAL_CLOCK_SPLIT-SERIAL_CLOCK_SPLIT-1 -3296 Y:0000F2 Y:0000F2 DC VIDEO+$000000+%1011000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. -3297 Y:0000F3 Y:0000F3 DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset -_On -3298 Y:0000F4 Y:0000F4 DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi -3299 Y:0000F5 Y:0000F5 DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo -3300 Y:0000F6 Y:0000F6 DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi -3301 Y:0000F7 Y:0000F7 DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo -3302 Y:0000F8 Y:0000F8 DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi -3303 Y:0000F9 Y:0000F9 DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -3304 END_SERIAL_CLOCK_SPLIT -3305 -3306 -3307 VIDEO_PROCESS -3308 Y:0000FA Y:0000FA DC END_VIDEO_PROCESS-VIDEO_PROCESS-1 -3309 ;SXMIT DC $00F000 ; Transmit A/D data to host -3310 Y:0000FB Y:0000FB DC VIDEO+$000000+%1011011 ; StopDCRestore and StopResetIntegrator -3311 Y:0000FC Y:0000FC DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec -3312 Y:0000FD Y:0000FD DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. -3313 Y:0000FE Y:0000FE DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -3314 Y:0000FF Y:0000FF DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo -3315 Y:000100 Y:000100 DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec -3316 Y:000101 Y:000101 DC VIDEO+$000000+%0010111 ; StopResetIntegrator -3317 Y:000102 Y:000102 DC VIDEO+DCRST_DELAY+%0110111 ; ADCLatch,NonInv ;mF to do ADC sampeling b -evore resetting -3318 END_VIDEO_PROCESS -3319 ;end binning waveforms -3320 -3321 -3322 ; Video processor bit definition -3323 ; xfer, A/D, integ, Pol+, Pol-, DCrestore, rst (1 => switch open) -3324 -3325 ; These are the three reading tables. Make sure they're all the same length -3326 ; 2->3->1->2 -3327 SERIAL_READ_LEFT -3328 Y:000103 Y:000103 DC END_SERIAL_READ_LEFT-SERIAL_READ_LEFT-1 -3329 Y:000104 Y:000104 DC VIDEO+$000000+%1111000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. -3330 Y:000105 Y:000105 DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset -_On -3331 Y:000106 Y:000106 DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi -3332 Y:000107 Y:000107 DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 LBNL_2Kx4K.waveforms Page 59 - - - -3333 Y:000108 Y:000108 DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi -3334 Y:000109 Y:000109 DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo -3335 Y:00010A Y:00010A DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi -3336 Y:00010B Y:00010B DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -3337 Y:00010C Y:00010C SXL DC $00F000 ;Transmit a/d data to host -3338 Y:00010D Y:00010D DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator -3339 Y:00010E Y:00010E DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec -3340 Y:00010F Y:00010F DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. -3341 Y:000110 Y:000110 DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -3342 Y:000111 Y:000111 DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo -3343 Y:000112 Y:000112 DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec -3344 Y:000113 Y:000113 DC VIDEO+DCRST_DELAY+%0010111 ; Now sit around for at least 520ns while t -he conversion happens -3345 Y:000114 Y:000114 DC VIDEO+$40000+%0010111 ; Now sit around for at least 520ns while t -he conversion happens -3346 END_SERIAL_READ_LEFT -3347 -3348 SERIAL_READ_SPLIT -3349 Y:000115 Y:000115 DC END_SERIAL_READ_SPLIT-SERIAL_READ_SPLIT-1 -3350 Y:000116 Y:000116 DC VIDEO+$000000+%1111000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. -3351 Y:000117 Y:000117 DC CLK3|S_DELAY|RH|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WL|TH ;h3->lo,SW->lo,Reset -_On -3352 -3353 Y:000118 Y:000118 DC CLK3|S_DELAY|RH|H1_1L|H1_2L|H1_3H|H2_1H|H2_2L|H2_3L|WL|TH ;h2->hi -3354 Y:000119 Y:000119 DC CLK3|S_DELAY|RH|H1_1L|H1_2H|H1_3H|H2_1H|H2_2H|H2_3L|WL|TH ;h1->lo -3355 Y:00011A Y:00011A DC CLK3|S_DELAY|RH|H1_1L|H1_2H|H1_3L|H2_1L|H2_2H|H2_3L|WL|TH ;h3->hi -3356 Y:00011B Y:00011B DC CLK3|S_DELAY|RH|H1_1H|H1_2H|H1_3L|H2_1L|H2_2H|H2_3H|WL|TH ;h2->lo -3357 Y:00011C Y:00011C DC CLK3|S_DELAY|RH|H1_1H|H1_2L|H1_3L|H2_1L|H2_2L|H2_3H|WL|TH ;h1->hi -3358 -3359 ; DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi -3360 ; DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo -3361 ; DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi -3362 ; DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo -3363 ; DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi -3364 -3365 -3366 Y:00011D Y:00011D DC CLK3|PRE_SET_DLY|RL|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WL|TH ;Reset_Off|Delay -3367 Y:00011E Y:00011E SXRL DC $00F0C2 ;Transmit a/d data to host -3368 Y:00011F Y:00011F DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator -3369 Y:000120 Y:000120 DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec -3370 Y:000121 Y:000121 DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. -3371 Y:000122 Y:000122 DC CLK3|SW_DELAY|RL|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WH|TH ;SW->hi -3372 Y:000123 Y:000123 DC CLK3|POST_SET_DLY|RL|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WL|TH ;SW->lo -3373 Y:000124 Y:000124 DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec -3374 Y:000125 Y:000125 DC VIDEO+DCRST_DELAY+%0010111 ; Sit around whilst sampling. -3375 Y:000126 Y:000126 DC VIDEO+$50000+%0010111 ; Now sit around for at least 520ns while t -he conversion happens -3376 END_SERIAL_READ_SPLIT -3377 -3378 -3379 SERIAL_READ_SPLIT_SPECIAL -3380 Y:000127 Y:000127 DC END_SERIAL_READ_SPLIT_SPECIAL-SERIAL_READ_SPLIT_SPECIAL-1 -3381 Y:000128 Y:000128 DC VIDEO+$000000+%1111000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. -3382 Y:000129 Y:000129 DC CLK3|S_DELAY|RH|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WL|TH ;h3->lo,SW->lo,Reset -_On -3383 -3384 Y:00012A Y:00012A DC CLK3|S_DELAY|RH|H1_1L|H1_2L|H1_3H|H2_1H|H2_2L|H2_3L|WL|TH ;h2->hi -3385 Y:00012B Y:00012B DC CLK3|S_DELAY|RH|H1_1L|H1_2H|H1_3H|H2_1H|H2_2H|H2_3L|WL|TH ;h1->lo -3386 Y:00012C Y:00012C DC CLK3|S_DELAY|RH|H1_1L|H1_2H|H1_3L|H2_1L|H2_2H|H2_3L|WL|TH ;h3->hi -3387 Y:00012D Y:00012D DC CLK3|S_DELAY|RH|H1_1H|H1_2H|H1_3L|H2_1L|H2_2H|H2_3H|WL|TH ;h2->lo -3388 Y:00012E Y:00012E DC CLK3|S_DELAY|RH|H1_1H|H1_2L|H1_3L|H2_1L|H2_2L|H2_3H|WL|TH ;h1->hi -3389 -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 LBNL_2Kx4K.waveforms Page 60 - - - -3390 Y:00012F Y:00012F DC CLK3|PRE_SET_DLY|RL|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WL|TH ;Reset_Off|Delay -3391 Y:000130 Y:000130 DC $00F041 ;Transmit a/d data to host -3392 Y:000131 Y:000131 DC CLK3|$20000|RL|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WL|TH ;Reset_Off|Delay -3393 Y:000132 Y:000132 DC $00F082 ; get the other ADC -3394 Y:000133 Y:000133 DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator -3395 Y:000134 Y:000134 DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec -3396 Y:000135 Y:000135 DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. -3397 Y:000136 Y:000136 DC CLK3|SW_DELAY|RL|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WH|TH ;SW->hi -3398 Y:000137 Y:000137 DC CLK3|POST_SET_DLY|RL|H1_1H|H1_2L|H1_3H|H2_1H|H2_2L|H2_3H|WL|TH ;SW->lo -3399 Y:000138 Y:000138 DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec -3400 Y:000139 Y:000139 DC VIDEO+DCRST_DELAY+%0010111 ; Sit around whilst sampling. -3401 Y:00013A Y:00013A DC VIDEO+$50000+%0010111 ; Now sit around for at least 520ns while t -he conversion happens -3402 END_SERIAL_READ_SPLIT_SPECIAL -3403 -3404 -3405 ; 2->1->3->2 -3406 SERIAL_READ_RIGHT -3407 Y:00013B Y:00013B DC END_SERIAL_READ_RIGHT-SERIAL_READ_RIGHT-1 -3408 Y:00013C Y:00013C DC VIDEO+$000000+%1111000 ; NonInv,DCRestore,StrtRstInt. -3409 Y:00013D Y:00013D DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset -_On -3410 Y:00013E Y:00013E DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h2->hi -3411 Y:00013F Y:00013F DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h1->lo -3412 Y:000140 Y:000140 DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi -3413 Y:000141 Y:000141 DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h2->lo -3414 Y:000142 Y:000142 DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h1->hi -3415 Y:000143 Y:000143 DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -3416 Y:000144 Y:000144 SXR DC $00F041 ;Transmit a/d data to host -3417 Y:000145 Y:000145 DC VIDEO+$000000+%0011011 ; StopDCRestore and StopResetIntegrator -3418 Y:000146 Y:000146 DC VIDEO+I_DELAY+%0001011 ; Integrate for I_DELAY microsec -3419 Y:000147 Y:000147 DC VIDEO+$000000+%0010111 ; Stop Integrate and sel inverting int. -3420 Y:000148 Y:000148 DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -3421 Y:000149 Y:000149 DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo -3422 Y:00014A Y:00014A DC VIDEO+I_DELAY+%0000111 ; Integrate for I_DELAY microsec -3423 Y:00014B Y:00014B DC VIDEO+DCRST_DELAY+%0010111 ; Wait for sampling -3424 Y:00014C Y:00014C DC VIDEO+$30000+%0010111 ; -3425 END_SERIAL_READ_RIGHT -3426 -3427 ; This waveforms for test only. Video is left under permamnet reset -3428 SERIAL_READ_LEFT_NULL -3429 Y:00014D Y:00014D DC END_SERIAL_READ_LEFT_NULL-SERIAL_READ_LEFT_NULL-1 -3430 Y:00014E Y:00014E DC VIDEO+$000000+%1111000 ; ADCLatch,NonInv,DCRestore,StrtRstInt. -3431 Y:00014F Y:00014F DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;h3->lo,SW->lo,Reset -_On -3432 Y:000150 Y:000150 DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi -3433 Y:000151 Y:000151 DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo -3434 Y:000152 Y:000152 DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi -3435 Y:000153 Y:000153 DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo -3436 Y:000154 Y:000154 DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi -3437 Y:000155 Y:000155 DC CLK3|PRE_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -3438 Y:000156 Y:000156 DC $00F000 ;Transmit a/d data to host -3439 Y:000157 Y:000157 DC VIDEO+$000000+%0011010 ; StopDCRestore and StopResetIntegrator -3440 Y:000158 Y:000158 DC VIDEO+I_DELAY+%0001010 ; Integrate for I_DELAY microsec -3441 Y:000159 Y:000159 DC VIDEO+$000000+%0010110 ; Stop Integrate and sel inverting int. -3442 Y:00015A Y:00015A DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -3443 Y:00015B Y:00015B DC CLK3|POST_SET_DLY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;SW->lo -3444 Y:00015C Y:00015C DC VIDEO+I_DELAY+%0000110 ; Integrate for I_DELAY microsec -3445 Y:00015D Y:00015D DC VIDEO+DCRST_DELAY+%0010110 ; Now sit around for at least 520ns while t -he conversion happens -3446 Y:00015E Y:00015E DC VIDEO+$40000+%0010110 ; Now sit around for at least 520ns while t -he conversion happens -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 LBNL_2Kx4K.waveforms Page 61 - - - -3447 END_SERIAL_READ_LEFT_NULL -3448 -3449 -3450 ; These are the three skipping tables. Make sure they're all the same length -3451 SERIAL_SKIP_LEFT ; Serial clocking waveform for skipping left -3452 Y:00015F Y:00015F DC END_SERIAL_SKIP_LEFT-SERIAL_SKIP_LEFT-1 -3453 Y:000160 Y:000160 DC VIDEO+$000000+%1011000 ; Change nearly everything -3454 Y:000161 Y:000161 DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h2->hi -3455 Y:000162 Y:000162 DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h1->lo -3456 Y:000163 Y:000163 DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi -3457 Y:000164 Y:000164 DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h2->lo -3458 Y:000165 Y:000165 DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h1->hi -3459 Y:000166 Y:000166 DC CLK3|S_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -3460 Y:000167 Y:000167 DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -3461 END_SERIAL_SKIP_LEFT -3462 -3463 SERIAL_SKIP_RIGHT ; Serial clocking waveform for skipping righ -t -3464 Y:000168 Y:000168 DC END_SERIAL_SKIP_RIGHT-SERIAL_SKIP_RIGHT-1 -3465 Y:000169 Y:000169 DC VIDEO+$000000+%1011000 ; Change nearly everything -3466 Y:00016A Y:00016A DC CLK3|S_DELAY|RH|H2_1H|H2_2L|H2_3L|H1_1H|H1_2L|H1_3L|WL|TH ;h2->hi -3467 Y:00016B Y:00016B DC CLK3|S_DELAY|RH|H2_1H|H2_2H|H2_3L|H1_1H|H1_2H|H1_3L|WL|TH ;h1->lo -3468 Y:00016C Y:00016C DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi -3469 Y:00016D Y:00016D DC CLK3|S_DELAY|RH|H2_1L|H2_2H|H2_3H|H1_1L|H1_2H|H1_3H|WL|TH ;h2->lo -3470 Y:00016E Y:00016E DC CLK3|S_DELAY|RH|H2_1L|H2_2L|H2_3H|H1_1L|H1_2L|H1_3H|WL|TH ;h1->hi -3471 Y:00016F Y:00016F DC CLK3|S_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Delay -3472 Y:000170 Y:000170 DC CLK3|SW_DELAY|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -3473 END_SERIAL_SKIP_RIGHT -3474 -3475 SERIAL_SKIP_SPLIT ; Serial clocking waveform for skipping both - ends -3476 Y:000171 Y:000171 DC END_SERIAL_SKIP_SPLIT-SERIAL_SKIP_SPLIT-1 -3477 Y:000172 Y:000172 DC VIDEO+$000000+%1011000 ; Change nearly everything -3478 Y:000173 Y:000173 DC CLK3|S_DELAY_SKIP|RH|H2_1H|H2_2L|H2_3L|H1_1L|H1_2L|H1_3H|WL|TH ;h2->hi -3479 Y:000174 Y:000174 DC CLK3|S_DELAY_SKIP|RH|H2_1H|H2_2H|H2_3L|H1_1L|H1_2H|H1_3H|WL|TH ;h1->lo -3480 Y:000175 Y:000175 DC CLK3|S_DELAY_SKIP|RH|H2_1L|H2_2H|H2_3L|H1_1L|H1_2H|H1_3L|WL|TH ;h3->hi -3481 Y:000176 Y:000176 DC CLK3|S_DELAY_SKIP|RH|H2_1L|H2_2H|H2_3H|H1_1H|H1_2H|H1_3L|WL|TH ;h2->lo -3482 Y:000177 Y:000177 DC CLK3|S_DELAY_SKIP|RH|H2_1L|H2_2L|H2_3H|H1_1H|H1_2L|H1_3L|WL|TH ;h1->hi -3483 Y:000178 Y:000178 DC CLK3|S_DELAY_SKIP|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WL|TH ;Reset_Off|Dela -y -3484 Y:000179 Y:000179 DC CLK3|SW_DELAY_SKIP|RL|H2_1H|H2_2L|H2_3H|H1_1H|H1_2L|H1_3H|WH|TH ;SW->hi -3485 END_SERIAL_SKIP_SPLIT -3486 -3488 ; ORG Y:$1C0,Y:$1C0 ; Download address -3490 VSUBN -3491 VOLTS VSUB,60.0 ; Vsub 0.0 140 V, pin # -**** 3496 [LBNL_2Kx4K.waveforms 843]: Setting voltage VSUB 60.0V 30723083264 -3497 Y:00017B Y:00017B ERHI DC ERHI_END-ERHI-1 -3498 VOLTS VSUB,0 ; Vsub 0.0 140 V, pin # -**** 3503 [LBNL_2Kx4K.waveforms 845]: Setting voltage VSUB 0V 03080192 -3504 ; VOLTS V1_HI,9 ; Vertical High -3505 ; VOLTS V1_LO,9 ; Vertical Low -3506 ; VOLTS V2_HI,9 ; Vertical High -3507 ; VOLTS V2_LO,9 ; Vertical Low -3508 ; VOLTS V3_HI,9 ; Vertical High -3509 ; VOLTS V3_LO,9 ; Vertical Low -3510 ; VOLTS FS1_HI,9 ; Vertical High -3511 ; VOLTS FS1_LO,9 ; Vertical Low -3512 ; VOLTS FS2_HI,9 ; Vertical High -3513 ; VOLTS FS2_LO,9 ; Vertical Low -3514 ; VOLTS FS3_HI,9 ; Vertical High -3515 ; VOLTS FS3_LO,9 ; Vertical Low -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 LBNL_2Kx4K.waveforms Page 62 - - - -3516 Y:00017D Y:00017D DC $200100+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #1, Vertical Clock 1 -3517 Y:00017E Y:00017E DC $200200+@CVI((9+Vmax)/(2*Vmax)*255) -3518 Y:00017F Y:00017F DC $200400+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #2, Vertical Clock 2 -3519 Y:000180 Y:000180 DC $200800+@CVI((9+Vmax)/(2*Vmax)*255) -3520 Y:000181 Y:000181 DC $202000+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #3, Vertical Clock 3 -3521 Y:000182 Y:000182 DC $204000+@CVI((9+Vmax)/(2*Vmax)*255) -3522 Y:000183 Y:000183 DC $208000+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #4, Frame Store 1 -3523 Y:000184 Y:000184 DC $210000+@CVI((9+Vmax)/(2*Vmax)*255) -3524 Y:000185 Y:000185 DC $220100+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #5, Frame Store 2 -3525 Y:000186 Y:000186 DC $220200+@CVI((9+Vmax)/(2*Vmax)*255) -3526 Y:000187 Y:000187 DC $220400+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #6, Frame Store 3 -3527 Y:000188 Y:000188 DC $220800+@CVI((9+Vmax)/(2*Vmax)*255) -3528 Y:000189 Y:000189 DC $222000+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #7, Transfer Gate 2 -3529 Y:00018A Y:00018A DC $224000+@CVI((9+Vmax)/(2*Vmax)*255) -3530 Y:00018B Y:00018B DC $228000+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #8, Transger Gate 1 -3531 Y:00018C Y:00018C DC $230000+@CVI((9+Vmax)/(2*Vmax)*255) -3532 Y:00018D Y:00018D DC $240100+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #9, Unused -3533 Y:00018E Y:00018E DC $240200+@CVI((9+Vmax)/(2*Vmax)*255) -3534 Y:00018F Y:00018F DC $240400+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #10, Unused -3535 Y:000190 Y:000190 DC $240800+@CVI((9+Vmax)/(2*Vmax)*255) -3536 Y:000191 Y:000191 DC $242000+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #11, Unused -3537 Y:000192 Y:000192 DC $244000+@CVI((9+Vmax)/(2*Vmax)*255) -3538 Y:000193 Y:000193 DC $248000+@CVI((9+Vmax)/(2*Vmax)*255) ; Pin #12, Unused -3539 Y:000194 Y:000194 DC $250000+@CVI((9+Vmax)/(2*Vmax)*255) -3540 Y:000195 Y:000195 ERHI_END DC EPUR-ERHI_END-1 -3541 ; VOLTS V1_HI,5.0 ; Vertical High -3542 ; VOLTS V1_LO,-3.0 ; Vertical Low -3543 ; VOLTS V2_HI,5.0 ; Vertical High -3544 ; VOLTS V2_LO,-3.0 ; Vertical Low -3545 ; VOLTS V3_HI,5.0 ; Vertical High -3546 ; VOLTS V3_LO,-3.0 ; Vertical Low -3547 ; VOLTS FS1_HI,5.0 ; Vertical High -3548 ; VOLTS FS1_LO,-3.0 ; Vertical Low -3549 ; VOLTS FS2_HI,5.0 ; Vertical High -3550 ; VOLTS FS2_LO,-3.0 ; Vertical Low -3551 ; VOLTS FS3_HI,5.0 ; Vertical High -3552 ; VOLTS FS3_LO,-3.0 ; Vertical Low -3553 ;Return to normal voltages -3554 Y:000196 Y:000196 DC $200100+@CVI((V1_HI+Vmax)/(2*Vmax)*255) ; Pin #1, Vertical Clock 1 -3555 Y:000197 Y:000197 DC $200200+@CVI((V1_LO+Vmax)/(2*Vmax)*255) -3556 Y:000198 Y:000198 DC $200400+@CVI((V2_HI+Vmax)/(2*Vmax)*255) ; Pin #2, Vertical Clock 2 -3557 Y:000199 Y:000199 DC $200800+@CVI((V2_LO+Vmax)/(2*Vmax)*255) -3558 Y:00019A Y:00019A DC $202000+@CVI((V3_HI+Vmax)/(2*Vmax)*255) ; Pin #3, Vertical Clock 3 -3559 Y:00019B Y:00019B DC $204000+@CVI((V3_LO+Vmax)/(2*Vmax)*255) -3560 Y:00019C Y:00019C DC $208000+@CVI((V1_HI+Vmax)/(2*Vmax)*255) ; Pin #4, Frame Store 1 -3561 Y:00019D Y:00019D DC $210000+@CVI((V1_LO+Vmax)/(2*Vmax)*255) -3562 Y:00019E Y:00019E DC $220100+@CVI((V2_HI+Vmax)/(2*Vmax)*255) ; Pin #5, Frame Store 2 -3563 Y:00019F Y:00019F DC $220200+@CVI((V2_LO+Vmax)/(2*Vmax)*255) -3564 Y:0001A0 Y:0001A0 DC $220400+@CVI((V3_HI+Vmax)/(2*Vmax)*255) ; Pin #6, Frame Store 3 -3565 Y:0001A1 Y:0001A1 DC $220800+@CVI((V3_LO+Vmax)/(2*Vmax)*255) -3566 Y:0001A2 Y:0001A2 DC $222000+@CVI((V1_HI+Vmax)/(2*Vmax)*255) ; Pin #7, Transfer Gate 2 -3567 Y:0001A3 Y:0001A3 DC $224000+@CVI((V1_LO+Vmax)/(2*Vmax)*255) -3568 Y:0001A4 Y:0001A4 DC $228000+@CVI((V2_HI+Vmax)/(2*Vmax)*255) ; Pin #8, Transger Gate 1 -3569 Y:0001A5 Y:0001A5 DC $230000+@CVI((V2_LO+Vmax)/(2*Vmax)*255) -3570 Y:0001A6 Y:0001A6 DC $240100+@CVI((V3_HI+Vmax)/(2*Vmax)*255) ; Pin #9, Unused -3571 Y:0001A7 Y:0001A7 DC $240200+@CVI((V3_LO+Vmax)/(2*Vmax)*255) -3572 Y:0001A8 Y:0001A8 DC $240400+@CVI((FS1_HI+Vmax)/(2*Vmax)*255) ; Pin #10, Unused -3573 Y:0001A9 Y:0001A9 DC $240800+@CVI((FS1_LO+Vmax)/(2*Vmax)*255) -3574 Y:0001AA Y:0001AA DC $242000+@CVI((FS2_HI+Vmax)/(2*Vmax)*255) ; Pin #11, Unused -3575 Y:0001AB Y:0001AB DC $244000+@CVI((FS2_LO+Vmax)/(2*Vmax)*255) -3576 Y:0001AC Y:0001AC DC $248000+@CVI((FS3_HI+Vmax)/(2*Vmax)*255) ; Pin #12, Unused -3577 Y:0001AD Y:0001AD DC $250000+@CVI((FS3_LO+Vmax)/(2*Vmax)*255) -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 LBNL_2Kx4K.waveforms Page 63 - - - -3578 -3579 Y:0001AE Y:0001AE DC $2A0100+@CVI((RL_HI+Vmax)/(2*Vmax)*255) ; Pin #34, Reset Gate Upper -3580 Y:0001AF Y:0001AF DC $2A0200+@CVI((RL_LO+Vmax)/(2*Vmax)*255) -3581 Y:0001B0 Y:0001B0 DC $2A0400+@CVI((RU_HI+Vmax)/(2*Vmax)*255) ; Pin #35, Reset Gate Lower -3582 Y:0001B1 Y:0001B1 DC $2A0800+@CVI((RU_LO+Vmax)/(2*Vmax)*255) -3583 -3584 Y:0001B2 Y:0001B2 EPUR DC EPUR_END-EPUR-1 -3585 Y:0001B3 Y:0001B3 DC $200100+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #1, Vertical Clock 1 -3586 Y:0001B4 Y:0001B4 DC $200200+@CVI((-9+Vmax)/(2*Vmax)*255) -3587 Y:0001B5 Y:0001B5 DC $200400+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #2, Vertical Clock 2 -3588 Y:0001B6 Y:0001B6 DC $200800+@CVI((-9+Vmax)/(2*Vmax)*255) -3589 Y:0001B7 Y:0001B7 DC $202000+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #3, Vertical Clock 3 -3590 Y:0001B8 Y:0001B8 DC $204000+@CVI((-9+Vmax)/(2*Vmax)*255) -3591 Y:0001B9 Y:0001B9 DC $208000+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #4, Frame Store 1 -3592 Y:0001BA Y:0001BA DC $210000+@CVI((-9+Vmax)/(2*Vmax)*255) -3593 Y:0001BB Y:0001BB DC $220100+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #5, Frame Store 2 -3594 Y:0001BC Y:0001BC DC $220200+@CVI((-9+Vmax)/(2*Vmax)*255) -3595 Y:0001BD Y:0001BD DC $220400+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #6, Frame Store 3 -3596 Y:0001BE Y:0001BE DC $220800+@CVI((-9+Vmax)/(2*Vmax)*255) -3597 Y:0001BF Y:0001BF DC $222000+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #7, Transfer Gate 2 -3598 Y:0001C0 Y:0001C0 DC $224000+@CVI((-9+Vmax)/(2*Vmax)*255) -3599 Y:0001C1 Y:0001C1 DC $228000+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #8, Transger Gate 1 -3600 Y:0001C2 Y:0001C2 DC $230000+@CVI((-9+Vmax)/(2*Vmax)*255) -3601 Y:0001C3 Y:0001C3 DC $240100+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #9, Unused -3602 Y:0001C4 Y:0001C4 DC $240200+@CVI((-9+Vmax)/(2*Vmax)*255) -3603 Y:0001C5 Y:0001C5 DC $240400+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #10, Unused -3604 Y:0001C6 Y:0001C6 DC $240800+@CVI((-9+Vmax)/(2*Vmax)*255) -3605 Y:0001C7 Y:0001C7 DC $242000+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #11, Unused -3606 Y:0001C8 Y:0001C8 DC $244000+@CVI((-9+Vmax)/(2*Vmax)*255) -3607 Y:0001C9 Y:0001C9 DC $248000+@CVI((-9+Vmax)/(2*Vmax)*255) ; Pin #12, Unused -3608 Y:0001CA Y:0001CA DC $250000+@CVI((-9+Vmax)/(2*Vmax)*255) -3609 -3610 Y:0001CB Y:0001CB DC $2A0100+@CVI((-6+Vmax)/(2*Vmax)*255) ; Pin #34, Reset Gate Upper -3611 Y:0001CC Y:0001CC DC $2A0200+@CVI((-6+Vmax)/(2*Vmax)*255) -3612 Y:0001CD Y:0001CD DC $2A0400+@CVI((-6+Vmax)/(2*Vmax)*255) ; Pin #35, Reset Gate Lower -3613 Y:0001CE Y:0001CE DC $2A0800+@CVI((-6+Vmax)/(2*Vmax)*255) -3614 -3615 EPUR_END -3616 -3617 ; Code for ARC32 = universal clock driver board -3618 Y:0001CF Y:0001CF DACS DC END_DACS-DACS-1 -3619 Y:0001D0 Y:0001D0 DC $2A0080 ; DAC = unbuffered mode -3620 -3621 Y:0001D1 Y:0001D1 DC $200100+@CVI((V1_HI+Vmax)/(2*Vmax)*255) ; Pin #1, Vertical Clock 1 -3622 Y:0001D2 Y:0001D2 DC $200200+@CVI((V1_LO+Vmax)/(2*Vmax)*255) -3623 Y:0001D3 Y:0001D3 DC $200400+@CVI((V2_HI+Vmax)/(2*Vmax)*255) ; Pin #2, Vertical Clock 2 -3624 Y:0001D4 Y:0001D4 DC $200800+@CVI((V2_LO+Vmax)/(2*Vmax)*255) -3625 Y:0001D5 Y:0001D5 DC $202000+@CVI((V3_HI+Vmax)/(2*Vmax)*255) ; Pin #3, Vertical Clock 3 -3626 Y:0001D6 Y:0001D6 DC $204000+@CVI((V3_LO+Vmax)/(2*Vmax)*255) -3627 Y:0001D7 Y:0001D7 DC $208000+@CVI((V1_HI+Vmax)/(2*Vmax)*255) ; Pin #4, Frame Store 1 -3628 Y:0001D8 Y:0001D8 DC $210000+@CVI((V1_LO+Vmax)/(2*Vmax)*255) -3629 Y:0001D9 Y:0001D9 DC $220100+@CVI((V2_HI+Vmax)/(2*Vmax)*255) ; Pin #5, Frame Store 2 -3630 Y:0001DA Y:0001DA DC $220200+@CVI((V2_LO+Vmax)/(2*Vmax)*255) -3631 Y:0001DB Y:0001DB DC $220400+@CVI((V3_HI+Vmax)/(2*Vmax)*255) ; Pin #6, Frame Store 3 -3632 Y:0001DC Y:0001DC DC $220800+@CVI((V3_LO+Vmax)/(2*Vmax)*255) -3633 Y:0001DD Y:0001DD DC $222000+@CVI((V1_HI+Vmax)/(2*Vmax)*255) ; Pin #7, Vertical Clock 1 -3634 Y:0001DE Y:0001DE DC $224000+@CVI((V1_LO+Vmax)/(2*Vmax)*255) -3635 Y:0001DF Y:0001DF DC $228000+@CVI((V2_HI+Vmax)/(2*Vmax)*255) ; Pin #8, Vertical Clock 2 -3636 Y:0001E0 Y:0001E0 DC $230000+@CVI((V2_LO+Vmax)/(2*Vmax)*255) -3637 -3638 Y:0001E1 Y:0001E1 DC $240100+@CVI((V3_HI+Vmax)/(2*Vmax)*255) ; Pin #9, Vertical Clock 3 -3639 Y:0001E2 Y:0001E2 DC $240200+@CVI((V3_LO+Vmax)/(2*Vmax)*255) -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 LBNL_2Kx4K.waveforms Page 64 - - - -3640 Y:0001E3 Y:0001E3 DC $240400+@CVI((FS1_HI+Vmax)/(2*Vmax)*255) ; Pin #10, Frame Store 1 -3641 Y:0001E4 Y:0001E4 DC $240800+@CVI((FS1_LO+Vmax)/(2*Vmax)*255) -3642 Y:0001E5 Y:0001E5 DC $242000+@CVI((FS2_HI+Vmax)/(2*Vmax)*255) ; Pin #11, Frame Store 2 -3643 Y:0001E6 Y:0001E6 DC $244000+@CVI((FS2_LO+Vmax)/(2*Vmax)*255) -3644 Y:0001E7 Y:0001E7 DC $248000+@CVI((FS3_HI+Vmax)/(2*Vmax)*255) ; Pin #12, Frame Store 3 -3645 Y:0001E8 Y:0001E8 DC $250000+@CVI((FS3_LO+Vmax)/(2*Vmax)*255) -3646 -3647 Y:0001E9 Y:0001E9 DC $260100+@CVI((H1U2_L1_HI+Vmax)/(2*Vmax)*255) ; Pin #13, Horizontal 1 Upper -3648 Y:0001EA Y:0001EA DC $260200+@CVI((H1U2_L1_LO+Vmax)/(2*Vmax)*255) -3649 Y:0001EB Y:0001EB DC $260400+@CVI((H2U2_L1_HI+Vmax)/(2*Vmax)*255) ; Pin #14, Horizontal 2 Upper -3650 Y:0001EC Y:0001EC DC $260800+@CVI((H2U2_L1_LO+Vmax)/(2*Vmax)*255) -3651 Y:0001ED Y:0001ED DC $262000+@CVI((H3U2_L1_HI+Vmax)/(2*Vmax)*255) ; Pin #15, Horizontal 3 Upper -3652 Y:0001EE Y:0001EE DC $264000+@CVI((H3U2_L1_LO+Vmax)/(2*Vmax)*255) -3653 Y:0001EF Y:0001EF DC $268000+@CVI((H1U1_L2_HI+Vmax)/(2*Vmax)*255) ; Pin #16, Horizontal 1 Lower -3654 Y:0001F0 Y:0001F0 DC $270000+@CVI((H1U1_L2_LO+Vmax)/(2*Vmax)*255) -3655 Y:0001F1 Y:0001F1 DC $280100+@CVI((H2U1_L2_HI+Vmax)/(2*Vmax)*255) ; Pin #17, Horizontal 2 Lower -3656 Y:0001F2 Y:0001F2 DC $280200+@CVI((H2U1_L2_LO+Vmax)/(2*Vmax)*255) -3657 Y:0001F3 Y:0001F3 DC $280400+@CVI((H3U1_L2_HI+Vmax)/(2*Vmax)*255) ; Pin #18, Horizontal 3 Lower -3658 Y:0001F4 Y:0001F4 DC $280800+@CVI((H3U1_L2_LO+Vmax)/(2*Vmax)*255) -3659 Y:0001F5 Y:0001F5 DC $282000+@CVI((SWL_HI+Vmax)/(2*Vmax)*255) ; Pin #19, Summing Well Upper -3660 Y:0001F6 Y:0001F6 DC $284000+@CVI((SWL_LO+Vmax)/(2*Vmax)*255) -3661 Y:0001F7 Y:0001F7 DC $288000+@CVI((SWU_HI+Vmax)/(2*Vmax)*255) ; Pin #33, Summing Well Lower -3662 Y:0001F8 Y:0001F8 DC $290000+@CVI((SWU_LO+Vmax)/(2*Vmax)*255) -3663 Y:0001F9 Y:0001F9 DC $2A0100+@CVI((RL_HI+Vmax)/(2*Vmax)*255) ; Pin #34, Reset Gate Upper -3664 Y:0001FA Y:0001FA DC $2A0200+@CVI((RL_LO+Vmax)/(2*Vmax)*255) -3665 Y:0001FB Y:0001FB DC $2A0400+@CVI((RU_HI+Vmax)/(2*Vmax)*255) ; Pin #35, Reset Gate Lower -3666 Y:0001FC Y:0001FC DC $2A0800+@CVI((RU_LO+Vmax)/(2*Vmax)*255) -3667 Y:0001FD Y:0001FD DC $2A2000+@CVI((T1_HI+Vmax)/(2*Vmax)*255) ; Pin #36, Transfer Gate 1 -3668 Y:0001FE Y:0001FE DC $2A4000+@CVI((T1_LO+Vmax)/(2*Vmax)*255) -3669 Y:0001FF Y:0001FF DC $2A8000+@CVI((T2_HI+Vmax)/(2*Vmax)*255) ; Pin #37, Transfer Gate 2 -3670 Y:000200 Y:000200 DC $2B0000+@CVI((T2_LO+Vmax)/(2*Vmax)*255) -3671 -3672 -3673 ; DC bias voltages for the LBL CCD chip -3674 VOLTS VSUB,60.0 ; Vsub 0.0 140 V -**** 3679 [LBNL_2Kx4K.waveforms 1016]: Setting voltage VSUB 60.0V 30723083264 -3680 VOLTS RAMP,5.0 ; Vsub AVG RAMP RATE -**** 3685 [LBNL_2Kx4K.waveforms 1017]: Setting voltage RAMP 5.0V 20483098624 -3686 VOLTS VDDL2,-22.0 ; Vdd -5.1 -25V -**** 3691 [LBNL_2Kx4K.waveforms 1018]: Setting voltage VDDL2 -22.0V 36042985492 -3692 VOLTS VDDU2,-22.0 ; Vdd -5.1 -25V -**** 3697 [LBNL_2Kx4K.waveforms 1019]: Setting voltage VDDU2 -22.0V 36043001876 -3698 VOLTS VDDL1,-22.0 ; Vdd -5.1 -25V -**** 3703 [LBNL_2Kx4K.waveforms 1020]: Setting voltage VDDL1 -22.0V 36042952724 -3704 VOLTS VDDU1,-22.0 ; Vdd -5.1 -25V -**** 3709 [LBNL_2Kx4K.waveforms 1021]: Setting voltage VDDU1 -22.0V 36042969108 -3710 VOLTS VRL2,-12.5 ; Vr -5.1 -25V -**** 3715 [LBNL_2Kx4K.waveforms 1022]: Setting voltage VRL2 -12.5V 20482918400 -3716 VOLTS VRU2,-12.5 ; Vr -5.1 -25V -**** 3721 [LBNL_2Kx4K.waveforms 1023]: Setting voltage VRU2 -12.5V 20482934784 -3722 VOLTS VRL1,-12.5 ; Vr -5.1 -25V -**** 3727 [LBNL_2Kx4K.waveforms 1024]: Setting voltage VRL1 -12.5V 20482885632 -3728 VOLTS VRU1,-12.5 ; Vr -5.1 -25V -**** 3733 [LBNL_2Kx4K.waveforms 1025]: Setting voltage VRU1 -12.5V 20482902016 -3734 VOLTS VOGL2,2.50 ; Vopg -10 10 V -**** 3739 [LBNL_2Kx4K.waveforms 1026]: Setting voltage VOGL2 2.50V 20483049472 -3740 VOLTS VOGU2,2.50 ; Vopg -10 10 V -**** 3745 [LBNL_2Kx4K.waveforms 1027]: Setting voltage VOGU2 2.50V 20483065856 -3746 VOLTS VOGL1,2.50 ; Vopg -10 10 V -**** 3751 [LBNL_2Kx4K.waveforms 1028]: Setting voltage VOGL1 2.50V 20483016704 -3752 VOLTS VOGU1,3.50 ; Vopg -10 10 V -**** 3757 [LBNL_2Kx4K.waveforms 1029]: Setting voltage VOGU1 3.50V 28673033907 -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 LBNL_2Kx4K.waveforms Page 65 - - - -3758 -3759 -3760 ; Set gain and integrator speed. (77, bb, dd, ee; low gain to high) -3761 -3762 ; Board #0 -3763 ; DC $0c3c77 ; Gain x1, slow integ. speed, board #0 -3764 ; DC $0c3f77 ; Gain x1, fast integrate speed -3765 Y:00020F Y:00020F DC $0c3cbb ; Gain x2 -3766 ; DC $0c3cdd ; Gain x4.75, slow -3767 ; DC $0c3fee ; Gain x9.50 -3768 ; DC $0c3cee ; Gain x9.50, slow -3769 -3770 ; Board #1 -3771 ; DC $1c3c77 ; Gain x1, slow integ. speed, board #1 -3772 ; DC $1c3f77 ; Gain x1, fast integrate speed -3773 Y:000210 Y:000210 DC $1c3cbb ; Gain x2, slow -3774 ; DC $1c3cdd ; Gain x4.75, slow -3775 ; DC $1c3cee ; Gain x9.50, slow -3776 -3777 GAIN_SETTING -3778 Y:000211 Y:000211 DC VID0+$0D000E -3779 -3780 ; Set offset voltages in Video boards -3781 -3782 ; Board #0 -3783 Y:000212 Y:000212 DC $0C8000+OFFSET0 -3784 Y:000213 Y:000213 DC $0CC000+OFFSET1 -3785 -3786 ; Board #1 -3787 Y:000214 Y:000214 DC $1C8000+OFFSET2 -3788 Y:000215 Y:000215 DC $1CC000+OFFSET3 -3789 -3790 ; Bias voltages in the Video Boards used only for diagnostics (not connected to CCD) -3791 ; Bias range = -10V to +10V -3792 000700 BIAS_TST EQU $700 ; -1.25V -3793 -3794 ; Board #0 -3795 Y:000216 Y:000216 DC $0E0000+BIAS_TST ; DB-25 Pin 9 -3796 Y:000217 Y:000217 DC $0E4000+BIAS_TST ; DB-25 Pin 10 -3797 -3798 ; Board #1 -3799 Y:000218 Y:000218 DC $1E0000+BIAS_TST ; DB-25 Pin 9 -3800 Y:000219 Y:000219 DC $1E4000+BIAS_TST ; DB-25 Pin 10 -3801 -3802 END_DACS -3803 -3804 -3805 ; Pixel table generated in "timCCD.asm" -3806 Y:00021A Y:00021A PXL_TBL DC 0 -3807 -3808 -3809 -3810 Y:00024D Y:00024D ORG Y:@LCV(L)+50,Y:@LCV(L)+50 -3811 -3812 TMP_PXL_TBL1 -3813 Y:00024D Y:00024D DC 0 -3814 -3815 Y:000280 Y:000280 ORG Y:@LCV(L)+50,Y:@LCV(L)+50 -3816 -3817 TMP_PXL_TBL2 -3818 Y:000280 Y:000280 DC 0 -3819 -Motorola DSP56300 Assembler Version 6.3.4 21-12-08 11:13:23 tim.asm Page 66 - - - -3820 Y:0002B3 Y:0002B3 ORG Y:@LCV(L)+50,Y:@LCV(L)+50 -3821 -3822 TMP_PXL_TBL3 -3823 Y:0002B3 Y:0002B3 DC 0 -3824 -3825 END_APPLICATON_Y_MEMORY -3826 0002B4 EQU @LCV(L) -3827 -3828 -3829 ; End of program -3830 END - -0 Errors -0 Warnings - - diff --git a/DSP/DBSP-red/timCCDmisc.asm b/DSP/DBSP-red/timCCDmisc.asm deleted file mode 100755 index 1a49d81e..00000000 --- a/DSP/DBSP-red/timCCDmisc.asm +++ /dev/null @@ -1,1160 +0,0 @@ -; Miscellaneous CCD control routines, common to all detector types - -; 2011-10-21 (GR): Added SBINN to for binning (only parallel binning implemented so far) -; 2011-10-23 (GR): Replaced SERIAL_SKIP waveforms for _U1 with SERIAL_SKIP_SPLIT for faster flush of serial reg after each parallel skip - - -POWER_OFF - JSR Turn on +36V - MOVE #10000000,X0 - DO X0,*+3 ; Wait 100 millisec for settling - NOP - RTS - - -RAW_COMMAND - BSET #3,X:PCRD ; Turn on the serial clock - MOVE X:(R3)+,A ; Get the command which should just be a word - JSR $10,X0 - JSR $10,X0 - JSR 1.0 microsec per pixel - NOP - ADD #1,A ; Pixel data = Pixel data + 1 - NOP - MOVE A,B - JSR 1,X0 - CLR B - - DO #15,CHK_GAIN - CMP B,A - JEQ 7,X0 - AND X0,B ; Get 3 least significant bits of clock # - CMP #0,B - JNE $FF,Y0 ; Mask off just 8 bits - AND Y0,A - OR X0,A - JMP 24,X0 ; Check for argument less than 32 - CMP X0,A - JGE ERR_SM1 - MOVE A,B - MOVE #>7,X0 - AND X0,B - MOVE #>$18,X0 - AND X0,A - JNE $08,X0 - CMP X0,A ; Test for 8 <= MUX number <= 15 - JNE $10,X0 - CMP X0,A ; Test for 16 <= MUX number <= 23 - JNE 24,X0 ; Check for argument less than 32 - CMP X0,A - JGE $600,X0 - AND X0,A - JNE $200,X0 - CMP X0,A ; Test for 8 <= MUX number <= 15 - JNE $400,X0 - CMP X0,A ; Test for 16 <= MUX number <= 23 - JNE only restore registers -END_BYT MOVE A1,X:(R4)+ ; Put the 24-bit word into the SCI buffer - MOVE #SRXL,R0 ; Re-establish first address of SCI interface - MOVE #0,A1 ; For zeroing out SCI_A1 -MID_BYT MOVE R0,X: CLR SR, return - JMP try again -TST2 JCLR #EF,X:HDR,CLR_CC ; Low, High => try again - JMP read FIFO -TST3 JCLR #EF,X:HDR,CHK_FO - - MOVEP #$028FE2,X:BCR ; Slow down RDFO access - NOP - NOP - MOVE Y:RDFO,B - MOVE #0,B2 - AND #$FF,B - CMP #>$AC,B ; It must be $AC to be a valid word - JNE SR carry bit = 1 - MOVEP #$028FE1,X:BCR ; Restore RDFO access - RTS -CLR_CC BCLR #0,SR ; Not valid word => SR carry bit = 0 - MOVEP #$028FE1,X:BCR ; Restore RDFO access - RTS - -; Test the SCI (= synchronous communications interface) for new words -CHK_SCI MOVE X:(SCI_TABLE+33),X0 - MOVE R4,A - MOVE X0,R0 - CMP X0,A - JEQ 0 - JEQ when not - MOVE R0,X: when not - MOVE R0,X:1,X:HPCR ; All pins enabled as GPIO - MOVEP #$810C,X:HDR - MOVEP #$B10E,X:HDDR ; Data Direction Register - ; (1 for Output, 0 for Input) - -; Port B conversion from software bits to schematic labels -; PB0 = PWROK PB08 = PRSFIFO* -; PB1 = LED1 PB09 = EF* -; PB2 = LVEN PB10 = EXT-IN0 -; PB3 = HVEN PB11 = EXT-IN1 -; PB4 = STATUS0 PB12 = EXT-OUT0 -; PB5 = STATUS1 PB13 = EXT-OUT1 -; PB6 = STATUS2 PB14 = SSFHF* -; PB7 = STATUS3 PB15 = SELSCI - -; Program the serial port ESSI0 = Port C for serial communication with -; the utility board - MOVEP #>0,X:PCRC ; Software reset of ESSI0 - MOVEP #$180809,X:CRA0 ; Divide 100 MHz by 20 to get 5.0 MHz - ; DC[4:0] = 0 for non-network operation - ; WL0-WL2 = 3 for 24-bit data words - ; SSC1 = 0 for SC1 not used - MOVEP #$020020,X:CRB0 ; SCKD = 1 for internally generated clock - ; SCD2 = 0 so frame sync SC2 is an output - ; SHFD = 0 for MSB shifted first - ; FSL = 0, frame sync length not used - ; CKP = 0 for rising clock edge transitions - ; SYN = 0 for asynchronous - ; TE0 = 1 to enable transmitter #0 - ; MOD = 0 for normal, non-networked mode - ; TE0 = 0 to NOT enable transmitter #0 yet - ; RE = 1 to enable receiver - MOVEP #%111001,X:PCRC ; Control Register (0 for GPIO, 1 for ESSI) - MOVEP #%000110,X:PRRC ; Data Direction Register (0 for In, 1 for Out) - MOVEP #%000100,X:PDRC ; Data Register - WR_ENA* = 1 - -; Port C version = Analog boards -; MOVEP #$000809,X:CRA0 ; Divide 100 MHz by 20 to get 5.0 MHz -; MOVEP #$000030,X:CRB0 ; SCKD = 1 for internally generated clock -; MOVEP #%100000,X:PCRC ; Control Register (0 for GPIO, 1 for ESSI) -; MOVEP #%000100,X:PRRC ; Data Direction Register (0 for In, 1 for Out) -; MOVEP #%000000,X:PDRC ; Data Register: 'not used' = 0 outputs - - MOVEP #0,X:TX00 ; Initialize the transmitter to zero - NOP - NOP - BSET #TE,X:CRB0 ; Enable the SSI transmitter - -; Conversion from software bits to schematic labels for Port C -; PC0 = SC00 = UTL-T-SCK -; PC1 = SC01 = 2_XMT = SYNC on prototype -; PC2 = SC02 = WR_ENA* -; PC3 = SCK0 = TIM-U-SCK -; PC4 = SRD0 = UTL-T-STD -; PC5 = STD0 = TIM-U-STD - -; Program the serial port ESSI1 = Port D for serial transmission to -; the analog boards and two parallel I/O input pins - MOVEP #>0,X:PCRD ; Software reset of ESSI0 - MOVEP #$000809,X:CRA1 ; Divide 100 MHz by 20 to get 5.0 MHz - ; DC[4:0] = 0 - ; WL[2:0] = ALC = 0 for 8-bit data words - ; SSC1 = 0 for SC1 not used - MOVEP #$000030,X:CRB1 ; SCKD = 1 for internally generated clock - ; SCD2 = 1 so frame sync SC2 is an output - ; SHFD = 0 for MSB shifted first - ; CKP = 0 for rising clock edge transitions - ; TE0 = 0 to NOT enable transmitter #0 yet - ; MOD = 0 so its not networked mode - MOVEP #%100000,X:PCRD ; Control Register (0 for GPIO, 1 for ESSI) - ; PD3 = SCK1, PD5 = STD1 for ESSI - MOVEP #%000100,X:PRRD ; Data Direction Register (0 for In, 1 for Out) - MOVEP #%000100,X:PDRD ; Data Register: 'not used' = 0 outputs - MOVEP #0,X:TX10 ; Initialize the transmitter to zero - NOP - NOP - BSET #TE,X:CRB1 ; Enable the SSI transmitter - -; Conversion from software bits to schematic labels for Port D -; PD0 = SC10 = 2_XMT_? input -; PD1 = SC11 = SSFEF* input -; PD2 = SC12 = PWR_EN -; PD3 = SCK1 = TIM-A-SCK -; PD4 = SRD1 = PWRRST -; PD5 = STD1 = TIM-A-STD - -; Program the SCI port to communicate with the utility board - MOVEP #$0B04,X:SCR ; SCI programming: 11-bit asynchronous - ; protocol (1 start, 8 data, 1 even parity, - ; 1 stop); LSB before MSB; enable receiver - ; and its interrupts; transmitter interrupts - ; disabled. - MOVEP #$0003,X:SCCR ; SCI clock: utility board data rate = - ; (390,625 kbits/sec); internal clock. - MOVEP #%011,X:PCRE ; Port Control Register = RXD, TXD enabled - MOVEP #%000,X:PRRE ; Port Direction Register (0 = Input) - -; PE0 = RXD -; PE1 = TXD -; PE2 = SCLK - -; Program one of the three timers as an exposure timer - MOVEP #$C34F,X:TPLR ; Prescaler to generate millisecond timer, - ; counting from the system clock / 2 = 50 MHz - MOVEP #$208200,X:TCSR0 ; Clear timer complete bit and enable prescaler - MOVEP #0,X:TLR0 ; Timer load register - -; Enable interrupts for the SCI port only - MOVEP #$000000,X:IPRC ; No interrupts allowed - MOVEP #>$80,X:IPRP ; Enable SCI interrupt only, IPR = 1 - ANDI #$FC,MR ; Unmask all interrupt levels - -; Initialize the fiber optic serial receiver circuitry - DO #20,L_FO_INIT - MOVE Y:RDFO,B - REP #5 - NOP -L_FO_INIT - -; Pulse PRSFIFO* low to revive the CMDRST* instruction and reset the FIFO - MOVE #1000000,X0 ; Delay by 10 milliseconds - DO X0,*+3 - NOP - BCLR #8,X:HDR - REP #20 - NOP - BSET #8,X:HDR - -; Reset the utility board - BCLR #5,X:$AC,X0 - MOVE X0,X: milliseconds -TPCR EQU $FFFF82 ; Timer prescaler count register -TIM_BIT EQU 0 ; Set to enable the timer -TRM EQU 9 ; Set to enable the timer preloading -TCF EQU 21 ; Set when timer counter = compare register - -; Board specific addresses and constants -RDFO EQU $FFFFF1 ; Read incoming fiber optic data byte -WRFO EQU $FFFFF2 ; Write fiber optic data replies -WRSS EQU $FFFFF3 ; Write switch state -WRLATCH EQU $FFFFF5 ; Write to a latch -RDAD EQU $010000 ; Read A/D values into the DSP -EF EQU 9 ; Serial receiver empty flag - -; DSP port A bit equates -PWROK EQU 0 ; Power control board says power is OK -LED1 EQU 1 ; Control one of two LEDs -LVEN EQU 2 ; Low voltage power enable -HVEN EQU 3 ; High voltage power enable -SSFHF EQU 14 ; Switch state FIFO half full flag -EXT_IN0 EQU 10 ; External digital I/O to the timing board -EXT_IN1 EQU 11 -EXT_OUT0 EQU 12 -EXT_OUT1 EQU 13 - -; Port D equate -SLAVE EQU 0 ; Set if not a master by having jumper 2 not installed -SSFEF EQU 1 ; Switch state FIFO empty flag - -; Other equates -WRENA EQU 2 ; Enable writing to the EEPROM - -; Latch U25 bit equates -CDAC EQU 0 ; Clear the analog board DACs -ENCK EQU 2 ; Enable the clock outputs -SHUTTER EQU 4 ; Control the shutter -TIM_U_RST EQU 5 ; Reset the utility board - -; Software status bits, defined at X: Date: Fri, 7 Nov 2025 16:29:33 -0800 Subject: [PATCH 12/19] more changes, not compiling --- Config/flexured.cfg.in | 18 ++-- flexured/flexure_compensator.cpp | 163 ++++++++++++++++++++----------- flexured/flexure_compensator.h | 33 ++++++- flexured/flexure_interface.cpp | 22 +++-- flexured/flexure_interface.h | 2 +- flexured/flexure_server.cpp | 78 ++------------- 6 files changed, 164 insertions(+), 152 deletions(-) diff --git a/Config/flexured.cfg.in b/Config/flexured.cfg.in index e1e9e200..f0a1963f 100644 --- a/Config/flexured.cfg.in +++ b/Config/flexured.cfg.in @@ -15,17 +15,17 @@ EMULATOR_PORT=@FLEXURED_EMULATOR@ # COLLIMATOR_POSITION # -COLLIMATOR_POSITION_RXE=(21.2591 -0.275957 1.29479) -COLLIMATOR_POSITION_RYE=(0.266115 22.3092 -0.821104) -COLLIMATOR_POSITION_IXE=(19.2199 0.149826 -0.159326) -COLLIMATOR_POSITION_IYE=(0.123447 -20.5831 0.307648) +POSITION_COEFFICIENTS=(R X 21.2591 -0.275957 1.29479) +POSITION_COEFFICIENTS=(R Y 0.266115 22.3092 -0.821104) +POSITION_COEFFICIENTS=(I X 19.2199 0.149826 -0.159326) +POSITION_COEFFICIENTS=(I Y 0.123447 -20.5831 0.307648) -# Flexure polynomial data +# FLEXURE_POLYNOMIALS # -FLEXURE_POLY_IX=( 0.0135162 -0.00447609 -6.48415e-05 6.43345e-06 -4.00865e-08 0.0415762 -0.0701252 0.000227690 0 0 0.288840 -0.00161429 0 0 0 -0.0112647 -0.00343684 0.000147780 -1.68025e-06 7.84644e-09) -FLEXURE_POLY_IY=( -0.00694281 0.00341489 -0.000852294 6.95515e-06 -6.85542e-08 0.00583450 -0.00415384 -5.64805e-05 0 0 2.30189 -0.0106356 0 0 0 -0.163970 0.000321176 8.95876e-06 0 0 ) -FLEXURE_POLY_RX=( 0.00 0.00 0.0 0.0 0.0 -0.0641885 -0.0317361 -0.000197792 0 0 2.57404 -0.00327556 0 0 0 0.000445881 0.0107193 -0.000509618 9.11488e-6 -4.74720e-8) -FLEXURE_POLY_RY=( -0.00644079 0.00907213 -0.000377799 1.49786e-05 -3.50103e-08 -0.0180188 -0.0165204 8.40640e-05 0 0 2.61190 -0.00353314 0 0 0 -0.00104779 0.000841425 4.02491e-06 0 0) +FLEXURE_POLYNOMIALS=( I X 0.0135162 -0.00447609 -6.48415e-05 6.43345e-06 -4.00865e-08 0.0415762 -0.0701252 0.000227690 0 0 0.288840 -0.00161429 0 0 0 -0.0112647 -0.00343684 0.000147780 -1.68025e-06 7.84644e-09) +FLEXURE_POLYNOMIALS=( I Y -0.00694281 0.00341489 -0.000852294 6.95515e-06 -6.85542e-08 0.00583450 -0.00415384 -5.64805e-05 0 0 2.30189 -0.0106356 0 0 0 -0.163970 0.000321176 8.95876e-06 0 0 ) +FLEXURE_POLYNOMIALS=( R X 0.00 0.00 0.0 0.0 0.0 -0.0641885 -0.0317361 -0.000197792 0 0 2.57404 -0.00327556 0 0 0 0.000445881 0.0107193 -0.000509618 9.11488e-6 -4.74720e-8) +FLEXURE_POLYNOMIALS=( R Y -0.00644079 0.00907213 -0.000377799 1.49786e-05 -3.50103e-08 -0.0180188 -0.0165204 8.40640e-05 0 0 2.61190 -0.00353314 0 0 0 -0.00104779 0.000841425 4.02491e-06 0 0) # For each actuator's controller specify: # MOTOR_CONTROLLER=" " diff --git a/flexured/flexure_compensator.cpp b/flexured/flexure_compensator.cpp index 45e26f8a..db5680a4 100644 --- a/flexured/flexure_compensator.cpp +++ b/flexured/flexure_compensator.cpp @@ -9,6 +9,19 @@ namespace Flexure { + Compensator::Compensator() { + for (const auto &chan : { "U", "G", "R", "I" }) { + for (const auto &axis : { "X", "Y" }) { + position_coefficients[{chan,axis}] = std::vector(); + flexure_polynomials[{chan,axis}] = std::vector(); + } + } + + this->trigfunction["R"] = TrigFunction::Sine; + this->trigfunction["I"] = TrigFunction::Cosine; + + } + /***** Flexure::Compensator::datavec_name ***********************************/ /** * @brief returns the name of a vector type @@ -31,70 +44,70 @@ namespace Flexure { /***** Flexure::Compensator::datavec_name ***********************************/ - /***** Flexure::Compensator::load_vector_from_config ************************/ + /***** Flexure::Compensator::load_position_coefficients *********************/ /** - * @brief loads data from Config file into the appropriate vector - * @param[in] config configuration line - * @param[in] vectype DataVectorType specifies which vector to load - * @param[in] vecsize number of elements in this vector - * + * @brief loads position coefficients from configuration file + * @param[in] config configuration line + * @param[in] type one of VectorType enum to specify which vector map to load + * @return ERROR|NO_ERROR */ - long Compensator::load_vector_from_config(std::string &config, DataVectorType vectype, size_t vecsize) { - const std::string function("Flexure::Compensator::load_vector_from_config"); + long Compensator::load_vector_from_config(std::string &config, VectorType type) { + const std::string function("Flexure::Compensator::load_position_coefficients"); + std::vector tokens; + Tokenize(config, tokens, " "); - if (vecsize<1) { - logwrite(function, "ERROR requested zero vector size for "+datavec_name(vectype)); + size_t vecsize; + vector_map_t* vecmap; + + if (type==VectorType::POSITION_COEFFICIENTS) { + vecmap = &this->position_coefficients; + vecsize = 3; + } + else + if (type==VectorType::FLEXURE_POLYNOMIALS) { + vecmap = &this->flexure_polynomials; + vecsize = 20; + } + else { + logwrite(function, "ERROR invalid vector type"); return ERROR; } - std::vector* vec=nullptr; // reference to specified class vector - - // select which vector to load - switch (vectype) { - case DataVectorType::RXE: vec = &this->rxe; - break; - case DataVectorType::RYE: vec = &this->rye; - break; - case DataVectorType::IXE: vec = &this->ixe; - break; - case DataVectorType::IYE: vec = &this->iye; - break; - case DataVectorType::PIX: vec = &this->pix; - break; - case DataVectorType::PIY: vec = &this->piy; - break; - case DataVectorType::PRX: vec = &this->prx; - break; - case DataVectorType::PRY: vec = &this->pry; - break; - default: - logwrite(function, "ERROR invalid vector type"); - return ERROR; + // expect ... + // + if (tokens.size() != vecsize ) { + std::ostringstream oss; + oss << "ERROR got \"" << config << "\" but expected ... (" << vecsize << " values)"; + logwrite(function, oss.str()); + return ERROR; } - std::vector tokens; - Tokenize(config, tokens, " "); + // the vector is in a map indexed by channel and axis + // + std::string chan = tokens[0]; + std::string axis = tokens[1]; - if (tokens.size() != vecsize) { - logwrite(function, "ERROR "+std::to_string(tokens.size()) - +" tokens do not match vector size "+std::to_string(vecsize) - +" for "+datavec_name(vectype)); + if (vecmap->find({chan,axis}) == vecmap->end()) { + logwrite(function, "ERROR invalid chan,axis: "+chan+","+axis); return ERROR; } - // erase and load vector + // erase the vector and load it with all of the provided values + // try { - vec->clear(); - for (const auto &tok : tokens) vec->push_back( std::stod(tok) ); + (*vecmap)[{chan,axis}].clear(); + for (int tok=2; tokflexure_polynomials.at(which)[offset + 0] + + this->flexure_polynomials.at(which)[offset + 1] * inputvar + + this->flexure_polynomials.at(which)[offset + 2] * std::pow(inputvar, 2.0) + + this->flexure_polynomials.at(which)[offset + 3] * std::pow(inputvar, 3.0) + + this->flexure_polynomials.at(which)[offset + 4] * std::pow(inputvar, 4.0); return vec[offset + 0] + vec[offset + 1] * inputvar + vec[offset + 2] * std::pow(inputvar, 2.0) @@ -124,24 +143,33 @@ namespace Flexure { /***** Flexure::Compensator::flexure_polynomial_fit *************************/ - /***** Flexure::Compensator::flexure_fit ************************************/ + /***** Flexure::Compensator::calculate_shift ********************************/ /** - * @brief calculates fit + * @brief calculates the shift(chan,axis) of the spectrum on the detector * @details C + A1 * sin(cass-theta) + A2 * sin(2*(cass-theta)) or * C + A1 * cos(cass-theta) + A2 * cos(2*(cass-theta)) - * @param[in] poly vector of polynomial data + * Input coefficients are a function of (chan,axis) so the output + * shift will also be a function of (chan,axis). + * @param[in] coefficients vector of coefficients data * @param[in] func type of trig function to use, Sine or Cosine * @return fitted value * @throws std::exception * */ - double Compensator::flexure_fit(double poly, TrigFunction func) { - const std::string function("Flexure::Compensator::flexure_fit"); + /** + * @brief calculates the shift of the spectrum on the detector + * @details shift is function of (chan, axis) + * needs cass, alt, and coefficients(chan,axis) + * + */ + double Compensator::calculate_shift(std::pair which) { +//double Compensator::calculate_shift(double coefficients, TrigFunction func) { + const std::string function("Flexure::Compensator::calculate_shift"); try { - double c = flexure_polynomial_fit(poly, zenith, 0); - double a1 = flexure_polynomial_fit(poly, zenith, 5); - double theta = flexure_polynomial_fit(poly, zenith, 10); - double a2 = flexure_polynomial_fit(poly, zenith, 15); + double c = flexure_polynomial_fit(coefficients, zenith, 0); + double a1 = flexure_polynomial_fit(coefficients, zenith, 5); + double theta = flexure_polynomial_fit(coefficients, zenith, 10); + double a2 = flexure_polynomial_fit(coefficients, zenith, 15); switch (func) { case TrigFunction::Sine: @@ -158,7 +186,7 @@ namespace Flexure { throw; } } - /***** Flexure::Compensator::flexure_fit ************************************/ + /***** Flexure::Compensator::calculate_shift ********************************/ /***** Flexure::Compensator::compute_flexure_compensation ******************/ @@ -195,10 +223,10 @@ namespace Flexure { double equivalent_cass = (-(pa + cassring) + 180) % 360 - 180; // calculate flexure of each axis - srx = flexure_fit(this->prx, Sine); - sry = flexure_fit(this->pry, Sine); - six = flexure_fit(this->pix, Cosine); - siy = flexure_fit(this->piy, Cosine); + srx = calculate_shift(this->prx, Sine); + sry = calculate_shift(this->pry, Sine); + six = calculate_shift(this->pix, Cosine); + siy = calculate_shift(this->piy, Cosine); collimator_position(srx, sry, &drx, &dry, &tx, &ty); @@ -212,4 +240,23 @@ namespace Flexure { } /***** Flexure::Compensator::compute_flexure_compensation ******************/ + + + /** + * @brief calculates the adjustments needed to compensate for a shift + * @details input is output of calculate_shift() + * output is correction to apply to flexure actuator position + * + */ + void Compensator::calculate_compensation(std::pair which) { + + calculate_shift + } + + + long test() { + this->calculate_shift( { "R", "X" } ); + return NO_ERROR; + } + } diff --git a/flexured/flexure_compensator.h b/flexured/flexure_compensator.h index 0bfc6c61..156446c8 100644 --- a/flexured/flexure_compensator.h +++ b/flexured/flexure_compensator.h @@ -15,6 +15,13 @@ namespace Flexure { constexpr double PI = 3.14159265358979323846; constexpr double DEGTORAD = PI/180.0; + namespace Channel { + constexpr const char* U = "U"; + constexpr const char* G = "G"; + constexpr const char* R = "R"; + constexpr const char* I = "I"; + } + enum class TrigFunction { Sine, Cosine @@ -34,6 +41,11 @@ namespace Flexure { PRY }; + enum VectorType : size_t { + POSITION_COEFFICIENTS, + FLEXURE_POLYNOMIALS + }; + /***** Flexure::Compensator *************************************************/ /** * @brief contains functions and data for performing compensation @@ -42,22 +54,35 @@ namespace Flexure { */ class Compensator { private: + using vector_map_t = std::map, std::vector>; + + vector_map_t position_coefficients; + vector_map_t flexure_polynomials; + + std::map trigfunction; + std::vector rxe, rye, ixe, iye, pix, prx, piy, pry; + void calculate_compensation(); + // From Matt Matuszewski // void collimator_position(double x, double y, double *rx, double *ry, double *ix, double *iy); - double flexure_polynomial_fit(double elevation, double *p); - double flexure_fit(double modified_cass, double elevation, double *p); - double flexure_fit_cos(double modified_cass, double elevation, double *p); + double flexure_polynomial_fit(double vec, double inputvar, size_t offset); + double calculate_shift(std::pair which); +// double calculate_shift(double modified_cass, double elevation, double *p); void compute_flexure_compensation(double ha, double dec, double cassring, double exptime, double *prx, double *pry, double *pix, double *piy, double nrx, double nry, double nix, double niy, double *arx, double *ary, double *aix, double *aiy); public: + Compensator(); + static std::string datavec_name(DataVectorType vectype); - long load_vector_from_config(std::string &config, DataVectorType vectype, size_t vecsize); + long load_vector_from_config(std::string &config, VectorType type); + + long test(); long calculate(/* TBD */); // presumably the equivalent of Matt's main() }; diff --git a/flexured/flexure_interface.cpp b/flexured/flexure_interface.cpp index 55288f71..a6f73d03 100644 --- a/flexured/flexure_interface.cpp +++ b/flexured/flexure_interface.cpp @@ -461,19 +461,19 @@ namespace Flexure { // their telemetry which is returned as a serialized json string // held in retstring. // - // handle_json_message() will parse the serialized json string. + // parse_incoming_telemetry() will parse the serialized json string. // std::string retstring; for ( const auto &provider : this->telemetry_providers ) { Common::collect_telemetry( provider, retstring ); - handle_json_message(retstring); + parse_incoming_telemetry(retstring); } return; } /***** Flexure::Interface::get_external_telemetry ***************************/ - /***** Flexure::Interface::handle_json_message ******************************/ + /***** Flexure::Interface::parse_incoming_telemetry *************************/ /** * @brief parses incoming telemetry messages * @details Requesting telemetry from another daemon returns a serialized @@ -482,8 +482,8 @@ namespace Flexure { * @return ERROR | NO_ERROR * */ - long Interface::handle_json_message( std::string message_in ) { - const std::string function="Flexure::Interface::handle_json_message"; + long Interface::parse_incoming_telemetry( std::string message_in ) { + const std::string function="Flexure::Interface::parse_incoming_telemetry"; std::stringstream message; try { @@ -519,10 +519,11 @@ namespace Flexure { } else if ( messagetype == "tcsinfo" ) { - double casangle=NAN, alt=NAN; + double casangle=NAN, alt=NAN, pa=NAN; Common::extract_telemetry_value( message_in, "CASANGLE", casangle ); Common::extract_telemetry_value( message_in, "ALT", alt ); - message.str(""); message << "casangle=" << casangle << " alt=" << alt; + Common::extract_telemetry_value( message_in, "PA", pa ); + message.str(""); message << "casangle=" << casangle << " alt=" << alt << " PA=" << pa; logwrite( function, message.str() ); } else @@ -547,7 +548,7 @@ namespace Flexure { return NO_ERROR; } - /***** Flexure::Interface::handle_json_message ******************************/ + /***** Flexure::Interface::parse_incoming_telemetry *************************/ /***** Flexure::Interface::test *********************************************/ @@ -615,6 +616,11 @@ namespace Flexure { } retstring.append("\n"); } + else + + if (testname == "calcshift") { + this->compensator.test(); + } else { message.str(""); message << "ERROR: test " << testname << " unknown";; diff --git a/flexured/flexure_interface.h b/flexured/flexure_interface.h index 70569188..34d08924 100644 --- a/flexured/flexure_interface.h +++ b/flexured/flexure_interface.h @@ -73,7 +73,7 @@ namespace Flexure { long send_command( const std::string &name, std::string cmd, std::string &retstring ); ///< writes command?, reads reply void make_telemetry_message( std::string &retstring ); ///< assembles a telemetry message void get_external_telemetry(); ///< collect telemetry from other daemon(s) - long handle_json_message( std::string message_in ); ///< parses incoming telemetry messages + long parse_incoming_telemetry( std::string message_in ); ///< parses incoming telemetry messages long test( std::string args, std::string &retstring ); ///< test routines std::mutex pi_mutex; ///< mutex to protect multi-threaded access to PI controller diff --git a/flexured/flexure_server.cpp b/flexured/flexure_server.cpp index 14df892a..297c29a1 100644 --- a/flexured/flexure_server.cpp +++ b/flexured/flexure_server.cpp @@ -157,10 +157,10 @@ namespace Flexure { } else - // COLLIMATOR_POSITION_RXE + // POSITION_COEFFICIENTS // - if ( config.param[entry] == "COLLIMATOR_POSITION_RXE" ) { - error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::RXE, 3 ); + if ( config.param[entry] == "POSITION_COEFFICIENTS" ) { + error=interface.compensator.load_vector_from_config(config.arg[entry], VectorType::POSITION_COEFFICIENTS); if (error==NO_ERROR) { numapplied++; } @@ -168,76 +168,10 @@ namespace Flexure { } else - // COLLIMATOR_POSITION_RYE + // FLEXURE_POLYNOMIALS // - if ( config.param[entry] == "COLLIMATOR_POSITION_RYE" ) { - error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::RYE, 3 ); - if (error==NO_ERROR) { - numapplied++; - } - else return ERROR; - } - else - - // COLLIMATOR_POSITION_IXE - // - if ( config.param[entry] == "COLLIMATOR_POSITION_IXE" ) { - error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::IXE, 3 ); - if (error==NO_ERROR) { - numapplied++; - } - else return ERROR; - } - else - - // COLLIMATOR_POSITION_IYE - // - if ( config.param[entry] == "COLLIMATOR_POSITION_IYE" ) { - error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::IYE, 3 ); - if (error==NO_ERROR) { - numapplied++; - } - else return ERROR; - } - else - - // FLEXURE_POLY_IX - // - if ( config.param[entry] == "FLEXURE_POLY_IX" ) { - error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::PIX, 20 ); - if (error==NO_ERROR) { - numapplied++; - } - else return ERROR; - } - else - - // FLEXURE_POLY_IY - // - if ( config.param[entry] == "FLEXURE_POLY_IY" ) { - error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::PIY, 20 ); - if (error==NO_ERROR) { - numapplied++; - } - else return ERROR; - } - else - - // FLEXURE_POLY_RX - // - if ( config.param[entry] == "FLEXURE_POLY_RX" ) { - error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::PRX, 20 ); - if (error==NO_ERROR) { - numapplied++; - } - else return ERROR; - } - else - - // FLEXURE_POLY_RY - // - if ( config.param[entry] == "FLEXURE_POLY_RY" ) { - error=interface.compensator.load_vector_from_config( config.arg[entry], DataVectorType::PRY, 20 ); + if ( config.param[entry] == "FLEXURE_POLYNOMIALS" ) { + error=interface.compensator.load_vector_from_config(config.arg[entry], VectorType::FLEXURE_POLYNOMIALS); if (error==NO_ERROR) { numapplied++; } From c4d55b77ffde419825b0626cdf7ddc091d03abed Mon Sep 17 00:00:00 2001 From: David Hale Date: Mon, 10 Nov 2025 13:31:12 -0800 Subject: [PATCH 13/19] core calculation functions are complete --- Config/flexured.cfg.in | 3 +- flexured/flexure_compensator.cpp | 181 ++++++++++++++++++------------- flexured/flexure_compensator.h | 62 +++++------ flexured/flexure_interface.cpp | 10 +- 4 files changed, 149 insertions(+), 107 deletions(-) diff --git a/Config/flexured.cfg.in b/Config/flexured.cfg.in index f0a1963f..62dcefbf 100644 --- a/Config/flexured.cfg.in +++ b/Config/flexured.cfg.in @@ -4,7 +4,6 @@ LOGPATH=/data/logs/ # where to write logs BLKPORT=@FLEXURED_BLK_PORT@ # slitd server blocking port NBPORT=@FLEXURED_NB_PORT@ # slitd server non-blocking port -DAEMON=no # run as daemon? ASYNCPORT=@MESSAGEPORT@ # asynchronous message port ASYNCGROUP=239.1.1.234 # asynchronous message broadcast group PUBLISHER_PORT="tcp://127.0.0.1:@FLEXURED_PUB_PORT@" # my zeromq pub port @@ -14,6 +13,7 @@ PUBLISHER_PORT="tcp://127.0.0.1:@FLEXURED_PUB_PORT@" # my zeromq pub port EMULATOR_PORT=@FLEXURED_EMULATOR@ # COLLIMATOR_POSITION +# # POSITION_COEFFICIENTS=(R X 21.2591 -0.275957 1.29479) POSITION_COEFFICIENTS=(R Y 0.266115 22.3092 -0.821104) @@ -21,6 +21,7 @@ POSITION_COEFFICIENTS=(I X 19.2199 0.149826 -0.159326) POSITION_COEFFICIENTS=(I Y 0.123447 -20.5831 0.307648) # FLEXURE_POLYNOMIALS +# < ... > (expected 20 values) # FLEXURE_POLYNOMIALS=( I X 0.0135162 -0.00447609 -6.48415e-05 6.43345e-06 -4.00865e-08 0.0415762 -0.0701252 0.000227690 0 0 0.288840 -0.00161429 0 0 0 -0.0112647 -0.00343684 0.000147780 -1.68025e-06 7.84644e-09) FLEXURE_POLYNOMIALS=( I Y -0.00694281 0.00341489 -0.000852294 6.95515e-06 -6.85542e-08 0.00583450 -0.00415384 -5.64805e-05 0 0 2.30189 -0.0106356 0 0 0 -0.163970 0.000321176 8.95876e-06 0 0 ) diff --git a/flexured/flexure_compensator.cpp b/flexured/flexure_compensator.cpp index db5680a4..831b5d12 100644 --- a/flexured/flexure_compensator.cpp +++ b/flexured/flexure_compensator.cpp @@ -10,8 +10,13 @@ namespace Flexure { Compensator::Compensator() { + // Initialize the map indices. + // position_coefficients and flexure_polynomials are maps + // indexed by a pair + // These maps will be loaded by Compensator::load_position_coefficients + // for (const auto &chan : { "U", "G", "R", "I" }) { - for (const auto &axis : { "X", "Y" }) { + for (const auto &axis : { X, Y }) { position_coefficients[{chan,axis}] = std::vector(); flexure_polynomials[{chan,axis}] = std::vector(); } @@ -22,43 +27,28 @@ namespace Flexure { } - /***** Flexure::Compensator::datavec_name ***********************************/ - /** - * @brief returns the name of a vector type - * @param[in] vectype DataVectorType - * @return string - */ - std::string Compensator::datavec_name(DataVectorType vectype) { - switch (vectype) { - case RXE: return "RXE"; - case RYE: return "RYE"; - case IXE: return "IXE"; - case IYE: return "IYE"; - case PIX: return "PIY"; - case PIY: return "PIY"; - case PRX: return "PRX"; - case PRY: return "PRY"; - default: return "UNKNOWN"; - } - } - /***** Flexure::Compensator::datavec_name ***********************************/ - - /***** Flexure::Compensator::load_position_coefficients *********************/ + /***** Flexure::Compensator::load_vector_from_config ************************/ /** * @brief loads position coefficients from configuration file + * @details This parses a configuration file row given the specified VectorType + * and loads the class map vector specified by VectorType. This will be + * either a vector of POSITION_COEFFICIENTS or FLEXURE_POLYNOMIALS, + * which are vectors assigned to a map indexed by pair { chan, axis }. * @param[in] config configuration line * @param[in] type one of VectorType enum to specify which vector map to load * @return ERROR|NO_ERROR */ long Compensator::load_vector_from_config(std::string &config, VectorType type) { - const std::string function("Flexure::Compensator::load_position_coefficients"); + const std::string function("Flexure::Compensator::load_vector_from_config"); std::vector tokens; Tokenize(config, tokens, " "); size_t vecsize; vector_map_t* vecmap; + // assign the vecmap pointer to the appropriate map based on VectorType, + // which also has a fixed vector size if (type==VectorType::POSITION_COEFFICIENTS) { vecmap = &this->position_coefficients; vecsize = 3; @@ -74,16 +64,14 @@ namespace Flexure { } // expect ... - // - if (tokens.size() != vecsize ) { + if (tokens.size() != vecsize+2 ) { std::ostringstream oss; oss << "ERROR got \"" << config << "\" but expected ... (" << vecsize << " values)"; logwrite(function, oss.str()); return ERROR; } - // the vector is in a map indexed by channel and axis - // + // the vector is in a map indexed by pair { chan, axis } std::string chan = tokens[0]; std::string axis = tokens[1]; @@ -92,11 +80,10 @@ namespace Flexure { return ERROR; } - // erase the vector and load it with all of the provided values - // + // erase the vector and load it with the values provided by the configuration row try { (*vecmap)[{chan,axis}].clear(); - for (int tok=2; tokflexure_polynomials[{chan,axis}] + * are a,b,c,d,e then return a + bx + cx^2 + dx^3 + ex^4. + * @param[in] which pair { channel, axis } * @param[in] inputvar independent input variable for the polynomial fit * @param[in] offset offset in vector to start reading coefficients + * @return double (a + bx + cx^2 + dx^3 + ex^4) * @throws std::out_of_range * */ - double Compensator::flexure_polynomial_fit(double vec, double inputvar, size_t offset) { - const std::string function("Flexure::Compensator::flexure_polynomial_fit"); - if (offset+5 > vec.size()) { - logwrite(function, "ERROR not enough coefficients in vector for requested offset"); - throw std::out_of_range("not enough coefficients in vector"); + double Compensator::flexure_polynomial_fit(const std::pair &which, double inputvar, size_t offset) { + + std::cerr << "flexure_polynomial_fit size=" << this->flexure_polynomials.at(which).size() << "\n"; + if (offset+5 > this->flexure_polynomials.at(which).size()) { + throw std::out_of_range("not enough flexure polynomial coefficients"); } + // a + bx + cx^2 + dx^3 + ex^4 + // return this->flexure_polynomials.at(which)[offset + 0] + this->flexure_polynomials.at(which)[offset + 1] * inputvar + this->flexure_polynomials.at(which)[offset + 2] * std::pow(inputvar, 2.0) + this->flexure_polynomials.at(which)[offset + 3] * std::pow(inputvar, 3.0) + this->flexure_polynomials.at(which)[offset + 4] * std::pow(inputvar, 4.0); - return vec[offset + 0] - + vec[offset + 1] * inputvar - + vec[offset + 2] * std::pow(inputvar, 2.0) - + vec[offset + 3] * std::pow(inputvar, 3.0) - + vec[offset + 4] * std::pow(inputvar, 4.0); } /***** Flexure::Compensator::flexure_polynomial_fit *************************/ @@ -150,39 +137,36 @@ namespace Flexure { * C + A1 * cos(cass-theta) + A2 * cos(2*(cass-theta)) * Input coefficients are a function of (chan,axis) so the output * shift will also be a function of (chan,axis). - * @param[in] coefficients vector of coefficients data - * @param[in] func type of trig function to use, Sine or Cosine - * @return fitted value + * @param[in] which pair { channel, axis } + * @return double (calculated shift) * @throws std::exception * */ - /** - * @brief calculates the shift of the spectrum on the detector - * @details shift is function of (chan, axis) - * needs cass, alt, and coefficients(chan,axis) - * - */ - double Compensator::calculate_shift(std::pair which) { -//double Compensator::calculate_shift(double coefficients, TrigFunction func) { + double Compensator::calculate_shift(const std::pair &which) { const std::string function("Flexure::Compensator::calculate_shift"); try { - double c = flexure_polynomial_fit(coefficients, zenith, 0); - double a1 = flexure_polynomial_fit(coefficients, zenith, 5); - double theta = flexure_polynomial_fit(coefficients, zenith, 10); - double a2 = flexure_polynomial_fit(coefficients, zenith, 15); - - switch (func) { - case TrigFunction::Sine: - return c + a1 * std::sin( (equivalent_cass * DEGTORAD - theta)) - + a2 * std::sin(2*(equivalent_cass * DEGTORAD - theta)); - case TrigFunction::Cosine: - default: - return c + a1 * std::cos( (equivalent_cass * DEGTORAD - theta)) - + a2 * std::cos(2*(equivalent_cass * DEGTORAD - theta)); + double c = flexure_polynomial_fit(which, this->tcs_info.zenith, 0); + double a1 = flexure_polynomial_fit(which, this->tcs_info.zenith, 5); + double theta = flexure_polynomial_fit(which, this->tcs_info.zenith, 10); + double a2 = flexure_polynomial_fit(which, this->tcs_info.zenith, 15); + + auto [ chan, axis ] = which; + + if (this->trigfunction[chan] == TrigFunction::Sine) { + return c + a1 * std::sin( (this->tcs_info.equivalent_cass * DEGTORAD - theta)) + + a2 * std::sin(2*(this->tcs_info.equivalent_cass * DEGTORAD - theta)); + } + else + if (this->trigfunction[chan] == TrigFunction::Cosine) { + return c + a1 * std::cos( (this->tcs_info.equivalent_cass * DEGTORAD - theta)) + + a2 * std::cos(2*(this->tcs_info.equivalent_cass * DEGTORAD - theta)); + } + else { + logwrite(function, "ERROR undefined trig function for channel "+chan); + return NAN; } } catch (const std::exception &e) { - logwrite(function, "ERROR: "+std::string(e.what())); throw; } } @@ -206,6 +190,7 @@ namespace Flexure { * @param[out] aiy -- adjusted stage positions * */ +/*** void Compensator::compute_flexure_compensation(double ha, double dec, double cassring, double exptime, double &prx, double &pry, double &pix, double &piy, double nrx, double nry, double nix, double niy, @@ -221,7 +206,6 @@ namespace Flexure { double adjusted_hour_angle = ha + exptime / 2.0 / 3600.0 * 15.0; double equivalent_cass = (-(pa + cassring) + 180) % 360 - 180; - // calculate flexure of each axis srx = calculate_shift(this->prx, Sine); sry = calculate_shift(this->pry, Sine); @@ -238,24 +222,73 @@ namespace Flexure { aix = dix + nix; aiy = -diy + niy; } +***/ /***** Flexure::Compensator::compute_flexure_compensation ******************/ + /***** Flexure::Compensator::compensate_shift_to_delta *********************/ + /** + * @brief calculates the tip-tilt adjustment needed to compensate for shift + * @details Given the spectral shift for a specific channel, this calculates + * the adjustment needed to compensate for that shift. + * @param[in] channel string channel name + * @param[in] shift pair { sx, sy } representing shift in X, Y + * @param[out] delta pair { dx, dy } representing adjustments to X, Y + * + */ + void Compensator::compensate_shift_to_delta(const std::string &channel, + const std::pair &shift, std::pair delta) { + delta.first = this->position_coefficients.at({channel,X})[0] * shift.first + + this->position_coefficients.at({channel,X})[1] * shift.second + + this->position_coefficients.at({channel,X})[2]; + + delta.second = this->position_coefficients.at({channel,Y})[0] * shift.first + + this->position_coefficients.at({channel,Y})[1] * shift.second + + this->position_coefficients.at({channel,Y})[2]; + } + /***** Flexure::Compensator::compensate_shift_to_delta *********************/ + + + /***** Flexure::Compensator::calculate_compensation ************************/ /** * @brief calculates the adjustments needed to compensate for a shift * @details input is output of calculate_shift() * output is correction to apply to flexure actuator position + * @param[in] which pair { channel, axis } + * @param[out] delta pair { dx, dy } representing adjustments to X, Y * */ - void Compensator::calculate_compensation(std::pair which) { + void Compensator::calculate_compensation(const std::string &channel, std::pair &delta) { + + try { + // calculate shift of spectrum on detector + // + double shift_x = this->calculate_shift({channel, X}); + double shift_y = this->calculate_shift({channel, Y}); - calculate_shift + std::pair shift = { shift_x, shift_y }; + + // calculate tip-tilt adjustment needed to compenstate for shift + // + this->compensate_shift_to_delta(channel, shift, delta); + } + catch (const std::exception &e) { + delta = { NAN, NAN }; + throw; + } } + /***** Flexure::Compensator::calculate_compensation ************************/ - long test() { - this->calculate_shift( { "R", "X" } ); + long Compensator::test(const std::pair which, double &shift) { + try { + shift = this->calculate_shift( which ); + } + catch (const std::exception &e) { + shift = NAN; + logwrite("Flexure::Compensator::test", "ERROR: "+std::string(e.what())); + } return NO_ERROR; } diff --git a/flexured/flexure_compensator.h b/flexured/flexure_compensator.h index 156446c8..38af5645 100644 --- a/flexured/flexure_compensator.h +++ b/flexured/flexure_compensator.h @@ -15,6 +15,9 @@ namespace Flexure { constexpr double PI = 3.14159265358979323846; constexpr double DEGTORAD = PI/180.0; + constexpr const char* X = "X"; + constexpr const char* Y = "Y"; + namespace Channel { constexpr const char* U = "U"; constexpr const char* G = "G"; @@ -27,25 +30,31 @@ namespace Flexure { Cosine }; - /** - * @brief - */ - enum DataVectorType : size_t { - RXE, - RYE, - IXE, - IYE, - PIX, - PIY, - PRX, - PRY - }; - enum VectorType : size_t { POSITION_COEFFICIENTS, FLEXURE_POLYNOMIALS }; + + /***** Flexure::TcsInfo *****************************************************/ + /** + * @brief contains TCS telemetry + * + */ + class TcsInfo { + public: + double zenith; + double equivalent_cass; + double pa; + double cassring; + TcsInfo() + : zenith(1), equivalent_cass(3), pa(5), cassring(7) { +// this->equivalent_cass=(-(this->pa + this->cassring) + 180) % 360 - 180; + } + }; + /***** Flexure::TcsInfo *****************************************************/ + + /***** Flexure::Compensator *************************************************/ /** * @brief contains functions and data for performing compensation @@ -61,30 +70,21 @@ namespace Flexure { std::map trigfunction; - std::vector rxe, rye, ixe, iye, pix, prx, piy, pry; - - void calculate_compensation(); - - // From Matt Matuszewski - // - void collimator_position(double x, double y, double *rx, double *ry, double *ix, double *iy); - double flexure_polynomial_fit(double vec, double inputvar, size_t offset); - double calculate_shift(std::pair which); -// double calculate_shift(double modified_cass, double elevation, double *p); - void compute_flexure_compensation(double ha, double dec, double cassring, double exptime, - double *prx, double *pry, double *pix, double *piy, - double nrx, double nry, double nix, double niy, - double *arx, double *ary, double *aix, double *aiy); + double flexure_polynomial_fit(const std::pair &which, double inputvar, size_t offset); + double calculate_shift(const std::pair &which); + void compensate_shift_to_delta(const std::string &channel, + const std::pair &shift, std::pair delta); public: Compensator(); - static std::string datavec_name(DataVectorType vectype); + TcsInfo tcs_info; + long load_vector_from_config(std::string &config, VectorType type); - long test(); + void calculate_compensation(const std::string &channel, std::pair &delta); - long calculate(/* TBD */); // presumably the equivalent of Matt's main() + long test(const std::pair which, double &shift); }; /***** Flexure::Compensator *************************************************/ diff --git a/flexured/flexure_interface.cpp b/flexured/flexure_interface.cpp index a6f73d03..59c95f02 100644 --- a/flexured/flexure_interface.cpp +++ b/flexured/flexure_interface.cpp @@ -619,7 +619,15 @@ namespace Flexure { else if (testname == "calcshift") { - this->compensator.test(); + if (tokens.size() != 3) { + logwrite(function, "ERROR expected "); + return ERROR; + } + double shift; + this->compensator.test({tokens[1], tokens[2]}, shift); + message.str(""); message << shift; + retstring = message.str(); + return NO_ERROR; } else { From 175643a55e3904c0e27c513a8609bac41e67aaff Mon Sep 17 00:00:00 2001 From: David Hale Date: Mon, 10 Nov 2025 16:26:16 -0800 Subject: [PATCH 14/19] adds ZMQ Pub-Sub to flexured --- Config/flexured.cfg.in | 6 +++- common/common.h | 7 +++++ flexured/CMakeLists.txt | 9 ++++++ flexured/flexure_interface.cpp | 48 ++++++++++++++++++++++++++++++++ flexured/flexure_interface.h | 51 ++++++++++++++++++++++++++++++---- flexured/flexure_server.cpp | 19 +++++++++++++ 6 files changed, 134 insertions(+), 6 deletions(-) diff --git a/Config/flexured.cfg.in b/Config/flexured.cfg.in index 62dcefbf..59b9d74a 100644 --- a/Config/flexured.cfg.in +++ b/Config/flexured.cfg.in @@ -6,7 +6,11 @@ BLKPORT=@FLEXURED_BLK_PORT@ # slitd server blocking port NBPORT=@FLEXURED_NB_PORT@ # slitd server non-blocking port ASYNCPORT=@MESSAGEPORT@ # asynchronous message port ASYNCGROUP=239.1.1.234 # asynchronous message broadcast group -PUBLISHER_PORT="tcp://127.0.0.1:@FLEXURED_PUB_PORT@" # my zeromq pub port + +# Message pub/sub +# +PUB_ENDPOINT="tcp://127.0.0.1:@MESSAGE_BROKER_SUB_PORT@" +SUB_ENDPOINT="tcp://127.0.0.1:@MESSAGE_BROKER_PUB_PORT@" # this is the port number that the emulator listens to # diff --git a/common/common.h b/common/common.h index 9ed10dba..ddfd42cb 100644 --- a/common/common.h +++ b/common/common.h @@ -222,6 +222,13 @@ namespace Common { iface.subscriber_topics.push_back(topic); } + // check subscriber initialization (this would be a programming error) + // + if (!iface.subscriber) { + logwrite(function, "ERROR subscriber object is not initialized"); + return ERROR; + } + try { // connect to the message broker and wait for connection to establish // diff --git a/flexured/CMakeLists.txt b/flexured/CMakeLists.txt index 068c0000..9665cb9d 100644 --- a/flexured/CMakeLists.txt +++ b/flexured/CMakeLists.txt @@ -4,6 +4,8 @@ # @author David Hale # ---------------------------------------------------------------------------- +# add_compile_options( -O0 -g -march=native -DNDEBUG) + cmake_minimum_required( VERSION 3.12 ) set( FLEXURED_DIR ${PROJECT_BASE_DIR}/flexured ) @@ -16,6 +18,11 @@ include_directories( ${PROJECT_BASE_DIR}/common ) link_directories( ${PROJECT_BASE_DIR}/lib ) +# ZeroMQ +# +find_library( ZMQPP_LIB zmqpp NAMES libzmqpp PATHS /usr/local/lib ) +find_library( ZMQ_LIB zmq NAMES libzmq PATHS /usr/local/lib ) + add_executable(flexured ${FLEXURED_DIR}/flexured.cpp ${FLEXURED_DIR}/flexure_server.cpp @@ -30,6 +37,8 @@ target_link_libraries(flexured logentry utilities ${CMAKE_THREAD_LIBS_INIT} + ${ZMQPP_LIB} + ${ZMQ_LIB} ) # -- Port Definitions ---------------------------------------------------------- diff --git a/flexured/flexure_interface.cpp b/flexured/flexure_interface.cpp index 59c95f02..3cdb11e5 100644 --- a/flexured/flexure_interface.cpp +++ b/flexured/flexure_interface.cpp @@ -43,6 +43,54 @@ namespace Flexure { /***** Flexure::Interface::initialize_class *********************************/ + /***** Flexure::Interface::handletopic_snapshot *****************************/ + /** + * @brief publishes a snapshot of my telemetry + * @details This publishes a JSON message containing a snapshot of my + * telemetry info when the subscriber receives the "_snapshot" + * topic and the payload contains my daemon name. + * @param[in] jmessage subscribed-received JSON message + * @return ERROR or NO_ERROR + * + */ + void Interface::handletopic_snapshot(const nlohmann::json &jmessage) { + // If my name is in the jmessage then publish my snapshot + // + if (jmessage.contains(Flexure::DAEMON_NAME)) { + this->publish_snapshot(); + } + else + if (jmessage.contains("test")) { + logwrite("Flexure::Interface::handletopic_snapshot", jmessage.dump()); + } + } + /***** Flexure::Interface::handletopic_snapshot *****************************/ + + + void Interface::handletopic_tcsd(const nlohmann::json &jmessage) { + logwrite("Flexure::Interface::handletopic_tcsd", "will process tcsinfo here"); + } + + + void Interface::publish_snapshot() { + std::string dontcare; + this->publish_snapshot(dontcare); + } + void Interface::publish_snapshot(std::string &retstring) { + nlohmann::json jmessage_out; + jmessage_out["source"] = "flexured"; + retstring=jmessage_out.dump(); + retstring.append(JEOF); + + try { + this->publisher->publish( jmessage_out ); + } + catch (const std::exception &e) { + logwrite("Flexure::Interface::publish_snapshot", "ERROR: "+std::string(e.what())); + } + } + + /***** Flexure::Interface::open *********************************************/ /** * @brief opens the PI socket connection diff --git a/flexured/flexure_interface.h b/flexured/flexure_interface.h index 34d08924..6ba80667 100644 --- a/flexured/flexure_interface.h +++ b/flexured/flexure_interface.h @@ -43,11 +43,56 @@ namespace Flexure { */ class Interface { private: + zmqpp::context context; size_t numdev; bool class_initialized; + public: + Interface() : + context(), + numdev(-1), + motorinterface(FLEXURE_MOVE_TIMEOUT, 0, FLEXURE_POSNAME_TOLERANCE), + subscriber(std::make_unique(context, Common::PubSub::Mode::SUB)), + is_subscriber_thread_running(false), + should_subscriber_thread_run(false) + { + topic_handlers = { + { "_snapshot", std::function( + [this](const nlohmann::json &msg) { handletopic_snapshot(msg); } ) }, + { "tcsd", std::function( + [this](const nlohmann::json &msg) { handletopic_tcsd(msg); } ) } + }; + } + + // PI Interface class for the Piezo type + // + Physik_Instrumente::Interface motorinterface; + + std::unique_ptr publisher; ///< publisher object + std::string publisher_address; ///< publish socket endpoint + std::string publisher_topic; ///< my default topic for publishing + std::unique_ptr subscriber; ///< subscriber object + std::string subscriber_address; ///< subscribe socket endpoint + std::vector subscriber_topics; ///< list of topics I subscribe to + std::atomic is_subscriber_thread_running; ///< is my subscriber thread running? + std::atomic should_subscriber_thread_run; ///< should my subscriber thread run? + std::unordered_map> topic_handlers; + ///< maps a handler function to each topic + + // publish/subscribe functions + // + long init_pubsub(const std::initializer_list &topics={}) { + return Common::PubSubHandler::init_pubsub(context, *this, topics); + } + void start_subscriber_thread() { Common::PubSubHandler::start_subscriber_thread(*this); } + void stop_subscriber_thread() { Common::PubSubHandler::stop_subscriber_thread(*this); } + + void handletopic_snapshot( const nlohmann::json &jmessage ); + void handletopic_tcsd( const nlohmann::json &jmessage ); - Interface() : numdev(-1), motorinterface( FLEXURE_MOVE_TIMEOUT, 0, FLEXURE_POSNAME_TOLERANCE ) {} + void publish_snapshot(); + void publish_snapshot(std::string &retstring); std::map telemetry_providers; ///< map of port[daemon_name] for external telemetry providers @@ -55,10 +100,6 @@ namespace Flexure { Compensator compensator; - // PI Interface class for the Piezo type - // - Physik_Instrumente::Interface motorinterface; - long initialize_class(); long open(); ///< opens the PI socket connection long close(); ///< closes the PI socket connection diff --git a/flexured/flexure_server.cpp b/flexured/flexure_server.cpp index 297c29a1..8ed824ba 100644 --- a/flexured/flexure_server.cpp +++ b/flexured/flexure_server.cpp @@ -124,6 +124,22 @@ namespace Flexure { } else + // PUB_ENDPOINT -- my ZeroMQ socket endpoint for publishing + // + if ( config.param[entry] == "PUB_ENDPOINT" ) { + this->interface.publisher_address = config.arg[entry]; + this->interface.publisher_topic = DAEMON_NAME; // default publish topic is my name + numapplied++; + } + else + + // SUB_ENDPOINT + // + if ( config.param[entry] == "SUB_ENDPOINT" ) { + this->interface.subscriber_address = config.arg[entry]; + numapplied++; + } + // MOTOR_AXIS -- axis info for specified MOTOR_CONTROLLER // if ( config.param[entry].find( "MOTOR_AXIS" ) == 0 ) { @@ -208,6 +224,9 @@ namespace Flexure { } } // end loop through the entries in the configuration file +//logwrite(function, "will start subscriber thread"); +// this->interface.start_subscriber_thread(); + message.str(""); if (numapplied==0) { message << "ERROR: "; From 9f56381b6aa2c0a5973b3b35c37e665eabeda694 Mon Sep 17 00:00:00 2001 From: David Hale Date: Tue, 11 Nov 2025 14:39:50 -0800 Subject: [PATCH 15/19] receives/parses TCS ZMQ-published telemetry adds compensate functionality cleans up signal handler --- flexured/flexure_compensator.cpp | 29 +++-- flexured/flexure_compensator.h | 29 +---- flexured/flexure_interface.cpp | 200 +++++++++++++++++++++++++++---- flexured/flexure_interface.h | 27 ++++- flexured/flexure_server.cpp | 36 ++++++ flexured/flexure_server.h | 13 +- flexured/flexured.cpp | 97 +++++---------- flexured/flexured.h | 2 - flexured/tcs_info.h | 50 ++++++++ 9 files changed, 357 insertions(+), 126 deletions(-) create mode 100644 flexured/tcs_info.h diff --git a/flexured/flexure_compensator.cpp b/flexured/flexure_compensator.cpp index 831b5d12..e23dc30b 100644 --- a/flexured/flexure_compensator.cpp +++ b/flexured/flexure_compensator.cpp @@ -2,18 +2,26 @@ * @file flexure_compensator.cpp * @brief this contains the flexure compensator code * @author David Hale & Matt + * Algorithms by Matt Matuszewski * */ +#include "tcs_info.h" #include "flexure_compensator.h" namespace Flexure { - Compensator::Compensator() { - // Initialize the map indices. + /***** Flexure::Compensator::Compensator ************************************/ + /** + * @brief class constructor + * @param[in] info constructed with a reference to the TcsInfo object + * owned by Interface. + * + */ + Compensator::Compensator(TcsInfo &info) : tcs_info(info) { // position_coefficients and flexure_polynomials are maps - // indexed by a pair - // These maps will be loaded by Compensator::load_position_coefficients + // indexed by a pair. This initializes their indices. + // Values will be loaded by Compensator::load_position_coefficients(). // for (const auto &chan : { "U", "G", "R", "I" }) { for (const auto &axis : { X, Y }) { @@ -26,6 +34,7 @@ namespace Flexure { this->trigfunction["I"] = TrigFunction::Cosine; } + /***** Flexure::Compensator::Compensator ************************************/ /***** Flexure::Compensator::load_vector_from_config ************************/ @@ -38,6 +47,7 @@ namespace Flexure { * @param[in] config configuration line * @param[in] type one of VectorType enum to specify which vector map to load * @return ERROR|NO_ERROR + * */ long Compensator::load_vector_from_config(std::string &config, VectorType type) { const std::string function("Flexure::Compensator::load_vector_from_config"); @@ -114,7 +124,6 @@ namespace Flexure { */ double Compensator::flexure_polynomial_fit(const std::pair &which, double inputvar, size_t offset) { - std::cerr << "flexure_polynomial_fit size=" << this->flexure_polynomials.at(which).size() << "\n"; if (offset+5 > this->flexure_polynomials.at(which).size()) { throw std::out_of_range("not enough flexure polynomial coefficients"); } @@ -145,10 +154,10 @@ namespace Flexure { double Compensator::calculate_shift(const std::pair &which) { const std::string function("Flexure::Compensator::calculate_shift"); try { - double c = flexure_polynomial_fit(which, this->tcs_info.zenith, 0); - double a1 = flexure_polynomial_fit(which, this->tcs_info.zenith, 5); - double theta = flexure_polynomial_fit(which, this->tcs_info.zenith, 10); - double a2 = flexure_polynomial_fit(which, this->tcs_info.zenith, 15); + double c = flexure_polynomial_fit(which, this->tcs_info.zenangle, 0); + double a1 = flexure_polynomial_fit(which, this->tcs_info.zenangle, 5); + double theta = flexure_polynomial_fit(which, this->tcs_info.zenangle, 10); + double a2 = flexure_polynomial_fit(which, this->tcs_info.zenangle, 15); auto [ chan, axis ] = which; @@ -167,6 +176,7 @@ namespace Flexure { } } catch (const std::exception &e) { + logwrite("Flexure::Compensator::calculate_shift", "ERROR: "+std::string(e.what())); throw; } } @@ -274,6 +284,7 @@ namespace Flexure { this->compensate_shift_to_delta(channel, shift, delta); } catch (const std::exception &e) { + logwrite("Flexure::Compensator::calculate_compensation", "ERROR: "+std::string(e.what())); delta = { NAN, NAN }; throw; } diff --git a/flexured/flexure_compensator.h b/flexured/flexure_compensator.h index 38af5645..f00364b1 100644 --- a/flexured/flexure_compensator.h +++ b/flexured/flexure_compensator.h @@ -9,6 +9,7 @@ #pragma once #include "common.h" +#include "tcs_info.h" namespace Flexure { @@ -35,29 +36,9 @@ namespace Flexure { FLEXURE_POLYNOMIALS }; - - /***** Flexure::TcsInfo *****************************************************/ - /** - * @brief contains TCS telemetry - * - */ - class TcsInfo { - public: - double zenith; - double equivalent_cass; - double pa; - double cassring; - TcsInfo() - : zenith(1), equivalent_cass(3), pa(5), cassring(7) { -// this->equivalent_cass=(-(this->pa + this->cassring) + 180) % 360 - 180; - } - }; - /***** Flexure::TcsInfo *****************************************************/ - - /***** Flexure::Compensator *************************************************/ /** - * @brief contains functions and data for performing compensation + * @brief contains functions and data for calculating compensation * @details this does not compensate anything, just informs how to compensate * */ @@ -65,6 +46,8 @@ namespace Flexure { private: using vector_map_t = std::map, std::vector>; + TcsInfo &tcs_info; ///< reference to Interface's TcsInfo + vector_map_t position_coefficients; vector_map_t flexure_polynomials; @@ -76,9 +59,7 @@ namespace Flexure { const std::pair &shift, std::pair delta); public: - Compensator(); - - TcsInfo tcs_info; + Compensator(TcsInfo &info); long load_vector_from_config(std::string &config, VectorType type); diff --git a/flexured/flexure_interface.cpp b/flexured/flexure_interface.cpp index 3cdb11e5..d589cf14 100644 --- a/flexured/flexure_interface.cpp +++ b/flexured/flexure_interface.cpp @@ -45,12 +45,11 @@ namespace Flexure { /***** Flexure::Interface::handletopic_snapshot *****************************/ /** - * @brief publishes a snapshot of my telemetry + * @brief handler when subscriber receives a message with topic "_snapshot" * @details This publishes a JSON message containing a snapshot of my * telemetry info when the subscriber receives the "_snapshot" * topic and the payload contains my daemon name. * @param[in] jmessage subscribed-received JSON message - * @return ERROR or NO_ERROR * */ void Interface::handletopic_snapshot(const nlohmann::json &jmessage) { @@ -67,28 +66,97 @@ namespace Flexure { /***** Flexure::Interface::handletopic_snapshot *****************************/ + /***** Flexure::Interface::handletopic_tcsd *********************************/ + /** + * @brief handler when subscriber receives a message with topic "tcsd" + * @details This loads the tcs_info class with values published by tcsd. + * @param[in] jmessage subscribed-received JSON message + * + */ void Interface::handletopic_tcsd(const nlohmann::json &jmessage) { - logwrite("Flexure::Interface::handletopic_tcsd", "will process tcsinfo here"); + { + std::lock_guard lock(snapshot_mutex); + this->tcs_snapshot_status = true; + } + // extract and store values in the class + Common::extract_telemetry_value(jmessage, "CASANGLE", this->tcs_info.casangle); + Common::extract_telemetry_value(jmessage, "ZENANGLE", this->tcs_info.zenangle); + Common::extract_telemetry_value(jmessage, "PA", this->tcs_info.pa); + this->tcs_info.set(); } + /***** Flexure::Interface::handletopic_tcsd *********************************/ + /***** Flexure::Interface::publish_snapshot *********************************/ + /** + * @brief publishes a snapshot of my telemetry + * @details This loads the tcs_info class with values published by tcsd. + * + */ void Interface::publish_snapshot() { - std::string dontcare; - this->publish_snapshot(dontcare); - } - void Interface::publish_snapshot(std::string &retstring) { nlohmann::json jmessage_out; - jmessage_out["source"] = "flexured"; - retstring=jmessage_out.dump(); - retstring.append(JEOF); + jmessage_out["source"] = "flexured"; // informs subscriber of the source of this telemetry try { - this->publisher->publish( jmessage_out ); + this->publisher->publish(jmessage_out); } catch (const std::exception &e) { logwrite("Flexure::Interface::publish_snapshot", "ERROR: "+std::string(e.what())); } } + /***** Flexure::Interface::publish_snapshot *********************************/ + + + /***** Flexure::Interface::request_tcs_snapshot *****************************/ + /** + * @brief requests tcsd to publish a snapshot of its telemetry + * @details This publishes a "_snapshot" message with "tcsd" topic, which + * will cause tcsd to publish its snapshot. + * @throws std::exception + * + */ + void Interface::request_tcs_snapshot() { + nlohmann::json jmessage; + { + std::lock_guard lock(snapshot_mutex); + this->tcs_snapshot_status = false; + jmessage["tcsd"] = false; + } + try { + this->publisher->publish(jmessage, "_snapshot"); + } + catch (const std::exception &e) { + throw; + } + } + /***** Flexure::Interface::request_tcs_snapshot *****************************/ + + + /***** Flexure::Interface::wait_for_tcs_snapshot ****************************/ + /** + * @brief wait for tcs snapshot data to be published + * @details This is used after request_tcs_snapshot to wait for that to be received. + * @return true when subscriber receives snapshot data + * @throws std::runtime_error on timeout + * + */ + bool Interface::wait_for_tcs_snapshot() { + auto start_time = std::chrono::steady_clock::now(); + auto timeout = std::chrono::seconds(3); + + while (true) { + { + std::lock_guard lock(snapshot_mutex); + if (this->tcs_snapshot_status) return true; + } + + if (std::chrono::steady_clock::now() - start_time > timeout) { + throw std::runtime_error("timeout waiting for TCS telemetry"); + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } + /***** Flexure::Interface::wait_for_tcs_snapshot ****************************/ /***** Flexure::Interface::open *********************************************/ @@ -363,26 +431,99 @@ namespace Flexure { if ( args == "?" || args == "help" ) { retstring = FLEXURED_COMPENSATE; - retstring.append( " [ dryrun ]\n" ); - retstring.append( " Performs the flexure compensation. If the optional dryrun argument\n" ); - retstring.append( " is supplied then perform the calcuations and show the actions that\n" ); - retstring.append( " would be taken without actually moving anything.\n" ); + retstring.append( " [ ...] [ --dryrun ]\n" ); + retstring.append( " Performs the flexure compensation on one or more specified channels.\n" ); + retstring.append( " If the optional --dryrun argument is supplied then perform the calcuations\n" ); + retstring.append( " and show the actions that would be taken without actually moving anything.\n" ); return HELP; } - // get the needed telemetry (telescope position and temperatures) + // check for --dryrun // - this->get_external_telemetry(); + bool is_dryrun = false; + auto pos = args.find("--dryrun"); + if (pos != std::string::npos) { // if switch in the args + args.erase(pos, 8); // then remove it + is_dryrun = true; // and set is_dryrun + } - // perform the calculations + // args can contain a space-delimited list of channels // - retstring="not_yet_implemented"; + std::vector channels; + Tokenize(args, channels, " "); + if (channels.empty()) { + logwrite(function, "ERROR no channel specified"); + return ERROR; + } - return ERROR; + std::pair delta; + auto motormap = this->motorinterface.get_motormap(); + + // loop through list of specified channel(s) + // + for (const auto &chan : channels) { + try { + if (motormap.find(chan) == motormap.end()) throw std::runtime_error("unrecognized channel: "+chan); + this->validate_tcs_telemetry(); + this->compensator.calculate_compensation(chan, delta); + this->offset_tiptilt(chan, delta, is_dryrun); + } + catch (const std::exception &e) { + logwrite(function, "ERROR: "+std::string(e.what())); + return ERROR; + } + } + + return NO_ERROR; } /***** Flexure::Interface::compensate ***************************************/ + /***** Flexure::Interface::offset_tiptilt ***********************************/ + /** + * @brief offsets the X, Y axes for the specified channel by specified delta + * @param[in] chan string channel + * @param[in] delta double pair { X, Y } of calculated offsets + * @param[in] is_dryrun if true then no motion is commanded + * @throws std::runtime_error + * + */ + void Interface::offset_tiptilt(const std::string &chan, const std::pair &delta, bool is_dryrun) { + + auto addr=this->motorinterface.get_motormap()[chan].addr; + float position_x=NAN, position_y=NAN; + std::string posname, retstring; + + // get the current positions + if ( this->motorinterface.get_pos( chan, 2, addr, position_x, posname ) != NO_ERROR || + this->motorinterface.get_pos( chan, 3, addr, position_y, posname ) != NO_ERROR ) { + throw std::runtime_error("reading positions for channel "+chan); + } + + float newposition_x = position_x + delta.first; + float newposition_y = position_y + delta.second; + + if ( is_dryrun ) { + std::ostringstream oss; + oss << "dry run: would move chan " << chan << " by " << delta.first << ", " << delta.second + << " to X=" << newposition_x << " Y=" << newposition_y; + logwrite("Flexure::Interface::offset_tiptilt", oss.str()); + return; + } + + // move X-axis + if (this->motorinterface.moveto( chan, 2, newposition_x, retstring ) != NO_ERROR) { + throw std::runtime_error("moving X axis for channel "+chan); + } + + // move Y-axis + if (this->motorinterface.moveto( chan, 3, newposition_y, retstring ) != NO_ERROR) { + throw std::runtime_error("moving Y axis for channel "+chan); + } + } + /***** Flexure::Interface::offset_tiptilt ***********************************/ + + /***** Flexure::Interface::stop *********************************************/ /** * @brief send the stop-all-motion command to all controllers @@ -677,6 +818,25 @@ namespace Flexure { retstring = message.str(); return NO_ERROR; } + else + + if (testname == "compensate") { + if (tokens.size() != 2) { + logwrite(function, "ERROR expected "); + return ERROR; + } + + try { + std::pair delta; + this->compensator.calculate_compensation(tokens[1], delta); + this->offset_tiptilt(tokens[1], delta, true); // true = dry run + } + catch (const std::exception &e) { + logwrite(function, std::string(e.what())); + return ERROR; + } + return NO_ERROR; + } else { message.str(""); message << "ERROR: test " << testname << " unknown";; diff --git a/flexured/flexure_interface.h b/flexured/flexure_interface.h index 6ba80667..25c6e9aa 100644 --- a/flexured/flexure_interface.h +++ b/flexured/flexure_interface.h @@ -12,6 +12,7 @@ #include "pi.h" #include "logentry.h" #include "common.h" +#include "tcs_info.h" #include "flexured_commands.h" #include "flexure_compensator.h" #include @@ -54,7 +55,10 @@ namespace Flexure { motorinterface(FLEXURE_MOVE_TIMEOUT, 0, FLEXURE_POSNAME_TOLERANCE), subscriber(std::make_unique(context, Common::PubSub::Mode::SUB)), is_subscriber_thread_running(false), - should_subscriber_thread_run(false) + should_subscriber_thread_run(false), + tcs_snapshot_status(false), + tcs_info(), + compensator(tcs_info) { topic_handlers = { { "_snapshot", std::function( @@ -80,6 +84,9 @@ namespace Flexure { std::function> topic_handlers; ///< maps a handler function to each topic + bool tcs_snapshot_status; + std::mutex snapshot_mutex; + // publish/subscribe functions // long init_pubsub(const std::initializer_list &topics={}) { @@ -92,12 +99,15 @@ namespace Flexure { void handletopic_tcsd( const nlohmann::json &jmessage ); void publish_snapshot(); - void publish_snapshot(std::string &retstring); + void request_tcs_snapshot(); + bool wait_for_tcs_snapshot(); std::map telemetry_providers; ///< map of port[daemon_name] for external telemetry providers Common::Queue async; + TcsInfo tcs_info; ///< defined in tcs_info.h + Compensator compensator; long initialize_class(); @@ -108,6 +118,7 @@ namespace Flexure { long set( std::string args, std::string &retstring ); ///< set the slit width and offset long get( std::string args, std::string &retstring ); ///< get the current width and offset long compensate( std::string args, std::string &retstring ); ///< perform flexure compensation + void offset_tiptilt(const std::string &chan, const std::pair &delta, bool is_dryrun); long stop(); ///< send the stop-all-motion command to all controllers long send_command( const std::string &name, std::string cmd ); ///< writes the raw command as received to the master controller, no reply @@ -124,6 +135,18 @@ namespace Flexure { std::mutex wait_mtx; ///< mutex object for waiting for threads std::condition_variable cv; ///< condition variable for waiting for threads + + void validate_tcs_telemetry() { + // if TCS telemetry is old then ask it to publish + // + if (this->tcs_info.is_older_than(std::chrono::seconds(10))) { + try { + this->request_tcs_snapshot(); + this->wait_for_tcs_snapshot(); + } + catch (const std::exception &e) { throw; } + } + } }; /***** Flexure::Interface ***************************************************/ diff --git a/flexured/flexure_server.cpp b/flexured/flexure_server.cpp index 8ed824ba..f04451fd 100644 --- a/flexured/flexure_server.cpp +++ b/flexured/flexure_server.cpp @@ -9,6 +9,7 @@ namespace Flexure { + Server* Server::instance = nullptr; /***** Flexure::Server::exit_cleanly ****************************************/ /** @@ -24,6 +25,41 @@ namespace Flexure { /***** Flexure::Server::exit_cleanly ****************************************/ + /***** Flexure::Server::handle_signal ***************************************/ + /** + * @brief handles ctrl-C and other signals + * @param[in] signo + * + */ + void Server::handle_signal(int signo) { + const std::string function("Flexure::Server::handle_signal"); + std::ostringstream message; + + switch (signo) { + case SIGTERM: + case SIGINT: + logwrite(function, "received termination signal"); + message << "NOTICE:" << Flexure::DAEMON_NAME << " exit"; + Server::instance->interface.async.enqueue( message.str() ); + Server::instance->exit_cleanly(); // shutdown the daemon + break; + case SIGHUP: + logwrite(function, "ignored SIGHUP"); + break; + case SIGPIPE: + logwrite(function, "ignored SIGPIPE"); + break; + default: + message << "received unknown signal " << strsignal(signo); + logwrite( function, message.str() ); + message.str(""); message << "NOTICE:" << Flexure::DAEMON_NAME << " exit"; + Server::instance->interface.async.enqueue( message.str() ); + break; + } + } + /***** Flexure::Server::handle_signal ***************************************/ + + /***** Flexure::Server::configure_flexured **********************************/ /** * @brief read and apply the configuration file for the flexure daemon diff --git a/flexured/flexure_server.h b/flexured/flexure_server.h index fa7a47f6..280ad267 100644 --- a/flexured/flexure_server.h +++ b/flexured/flexure_server.h @@ -46,11 +46,20 @@ namespace Flexure { class Server { private: public: + static Server* instance; + /***** Flexure::Server::Server ******************************************/ /** * @brief class constructor */ - Server() : nbport(-1), blkport(-1), asyncport(-1), cmd_num(0), threads_active(0), id_pool(Flexure::N_THREADS) { } + Server() : nbport(-1), blkport(-1), asyncport(-1), cmd_num(0), threads_active(0), id_pool(Flexure::N_THREADS) { + instance=this; + // register these signals + // + signal(SIGINT, this->signal_handler); + signal(SIGPIPE, this->signal_handler); + signal(SIGHUP, this->signal_handler); + } /***** Flexure::Server::~Server *****************************************/ /** @@ -102,6 +111,8 @@ namespace Flexure { long configure_flexured(); ///< read and apply the configuration file void doit(Network::TcpSocket &sock); ///< the workhorse of each thread connetion + void handle_signal(int signo); + static inline void signal_handler(int signo) { if (instance) { instance->handle_signal(signo); } } }; /***** Flexure::Server ******************************************************/ diff --git a/flexured/flexured.cpp b/flexured/flexured.cpp index f78cefb6..f705f097 100644 --- a/flexured/flexured.cpp +++ b/flexured/flexured.cpp @@ -17,18 +17,25 @@ * */ int main(int argc, char **argv) { - std::string function = "Flexure::main"; + const std::string function("main"); std::stringstream message; - std::string logpath; - long ret=NO_ERROR; - std::string daemon_in; // daemon setting read from config file - bool start_daemon = false; // don't start as daemon unless specifically requested - // capture these signals + // Unless specifically requested to run in foreground, + // immediately daemonize. // - signal(SIGINT, signal_handler); - signal(SIGPIPE, signal_handler); - signal(SIGHUP, signal_handler); + if ( !cmdOptionExists( argv, argv+argc, "--foreground" ) ) { + logwrite(function, "starting daemon"); + Daemon::daemonize( Flexure::DAEMON_NAME, "/tmp", "/dev/null", "/tmp/flexured.stderr", "", false ); + std::cerr << get_timestamp() << " (" << function << ") daemonized. child process running" << std::endl; + } + else logwrite(function, "starting"); + + // the child process instantiates a Server object + // + Flexure::Server flexured; + + std::string daemon_in; // daemon setting read from config file + bool start_daemon = false; // don't start as daemon unless specifically requested // check for "-f " command line option to specify config file // @@ -56,6 +63,8 @@ int main(int argc, char **argv) { flexured.exit_cleanly(); } + std::string logpath; + for (int entry=0; entry < flexured.config.n_entries; entry++) { if (flexured.config.param[entry] == "LOGPATH") logpath = flexured.config.arg[entry]; if (flexured.config.param[entry] == "DAEMON") daemon_in = flexured.config.arg[entry]; @@ -78,31 +87,11 @@ int main(int argc, char **argv) { flexured.exit_cleanly(); } - if ( !daemon_in.empty() && daemon_in == "yes" ) start_daemon = true; - else - if ( !daemon_in.empty() && daemon_in == "no" ) start_daemon = false; - else { - message.str(""); message << "ERROR: unrecognized argument DAEMON=" << daemon_in << ", expected { yes | no }"; - logwrite( function, message.str() ); - flexured.exit_cleanly(); - } - - // check for "-d" command line option last so that the command line - // can override the config file to start as daemon - // - if ( cmdOptionExists( argv, argv+argc, "-d" ) ) { - start_daemon = true; - } - - if ( start_daemon ) { - logwrite( function, "starting daemon" ); - Daemon::daemonize( Flexure::DAEMON_NAME, "/tmp", "", "", "" ); - } - if ( ( init_log( logpath, Flexure::DAEMON_NAME ) != 0 ) ) { // initialize the logging system logwrite(function, "ERROR: unable to initialize logging system"); flexured.exit_cleanly(); } + logwrite(function, "world"); message << "this version built " << BUILD_DATE << " " << BUILD_TIME; logwrite(function, message.str()); @@ -110,7 +99,7 @@ int main(int argc, char **argv) { message.str(""); message << flexured.config.n_entries << " lines read from " << flexured.config.filename; logwrite(function, message.str()); - if (ret==NO_ERROR) ret=flexured.configure_flexured(); // get needed values out of read-in configuration file for the daemon + long ret=flexured.configure_flexured(); // get needed values out of read-in configuration file for the daemon if (ret != NO_ERROR) { logwrite(function, "ERROR: unable to configure system"); @@ -122,6 +111,15 @@ int main(int argc, char **argv) { flexured.exit_cleanly(); } + // initialize the pub/sub handler + // + if ( flexured.interface.init_pubsub({"tcsd"}) == ERROR ) { + logwrite(function, "ERROR initializing publisher-subscriber handler"); + flexured.exit_cleanly(); + } + std::this_thread::sleep_for( std::chrono::milliseconds(500) ); + flexured.interface.publish_snapshot(); + // This will pre-thread N_THREADS threads. // The 0th thread is reserved for the blocking port, and the rest are for the non-blocking port. // Each thread gets a socket object. All of the socket objects are stored in a vector container. @@ -205,40 +203,3 @@ int main(int argc, char **argv) { return 0; } /***** main *******************************************************************/ - - -/***** signal_handler *********************************************************/ -/** - * @brief handles ctrl-C - * @param[in] signo - * - */ -void signal_handler(int signo) { - std::string function = "Flexure::signal_handler"; - std::stringstream message; - - switch (signo) { - case SIGTERM: - case SIGINT: - logwrite(function, "received termination signal"); - message << "NOTICE:" << Flexure::DAEMON_NAME << " exit"; - flexured.interface.async.enqueue( message.str() ); - flexured.exit_cleanly(); // shutdown the daemon - break; - case SIGHUP: - logwrite(function, "caught SIGHUP"); - break; - case SIGPIPE: - logwrite(function, "caught SIGPIPE"); - break; - default: - message << "received unknown signal " << strsignal(signo); - logwrite( function, message.str() ); - message.str(""); message << "NOTICE:" << Flexure::DAEMON_NAME << " exit"; - flexured.interface.async.enqueue( message.str() ); - flexured.exit_cleanly(); // shutdown the daemon - break; - } - return; -} -/***** signal_handler *********************************************************/ diff --git a/flexured/flexured.h b/flexured/flexured.h index 7fdafecc..afd040f0 100644 --- a/flexured/flexured.h +++ b/flexured/flexured.h @@ -29,7 +29,5 @@ #define CONN_TIMEOUT 3000 ///< incoming (non-blocking) connection timeout in milliseconds -Flexure::Server flexured; ///< global Flexure::Server object so that the main daemon can access the namespace - void signal_handler(int signo); ///< handles ctrl-C int main(int argc, char **argv); ///< the main function diff --git a/flexured/tcs_info.h b/flexured/tcs_info.h new file mode 100644 index 00000000..88f6d5d9 --- /dev/null +++ b/flexured/tcs_info.h @@ -0,0 +1,50 @@ +#pragma once + +#include + +namespace Flexure { + + /***** Flexure::TcsInfo *****************************************************/ + /** + * @brief contains TCS telemetry + * + */ + class TcsInfo { + private: + bool is_timeset; + std::chrono::system_clock::time_point telemetry_time; + + public: + double zenangle; + double equivalent_cass; + double pa; + double casangle; + + TcsInfo() + : is_timeset(false), zenangle(0), equivalent_cass(0), pa(0), casangle(0) { } + + bool is_older_than(std::chrono::seconds sec) { + if (!this->is_timeset) return true; + if (std::chrono::system_clock::now() > this->telemetry_time+sec) { + return true; + } + return false; + } + + void set() { + double angle = this->pa + this->casangle; + + if (angle < -180.0) angle += 360.0; + if (angle > 180.0) angle -= 360.0; + + this->equivalent_cass = angle; + + // record the time that telemetry was received + this->telemetry_time = std::chrono::system_clock::now(); + this->is_timeset = true; + } + + }; + /***** Flexure::TcsInfo *****************************************************/ + +} From 3ddd5f7fec82a9c877e703c6f71318dbfac6da69 Mon Sep 17 00:00:00 2001 From: David Hale Date: Tue, 11 Nov 2025 16:24:56 -0800 Subject: [PATCH 16/19] fixes a bug in compensate_shift_to_delta and adds some test functions. ready to test. --- flexured/flexure_compensator.cpp | 77 +++----------------------------- flexured/flexure_compensator.h | 7 +-- flexured/flexure_interface.cpp | 41 ++++++++++++++--- flexured/flexure_server.cpp | 2 +- 4 files changed, 43 insertions(+), 84 deletions(-) diff --git a/flexured/flexure_compensator.cpp b/flexured/flexure_compensator.cpp index e23dc30b..6530478f 100644 --- a/flexured/flexure_compensator.cpp +++ b/flexured/flexure_compensator.cpp @@ -154,10 +154,10 @@ namespace Flexure { double Compensator::calculate_shift(const std::pair &which) { const std::string function("Flexure::Compensator::calculate_shift"); try { - double c = flexure_polynomial_fit(which, this->tcs_info.zenangle, 0); - double a1 = flexure_polynomial_fit(which, this->tcs_info.zenangle, 5); - double theta = flexure_polynomial_fit(which, this->tcs_info.zenangle, 10); - double a2 = flexure_polynomial_fit(which, this->tcs_info.zenangle, 15); + double c = this->flexure_polynomial_fit(which, this->tcs_info.zenangle, 0); + double a1 = this->flexure_polynomial_fit(which, this->tcs_info.zenangle, 5); + double theta = this->flexure_polynomial_fit(which, this->tcs_info.zenangle, 10); + double a2 = this->flexure_polynomial_fit(which, this->tcs_info.zenangle, 15); auto [ chan, axis ] = which; @@ -183,59 +183,6 @@ namespace Flexure { /***** Flexure::Compensator::calculate_shift ********************************/ - /***** Flexure::Compensator::compute_flexure_compensation ******************/ - /** - * @brief - * @details - * - * @param[in] ha hour angle in decimal degrees. - * @param[in] dec declination in decimal degrees. - * @param[in] cassring - * @param[in] exptime exposure time in seconds for future calculation - * @param[in] prx, pry, pix, piy -- polynomial coefficients to compute fit parameters - * @param[in] nrx, nry, nix, niy -- nominal stage positions - * @param[out] arx-- adjusted stage positions - * @param[out] ary-- adjusted stage positions - * @param[out] aix-- adjusted stage positions - * @param[out] aiy -- adjusted stage positions - * - */ -/*** - void Compensator::compute_flexure_compensation(double ha, double dec, double cassring, double exptime, - double &prx, double &pry, double &pix, double &piy, - double nrx, double nry, double nix, double niy, - double &arx, double &ary, double &aix, double &aiy) { - - double alt, az, pa; // elevation, azimuth, and parallactic angle from TCS - double zenith; // zenith angle - double srx, sry, six, siy; // intermediate computation step -- expected flexure - double drx, dry, dix,diy; // computed correction deltas - double tx, ty; // temporary. - - // adjust hour angle for exposure time midpoint - double adjusted_hour_angle = ha + exptime / 2.0 / 3600.0 * 15.0; - - double equivalent_cass = (-(pa + cassring) + 180) % 360 - 180; - // calculate flexure of each axis - srx = calculate_shift(this->prx, Sine); - sry = calculate_shift(this->pry, Sine); - six = calculate_shift(this->pix, Cosine); - siy = calculate_shift(this->piy, Cosine); - - - collimator_position(srx, sry, &drx, &dry, &tx, &ty); - collimator_position(six, siy, &tx, &ty, &dix, &diy); - - // ajusted stage positions - arx = drx + nrx; - ary = -dry + nry; - aix = dix + nix; - aiy = -diy + niy; - } -***/ - /***** Flexure::Compensator::compute_flexure_compensation ******************/ - - /***** Flexure::Compensator::compensate_shift_to_delta *********************/ /** * @brief calculates the tip-tilt adjustment needed to compensate for shift @@ -243,11 +190,11 @@ namespace Flexure { * the adjustment needed to compensate for that shift. * @param[in] channel string channel name * @param[in] shift pair { sx, sy } representing shift in X, Y - * @param[out] delta pair { dx, dy } representing adjustments to X, Y + * @param[out] delta reference to pair { dx, dy } representing adjustments to X, Y * */ void Compensator::compensate_shift_to_delta(const std::string &channel, - const std::pair &shift, std::pair delta) { + const std::pair &shift, std::pair &delta) { delta.first = this->position_coefficients.at({channel,X})[0] * shift.first + this->position_coefficients.at({channel,X})[1] * shift.second + @@ -291,16 +238,4 @@ namespace Flexure { } /***** Flexure::Compensator::calculate_compensation ************************/ - - long Compensator::test(const std::pair which, double &shift) { - try { - shift = this->calculate_shift( which ); - } - catch (const std::exception &e) { - shift = NAN; - logwrite("Flexure::Compensator::test", "ERROR: "+std::string(e.what())); - } - return NO_ERROR; - } - } diff --git a/flexured/flexure_compensator.h b/flexured/flexure_compensator.h index f00364b1..ee472a3d 100644 --- a/flexured/flexure_compensator.h +++ b/flexured/flexure_compensator.h @@ -54,18 +54,15 @@ namespace Flexure { std::map trigfunction; double flexure_polynomial_fit(const std::pair &which, double inputvar, size_t offset); - double calculate_shift(const std::pair &which); void compensate_shift_to_delta(const std::string &channel, - const std::pair &shift, std::pair delta); + const std::pair &shift, std::pair &delta); public: Compensator(TcsInfo &info); long load_vector_from_config(std::string &config, VectorType type); - + double calculate_shift(const std::pair &which); void calculate_compensation(const std::string &channel, std::pair &delta); - - long test(const std::pair which, double &shift); }; /***** Flexure::Compensator *************************************************/ diff --git a/flexured/flexure_interface.cpp b/flexured/flexure_interface.cpp index d589cf14..1ae256c6 100644 --- a/flexured/flexure_interface.cpp +++ b/flexured/flexure_interface.cpp @@ -782,6 +782,9 @@ namespace Flexure { retstring.clear(); retstring.append( " motormap return definition of motormap\n" ); retstring.append( " posmap return definition of posmap\n" ); + retstring.append( " shift calculate shift(chan,axis) of spectrum on detector\n" ); + retstring.append( " comp calculates adjustments needed to compensate for shift\n" ); + retstring.append( " tcsinfo [ ] overrides tcsinfo\n" ); return HELP; } else @@ -807,20 +810,18 @@ namespace Flexure { } else - if (testname == "calcshift") { + if (testname == "shift") { if (tokens.size() != 3) { logwrite(function, "ERROR expected "); return ERROR; } - double shift; - this->compensator.test({tokens[1], tokens[2]}, shift); - message.str(""); message << shift; + message.str(""); + message << this->compensator.calculate_shift({tokens[1], tokens[2]}); retstring = message.str(); - return NO_ERROR; } else - if (testname == "compensate") { + if (testname == "comp") { if (tokens.size() != 2) { logwrite(function, "ERROR expected "); return ERROR; @@ -829,13 +830,39 @@ namespace Flexure { try { std::pair delta; this->compensator.calculate_compensation(tokens[1], delta); + message.str(""); message << "delta X=" << delta.first << " Y=" << delta.second; + logwrite(function, message.str()); this->offset_tiptilt(tokens[1], delta, true); // true = dry run } catch (const std::exception &e) { logwrite(function, std::string(e.what())); return ERROR; } - return NO_ERROR; + } + else + + if (testname=="tcsinfo") { + if (tokens.size()>=4) { + try { + this->tcs_info.zenangle = std::stod(tokens[1]); + this->tcs_info.pa = std::stod(tokens[2]); + this->tcs_info.casangle = std::stod(tokens[3]); + if (tokens.size()==5) { + this->tcs_info.equivalent_cass = std::stod(tokens[4]); + } + else this->tcs_info.set(); + } + catch (const std::exception &e) { + logwrite(function, "ERROR: "+std::string(e.what())); + return ERROR; + } + } + message.str(""); + message << "zenangle = " << this->tcs_info.zenangle << "\n" + << "pa = " << this->tcs_info.pa << "\n" + << "casangle = " << this->tcs_info.casangle << "\n" + << "equivalent_cass = " << this->tcs_info.equivalent_cass << "\n"; + retstring=message.str(); } else { diff --git a/flexured/flexure_server.cpp b/flexured/flexure_server.cpp index f04451fd..d137f70a 100644 --- a/flexured/flexure_server.cpp +++ b/flexured/flexure_server.cpp @@ -629,7 +629,7 @@ namespace Flexure { // Don't append anything nor log the reply if the command was just requesting help. // if (ret != NOTHING) { - if ( ! retstring.empty() ) retstring.append( " " ); + if ( ! retstring.empty() && ret != HELP ) retstring.append( " " ); if ( ret != HELP && ret != JSON ) retstring.append( ret == NO_ERROR ? "DONE" : "ERROR" ); if ( ret == JSON ) { From c28b7db6255739649052e7dfc2b5e38a7b7c9b83 Mon Sep 17 00:00:00 2001 From: David Hale Date: Wed, 12 Nov 2025 12:48:17 -0800 Subject: [PATCH 17/19] cleans up tcs_info --- flexured/flexure_compensator.cpp | 21 +++++----- flexured/flexure_interface.cpp | 39 ++++++++++++------- flexured/tcs_info.h | 66 +++++++++++++++++++++++++++----- 3 files changed, 93 insertions(+), 33 deletions(-) diff --git a/flexured/flexure_compensator.cpp b/flexured/flexure_compensator.cpp index 6530478f..87dab529 100644 --- a/flexured/flexure_compensator.cpp +++ b/flexured/flexure_compensator.cpp @@ -153,22 +153,25 @@ namespace Flexure { */ double Compensator::calculate_shift(const std::pair &which) { const std::string function("Flexure::Compensator::calculate_shift"); + double zenangle = this->tcs_info.get_zenangle(); + double equivalentcass = this->tcs_info.get_equivalentcass(); + try { - double c = this->flexure_polynomial_fit(which, this->tcs_info.zenangle, 0); - double a1 = this->flexure_polynomial_fit(which, this->tcs_info.zenangle, 5); - double theta = this->flexure_polynomial_fit(which, this->tcs_info.zenangle, 10); - double a2 = this->flexure_polynomial_fit(which, this->tcs_info.zenangle, 15); + double c = this->flexure_polynomial_fit(which, zenangle, 0); + double a1 = this->flexure_polynomial_fit(which, zenangle, 5); + double theta = this->flexure_polynomial_fit(which, zenangle, 10); + double a2 = this->flexure_polynomial_fit(which, zenangle, 15); auto [ chan, axis ] = which; if (this->trigfunction[chan] == TrigFunction::Sine) { - return c + a1 * std::sin( (this->tcs_info.equivalent_cass * DEGTORAD - theta)) - + a2 * std::sin(2*(this->tcs_info.equivalent_cass * DEGTORAD - theta)); + return c + a1 * std::sin( (equivalentcass * DEGTORAD - theta)) + + a2 * std::sin(2*(equivalentcass * DEGTORAD - theta)); } else if (this->trigfunction[chan] == TrigFunction::Cosine) { - return c + a1 * std::cos( (this->tcs_info.equivalent_cass * DEGTORAD - theta)) - + a2 * std::cos(2*(this->tcs_info.equivalent_cass * DEGTORAD - theta)); + return c + a1 * std::cos( (equivalentcass * DEGTORAD - theta)) + + a2 * std::cos(2*(equivalentcass * DEGTORAD - theta)); } else { logwrite(function, "ERROR undefined trig function for channel "+chan); @@ -176,7 +179,7 @@ namespace Flexure { } } catch (const std::exception &e) { - logwrite("Flexure::Compensator::calculate_shift", "ERROR: "+std::string(e.what())); + logwrite(function, "ERROR: "+std::string(e.what())); throw; } } diff --git a/flexured/flexure_interface.cpp b/flexured/flexure_interface.cpp index 1ae256c6..ac19d9d2 100644 --- a/flexured/flexure_interface.cpp +++ b/flexured/flexure_interface.cpp @@ -79,10 +79,11 @@ namespace Flexure { this->tcs_snapshot_status = true; } // extract and store values in the class - Common::extract_telemetry_value(jmessage, "CASANGLE", this->tcs_info.casangle); - Common::extract_telemetry_value(jmessage, "ZENANGLE", this->tcs_info.zenangle); - Common::extract_telemetry_value(jmessage, "PA", this->tcs_info.pa); - this->tcs_info.set(); + double zenangle, casangle, pa; + Common::extract_telemetry_value(jmessage, "CASANGLE", casangle); + Common::extract_telemetry_value(jmessage, "ZENANGLE", zenangle); + Common::extract_telemetry_value(jmessage, "PA", pa); + this->tcs_info.store(zenangle, casangle, pa); } /***** Flexure::Interface::handletopic_tcsd *********************************/ @@ -90,7 +91,6 @@ namespace Flexure { /***** Flexure::Interface::publish_snapshot *********************************/ /** * @brief publishes a snapshot of my telemetry - * @details This loads the tcs_info class with values published by tcsd. * */ void Interface::publish_snapshot() { @@ -810,6 +810,9 @@ namespace Flexure { } else + // shift + // calculate shift of spectrum on detector + // if (testname == "shift") { if (tokens.size() != 3) { logwrite(function, "ERROR expected "); @@ -821,6 +824,9 @@ namespace Flexure { } else + // comp + // calculate adjustments needed to compensate for shift + // if (testname == "comp") { if (tokens.size() != 2) { logwrite(function, "ERROR expected "); @@ -841,16 +847,21 @@ namespace Flexure { } else + // tcsinfo [ [ ] ] + // get (no args) or optionally override tcsinfo, with equivcass optional + // if (testname=="tcsinfo") { if (tokens.size()>=4) { try { - this->tcs_info.zenangle = std::stod(tokens[1]); - this->tcs_info.pa = std::stod(tokens[2]); - this->tcs_info.casangle = std::stod(tokens[3]); + double zenangle = std::stod(tokens[1]); + double casangle = std::stod(tokens[2]); + double pa = std::stod(tokens[3]); + // equivalent cass is normally calculated but can be overridden if (tokens.size()==5) { - this->tcs_info.equivalent_cass = std::stod(tokens[4]); + double equivalentcass = std::stod(tokens[4]); + this->tcs_info.store(zenangle, casangle, pa, equivalentcass); } - else this->tcs_info.set(); + else this->tcs_info.store(zenangle, casangle, pa); } catch (const std::exception &e) { logwrite(function, "ERROR: "+std::string(e.what())); @@ -858,10 +869,10 @@ namespace Flexure { } } message.str(""); - message << "zenangle = " << this->tcs_info.zenangle << "\n" - << "pa = " << this->tcs_info.pa << "\n" - << "casangle = " << this->tcs_info.casangle << "\n" - << "equivalent_cass = " << this->tcs_info.equivalent_cass << "\n"; + message << "zenangle = " << this->tcs_info.get_zenangle() << "\n" + << "casangle = " << this->tcs_info.get_casangle() << "\n" + << "pa = " << this->tcs_info.get_pa() << "\n" + << "equivalent_cass = " << this->tcs_info.get_equivalentcass() << "\n"; retstring=message.str(); } diff --git a/flexured/tcs_info.h b/flexured/tcs_info.h index 88f6d5d9..f811d550 100644 --- a/flexured/tcs_info.h +++ b/flexured/tcs_info.h @@ -1,6 +1,14 @@ +/** --------------------------------------------------------------------------- + * @file tcs_info.h + * @brief defines a class in Flexure for holding TCS info + * @author David Hale + * + */ + #pragma once #include +#include namespace Flexure { @@ -11,18 +19,33 @@ namespace Flexure { */ class TcsInfo { private: + double zenangle; + double casangle; + double pa; + double equivalentcass; + bool is_timeset; std::chrono::system_clock::time_point telemetry_time; public: - double zenangle; - double equivalent_cass; - double pa; - double casangle; TcsInfo() - : is_timeset(false), zenangle(0), equivalent_cass(0), pa(0), casangle(0) { } + : zenangle(0), casangle(0), pa(0), equivalentcass(0), is_timeset(false) { } + + double get_zenangle() { return this->zenangle; } + double get_casangle() { return this->casangle; } + double get_pa() { return this->pa; } + double get_equivalentcass() { return this->equivalentcass; } + /***** Flexure::TcsInfo:is_older_than ***********************************/ + /** + * @brief is the TCS telemetry more than seconds old? + * @details When the telemetry is stored in this class it is time-stamped. + * This returns true if that time stamp is more than + * seconds ago from now. + * @param[in] sec number of seconds + * @return true|false + */ bool is_older_than(std::chrono::seconds sec) { if (!this->is_timeset) return true; if (std::chrono::system_clock::now() > this->telemetry_time+sec) { @@ -30,19 +53,42 @@ namespace Flexure { } return false; } + /***** Flexure::TcsInfo:is_older_than ***********************************/ - void set() { - double angle = this->pa + this->casangle; + /***** Flexure::TcsInfo:set *********************************************/ + /** + * @brief timestamp telemetry + * @details Call this function when + * This returns true if that time stamp is more than + * + */ + void store(const double &_zenangle, + const double &_casangle, + const double &_pa, + const std::optional &_equivalentcass=std::nullopt) { - if (angle < -180.0) angle += 360.0; - if (angle > 180.0) angle -= 360.0; + // store the values received + this->zenangle = _zenangle; + this->casangle = _casangle; + this->pa = _pa; - this->equivalent_cass = angle; + // if equivalentcass provided then use it + if (_equivalentcass) { + this->equivalentcass = *_equivalentcass; + } + // otherwise calculate it + else { + double angle = this->pa + this->casangle; + if (angle < -180.0) angle += 360.0; + if (angle > 180.0) angle -= 360.0; + this->equivalentcass = angle; + } // record the time that telemetry was received this->telemetry_time = std::chrono::system_clock::now(); this->is_timeset = true; } + /***** Flexure::TcsInfo:set *********************************************/ }; /***** Flexure::TcsInfo *****************************************************/ From 274c03f257fc16b01cbb9230d3741ef1ae7404f2 Mon Sep 17 00:00:00 2001 From: David Hale Date: Tue, 25 Nov 2025 18:34:13 -0800 Subject: [PATCH 18/19] fixes bug (sign error) and adds some test routines --- flexured/flexure_interface.cpp | 70 ++++++++++++++++++++++++++-------- flexured/tcs_info.h | 2 +- 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/flexured/flexure_interface.cpp b/flexured/flexure_interface.cpp index ac19d9d2..3caa68ac 100644 --- a/flexured/flexure_interface.cpp +++ b/flexured/flexure_interface.cpp @@ -784,7 +784,9 @@ namespace Flexure { retstring.append( " posmap return definition of posmap\n" ); retstring.append( " shift calculate shift(chan,axis) of spectrum on detector\n" ); retstring.append( " comp calculates adjustments needed to compensate for shift\n" ); - retstring.append( " tcsinfo [ ] overrides tcsinfo\n" ); + retstring.append( " tcsinfo print current tcsinfo\n" ); + retstring.append( " ishift calculate shift for \n" ); + retstring.append( " icomp calculate adjustments for \n" ); return HELP; } else @@ -847,33 +849,71 @@ namespace Flexure { } else - // tcsinfo [ [ ] ] - // get (no args) or optionally override tcsinfo, with equivcass optional + // get tcsinfo // if (testname=="tcsinfo") { - if (tokens.size()>=4) { + message.str(""); + message << "zenangle = " << this->tcs_info.get_zenangle() << "\n" + << "casangle = " << this->tcs_info.get_casangle() << "\n" + << "pa = " << this->tcs_info.get_pa() << "\n" + << "equivalent_cass = " << this->tcs_info.get_equivalentcass() << "\n"; + retstring=message.str(); + } + else + + // interactive shift + // calculate shift for specified tcsinfo + // + if (testname=="ishift") { + if (tokens.size()!=6) { + logwrite(function, "ERROR expected "); + return ERROR; + } try { double zenangle = std::stod(tokens[1]); double casangle = std::stod(tokens[2]); double pa = std::stod(tokens[3]); - // equivalent cass is normally calculated but can be overridden - if (tokens.size()==5) { - double equivalentcass = std::stod(tokens[4]); - this->tcs_info.store(zenangle, casangle, pa, equivalentcass); + { + std::lock_guard lock(snapshot_mutex); + this->tcs_info.store(zenangle, casangle, pa); + message.str(""); + message << this->compensator.calculate_shift({tokens[4], tokens[5]}); } - else this->tcs_info.store(zenangle, casangle, pa); + retstring=message.str(); } catch (const std::exception &e) { logwrite(function, "ERROR: "+std::string(e.what())); return ERROR; } + } + else + + // interactive comp + // calculate compensation adjustments for specified tcsinfo + // + if (testname=="icomp") { + if (tokens.size()!=5) { + logwrite(function, "ERROR expected "); + return ERROR; + } + try { + double zenangle = std::stod(tokens[1]); + double casangle = std::stod(tokens[2]); + double pa = std::stod(tokens[3]); + std::pair delta; + { + std::lock_guard lock(snapshot_mutex); + this->tcs_info.store(zenangle, casangle, pa); + this->compensator.calculate_compensation(tokens[4], delta); + message.str(""); message << "delta X=" << delta.first << " Y=" << delta.second; + } + retstring=message.str(); + this->offset_tiptilt(tokens[4], delta, true); // true = dry run + } + catch (const std::exception &e) { + logwrite(function, "ERROR: "+std::string(e.what())); + return ERROR; } - message.str(""); - message << "zenangle = " << this->tcs_info.get_zenangle() << "\n" - << "casangle = " << this->tcs_info.get_casangle() << "\n" - << "pa = " << this->tcs_info.get_pa() << "\n" - << "equivalent_cass = " << this->tcs_info.get_equivalentcass() << "\n"; - retstring=message.str(); } else { diff --git a/flexured/tcs_info.h b/flexured/tcs_info.h index f811d550..a0279e79 100644 --- a/flexured/tcs_info.h +++ b/flexured/tcs_info.h @@ -78,7 +78,7 @@ namespace Flexure { } // otherwise calculate it else { - double angle = this->pa + this->casangle; + double angle = this->casangle - this->pa; if (angle < -180.0) angle += 360.0; if (angle > 180.0) angle -= 360.0; this->equivalentcass = angle; From 279b3b752000f610ff3b0d4c904384f151450551 Mon Sep 17 00:00:00 2001 From: David Hale Date: Mon, 1 Dec 2025 16:56:06 -0800 Subject: [PATCH 19/19] fixes another sign error and applies correction to nominal position instead of current position. This should complete flexure. --- flexured/flexure_compensator.cpp | 2 ++ flexured/flexure_compensator.h | 6 +++++ flexured/flexure_interface.cpp | 41 +++++++++++++++++--------------- 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/flexured/flexure_compensator.cpp b/flexured/flexure_compensator.cpp index 87dab529..2db5c884 100644 --- a/flexured/flexure_compensator.cpp +++ b/flexured/flexure_compensator.cpp @@ -199,10 +199,12 @@ namespace Flexure { void Compensator::compensate_shift_to_delta(const std::string &channel, const std::pair &shift, std::pair &delta) { + // delta.first is delta-X = [0]*x + [1]*y + [2] delta.first = this->position_coefficients.at({channel,X})[0] * shift.first + this->position_coefficients.at({channel,X})[1] * shift.second + this->position_coefficients.at({channel,X})[2]; + // delta.second is delta-Y = [0]*x + [1]*y + [2] delta.second = this->position_coefficients.at({channel,Y})[0] * shift.first + this->position_coefficients.at({channel,Y})[1] * shift.second + this->position_coefficients.at({channel,Y})[2]; diff --git a/flexured/flexure_compensator.h b/flexured/flexure_compensator.h index ee472a3d..9a602ec8 100644 --- a/flexured/flexure_compensator.h +++ b/flexured/flexure_compensator.h @@ -16,6 +16,12 @@ namespace Flexure { constexpr double PI = 3.14159265358979323846; constexpr double DEGTORAD = PI/180.0; + // PI actuator axis numbers + // + constexpr int AXIS_Z = 1; ///< piston + constexpr int AXIS_X = 2; ///< spectral + constexpr int AXIS_Y = 3; ///< spatial + constexpr const char* X = "X"; constexpr const char* Y = "Y"; diff --git a/flexured/flexure_interface.cpp b/flexured/flexure_interface.cpp index 3caa68ac..845330c1 100644 --- a/flexured/flexure_interface.cpp +++ b/flexured/flexure_interface.cpp @@ -482,27 +482,29 @@ namespace Flexure { /***** Flexure::Interface::offset_tiptilt ***********************************/ /** * @brief offsets the X, Y axes for the specified channel by specified delta + * @details The compensation offsets (delta) must be calculated first, with + * a call to this->compensator.calculate_compensation() for a given + * channel. That returns a delta pair which this function adds to + * the nominal positions and then sends the modified position to the + * actuators. * @param[in] chan string channel - * @param[in] delta double pair { X, Y } of calculated offsets + * @param[in] delta double pair { X, Y } of calculated compensation offsets * @param[in] is_dryrun if true then no motion is commanded * @throws std::runtime_error * */ void Interface::offset_tiptilt(const std::string &chan, const std::pair &delta, bool is_dryrun) { - auto addr=this->motorinterface.get_motormap()[chan].addr; - float position_x=NAN, position_y=NAN; - std::string posname, retstring; - - // get the current positions - if ( this->motorinterface.get_pos( chan, 2, addr, position_x, posname ) != NO_ERROR || - this->motorinterface.get_pos( chan, 3, addr, position_y, posname ) != NO_ERROR ) { - throw std::runtime_error("reading positions for channel "+chan); - } + // nominal positions + auto motormap=this->motorinterface.get_motormap()[chan]; + float nominal_x=motormap.axes[AXIS_X].defpos; + float nominal_y=motormap.axes[AXIS_Y].defpos; - float newposition_x = position_x + delta.first; - float newposition_y = position_y + delta.second; + // new positions + float newposition_x = nominal_x + delta.first; + float newposition_y = nominal_y - delta.second; + // dryrun only logs what it would have done if ( is_dryrun ) { std::ostringstream oss; oss << "dry run: would move chan " << chan << " by " << delta.first << ", " << delta.second @@ -512,12 +514,13 @@ namespace Flexure { } // move X-axis - if (this->motorinterface.moveto( chan, 2, newposition_x, retstring ) != NO_ERROR) { + std::string retstring; + if (this->motorinterface.moveto( chan, AXIS_X, newposition_x, retstring ) != NO_ERROR) { throw std::runtime_error("moving X axis for channel "+chan); } // move Y-axis - if (this->motorinterface.moveto( chan, 3, newposition_y, retstring ) != NO_ERROR) { + if (this->motorinterface.moveto( chan, AXIS_Y, newposition_y, retstring ) != NO_ERROR) { throw std::runtime_error("moving Y axis for channel "+chan); } } @@ -612,9 +615,9 @@ namespace Flexure { std::string key; this->motorinterface.get_pos( chan, axis.second.axisnum, addr, position, posname ); switch ( axis.second.axisnum ) { - case 1 : key = "FLXPIS_" + chan; break; - case 2: key = "FLXSPE_" + chan; break; - case 3: key = "FLXSPA_" + chan; break; + case AXIS_Z : key = "FLXPIS_" + chan; break; + case AXIS_X: key = "FLXSPE_" + chan; break; + case AXIS_Y: key = "FLXSPA_" + chan; break; default: key = "error"; message.str(""); message << "ERROR unknown axis " << axis.second.axisnum; logwrite( function, message.str() ); @@ -767,7 +770,7 @@ namespace Flexure { std::vector tokens; long error = NO_ERROR; - auto _motormap = this->motorinterface.get_motormap(); + auto motormap = this->motorinterface.get_motormap(); Tokenize( args, tokens, " " ); @@ -795,7 +798,7 @@ namespace Flexure { // if ( testname == "motormap" ) { retstring="name host:port addr naxes \n axisnum min max reftype defpos"; - for ( const auto &mot : _motormap ) { + for ( const auto &mot : motormap ) { retstring.append("\n"); message.str(""); message << mot.first << " " << mot.second.host << ":"