//
// 25-Mar-2010 SDS - First Version
//
block SpireBb_StopMcuData SPIRE 3420 {
}{
    SpireProc_Set_StopMcuData();
    sync();
}

//
// Dump entire DPU memory
// 19/05/2010: SDS First Version 
//
//
block SpireBb_DumpMemory SPIRE 3424 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_DumpMemory started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    //
    // Dump used PM
    //
    Spire_DUMP_MEMORY_RAW(0,0x0,0x100);
    delay(4);
    Spire_DUMP_MEMORY_RAW(0,0x100,0x3f00);
    delay(10);
    //
    Spire_DUMP_MEMORY_RAW(0,0x4000,0x2000);
    delay(10);
    Spire_DUMP_MEMORY_RAW(0,0x6000,0xffff);
    delay(45);
    Spire_DUMP_MEMORY_RAW(0,0x15fff,0x59);
    delay(2);
    //
    // Report the PM checksums as well
    //
    Spire_CHECK_MEMORY_RAW(0,0x4000,0x174b);
    delay(2);
    Spire_CHECK_MEMORY_RAW(0,0x6000,0xffff);
    delay(2);
    Spire_CHECK_MEMORY_RAW(0,0x15fff,0x59);
    delay(2);
    //
    // Dump unused Program Memory
    //
    Spire_DUMP_MEMORY_RAW(0,0x16058,0x9fa8);
    delay(30);
    //
    Spire_DUMP_MEMORY_RAW(0,0x20000,0x8000);
    delay(20);
    //
    Spire_DUMP_MEMORY_RAW(0,0x28000,0x8000);
    delay(20);
    //
    Spire_DUMP_MEMORY_RAW(0,0x30000,0x8000);
    delay(20);
    //
    Spire_DUMP_MEMORY_RAW(0,0x38000,0x8000);
    delay(20);
    //
    Spire_DUMP_MEMORY_RAW(0,0x40000,0x8000);
    delay(20);
    //
    Spire_DUMP_MEMORY_RAW(0,0x48000,0x8000);
    delay(20);
    //
    Spire_DUMP_MEMORY_RAW(0,0x50000,0x8000);
    delay(20);
    //
    Spire_DUMP_MEMORY_RAW(0,0x58000,0x8000);
    delay(20);
    //
    Spire_DUMP_MEMORY_RAW(0,0x60000,0x8000);
    delay(20);
    //
    Spire_DUMP_MEMORY_RAW(0,0x68000,0x8000);
    delay(20);
    //
    Spire_DUMP_MEMORY_RAW(0,0x70000,0x8000);
    delay(20);
    //
    Spire_DUMP_MEMORY_RAW(0,0x78000,0x8000);
    delay(20);
    //
    //
    // Dump Data Memory
    //
    Spire_DUMP_MEMORY_RAW(1,0x0,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(1,0x8000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(1,0x10000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(1,0x18000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(1,0x20000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(1,0x28000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(1,0x30000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(1,0x38000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(1,0x40000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(1,0x48000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(1,0x50000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(1,0x58000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(1,0x60000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(1,0x68000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(1,0x70000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(1,0x78000,0x8000);
    delay(15);
    //
    // Dump the EEPROM
    //
    Spire_DUMP_MEMORY_RAW(2,0x0,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(2,0x8000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(2,0x10000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(2,0x18000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(2,0x20000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(2,0x28000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(2,0x30000,0x8000);
    delay(15);
    //
    Spire_DUMP_MEMORY_RAW(2,0x38000,0x8000);
    delay(15);
    //
    //
    //
    //
    //
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_DumpMemory ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

// SpireBb_CalPdetOn
//
// $id$
//
// This building block switches on the photometer detectors for calibration observations
// 
// The instrument should be in the REDY mode before execution of this building block
//
// 07/01/2010 S.D.Sidher V0.1: 
//         Adapted from SpireBbPdetOn (does not set the mode)
//
//
block SpireBb_CalPdetOn SPIRE 3413 {
    int jfet_heater_V = 0; // By default don't switch on jfet heater 
    string detVersion = "v00";
    string vssVersion = "v00";
    bool debug = false;
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB CalPdetOn started");
    SpireMsg(2,"          $Id$");
    //
    int cmd = 0x0;
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP to 0
    SpireSetObsStep(0x0);
    //
    // Retrieve bias settings
    //
    int biasmode = ilookup("SpireTable_DefaultParams.txt","v00","biasMode");
    int mclkdiv = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","mclkDiv",detVersion,debug);
    int biasdiv = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","biasDiv",detVersion,debug);
    //
    // Retrive array nominal settings for PHTSTBY mode
    //
    int psw_bias = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","pswBias",detVersion,debug);
    int psw_phase = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","pswPhase",detVersion,debug);
    int pmw_bias = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","pmwBias",detVersion,debug);
    int pmw_phase = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","pmwPhase",detVersion,debug);
    int plw_bias = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","plwBias",detVersion,debug);
    int plw_phase = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","plwPhase",detVersion,debug);
    int ptc_bias = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","ptcBias",detVersion,debug);
    int ptc_phase = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","ptcPhase",detVersion,debug);
    //
    // ---
    // Building block starts
    // ---
    SpireSetObsStep(0x1);
    delay(1);
    //
    // Switch ON PLIAs
    //
    SpireSendDrcuCmd(0xa0870005,0);
    delay(1);
    //
    // Set bias mode ,bias frequency and sampling frequency
    //
    SpireSendDrcuCmd(0x84000000 + biasmode,0);
    SpireSendDrcuCmd(0x84190000 + mclkdiv,0);
    delay(1);
    SpireSendDrcuCmd(0x84180000 + biasdiv,0);
    //
    // Switch on with small bias (~ 1 mVrms) across the arrays
    //
    SpireSendDrcuCmd(0x84010002,0);
    delay(1);
    SpireSendDrcuCmd(0x84020002,0);
    SpireSendDrcuCmd(0x84030002,0);
    delay(1);
    SpireSendDrcuCmd(0x84040002,0);
    //
    // Set demodulation phase shift
    //
    SpireSendDrcuCmd(0x841a0000 + psw_phase,0);
    delay(1);
    SpireSendDrcuCmd(0x841b0000 + pmw_phase,0);
    SpireSendDrcuCmd(0x841c0000 + plw_phase,0);
    delay(1);
    SpireSendDrcuCmd(0x841d0000 + ptc_phase,0);
    delay(1);
    //
    // Automatic offset setting + get offsets
    //
    SpireSendDrcuCmd(0x843c0010,0);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(2);
    SpireSendDrcuCmd(0x843e0000,0);
    SpireSendDrcuCmd(0x843c0018,0);
    delay(1);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(3);
    SpireSendDrcuCmd(0x843e0000,0);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(1);
    //
    // Start PF data generation
    //
    SpireSendDrcuCmd(0x843c0000,0);
    SpireSendDrcuCmd(0x843d0000,0);
    delay(1);
    SpireSendDrcuCmd(0x843e0001,0);
    //
    // If necessary switch ON jfet heater
    if(jfet_heater_V != 0) {
        SpireSendDrcuCmd(0x84110000 + jfet_heater_V,0);
        delay(60);
        SpireSendDrcuCmd(0x84110000,0);
    } else {
        delay(3);
    }
    //
    // Apply Startup Vss voltages
    //
    // Read the startup Vss settings 
    // 
    //PSW
    int psw_jfet_Vss1 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","psw_vss1",vssVersion,debug);
    int psw_jfet_Vss2 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","psw_vss2",vssVersion,debug);
    int psw_jfet_Vss3 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","psw_vss3",vssVersion,debug);
    int psw_jfet_Vss4 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","psw_vss4",vssVersion,debug);
    int psw_jfet_Vss5 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","psw_vss5",vssVersion,debug);
    int psw_jfet_Vss6 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","psw_vss6",vssVersion,debug);
    // PMW
    int pmw_jfet_Vss1 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","pmw_vss1",vssVersion,debug);
    int pmw_jfet_Vss2 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","pmw_vss2",vssVersion,debug);
    int pmw_jfet_Vss3 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","pmw_vss3",vssVersion,debug);
    int pmw_jfet_Vss4 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","pmw_vss4",vssVersion,debug);
    //PLW
    int plw_jfet_Vss1 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","plw_vss1",vssVersion,debug);
    int plw_jfet_Vss2 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","plw_vss2",vssVersion,debug);
    // PTC
    int ptc_jfet_Vss = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","ptc_vss1",vssVersion,debug);
    //
    //  Apply PSW Vss voltages followed by PSW Vdd
    //
    // PSW JFET1 
    SpireSendDrcuCmd(0x84050000 + psw_jfet_Vss1,0);
    SpireSendDrcuCmd(0x84120001,0);
    delay(1);
    // PSW JFET2	
    SpireSendDrcuCmd(0x84060000 + psw_jfet_Vss2,0);
    SpireSendDrcuCmd(0x84120003,0);
    delay(1);
    // PSW JFET3	
    SpireSendDrcuCmd(0x84070000 + psw_jfet_Vss3,0);
    SpireSendDrcuCmd(0x84120007,0);
    delay(1);
    // PSW JFET4	
    SpireSendDrcuCmd(0x84080000 + psw_jfet_Vss4,0);
    SpireSendDrcuCmd(0x8412000f,0);
    delay(1);
    // PSW JFET5	
    SpireSendDrcuCmd(0x84090000 + psw_jfet_Vss5,0);
    SpireSendDrcuCmd(0x8412001f,0);
    delay(1);
    // PSW JFET6	
    SpireSendDrcuCmd(0x840a0000 + psw_jfet_Vss6,0);
    SpireSendDrcuCmd(0x8412003f,0);
    delay(1);
    //
    // Apply PMW Vss voltages followed by PMW Vdd
    //
    // PMW JFET1
    SpireSendDrcuCmd(0x840b0000 + pmw_jfet_Vss1,0);
    SpireSendDrcuCmd(0x84130001,0);
    delay(1);
    // PMW JFET2
    SpireSendDrcuCmd(0x840c0000 + pmw_jfet_Vss2,0);
    SpireSendDrcuCmd(0x84130003,0);
    delay(1);
    // PMW JFET3
    SpireSendDrcuCmd(0x840d0000 + pmw_jfet_Vss3,0);
    SpireSendDrcuCmd(0x84130007,0);
    delay(1);
    // PMW JFET4	
    SpireSendDrcuCmd(0x840e0000 + pmw_jfet_Vss4,0);
    SpireSendDrcuCmd(0x8413000f,0);
    delay(1);
    //
    // Apply PLW Vss voltages followed by PLW Vdd
    //
    // PLW JFET1
    SpireSendDrcuCmd(0x840f0000 + plw_jfet_Vss1,0);
    SpireSendDrcuCmd(0x8413001f,0);
    // PLW JFET2
    SpireSendDrcuCmd(0x84100000 + plw_jfet_Vss2,0);
    SpireSendDrcuCmd(0x8413003f,0);
    delay(1);
    //
    // Apply TC Vss voltage followed by Vdd
    //
    SpireSendDrcuCmd(0x84140000 + ptc_jfet_Vss,0);
    SpireSendDrcuCmd(0x8413007f,0);
    //
    // Wait 30 seconds before setting nominal biases 
    //
    delay(30);
    SpireSendDrcuCmd(0x84010000 + psw_bias,0);
    delay(1);
    SpireSendDrcuCmd(0x84020000 + pmw_bias,0);
    delay(1);
    SpireSendDrcuCmd(0x84030000 + plw_bias,0);
    delay(1);
    SpireSendDrcuCmd(0x84040000 + ptc_bias,0);
    delay(1);
    //
    // Stop DCU data, apply automatic offset setting + get offsets
    // 
    SpireSendDrcuCmd(0x843e0000,0);
    delay(1);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(3);
    SpireSendDrcuCmd(0x843c0010,0);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(2);
    SpireSendDrcuCmd(0x843e0000,0);
    SpireSendDrcuCmd(0x843c0018,0);
    delay(1);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(3);
    SpireSendDrcuCmd(0x843e0000,0);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(1);
    //
    // Start PF data generation
    //
    SpireSendDrcuCmd(0x843c0000,0);
    SpireSendDrcuCmd(0x843d0000,0);
    delay(1);
    SpireSendDrcuCmd(0x843e0001,0);
    //
    // Wait 30 seconds before setting the optimum Vss values
    //
    delay(30);
    //
    // Read the optimum Vss settings (lowest noise)
    // 
    //PSW
    int psw_jfet_OVss1 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","psw_vss1",vssVersion,debug);
    int psw_jfet_OVss2 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","psw_vss2",vssVersion,debug);
    int psw_jfet_OVss3 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","psw_vss3",vssVersion,debug);
    int psw_jfet_OVss4 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","psw_vss4",vssVersion,debug);
    int psw_jfet_OVss5 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","psw_vss5",vssVersion,debug);
    int psw_jfet_OVss6 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","psw_vss6",vssVersion,debug);
    //
    // PMW
    int pmw_jfet_OVss1 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","pmw_vss1",vssVersion,debug);
    int pmw_jfet_OVss2 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","pmw_vss2",vssVersion,debug);
    int pmw_jfet_OVss3 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","pmw_vss3",vssVersion,debug);
    int pmw_jfet_OVss4 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","pmw_vss4",vssVersion,debug);
    //
    // PLW
    int plw_jfet_OVss1 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","plw_vss1",vssVersion,debug);
    int plw_jfet_OVss2 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","plw_vss2",vssVersion,debug);
    //
    // PTC
    int ptc_jfet_OVss = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","ptc_vss1",vssVersion,debug);
    // 
    // Now set the optimum Vss values for all the JFETs
    //
    // PSW JFET1 
    SpireSendDrcuCmd(0x84050000 + psw_jfet_OVss1,0);
    // PSW JFET2
    SpireSendDrcuCmd(0x84060000 + psw_jfet_OVss2,0);
    delay(1);
    // PSW JFET3	
    SpireSendDrcuCmd(0x84070000 + psw_jfet_OVss3,0);
    // PSW JFET4	
    SpireSendDrcuCmd(0x84080000 + psw_jfet_OVss4,0);
    delay(1);
    // PSW JFET5	
    SpireSendDrcuCmd(0x84090000 + psw_jfet_OVss5,0);
    // PSW JFET6	
    SpireSendDrcuCmd(0x840a0000 + psw_jfet_OVss6,0);
    delay(1);
    // PMW JFET1
    SpireSendDrcuCmd(0x840b0000 + pmw_jfet_OVss1,0);
    // PMW JFET2
    SpireSendDrcuCmd(0x840c0000 + pmw_jfet_OVss2,0);
    delay(1);
    // PMW JFET3
    SpireSendDrcuCmd(0x840d0000 + pmw_jfet_OVss3,0);
    // PMW JFET4	
    SpireSendDrcuCmd(0x840e0000 + pmw_jfet_OVss4,0);
    delay(1);
    // PLW JFET1
    SpireSendDrcuCmd(0x840f0000 + plw_jfet_OVss1,0);
    // PLW JFET2
    SpireSendDrcuCmd(0x84100000 + plw_jfet_OVss2,0);
    delay(1);
    // PTC JFET Vss
    SpireSendDrcuCmd(0x84140000 + ptc_jfet_OVss,0);
    //
    //
    delay(10);
    // stop data collection
    SpireSendDrcuCmd(0x843e0000,0);
    //
    // flush data from FIFOs
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(1);
    delay(3);
    //
    SpireSetObsStep(0x0);
    sync();
    //
    // completion
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB CalPdetOn   ended");
    SpireMsg(1,"  ..CalPdetOn (" + (time() - t0) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_McuFramerate.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to translate user input in Hz for MCU framrates into nearest 
//  commanded values  
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/31 V0.1: Initial version adapted from
//                  SpireProc_CalcParam_BsmFramerate (2009/02/15 V0.1)
//
///////////////////////////////////////////////////////////////////////////
int procedure SpireProc_CalcParam_McuFramerate {
    double frateHz = 0.0; // Input MCU (==BSM,SMEC) framerate [Hz]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Convert from Hz to RAW values:
    //
    int frateInt = iround(1000000.0 / (frateHz * 420.0));
    // //
    // //
    // Debug printout:
    //
    if(debug) {
        debug_print("Input Hz value for MCU(==BSM,SMEC) framerate: " + frateHz);
        debug_print("Output Dec(Hex) values for MCU(==BSM,SMEC) framerate: " + frateInt);
    }
    // //
    // //
    // Return required values:
    //

    return frateInt;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_Bsm.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to set BSM parameters
//
///////////////////////////////////////////////////////////////////////////
//
// K. King:
// 2009/11/09 V1.0: First version 
// S.D.Sidher
// 2010/02/03 V1.1: Typo in script corrected. The Jigg FF offset was being set to the Jigg FF gain
// 2010/03/04 V1.2: Now also setting CHOPINTLIMIT and CHOPINTREF
// 2010/03/25 V1.3: Removed the setting of CHOPINTLIMIT and CHOPINTREF
// 
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_Bsm {
    int chopFfOffset = 0;
    int chopFfGain = 0;
    int chopKp = 1000; // Chop Kp
    int chopKi = 536; // Chop Ki
    int chopKd = 3504; // Chop Kd
    int jiggFfOffset = 0;
    int jiggFfGain = 0;
    int jiggKp = 1000; // Jiggle Kp
    int jiggKi = 536; // Jiggle Ki
    int jiggKd = 3504; // Jiggle Kd
    int cjCouple = 0; // ChopJiggleCouple
    int cjdCouple = 0;
    int sampFreq = 10; // BSM sampling frequency
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // 
    // Define some variables:
    //
    string hstr = "";
    // a hex string
    string tstr = "";
    // a time string
    // //
    // //
    // Start procedure:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(3,"    " + tstr + ": SpireProc_Set_Bsm started");
    SpireMsg(3,"          $Id: $");
    // //
    // //
    // Set parameters:
    //
    // Set Chop FF Offset parameter:
    SpireSendDrcuCmd(0x90c70000 + chopFfOffset,0);
    //
    // Set Chop FF Gain parameter:
    SpireSendDrcuCmd(0x90cd0000 + chopFfGain,0);
    delay(1);
    //
    // Set Chop Kp parameter:
    SpireSendDrcuCmd(0x90c80000 + chopKp,0);
    //
    // Set Chop Ki parameter:
    SpireSendDrcuCmd(0x90ca0000 + chopKi,0);
    delay(1);
    //
    // Set Chop Kd parameter:
    SpireSendDrcuCmd(0x90c90000 + chopKd,0);
    //
    // Set Jiggle FF Offset parameter:
    SpireSendDrcuCmd(0x91470000 + jiggFfOffset,0);
    delay(1);
    //
    // Set Jiggle FF Gain parameter:
    SpireSendDrcuCmd(0x914d0000 + jiggFfGain,0);
    delay(1);
    //
    // Set JiggleKp parameter:
    SpireSendDrcuCmd(0x91480000 + jiggKp,0);
    //
    // Set Jiggle Ki parameter:
    SpireSendDrcuCmd(0x914a0000 + jiggKi,0);
    delay(1);
    //
    // Set Jiggle Kd parameter:
    SpireSendDrcuCmd(0x91490000 + jiggKd,0);
    //
    // Set ChopJiggleCoupling  parameters:
    SpireSendDrcuCmd(0x90d90000 + cjCouple,0);
    SpireSendDrcuCmd(0x90da0000 + cjdCouple,0);
    //
    // Set Sampling Frequency:
    SpireSendDrcuCmd(0x91c20000 + sampFreq,0);
    //
    // set BSM sampled parameters
    SpireSendDrcuCmd(0x91cd0102,0);
    // sample CHOPPOSNERR
    SpireSendDrcuCmd(0x91d00182,0);
    // sample JIGGPOSNERR
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(3,"    " + tstr + ": SpireProc_Set_Bsm ended");
    //
}

// SpireEngBsmTuneFf
//
// $id$
//
// This observation allows tuning of the BSM CHOPFFGAIN and CHOPFFOFFSET for 7-point Jiggle Map, keeping all other parameters fixed, including CHOPKP. 
// 
// The instrument should be in REDY mode before execution of this observation
// Final Configuration: Instrument is still in REDY mode after execution of this observation
//
//
// 01/02/2010 SDS: First Version 1.0 
//
// 04/03/2010 SDS: V1.1
//                            Inserted default CHOPINTLIMIT and CHOPINTREF values in calls to SpireBb_SetBsm
// 25/03/2010 SDS: V1.2
//                            Removed the setting of CHOPINTLIMIT and CHOPINTREF
//
//
//
obs SpireEngBsmTuneFf {
    int chopFfOffsetNom = 0x929f;
    double chopFfOffsetLow = 0.93606; // starting value of CHOPFFOFFSET as a fraction of the nominal value
    double chopFfOffsetHigh = 1.06394; // end value of CHOPFFOFFSET as a fraction of the nominal value
    double chopFfOffsetStep = 0.021313; // increment in value of CHOPFFOFFSET as a fraction of the nominal value
    int chopFfGainNom = 0x8fc; // nominal value of CHOPFFGAIN
    double chopFfGainLow = 0.843478; // starting value of CHOPFFGAIN as a fraction of the nominal value
    double chopFfGainHigh = 1.156522; // end value of CHOPFFGAIN as a fraction of the nominal value
    double chopFfGainStep = 0.052174; // increment in value of CHOPFFGAIN as a fraction of the nominal value
    int chopKpNom = 0;
    int chopKiNom = 0;
    int chopKdNom = 0xdec;
    int jiggFfOffsetNom = 0x9946;
    int jiggFfGainNom = 0x17d8; // nominal value of JIGGFFGAIN
    int jiggKpNom = 1500;
    int jiggKiNom = 500;
    int jiggKdNom = 0x1b58; // nominal value of JIGGKD
    int cjCoupleNom = 0x8211; // nominal value of CHOPJIGGCOUPLE
    int cjdCoupleNom = 0x8000;
    int jcCoupleNom = 0x8000;
    int chopOn7 = 0xb5ac;
    int chopOff7 = 0x6b90;
    int jigglePosn7 = 0x9a19;
    int nChopCycles = 10;
    int chopPeriod = 500000;
    int dcuMode = 0;
    int dcuSample = 1;
    int dcuDelay = 34959;
    int bsmSample = 0x50;
    int sampFreq = 10;
    string bsmModel = "initial";
    string bsmVersion = "v00";
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // variables
    int chopFfOffset = 0;
    int chopFfGain = 0;
    double g = 0.0;
    double d = 0.0;
    int s = 0;
    int t = duration(SpireBbStartObs()) + duration(SpireBbSetNhkSampling("PHTSTBY","v00",debug)) + duration(SpireBbBsmOn("PHTSTBY",bsmModel,bsmVersion,debug)) + duration(SpireBbBsmChopInit("PHTSTBY",bsmModel,bsmVersion,debug)) + duration(SpireBbBsmJiggInit("PHTSTBY",bsmModel,bsmVersion,debug)) + duration(SpireBbBsmOff()) + duration(SpireBbSetDetSampling("REDY",true,"v00",false,debug)) + duration(SpireBbSetBsmSampling("REDY","v00",debug)) + duration(SpireBb_ResetBsm(debug)) + duration(SpireBbSetNhkSampling("REDY","v00",debug)) + duration(SpireBbEndObs());
    g = chopFfGainLow;
    d = chopFfOffsetLow;
    while(g <= chopFfGainHigh) {
        d = chopFfOffsetLow;
        while(d <= chopFfOffsetHigh) {
            t = t + duration(SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,chopKiNom,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug));
            t = t + duration(SpireBb_Chop(71,0,10,chopOn7,jigglePosn7,chopOff7,jigglePosn7,nChopCycles,chopPeriod,dcuMode,dcuSample,dcuDelay,bsmSample,0,debug));
            t = t + duration(SpireBb_StopDcuMcuData());
            d = d + chopFfOffsetStep;
        }
        g = g + chopFfGainStep;
    }
    int[] ts = no_pointing(true,0,0,t);
}{
    int step = 0x0;
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            mois_comment("Procedure SpireEngBsmTuneFf: to tune the BSM Chop Feed Forward Settings");
            mois_comment("Procedure starts and ends in SPIRE REDY mode");
            mois_comment("The OBSID needs to be set manually in the first TC");
            mois_tmcheck("Verify that the OBSID has been set correctly");
            mois_comment("No other manual TM checks or intervention is necessary");
            mois_comment("Rest of commands in procedure can be executed automatically");
            SpireBbStartObs();
            // set nominal housekeeping rate to PHTSTBY
            SpireBbSetNhkSampling("PHTSTBY","v00",debug);
            // // 
            // switch on BMS in nominal configuration
            SpireBbBsmOn("PHTSTBY",bsmModel,bsmVersion,debug);
            SpireBbBsmChopInit("PHTSTBY",bsmModel,bsmVersion,debug);
            SpireBbBsmJiggInit("PHTSTBY",bsmModel,bsmVersion,debug);
            chopFfOffset = chopFfOffsetNom;
            chopFfGain = chopFfGainNom;
            step = 0x0;
            g = chopFfGainLow;
            d = chopFfOffsetLow;
            s = 0;
            while(g <= chopFfGainHigh) {
                chopFfGain = ifloor(g * double(chopFfGainNom));
                step = step + 0x40;
                s = step;
                d = chopFfOffsetLow;
                while(d <= chopFfOffsetHigh) {
                    chopFfOffset = ifloor(d * double(chopFfOffsetNom));
                    s = s + 0x1;
                    SpireBb_SetBsm(chopFfOffset,chopFfGain,chopKpNom,chopKiNom,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
                    SpireBb_Chop(71,0,10,chopOn7,jigglePosn7,chopOff7,jigglePosn7,nChopCycles,chopPeriod,dcuMode,dcuSample,dcuDelay,bsmSample,s,debug);
                    SpireBb_StopDcuMcuData();
                    d = d + chopFfOffsetStep;
                }
                g = g + chopFfGainStep;
            }
            // switch off BSM
            SpireBbBsmOff();
            // Set the DCU detector sampling for REDY mode
            SpireBbSetDetSampling("REDY",true,"v00",false,debug);
            // Set the BSM sampling for REDY mode (i.e. Off)
            SpireBbSetBsmSampling("REDY","v00",debug);
            // Reset BSM frame parameters back to their default values
            SpireBb_ResetBsm(debug);
            // set nominal housekeeping rate to REDY mode
            SpireBbSetNhkSampling("REDY","v00",debug);
            // // 
            SpireBbEndObs();
        }
    }
}

// SpireBbPOF2End
//
// $Id:$
//
// Building Block to reconfigure the instrument to PHOT_STBY mode from POF2 (7-point jiggle) mode
//
//  26 Jan 2008: KK removed resetting of OBSID and BBISD as they are now 
//               done in SpireBb_EndObsAll
//  14 Feb 2009: MP peplace calls to SpireProc_Set_PhotPhase/Bias with 
//               call to SpireProc_Set_PhotBright
//  02/07/2009  KJK:
//         - Replaced version input parameter with photVersion and comVersion
//         - Replaced call to Proc_SetPhotBRight with Proc_SetPhotMode to reset the 
//            detectors if bright setting has been used
//  10/08/2009 KJK:
//         SPR-1709:  Updated to execute SpireProc_Set_PhotMode if photversion is not "V00"
//                           Updated to always use photVersion and comVersion = "v00" for all calls - to reset the detectors
//  17/08/2009 KJK:
//         SPR-1823: Added command to reset MCU Frame Number to default value
//  25-Aug-2009 KJK:
//        SPR Spire-1641: Now read BSM HOLD positions from SpireTable_BsmNominalSettings.txt rather than BSM.txt
//                                 Needed new input parameters bsmModel and bsmVersion
//  10/09/2009 KJK:
//        SCR Spire-1943: call SPireProcSetDetSampling  and SpireProcSetBsmSampling to reset sampling that may have changed
//
block SpireBbPOF2End SPIRE 8226 {
    string obsMode = "PHTSTBY";
    bool isBright = false in [true,false];
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string detVersion = "v00";
    string photVersion = "v00";
    string comVersion = "v00";
    bool debug = false in [true,false];
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF2 Reconfiguration started");
    SpireMsg(2,"          $Id:$");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP to zero
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x0000)");
    Spire_SET_OBS_STEP_RAW(0x0);
    //
    // reset BSM
    //
    // Move BSM to HOLD
    int bsmHoldChopPosn = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",bsmModel,"chop_0_I",bsmVersion,debug);
    int bsmHoldJiggPosn = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",bsmModel,"jigg_0_I",bsmVersion,debug);
    SpireBsmMove(bsmHoldChopPosn,bsmHoldJiggPosn);
    //
    // Reset BSM sampling
    double bsmDataRate = SpireProcSetBsmSampling(obsMode,bsmVersion,debug);
    //
    //
    // reset Detectors
    //
    // reset bright-source biases and phases - if needed
    if(isBright) {
        SpireProc_Set_PhotMode(obsMode,isBright,"v00","v00",debug);
    } else {
        if(photVersion != "v00") {
            SpireProc_Set_PhotMode(obsMode,isBright,"v00","v00",debug);
        }
    }
    //
    //  Reset detector sampling
    double dcuDataRate = SpireProcSetDetSampling(obsMode,true,detVersion,false,debug);
    //
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF2 Reconfiguration ended");
    SpireMsg(1,"  ..POF2 Reconfiguration  (" + (time() - t) + " seconds)");
}

//
// $id$
//
// This observation allows tuning of the BSM Chop parameters.
//
// The instrument should be in REDY mode before execution of this observation
// Final Configuration: Instrument is still in REDY mode after execution of this observation
//
//
// 24/03/2010 SDS: First Version 1.0
//                       For each set of parameters perform a 7-Point Jiggle Map. Also visit the four corners of the SM16 jiigle table
//
// 20/04/2010 SDS: V1.1
//                       SPIRE-SCR-2519: Changed calls to SpireBbJiggle to use v04 row from the SpireTable_ChopParams.txt table (1 DCU sample per chop position)
//                       Removed references to SM16 table as now not using BSMMove VM
//
//
obs SpireEngBsmTuneChopSettings {
    int chopFfOffsetNom = 0x8f86; // Nominal CHOPFFOFFSET = 36742 determined from SpireEngBsmTuneFf (11th Feb 2010, OD274)
    int chopFfGainNom = 0x92e; // Nominal CHOPFFGAIN = 2350 determined from SpireEngBsmTuneFf (11th Feb 2010, OD274)
    int chopKpNom = 0x64; // 100
    int chopKiNom = 0x64; //// 100
    int chopKdNom = 0x10b6; // 4278
    int jiggFfOffsetNom = 0x9946;
    int jiggFfGainNom = 0x17d8; // 
    int jiggKpNom = 1500;
    int jiggKiNom = 500;
    int jiggKdNom = 0x1b58; // 
    int cjCoupleNom = 0x8211; // 
    int cjdCoupleNom = 0x8000;
    int jcCoupleNom = 0x8000;
    int sampFreq = 10;
    string bsmModel = "initial";
    string bsmVersion = "v00";
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0x0; //Spare parameter (currently not in use)
    int pInt2 = 0x0; // Spare parameter (currently not in use)
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // //
    // //
    // Read BSM hold position from calibration table:  
    //
    string tabName = "SpireTable_BsmNominalSettings.txt";
    string version = bsmVersion;
    string selCol = "model";
    string selVal = bsmModel;
    string tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    //
    int s = 0;
    int t = duration(SpireBbStartObs()) + duration(SpireBbSetNhkSampling("PHTSTBY","v00",debug)) + duration(SpireBbBsmOn("PHTSTBY",bsmModel,bsmVersion,debug)) + duration(SpireBbBsmChopInit("PHTSTBY",bsmModel,bsmVersion,debug)) + duration(SpireBbBsmJiggInit("PHTSTBY",bsmModel,bsmVersion,debug)) + duration(SpireBbBsmOff()) + duration(SpireBbSetDetSampling("REDY",true,"v00",false,debug)) + duration(SpireBbSetBsmSampling("REDY","v00",debug)) + duration(SpireBb_ResetBsm(debug)) + duration(SpireBbSetNhkSampling("REDY","v00",debug)) + duration(SpireBbEndObs());
    // Calculate duration for all the 7-point Jiggle Maps
    int tset = duration(SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,chopKiNom,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug));
    t = t + 34 * tset;
    //
    int tjiggle = duration(SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false));
    t = t + 34 * tjiggle;
    int tSOF2Jiggle = duration(SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug));
    t = t + 34 * tSOF2Jiggle;
    //
    int[] ts = no_pointing(true,0,0,t);
}{
    int step = 0x0;
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            mois_comment("Procedure SpireEngBsmTuneChopSettings: to tune the BSM Chop parameter settings");
            mois_comment("Procedure starts and ends in SPIRE REDY mode");
            mois_comment("The OBSID needs to be set manually in the first TC");
            mois_tmcheck("Verify that the OBSID has been set correctly");
            mois_comment("No other manual TM checks or intervention is necessary");
            mois_comment("Rest of commands in procedure can be executed automatically");
            SpireBbStartObs();
            // set nominal housekeeping rate to PHTSTBY
            SpireBbSetNhkSampling("PHTSTBY","v00",debug);
            // //
            // switch on BMS in nominal configuration
            SpireBbBsmOn("PHTSTBY",bsmModel,bsmVersion,debug);
            SpireBbBsmChopInit("PHTSTBY",bsmModel,bsmVersion,debug);
            SpireBbBsmJiggInit("PHTSTBY",bsmModel,bsmVersion,debug);
            //
            // Start by doing a 7-Point JM with all nominal settings, except Kp=0 (same as in last tuning test done on OD313)
            //
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,0,chopKiNom,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            // Next do a 7-Point JM with all the nominal settings
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,chopKiNom,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Kd=7000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,chopKiNom,7000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Kd=8000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,chopKiNom,8000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Kd=9000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,chopKiNom,9000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Ki=0
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,0,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Ki=0 and Kd=7000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,0,7000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Ki=0 and Kd=8000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,0,8000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Ki=0 and Kd=9000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,0,9000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Kp=400 and Ki=0
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,400,0,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Kp=400 and Ki=0 and Kd=7000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,400,0,7000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Kp=400 and Ki=0 and Kd=8000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,400,0,8000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Kp=400 and Ki=0 and Kd=9000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,400,0,9000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Kp=Ki=0
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,0,0,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Kp=Ki=0 and Kd=7000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,0,0,7000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            // 
            //
            // Next do a 7-Point JM with all the nominal settings, except Kp=Ki=0 and Kd=8000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,0,0,8000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Kp=Ki=0 and Kd=9000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,0,0,9000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            //
            // Reduce FF Gain to 1900 and repeat above sequence
            //
            chopFfGainNom = 0x76c;
            //
            //
            // Start by doing a 7-Point JM with all nominal settings, except Kp=0 (same as in last tuning test done on OD313)
            //
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,0,chopKiNom,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            //
            //
            // Next do a 7-Point JM with all the nominal settings
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,chopKiNom,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Kd=7000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,chopKiNom,7000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Kd=8000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,chopKiNom,8000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            // Move the BSM to hold position 
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Kd=9000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,chopKiNom,9000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Ki=200
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,200,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Ki=200 and Kd=7000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,200,7000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Ki=200 and Kd=8000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,200,8000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Ki=200 and Kd=9000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,200,9000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Ki=50
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,50,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Ki=50 and Kd=7000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,50,7000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Ki=50 and Kd=8000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,50,8000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Ki=50 and Kd=9000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,50,9000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Ki=300
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,300,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Ki=300 and Kd=7000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,300,7000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Ki=300 and Kd=8000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,300,8000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            // Next do a 7-Point JM with all the nominal settings, except Ki=300 and Kd=9000
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,300,9000,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,1,0,"v00","v04",false);
            //
            //
            // Now move the BSM to each of the full SOF2 spectral map positions 
            //
            SpireProc_SOF2Jiggle(hold_chop,hold_jigg,debug);
            //
            //
            //
            //
            // switch off BSM
            //
            //
            SpireBbBsmOff();
            // Set the DCU detector sampling for REDY mode
            SpireBbSetDetSampling("REDY",true,"v00",false,debug);
            // Set the BSM sampling for REDY mode (i.e. Off)
            SpireBbSetBsmSampling("REDY","v00",debug);
            // Reset BSM frame parameters back to their default values
            SpireBb_ResetBsm(debug);
            // set nominal housekeeping rate to REDY mode
            SpireBbSetNhkSampling("REDY","v00",debug);
            // //
            SpireBbEndObs();
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_Cal_PointJiggleId55.txt
//
///////////////////////////////////////////////////////////////////////////
//
// The high level script for the Spire Photometer Point Source observing 
// mode using a 7-pnt jiggle map with changable jiggle configurations
//
///////////////////////////////////////////////////////////////////////////
//
// Michael Pohlen:
// 2009/09/17 V1.0: Version renamed from 
//                  SpirePhotoPointJiggle (10-Sep-2009 KJK)
//                  making the necessary Id55 changes
//
///////////////////////////////////////////////////////////////////////////
{int,int,int,int} obs SpirePhoto_Cal_PointJiggleId55 {
    double ra = 0.0 in [0.0,360.0]; // RA of Target
    double dec = 0.0 in [-90.0,90.0]; // Dec of Target
    int naifid = 0; // NAIF identifier
    string source = "point" in ["point","small","large"]; // source type
    bool choppingAvoidOn = false; // is chopping avoidance selected
    int choppingAvoidNumber = 0 in [0,3]; // the number of chopping avoid angles selected
    double choppingAvoidFrom1 = 0.0 in [0.0,360.0];
    double choppingAvoidTo1 = 0.0 in [0.0,360.0];
    double choppingAvoidFrom2 = 0.0 in [0.0,360.0];
    double choppingAvoidTo2 = 0.0 in [0.0,360.0];
    double choppingAvoidFrom3 = 0.0 in [0.0,360.0];
    double choppingAvoidTo3 = 0.0 in [0.0,360.0];
    int nRepetitions = 1 in [1,600]; // number of repeats of basic observing cycle 
    double sourceFluxPSW = -1.0;
    double sourceFluxPMW = -1.0;
    double sourceFluxPLW = -1.0;
    bool isBright = false; // Use settings for bright source (==tick)
    bool isJiggleMap = true;
    int itableID = 0x37; // VM table ID with jig.pos. to be uploaded 
    string idVersion = "v01"; // Version in calibration file with jig.pos. 
    int nCycles = 1; // total number of nod cycles to perform
    int nNodInts = 1; // number of times to repeat NJigg jiggles at each nod position 
    int nCal = 999999; // number of nod cycles per Gyro calibration 
    int nFlash = 999999; // number of nod cycles per PCAL flash
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string detVersion = "v00"; // Version in cal table SpireTable_DefaultParams.txt
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParams
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    string flashVersion = "v00"; // Version in cal table SpireTable_FlashParms
    string chopVersion = "v00"; // Version in cal table SpireTable_ChopParams
    string photVersion = "v00"; // Version in cal table SpireTable_PhotModeParams.txt
    string comVersion = "v00"; // Version in cal table SpireTable_CommonModeParams.txt
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Load 7-Point Jiggle Map Table?
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // *****************
    // check user inputs
    // *****************
    if(source != "point") {
        error("SpirePhotoPointJiggle: Source is not a point");
    }
    //
    // *****************
    // set constants
    // *****************
    string obsMode = "POF2";
    bool isPhot = true;
    // is a photometer observation
    double yOffset = 0.0;
    //  offset to observation position from target in Y direction (arcsecs)
    double zOffset = 0.0;
    // offset to observation position from target in Z direction (arcsecs)
    //   
    // *****************************************
    //      set up telescope pointing mode    
    // *****************************************
    //
    // *****  operating mode parameters *****
    // instrument boresight
    string ib = SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode",obsMode,"Boresight",opsVersion,debug);
    // offset to pixel centre from boresight in Y direction (arcsecs)
    double deltaY = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"DeltaY",opsVersion,debug);
    // offset to pixel centre from boresight in Z direction (arcsecs)
    double deltaZ = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"DeltaZ",opsVersion,debug);
    // pattern angle definition
    bool fixed = SpireProc_GetTableEntryBool("SpireTable_OpsParms.txt","mode",obsMode,"Fixed",opsVersion,debug);
    // direction of nod
    double pattNod = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"Patt",opsVersion,debug);
    double chopThrow = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"D1",opsVersion,debug);
    //
    // Jiggle Table ID read from input:
    int jiggleTable = itableID;
    // 
    // Jiggle Table ID
    //int jiggleTable = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"TableId",opsVersion,debug);
    // Jiggle Table length
    int jiggleSize = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"TableSize",opsVersion,debug);
    // number of chop cycles per jiggle position
    int nChops = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NChops",opsVersion,debug);
    // number of jiggle positions per nod position
    int nJiggs = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NJiggs",opsVersion,debug);
    // number of nod positions in a nod cycle
    int nNodPosns = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NNodPosns",opsVersion,debug);
    // initial flash flag
    bool initFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"InitFlash",spireVersion,debug);
    // final flash flag
    bool endFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"EndFlash",spireVersion,debug);
    // effective on source integration time per nod cycle
    double cycTime = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"SrcTime",opsVersion,debug);
    //
    // ***** pointing mode timing parameters *****
    {int,int,int,int,int,int} pof2Point = SpirePOF2Pointing(nCycles,nNodInts,nCal,nFlash,isBright,bsmModel,bsmVersion,detVersion,spireVersion,opsVersion,flashVersion,chopVersion,photVersion,comVersion,debug,pBool1);
    int tSlewMin = pof2Point{0};
    int tInitHold = pof2Point{1} + duration(SpireProc_Set_VmTable(itableID,idVersion));
    int tFinalHold = pof2Point{2};
    int tp = pof2Point{3};
    int tHold = pof2Point{4};
    int nHold = pof2Point{5};
    //
    // ***** fetch timing information *****
    int tFlash = duration(SpireBbPcalFlash("PFlash",flashVersion,0,debug));
    // time for a PCAL flash
    int tSerendipity = duration(SpireBbPhotSerendipity(obsMode,0));
    // minimum time for a serendipity observation
    //
    //
    // ****** execute telescope pointing mode ******
    //
    int[] ts = nodding_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,fixed,pattNod,yOffset + deltaY,zOffset + deltaZ,nCycles * nNodPosns / 2,chopThrow,tp,tp,0,0,tHold,nHold,false);
    //
}{
    // *****************************************
    //   Display input parameters
    // *****************************************
    SpireMsg(3,"     Using MODE " + obsMode);
    SpireMsg(3,"     Input values:");
    SpireMsg(3,"     ..RA: " + ra);
    SpireMsg(3,"     ..Dec: " + dec);
    SpireMsg(3,"     ..NAIF ID: " + naifid);
    SpireMsg(3,"     ..Y Offset: " + yOffset);
    SpireMsg(3,"     ..Z Offset: " + zOffset);
    SpireMsg(3,"     ..No of Nod Cycles: " + nCycles);
    SpireMsg(3,"     ..No of Ints per Nod Posn: " + nNodInts);
    // SpireMsg(3,"     ..No of  Nod Cycles between Gyro Calibrations: " + nCal);
    SpireMsg(3,"     ..No of  Nod Cycles between Flashes: " + nFlash);
    SpireMsg(3,"     POF2 Fixed values:");
    SpireMsg(3,"     ..ib: " + ib);
    SpireMsg(3,"     ..deltaY: " + deltaY);
    SpireMsg(3,"     ..deltaZ: " + deltaZ);
    SpireMsg(3,"     ..fixed: " + fixed);
    SpireMsg(3,"     ..pattNod: " + pattNod);
    SpireMsg(3,"     ..chopThrow: " + chopThrow);
    SpireMsg(3,"     ..jiggleTable: " + jiggleTable);
    SpireMsg(3,"     ..jiggleSize: " + jiggleSize);
    SpireMsg(3,"     ..nChops: " + nChops);
    SpireMsg(3,"     ..nJiggs: " + nJiggs);
    SpireMsg(3,"     ..nNods: " + nNodPosns);
    SpireMsg(3,"     ..initFlash: " + initFlash);
    SpireMsg(3,"     ..endFlash: " + endFlash);
    SpireMsg(3,"    Composite Nodding Pointing Mode Input values:");
    SpireMsg(3,"    ..tSlewMin: " + tSlewMin);
    SpireMsg(3,"    ..tInitHold: " + tInitHold);
    SpireMsg(3,"    ..tFInalHold: " + tFinalHold);
    SpireMsg(3,"    ..tp: " + tp);
    SpireMsg(3,"    ..tHold: " + tHold);
    SpireMsg(3,"    ..nHold: " + nHold);
    SpireMsg(3,"    Composite Nodding Pointing Mode Output values:");
    SpireMsg(3,"    ..tobs: " + ts[0]);
    SpireMsg(3,"    ..tslew: " + ts[1]);
    SpireMsg(3,"    ..tnod: " + ts[2]);
    SpireMsg(3,"    ..tss: " + ts[3]);
    SpireMsg(3,"    ..tload: " + ts[4]);
    SpireMsg(3,"    ..tend: " + ts[5]);
    // *****************************************
    //   execute observation
    // *****************************************
    SpireMsg(0,"Observation Start");
    SpireMsg(0,"  Uses observing mode POF2 (7-pnt Jiggle Map)");
    SpireMsg(3,"       $Id:$");
    data_rate(0.0);
    double chkrate = dlookup("Datarates.txt",obsMode,"CHK");
    ess_hk_data_rate(chkrate);
    double nhkrate = dlookup("Datarates.txt",obsMode,"NHK");
    non_ess_hk_data_rate(nhkrate);
    //
    //??p pointing file generation ------------------------------
    double pos = 90.0;
    //??p double[] rdp0 = PtOffset([ra,dec,pos],zOffset,yOffset,0.0,false);
    //??p pointing file generation ------------------------------
    //
    int tslew = ts[1];
    // slew time
    string tstr = "";
    // time string
    bool holdFlag = false;
    // true when holding at nod position
    int otf = 0x8000;
    // On Target Flag
    int nf = 0x4000;
    // Nod Flag
    int step = 0x0;
    // value of STEP parameter
    double srcTime = 0.0;
    //  total on source integration time
    int np = 0;
    // pointing counter
    double s = 0.0;
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // ***********************  SLEWING
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Slewing to start position");
            // set up observation parameters
            SpireBb_StartObsAll(obsMode);
            // perform serendipity operation if possible
            if(tslew > tSerendipity + tSlewMin) {
                SpireBbPhotSerendipity(obsMode,tslew - tSlewMin - 2);
            }
            // configure instrument for operations
            if(pBool1) {
                SpireBb_LoadTableJM07b();
            }
            SpireBbPOF2Config(obsMode,isBright,photVersion,comVersion,debug);
        }
        if(state[0] == 2) {
            // ***********************  INITIAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Initialising Instrument");
            // initialise instrument
            SpireBbPOF2Init();
            // calibrate if necessary
            if(initFlash || nFlash < nCycles) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireBbPcalFlash("PFlash",flashVersion,otf,debug);
            }
            // // 
            // // 
            // Add upload of new VM table:
            //
            SpireBb_SetVmTable(itableID,idVersion);
        }
        if(state[0] == 5) {
            // ***********************  FINAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Reconfiguring Instrument");
            // calibrate if necessary
            if(endFlash || nFlash < nCycles) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireBbPcalFlash("PFlash",flashVersion,otf | np,debug);
            }
            // reconfigure back to PHOT_STBY configuration
            SpireBbPOF2End("PHTSTBY",isBright,bsmModel,bsmVersion,detVersion,photVersion,comVersion,debug);
            SpireBb_EndObsAll(isPhot);
        }
        if(state[0] == 6) {
            // ***********************  HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
            SpireBbPcalFlash("PFlash",flashVersion,otf,debug);
        }
        if(state[0] == 3) {
            // ***********************  POINTING
            //??p pointing file generation ------------------------------
            //??p PtOutput(rdp0);
            //??p pointing file generation ------------------------------
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Instrument at Pointing Position");
            SpireMsg(2,"    " + tstr + " Start Jiggles " + np);
            step = otf;
            s = SpireBbJiggle("POF2",jiggleTable,0,nJiggs,nNodInts,step,opsVersion,chopVersion,debug);
            srcTime = srcTime + s;
            np = np + 1;
            step = 0;
            SpireBbMove(step);
        }
        if(state[0] == 7) {
            // ***********************  NOD
            //??p pointing file generation ------------------------------
            //??p PtNod(rdp0,patt,d1,patt,false,false);
            //??p pointing file generation ------------------------------
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Instrument at Nod Position");
            SpireMsg(2,"    " + tstr + " Start Jiggles " + np);
            step = nf | otf;
            s = SpireBbJiggle("POF2",jiggleTable,0,nJiggs,nNodInts,step,opsVersion,chopVersion,debug);
            srcTime = srcTime + s;
            np = np + 1;
            step = 0;
            SpireBbMove(step);
        }
        if(state[0] == 9) {
            // ***********************  LOAD
        }
    }
    assert (time() == ts[0] + ts[1]);
    //
    // finish observation
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + " Instrument Reconfigured");
    //
    //
    SpireMsg(0,"Observation Completed  (" + time() + " seconds)");
    SpireMsg(0,"Note: Total time (s) = Observation Completed time - slew time + Observatory Overheads");

    return {nCycles,iround(cycTime),iround(srcTime),time() - iround(srcTime) - tslew};
}

// SpireBbSOF1Init
//
// $id:$
//
// Building Block to initialise the instrument for SOF1 operation
//
// The complete instrument setup operation is divided into two parts:
//   Configuration: actions that can be executed during the slew to the start
//          position of the S/C pointing mode.
//   Initialisation: actions that must be carried out at the S/C intial pointing
//          position before any observational operations are executed.   
//
// This building Block implements the second part of the setup 
// 
// 04 November 2008: 
//         added data_rate commands
//         added commands to setup the detector sampling
// 14/09/2009 KJK:
//         SCR Spire-1953: updated to take smodeVersion as input parameter
//                                   uses this to set phases
//  24/09/2009 KJK: SPR Spire-1978
//         remove setting of phases, as these are already setup in Config
//  29/09/2099 MP: SPR-SPIRE-2048
//         Script need to take isBright as input to pass mode on. 
// 
/////////////////////////////////////////////////////////////////////////////
block SpireBbSOF1Init SPIRE 8369 {
    string smodeVersion = "v00";
    bool isBright = false;
    bool debug = false;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SOF1 Initialisation started");
    SpireMsg(2,"          $Id:$");
    //
    // ..... configuration .....
    //
    int cmd = 0x0;
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP  to On Target
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x8000)");
    Spire_SET_OBS_STEP_RAW(0x8000);
    //
    // set detector offsets
    // set DCU data mode  to Auto Offset 
    cmd = 0x843c0014;
    SpireSendDrcuCmd(cmd,0);
    // start auto offset generation
    cmd = 0x843e0001;
    SpireSendDrcuCmd(cmd,0);
    delay(15);
    //
    // dump detector offsets
    // stop auto offset generation
    cmd = 0x843e0000;
    SpireSendDrcuCmd(cmd,0);
    // set DCU data mode to get offset data
    cmd = 0x843c001c;
    SpireSendDrcuCmd(cmd,0);
    // start offset data dump
    cmd = 0x843e0001;
    SpireSendDrcuCmd(cmd,0);
    //  set datarate
    double rate = 0.0;
    rate = dlookup("Datarates.txt","SOffsets","DCU");
    data_rate(rate);
    delay(5);
    // stop offset data dump 
    cmd = 0x843e0000;
    SpireSendDrcuCmd(cmd,0);
    data_rate(0.0);
    //
    // flush data
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(2);
    //
    //  set up detectors for operations
    //
    if(isBright) {
        SpireConfigDcuData("Scan_b");
    } else {
        SpireConfigDcuData("Scan");
    }
    sync();
    //
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SOF1 Initialisation ended");
    SpireMsg(1,"  ..SOF1 Initialisation (" + (time() - t) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_CalGCO_ScannedSmecBeamProfile.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Spec Scanned SMEC Beam Profile'
//
//         in *custom_map_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/11/06 V0.1: Initial version adapted from
//                  SpireSpectro_CalGCO_FixedSmecBeamProfile (2008/11/03 V0.2)
// 2008/11/12 V0.2: Implement mode setting; Add isBright 
// 2009/03/30 V0.3: Add debug_print as input abd pass to low level scripts. 
//                  Set default gcp_time to 20 (desired value for SOVT2). 
//                  Use new SpireBb_EndObsAll and SpireBb_StartObsAll. Read 
//                  nominal bias frequency and bias dividerfrom new
//                  SpireTable_SpecModeParams. Implemented setting of
//                  datarates. Implemented isBright setting. Change call to 
//                  SpireBb_StartDcuData. Use SpireBb_SpecSetMode to set 
//                  to SPECSTBY during SLEW and FINAL_HOLD. Set first obsstep 
//                  to 1. Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Add additional resolution
//                  setting 'C' (see SCR-1114). Added header line.
// 2009/03/31 V0.4: Move order of SpireBb_SmecMove and SpireBb_SetupSmecScan.
//                  Add new SpireBb_SmecHold to account for the fact that
//                  SpireBb_SmecMove does not stop SMEC (desired inside script
//                  but not at the very end). Added start/stop of DCU+MCU data.
//                  Added setting of MCU framerates as input and reset to 
//                  default values at end.   
// 2009/09/15 V0.5: Add in move BSM/SMEC to hold/home at start. Add new 
//                  SpireBb_SmecHold to account for the fact that
//                  SpireBb_SmecMove2Home does not stop SMEC.
//                  Gather procedures at start and end in separate BBs:
//                  SpireBb_Start/EndScannedSmecBeamProfile. 
// 2009/09/17 V0.6: Allow # of raster points to be input parameters. Allow
//                  added cross as input.  
// 2009/10/28 V1.0: (SPR-SPIRE-2062) Close/open SMEC loop at start/end. Change
//                  call to SpireBb_StartScannedSmecBeamProfile.
//                  (SCR-SPIRE-2118) Allow SSO. Hardcode gcp_period for SSOs. 
// 2009/11/16 V1.1: (SPR-SPIRE-2157) Change default aperture.
//
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in SPECSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for all three arrays and could be taken from following cal table: 
//   SpireTable_SpecModeParams.txt
//
//  3) That currently the gyro reconstruction is only available for 
//     non-SSO targets.  
//
//  4) SMEC scan parameters can be read from calibration table:
//     SpireTable_Spectrometer.txt
// 
//  5) SMEC move parameters can be read from calibration table:
//     SpireTable_SpecSmecNominalSettings.txt
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_CalGCO_ScannedSmecBeamProfile {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; //NAIF identifier: put '0' to use RA/DEC, or correct 'NAIFID'
    bool isBright = false; // Use settings for bright source (==tick)
    /* */
    double raoff = 0.0 in [0.0,360.0]; // RA of GCP position
    double decoff = 0.0 in [-90.0,90.0]; // DEC of GCP position 
    string ib = "S24_0"; // Central aperture (defined in SIAM) of raster
    int m = 11; // Number of points in raster along Y [odd number!]
    int n = 11; // Number of points in raster along Z [odd number!]
    bool cross = false; // Add interlaced cross or use a simple mxn raster? 
    double d1 = 2.0; // Angular stepsize between raster pts [arcsec]
    string resolution = "M" in ["L","M","H","C"]; // Resolution (low, medium, high,calibration)
    int nscans = 1; // Number of SMEC scans (back+forth==1)
    int gcp_time = 20; // Time spend at GCP (gyro calibration position) [s]
    int gcp_period = 600; // Maximum time between successiv GCP visits (Note, set to 64800 for SSOs!) [s]
    double bsmFrateInput = 15.98; // Specifies the BSM framerate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    double smecFrateInput = 238.08; // Specifies the SMEC framerate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParam
    string version03 = "v00"; // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial"; // Model in cal table SpireTable_BsmNominalSettings 
    string version05 = "v00"; // Version in cal table SpireTable_Spectrometer
    string version06 = "v00"; // Version in cal table SpireTable_SmecNominalSettings
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Current restrictions:
    //
    if(naifid != 0) {
        message("Note, currently no SSO objects are allowed if gyro reconstruction is needed. Using SSO tracking the visists to the OFF position are minimised by setting gcp_period to 18h.");
        gcp_period = 64800;
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = false;
    bool fts = !phot;
    //
    // Start timing of script:
    int start = time();
    //
    // First obsstep (start at 1):
    int obsstep = 1;
    //
    // Count raster points (needs to start at 0): 
    int raster_counter = 0;
    //
    // GCP counter (start at 1):
    int gcpcounter = 1;
    //
    // DCU data mode (0 == Full photometer; 4 == Full spectrometer)
    int dcumode = 4;
    //
    // Angular stepsize along Z axis [arcsec]:
    double d2 = d1;
    // NOTE: Script works only for equidistant raster points in both axes:
    //
    bool setFramerate = true;
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    string tabName05 = "SpireTable_Spectrometer.txt";
    string tabName06 = "SpireTable_SmecNominalSettings.txt";
    //
    // Currently hardcoded parameter:
    // Is (==tick) the DCU currently sampled? 
    bool dcuData = false;
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS35";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "SEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Read SMEC home position from calibration file:
    //
    tarCol = "Home";
    tabName = tabName06;
    selVal = version06;
    int smecHomePosn = ilookup(tabName,selVal,tarCol);
    // //
    // //
    // Retrieve SMEC scanStart parameters from calibration table: 
    // 
    tarCol = "ScanStart";
    selVal = "ResChar";
    tabName = tabName05;
    version = version05;
    int scanStart = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt",selVal,resolution,tarCol,version,debug);
    // //
    // //
    // Retrieve BSM SPECSTBY framerate from calibration table: 
    // 
    version = version02;
    tabName = tabName02;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "bsmFrameRate";
    int bsmFrameRate = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    double bsmFrameRateHz = 0.0;
    if(bsmFrameRate != 0) {
        bsmFrameRateHz = 1000000.0 / (double(bsmFrameRate) * 420.0);
    }
    //
    // Compare nominal with input BSM framerate:
    // 
    int frate = SpireProc_CalcParam_BsmFramerate(bsmFrateInput,debug);
    if(debug) {
        debug_print("frate = " + frate);
        debug_print("bsmFrameRate = " + bsmFrameRate);
    }
    if(frate == bsmFrameRate) {
        if(debug) {
            debug_print("Do not set the BSM framerate during slew.");
        }
        setFramerate = false;
    }
    // //
    // //
    // Setup parameters for BSM chopping movement: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version03;
    tabName = tabName03;
    // Name of column for selecting: 
    selCol = "model";
    // Value of 'string' selector:
    selVal = model;
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Retrieve SMEC SPECSTBY framerate from calibration table: 
    // 
    version = version01;
    tabName = tabName01;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "smecFrameRate";
    int smecFrameRate = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    double smecFrameRateHz = 0.0;
    if(smecFrameRate != 0) {
        smecFrameRateHz = 1000000.0 / (double(smecFrameRate) * 420.0);
    }
    if(debug) {
        debug_print("Nominal SMEC sampling rate is: " + smecFrameRateHz + " [Hz]");
    }
    // //
    // //
    // Calculate commanded framerates for SMEC+BSM from user input: 
    int bsmFrate = SpireProc_CalcParam_McuFramerate(bsmFrateInput,debug);
    int smecFrate = SpireProc_CalcParam_McuFramerate(smecFrateInput,debug);
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    // 
    int tslewmin = duration(SpireBb_StartScannedSmecBeamProfile(obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,setFramerate,frate,smecFrate,debug));
    // 
    // BBs carried out when the pointing is reached:
    //
    int tinithold = duration(SpireBbSmecInit(resolution,version03,version06,version05,debug)) + duration(SpireBb_SetSmecFramerate(smecFrate,debug)) + duration(SpireBb_SmecMove(scanStart,smecHomePosn,debug)) + duration(SpireBb_SetupSmecScan(resolution,version05,debug));
    //
    // BB carried out during pointing:
    // 
    int tp_np = duration(SpireBb_SmecScan(resolution,nscans,version05,debug)) + duration(SpireBb_SpecOffsetAuto(dcuData,debug)) + duration(SpireBb_SetObsStep(9999,debug)) + duration(SpireBb_StartDcuMcuData()) + duration(SpireBb_StopDcuMcuData());
    //
    // Activities at normal raster point:
    int tp_gp = gcp_time;
    // Note, this means 'just wait at GCP' 
    //
    if(gcp_time > tp_np) {
        // Scan at GCP + extra delay: 
        int extra_delay = gcp_time - tp_np;
    }
    // BB carried out at the end:
    //
    int tfinalhold = duration(SpireBb_EndScannedSmecBeamProfile(resolution,hold_chop,hold_jigg,smecHomePosn,isBright,version01,version02,version05,debug));
    // //
    // //
    // Debug printing:
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing normal= " + tp_np);
        debug_print("tpointing @GCP= " + tp_gp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                              */
    // ****************************************************** */
    // //
    // //
    // Fixed parameters for pointing mode:
    //   
    bool fixed = false;
    // Pattern orientation (true==sky; false==array)
    double patt = 90.0;
    // Rotation angle of the pattern
    double yoffset = 0.0;
    // Offset of pattern in the direction of the +Y
    double zoffset = 0.0;
    // Offset of pattern in the direction of the +Z
    int thold = 0;
    // The duration of the hold when nhold>0.
    int nhold = 0;
    // Number of nods or raster points or scan lines before
    //              // performing a hold.
    double pattnod = 0.0;
    //
    double chopthrow = 2.0;
    //
    int nnod = 1;
    //
    int knod = 0;
    //
    int nload = 0;
    //
    int tloadmin = 0;
    //
    // //
    // //
    // Calculate array of points:
    //
    {double[],double[]} array = SpireProc_CalcParam_RasterCross(m,n,d1,d2,cross,debug);
    double[] zarray_org = array{0};
    double[] yarray_org = array{1};
    int numpixel = length(yarray_org);
    int nump_org = length(yarray_org);
    // //
    // //
    // Add GCP visit after every raster point (except first which is GCP)
    // and create tp (duration of fine pointing) vector new raster:
    //
    double[] yarray = [0.0];
    double[] zarray = [0.0];
    int run = 1;
    int aindex = 1;
    int fin = length(yarray_org);
    yarray[0] = yarray_org[0];
    zarray[0] = zarray_org[0];
    bool gcpp = false;
    int[] tpv = [0];
    // First GCP visit is normal raster position (assuming gcp_time<tp_np)
    tpv[0] = tp_np;
    do {
        if(gcpp) {
            yarray[aindex] = yarray_org[0];
            zarray[aindex] = zarray_org[0];
            tpv[aindex] = tp_gp;
            gcpp = false;
        } else {
            yarray[aindex] = yarray_org[run];
            zarray[aindex] = zarray_org[run];
            tpv[aindex] = tp_np;
            run = run + 1;
            gcpp = true;
        }
        aindex = aindex + 1;
    } while (run < fin);
    // Add GCP visit at end:
    yarray[aindex] = yarray_org[0];
    zarray[aindex] = zarray_org[0];
    tpv[aindex] = tp_gp;
    //
    // //
    // //
    if(debug) {
        debug_print("timing vector : " + tpv);
        debug_print("zarray_org: " + zarray_org);
        debug_print("zarray: " + zarray);
    }
    //
    // Calculate slew times in pointing mode:
    //
    int[] ts_tr = custom_map_pointing(false,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,fixed,patt,yoffset,zoffset,yarray,zarray,tpv,pattnod,chopthrow,nnod,knod,tloadmin,nload,thold,nhold);
    //
    if(debug) {
        debug_print("Pointing vector : " + ts_tr);
    }
    // //
    // //
    // Determine maximal slew to GCP:
    //
    int nump = length(yarray);
    int nslews = nump;
    int nlslews = numpixel;
    int tpp = ts_tr[7];
    int[] tslews = [0];
    tslews[0] = 0;
    for(int j = 1 .. nslews - 1) {
        if(debug) {
            debug_print("entry: " + (j + 6));
        }
        tslews[j] = ts_tr[j + 6];
    }
    //
    int maxslew = 0;
    for(int k = 0 .. length(tslews) - 1) {
        maxslew = iceil(max(double(maxslew),double(tslews[k])));
    }
    if(debug) {
        debug_print("nlslews: " + nlslews);
        debug_print("nslews: " + nslews);
        debug_print("tslews: " + tslews);
        debug_print("maxslew: " + maxslew);
    }
    // //
    // //
    // Determine slew time between small raster points:
    //
    int tppn = tslews[1];
    // == slew beteen first and second raster point
    // //
    // //
    // Decrease frequency of GCP visits until gcp_period matched
    //
    //   
    int kgcp = 1;
    int ktime = 0;
    int ktime_old = 0;
    int nslew = 0;
    do {
        ktime_old = ktime;
        //
        // Count number of slews between the mxn rasters: 
        if(2 * kgcp + 1 > (nslew + 1) * m * n) {
            nslew = nslew + 1;
            if(debug) {
                debug_print("nslew: " + nslew);
            }
        }
        //
        // Calculate approximate(!) time between off visits :
        // [Problem: slews are not 100% predictable with single dummy run]
        //
        ktime = tp_gp + kgcp * tp_np + (kgcp - nslew) * tppn + nslew * maxslew + 2 * maxslew;
        // 
        // Add safety time:
        // [to account for possible longer slews than in dummy run] 
        ktime = ktime + 0;
        int kdiff = ktime - ktime_old;
        //
        // Print out error if gcp_period < ktime for first case 
        // (== having a GCP after each point):
        if(kgcp == 1) {
            if(gcp_period < ktime) {
                if(debug) {
                    debug_print("gcp_period < ktime: " + gcp_period + " < " + ktime);
                }
                error("gcp_period smaller than expected times between GCP visits! Change input parameters!");
            }
        }
        // 
        if(debug) {
            debug_print("tpv[0]: " + tpv[0]);
            debug_print("tp_np: " + tp_np);
            debug_print("tp_gp: " + tp_gp);
            debug_print("tppn: " + tppn);
            debug_print("maxslew: " + maxslew);
            debug_print("nslew: " + nslew);
            debug_print("ktime-ktime_old: " + kdiff);
            debug_print("ktime loop kgcp/ktime: " + kgcp + "/" + ktime);
        }
        //
        //
        // Increment kgcp (i.e delay visit to GCP by one more raster point): 
        if(debug) {
            debug_print("increment kgcp by 1");
        }
        kgcp = kgcp + 1;
        if(debug) {
            debug_print("new kgcp: " + kgcp);
        }
        //
    } while (ktime < gcp_period);
    //
    // Select last kgcp for which condition was fulfilled:
    int kgcp_old = 1;
    if(kgcp > 2) {
        kgcp_old = kgcp - 2;
    }
    message("Return to GCP after every " + kgcp_old + " normal raster point(s)!");
    //
    if(debug) {
        debug_print("values after kgcp selection loop:");
        debug_print("nump: " + nump);
        debug_print("nslews: " + nslews);
        debug_print("tslews: " + tslews);
        debug_print("maxslew: " + maxslew);
        debug_print("ktime loop end: " + ktime);
        debug_print("kgcp loop end:" + kgcp);
        debug_print("ktime_old: " + ktime_old);
        debug_print("kgcp_old:" + kgcp_old);
    }
    // //
    // //
    // Add visits to the GCP tp raster array:
    //
    int counter = 0;
    double[] yarray_new = [0.0];
    double[] zarray_new = [0.0];
    double ygcp = yarray[0];
    double zgcp = zarray[0];
    if(debug) {
        debug_print("ygcp/zgcp: " + ygcp + "/" + zgcp);
        debug_print("zarray: " + zarray);
    }
    //
    // Start loop:
    int end = nump_org;
    int ln = 0;
    int stop = 0;
    int index = 0;
    bool[] raster = [true];
    do {
        if(debug) {
            debug_print("stop : " + stop);
            debug_print("end : " + end);
            debug_print("index : " + index);
            debug_print("counter: " + counter);
        }
        if(counter > kgcp_old - 1) {
            yarray_new[index] = ygcp;
            zarray_new[index] = zgcp;
            ln = ln + 1;
            counter = 0;
            raster[index] = false;
        } else {
            yarray_new[index] = yarray_org[index - ln];
            zarray_new[index] = zarray_org[index - ln];
            if(debug) {
                debug_print("index -ln : " + (index - ln));
            }
            stop = stop + 1;
            counter = counter + 1;
            raster[index] = true;
        }
        index = index + 1;
    } while (stop < end);
    //
    // Define first point always as regular raster point:
    raster[0] = true;
    // assuming gcp_time < tp_np    
    //
    // Add additional visit to GCP at end:
    // (could give unsymmetric GCP visits but ensures a GCP at start AND end)
    if(debug) {
        debug_print("index : " + index);
    }
    if(yarray_new[index - 1] != ygcp) {
        yarray_new[index] = ygcp;
        zarray_new[index] = zgcp;
        raster[index] = false;
    }
    // 
    if(debug) {
        debug_print("# pts without GCPs: " + length(yarray_org));
        debug_print("# pts with GCPs: " + length(yarray_new));
        debug_print("yarray_org: " + yarray_org);
        debug_print("zarray_org: " + zarray_org);
        debug_print("yarray_new = " + yarray_new);
        debug_print("zarray_new = " + zarray_new);
    }
    //
    // Adapt tp vector to new number of points:
    int[] tpv_new = [0];
    for(int ind = 0 .. length(yarray_new) - 1) {
        if(ind == 0) {
            tpv_new[0] = tpv[0];
        } else {
            if(yarray_new[ind] == ygcp) {
                if(zarray_new[ind] == zgcp) {
                    tpv_new[ind] = tp_gp;
                } else {
                    tpv_new[ind] = tp_np;
                }
            } else {
                tpv_new[ind] = tp_np;
            }
        }
    }
    if(debug) {
        debug_print("raster vector = " + raster);
        debug_print("new timing vector = " + tpv_new);
        debug_print("length(raster): " + length(raster));
        debug_print("length(yarray_new): " + length(yarray_new));
        debug_print("length(tpv_new): " + length(tpv_new));
    }
    // //
    // //
    // Set pointing mode:
    //
    //custom_map_pointing(true, tslewmin, tinithold, tfinalhold, ib, naifid,
    //ra,dec,fixed,patt,yoffset,zoffset,yarray,zarray,tpv, pattnod,chopthrow,
    //nnod,knod,tloadmin,nload, thold, nhold);
    //
    int[] ts = custom_map_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,fixed,patt,yoffset,zoffset,yarray_new,zarray_new,tpv_new,pattnod,chopthrow,nnod,knod,tloadmin,nload,thold,nhold);
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC              */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Prepare observation: 
            //     
            SpireBb_StartScannedSmecBeamProfile(obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,setFramerate,frate,smecFrate,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // Initialise SMEC (close loop) (new for SPR-SPIRE-2062)
            //
            SpireBbSmecInit(resolution,version03,version06,version05,debug);
            // //
            // //
            // Set SMEC framerate (== SMEC sampling rate) to input:
            //
            SpireBb_SetSmecFramerate(smecFrate,debug);
            // //
            // //
            // Move SMEC to start of scan 
            //
            SpireBb_SmecMove(scanStart,smecHomePosn,debug);
            // //
            // //
            // Setup SMEC Scan:
            //
            SpireBb_SetupSmecScan(resolution,version05,debug);
            //
            //delay(tinithold);
        }
        if(state[0] == 3) {
            // STATE = POINT (spacecraft is at nominal RA,DEC (staring, raster))
            //
            //delay(tp);
            // //
            // //
            // Different timings for different raster points (normal vs. GCP):
            // 
            if(raster[raster_counter] == false) {
                // //
                // //
                // Show time elapsed between visits to GCP:
                int t = time() - start;
                message("Time elapsed since last visit to GCP: " + t);
                if(debug) {
                    debug_print("Time elapsed since last visit to GCP: " + t);
                }
                // 
                if(t > gcp_period) {
                    error("Elapsed time between GCP visits larger than gcp_period! Change script.");
                }
                //
                // Reset timer:           
                start = time();
                // //
                // //
                // Wait for gcp_time at GCP if gcp_time < tp_np
                // otherwise add in an additional scan at the GCP 
                //
                if(gcp_time < tp_np) {
                    // //
                    // //
                    // Set Obs step at GCP to fff:
                    //
                    SpireBb_SetObsStep(4095,debug);
                    // //
                    // //
                    // Wait at GCP:
                    //
                    delay(gcp_time - duration(SpireBb_SetObsStep(9999,debug)));
                    //
                } else {
                    // //
                    // //
                    // Set Obs step at GCP to fff:
                    //
                    SpireBb_SetObsStep(4095,debug);
                    // //
                    // //
                    // Set offsets at raster point:
                    //
                    SpireBb_SpecOffsetAuto(dcuData,debug);
                    // //
                    // //
                    // Start DCU+MCU data generation:
                    //
                    SpireBb_StartDcuMcuData();
                    // //
                    // //
                    // Perform SMEC scan:
                    //
                    SpireBb_SmecScan(resolution,nscans,version05,debug);
                    // //
                    // //
                    // Add extra time to account for gcp_time > tp_np:
                    //
                    delay(extra_delay);
                    // //
                    // //
                    // Stop DCU+MCU data generation:
                    //
                    SpireBb_StopDcuMcuData();
                }
                //
            } else {
                // //
                // //
                // Reset timing at first raster point:
                if(obsstep == 1) {
                    start = time();
                }
                // //
                // //
                // Set Obs step:
                //
                SpireBb_SetObsStep(obsstep,debug);
                // //
                // //
                // Set offsets at raster point:
                //
                SpireBb_SpecOffsetAuto(dcuData,debug);
                // //
                // //
                // Start DCU+MCU data generation:
                //
                SpireBb_StartDcuMcuData();
                // //
                // //
                // Perform SMEC scan:
                //
                SpireBb_SmecScan(resolution,nscans,version05,debug);
                // //
                // //
                // Allow extra time at first raster point if gcp_time > tp_np:
                //
                if(obsstep == 1) {
                    if(gcp_time > tp_np) {
                        delay(extra_delay);
                    }
                }
                // //
                // //
                // Stop DCU+MCU data generation:
                //
                SpireBb_StopDcuMcuData();
                // //
                // //
                // Increase obsstep parameter for next point:
                //
                obsstep = obsstep + 1;
                //
            }
            raster_counter = raster_counter + 1;
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ("sky" observation ends, performing final activities )
            // //
            // //
            // End observation:
            //
            SpireBb_EndScannedSmecBeamProfile(resolution,hold_chop,hold_jigg,smecHomePosn,isBright,version01,version02,version05,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END (end of the pointing/commanding part of the code)
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_CalGCO_FovMapCrossRaster.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Spec FOV Mapping Cross Raster' 
//
//         in *custom_map_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/09/17 V0.1: Initial version adapted from
//                  SpirePhoto_CalGCO_FovMapCrossRaster (2009/03/16 V1.0)
// 2009/05/05 V0.2: Add in move BSM/SMEC to hold/home at start. Add new 
//                  SpireBb_SmecHold to account for the fact that
//                  SpireBb_SmecMove2Home does not stop SMEC.
//                  Gather procedures at start and end in separate BB. 
//                  Remove isSerendipity approach.
// 2009/09/05 V1.0: Allow to visit raster points in reverse order. 
//                  (SCR-SPIRE-1915)
// 
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in SPECSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for all three arrays and could be taken from following cal table: 
//  SpireTable_SpecModeParams.txt
// 
//  3) Home position of BSM can be read from SpireTable_BsmNominalSettings.txt
//
//  4) Some VM parameters for chopping are read from following cal table:
//     SpireTable_CommandLists.txt
// 
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_CalGCO_FovMapCrossRaster {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; //NAIF identifier: put '0' to use RA/DEC, or correct 'NAIFID'
    /* */
    bool isBright = false; // Use settings for bright source (==tick)
    string ib = "S24_0"; // Central aperture (defined in SIAM) of raster
    double d1 = 4.0; // Angular stepsize along Y axis [arcsec] 
    double d2 = 4.0; // Angular stepsize along Z axis [arcsec]
    int m = 9 in [3,2997]; // Total number of points in Y/Z [odd number, symmetric!]
    int k = 0; // Additional visits to GCP on each arm of the cross
    int ftime = 60; // Read-out time [s]
    double chopf = 2.0 in [0.1,4.0]; // Chop frequency [Hz] 
    int offChopfh = 9600; // off-source chop position (+ or - relative to hold) [Dec(Hex)]
    double framerate = 125.0; // Specifies the MCU framerate [Hz]
    int gcp_time = 20; // Time spend at GCP (gyro calibration position) [s]
    int gcp_period = 600; // Maximum time between successiv GCP visits [s]
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParas    
    string version03 = "v00"; // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial"; // Model in cal table SpireTable_BsmNominalSettings
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Visit raster pts in reverse order (==tick)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // //
    // //
    // Assign spare parameters:
    //
    bool reverse = pBool1;
    // 
    // //
    // //
    // Current restrictions:
    //
    if(naifid != 0) {
        error("Currently no SSO objects are allowed as input!");
    }
    // //
    // //
    // Declare some variable:
    //
    // Spectrometer or FTS:
    bool phot = false;
    bool fts = !phot;
    //
    // Start timing of script:
    int start = time();
    //
    // Keep track of actual visits to GCP: 
    double maxgcp_period = 0.0;
    //
    // First obsstep [HEX]:
    int obsstep = 0x0;
    //
    // Count raster points: 
    int raster_counter = 0;
    //
    int obsStep = 0;
    int tslewminadd = 0;
    bool setFramerate = true;
    string version = "";
    string tabName = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    // DCU data mode (0 == Full spectrometer; 4 == Full spectrometer):
    int dcumode = 4;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    string tabName04 = "SpireTable_CommandLists.txt";
    string tabName06 = "SpireTable_SmecNominalSettings.txt";
    //
    // Currently hardcoded version:
    //
    string version06 = "v00";
    // Version in cal table SpireTable_SmecNominalSettings
    //
    // Currently hardcoded parameter:
    // Is (==tick) the DCU currently sampled? 
    bool dcuData = false;
    //
    // Currently hardcoded parameter:
    // Useful length of serendipity observation
    int limit = 20;
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS43";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for setup and datarates:  
    string obsMode = "SEngCalObs";
    // Note: datarates are currently only maximum values
    // //
    // //
    // Setup parameters for BSM chopping movement: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version03;
    tabName = tabName03;
    string selCol = "model";
    // Name of column for selecting 
    string selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    string tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set chop/jigg positions:
    //    
    // on-source Chop position [Dec(Hex)]:
    int onChop = hold_chop;
    //
    // on-source Jiggle position:
    int onJigg = hold_jigg;
    //
    // off-source Chop position:
    int offChop = hold_chop + offChopfh;
    //
    // off-source Jiggle position:
    int offJigg = hold_jigg;
    // 
    // Read VM parameters from calibration table:
    //
    tabName = tabName04;
    selVal = "Chop";
    int vmId = ilookup(tabName,selVal,"Id");
    int vmIndex = ilookup(tabName,selVal,"Index");
    int nParms = ilookup(tabName,selVal,"Nparms");
    // //
    // //
    // Read SMEC home position from calibration file:
    //
    tarCol = "Home";
    tabName = tabName06;
    selVal = version06;
    int smecHomePosn = ilookup(tabName,selVal,tarCol);
    // //
    // //
    // Read nominal bias frequency and bias divider:
    //    
    // Select version flag and set GetTableEntry parameters:
    version = version01;
    tabName = tabName01;
    selCol = "mode";
    // Name of column for selecting 
    selVal = obsMode;
    // Value of 'string' selector
    //
    tarCol = "mclkDiv";
    int mclkdiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "biasDiv";
    int biasdiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Calculate nominal sampling rate from mclkdiv and biasdiv:
    //
    double mclkdivHz = 1.0E7 / (512.0 * double(mclkdiv + 1));
    double biasdivHz = 1.0 / (double(biasdiv) + 1.0) * mclkdivHz;
    if(debug) {
        debug_print("Nominal sampling rate is: " + biasdivHz + " [Hz]");
    }
    //
    // //
    // //
    // Compare read-out time and dwell time on GCP:
    //
    int dtime = 0;
    // time to be spend on GCP position
    if(gcp_time < ftime) {
        dtime = ftime;
    } else {
        dtime = gcp_time;
    }
    if(debug) {
        debug_print("ftime: " + ftime);
        debug_print("gcp_time: " + gcp_time);
        debug_print("dtime: " + dtime);
    }
    // //
    // //
    // Calculate BSM chop parameters:
    //
    int[] chopparam1 = SpireProc_CalcParam_BsmSetup(ftime,chopf,biasdivHz,framerate,debug);
    int ncycles = chopparam1[0];
    int chop_period = chopparam1[1];
    int dcusample = chopparam1[2];
    int dcudelay = chopparam1[3];
    int bsmsample = chopparam1[4];
    //
    int[] chopparam2 = SpireProc_CalcParam_BsmSetup(dtime,chopf,biasdivHz,framerate,debug);
    int ncycles_2 = chopparam2[0];
    int chop_period_2 = chopparam2[1];
    int dcusample_2 = chopparam2[2];
    int dcudelay_2 = chopparam2[3];
    int bsmsample_2 = chopparam2[4];
    // //
    // //
    // Compare user input of BSM framerate with default value:
    //
    version = version02;
    tabName = tabName02;
    tarCol = "bsmFrameRate";
    int bsmFrameRate = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    double bsmFrameRateHz = 1000000.0 / (double(bsmFrameRate) * 420.0);
    if(debug) {
        debug_print("Nominal BSM sampling rate is: " + bsmFrameRateHz + " [Hz]");
    }
    //
    // Compare nominal with input BSM framerate:
    // 
    int frate = SpireProc_CalcParam_BsmFramerate(framerate,debug);
    if(frate == bsmFrameRate) {
        setFramerate = false;
    }
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    // 
    int tslewmin = duration(SpireBb_StartFovMapCrossRaster(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,setFramerate,frate,smecHomePosn,debug));
    //
    //BBs carried out when the pointing is reached:
    //
    int tinithold = 0;
    //
    // BB carried out during pointing:
    // 
    int tp_np = duration(SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles,chop_period,dcumode,dcusample,dcudelay,bsmsample,9999,debug)) + duration(SpireBb_SpecOffsetAuto(dcuData,debug));
    int tp_gp = duration(SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles_2,chop_period_2,dcumode,dcusample_2,dcudelay_2,bsmsample_2,9999,debug)) + duration(SpireBb_SpecOffsetAuto(dcuData,debug));
    //    
    // BB carried out at the end:
    //
    int tfinalhold = duration(SpireBb_EndFovMapCrossRaster(phot,hold_chop,hold_jigg,isBright,version01,version02,debug));
    // //
    // //
    // Debug printing:
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing normal= " + tp_np);
        debug_print("tpointing @GCP= " + tp_gp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                              */
    // ****************************************************** */
    // //
    // //
    // Fixed parameters for pointing mode:
    //   
    // Pattern orientation (true==sky; false==array):
    bool fixed = false;
    //
    // Rotation angle of the pattern:
    double patt = 90.0;
    //
    // Offset of pattern in the direction of the +Y:
    double yoffset = 0.0;
    //
    // Offset of pattern in the direction of the +Z:
    double zoffset = 0.0;
    //
    // The duration of the hold when nhold>0:
    int thold = 0;
    //
    // Number of nods or raster points or scan lines before
    // performing a hold.
    int nhold = 0;
    //              
    double pattnod = 0.0;
    //
    double chopthrow = 2.0;
    //
    int nnod = 1;
    //
    int knod = 0;
    //
    int nload = 0;
    //
    int tloadmin = 0;
    //
    // //
    // //
    // Calculate array of points:
    //
    {double[],double[],bool[]} array = SpireProc_CalcParam_FovMapCrossRaster(d1,d2,m,k,reverse,debug);
    double[] zarray = array{0};
    double[] yarray = array{1};
    bool[] raster = array{2};
    int nump = length(yarray);
    // //
    // //
    // Set pointing vector: 
    //
    int[] tpv = [0];
    for(int index = 0 .. nump - 1) {
        if(raster[index]) {
            tpv[index] = tp_np;
        } else {
            tpv[index] = tp_gp;
        }
        index = index + 1;
    }
    if(debug) {
        debug_print("tpv = " + tpv);
    }
    // //
    // //
    // Set pointing mode:
    //
    //custom_map_pointing(true, tslewmin, tinithold, tfinalhold, ib, naifid,
    //ra,dec,fixed,patt,yoffset,zoffset,yarray,zarray,tpv, pattnod,chopthrow,
    //nnod,knod,tloadmin,nload, thold, nhold);
    //
    int[] ts = custom_map_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,fixed,patt,yoffset,zoffset,yarray,zarray,tpv,pattnod,chopthrow,nnod,knod,tloadmin,nload,thold,nhold);
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC              */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //     
            SpireBb_StartFovMapCrossRaster(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,setFramerate,frate,smecHomePosn,debug);
            // //
            // //
            // Perform serendipity operation if possible:
            //
            // Read slew time from pointing mode:
            //int tslew = ts[1];
            // Slew time    
            //
            // Minimum time for a serendipity observation:
            //int tSerendipity = duration(SpireProc_Exec_Serendipity(0,debug));
            //if(debug) {
            //    debug_print("Minimum time for a serendipity observation: " + tSerendipity);
            //}
            ////
            //// 
            //if(tslew > tSerendipity + tslewmin + 20) {
            //    // Time remaining for serendipity observation:
            //    int stime = tslew - tslewmin;
            //    // 
            //    // Execute observation: 
            //    if(isSerendipity) {
            //        SpireProc_Exec_Serendipity(stime,debug);
            //    }
            //}
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            //
            //
            //delay(tinithold);
        }
        if(state[0] == 3) {
            // STATE = POINT (spacecraft is at nominal RA,DEC (staring, raster))
            // //
            // //
            // Set offsets at each raster point:
            //
            SpireBb_SpecOffsetAuto(dcuData,debug);
            // //
            // //
            // Different timings for different raster points (normal vs. GCP):
            // 
            if(raster[raster_counter] == false) {
                // //
                // //
                // Show time elapsed between visits to GCP:
                //
                if(raster_counter == 0) {
                    // Reset timer:
                    start = time();
                } else {
                    int t = time() - start;
                    // Check elapsed time and give out error:
                    maxgcp_period = max(maxgcp_period,double(t));
                    if(maxgcp_period > double(gcp_period)) {
                        error("gcp_period constraint violated!! Increase k parameter by 1");
                    }
                    message("Time elapsed since last visit to GCP: " + t);
                    if(debug) {
                        debug_print("Time elapsed since last visit to GCP: " + t);
                        debug_print("Maximum time between two GCPs: " + maxgcp_period);
                    }
                    //
                    // Reset timer:           
                    start = time();
                }
                // //
                // //
                // Run chop VM (includes data taking) and set obs step parameter: 
                //
                if(debug) {
                    debug_print("Chop on GCP raster point!");
                }
                SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles_2,chop_period_2,dcumode,dcusample_2,dcudelay_2,bsmsample_2,65535,debug);
                //
            } else {
                // //
                // //
                // Run chop VM (includes data taking) and set obs step parameter: 
                //
                if(debug) {
                    debug_print("Chop on regular raster point!");
                }
                SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles,chop_period,dcumode,dcusample,dcudelay,bsmsample,obsstep,debug);
                obsstep = obsstep + 1;
                //
            }
            raster_counter = raster_counter + 1;
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ("sky" observation ends, performing final activities )
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            SpireBb_EndFovMapCrossRaster(phot,hold_chop,hold_jigg,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END (end of the pointing/commanding part of the code)
            //
        }
    }
}

// SpireEngPHOT_STBYtoREDY
//
// $id$
//
// This observation puts the instrument into the REDY mode
// 
// The instrument should be in  the PHOT_STBY mode before execution of this observation
//
// 08/11/2007 KJK: explicitly run StartObs and EndObs building blocks around the engineering procedure
//
obs SpireEngPHOT_STBYtoREDY {
    string bsmVersion = "v00";
    string detVersion = "v00";
    string ptcVersion = "v00";
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int t = duration(SpireBbStartObs()) + duration(SpirePHOT_STBYtoREDY(bsmVersion,detVersion,ptcVersion,debug)) + duration(SpireBbEndObs());
    int[] ts = no_pointing(true,0,0,t);
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            SpireBbStartObs();
            SpirePHOT_STBYtoREDY(bsmVersion,detVersion,ptcVersion,debug);
            SpireBbEndObs();
        }
    }
}

// Missionphase  : 
//
// Purpose       : Send the appropriate TC to set a determined bias voltage
//                 for a group 1 matrix. The bias voltage is expressed in
//                 volts
// Author        : Diego A. Cesarsky
// CUS script    : Diego A. Cesarsky
// CVS file      : PHOT_bias_group_1.txt
//
// Arguments     : 
// string  biasName    The bias name in accordance with the MIB convention
// float   bias        The corresponding bias voltage [volts]
//
// Description   : Extremely unsatisfactory code to find the bias name and
//                 issue the corresponding TC. If bias name is not found,
//                 the procedure sets an error condition
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : The code is awful since it has to use dedicated TCs for
//                 each bias of each group, namely 20 different TCs. There
//                 are similar CUS procedures for each of the other 5 groups.
//                 There are two "sanity checks":
//                 1- group number has to agree with procedure name
//                 2- bias number has to agree with bias name
//
// Version       : 0.1 07-aug-2006 Creation by DAC
// History       :
//               :
procedure PHOT_bias_group_3 {
    int grpNb = 3 in [3,3]; // The group number (sort of sanity check)
    int biasNb = 1; // The bias number (sort of sanity check)
    string biasName = "VH"; // The corresponding bias name as per MIB
    double bias = 1.62312; // The bias voltage to be set for biasName
}{
    //
    // Assume failure
    bool sentTC = false;
    // Start stupid "if" code
    // Bias name Pacs_BOLC_SET_VH
    if(biasName == "VH" && biasNb == 1) {
        Pacs_BOLC_SET_VH_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VL
    if(biasName == "VL" && biasNb == 2) {
        Pacs_BOLC_SET_VL_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VRL
    if(biasName == "VRL" && biasNb == 3) {
        Pacs_BOLC_SET_VRL_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VINJ 
    if(biasName == "VINJ" && biasNb == 4) {
        Pacs_BOLC_SET_VINJ_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VCH
    if(biasName == "VCH" && biasNb == 5) {
        Pacs_BOLC_SET_VCH_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDL
    if(biasName == "VDL" && biasNb == 6) {
        Pacs_BOLC_SET_VDL_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSS
    if(biasName == "VSS" && biasNb == 7) {
        Pacs_BOLC_SET_VSS_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGL
    if(biasName == "VGL" && biasNb == 8) {
        Pacs_BOLC_SET_VGL_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_CKRLH
    if(biasName == "CKRLH" && biasNb == 9) {
        Pacs_BOLC_SET_CKRLH_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_CKRLL
    if(biasName == "CKRLL" && biasNb == 10) {
        Pacs_BOLC_SET_CKRLL_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDECX_H
    if(biasName == "VDECX-H" && biasNb == 11) {
        Pacs_BOLC_SET_VDECX_H_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDECX_L
    if(biasName == "VDECX-L" && biasNb == 12) {
        Pacs_BOLC_SET_VDECX_L_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSMS_H
    if(biasName == "VSMS-H" && biasNb == 13) {
        Pacs_BOLC_SET_VSMS_H_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSMS_L
    if(biasName == "VSMS-L" && biasNb == 14) {
        Pacs_BOLC_SET_VSMS_L_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGG
    if(biasName == "VGG" && biasNb == 15) {
        Pacs_BOLC_SET_VGG_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDD
    if(biasName == "VDD" && biasNb == 16) {
        Pacs_BOLC_SET_VDD_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSS_BU
    if(biasName == "VSS-BU" && biasNb == 17) {
        Pacs_BOLC_SET_VSS_BU_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDL_BU
    if(biasName == "VDL-BU" && biasNb == 18) {
        Pacs_BOLC_SET_VDL_BU_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGL_BU
    if(biasName == "VGL-BU" && biasNb == 19) {
        Pacs_BOLC_SET_VGL_BU_G3(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VH_BLIND
    if(biasName == "VH-BLIND" && biasNb == 20) {
        Pacs_BOLC_SET_VH_BLIND_G3(bias);
        sentTC = true;
    }
    // Error condition if no bias was set
    if(!sentTC) {
        error("The combination " + biasName + "/" + biasNb + " is not correct");
    }
}

// Missionphase  : 
//
// Purpose       : Send the appropriate TC to set a determined bias voltage
//                 for a group 1 matrix. The bias voltage is expressed in
//                 volts
// Author        : Diego A. Cesarsky
// CUS script    : Diego A. Cesarsky
// CVS file      : PHOT_bias_group_2.txt
//
// Arguments     : 
// string  biasName    The bias name in accordance with the MIB convention
// float   bias        The corresponding bias voltage [volts]
//
// Description   : Extremely unsatisfactory code to find the bias name and
//                 issue the corresponding TC. If bias name is not found,
//                 the procedure sets an error condition
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : The code is awful since it has to use dedicated TCs for
//                 each bias of each group, namely 20 different TCs. There
//                 are similar CUS procedures for each of the other 5 groups.
//                 There are two "sanity checks":
//                 1- group number has to agree with procedure name
//                 2- bias number has to agree with bias name
//
// Version       : 0.1 07-aug-2006 Creation by DAC
// History       :
//               :
procedure PHOT_bias_group_2 {
    int grpNb = 2 in [2,2]; // The group number (sort of sanity check)
    int biasNb = 1; // The bias number (sort of sanity check)
    string biasName = "VH"; // The corresponding bias name as per MIB
    double bias = 1.62312; // The bias voltage to be set for biasName
}{
    //
    // Assume failure
    bool sentTC = false;
    // Start stupid "if" code
    // Bias name Pacs_BOLC_SET_VH
    if(biasName == "VH" && biasNb == 1) {
        Pacs_BOLC_SET_VH_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VL
    if(biasName == "VL" && biasNb == 2) {
        Pacs_BOLC_SET_VL_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VRL
    if(biasName == "VRL" && biasNb == 3) {
        Pacs_BOLC_SET_VRL_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VINJ 
    if(biasName == "VINJ" && biasNb == 4) {
        Pacs_BOLC_SET_VINJ_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VCH
    if(biasName == "VCH" && biasNb == 5) {
        Pacs_BOLC_SET_VCH_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDL
    if(biasName == "VDL" && biasNb == 6) {
        Pacs_BOLC_SET_VDL_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSS
    if(biasName == "VSS" && biasNb == 7) {
        Pacs_BOLC_SET_VSS_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGL
    if(biasName == "VGL" && biasNb == 8) {
        Pacs_BOLC_SET_VGL_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_CKRLH
    if(biasName == "CKRLH" && biasNb == 9) {
        Pacs_BOLC_SET_CKRLH_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_CKRLL
    if(biasName == "CKRLL" && biasNb == 10) {
        Pacs_BOLC_SET_CKRLL_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDECX_H
    if(biasName == "VDECX-H" && biasNb == 11) {
        Pacs_BOLC_SET_VDECX_H_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDECX_L
    if(biasName == "VDECX-L" && biasNb == 12) {
        Pacs_BOLC_SET_VDECX_L_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSMS_H
    if(biasName == "VSMS-H" && biasNb == 13) {
        Pacs_BOLC_SET_VSMS_H_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSMS_L
    if(biasName == "VSMS-L" && biasNb == 14) {
        Pacs_BOLC_SET_VSMS_L_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGG
    if(biasName == "VGG" && biasNb == 15) {
        Pacs_BOLC_SET_VGG_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDD
    if(biasName == "VDD" && biasNb == 16) {
        Pacs_BOLC_SET_VDD_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSS_BU
    if(biasName == "VSS-BU" && biasNb == 17) {
        Pacs_BOLC_SET_VSS_BU_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDL_BU
    if(biasName == "VDL-BU" && biasNb == 18) {
        Pacs_BOLC_SET_VDL_BU_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGL_BU
    if(biasName == "VGL-BU" && biasNb == 19) {
        Pacs_BOLC_SET_VGL_BU_G2(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VH_BLIND
    if(biasName == "VH-BLIND" && biasNb == 20) {
        Pacs_BOLC_SET_VH_BLIND_G2(bias);
        sentTC = true;
    }
    // Error condition if no bias was set
    if(!sentTC) {
        error("The combination " + biasName + "/" + biasNb + " is not correct");
    }
}

// Missionphase  : 
//
// Purpose       : Send the appropriate TC to set a determined bias voltage
//                 for a group 1 matrix. The bias voltage is expressed in
//                 volts
// Author        : Diego A. Cesarsky
// CUS script    : Diego A. Cesarsky
// CVS file      : PHOT_bias_group_1.txt
//
// Arguments     : 
// string  biasName    The bias name in accordance with the MIB convention
// float   bias        The corresponding bias voltage [volts]
//
// Description   : Extremely unsatisfactory code to find the bias name and
//                 issue the corresponding TC. If bias name is not found,
//                 the procedure sets an error condition
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : The code is awful since it has to use dedicated TCs for
//                 each bias of each group, namely 20 different TCs. There
//                 are similar CUS procedures for each of the other 5 groups.
//                 There are two "sanity checks":
//                 1- group number has to agree with procedure name
//                 2- bias number has to agree with bias name
//
// Version       : 0.1 07-aug-2006 Creation by DAC
// History       :
//               :
procedure PHOT_bias_group_1 {
    int grpNb = 1 in [1,1]; // The group number (sort of sanity check)
    int biasNb = 1; // The bias number (sort of sanity check)
    string biasName = "VH"; // The corresponding bias name as per MIB
    double bias = 1.62312; // The bias voltage to be set for biasName
}{
    //
    // Assume failure
    bool sentTC = false;
    // Start stupid "if" code
    // Bias name Pacs_BOLC_SET_VH
    if(biasName == "VH" && biasNb == 1) {
        Pacs_BOLC_SET_VH_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VL
    if(biasName == "VL" && biasNb == 2) {
        Pacs_BOLC_SET_VL_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VRL
    if(biasName == "VRL" && biasNb == 3) {
        Pacs_BOLC_SET_VRL_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VINJ 
    if(biasName == "VINJ" && biasNb == 4) {
        Pacs_BOLC_SET_VINJ_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VCH
    if(biasName == "VCH" && biasNb == 5) {
        Pacs_BOLC_SET_VCH_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDL
    if(biasName == "VDL" && biasNb == 6) {
        Pacs_BOLC_SET_VDL_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSS
    if(biasName == "VSS" && biasNb == 7) {
        Pacs_BOLC_SET_VSS_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGL
    if(biasName == "VGL" && biasNb == 8) {
        Pacs_BOLC_SET_VGL_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_CKRLH
    if(biasName == "CKRLH" && biasNb == 9) {
        Pacs_BOLC_SET_CKRLH_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_CKRLL
    if(biasName == "CKRLL" && biasNb == 10) {
        Pacs_BOLC_SET_CKRLL_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDECX_H
    if(biasName == "VDECX-H" && biasNb == 11) {
        Pacs_BOLC_SET_VDECX_H_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDECX_L
    if(biasName == "VDECX-L" && biasNb == 12) {
        Pacs_BOLC_SET_VDECX_L_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSMS_H
    if(biasName == "VSMS-H" && biasNb == 13) {
        Pacs_BOLC_SET_VSMS_H_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSMS_L
    if(biasName == "VSMS-L" && biasNb == 14) {
        Pacs_BOLC_SET_VSMS_L_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGG
    if(biasName == "VGG" && biasNb == 15) {
        Pacs_BOLC_SET_VGG_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDD
    if(biasName == "VDD" && biasNb == 16) {
        Pacs_BOLC_SET_VDD_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSS_BU
    if(biasName == "VSS-BU" && biasNb == 17) {
        Pacs_BOLC_SET_VSS_BU_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDL_BU
    if(biasName == "VDL-BU" && biasNb == 18) {
        Pacs_BOLC_SET_VDL_BU_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGL_BU
    if(biasName == "VGL-BU" && biasNb == 19) {
        Pacs_BOLC_SET_VGL_BU_G1(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VH_BLIND
    if(biasName == "VH-BLIND" && biasNb == 20) {
        Pacs_BOLC_SET_VH_BLIND_G1(bias);
        sentTC = true;
    }
    // Error condition if no bias was set
    if(!sentTC) {
        error("The combination " + biasName + "/" + biasNb + " is not correct");
    }
}

// Missionphase  : 
//
// Purpose       : Send the appropriate TC to set a determined bias voltage
//                 for a group 1 matrix. The bias voltage is expressed in
//                 volts
// Author        : Diego A. Cesarsky
// CUS script    : Diego A. Cesarsky
// CVS file      : PHOT_bias_group_1.txt
//
// Arguments     : 
// string  biasName    The bias name in accordance with the MIB convention
// float   bias        The corresponding bias voltage [volts]
//
// Description   : Extremely unsatisfactory code to find the bias name and
//                 issue the corresponding TC. If bias name is not found,
//                 the procedure sets an error condition
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : The code is awful since it has to use dedicated TCs for
//                 each bias of each group, namely 20 different TCs. There
//                 are similar CUS procedures for each of the other 5 groups.
//                 There are two "sanity checks":
//                 1- group number has to agree with procedure name
//                 2- bias number has to agree with bias name
//
// Version       : 0.1 07-aug-2006 Creation by DAC
// History       :
//               :
procedure PHOT_bias_group_6 {
    int grpNb = 6 in [6,6]; // The group number (sort of sanity check)
    int biasNb = 1; // The bias number (sort of sanity check)
    string biasName = "VH"; // The corresponding bias name as per MIB
    double bias = 1.62312; // The bias voltage to be set for biasName
}{
    //
    // Assume failure
    bool sentTC = false;
    // Start stupid "if" code
    // Bias name Pacs_BOLC_SET_VH
    if(biasName == "VH" && biasNb == 1) {
        Pacs_BOLC_SET_VH_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VL
    if(biasName == "VL" && biasNb == 2) {
        Pacs_BOLC_SET_VL_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VRL
    if(biasName == "VRL" && biasNb == 3) {
        Pacs_BOLC_SET_VRL_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VINJ 
    if(biasName == "VINJ" && biasNb == 4) {
        Pacs_BOLC_SET_VINJ_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VCH
    if(biasName == "VCH" && biasNb == 5) {
        Pacs_BOLC_SET_VCH_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDL
    if(biasName == "VDL" && biasNb == 6) {
        Pacs_BOLC_SET_VDL_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSS
    if(biasName == "VSS" && biasNb == 7) {
        Pacs_BOLC_SET_VSS_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGL
    if(biasName == "VGL" && biasNb == 8) {
        Pacs_BOLC_SET_VGL_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_CKRLH
    if(biasName == "CKRLH" && biasNb == 9) {
        Pacs_BOLC_SET_CKRLH_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_CKRLL
    if(biasName == "CKRLL" && biasNb == 10) {
        Pacs_BOLC_SET_CKRLL_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDECX_H
    if(biasName == "VDECX-H" && biasNb == 11) {
        Pacs_BOLC_SET_VDECX_H_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDECX_L
    if(biasName == "VDECX-L" && biasNb == 12) {
        Pacs_BOLC_SET_VDECX_L_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSMS_H
    if(biasName == "VSMS-H" && biasNb == 13) {
        Pacs_BOLC_SET_VSMS_H_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSMS_L
    if(biasName == "VSMS-L" && biasNb == 14) {
        Pacs_BOLC_SET_VSMS_L_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGG
    if(biasName == "VGG" && biasNb == 15) {
        Pacs_BOLC_SET_VGG_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDD
    if(biasName == "VDD" && biasNb == 16) {
        Pacs_BOLC_SET_VDD_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSS_BU
    if(biasName == "VSS-BU" && biasNb == 17) {
        Pacs_BOLC_SET_VSS_BU_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDL_BU
    if(biasName == "VDL-BU" && biasNb == 18) {
        Pacs_BOLC_SET_VDL_BU_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGL_BU
    if(biasName == "VGL-BU" && biasNb == 19) {
        Pacs_BOLC_SET_VGL_BU_G6(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VH_BLIND
    if(biasName == "VH-BLIND" && biasNb == 20) {
        Pacs_BOLC_SET_VH_BLIND_G6(bias);
        sentTC = true;
    }
    // Error condition if no bias was set
    if(!sentTC) {
        error("The combination " + biasName + "/" + biasNb + " is not correct");
    }
}

// Missionphase  : 
//
// Purpose       : Send the appropriate TC to set a determined bias voltage
//                 for a group 1 matrix. The bias voltage is expressed in
//                 volts
// Author        : Diego A. Cesarsky
// CUS script    : Diego A. Cesarsky
// CVS file      : PHOT_bias_group_1.txt
//
// Arguments     : 
// string  biasName    The bias name in accordance with the MIB convention
// float   bias        The corresponding bias voltage [volts]
//
// Description   : Extremely unsatisfactory code to find the bias name and
//                 issue the corresponding TC. If bias name is not found,
//                 the procedure sets an error condition
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : The code is awful since it has to use dedicated TCs for
//                 each bias of each group, namely 20 different TCs. There
//                 are similar CUS procedures for each of the other 5 groups.
//                 There are two "sanity checks":
//                 1- group number has to agree with procedure name
//                 2- bias number has to agree with bias name
//
// Version       : 0.1 07-aug-2006 Creation by DAC
// History       :
//               :
procedure PHOT_bias_group_4 {
    int grpNb = 4 in [4,4]; // The group number (sort of sanity check)
    int biasNb = 1; // The bias number (sort of sanity check)
    string biasName = "VH"; // The corresponding bias name as per MIB
    double bias = 1.62312; // The bias voltage to be set for biasName
}{
    //
    // Assume failure
    bool sentTC = false;
    // Start stupid "if" code
    // Bias name Pacs_BOLC_SET_VH
    if(biasName == "VH" && biasNb == 1) {
        Pacs_BOLC_SET_VH_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VL
    if(biasName == "VL" && biasNb == 2) {
        Pacs_BOLC_SET_VL_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VRL
    if(biasName == "VRL" && biasNb == 3) {
        Pacs_BOLC_SET_VRL_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VINJ 
    if(biasName == "VINJ" && biasNb == 4) {
        Pacs_BOLC_SET_VINJ_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VCH
    if(biasName == "VCH" && biasNb == 5) {
        Pacs_BOLC_SET_VCH_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDL
    if(biasName == "VDL" && biasNb == 6) {
        Pacs_BOLC_SET_VDL_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSS
    if(biasName == "VSS" && biasNb == 7) {
        Pacs_BOLC_SET_VSS_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGL
    if(biasName == "VGL" && biasNb == 8) {
        Pacs_BOLC_SET_VGL_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_CKRLH
    if(biasName == "CKRLH" && biasNb == 9) {
        Pacs_BOLC_SET_CKRLH_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_CKRLL
    if(biasName == "CKRLL" && biasNb == 10) {
        Pacs_BOLC_SET_CKRLL_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDECX_H
    if(biasName == "VDECX-H" && biasNb == 11) {
        Pacs_BOLC_SET_VDECX_H_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDECX_L
    if(biasName == "VDECX-L" && biasNb == 12) {
        Pacs_BOLC_SET_VDECX_L_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSMS_H
    if(biasName == "VSMS-H" && biasNb == 13) {
        Pacs_BOLC_SET_VSMS_H_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSMS_L
    if(biasName == "VSMS-L" && biasNb == 14) {
        Pacs_BOLC_SET_VSMS_L_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGG
    if(biasName == "VGG" && biasNb == 15) {
        Pacs_BOLC_SET_VGG_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDD
    if(biasName == "VDD" && biasNb == 16) {
        Pacs_BOLC_SET_VDD_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSS_BU
    if(biasName == "VSS-BU" && biasNb == 17) {
        Pacs_BOLC_SET_VSS_BU_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDL_BU
    if(biasName == "VDL-BU" && biasNb == 18) {
        Pacs_BOLC_SET_VDL_BU_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGL_BU
    if(biasName == "VGL-BU" && biasNb == 19) {
        Pacs_BOLC_SET_VGL_BU_G4(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VH_BLIND
    if(biasName == "VH-BLIND" && biasNb == 20) {
        Pacs_BOLC_SET_VH_BLIND_G4(bias);
        sentTC = true;
    }
    // Error condition if no bias was set
    if(!sentTC) {
        error("The combination " + biasName + "/" + biasNb + " is not correct");
    }
}

// Missionphase  : 
//
// Purpose       : Send the appropriate TC to set a determined bias voltage
//                 for a group 1 matrix. The bias voltage is expressed in
//                 volts
// Author        : Diego A. Cesarsky
// CUS script    : Diego A. Cesarsky
// CVS file      : PHOT_bias_group_1.txt
//
// Arguments     : 
// string  biasName    The bias name in accordance with the MIB convention
// float   bias        The corresponding bias voltage [volts]
//
// Description   : Extremely unsatisfactory code to find the bias name and
//                 issue the corresponding TC. If bias name is not found,
//                 the procedure sets an error condition
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : The code is awful since it has to use dedicated TCs for
//                 each bias of each group, namely 20 different TCs. There
//                 are similar CUS procedures for each of the other 5 groups.
//                 There are two "sanity checks":
//                 1- group number has to agree with procedure name
//                 2- bias number has to agree with bias name
//
// Version       : 0.1 07-aug-2006 Creation by DAC
// History       :
//               :
procedure PHOT_bias_group_5 {
    int grpNb = 5 in [5,5]; // The group number (sort of sanity check)
    int biasNb = 1; // The bias number (sort of sanity check)
    string biasName = "VH"; // The corresponding bias name as per MIB
    double bias = 1.62312; // The bias voltage to be set for biasName
}{
    //
    // Assume failure
    bool sentTC = false;
    // Start stupid "if" code
    // Bias name Pacs_BOLC_SET_VH
    if(biasName == "VH" && biasNb == 1) {
        Pacs_BOLC_SET_VH_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VL
    if(biasName == "VL" && biasNb == 2) {
        Pacs_BOLC_SET_VL_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VRL
    if(biasName == "VRL" && biasNb == 3) {
        Pacs_BOLC_SET_VRL_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VINJ 
    if(biasName == "VINJ" && biasNb == 4) {
        Pacs_BOLC_SET_VINJ_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VCH
    if(biasName == "VCH" && biasNb == 5) {
        Pacs_BOLC_SET_VCH_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDL
    if(biasName == "VDL" && biasNb == 6) {
        Pacs_BOLC_SET_VDL_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSS
    if(biasName == "VSS" && biasNb == 7) {
        Pacs_BOLC_SET_VSS_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGL
    if(biasName == "VGL" && biasNb == 8) {
        Pacs_BOLC_SET_VGL_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_CKRLH
    if(biasName == "CKRLH" && biasNb == 9) {
        Pacs_BOLC_SET_CKRLH_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_CKRLL
    if(biasName == "CKRLL" && biasNb == 10) {
        Pacs_BOLC_SET_CKRLL_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDECX_H
    if(biasName == "VDECX-H" && biasNb == 11) {
        Pacs_BOLC_SET_VDECX_H_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDECX_L
    if(biasName == "VDECX-L" && biasNb == 12) {
        Pacs_BOLC_SET_VDECX_L_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSMS_H
    if(biasName == "VSMS-H" && biasNb == 13) {
        Pacs_BOLC_SET_VSMS_H_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSMS_L
    if(biasName == "VSMS-L" && biasNb == 14) {
        Pacs_BOLC_SET_VSMS_L_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGG
    if(biasName == "VGG" && biasNb == 15) {
        Pacs_BOLC_SET_VGG_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDD
    if(biasName == "VDD" && biasNb == 16) {
        Pacs_BOLC_SET_VDD_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VSS_BU
    if(biasName == "VSS-BU" && biasNb == 17) {
        Pacs_BOLC_SET_VSS_BU_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VDL_BU
    if(biasName == "VDL-BU" && biasNb == 18) {
        Pacs_BOLC_SET_VDL_BU_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VGL_BU
    if(biasName == "VGL-BU" && biasNb == 19) {
        Pacs_BOLC_SET_VGL_BU_G5(bias);
        sentTC = true;
    }
    // Bias name Pacs_BOLC_SET_VH_BLIND
    if(biasName == "VH-BLIND" && biasNb == 20) {
        Pacs_BOLC_SET_VH_BLIND_G5(bias);
        sentTC = true;
    }
    // Error condition if no bias was set
    if(!sentTC) {
        error("The combination " + biasName + "/" + biasNb + " is not correct");
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartLoadCurvePcalOn.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpirePhoto/Spectro_Cal_LoadCurvePcalOn.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/06 V0.1: Initial version adapted from
//                  SpireBb_StartBsmAngleCal (2009/05/05 V0.1) and
//                  SpirePhoto_Cal_LoadCurvePcalOn (2009/04/01 V0.1).
//                  BB includes now to move BSM/SMEC to hold/home.  
// 2009/07/07 V1.0: Fix bug to allow spectrometer to use script too.   
// 2009/07/10 V1.1: Fix bug SPR-SPIRE-1612
// 
// Notes:
//    1) Scripts assumes that SpireBb_SpecOffsetAuto is run 
//       during INITHOLD or at first POINTING.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartLoadCurvePcalOn SPIRE 14060 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    string obsModeQla = "ENG_CAL_OBS15";
    string obsMode = "PEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_Phot/SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    int smecHomePosn = 3500; // SMEC home position
    int mclkdiv = 149; // mclkdiv (spec ==~ 121)
    int biasdiv = 6; // biasdiv (spec ==~ 1)
    int psw_bias = 62; //
    int pmw_bias = 62; //
    int plw_bias = 62; //
    int ptc_bias = 62; //
    int psw_phase = 127; //
    int pmw_phase = 127; //
    int plw_phase = 127; //
    int ptc_phase = 127; //
    int ssw_bias = 45; //
    int slw_bias = 45; //
    int ssw_phase = 128; //
    int slw_phase = 128; // 
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartLoadCurvePcalOn configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // In case move SMEC to home:
    // 
    if(!phot) {
        //
        // Calculate available time for possible movement:
        //
        int tmove = duration(SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug)) + duration(SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug)) + duration(SpireProc_Set_DcuFreqSamp(mclkdiv,biasdiv,phot,debug)) + duration(SpireProc_Set_PhotPhase(psw_phase,pmw_phase,plw_phase,ptc_phase,debug)) + duration(SpireProc_Set_PhotBias(psw_bias,pmw_bias,plw_bias,ptc_bias,debug)) + duration(SpireBb_SpecOffsetAuto(false,debug));
        //
        // Calculate max offset for which time is available:
        //
        int smecMaxOff = tmove * 500;
        // Note, 500 is maximum possible SMEC speed.
        int smecStart = smecHomePosn + smecMaxOff;
        // Note, formula above only reasonable 
        // when smecHomePosn small compared to 39500  
        // Safety check: 
        if(smecStart > 39500) {
            smecStart = 39500;
        }
        if(debug) {
            debug_print("smecStart: " + smecStart);
            debug_print("smecHomePosn: " + smecHomePosn);
            debug_print("tmove: " + tmove);
        }
        // 
        // Move from maximal offset to home:
        //
        SpireProc_SmecMove2Home(smecHomePosn,smecHomePosn + smecMaxOff,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    if(phot) {
        SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    }
    //delay(timeSlewCal);
    // //
    // //
    // Set requested frequency and phase plus first bias level:
    //
    SpireProc_Set_DcuFreqSamp(mclkdiv,biasdiv,phot,debug);
    if(phot) {
        SpireProc_Set_PhotPhase(psw_phase,pmw_phase,plw_phase,ptc_phase,debug);
        SpireProc_Set_PhotBias(psw_bias,pmw_bias,plw_bias,ptc_bias,debug);
    } else {
        SpireProc_Set_SpecBias(ssw_bias,slw_bias,debug);
        SpireProc_Set_SpecPhase(ssw_phase,slw_phase,debug);
    }
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartLoadCurvePcalOn configuration ended");
    SpireMsg(1,"  ..StartLoadCurvePcalOn took " + (time() - t) + " seconds)");
    //
}

//
// Dump PM
// 06/11/2009: SDS First Version (For dumping OBS 4.0.0 PM - SPIRE-SCR-2127)
//    
block SpireBb_PMDump SPIRE 3403 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_PMDump started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // Dump PM
    Spire_DUMP_MEMORY_RAW(0,0x4000,0x174b);
    delay(10);
    Spire_DUMP_MEMORY_RAW(0,0x6000,0xffff);
    delay(60);
    Spire_DUMP_MEMORY_RAW(0,0x15fff,0x59);
    delay(5);
    // Report the PM checksums as well
    Spire_CHECK_MEMORY_RAW(0,0x4000,0x174b);
    delay(5);
    Spire_CHECK_MEMORY_RAW(0,0x6000,0xffff);
    delay(5);
    Spire_CHECK_MEMORY_RAW(0,0x15fff,0x59);
    delay(5);
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_PMDump ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

// SpireEngLoadAllTables
//
// $id$
//
// This observation loads all the tables to the OBS
//
// The instrument should normally be in REDY mode before execution
// of this observation.
//
//
// 06/11/2009 SDS: First Version 1.0 (For SCR-SPIRE-2127 - to be run after upload of OBS 4.0.0)
//
// 21/07/2011 SDS: Version 1.1 (For SCR-SPIRE-3622 - to include the loading of SM02 table)
//
///////////////////////////////////////////////////////////////////////////
obs SpireEngLoadAllTables {
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use)
    int pInt2 = 0; // Spare parameter (currently not in use)
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int t = duration(SpireBbStartObs()) + duration(SpireBbEndObs());
    // ********* Update t for tables to be loaded *******
    t = t + duration(SpireBb_LoadTableActions());
    t = t + duration(SpireBb_LoadTableAutonomy());
    t = t + duration(SpireBb_LoadTableBSMMove());
    t = t + duration(SpireBb_LoadTableChop());
    t = t + duration(SpireBb_LoadTableCREC());
    t = t + duration(SpireBb_LoadTableCtrlOff());
    t = t + duration(SpireBb_LoadTableFlash());
    t = t + duration(SpireBb_LoadTableFunctions());
    t = t + duration(SpireBb_LoadTableJiggleMap());
    t = t + duration(SpireBb_LoadTableJM07());
    t = t + duration(SpireBb_LoadTableJM07b());
    t = t + duration(SpireBb_LoadTableJM64());
    t = t + duration(SpireBb_LoadTableJM64b());
    t = t + duration(SpireBb_LoadTableMCUSAFE());
    t = t + duration(SpireBb_LoadTableMonitor());
    t = t + duration(SpireBb_LoadTablePTC());
    t = t + duration(SpireBb_LoadTableREDY());
    t = t + duration(SpireBb_LoadTableSAFE());
    t = t + duration(SpireBb_LoadTableSCAL());
    t = t + duration(SpireBb_SetVMStorage());
    t = t + duration(SpireBb_LoadTableSM01());
    t = t + duration(SpireBb_LoadTableSM02());
    t = t + duration(SpireBb_LoadTableSM04());
    t = t + duration(SpireBb_LoadTableSM16());
    t = t + duration(SpireBb_LoadTableSmec());
    t = t + duration(SpireBb_LoadTableStepAndChop());
    t = t + duration(SpireBb_UpdateNHK());
    // Update t for the PM dump
    t = t + duration(SpireBb_PMDump());
    //
    // ***********************************************
    int[] ts = no_pointing(true,0,0,t);
}{
    SpireMsg(0,"Observation Start");
    SpireMsg(3,"       $Id:$");
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            SpireBbStartObs();
            // Load all the OBS tables
            SpireBb_LoadTableActions();
            SpireBb_LoadTableAutonomy();
            SpireBb_LoadTableBSMMove();
            SpireBb_LoadTableChop();
            SpireBb_LoadTableCREC();
            SpireBb_LoadTableCtrlOff();
            SpireBb_LoadTableFlash();
            SpireBb_LoadTableFunctions();
            SpireBb_LoadTableJiggleMap();
            SpireBb_LoadTableJM07();
            SpireBb_LoadTableJM07b();
            SpireBb_LoadTableJM64();
            SpireBb_LoadTableJM64b();
            SpireBb_LoadTableMCUSAFE();
            SpireBb_LoadTableMonitor();
            SpireBb_LoadTablePTC();
            SpireBb_LoadTableREDY();
            SpireBb_LoadTableSAFE();
            SpireBb_LoadTableSCAL();
            SpireBb_SetVMStorage();
            SpireBb_LoadTableSM01();
            SpireBb_LoadTableSM02();
            SpireBb_LoadTableSM04();
            SpireBb_LoadTableSM16();
            SpireBb_LoadTableSmec();
            SpireBb_LoadTableStepAndChop();
            SpireBb_UpdateNHK();
            // Perform a PM Dump 
            SpireBb_PMDump();
            // 
            SpireBbEndObs();
        }
    }
    SpireMsg(0,"Observation Completed  (" + time() + " seconds)");
    SpireMsg(0,"Note: Total time (s) = Observation Completed time - slew time + Observatory Overheads");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_PhotFSetupData.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set bias frequency, amplitude, and phase of photometer arrays
//
// Note: Script does also set biasmode to 255 (sine) and frames to 0 (continous)
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/05/02 V0.1: Initial version adapted from old Setup_PF_Data
// 2008/07/03 V0.2: Renumber version; reduce maximal allowed sampling 
//                  rate to ensure data rate does not exceed limit;
//                  allow to set PTC bolometer phase/bias
// 2009/01/31 V1.0: Add debug_print as input. Change some comments. 
//                  Replace last delay(1) with sync(). Remove unsetting
//                  off BBID at end. 
// 2009/06/05 V1.1: Replace Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd 
//                  as requested in SPR-1482.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_PhotFSetupData SPIRE 14005 {
    int mclkdiv = 0x95; //Default (IST) bias freq (== 130.20833 Hz)
    int biasdiv = 0x6; //Default (IST) sampling freq (== 18.60119 Hz)
    int psw_bias = 0x3e; //Default (IST) bias amplitud  (==31.0761 mV)
    int pmw_bias = 0x3e; //Default (IST) bias amplitud  (==31.2735 mV)
    int plw_bias = 0x3e; //Default (IST) bias amplitud  (==31.4033 mV)
    int ptc_bias = 0x80; //Default (IST) bias amplitud  (==127.6311 mV)
    int psw_phase = 0x80; //Default phase (IST)  (== 180.7 deg)
    int pmw_phase = 0x80; //Default phase (IST)  (== 180.7 deg)
    int plw_phase = 0x80; //Default phase (IST)  (== 180.7 deg)
    int ptc_phase = 0x80; //Default phase (IST)  (== 180.7 deg)
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Set fixed (for flight) parameters:
    //
    // Default (IST) sine bias mode generation:
    int biasmode = 0xff;
    //
    // Default (IST) number of frames to request 
    // (do not use frames, but only ftime to select time)
    int frames = 0;
    // //
    // //
    // Safety checks
    //
    if(biasdiv < 2) {
        biasdiv = 2;
    }
    if(biasdiv > 255) {
        biasdiv = 255;
    }
    if(mclkdiv < 64) {
        mclkdiv = 64;
    }
    if(mclkdiv > 511) {
        mclkdiv = 511;
    }
    // //
    // //
    // Calculate bias and sampling frequencies based on mclkdiv and biasdiv:  
    //
    // Calculate bias frequency Hz:
    double bias_f = 1.0E7 / (512.0 * double(mclkdiv + 1));
    //
    // Calculate sampling rate Hz:
    double s_rate = bias_f / (1.0 + double(biasdiv));
    // //
    // //
    // Verify sampling rate does not exceed 20Hz for Full Photometer:
    // 
    if(s_rate > 20.0) {
        do {
            biasdiv = biasdiv + 1;
            s_rate = bias_f / (1.0 + double(biasdiv));
            if(debug) {
                debug_print("New bias divisor is: " + biasdiv);
                debug_print("New sampling rate is: " + s_rate);
            }
        } while (s_rate > 20.0);
    }
    // //
    // //
    // Calculate frametime (time between successive frames = 1/sampling rate): 
    //
    //Frametime difference in ms:
    double framerate = 1.0 / s_rate * 1000.0;
    // //
    // //
    // Debug printout:
    //
    if(debug) {
        debug_print("    BIAS FREQUENCY IS : " + bias_f + " [Hz]");
        debug_print("SAMPLING FREQUENCY IS : " + s_rate + " [Hz]");
        debug_print("    FRAMETIME DIFF IS : " + framerate + " [ms]");
    }
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set bias mode:
    //
    SpireSendDrcuCmd(0x84000000 + biasmode,0);
    delay(1);
    // //
    // //
    // Set data mode to nominal:
    //
    SpireSendDrcuCmd(0x843c0000,0);
    //delay(1);
    // //
    // //
    // Set number of frames to continuous:
    //
    SpireSendDrcuCmd(0x843d0000 + frames,0);
    delay(1);
    // //
    // //
    // Set mclkdiv and biasdiv:
    //
    SpireSendDrcuCmd(0x84190000 + mclkdiv,0);
    //delay(1);
    SpireSendDrcuCmd(0x84180000 + biasdiv,0);
    delay(1);
    // //
    // //
    // Set bias amplitude:
    //
    SpireSendDrcuCmd(0x84010000 + psw_bias,0);
    //delay(1);
    SpireSendDrcuCmd(0x84020000 + pmw_bias,0);
    delay(1);
    SpireSendDrcuCmd(0x84030000 + plw_bias,0);
    //delay(1);
    // //
    // //
    // Set phase:
    //
    SpireSendDrcuCmd(0x841a0000 + psw_phase,0);
    delay(1);
    SpireSendDrcuCmd(0x841b0000 + pmw_phase,0);
    //delay(1);
    SpireSendDrcuCmd(0x841c0000 + plw_phase,0);
    delay(1);
    // //
    // //
    // Set also the bias and phase for the TC to input values:
    //
    SpireSendDrcuCmd(0x84040000 + ptc_bias,0);
    //delay(1);
    SpireSendDrcuCmd(0x841d0000 + ptc_phase,0);
    sync();
    //
}

// SpireEngCheckPM
//
// $id$
//
// This observation checksthe DPU Program Memory
//
// The instrument should normally be in REDY mode before and after execution
// of this observation.
// Intended for daily execution from the MTL during the SOPS window
//
//
// 09/08/2010 SDS: First Version 1.0 
//                 See SPIRE-SCR-2762
///////////////////////////////////////////////////////////////////////////
obs SpireEngCheckPM {
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use)
    int pInt2 = 0; // Spare parameter (currently not in use)
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int t = duration(SpireBbStartObs()) + duration(SpireBbEndObs());
    t = t + duration(SpireBb_CheckPM());
    //
    // ***********************************************
    int[] ts = no_pointing(true,0,0,t);
}{
    SpireMsg(0,"Observation Start");
    SpireMsg(3,"       $Id:$");
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            SpireBbStartObs();
            // Check the PM
            SpireBb_CheckPM();
            // 
            SpireBbEndObs();
        }
    }
    SpireMsg(0,"Observation Completed  (" + time() + " seconds)");
    SpireMsg(0,"Note: Total time (s) = Observation Completed time - slew time + Observatory Overheads");
}

///////////////////////////////////////////////////////////////////////////
// 
// SpirePhotoPeakup.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// This observation executes a Peakup observation
// 
// The instrument should be in  the PHOTSTBY mode before execution 
// of this procedure.
//
// The peakup offset generated takes effect with the next observation 
// so this observation should be concatenated with a following observation 
// that requires peaking up
//
// 11/11/2008  KJK first version
// 14/11/2008  MP: renamed script to 'Photo' to conform to naming convention;
//             Transformed into a *basic_fine_pointing* version 
// 17/11/2008  MP: add offset setting at start 
// 01/02/2009  MP: add debug_print as input and pass to low level script
// 10/03/2009 KJK: 
//         SCR 1274, add additional dummy parameters 
//         Update input API to include versions for all cal tables
// 17/03/2009 KJK:
//         Updated to use SpireTable_OpsParms cal table
//         Added possibility to input boresight
//25/09/2009 kjk: SCR Spire-1932
//        modified call to SpirePeakup to pass on versions etc
//        added default values for versions
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhotoPeakup {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; // NAIF identifier
    string boresight = ""; // Instrument Boresight
    bool isBright = false; // Use settings for bright source (==tick)
    string opsVersion = "v00"; // Version in Table_OpsParms cal table 
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int step = 0;
    string comVersion = "v00";
    string pmodeVersion = "v00";
    string smodeVersion = "v00";
    string peakVersion = "v00";
    string siamVersion = "v00";
    //
    // Lookup boresight, if not provided
    string ib = boresight;
    if(boresight == "") {
        ib = SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode","POF1","Boresight",opsVersion,debug);
    }
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    int tslewmin = duration(SpireBbStartObs());
    //
    // BBs carried out when the pointing is reached:
    int tinithold = duration(SpireBb_PhotOffsetAuto(debug));
    //int tinithold = 0;
    //
    // BB carried out during pointing:
    int tp = duration(SpirePeakup("PPeakup",ib,0,comVersion,pmodeVersion,smodeVersion,peakVersion,siamVersion,debug));
    //
    // BB carried out at the end:
    int tfinalhold = duration(SpireBbEndObs());
    //
    // Debug_printing?
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                              */
    // ****************************************************** */
    //
    // Set pointing mode:
    //
    int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    // 
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
        debug_print("Boresight: " + ib);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBbStartObs();
            // 
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // Set offsets: 
            //
            SpireBb_PhotOffsetAuto(debug);
            //
            //
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            // //
            // //
            // Execute  Peakup
            //
            SpirePeakup("PPeakup",ib,0,comVersion,pmodeVersion,smodeVersion,peakVersion,siamVersion,debug);
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activities )
            // //
            // // 
            // Reset OBSID and BBID:
            //
            SpireBbEndObs();
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

// SpireBbPcalFlash
//
// execute PCAL calibration
//
//  K.J. King
//
// 04 November 2008: 
//       added data_rate commands
//       added commands to setup detector sampling for flash, in case it is set differently (e.g. for parallel mode)
// 12 December 2008:  SPR-1088:  Modified flashMode input to allow ParPFlash
// 05/07/2009 KJK:
//         SPR-1593 - Added flashVersion and debug to input parameters
// 03/08/2009 SDS:
//         SCR-1768 - Added flash modes "PFlashEng","SFlashEng" for the input flashMode parameter
//         SCR-1587 - Set the DCU sampling to continuous after PCAL flash
// 29/09/2009 MP: SPR-SPIRE-2048
//       Fix bug with hardcoded SFlash for isBright, add SFlash_b.
// 27/10/2009 KK: added Pflash_b to allow bright source photomery PCAL flash
//
////////////////////////////////////////////////////////////////////////
block SpireBbPcalFlash SPIRE 10241 {
    string flashMode = "PFlash" in ["PFlash","PFlash_b","ParPFlash","SFlash","SFlash_b","PFlashEng","SFlashEng"];
    string flashVersion = "v00";
    int step = 0;
    bool debug = false;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB PCAL Flash started");
    SpireMsg(2,"          $Id:$");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP 
    hstr = SpireHexStr(step,4);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(" + hstr + ")");
    Spire_SET_OBS_STEP_RAW(step);
    //
    // Time synchronisation
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RESET_DRCU_COUNTERS_RAW()");
    Spire_RESET_DRCU_COUNTERS_RAW();
    delay(2);
    //
    // position SMEC, if necessary
    //
    if(flashMode == "SFlash" || flashMode == "SFlash_b") {
        // Move SMEC to HOME position
        int home = ilookup("SMEC.txt","HOME","ivalue");
        SpireSendDrcuCmd(0x90450000 + home,0);
        // set position
        SpireSendDrcuCmd(0x90490001,0);
        // move
        SpireSendDrcuCmd(0x90490000,0);
        // hold position
        delay(2);
    }
    //
    // Set up detector sampling
    //
    // SpireConfigDcuData(flashMode);
    //
    // execute flash
    //
    int tableId = ilookup("SpireTable_CommandLists.txt","Flash","TableId");
    //  number of table containing the flash command list
    int startIndex = ilookup("SpireTable_CommandLists.txt","Flash","Index");
    //  istart point in table containing the flash command list
    int nParams = ilookup("SpireTable_CommandLists.txt","Flash","NParms");
    //  number of parameters to the flash command list
    int lowBias = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"LowBias",flashVersion,debug);
    int highBias = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"HighBias",flashVersion,debug);
    int cycles = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"Cycles",flashVersion,debug);
    int period = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"Period",flashVersion,debug);
    int dcuFrame = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"DcuFrame",flashVersion,debug);
    int dcuSamples = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"DcuSamples",flashVersion,debug);
    int dcuDelay = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"DcuDelay",flashVersion,debug);
    int scuMode = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"ScuMode",flashVersion,debug);
    int scuSamples = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"ScuSamples",flashVersion,debug);
    {int}[] parms = [{lowBias},{highBias},{cycles},{period},{dcuFrame},{dcuSamples},{dcuDelay},{scuMode},{scuSamples}];
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM_RAW(" + tableId + "," + startIndex + "," + nParams + "," + parms + ")");
    Spire_RUN_VM_RAW(tableId,startIndex,nParams,parms);
    //  set datarate
    double rate = 0.0;
    rate = dlookup("Datarates.txt",flashMode,"DCU");
    rate = rate + dlookup("Datarates.txt",flashMode,"SCU");
    data_rate(rate);
    delay(period * cycles / 1000000 + 2);
    data_rate(0.0);
    //
    //
    // ..... completion .....
    //
    // flush data
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x5000)");
    Spire_FLUSH_FIFO_RAW(0x5000);
    delay(2);
    //
    // Set DCU sampling back to continuous
    SpireSendDrcuCmd(0x843d0000,0);
    sync();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB PCAL Flash ended");
    SpireMsg(1,"  ..PCAL Flash (" + (time() - t) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SetSmecFramerate.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set SMEC framerate 
//
// Note: Script calls the procedure SpireProc_Set_SmecFramerate.txt
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/31 V1.0: Initial version adapted from
//                  SpireBb_SetBsmFramerate (2009/02/15 V1.1)
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SetSmecFramerate SPIRE 14039 {
    int frate = 149; // Specifies the frame rate [Dec(Hex)]
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    message("4    " + time() + ": SpireBb_SetSmecFramerate started");
    message("4          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    delay(1);
    // //
    // //
    // Set framerate:
    //
    SpireProc_Set_SmecFramerate(frate,debug);
    // //
    // //
    // End BB:
    //
    SpireMsg(4,"    " + time() + ": BB SpireBb_SetSmecFramerate ended");
    //
}

// SpireBbJiggleId55
//
// $id$
//
// execute jiggle operations with VM table 55
//
// returns the actual time on-source
//
// 10/12/2008 V0.1: MP First version, adapted from Ken's SpireBbJiggle 
//                  (04 November 2008)
//
// 13 Aug 2009 KJK:
//     Created from SpireBbJiggle
//
double block SpireBbJiggleId55 SPIRE 14022 {
    string opsMode = "" in ["POF2","POF3","POF4"];
    int jiggleTable = 0; // number of jiggle table
    int itableID = 0x37; // Table ID to be uploaded 
    int startPosn = 0; // starting position in jiggle map
    int nPosns = 1; // number of jiggle positions to execute
    int nRepeats = 1; // number of times to repeat this jiggle operation
    int step = 0; // step number
    string opsVersion = "v00";
    string chopVersion = "v00";
    bool debug = false;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Jiggle started");
    SpireMsg(2,"          $Id:$");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP 
    hstr = SpireHexStr(step,4);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(" + hstr + ")");
    Spire_SET_OBS_STEP_RAW(step);
    //
    //  set up detectors for operations
    //
    //SpireConfigDcuData(opsMode);
    //
    // execute jiggle
    //
    // New setup of VM table Id:
    //
    //int id = ilookup("SpireTable_CommandLists.txt","JiggleMap","Id");
    //  number of table containing the jiggle command list
    int id = itableID;
    //
    // Original setup:
    //
    int index = ilookup("SpireTable_CommandLists.txt","JiggleMap","Index");
    //  istart point in table containing the jiggle command list
    int nParms = ilookup("SpireTable_CommandLists.txt","JiggleMap","Nparms");
    //  number of parameters to the jiggle command list
    int nChops = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"NChops",opsVersion,debug);
    //  number of chop cycles per jiggle position
    int tChop = SpireProc_GetTableEntryInt("SpireTable_ChopParams.txt","mode",opsMode,"Period",chopVersion,debug);
    //  period of chop cycle
    int dcuFrame = SpireProc_GetTableEntryInt("SpireTable_ChopParams.txt","mode",opsMode,"DcuFrame",chopVersion,debug);
    //  DCU Sample Mode
    int nDcu = SpireProc_GetTableEntryInt("SpireTable_ChopParams.txt","mode",opsMode,"DcuSamples",chopVersion,debug);
    //  number of DCU Samples per chop position 
    int tDelay = SpireProc_GetTableEntryInt("SpireTable_ChopParams.txt","mode",opsMode,"DcuDelay",chopVersion,debug);
    //  delay to start of DCU sampling
    int nBsm = SpireProc_GetTableEntryInt("SpireTable_ChopParams.txt","mode",opsMode,"BsmSamples",chopVersion,debug);
    //  number of BSM samples per chop position
    //
    //  issue VM command 
    //
    {int}[] parms = [{jiggleTable},{startPosn * 2},{nPosns * 2},{nChops},{tChop},{dcuFrame},{nDcu},{tDelay},{nBsm},{nRepeats}];
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM_RAW(" + id + "," + index + "," + nParms + "," + parms + ")");
    Spire_RUN_VM_RAW(id,index,nParms,parms);
    //  set datarate
    double rate = 0.0;
    rate = dlookup("Datarates.txt",opsMode,"DCU");
    rate = rate + dlookup("Datarates.txt",opsMode,"BSM");
    data_rate(rate);
    // calc time to perform a jiggle operation
    int nOps = nPosns * nChops * nRepeats;
    // Add 2 seconds to the estimated time before flushing the FIFOs 
    double opsTime = double(nOps) * double(tChop) / 1000000.0 + 2.0;
    // wait to end of jiggle operation
    delay(iceil(opsTime));
    data_rate(0.0);
    //
    // flush data
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x3000)");
    Spire_FLUSH_FIFO_RAW(0x3000);
    delay(2);
    double srcTime = double(nOps) * double(tChop) / 1000000.0;
    //
    // effective integration time per jiggle operation
    //
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Jiggle ended");
    SpireMsg(1,"  ..Jiggle (" + (time() - t) + " seconds)");
    //

    return srcTime;
}

// SpireConfigDcuData
//
// $Id:$
//
// Procedure to configure the DCU to generate detector data TM packets for a particular operating mode
//
// 04 November 2008:  first version
// 15/09/2009 KJK:
//          SPR Spire-1924: changed to use new SpireTable_....    cal tables
// 19/09/2009 KJK:
//          SPR Spire-1979: sampling/bias frequencies are now set according to whether the mode is photometer or spectrometer
//
procedure SpireConfigDcuData {
    string opsMode = "";
}{
    string detVersion = "v00";
    // Version in cal table SpireTable_DefaultParams.txt
    string pmodeVersion = "v00";
    // Version in cal table SpireTable_PhotModeParams.txt
    string smodeVersion = "v00";
    // Version in cal table SpireTable_SpecModeParams.txt
    bool debug = false;
    //
    // check inputs
    if(opsMode == "REDY") {
        error("SpireConfigDcuData: opsMode not allowed: REDY ");
    }
    // find out which table to use
    int defSize = table_size("SpireTable_DefaultParams.txt");
    int photSize = table_size("SpireTable_PhotModeParams.txt");
    int specSize = table_size("SpireTable_SpecModeParams.txt");
    string[] defMode = scolumn("SpireTable_DefaultParams.txt","mode");
    string[] photMode = scolumn("SpireTable_PhotModeParams.txt","mode");
    string[] specMode = scolumn("SpireTable_SpecModeParams.txt","mode");
    string table = "";
    string version = "";
    string biasMode = "";
    for(int k = 0 .. defSize - 1) {
        if(defMode[k] == opsMode) {
            table = "SpireTable_DefaultParams.txt";
            version = detVersion;
            biasMode = opsMode;
        }
    }
    for(int i = 0 .. photSize - 1) {
        if(photMode[i] == opsMode) {
            table = "SpireTable_PhotModeParams.txt";
            version = pmodeVersion;
            biasMode = "PHTSTBY";
        }
    }
    for(int j = 0 .. specSize - 1) {
        if(specMode[j] == opsMode) {
            table = "SpireTable_SpecModeParams.txt";
            version = smodeVersion;
            biasMode = "SPECSTBY";
        }
    }
    if(table == "") {
        error("SpireConfigDcuData: Unknown opsMode " + opsMode);
    }
    //
    message("4    " + time() + ":  SpireConfigDcuData started");
    message("4          $Id:$");
    //
    // fetch sampling values
    int biasmode = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",biasMode,"biasMode",detVersion,debug);
    int mclkdiv = SpireProc_GetTableEntryInt(table,"mode",opsMode,"mclkDiv",version,debug);
    int biasdiv = SpireProc_GetTableEntryInt(table,"mode",opsMode,"biasDiv",version,debug);
    int datamode = SpireProc_GetTableEntryInt(table,"mode",opsMode,"dcuDataMode",version,debug);
    //
    // stop DCU data generation, just to make sure
    SpireSendDrcuCmd(0x843e0000,0);
    //
    // select data mode
    SpireSendDrcuCmd(0x843c0000 + datamode,0);
    //
    // setup sampling
    if(biasMode=="PHTSTBY") {			// Photometer mode
        SpireSendDrcuCmd(0x84000000 + biasmode,0);
        SpireSendDrcuCmd(0x84190000 + mclkdiv,0);
        delay(1);
        SpireSendDrcuCmd(0x84180000 + biasdiv,0);
    } 
    if(biasMode=="SPECSTBY") {			// Spectrometer mode
        SpireSendDrcuCmd(0x84300000 + biasmode,0);
        SpireSendDrcuCmd(0x84390000 + mclkdiv,0);
        delay(1);
        SpireSendDrcuCmd(0x84380000 + biasdiv,0);
    } 
    // Set sampling to continuous
    SpireSendDrcuCmd(0x843d0000,0);
    //
    delay(1);
    message("4    " + time() + ":  SpireConfigDcuData ended");
    //
}

// SpireSOF12Pointing
//
// $id$
//
// This procedure calculates and returns the pointing parameters for the SOF1 and SOF2 observing modes  
//
// 03/02/2009: KJK
//          changed input interface to accept 2 sets of scan info in 
//          order to call SpirePointSpectrum correctly
//          now calls SpireProc_SFlash to get PCAL flash duration 
//          (including SMEC movement times)
// 25/08/2009: KJK
//        SPR Spire-1641: Needed new input parameters bsmModel and bsmVersion
// 03/09/2009: KJK
//        Added smecVersion input parameter
// 04/09/2009: MP v1 SPR-SPIRE-1763
//        Pass smecVersion to SpireBbSOF1End. 
// 04/09/2009: MP v2 SPR-SPIRE-1763
//       Add in move of BSM to home before PCAL flash       
// 05/09/2009: MP  SPR-SPIRE-1763
//       Move extra time for BSM movement into tFlash 
//       (needed for SpireSpectroRaster)  
// 14/09/2009 KJK:
//       SCR Spire-1953: updated call to SpireBbSOF1Init to pass smodeVersion
//24/09/2009 KJK:
//       SPR Spire-1978: updated calls to SpireSOF1Config and SpireSOF1End
// 29/09/2009 MP: SPR-SPIRE-2048
//       Fix bug with hardcoded SFlash for isBright. Fix bug with passing 
//       specVersion instead of smodeVersion to SOF1Init. Changed call to
//       SpirePointSpectrum. Bug in call to SpireBbSOF1Config.
// 20/10/2009 KJK: SPR Spire-2062:
//       Added call to SpireBbSmecInit in INIT_HOLD 
// 16/02/2010 KJK: SCR Spire-2341:
//       Updated to get Flash info from SpireTable_SpireParams rather than SpireParams
//       This required a additional input parameter - spireVersion
//  31/03/2010 KJK: SCR Spire-2459:
//       Added calls to SpireBb_SetSpecDetOffsets when necessary
//       Corrected to call SOF1 or SOF2 Config, Init and End scripts
//  20/07/2011 SDS: SCR Spire-2563
//        Replaced calls to OpsParms.txt with SpireTable_OpsParms.txt
//        Added opsVersion input parameter for the version of the entry in SpireTable_OpsParms.txt  
////////////////////////////////////////////////////////////////////////////
{int,int,int,int,int,int} procedure SpireSOF12Pointing {
    string opsMode = "SOF1" in ["SOF1","SOF2","SOF2_int"]; // operations mode
    string res1 = "H" in ["H","M","C","L"]; // resolution for set 1
    int nCycles1 = 0; // number of cycles to execute in set 1
    double tCycle1 = 0.0; // time for a cycle in set 1
    int scansPerCycle1 = 0; // number of scans in a cycle for set 1
    string res2 = "L" in ["H","M","C","L"]; // resolution for set 2
    int nCycles2 = 0; // number of cycles to execute in set 2
    double tCycle2 = 0.0; // time for a cycle in set 2
    int scansPerCycle2 = 0; // number of scans in a cycle for set 2
    int nMaps = 1; // total number of number of maps to perform
    int nFlashes = 0; // number of flashes per point
    double tFlashInterval = 0.0; // time between flashes
    bool isBright = false;
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string comVersion = "v00";
    string spireVersion = "v00";
    string smodeVersion = "v00";
    string smecVersion = "v00";
    string specVersion = "v00";
    string flashVersion = "v00";
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    bool debug = false;
}{
    int tBsm = 0;
    string version = "v00";
    // //
    // //
    // Set flash to isBright:  
    //
    string flashMode = "";
    if(isBright) {
        flashMode = "SFlash_b";
    } else {
        flashMode = "SFlash";
    }
    // //
    // //
    // Read BSM hold position from calibration table:  
    //
    string tabName05 = "SpireTable_BsmNominalSettings.txt";
    version = bsmVersion;
    string tabName = tabName05;
    string selCol = "model";
    string selVal = bsmModel;
    string tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // initial flash flag
    bool initFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",opsMode,"InitFlash",spireVersion,debug);
    // final flash flag
    bool endFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",opsMode,"EndFlash",spireVersion,debug);
    int jiggleTable = ilookup("OpsParms.txt",opsMode,"TableId");
    // Jiggle Table ID
    //int jiggleSize = ilookup("OpsParms.txt",opsMode,"TableSize");
    int jiggleSize = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"TableSize",opsVersion,debug);
    // Jiggle Table length 
    //int hScansPerCycle = ilookup("OpsParms.txt",opsMode,"NHScans");
    int hScansPerCycle = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"NHScans",opsVersion,debug);
    //int mScansPerCycle = ilookup("OpsParms.txt",opsMode,"NMScans");
    int mScansPerCycle = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"NMScans",opsVersion,debug);
    //int lScansPerCycle = ilookup("OpsParms.txt",opsMode,"NLScans");
    int lScansPerCycle = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"NLScans",opsVersion,debug);
    //
    int scanStart1 = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",res1,"ScanStart",specVersion,debug);
    int smecHome = ilookup("SpireTable_SmecNominalSettings.txt",version,"Home");
    tBsm = duration(SpireBb_BsmMove(hold_chop,hold_jigg,debug));
    int tFlash = duration(SpireProc_SFlash(flashMode,scanStart1,scanStart1,0,bsmVersion,smodeVersion,flashVersion,debug)) + tBsm;
    //
    // total time pointing
    int tp = 2;
    int nPoints = 0;
    for(int i = 0 .. jiggleSize - 1) {
        // move to  jiggle point i
        tp = tp + duration(SpireBbBsmMove(jiggleTable,i,0));
        // insert flashes between points if flashes are required inside each point
        if(i > 0) {
            if(nFlashes > 0 || i % nPoints == 0) {
                tp = tp + tFlash;
                initFlash = true;
                endFlash = true;
            }
        }
        // observe jiggle point i
        tp = tp + duration(SpirePointSpectrum(res1,nCycles1,tCycle1,scansPerCycle1,res2,nCycles2,tCycle2,scansPerCycle2,tFlashInterval,0,bsmVersion,smodeVersion,specVersion,flashVersion,isBright,debug));
        if(opsMode != "SOF1" && isBright) {
            tp = tp + duration(SpireBb_SetSpecDetOffsets(debug));
        }
        // insert flashes every n points
        if(i == 0) {
            nPoints = ifloor(tFlashInterval / double(tp));
            if(nPoints == 0) {
                nPoints = jiggleSize;
            }
        }
        if(debug) {
            debug_print("tp=" + tp);
        }
    }
    //
    // minimum slew time
    int tSlewMin = duration(SpireBbObsConfig(0)) + 2;
    if(opsMode == "SOF1") {
        tSlewMin = tSlewMin + duration(SpireBbSOF1Config(opsMode,res1,isBright,comVersion,smodeVersion,smecVersion,specVersion,debug));
    } else {
        tSlewMin = tSlewMin + duration(SpireBbSOF2Config(opsMode,res1,isBright,comVersion,smodeVersion,smecVersion,specVersion,debug));
    }
    //
    // time for Initial Hold
    int tInitHold = duration(SpireBbSmecInit(res1,bsmVersion,smecVersion,specVersion,debug)) + 2;
    if(opsMode == "SOF1") {
        tInitHold = tInitHold + duration(SpireBbSOF1Init(smodeVersion,isBright,debug));
    } else {
        tInitHold = tInitHold + duration(SpireBbSOF2Init(smodeVersion,isBright,debug));
    }
    if(initFlash) {
        if(opsMode != "SOF1" && isBright) {
            tInitHold = tInitHold + duration(SpireBb_SetSpecDetOffsets(debug));
        }
        tInitHold = tInitHold + duration(SpireProc_SFlash(flashMode,scanStart1,scanStart1,0,bsmVersion,smodeVersion,flashVersion,debug));
    }
    //
    // time for Final Hold 
    int tFinalHold = 2;
    if(opsMode == "SOF1") {
        tFinalHold = tFinalHold + duration(SpireBbSOF1End(res1,isBright,bsmModel,bsmVersion,comVersion,smodeVersion,smecVersion,specVersion,debug));
    } else {
        tFinalHold = tFinalHold + duration(SpireBbSOF2End(res1,isBright,bsmModel,bsmVersion,comVersion,smodeVersion,smecVersion,specVersion,debug));
    }
    if(endFlash) {
        tFinalHold = tFinalHold + duration(SpireProc_SFlash(flashMode,scanStart1,scanStart1,0,bsmVersion,smodeVersion,flashVersion,debug)) + duration(SpireBb_BsmMove(hold_chop,hold_jigg,debug));
    }
    //
    // raster variables
    //
    int nFlash = 0;
    if(nFlashes > 0 || ifloor(tFlashInterval / double(tp)) == 0) {
        // flashes within a jiggle point or raster point
        nFlash = 1;
    } else {
        nFlash = ifloor(tFlashInterval / double(tp));
    }

    return {tSlewMin,tInitHold,tFinalHold,tp,tFlash,nFlash};
}

// SpireProc_Set_Scal
//
// $id$
//
// This procedure switches on/off the SCAL while optionally sampling the detectors
// 
// The instrument should be in SPECSTBY mode before execution of this observation
// Final Configuration: Instrument is still in SPECSTBY mode after execution of this observation
//
// 26/08/2009 KJK: First Version
//
procedure SpireProc_Set_Scal {
    string scal = "Default" in ["Default","SCAL2","SCAL4","None"]; // SCAL status
    int scalTemp = -1; // SCAL temperature, if you want to override the default
    int stabilisationTime = 120; // time (secs) to allow SCAL/Detectors to stabilise before starting observations
    bool sampleDetectors = true; // sample detectors during the stabilisation period (assumes detector sampling rate/mode is already configured)
    string scalVersion = "v00";
    string detVersion = "v00";
    bool debug = false;
}{
    // start detector sampling, if necessary
    if(sampleDetectors) {
        SpireBb_StartDcuData();
    }
    delay(2);
    //
    //  Switch on SCAL
    if(scal == "Default") {
        // read default status
        scal = SpireProc_GetTableEntryString("SpireTable_DefaultParams.txt","mode","SPECSTBY","scalVm",scalVersion,debug);
    }
    SpireBbSetScal(scal,scalTemp,scalVersion,debug);
    //
    // ----------------
    // Stabilisation
    // ----------------
    delay(stabilisationTime);
    //
    if(sampleDetectors) {
        SpireBb_StopDcuData();
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndObsAll.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of all AOTs
// (i.e. astronomer, engineering, and calibration ones) 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/01/21 V1.0: Merged BB using SpireBb_EndObs (2008/11/12 V0.2) and
//                  SpireBbEndObs (17/11/2008 KJK). This will also replace 
//                  part of the EndObs stuff done currently in 
//                  SpireBbPOF2End (v 1.1 2006/08/10) and 
//                  SpireBbPOF3End (v 1.3 2007/08/02) and 
//                  SpireBbPOF5End (v 1.1 2006/08/10)
//                  Script includes HSPOT messages and has an 
//                  added sync() statement to round up total duration (SxR?).
// 2009/01/30 V1.1: Changed entries in messages related to 'RAW'. Changed
//                  some comments. Removed last delay(1) before new sync().
// 2009/05/05 V1.2: Move commands into low level procedure 
//                  SpireProc_Set_EndObsAl which will be called here. 
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndObsAll SPIRE 14023 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // End observations: 
    //
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

block Pacs_CcuMonitorStartRecycle PACS 2102 {
}{
    PacsCcuMonitorPeriodRecycle();
    sync();
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartDcuMcuData.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to start generation of detector data (TM packets) plus MCU 
// (here only BSM and SMEC) data.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/31 V0.1: Initial version adapted from 
//                  SpireBb_StartDcuData (2009/02/18 V1.0)
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartDcuMcuData SPIRE 14037 {
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_StartDcuMcuData started");
    SpireMsg(2,"          $Id:$");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Start DCU data:
    //
    SpireProc_Set_StartDcuData();
    SpireProc_Set_StartMcuData();
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_StartDcuMcuData ended");
    SpireMsg(1,"  ..StartDcuMcuData (" + (time() - t) + " seconds)");
}

// $Id:
// Purpose       : Set BBID to its required value to indicate the end
//                 of current BB execution (see FIRST-FSC-DOC-0200) 
//                 and Delay Science Block afetr Cal block
//
// CUS script    : Vanessa Doublier-Pritchard
//
// Input arguments: delay
//
// Description   : BBID will be set to its specicifc delay
//
// Comments      : Needed for SCR PACS-2039
//
// Version       : 16-sep-2009 1.0 VD Creation
//
block PacsBbDelayScience PACS 1103 {
    int nDelay = 4;
}{
    // Write BBID to DEC/MEC
    Pacs_DMC_SET_BBID($BBID);
    delay(nDelay);
    Pacs_DMC_SET_BBID(0x40000000);
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_Cal_ScannedSmecCrossRaster
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Spec Scanned SMEC Cross Raster'
//
//         in *custom_map_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// S.D.Sidher:
// 2011/05/10 V0.1: Initial version adapted from
//                  SpireSpectro_CalGCO_ScannedSmecBeamProfile 
//                  (SCR-SPIRE-3476) 
//
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in SPECSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for all three arrays and could be taken from following cal table: 
//   SpireTable_SpecModeParams.txt
//
//  3) That no gyro reconstruction is available 
//
//  4) SMEC scan parameters can be read from calibration table:
//     SpireTable_Spectrometer.txt
// 
//  5) SMEC move parameters can be read from calibration table:
//     SpireTable_SpecSmecNominalSettings.txt
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_Cal_ScannedSmecCrossRaster {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; //NAIF identifier: put '0' to use RA/DEC, or correct 'NAIFID'
    bool isBright = false; // Use settings for bright source (==tick)
    /* */
    string ib = "S24_0"; // Central aperture (defined in SIAM) of raster
    double d1 = 4.0; // Angular stepsize along Y/Z axis [arcsec]
    int m = 5; // Number of points in raster along Y/Z [odd number! Only symmetric cross-raster allowed]
    string resolution = "M" in ["L","M","H","C"]; // Resolution (low, medium, high,calibration)
    int nscans = 1; // Number of SMEC scans (back+forth==1)
    double bsmFrateInput = 15.98; // Specifies the BSM framerate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    double smecFrateInput = 238.08; // Specifies the SMEC framerate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParam
    string version03 = "v00"; // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial"; // Model in cal table SpireTable_BsmNominalSettings 
    string version05 = "v00"; // Version in cal table SpireTable_Spectrometer
    string version06 = "v00"; // Version in cal table SpireTable_SmecNominalSettings
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = false;
    bool fts = !phot;
    //
    // Start timing of script:
    int start = time();
    //
    // First obsstep (start at 1):
    int obsstep = 1;
    //
    // Count raster points (needs to start at 0): 
    int raster_counter = 0;
    //
    // DCU data mode (0 == Full photometer; 4 == Full spectrometer)
    int dcumode = 4;
    //
    // Angular stepsize along Z axis [arcsec]:
    double d2 = d1;
    // NOTE: Script works only for equidistant raster points in both axes:
    //
    // Number of points in each arm of the cross raster
    int n = m;
    // NOTE: Script works only for same number of points in both Y/Z directions
    //
    bool setFramerate = true;
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    string tabName05 = "SpireTable_Spectrometer.txt";
    string tabName06 = "SpireTable_SmecNominalSettings.txt";
    //
    // Currently hardcoded parameter:
    // Is (==tick) the DCU currently sampled? 
    bool dcuData = false;
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS35";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "SEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Read SMEC home position from calibration file:
    //
    tarCol = "Home";
    tabName = tabName06;
    selVal = version06;
    int smecHomePosn = ilookup(tabName,selVal,tarCol);
    // //
    // //
    // Retrieve SMEC scanStart parameters from calibration table: 
    // 
    tarCol = "ScanStart";
    selVal = "ResChar";
    tabName = tabName05;
    version = version05;
    int scanStart = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt",selVal,resolution,tarCol,version,debug);
    // //
    // //
    // Retrieve BSM SPECSTBY framerate from calibration table: 
    // 
    version = version02;
    tabName = tabName02;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "bsmFrameRate";
    int bsmFrameRate = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    double bsmFrameRateHz = 0.0;
    if(bsmFrameRate != 0) {
        bsmFrameRateHz = 1000000.0 / (double(bsmFrameRate) * 420.0);
    }
    //
    // Compare nominal with input BSM framerate:
    // 
    int frate = SpireProc_CalcParam_BsmFramerate(bsmFrateInput,debug);
    if(debug) {
        debug_print("frate = " + frate);
        debug_print("bsmFrameRate = " + bsmFrameRate);
    }
    if(frate == bsmFrameRate) {
        if(debug) {
            debug_print("Do not set the BSM framerate during slew.");
        }
        setFramerate = false;
    }
    // //
    // //
    // Setup parameters for BSM chopping movement: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version03;
    tabName = tabName03;
    // Name of column for selecting: 
    selCol = "model";
    // Value of 'string' selector:
    selVal = model;
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Retrieve SMEC SPECSTBY framerate from calibration table: 
    // 
    version = version01;
    tabName = tabName01;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "smecFrameRate";
    int smecFrameRate = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    double smecFrameRateHz = 0.0;
    if(smecFrameRate != 0) {
        smecFrameRateHz = 1000000.0 / (double(smecFrameRate) * 420.0);
    }
    if(debug) {
        debug_print("Nominal SMEC sampling rate is: " + smecFrameRateHz + " [Hz]");
    }
    // //
    // //
    // Calculate commanded framerates for SMEC+BSM from user input: 
    int bsmFrate = SpireProc_CalcParam_McuFramerate(bsmFrateInput,debug);
    int smecFrate = SpireProc_CalcParam_McuFramerate(smecFrateInput,debug);
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    // 
    int tslewmin = duration(SpireBb_StartScannedSmecBeamProfile(obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,setFramerate,frate,smecFrate,debug));
    // 
    // BBs carried out when the pointing is reached:
    //
    int tinithold = duration(SpireBbSmecInit(resolution,version03,version06,version05,debug)) + duration(SpireBb_SetSmecFramerate(smecFrate,debug)) + duration(SpireBb_SmecMove(scanStart,smecHomePosn,debug)) + duration(SpireBb_SetupSmecScan(resolution,version05,debug));
    //
    // BB carried out during pointing:
    // 
    int tp_np = duration(SpireBb_SmecScan(resolution,nscans,version05,debug)) + duration(SpireBb_SpecOffsetAuto(dcuData,debug)) + duration(SpireBb_SetObsStep(9999,debug)) + duration(SpireBb_StartDcuMcuData()) + duration(SpireBb_StopDcuMcuData());
    //
    // BB carried out at the end:
    //
    int tfinalhold = duration(SpireBb_EndScannedSmecBeamProfile(resolution,hold_chop,hold_jigg,smecHomePosn,isBright,version01,version02,version05,debug));
    // //
    // //
    debug_print("tslewmin = " + tslewmin);
    debug_print("tinithold = " + tinithold);
    debug_print("tpointing normal= " + tp_np);
    debug_print("tfinalhold = " + tfinalhold);
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                              */
    // ****************************************************** */
    // //
    // //
    // Fixed parameters for pointing mode:
    //   
    bool fixed = false;
    // Pattern orientation (true==sky; false==array)
    double patt = 90.0;
    // Rotation angle of the pattern
    double yoffset = 0.0;
    // Offset of pattern in the direction of the +Y
    double zoffset = 0.0;
    // Offset of pattern in the direction of the +Z
    int thold = 0;
    // The duration of the hold when nhold>0.
    int nhold = 0;
    // Number of nods or raster points or scan lines before
    //              // performing a hold.
    double pattnod = 0.0;
    //
    double chopthrow = 2.0;
    //
    int nnod = 1;
    //
    int knod = 0;
    //
    int nload = 0;
    //
    int tloadmin = 0;
    //
    // //
    // //
    // Calculate array of points:
    //
    {double[],double[]} array = SpireProc_CalcParam_CrossRasterPositions(m,n,d1,d2,debug);
    double[] zarray = array{0};
    double[] yarray = array{1};
    int nump = length(yarray);
    // //
    // //
    // //
    // Set pointing vector:
    //
    int[] tpv = [0];
    for(int index = 0 .. nump - 1) {
        tpv[index] = tp_np;
        index = index + 1;
    }
    //
    // //
    // //
    if(debug) {
        debug_print("timing vector : " + tpv);
        debug_print("yarray: " + yarray);
        debug_print("zarray: " + zarray);
    }
    //
    // Calculate slew times in pointing mode:
    //
    int[] ts_tr = custom_map_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,fixed,patt,yoffset,zoffset,yarray,zarray,tpv,pattnod,chopthrow,nnod,knod,tloadmin,nload,thold,nhold);
    debug_print("Pointing vector : " + ts_tr);
    //
    if(debug) {
        debug_print("Pointing vector : " + ts_tr);
    }
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC              */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Prepare observation: 
            //     
            SpireBb_StartScannedSmecBeamProfile(obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,setFramerate,frate,smecFrate,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // Initialise SMEC (close loop) (new for SPR-SPIRE-2062)
            //
            SpireBbSmecInit(resolution,version03,version06,version05,debug);
            // //
            // //
            // Set SMEC framerate (== SMEC sampling rate) to input:
            //
            SpireBb_SetSmecFramerate(smecFrate,debug);
            // //
            // //
            // Move SMEC to start of scan 
            //
            SpireBb_SmecMove(scanStart,smecHomePosn,debug);
            // //
            // //
            // Setup SMEC Scan:
            //
            SpireBb_SetupSmecScan(resolution,version05,debug);
            //
            //delay(tinithold);
        }
        if(state[0] == 3) {
            // STATE = POINT (spacecraft is at nominal RA,DEC (staring, raster))
            //
            //delay(tp);
            // //
            // //
            // 
            // //
            // //
            // Reset timing at first raster point:
            if(obsstep == 1) {
                start = time();
            }
            // //
            // //
            // Set Obs step:
            //
            SpireBb_SetObsStep(obsstep,debug);
            // //
            // //
            // Set offsets at raster point:
            //
            SpireBb_SpecOffsetAuto(dcuData,debug);
            // //
            // //
            // Start DCU+MCU data generation:
            //
            SpireBb_StartDcuMcuData();
            // //
            // //
            // Perform SMEC scan:
            //
            SpireBb_SmecScan(resolution,nscans,version05,debug);
            // //
            // //
            // Stop DCU+MCU data generation:
            //
            SpireBb_StopDcuMcuData();
            // //
            // //
            // Increase obsstep parameter for next point:
            //
            obsstep = obsstep + 1;
            //
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ("sky" observation ends, performing final activities )
            // //
            // //
            // End observation:
            //
            SpireBb_EndScannedSmecBeamProfile(resolution,hold_chop,hold_jigg,smecHomePosn,isBright,version01,version02,version05,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END (end of the pointing/commanding part of the code)
            //
        }
    }
}

// SpireEngPTCThermistorOnwithSubK
//
// $id$
//
// This observation switches on the PTC with SUBKTEMP control first before switching to control with thermistors TC1, TC2 or TC3
// 
// The instrument should be in PHOTSTBY mode before execution of this observation
// Final Configuration: Instrument is still in PHOTSTBY mode after execution of this observation
//
//
// 23/11/2009 SDS: First Version 0.1 
//
obs SpireEngPTCThermistorOnwithSubK {
    int stabilisationTimeSubK = 1200; // time (secs) to allow detectors to stabilise after PTC SUBK VM
    int stabilisationTimeThermistor = 300; // time (secs) to allow detectors to stabilise after starting PTC Thermistor VM (Detector data will also be stopped at this time)
    bool sampleDetectors = true; // sample detectors during the stabilisation period
    string ptcVersionSubK = "v03";
    string ptcVersionThermistor = "v04";
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int t = duration(SpireBbStartObs()) + duration(SpireProc_PTCOn(stabilisationTimeSubK,sampleDetectors,ptcVersionSubK,debug)) + duration(SpireBb_PhotOffsetAuto(debug)) + duration(SpireBb_StartDcuData()) + duration(SpireBbStartPtc(stabilisationTimeThermistor,ptcVersionThermistor,debug)) + duration(SpireBb_StopDcuData()) + duration(SpireBbEndObs());
    int[] ts = no_pointing(true,0,0,t);
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            SpireBbStartObs();
            SpireProc_PTCOn(stabilisationTimeSubK,sampleDetectors,ptcVersionSubK,debug);
            SpireBb_PhotOffsetAuto(debug);
            SpireBb_StartDcuData();
            SpireBbStartPtc(stabilisationTimeThermistor,ptcVersionThermistor,debug);
            SpireBb_StopDcuData();
            SpireBbEndObs();
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndLoadCurvePcalOn.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of 
// SpirePhoto/Spectro_Cal_LoadCurvePcalOn.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V1.0: Initial version adapted from
//                  SpireBb_EndBsmAngleCal (2009/05/05 V1.2) and
//                  SpirePhoto_Cal_LoadCurvePcalOn (2009/04/01 V0.1).
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndLoadCurvePcalOn SPIRE 14061 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndLoadCurvePcalOn reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set instrument back to Phot/Spec-STBY:
    //
    if(phot) {
        SpireProc_Set_PhotMode("PHTSTBY",isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    }
    // //
    // //
    // End observation:
    //
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndLoadCurvePcalOn reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

// SpireStartDcuData
//
// $Id:$
//
// Procedure to start generation of detector data TM packets appropriate to the operating mode 
//
// 04 November 2008: 
//            added command to set DCU mode to continuous sampling
//            added data_rate command
//            changed to receive operating mode rather than data mode as a parameter
//            now calls SpireConfigDcuData to set up detectors
//
//
procedure SpireStartDcuData {
    string opsMode = "";
}{
    string version = "v00";
    bool debug = false;
    message("4    " + time() + ":  SpireStartDcuData started");
    message("4          $Id:$");
    // setup detectors
    SpireConfigDcuData(opsMode);
    // start data collection
    SpireSendDrcuCmd(0x843e0001,0);
    //  set datarate
    double rate = 0.0;
    rate = SpireProc_GetTableEntryDouble("SpireTable_Datarates.txt","mode",opsMode,"DCU",version,debug);
    data_rate(rate);
    //
    delay(1);
    message("4    " + time() + ":  SpireStartDcuData ended");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_BiasFreqSampFreq.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to translate user input in Hz for bias frequency and 
//  sampling rate into nearest Hex values for mclkdiv and biasdiv
// 
//  Adapted from: Proc_SetBias.txt (v1.4 2008/01/31 20:24:35)
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/05/02 V0.1: Initial version 
// 2008/06/09 V0.2: Changes to output printing and input values 
// 2008/06/10 V0.3: Change formula to calculate mclkdiv according to
//                  S060719_SAp-SPIRE-CCa-076-02_I1.3_DRCU-DPU-ICD.pdf
// 2008/08/15 V0.4: Add extra parameter to keep track of different
//                  boundary for biasdiv for photometer and FTS 
// 2009/01/31 V1.0: Add debug_print option.
//
///////////////////////////////////////////////////////////////////////////
//
int[] procedure SpireProc_CalcParam_BiasFreqSampFreq {
    double freq0 = 130.2; // Bias frequency (Hz)
    double freq1 = 18.6; // Sampling frequency 
    bool fts = false; // FTS or photometer limits? 
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Calculate mclkdiv and biasdiv based on user input in Hz:
    //
    // Master clock divisor, which specifies bias freq:
    // int mclkdiv = iround(1.0E7 / (512.0 * (freq0 + 1.0)));
    int mclkdiv = iround(1.0E7 / (512.0 * freq0)) - 1;
    //
    // Check boundaries:
    //
    if(mclkdiv < 64) {
        mclkdiv = 64;
    }
    if(mclkdiv > 511) {
        mclkdiv = 511;
    }
    //
    // Sampling divisor, which specifies sampling rate:
    int biasdiv = iround(freq0 / freq1) - 1;
    // //
    // //
    // Check boundaries:
    //
    int biasdiv_lim = 2;
    if(fts) {
        biasdiv_lim = 1;
    }
    //
    if(biasdiv < biasdiv_lim) {
        biasdiv = biasdiv_lim;
    }
    if(biasdiv > 255) {
        biasdiv = 255;
    }
    // //
    // //
    // Calculate Hz values of commanded frequencies:
    //
    double mclkdivHz = 1.0E7 / (512.0 * double(mclkdiv + 1));
    double biasdivHz = 1.0 / (double(biasdiv) + 1.0) * mclkdivHz;
    // //
    // //
    // Printout:
    //
    if(debug) {
        debug_print("Input values bias/samp. frequency: " + freq0 + " " + freq1);
        debug_print("Output values mclkdiv/biasdiv [raw]: " + mclkdiv + " " + biasdiv);
        debug_print("Output values mclkdiv/biasdiv [Hz]: " + mclkdivHz + " " + biasdivHz);
    }
    // //
    // //
    // Return required values:
    //

    return [mclkdiv,biasdiv];
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndBsmPcalFlash.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of SpireProc_Exec_BsmPcalFlash
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V1.0: Initial version adapted from
//                  SpireBb_EndBsmAngleCal (2009/05/05 V1.2),
//                  SpirePhoto_Cal_BsmPcalFlash (2009/03/04 V1.3), and
//                  SpireSpectro_Cal_BsmPcalFlash (2009/03/04 V0.1)
// 2009/05/07 V1.1: Set dcuFrameNumber and scuFrameNumber back to continuous
//                  to unset setting passed to VM. 
// 2009/06/05 V1.2: Replace Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd 
//                  as requested in SPR-1482.
// 2009/07/12 V1.3: Set SMEC framerate back to nominal. (SPR-SPIRE-1551).
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndBsmPcalFlash SPIRE 14043 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    int hold_chop = 37632; // Chop hold position [Dec(Hex)]
    int hold_jigg = 39520; // Jiggle hod position [Dec(Hex)]
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndBsmPcalFlash reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set obsstep back to 0:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP(0)");
    Spire_SET_OBS_STEP(0);
    // //
    // //
    // Set instrument back to Phot/Spec-STBY:
    //
    if(phot) {
        SpireProc_Set_PhotMode("PHTSTBY",isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Set number of DCU frames to continuous:
    //
    int dcuFrameNumber = 0;
    if(phot) {
        dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","PHTSTBY","dcuFrameNumber","v00",debug);
    } else {
        dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuFrameNumber","v00",debug);
    }
    //
    SpireSendDrcuCmd(0x843d0000 + dcuFrameNumber,0);
    // //
    // //
    // Set number of SCU frames to continuous:
    //
    int scuFrameNumber = 0;
    if(phot) {
        scuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","PHTSTBY","scuFrameNumber","v00",debug);
    } else {
        scuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","scuFrameNumber","v00",debug);
    }
    SpireSendDrcuCmd(0xa0840000 + scuFrameNumber,0);
    delay(1);
    // //
    // //
    // Set SMEC framerate (== SMEC sampling rate) back to SPEC_STBY:
    // (Note, hardcoded version to go back to STBY)
    //
    if(!phot) {
        int smecFrameRate = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","smecFrameRate","v00",debug);
        SpireProc_Set_SmecFramerate(smecFrameRate,debug);
    }
    // //
    // //
    // End observation:
    //
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndBsmPcalFlash reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

// SpireProc_SFlash
//
// Execute a PCAL: flash for spectrometer modes
// This procedure ensures the SMEC is located at the Home position for the duration of the flash
// It moves the SMEC to the Home position from the current position and returns it to the end position
// The SMEC scan speed may also be changed
//
// The BSM is assumed to be at its Hold position
//
//  K.J. King
//
// 27/01/2009: (KJK) First Version
// 18/02/2009: (MP) Changed call to updated SpireBb_PcalFlash which does 
//                      no longer set the data_rate.      
// 03/09/2009 KJK: 
//       Now sets up BSM and SMEC sampling to fix SPR-1763 (Problem1)
//       Required additional version input parameters
//
procedure SpireProc_SFlash {
    string flashMode = "SFlash";
    int smecCurrPosn = 1000; // Current SMEC position
    int smecEndPosn = 1000; // End SMEC position
    int step = 0;
    string bsmVersion = "v00";
    string smecVersion = "v00";
    string flashVersion = "v00"; // flash parameters version 
    bool debug = false;
}{
    string version = "v00";
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    // Start
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": Proc SFlash started");
    SpireMsg(2,"          $Id: $");
    //
    // move to Home position
    //
    SpireBb_SmecMove2Home(smecCurrPosn,debug);
    //
    // #################
    // Set MCU Data sampling
    // #################
    SpireBbSetBsmSampling(flashMode,bsmVersion,debug);
    SpireBbSetSmecSampling(flashMode,smecVersion,debug);
    //
    // execute flash
    //
    // fetch flash parameters
    int id = ilookup("CommandLists.txt","Flash","Id");
    //  number of table containing the flash command list
    int index = ilookup("CommandLists.txt","Flash","Index");
    //  istart point in table containing the flash command list
    int nParms = ilookup("CommandLists.txt","Flash","Nparms");
    //  number of parameters to the flash command list
    int lowBias = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"LowBias",flashVersion,debug);
    int highBias = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"HighBias",flashVersion,debug);
    int cycles = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"Cycles",flashVersion,debug);
    int period = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"Period",flashVersion,debug);
    int dcuMode = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"DcuFrame",flashVersion,debug);
    int dcuSamples = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"DcuSamples",flashVersion,debug);
    int dcuDelay = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"DcuDelay",flashVersion,debug);
    int scuMode = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"ScuMode",flashVersion,debug);
    int scuSamples = SpireProc_GetTableEntryInt("SpireTable_Flash.txt","Mode",flashMode,"ScuSamples",flashVersion,debug);
    //
    //  calculate datarate during flash
    double rate = 0.0;
    rate = dlookup("Datarates.txt",flashMode,"DCU");
    rate = rate + dlookup("Datarates.txt",flashMode,"SCU");
    rate = rate + dlookup("Datarates.txt",flashMode,"BSM");
    //
    // make flash
    SpireBb_PcalFlash(id,index,nParms,lowBias,highBias,cycles,period,dcuMode,dcuSamples,dcuDelay,scuMode,scuSamples,step,debug);
    //
    // set datarate after flash
    rate = dlookup("Datarates.txt",flashMode,"BSM");
    data_rate(rate);
    //
    // move to End posn
    int smecHomePosn = ilookup("SpireTable_SmecNominalSettings.txt",version,"Home");
    SpireBb_SmecMove(smecEndPosn,smecHomePosn,debug);
    //
    // finish
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": Proc SFlash ended");
    SpireMsg(1,"  Proc SFlash (" + (time() - t) + " seconds)");
}

// Missionphase  : 
//
// Purpose       : Set gain "HIGH" or "LOW" for the BOLO electronics
//                  
//                 
//
// TCL author    : 
// TCL file      : tm_phot_set_gain.tcl
// CUS author    : 
// Script file   : PHOT_set_gain.txt 
//
// Input arguments
// type    name         description
//
// Return values
// Type    Name      Default      Description
//
// Description   : This script will activate the LOW or HIGH gain modes
//
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : 
// 
// History       : 0.1 19-apr-2005 DAC.
// 
int[] procedure PHOT_set_gain {
    string set_gain = "LOW" in ["LOW","HIGH"]; // Set electronics gain
}{
    // Define variables to communicate various durations to HSPOT.
    // NOTE: all time variables in units of number of ramps (SPEC) or
    //       number of readouts (BOLO). The calling program must convert this
    //       count into actual duration in true time units [seconds].
    //       SRC, REF, CAL, OVR stand for time spent on SRC, REF (on sky),
    //       CAL source, and overheads (wait for something). Total
    //       duration is given by duree_num. If no error, this duration
    //       must be equal to the sum of all others
    int duree_num = 0;
    int duree_SRC = 0;
    int duree_REF = 0;
    int duree_CAL = 0;
    int duree_OVR = 0;
    int time_start = time();
    Pacs_BOLC_SET_GAIN(set_gain);
    // Time spent
    int duree_TCs = time() - time_start;
    duree_OVR = duree_TCs;
    duree_num = duree_OVR;
    // Return the array of times
    int[] time_array = [duree_num,duree_SRC,duree_REF,duree_CAL,duree_OVR];
    sync();

    return time_array;
}

//
// 25-Mar-2010 SDS - First Version
//
block SpireBb_StartMcuData SPIRE 3419 {
}{
    SpireProc_Set_StartMcuData();
    sync();
}

// SpireSpectro_Cal_Sample
//
// $id$
//
// This observation samples detector data while staring at a point on the sky. 
// It is based on the POF5 observing mode and configires the detectors as for obsMode=POF5_S_N
// 
// The instrument should normally be in SPECSTBY mode before execution of this observation
// Final Configuration: Instrument is still in SPECSTBY mode after execution of this observation
//
//
// 01/09/2009 KJK: First Version  (SCR Spire-2138)
//
// 16/11/2009 SDS: Removed redundant input parameter phortVersion (see SCR Spire-2138)
// 18/11/2009 SDS: Renamed to SpireSpectro_Cal_Sample (previous name SpireSpectroSample - see SCR Spire-2138)
obs SpireSpectro_Cal_Sample {
    double ra = 0.0 in [0.0,360.0]; // RA of Target
    double dec = 0.0 in [-90.0,90.0]; // DEC of Target
    int naifid = 0; // NAIF identifier
    int observingTime = 120; // Time (secs) to produce detector data
    bool initFlash = false; // Flash at start of observation?
    bool endFlash = false; // Flash at end of observation?
    bool isBright = false;
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParms
    string opsVersion = "v00";
    string flashVersion = "v00";
    string smodeVersion = "v00"; // Version in cal table SpireTable_SpecModeParams
    string specVersion = "v00"; // Version in cal table SpireTable_Spectrometer
    string comVersion = "v00";
    string smecVersion = "v00";
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    string obsMode = "SOF1";
    string res1 = "H";
    string ib = SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode",obsMode,"Boresight",opsVersion,debug);
    int smecHomePosn = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"Home");
    int tFlash = duration(SpireProc_SFlash("SFlash",smecHomePosn,smecHomePosn,0,bsmVersion,smodeVersion,flashVersion,debug));
    int tSlewMin = duration(SpireBb_StartObsAll(obsMode)) + duration(SpireBbSOF1Config(obsMode,res1,isBright,comVersion,smodeVersion,smecVersion,specVersion,debug)) + 2;
    int tInitHold = duration(SpireBbSOF1Init(smodeVersion,isBright,debug)) + duration(SpireBbStartDcuData("Scan")) + 2;
    if(initFlash) {
        tInitHold = tInitHold + tFlash;
    }
    int tFinalHold = duration(SpireBbSOF1End(res1,isBright,bsmModel,bsmVersion,comVersion,smodeVersion,smecVersion,specVersion,debug)) + duration(SpireBbStopDcuData()) + 2;
    if(endFlash) {
        tFinalHold = tFinalHold + tFlash;
    }
    int tp = observingTime;
    int tSerendipity = duration(SpireBbSpecSerendipity(obsMode,0));
    // minimum time for a serendipity observation
    //
    // Set pointing mode:
    //
    int[] ts = basic_fine_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,0.0,0.0,tp);
}{
    int tslew = ts[1];
    // slew time
    string tstr = "";
    // time string
    int otf = 0x8000;
    // On Target Flag
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // ***********************  SLEWING
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Slewing to start position");
            // set up observation parameters
            SpireBb_StartObsAll(obsMode);
            // perform serendipity operation if possible
            if(tslew > tSerendipity + tSlewMin) {
                SpireBbSpecSerendipity(obsMode,tslew - tSlewMin - 2);
            }
            // configure instrument for operations
            SpireBbSOF1Config(obsMode,res1,isBright,comVersion,smodeVersion,smecVersion,specVersion,debug);
        }
        if(state[0] == 2) {
            // ***********************  INITIAL HOLD          
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Initialising Instrument");
            // initialise instrument
            SpireBbSOF1Init(smodeVersion,isBright,debug);
            // calibrate if necessary
            if(initFlash) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireProc_SFlash("SFlash",smecHomePosn,smecHomePosn,otf,bsmVersion,smodeVersion,flashVersion,debug);
            }
            SpireMsg(2,"    " + tstr + " Sampling Started");
            SpireBbStartDcuData("Scan");
        }
        if(state[0] == 3) {
            // ***********************  POINTING
        }
        if(state[0] == 5) {
            // ***********************  FINAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Reconfiguring Instrument");
            SpireMsg(2,"    " + tstr + " Sampling Stopped");
            SpireBbStopDcuData();
            // calibrate if necessary
            if(endFlash) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireProc_SFlash("SFlash",smecHomePosn,smecHomePosn,otf,bsmVersion,smodeVersion,flashVersion,debug);
            }
            // reconfigure back to SPEC_STBY configuration
            SpireBbSOF1End(res1,isBright,bsmModel,bsmVersion,comVersion,smodeVersion,smecVersion,specVersion,debug);
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_PhotOffsetAuto.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to set the detector offset for the photometer arrays
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/19 V0.1: Initial version adapted from 
//                  SpireBb_PhotOffsetAuto (2009/01/31 V1.0)
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_PhotOffsetAuto {
    bool dcuData = false; // Is (==tick) the DCU currently sampled? 
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Define some variables:
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start procedure:
    //
    message("4    " + time() + ": SpireProc_Set_PhotOffsetAuto started");
    message("4          $Id: $");
    // //
    // //
    // In case stop data:
    //
    if(dcuData) {
        SpireSendDrcuCmd(0x843e0000,0);
    }
    // //
    // //
    // Reset DCU (x1000) fifo:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RESET_FIFOS(0x1000)");
    Spire_RESET_FIFOS(0x1000);
    sync();
    // //
    // //
    // Set data mode to 'Set automatic offset':
    //
    SpireSendDrcuCmd(0x843c0010,0);
    // //
    // //
    // Start data collection:
    //
    SpireSendDrcuCmd(0x843e0001,0);
    delay(3);
    // //
    // //
    // Stop data collection:
    //
    SpireSendDrcuCmd(0x843e0000,0);
    // //
    // //
    // Set data mode to 'Get offset data':
    //
    SpireSendDrcuCmd(0x843c0018,0);
    delay(1);
    // //
    // //
    // Start data collection:
    //
    SpireSendDrcuCmd(0x843e0001,0);
    delay(3);
    // //
    // //
    // Stop data collection:
    //
    SpireSendDrcuCmd(0x843e0000,0);
    // //
    // //
    // Flush DCU fifo:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO(0x1000)");
    Spire_FLUSH_FIFO(0x1000);
    delay(2);
    // //
    // //
    // Set data mode back to nominal:
    //
    SpireSendDrcuCmd(0x843c0000,0);
    // //
    // //
    // In case start data collection:
    //
    if(dcuData) {
        SpireSendDrcuCmd(0x843e0001,0);
    }
    sync();
    //
}

// SpirePhotoLargeLogic
//
// $id$
//
// This procedure selectes the SPIRE observing mode and calculates its instrument parameters  
//  for large map observations
//
// This type of observation may be executed using either the POF4 or POF5 observing modes
//
//  18/01/07:  v1.9:  updated call to SpirePOF5Estimate to pass obsMode
//  13/04/07:  v1.10: SPR 3010 - added option to select between two scan rates
//                    SPR 3043 - added option to select scan direction(s)
//  20/04/07:  v1.11: SPR 3125 - corrected nHold for scanab
//  26/04/07:  v1.12: SPR 3146 - swapped rate and tau paramaters in call to SpirePOF5Estimates
//  26/04/07:  v1.13: SPR 3148 - calculate patt correctly for each mode
//  27/04/07:  v1.14: SPR 3150 
// 10/03/2009 KJK: 
//         SCR 1274, add additional dummy parameters 
//         Update input API to include versions for all cal tables
//  02/07/2009  KJK:
//         Added configuration input parameters to pass to SpirePOF5Config, SpirePOF5Pointing and SpirePOF5End//
//  05/07/2009 KJK:
//         SPR-1593 - Updated call to SpirePOF5Pointing
//  15/08/2009 MP (SCR-SPIRE-1818): Updated call to SpirePOF5Pointing; Include
//             proper usage of versioning for SpireTable_OpsParms. 
//  16/08/2009 MP (SCR-SPIRE-1818): Change call to SpirePOF5Observing
//  10/09/2009 KJK: Modified call to SpirePOF5Pointing
//  15/02/2010 KJK: SCR Spire-1887:
//                             Added spireVersion to input parameters for call to SpirePOF5Observing
//
////////////////////////////////////////////////////////////////////////////
{{string,double,double,double,double,bool,double,double,double}[],bool,int,int,int,int,int,int,int,int,int,int,int} obs SpirePhotoLargeLogic {
    double ra = 0.0 in [0.0,360.0]; // RA of Target
    double dec = 0.0 in [-90.0,90.0]; // DEC of Target
    int naifid = 0; // NAIF identifier
    string source = "large" in ["point","small","large"]; // source type
    string scanDirection = "scanab" in ["scana","scanb","scanab"];
    double mapSize1 = 4.0 in [4.0,1200.0]; // arc minutes
    double mapSize2 = 0.0 in [0.0,240.0]; // arc minutes
    double mapOffsetY = 0.0 in [-300.0,300.0]; // offset to observation position from target in Y direction (arcmins)
    double mapOffsetZ = 0.0 in [-300.0,300.0]; // offset to observation position from target in Z direction (arcmins)
    string mapScanRate = "nominal" in ["nominal","fast"]; // selected scan rate
    bool mapOrientationArray = true; // is the map orientation an array (rather than array with constraints)
    double mapOrientationConFrom = 0.0 in [0.0,360.0];
    double mapOrientationConTo = 360.0 in [0.0,360.0];
    int nRepetitions = 1 in [1,100]; // number of repeats of a map sequence (nominal + orthoganal scans)
    double sourceFluxPSW = -1.0;
    double sourceFluxPMW = -1.0;
    double sourceFluxPLW = -1.0;
    double sourceBrightPSW = -1.0;
    double sourceBrightPMW = -1.0;
    double sourceBrightPLW = -1.0;
    bool isBright = false;
    string bsmModel = "initial";
    string bsmVersion = "v00"; // Version in cal table SpireTable_BsmNominalSettings.txt
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParms
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    string flashVersion = "v00"; // Version in cal table SpireTable_FlashParms
    string photVersion = "v00"; // Version in cal table SpireTable_PhotModeParams.txt
    string comVersion = "v00"; // Version in cal table SpireTable_CommonModeParams.txt
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // check inputs
    if(source != "large") {
        error("SpirePhotoLargeLogic: Source is not a large map");
    }
    if(scanDirection == "scanab" && mapSize1 > 240.0) {
        error("SpirePhotoLargeLogic: Scan length too big (>240.0 arcmin) ");
    }
    SpireMsg(0,"Photometric Large Map Observation");
    // //
    // //
    // Declare some variables:
    //
    int nRasters = nRepetitions;
    int nPoints = 1;
    int nMaps = 1;
    int nCycles = 1;
    int nNodInts = 1;
    int nLines = 1;
    int nCal = 99999;
    int nFlash = 99999;
    int nLinesx = 1;
    int nCalx = 99999;
    int nFlashx = 99999;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string selValN = "";
    string selValO = "";
    string tarCol = "";
    string version = "";
    double patt = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName05 = "SpireTable_OpsParms.txt";
    //
    //
    // *************************************************************
    //  calculate parameters for POF4 observation
    // *************************************************************
    //
    SpireMsg(1,"  POF4 (Raster map) mode parameters");
    //
    //    !!! THIS IS NOT IMPLEMENTED YET !!!
    //
    // *************************************************************
    //  calculate parameters for POF5 observation
    // *************************************************************
    SpireMsg(1,"  POF5 (Non-chopped Scan Map) mode parameters");
    //
    string obsMode = "POF5";
    if(mapScanRate == "fast") {
        obsMode = obsMode + "_F";
    } else {
        obsMode = obsMode + "_S";
    }
    string obsModeN = obsMode + "_N";
    string obsModeO = obsMode + "_O";
    if(debug) {
        debug_print("Selected obsMode: " + obsModeN + "/" + obsModeO);
    }
    // //
    // //
    // Select scan angle from calibration table:
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "Patt";
    version = opsVersion;
    //
    // Selection depending on direction of scan:
    // 
    if(scanDirection == "scana") {
        patt = SpireProc_GetTableEntryDouble(tabName,selCol,selValN,tarCol,version,debug);
    }
    if(scanDirection == "scanb") {
        patt = SpireProc_GetTableEntryDouble(tabName,selCol,selValO,tarCol,version,debug);
    }
    if(scanDirection == "scanab") {
        patt = SpireProc_GetTableEntryDouble(tabName,selCol,selValN,tarCol,version,debug);
    }
    // //
    // //
    // Select number of map repetitions (nMaps) from calibration table:
    // (incl. calculation of pof5Obs parameters)
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "NMaps";
    version = opsVersion;
    //
    // Selection depending on direction of scan:
    //  
    {double,double,int,int,int,int} pof5Obs = {0.0,0.0,0,0,0,0};
    if(scanDirection == "scana") {
        nMaps = SpireProc_GetTableEntryInt(tabName,selCol,selValN,tarCol,version,debug);
        pof5Obs = SpirePOF5Observing(obsModeN,nRepetitions * nMaps,mapSize1,mapSize2,opsVersion,spireVersion,debug);
    }
    if(scanDirection == "scanb") {
        nMaps = SpireProc_GetTableEntryInt(tabName,selCol,selValO,tarCol,version,debug);
        pof5Obs = SpirePOF5Observing(obsModeO,nRepetitions * nMaps,mapSize1,mapSize2,opsVersion,spireVersion,debug);
    }
    if(scanDirection == "scanab") {
        if(debug) {
            debug_print("nMaps/scanab path:");
            debug_print("tabName: " + tabName);
            debug_print("selCols: " + selCol);
            debug_print("selValN: " + selValN);
            debug_print("selValN: " + selValN);
            debug_print("tarCol: " + tarCol);
            debug_print("version: " + version);
        }
        nMaps = SpireProc_GetTableEntryInt(tabName,selCol,selValN,tarCol,version,debug);
        pof5Obs = SpirePOF5Observing(obsModeN,nMaps,mapSize1,mapSize2,opsVersion,spireVersion,debug);
    }
    double mapOsit = pof5Obs{0};
    double d1 = pof5Obs{1};
    int nRepeats = pof5Obs{2};
    nLines = pof5Obs{3};
    nCal = pof5Obs{4};
    nFlash = pof5Obs{5};
    //
    // //
    // //
    // Calculate further pointing mode input parameters:
    //
    {int,int,int,int,int,double,double} pof5Point = {0,0,0,0,0,0.0,0.0};
    if(scanDirection == "scanb") {
        pof5Point = SpirePOF5Pointing(obsModeO,nRepeats,nLines,nCal,nFlash,isBright,bsmModel,bsmVersion,spireVersion,flashVersion,photVersion,comVersion,opsVersion,debug);
    } else {
        pof5Point = SpirePOF5Pointing(obsModeN,nRepeats,nLines,nCal,nFlash,isBright,bsmModel,bsmVersion,spireVersion,flashVersion,photVersion,comVersion,opsVersion,debug);
    }
    int tSlewMin = pof5Point{0};
    int tInitHold = pof5Point{1};
    int tFinalHold = pof5Point{2};
    int tHold = pof5Point{3};
    int nHold = pof5Point{4};
    double d2 = pof5Point{5};
    double rate = pof5Point{6};
    // //
    // //
    // Calculate further cross scan parameters:
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "NMaps";
    version = opsVersion;
    //
    if(scanDirection == "scanab") {
        if(debug) {
            debug_print("x calculation");
        }
        nMaps = SpireProc_GetTableEntryInt(tabName,selCol,selValO,tarCol,version,debug);
        double mapOsitx = 0.0;
        // observing mode parameters
        {double,double,int,int,int,int} pof5Obsx = {0.0,0.0,0,0,0,0};
        pof5Obsx = SpirePOF5Observing(obsModeO,nMaps,mapSize2,mapSize1,opsVersion,spireVersion,debug);
        mapOsitx = pof5Obsx{0};
        double d1x = pof5Obsx{1};
        int nRepeatsx = pof5Obsx{2};
        nLinesx = pof5Obsx{3};
        nCalx = pof5Obsx{4};
        nFlashx = pof5Obsx{5};
        //
        // pointing mode input parameters:
        {int,int,int,int,int,double,double} pof5Pointx = {0,0,0,0,0,0.0,0.0};
        pof5Pointx = SpirePOF5Pointing(obsModeO,nRepeatsx,nLinesx,nCalx,nFlashx,isBright,bsmModel,bsmVersion,spireVersion,flashVersion,photVersion,comVersion,opsVersion,debug);
        int nHoldx = pof5Pointx{4};
        double d2x = pof5Pointx{5};
        //
        // Lookup direction of cross scan:
        //
        tabName = tabName05;
        selCol = "mode";
        selValN = obsModeN;
        selValO = obsModeO;
        tarCol = "Patt";
        version = opsVersion;
        double pattx = SpireProc_GetTableEntryDouble(tabName,selCol,selValO,tarCol,version,debug);
    }
    // //
    // //
    // Calculate further pointing mode pointing parameters:
    //
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "Boresight";
    version = opsVersion;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selValN,tarCol,version,debug);
    //
    // Lookup offset to pixel centre from boresight in Y direction (arcsecs):
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "DeltaY";
    version = opsVersion;
    double deltaY = SpireProc_GetTableEntryDouble(tabName,selCol,selValN,tarCol,version,debug);
    //
    // Lookup offset to pixel centre from boresight in Z direction (arcsecs)
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "DeltaZ";
    version = opsVersion;
    double deltaZ = SpireProc_GetTableEntryDouble(tabName,selCol,selValN,tarCol,version,debug);
    //
    // Lookup pattern angle definition:
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "Fixed";
    version = opsVersion;
    bool fixed = SpireProc_GetTableEntryBool(tabName,selCol,selValN,tarCol,version,debug);
    // //
    // //
    // Calculate further offsets:
    //
    // offset to observation position from target in Y direction (arcsecs):
    //
    double yOffset = mapOffsetY * 60.0 + deltaY;
    //
    // offset to observation position from target in Z direction (arcsecs):
    //
    double zOffset = mapOffsetZ * 60.0 + deltaZ;
    //
    //
    int[] ts = [];
    if(scanDirection == "scanab") {
        // correct nHold and nFlash
        if(nFlash < nLines) {
            int nFlashes = nLines / nFlash;
            nHold = nLines / (nFlashes + 1);
            nFlash = nHold;
        }
        ts = cross_scan_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,fixed,patt,yOffset,zOffset,nLines,d1,d2,rate,tHold,nHold,nRepetitions,nMaps,pattx,nLinesx,d1x,d2x,nHoldx);
    } else {
        ts = line_scan_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,fixed,patt,yOffset,zOffset,nLines,d1,d2,rate,tHold,nHold,nRepeats);
    }
    //
    // ***** choose observing mode *****
    //
    bool isRasterMap = false;
    SpireMsg(1,"  Using POF5 (Scan Map) Observing Mode");
}{
    // *******************************
    // return instrument parameters
    // *******************************
    //
    {string,double,double,double,double,bool,double,double,double}[] estimates = [];
    //
    if(isRasterMap) {
    } else {
        double tau = double(nRepetitions);
        estimates = SpirePOF5Estimate(obsMode + "_" + scanDirection,tau,rate,sourceFluxPSW,sourceFluxPMW,sourceFluxPLW,sourceBrightPSW,sourceBrightPMW,sourceBrightPLW,isBright);
    }
    //
    SpireMsg(3,"     Spire Photometry Large Map Mode parameters:");
    SpireMsg(3,"     ..estimates: " + estimates);
    SpireMsg(3,"     ..isRasterMap: " + isRasterMap);
    SpireMsg(3,"     ..nRasters: " + nRasters + "(# map repeats)");
    SpireMsg(3,"     ..nPoints: " + nPoints);
    SpireMsg(3,"     ..nMaps: " + nMaps);
    SpireMsg(3,"     ..nCycles: " + nCycles);
    SpireMsg(3,"     ..nNodInts: " + nNodInts);
    SpireMsg(3,"     ..nLines: " + nLines);
    SpireMsg(3,"     ..nCal: " + nCal);
    SpireMsg(3,"     ..nFlash: " + nFlash);
    SpireMsg(3,"     ..nLinesx: " + nLinesx);
    SpireMsg(3,"     ..nCalx: " + nCalx);
    SpireMsg(3,"     ..nFlashx: " + nFlashx);
    //

    return {estimates,isRasterMap,nRasters,nPoints,nMaps,nCycles,nNodInts,nLines,nCal,nFlash,nLinesx,nCalx,nFlashx};
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SmecHold.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to stop SMEC trajectory generation. 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/31 V0.1: Initial version
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SmecHold SPIRE 14036 {
    bool debug = false;
}{
    // //
    // //
    // Define some variables:
    //
    int t = time();
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SmecHold started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBID:
    // 
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    // //
    // //
    // Set SMEC to stop:
    //    
    SpireProc_SmecHold(debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SmecHold ended");
    SpireMsg(1,"  ..BB SmecHold (" + (time() - t) + " seconds)");
    //
}

// SpireSOF12Estimate
//
// $Id:$
//
// This procedure calculates the estimated noise and signal/noise
//  for the given observing time for all spectrometer modes.
//
//  for input values, a value less than 0 indicates value unknown
//
//  20/04/07: v1.5: SCR3054 
//  07/02/09: v1.6: Updated to select sensitivity tables depending on value of isBright
//
{{double,double,double,double,double,double}[],{double,double,double,double,double,double}[]} procedure SpireSOF12Estimate {
    string resolution = "H" in ["H","M","L","H+L"];
    double osit1 = 0.0; // set 1 on-source integration time
    double osit2 = 0.0; // set 2 on-source integration time
    double wavelength1 = -1.0;
    double wavelength2 = -1.0;
    double wavelength3 = -1.0;
    double wavelength4 = -1.0;
    double wavelength5 = -1.0;
    double wavelength6 = -1.0;
    double wavelength7 = -1.0;
    double wavelength8 = -1.0;
    double lineFlux1 = -1.0;
    double lineFlux2 = -1.0;
    double lineFlux3 = -1.0;
    double lineFlux4 = -1.0;
    double lineFlux5 = -1.0;
    double lineFlux6 = -1.0;
    double lineFlux7 = -1.0;
    double lineFlux8 = -1.0;
    bool isJyContinuum = true;
    double contFlux1 = -1.0;
    double contFlux2 = -1.0;
    double contFlux3 = -1.0;
    double contFlux4 = -1.0;
    double contFlux5 = -1.0;
    double contFlux6 = -1.0;
    double contFlux7 = -1.0;
    double contFlux8 = -1.0;
    bool isBright = false;
    string version = "v00";
    bool debug = false;
}{
    SpireMsg(3,"          Calculating SOF noise estimates");
    SpireMsg(3,"          $Id:$");
    SpireMsg(3,"          Input:");
    SpireMsg(3,"            Resolution:" + resolution);
    SpireMsg(3,"            osit1: " + osit1);
    SpireMsg(3,"            osit2: " + osit2);
    SpireMsg(3,"            Wavelength1: " + wavelength1);
    SpireMsg(3,"            Wavelength2: " + wavelength2);
    SpireMsg(3,"            Wavelength3: " + wavelength3);
    SpireMsg(3,"            Wavelength4: " + wavelength4);
    SpireMsg(3,"            Wavelength5: " + wavelength5);
    SpireMsg(3,"            Wavelength6: " + wavelength6);
    SpireMsg(3,"            Wavelength7: " + wavelength7);
    SpireMsg(3,"            Wavelength8: " + wavelength8);
    SpireMsg(3,"            Line 1 Flux density: " + lineFlux1);
    SpireMsg(3,"            Line 2 Flux density: " + lineFlux2);
    SpireMsg(3,"            Line 3 Flux density: " + lineFlux3);
    SpireMsg(3,"            Line 4 Flux density: " + lineFlux4);
    SpireMsg(3,"            Line 5 Flux density: " + lineFlux5);
    SpireMsg(3,"            Line 6 Flux density: " + lineFlux6);
    SpireMsg(3,"            Line 7 Flux density: " + lineFlux7);
    SpireMsg(3,"            Line 8 Flux density: " + lineFlux8);
    SpireMsg(3,"            Continuum 1 Flux density: " + contFlux1);
    SpireMsg(3,"            Continuum 2 Flux density: " + contFlux2);
    SpireMsg(3,"            Continuum 3 Flux density: " + contFlux3);
    SpireMsg(3,"            Continuum 4 Flux density: " + contFlux4);
    SpireMsg(3,"            Continuum 5 Flux density: " + contFlux5);
    SpireMsg(3,"            Continuum 6 Flux density: " + contFlux6);
    SpireMsg(3,"            Continuum 7 Flux density: " + contFlux7);
    SpireMsg(3,"            Continuum 8 Flux density: " + contFlux8);
    SpireMsg(3,"            Continuum in Jy: " + isJyContinuum);
    //
    double[] wave = [];
    // 
    // calculate sensitivities
    //
    string tabName = "Spec_Sensitivities.txt";
    if(isBright) {
        tabName = "Spec_BrightSensitivities.txt";
    }
    double hLineSensitivity = 0.0;
    double hContSensitivity = 0.0;
    double hResPower = 0.0;
    double lContSensitivity = 0.0;
    double lResPower = 0.0;
    double hres = SpireProc_GetTableEntryDouble("SpireTable_Spectrometer.txt","ResChar","H","Resolution",version,debug);
    double mres = SpireProc_GetTableEntryDouble("SpireTable_Spectrometer.txt","ResChar","M","Resolution",version,debug);
    double lres = SpireProc_GetTableEntryDouble("SpireTable_Spectrometer.txt","ResChar","L","Resolution",version,debug);
    {double,double,double,double,double,double}[] sensitivities = [];
    //
    wave = [194.0,200.0,250.0,300.0,320.0,400.0,550.0,672.0];
    SpireMsg(3," Output Sensitivities:");
    SpireMsg(3,"            Wavelength             HR Sensitivity     HR Cont Sensitivity       HR Res Pwr         LR Cont Sensitivity     LR Res Pwr");
    for(int w1 = 0 .. length(wave) - 1) {
        hLineSensitivity = 0.0;
        hContSensitivity = 0.0;
        lContSensitivity = 0.0;
        hResPower = 0.0;
        lResPower = 0.0;
        if(resolution == "H" || resolution == "H+L") {
            hLineSensitivity = interpolate(tabName,"HLineUnc",wave[w1]) / sqrt(osit1);
            if(isJyContinuum) {
                hContSensitivity = interpolate(tabName,"HContUncJ",wave[w1]) / sqrt(osit1);
            } else {
                hContSensitivity = interpolate(tabName,"HContUncW",wave[w1]) / sqrt(osit1);
            }
            hResPower = 10000.0 / (wave[w1] * hres);
        }
        if(resolution == "M") {
            hLineSensitivity = interpolate(tabName,"MLineUnc",wave[w1]) / sqrt(osit1);
            if(isJyContinuum) {
                hContSensitivity = interpolate(tabName,"MContUncJ",wave[w1]) / sqrt(osit1);
            } else {
                hContSensitivity = interpolate(tabName,"MContUncW",wave[w1]) / sqrt(osit1);
            }
            hResPower = 10000.0 / (wave[w1] * mres);
        }
        if(resolution == "L") {
            if(isJyContinuum) {
                lContSensitivity = interpolate(tabName,"LContUncJ",wave[w1]) / sqrt(osit1);
            } else {
                lContSensitivity = interpolate(tabName,"LContUncW",wave[w1]) / sqrt(osit1);
            }
            lResPower = 10000.0 / (wave[w1] * lres);
        }
        if(resolution == "H+L") {
            if(isJyContinuum) {
                lContSensitivity = interpolate(tabName,"LContUncJ",wave[w1]) / sqrt(osit2);
            } else {
                lContSensitivity = interpolate(tabName,"LContUncW",wave[w1]) / sqrt(osit2);
            }
            lResPower = 10000.0 / (wave[w1] * lres);
        }
        sensitivities[w1] = {wave[w1],hLineSensitivity,hContSensitivity,hResPower,lContSensitivity,lResPower};
        SpireMsg(3,"            " + wave[w1] + "       " + hLineSensitivity + "            " + hContSensitivity + "            " + hResPower + "           " + lContSensitivity + "           " + lResPower);
    }
    //  
    // calculate signal/noise estimates
    //
    double hLineSN = 0.0;
    double hContSN = 0.0;
    double lContSN = 0.0;
    {double,double,double,double,double,double}[] estimates = [];
    //
    wave = [wavelength1,wavelength2,wavelength3,wavelength4,wavelength5,wavelength6,wavelength7,wavelength8];
    double[] lineFlux = [lineFlux1,lineFlux2,lineFlux3,lineFlux4,lineFlux5,lineFlux6,lineFlux7,lineFlux8];
    double[] contFlux = [contFlux1,contFlux2,contFlux3,contFlux4,contFlux5,contFlux6,contFlux7,contFlux8];
    //
    SpireMsg(3," Output Estimates:");
    SpireMsg(3,"            Wavelength             Line Flux      High Res S/N on Line       Continuum Flux         High Res S/N on Continuum     Low Res S/N on Continuum");
    for(int w2 = 0 .. length(wave) - 1) {
        hLineSN = -1.0;
        hContSN = -1.0;
        lContSN = -1.0;
        if(wave[w2] > 0.0) {
            if(resolution == "H" || resolution == "H+L") {
                if(lineFlux[w2] >= 0.0) {
                    hLineSN = lineFlux[w2] * sqrt(osit1) / interpolate(tabName,"HLineUnc",wave[w2]);
                    if(hLineSN > 200.0) {
                        hLineSN = 200.0;
                    }
                }
                if(contFlux[w2] >= 0.0) {
                    if(isJyContinuum) {
                        hContSN = contFlux[w2] * sqrt(osit1) / interpolate(tabName,"HContUncJ",wave[w2]);
                    } else {
                        hContSN = contFlux[w2] * sqrt(osit1) / interpolate(tabName,"HContUncW",wave[w2]);
                    }
                    if(hContSN > 200.0) {
                        hContSN = 200.0;
                    }
                }
            }
            if(resolution == "M") {
                if(lineFlux[w2] >= 0.0) {
                    hLineSN = lineFlux[w2] * sqrt(osit1) / interpolate(tabName,"MLineUnc",wave[w2]);
                    if(hLineSN > 200.0) {
                        hLineSN = 200.0;
                    }
                }
                if(contFlux[w2] >= 0.0) {
                    if(isJyContinuum) {
                        hContSN = contFlux[w2] * sqrt(osit1) / interpolate(tabName,"MContUncJ",wave[w2]);
                    } else {
                        hContSN = contFlux[w2] * sqrt(osit1) / interpolate(tabName,"MContUncW",wave[w2]);
                    }
                    if(hContSN > 200.0) {
                        hContSN = 200.0;
                    }
                }
            }
            if(resolution == "L") {
                if(contFlux[w2] >= 0.0) {
                    if(isJyContinuum) {
                        lContSN = contFlux[w2] * sqrt(osit1) / interpolate(tabName,"LContUncJ",wave[w2]);
                    } else {
                        lContSN = contFlux[w2] * sqrt(osit1) / interpolate(tabName,"LContUncW",wave[w2]);
                    }
                    if(lContSN > 200.0) {
                        lContSN = 200.0;
                    }
                }
            }
            if(resolution == "H+L") {
                if(contFlux[w2] >= 0.0) {
                    if(isJyContinuum) {
                        lContSN = contFlux[w2] * sqrt(osit2) / interpolate(tabName,"LContUncJ",wave[w2]);
                    } else {
                        lContSN = contFlux[w2] * sqrt(osit2) / interpolate(tabName,"LContUncW",wave[w2]);
                    }
                    if(lContSN > 200.0) {
                        lContSN = 200.0;
                    }
                }
            }
            estimates[w2] = {wave[w2],lineFlux[w2],contFlux[w2],hLineSN,hContSN,lContSN};
            SpireMsg(3,"            " + wave[w2] + "       " + lineFlux[w2] + "            " + hLineSN + "            " + contFlux[w2] + "           " + hContSN + "           " + lContSN);
        }
    }
    //

    return {sensitivities,estimates};
}

// SpireSetObsStep
//
// $id$
//
// This building block sets the Observing Step parameter
// 
procedure SpireSetObsStep {
    int step = 0; // step value
}{
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    hstr = SpireHexStr(step,4);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(" + hstr + ")");
    Spire_SET_OBS_STEP_RAW(step);
}

// SpirePOF5Observing
//
// $Id:$
//
// This is the  procedure to calculate 
// instrument observing parameters for the Scan Map observing mode
//
//    Note:
//       This procedure assumes that 2 seconds are required at the start of the scan to allow
//       setting of the BB and STEP.
//       It also assumes that 2 seconds are required at the end of the scan to 
//       reset the STEP parameter 
//
//  13/04/07: SCR3010 - changed default obsMode
//  15/08/2009 MP (SCR-SPIRE-1818): New input opsVersion to allow changes 
//             to rate/d2 from the top level script. Furthermore, use now
//             the correct cal. table SpireTable_OpsParms. Add debug as input.
//  10/09/2009 KJK:
//             SPR Spire-1897-3: Changed calculation of nLines to give 1 if mapHeight - hLoss is negative and >d2 
//  15/02/2010 KJK: SCR Spire-1887:
//                             Updated to use SpireTable_SpireParams to determine the initFlash and endFlash flags status
//                             Updated to use SpireTable_SpireParams to determine the flashTime and calTime values
//                             Added spireVersion to input parameters
// 
///////////////////////////////////////////////////////////////////////
{double,double,int,int,int,int} procedure SpirePOF5Observing {
    string obsMode = "POF5_S_N";
    int nRepeats = 1; // requested number of map repeats
    double mapWidth = 0.0; // requested map width (arcmins)
    double mapHeight = 0.0; // requested map height (arcmin)
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParams
    bool debug = false;
}{
    SpireMsg(2,"    Observing mode POF5 Observing Parameters ");
    SpireMsg(2,"    $Id:$");
    // //
    // //
    // Declare some variables:
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double patt = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName05 = "SpireTable_OpsParms.txt";
    // //
    // Fetch operating parameters:
    //
    int flashTime = SpireProc_GetTableEntryInt("SpireTable_SpireParams.txt","mode",obsMode,"FlashTime",spireVersion,debug);
    // Optimum time between flashes
    int calTime = SpireProc_GetTableEntryInt("SpireTable_SpireParams.txt","mode",obsMode,"CalTime",spireVersion,debug);
    // Minimum time between gyro calibrations
    //
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Boresight";
    version = opsVersion;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Lookup scan angle:
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Patt";
    version = opsVersion;
    patt = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
    // 
    // Lookup scan line separation:   
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "D2";
    version = opsVersion;
    double d2 = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
    // 
    // Lookup map height loss :   
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "HLoss";
    version = opsVersion;
    double hLoss = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
    // 
    // Lookup map length loss :   
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "LLoss";
    version = opsVersion;
    double lLoss = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
    // 
    // Lookup scan rate:  
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "ScanRate";
    version = opsVersion;
    double scanRate = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
    //
    // initial flash flag
    bool initFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"InitFlash",spireVersion,debug);
    // final flash flag
    bool endFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"EndFlash",spireVersion,debug);
    //     
    // *****************************************
    //   Display input parameters
    // *****************************************
    SpireMsg(3,"     POF5 Observing Input values:");
    SpireMsg(3,"     ..nRepeats: " + nRepeats);
    SpireMsg(3,"     ..mapWidth: " + mapWidth);
    SpireMsg(3,"     ..mapHeight: " + mapHeight);
    SpireMsg(3,"     POF5 Fixed values:");
    SpireMsg(3,"     ..ib: " + ib);
    SpireMsg(3,"     ..patt: " + patt);
    SpireMsg(3,"     ..d2: " + d2);
    SpireMsg(3,"     ..hLoss: " + hLoss);
    SpireMsg(3,"     ..lLoss: " + lLoss);
    SpireMsg(3,"     ..scanRate: " + scanRate);
    SpireMsg(3,"     ..flashTime: " + flashTime);
    SpireMsg(3,"     ..calTime: " + calTime);
    SpireMsg(3,"     ..initFlash: " + initFlash);
    SpireMsg(3,"     ..endFlash: " + endFlash);
    //
    // calculate observing parameters
    SpireMsg(2,"    Calculated Parameters:");
    //
    // number of lines in a map
    int nLines = iceil((mapHeight * 60.0 - hLoss) / d2);
    if(nLines < 0) {
        nLines = 0;
    }
    nLines = nLines + 1;
    SpireMsg(3,"      Required number of scan lines in map: " + nLines);
    //
    // observing scanLength
    double scanLength = mapWidth * 60.0 + lLoss;
    // 
    // integration time per line (covering user requested length)
    double lineOsit = scanLength / scanRate;
    SpireMsg(3,"      Integration time per scan line: " + lineOsit);
    //
    // increase scan length to allow time to start the scan
    int tStart = 2;
    int tEnd = 2;
    scanLength = scanLength + double(tStart + tEnd) * scanRate;
    SpireMsg(3,"      Required scan length: " + scanLength);
    //
    // time per line
    double lineTime = scanLength / scanRate;
    //
    // total observing time  
    int d = duration(SpireBbScanLine(iceil(lineTime),0));
    double totalTime = double(nRepeats) * double(nLines) * double(d);
    SpireMsg(3,"      Total observing time: " + totalTime);
    //
    // number of lines per Gyro calibration 
    // Note: this only takes into account on source observing time, not movement between lines, 
    // which is assumed to be a small fraction of the observing time, and so the value obtained is approximate 
    int nCals = ifloor(totalTime / double(calTime));
    // SpireMsg(3,"      Number of Gyro Calibrations: " + nCals);
    int nCal = iceil(totalTime / lineTime);
    // default is no gyro calibrations during observation 
    if(nCals > 0) {
        nCal = iceil(double(nLines) * double(nRepeats) / double(nCals + 1));
    }
    if(nLines % nCal == 0) {
        nCal = nCal + 1;
    }
    // SpireMsg(3,"      Number of Gyro Calibrations(adjusted): " + nCals);
    // SpireMsg(3,"      Number of nod lines per Gyro calibration: " + nCal);
    //
    // number of lines per PCAL calibration 
    // Note: this only takes into account on source observing time, not movement between lines, 
    // which is assumed to be a small fraction of the observing time, and so the value obtained is approximate 
    int nFlashes = ifloor(totalTime / double(flashTime));
    SpireMsg(3,"      Number of Flashes: " + nFlashes);
    int nFlash = iceil(totalTime / lineTime);
    // default is no flashes during observation 
    if(nFlashes > 0) {
        nFlash = iceil(double(nLines) * double(nRepeats) / double(nFlashes + 1));
    }
    if(nLines % nFlash == 0) {
        nFlash = nFlash + 1;
    }
    SpireMsg(3,"      Number of Flashes(adjusted): " + nFlashes);
    SpireMsg(3,"      Number of nod lines per PCAL calibration: " + nFlash);

    return {lineOsit * double(nLines),scanLength,nRepeats,nLines,nCal,nFlash};
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_Cal_StdLoadCurve.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  CUS script for: 'Spec Standard Load Curve'   
//
//  in *basic_fine_pointing* or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/15 V0.1: Initial version adapted from
//                  SpirePhoto_Cal_StdLoadCurve (2008/07/21 V0.4)
//                  based on 
//                  Mode_ILT_PERF_DAB_S_Levels.txt (v 1.3 2008/01/31 23:35:17)
// 2008/11/11 V0.2: Allow 'no pointing' as input option; Adapt debug printing
// 2008/11/12 V0.3: Implement mode setting; Add isBright 
//                  Change 'no pointing' implementation
// 2009/02/19 V0.4: Add debug_print as input and pass it to low level 
//                  scripts. Use new SpireBb_EndObsAll and SpireBb_StartObsAll. 
//                  Read nominal bias frequency and bias divider from new
//                  SpireTable_SpecModeParms. Implemented message 
//                  if activating isBright setting. Implemented setting 
//                  of datarates. Bias levels used for the load curve are 
//                  now calculated in SpireProc_CalcParam_LoadCurve.
//                  Use SpireBb_SpecSetMode to set to SPECSTBY during 
//                  SLEW and FINAL_HOLD. Read boresight from 
//                  SpireTable_OpsParms. Remove cal. table name from input. 
//                  Replace call to SpireBb_SpecFSetupData with call to 
//                  SpireBb_SpecFSetPhase and SpireBb_SpecFSetBiasAmpl to 
//                  set user requested frequency, phase, and first BiasAmpl.
// 2009/03/04 V0.5: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Replace 'message' by
//                  'error' if isBright is selected. 
// 2009/05/06 V0.6: Add in move BSM/SMEC to hold/home at start. Add new 
//                  SpireBb_SmecHold to account for the fact that
//                  SpireBb_SmecMove2Home does not stop SMEC.
//                  Gather procedures at start and end in separate BB. 
// 2010/01/06 V1.0: Edit default parameters for input phases (SCR-SPIRE-2300)
//
///////////////////////////////////////////////////////////////////////////
//
//  Script assumes that:
//
//  1)  Instrument is in SPECSTBY at beginning 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Phase is kept constant (from input) during this test, i.e no 
//     adjustment of the phase with changing bias amplitude and frequency
//
//  3) Bias frequency and sampling rate are input parameters
//
//  4) Boresight of array can be read from following cal table:
//     SpireTable_OpsParms.txt   
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_Cal_StdLoadCurve {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; // NAIF identifier
    bool isBright = false; // Use settings for bright source (==tick)
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    double biasfreq = 160.1 in [80.0,240.0]; // Bias frequency [Hz]
    double samplerate = 80.0 in [1.0,80.5]; // Sampling rate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    double phasedeg_ssw = 186.353 in [0.0,360.0]; // SSW Bias phase [deg]
    double phasedeg_slw = 190.588 in [0.0,360.0]; // SLW Bias phase [deg]
    int ftime = 10; // Readout time at each bias level [s]
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_StdLoadCurveLevels
    string version05 = "v00"; // Version in cal table SpireTable_OpsParms.txt
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // //
    // //
    // Check for is bright setting: 
    //
    if(isBright) {
        isBright = false;
        error("IsBright does not make sense here. Try again (e.g. subtract the phase shift manually from the input)!");
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = false;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_StdLoadCurveLevels.txt";
    string tabName04 = "SpireTable_BsmNominalSettings.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    string tabName06 = "SpireTable_SmecNominalSettings.txt";
    // Currently hardcoded version and model parameter:
    //
    string version06 = "v00";
    // Version in cal table SpireTable_SmecNominalSettings
    string version04 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    //
    // Dummy value for Phot script:
    // (needed but not used in spec script!)
    //
    int psw_bias = 62;
    //
    int pmw_bias = 62;
    //
    int plw_bias = 62;
    //
    int ptc_bias = 62;
    //
    int psw_phase = 127;
    //
    int pmw_phase = 127;
    //
    int plw_phase = 127;
    //
    int ptc_phase = 127;
    //
    //
    //
    // Currently hardcoded parameter:
    // Is (==tick) the DCU currently sampled? 
    bool dcuData = false;
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS41";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "SEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Retrieve bias levels used for the load curve:
    // 
    tabName = tabName03;
    version = version03;
    int[] nbiaslist = SpireProc_CalcParam_LoadCurve(tabName,version,debug);
    //
    // Lookup first bias level:    
    int ssw_bias = nbiaslist[0];
    int slw_bias = nbiaslist[0];
    // //
    // //
    // Convert user input to Hex values:
    //
    // for bias frequency and sample rate: 
    // 
    int[] hexvalues = SpireProc_CalcParam_BiasFreqSampFreq(biasfreq,samplerate,fts,debug);
    int mclkdiv = hexvalues[0];
    int biasdiv = hexvalues[1];
    if(debug) {
        debug_print("Hex values of mclkdiv/biasdiv are: " + mclkdiv + " " + biasdiv);
    }
    //
    // for bias phase:
    //
    int[] phasehex = SpireProc_CalcParam_SpecPhaseConvert(phasedeg_ssw,phasedeg_slw,debug);
    int ssw_phase = phasehex[0];
    int slw_phase = phasehex[1];
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version04;
    tabName = tabName04;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Read SMEC home position from calibration file:
    //
    tarCol = "Home";
    tabName = tabName06;
    selVal = version06;
    int smecHomePosn = ilookup(tabName,selVal,tarCol);
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // // 
    // // 
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartStdLoadCurve(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,psw_phase,pmw_phase,plw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug));
    // 
    // BBs carried out when the pointing is reached:
    if(pointing) {
        int tinithold = 0;
    } else {
        tinithold = tslewmin;
    }
    //
    // BB carried out during pointing:
    int tp = duration(SpireProc_Exec_SpecStdLoadCurve(nbiaslist,ftime,dcuData,debug));
    //
    // BB carried out at the end:
    int tfinalhold = duration(SpireBb_EndStdLoadCurve(phot,isBright,version01,version02,debug));
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                              */
    // ****************************************************** */
    // //
    // //
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartStdLoadCurve(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,psw_phase,pmw_phase,plw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            //
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation: 
                //
                SpireBb_StartStdLoadCurve(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,psw_phase,pmw_phase,plw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug);
                //
            }
            //
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            // //
            // //
            // Execute load curve:
            //
            SpireProc_Exec_SpecStdLoadCurve(nbiaslist,ftime,dcuData,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            SpireBb_EndStdLoadCurve(phot,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_Cal_IltPcalFlash.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Phot ILT PCAL Flash' 
//
//  in *basic_fine_pointing* or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/05/05 V0.1: Initial version adapted from 
//                  Mode_ILT_PERF_DAB_P_CPS.txt (v1.3 2008/01/31 23:35:17)
// 2008/06/09 V0.2: Changed name to be conform with new naming convention
// 2008/07/21 V0.3: Allow nafid as input parameter
// 2008/08/12 V0.4: Remove test number; change name of low level script in 
//                  description; Remove calculation of ILT flash parameters
//                  and use new Exec script with fixed ILT parameters 
// 2008/08/15 V0.5: Adapt new input to improved Exec script which properly 
//                  allows to recover the erroneous calculated parameters 
//                  during ILT; allow detector settings as input; Adapt to
//                  change in call to low level script 
//                  SpireProc_CalcParam_BiasFreqSampFreq.txt 
// 2008/11/11 V0.6: Allow 'no pointing' as input option; Adapt debug printing
// 2008/11/12 V0.7: Implement mode setting; Add isBright
//                  Change 'no pointing' implementation 
// 2009/02/02 V1.0: Add debug_print as input and pass it to some low 
//                  level scripts. Add setting of NHK STEP parameter
//                  in  SpireProc_Exec_IltPcalFlash and unset at end.   
//                  Use new SpireBb_EndObsAll and SpireBb_StartObsAll. 
//                  Read nominal bias frequency and bias divider from new
//                  SpireTable_DetectorSettings.txt. Implemented setting 
//                  of datarates. Replace SpireProc_Set_PhotNominal by
//                  SpireProc_Set_FreqSampAmpPhasNominal. Implemented message 
//                  if activating isBright setting.
// 2009/02/17 V1.1: Remove cal table name from input and hardcode. Replace call
//                  to SpireBb_PhotFSetupData by call to SpireBb_DcuSetFreqSamp
//                  SpireBb_PhotFSetPhase and SpireBb_PhotFSetBiasAmpl. 
//                  New setting of datarates. Use SpireBb_PhotSetMode to set 
//                  to PHOTSTBY during SLEW and FINAL_HOLD. Unset isBright 
//                  if set. Read boresight from SpireTable_OpsParms.
// 2009/02/18 V1.2: Adapt to change in call to SpireProc_Exec_IltPcalFlash 
// 2009/02/19 V1.3: Elevate version05 to input. Update call to 
//                  SpireProc_Exec_IltPcalFlash to allow for proper setting
//                  of FTS ILT Pcal highbias levels (bug detected at SDAG#19). 
// 2009/03/04 V1.4: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Change isBright behaviour.
//                  Use maxbias for amplitude and subtract isBright phase
//                  shift read from calibration file from the user input phase.
// 2009/05/06 V1.5: Add in move BSM to hold at start. Gather procedures at 
//                  start and end in separate BB. 
// 2009/05/26 V1.6: Change default input phases from 180.7 (all) to the values
//                  given in SCR 1441. 
// 2009/06/05 V1.7: Hardcode STBY 'v00' in EndBB (SPR-1477). Changed peak2peak
//                  in input description with correct zero2peak.
// 
// Caveat: isBright bias amplitude is hardcoded in script!
//
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in PHOTSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Boresight of array can be read from following cal table:
//     SpireTable_OpsParms.txt  
//
//  3) Phase shift for isBright setting can be read from following
//     cal table: SpireTable_IsBrightPhaseShift.txt 
//
//  4) Needs additional procedure SpireProc_Exec_IltPcalFlash.txt and 
//     SpireProc_CalcParam_IltPcalFlash to execute ILT PCAL flash.  
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhoto_Cal_IltPcalFlash {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; // NAIF identifier
    bool isBright = false; // Use settings for bright source (==tick)
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    double biasfreq = 130.2 in [70.0,200.0]; // Bias frequency [Hz]
    double samplerate = 18.6 in [1.0,20.0]; // Sampling rate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    double biasmV_psw = 31.2 in [0.0,127.813]; // PSW Bias amplitude (zero2peak) [mV]
    double biasmV_pmw = 31.2 in [0.0,128.625]; // PMW Bias amplitude (zero2peak) [mV]
    double biasmV_plw = 31.2 in [0.0,129.159]; // PLW Bias amplitude (zero2peak) [mV]
    double biasmV_ptc = 127.6 in [0.0,254.265]; // PTC Bias amplitude (zero2peak) [mV]
    double phasedeg_psw = 179.29 in [0.0,360.0]; // PSW Bias phase [deg]
    double phasedeg_pmw = 179.29 in [0.0,360.0]; // PMW Bias phase [deg]
    double phasedeg_plw = 182.11 in [0.0,360.0]; // PLW Bias phase [deg]
    double phasedeg_ptc = 208.0 in [0.0,360.0]; // PTC Bias phase [deg]
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version05 = "v00"; // Version in cal table SpireTable_OpsParms 
    string version06 = "v00"; // Version in cal table SpireTable_IsBrightPhaseShift
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // //
    // //
    // Check for is bright setting: 
    //
    if(isBright) {
        message("IsBright selected! PxW bia amplitude is set to 255 and isBright phase-shift is subtracted.");
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = true;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string tarCol = "";
    string selVal = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    string tabName06 = "SpireTable_IsBrightPhaseShift.txt";
    //
    // Currently hardcoded version and model parameter:
    //
    string version03 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    //
    // Dummy value for Spec script:
    // (needed but not used in phot script!)
    //
    int smecHomePosn = 3500;
    // SMEC home position
    int bias_ssw = 45;
    //
    int bias_slw = 45;
    //
    int phase_ssw = 128;
    //
    int phase_slw = 128;
    // 
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS07";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "PEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Read isBright phase shift from calibration table:
    //
    int photPhaseShift = ilookup(tabName06,version06,"photPhaseShift");
    // //
    // //
    // Convert user input to Hex values:
    //
    // for bias frequency and sample rate: 
    //
    int[] hexvalues = SpireProc_CalcParam_BiasFreqSampFreq(biasfreq,samplerate,fts,debug);
    int mclkdiv = hexvalues[0];
    int biasdiv = hexvalues[1];
    if(debug) {
        debug_print("Hex values of mclkdiv/biasdiv are: " + mclkdiv + " " + biasdiv);
    }
    //
    // for bias phase:
    //
    int[] phasehex = SpireProc_CalcParam_PhotPhaseConvert(phasedeg_psw,phasedeg_pmw,phasedeg_plw,phasedeg_ptc,debug);
    int phase_psw = phasehex[0];
    int phase_pmw = phasehex[1];
    int phase_plw = phasehex[2];
    if(isBright) {
        phase_psw = SpireProc_CalcParam_IsBrightPhaseShift(phase_psw,photPhaseShift,debug);
        phase_pmw = SpireProc_CalcParam_IsBrightPhaseShift(phase_pmw,photPhaseShift,debug);
        phase_plw = SpireProc_CalcParam_IsBrightPhaseShift(phase_plw,photPhaseShift,debug);
    }
    int phase_ptc = phasehex[3];
    //
    // for bias amplitude:
    //
    int[] biashex = SpireProc_CalcParam_PhotBiasConvert(biasmV_psw,biasmV_pmw,biasmV_plw,biasmV_ptc,debug);
    int bias_psw = biashex[0];
    int bias_pmw = biashex[1];
    int bias_plw = biashex[2];
    if(isBright) {
        bias_psw = 255;
        bias_pmw = 255;
        bias_plw = 255;
    }
    int bias_ptc = biashex[3];
    // //
    // //
    // Set PCAL Flash values to the once fixed used during ILT: 
    //
    //PCAL Flash FULL period (high and low bias) [microsec]:
    int period = 4000000;
    //
    // DCU data mode (0 == PF; 4 == SF):
    int ndcumode = 0;
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version03;
    tabName = tabName03;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    //
    int tslewmin = duration(SpireBb_StartIltPcalFlash(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,bias_psw,bias_pmw,bias_plw,bias_ptc,phase_psw,phase_pmw,phase_plw,phase_ptc,bias_ssw,bias_slw,phase_ssw,phase_slw,debug));
    //   
    // BBs carried out when the pointing is reached:
    //
    if(pointing) {
        int tinithold = duration(SpireBb_PhotOffsetAuto(debug));
    } else {
        tinithold = duration(SpireBb_PhotOffsetAuto(debug)) + tslewmin;
    }
    //
    // BB carried out during pointing:
    //
    int tp = duration(SpireProc_Exec_IltPcalFlash(period,mclkdiv,biasdiv,ndcumode,phot,debug));
    //
    // BB carried out at the end:
    //
    int tfinalhold = duration(SpireBb_EndIltPcalFlash(phot,isBright,version01,version02,debug));
    //
    // Debug printing:
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                              */
    // ****************************************************** */
    //
    // Lookup boresight:
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    // 
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartIltPcalFlash(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,bias_psw,bias_pmw,bias_plw,bias_ptc,phase_psw,phase_pmw,phase_plw,phase_ptc,bias_ssw,bias_slw,phase_ssw,phase_slw,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            //
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation: 
                //
                SpireBb_StartIltPcalFlash(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,bias_psw,bias_pmw,bias_plw,bias_ptc,phase_psw,phase_pmw,phase_plw,phase_ptc,bias_ssw,bias_slw,phase_ssw,phase_slw,debug);
                //
            }
            // //
            // //
            // Set offsets: 
            //
            SpireBb_PhotOffsetAuto(debug);
            //
            //delay(tinithold);
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            //delay(tp);
            // //
            // //
            // Execute ILT PCAL flashes:
            //
            SpireProc_Exec_IltPcalFlash(period,mclkdiv,biasdiv,ndcumode,phot,debug);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activities )
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            //
            SpireBb_EndIltPcalFlash(phot,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

//
// Update NHK
// 06/11/2009: SDS First Version (For OBS 4.0.0 - SPIRE-SCR-2127)
//
block SpireBb_UpdateNHK SPIRE 3402 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //    //
    //
    int t = time();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_UpdateNHK started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    //Clear NHK report
    Spire_CLEAR_HK_REPORT(0x301);
    delay(4);
    // Add the get command for the CHOPJIGG_DCOUPLE
    Spire_UPDATE_TABLE(0x1,45,1,[{0x98da0000}]);
    delay(4);
    //
    //Define new nominal HK report
    Spire_DEFINE_NEW_HK_REPORT(0x301,0x301,0xfa0,1,1);
    delay(4);
    //
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x1,0x0,0x0);
    delay(4);
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_UpdateNHK ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

// CVS comments  : $Id: WriteEndID.txt,v 1.9 2007/08/22 10:21:52 dcesarsk Exp $ 
// Purpose       : Set the BBID and OBSID to the predefined values shown
//                 in FIRST-FSC-DOC-0200 
//
// CUS script    : Diego A. Cesarsky (diego.cesarsky@mpe.mpg.de)
// Original TCL  : N/A
// CVS file      : WriteEndID.txt
//
// Input arguments 
// Type  Name     DefVal  Description
//
// Description   : Equivalent of WriteOBSID and WriteBBID but using preset
//                 values for $OBSID and $BBID
//
// Dependencies  : Pacs_DMC_SET_BBID and Pacs_DMC_SET_OBSID
//
// Comments      : 
//
// Version       : 0.1 12-Oct-2004 First creation
// History       : 0.2 21-Oct-2004 Added write to CDMS
// 1.0 24-Mar-2005 DAC Removed all writes except to DMC (ASTRIUM environment)
// 1.1 20-oct-2005 BBID and then OBSID; do not sync() before leaving as this
//                 is the last TC ever.
// 1.2 19-apr-2006 Do sync so duration() will give time for next TC
// 1.2.1 22-nov-2006 Removed debug_print
// 2.0 21-aug-2007 According to HERSCHEL SCIENCE GROUND SEGMENT
//                 TO INSTRUMENTS INTERFACE CONTROL DOCUMENT
//                 reference FIRST-FSC-DOC-0200; OBSID should be set
//                 to zero when no observing (in OBS phase)
//                 Removed write to BBID as all blocks now end by setting
//                 their BBIDs to the default value (SCR-3507) 
// 2.1 02-jun-2009 VD SCR 6979: according to an ever changing documentation
//     		      OBSID has to be set to 50000000hex
//
procedure WriteEndID {
}{
    //   int iBBID = 0x40000000;
    //    // Write BBID to DEC/MEC
    //    Pacs_DMC_SET_BBID(iBBID);
    int iOBSID = 0x50000000;
    // Write OBSID to DEC/MEC
    Pacs_DMC_SET_OBSID(iOBSID);
    sync();
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartBsmAngleCal.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpirePhoto/Spectro_Cal_BsmAngleCal.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V0.1: Initial version adapted from
//                  SpireBb_EndBsmAngleCal (2009/02/14 V1.1) and 
//                  SpirePhoto_Cal_BsmAngleCal (2009/04/01 V1.6)
//                  BB includes now to move BSM to hold.  
// 2009/07/12 V0.2: Fix bug in passing of SMEC home position (SPR-SPIRE-1612)
//                  Set SMEC framerate to zero to get all BSM samples 
//                  (SPR-SPIRE-1551).
// 
// Notes:
//    1) Scripts assumes that SpireBb_SpecOffsetAuto is run 
//       during INITHOLD or at first POINTING.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartBsmAngleCal SPIRE 14041 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    string obsModeQla = "ENG_CAL_OBS01";
    string obsMode = "PEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_Phot/SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    double framerate = 125.0; // Specifies the MCU framerate [Hz]
    int smecHomePosn = 3500; // SMEC home position
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartBsmAngleCal configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // In case move SMEC to home:
    // 
    if(!phot) {
        //
        // Calculate available time for possible movement:
        //
        int tmove = duration(SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug)) + duration(SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug)) + duration(SpireProc_Set_BsmFramerate(19,debug)) + duration(SpireBb_SpecOffsetAuto(false,debug));
        //
        // Calculate max offset for which time is available:
        //
        int smecMaxOff = tmove * 500;
        // Note, 500 is maximum possible SMEC speed.
        int smecStart = smecHomePosn + smecMaxOff;
        // Note, formula above only reasonable 
        // when smecHomePosn small compared to 39500  
        // Safety check: 
        if(smecStart > 39500) {
            smecStart = 39500;
        }
        if(debug) {
            debug_print("smecStart: " + smecStart);
            debug_print("smecHomePosn: " + smecHomePosn);
            debug_print("tmove: " + tmove);
        }
        // 
        // Move from maximal offset to home:
        //
        SpireProc_SmecMove2Home(smecHomePosn,smecHomePosn + smecMaxOff,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    if(phot) {
        SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    }
    //delay(timeSlewCal);
    // //
    // //
    // Set user requested framerate:
    // 
    int frate = SpireProc_CalcParam_BsmFramerate(framerate,debug);
    SpireProc_Set_BsmFramerate(frate,debug);
    // //
    // //
    // Set SMEC framerate (== SMEC sampling rate) to zero:
    //
    if(!phot) {
        SpireProc_Set_SmecFramerate(0,debug);
    }
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartBsmAngleCal configuration ended");
    SpireMsg(1,"  ..StartBsmAngleCal took " + (time() - t) + " seconds)");
    //
}

// SpireREDYtoPHOT_STBY
//
// $id$
//
// This procedure configures the instrument into the PHOT_STBY mode
// 
// The instrument should be in  the REDY mode before execution of this observation
//
//
// 08/11/2007 KJK: removed StartObs and EndObs building blocks from the engineering procedure
// 27/04/2009 KJK: bsmModel, bsmVersion and debug passed as parameters
// 09/06/2009 KJK: added parameter and commands to switch on PTC PID, if required
// 02/07/2009 MP: Added report of tables and memory checksums (SPIRE-SCR-1527)  
// 12/07/2009 MP: Changed default stabilisationTime (SCR-SPIRE-1632)
//  15/02/2010 KJK: SCR Spire-1887:
//                             Added OD PCAL FLash at end of procedure
//
procedure SpireREDYtoPHOT_STBY {
    int jfet_heater_V = 0; // Default jfet heater voltage at switch on
    string ptc = "Default" in ["Default","On","Off"]; // PTC status
    int ptcHold = 0; // time to wait for detectors to settle before starting PTC 
    int stabilisationTime = 120; // time (secs) to allow Detectors to stabilise before starting observations
    bool sampleDetectors = false; // sample detectors during the stabilisation periods
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string detVersion = "v00";
    string vssVersion = "v00";
    string ptcVersion = "v00";
    bool debug = false;
}{
    // set nominal housekeeping rate
    SpireBbSetNhkSampling("PHTSTBY","v00",debug);
    // // 
    // //
    // Report tables and do memory checksums:
    //
    SpireBb_RepTabAndMemChecksum();
    //
    //
    // -----------
    // configure BSM
    // -----------
    //
    // switch on BSM
    mois_comment("Procedure SPIRE_BSM_ON: to switch on the SPIRE BSM");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    mois_tmcheck("Check that parameter CHOPSENSPWR is set to 0");
    mois_tmcheck("Check that parameter JIGGSENSPWR is set to 0");
    SpireBbBsmOn("PHTSTBY",bsmModel,bsmVersion,debug);
    mois_comment("SPIRE SPIRE_BSM_ON Procedure Completed");
    mois_tmcheck("Check that parameter CHOPSENSPWR is set to 1");
    mois_tmcheck("Check that parameter JIGGSENSPWR is set to 1");
    mois_tmcheck("Check that parameter MODE is set to BSM_ON");
    //
    // initialise BSM
    mois_comment("Procedure SPIRE_BSM_INIT: to initialise the SPIRE BSM");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    mois_spacon("Ensure that SPIRE_BSM_ON procedure has been run before continuing");
    mois_tmcheck("Ensure that parameter MODE is set to BSM_ON");
    SpireBbBsmChopInit("PHTSTBY",bsmModel,bsmVersion,debug);
    SpireBbBsmJiggInit("PHTSTBY",bsmModel,bsmVersion,debug);
    // Setup  BSM sampling
    SpireBbSetBsmSampling("PHTSTBY",bsmVersion,debug);
    mois_comment("SPIRE SPIRE_BSM_INIT Procedure Completed");
    mois_tmcheck("Check that parameter MODE is set to BSM_INIT");
    //
    // ----------------
    // configure Detectors
    // ----------------
    //
    mois_comment("Procedure SPIRE_PDET_ON: to switch on the SPIRE Photometer");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    mois_tmcheck("Ensure that parameter MODE is set to BSM_INIT");
    mois_tmcheck("Ensure PLIABITSTAT is set to 0");
    mois_tmcheck("Ensure PSWJFETSTAT is set to 0");
    mois_tmcheck("Ensure PMLWJFETSTAT is set to 0");
    mois_tmcheck("Ensure parameters PSWJFET1V to PSWJFET6V are all set to 0");
    mois_tmcheck("Ensure parameters PMWJFET1V to PSWJFET4V are all set to 0");
    mois_tmcheck("Ensure parameters PLWJFET1V to PSWJFET2V are all set to 0");
    mois_spacon("Select the TM Display for SFT PARAMETERS");
    mois_tmcheck("PLIAP5V, PLIAP9V and PLIAM9V should all be set to 0");
    SpireBbPdetOn(jfet_heater_V,detVersion,vssVersion,debug);
    mois_comment("SPIRE SPIRE_PDET_ON Procedure Completed");
    mois_tmcheck("Ensure PLIABITSTAT is set to 1");
    mois_tmcheck("PLIAP5V should be ~5V");
    mois_tmcheck("PLIAP9V should be ~11.5V");
    mois_tmcheck("PLIAM9V should be ~-11.5V");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    mois_tmcheck("Ensure PSWJFETSTAT is set to 0x3F");
    mois_tmcheck("Ensure PMLWJFETSTAT is set to 0x7F");
    mois_tmcheck("Ensure parameters PSWJFET1V to PSWJFET6V are all < 0 - nominally within ~ -1V and -3V");
    mois_tmcheck("Ensure parameters PMWJFET1V to PSWJFET4V are all < 0 - nominally within ~ -1V and -3V");
    mois_tmcheck("Ensure parameters PLWJFET1V & PSWJFET2V are all < 0 - nominally within ~ -1V and -3V");
    mois_tmcheck("Ensure that parameter MODE is set to PHOTSTBY");
    if(sampleDetectors) {
        SpireBbSetDetSampling("PHTSTBY",true,detVersion,sampleDetectors,debug);
    }
    //
    // ----------------
    // configure SCU
    // ----------------
    //
    SpireBbSetScuSampling("PHTSTBY","v00",debug);
    //
    // ----------------
    // Configure PTC
    // ----------------
    //
    delay(ptcHold);
    if(ptc == "Default") {
        // read default status
        ptc = SpireProc_GetTableEntryString("SpireTable_DefaultParams.txt","mode","PHTSTBY","ptcVm",ptcVersion,debug);
    }
    SpireBbSetPtc(ptc,ptcVersion,debug);
    //
    // ----------------
    // Stabilisation
    // ----------------
    delay(stabilisationTime);
    //
    // -----------------------
    // Setup final detector sampling
    // -----------------------
    SpireBbSetDetSampling("PHTSTBY",true,detVersion,false,debug);
    //
    // ----------------
    // start of  OD PCAL Flash
    // ----------------
    SpireBb_PhotSetMode("PFlash",false,"v00","v00",debug);
    SpireBbPcalFlash("PFlash","v00",0,debug);
    SpireBb_PhotSetMode("PHTSTBY",false,"v00","v00",debug);
}

// SpirePOF3Pointing
//
// $id$
//
// This procedure calculates and returns the pointing parameters for the POF3 observing mode  
//
//  11/02/09: KJK Updated to reflect changed configuration and reconfiguration stages
//  03/07/2009  KJK:
//         Added configuration input parameters to pass to SpirePOF3Config and SpirePOF3End
//  05/07/2009 KJK:
//         SPR-1593 - added flashVersion to input parameters
//                         - changed call to SpireBbPcalFlash
//
//  22/07/2009 SDS:
//         SCR-1670 - Added pBool1 option to load new JM64 table which has +/- 126 arcseconds chop throw
//  27/07/2009 SDS:
//         SCR-1728 - Added chopVersion to be able set Kp/Ki/Kd for JM64 maps
//  10/08/2009 KJK:
//         SPR-1709:  Added new input parameter, comVersion to call to SpreBbPOF3Config
//  12/08/2009 KJK:
//         SPIRE-1804:Added chopVersion as new input parameter (changed chopVersion to bsmVersion in line with other scripts)
//                           Changed calls to SpirebBJiggle to provide versions and debug parameters
//         Changed call to read operating mode parameters from SpireTable_OpsParms
//  14/08/2009 KJK:
//         Spire-1759: Added duration of SpireBb_LoadTableJM65b() to tSlewMin, if necessary - it is no longer calculated
//                            in SpirePOF3Config()
//  25-Aug-2009 KJK:
//        SPR Spire-1641: Needed new input parameter bsmModel 
//  10-Sep-2009 KJK:
//        SCR Spire-1943: Needed new input parameter detVersion
//
{int,int,int,int,int,int,int} procedure SpirePOF3Pointing {
    int nMaps = 1; // total number of number of maps to perform
    int nCycles = 1; // number of nod cycles per map
    int nNodInts = 1; // number of nod integrations per nod position    
    int nCal = 99999; // number of nod cycles per Gyro calibration
    int nFlash = 99999; // number of nod cycles per PCAL flash
    bool isBright = false;
    string bsmModel = "initial";
    string bsmVersion = "v00"; // Version of the SpireTable_BsmNominalSettings.txt table
    string detVersion = "v00";
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParms
    string opsVersion = "v00";
    string flashVersion = "v00";
    string chopVersion = "v00"; // Version in cal table SpireTable_ChopParams
    string photVersion = "v00";
    string comVersion = "v00";
    bool debug = false;
    bool pBool1 = false; // Load 64-Point Jiggle Map Table?
}{
    //
    // ***** fetch fixed operating mode parameters *****
    //
    string obsMode = "POF3";
    // Jiggle Table ID
    int jiggleTable = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"TableId",opsVersion,debug);
    // Jiggle Table length
    int jiggleSize = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"TableSize",opsVersion,debug);
    // number of jiggle positions per nod position
    int nJiggs = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NJiggs",opsVersion,debug);
    // number of nod positions in a nod cycle
    int nNodPosns = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NNodPosns",opsVersion,debug);
    // initial flash flag
    bool initFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"InitFlash",spireVersion,debug);
    // final flash flag
    bool endFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"EndFlash",spireVersion,debug);
    //
    // ***** check inputs *****
    int nMoves = nMaps * nCycles * nNodPosns / 2;
    if(nMoves > 1200) {
        error("POFS3Pointing: number of nod switches is greater  than maximum allowed (1200): " + nMoves);
    }
    //
    // ****** calculate parameters for pointing mode ******
    //
    // minimum slew time
    int tSlewMin = duration(SpireBb_StartObsAll("POF3")) + duration(SpireBbPOF3Config("POF3",isBright,bsmVersion,photVersion,comVersion,debug)) + 2;
    if(pBool1) {
        tSlewMin = tSlewMin + duration(SpireBb_LoadTableJM64b());
    }
    //
    // time for Initial Hold
    int tInitHold = duration(SpireBbPOF3Init()) + 2;
    int tFlash = duration(SpireBbPcalFlash("PFlash",flashVersion,0,debug));
    if(endFlash || nFlash < nCycles) {
        tInitHold = tInitHold + tFlash;
    }
    //
    // time for Final Hold 
    int tFinalHold = duration(SpireBbPOF3End("PHTSTBY",isBright,bsmModel,bsmVersion,detVersion,photVersion,comVersion,debug)) + duration(SpireBb_EndObsAll(true)) + 2;
    if(endFlash || nFlash < nCycles) {
        tFinalHold = tFinalHold + tFlash;
    }
    //
    // time at hold position
    int tHold = tFlash + 2;
    //
    // number of nods per hold
    int nHold = 0;
    if(nFlash < nMaps * nCycles) {
        nHold = nFlash * nNodPosns / 2;
    }
    //
    int tp = duration(SpireBbJiggle("POF3",jiggleTable,0,nJiggs,nNodInts,0,opsVersion,chopVersion,debug)) + duration(SpireBbMove(0)) + 2;

    return {tSlewMin,tInitHold,tFinalHold,nMoves,tp,tHold,nHold};
}

// SpireBbPOF5Config
//
// $Id:$
//
// Building Block to configure the instrument for POF5 (scan map) operation
//
// The complete instrument setup operation is divided into two parts:
//   Configuration: actions that can be executed during the slew to the start
//          position of the S/C pointing mode.
//   Initialisation: actions that must be carried out at the S/C intial pointing
//          position before any observational operations are executed.   
//
// This building Block implements the first part of the setup 
//
//  02/07/2009 KJK: 
//         - Added bsmModel, isBright, bsmVersion, photVersion and debug input parameters
//         - Added use of possible bright-source settings
//  10/08/2009 KJK:
//         SPR-1709:  Added new input parameter, comVersion
//                           updated to execute SpireProc_Set_PhotMode if photversion is not "V00"
//  25-Aug-2009 KJK:
//        SPR Spire-1641: Now read BSM HOLD positions from SpireTable_BsmNominalSettings.txt rather than BSM.txt
//  25-Jan-2010 KJK: removed setting of MODE and Resetting of DRCU Counters as this is now done by BbStartObsAll
//
block SpireBbPOF5Config SPIRE 8272 {
    string obsMode = "POF5";
    bool isBright = false in [true,false];
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string photVersion = "v00";
    string comVersion = "v00";
    bool debug = false in [true,false];
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF5 Configuration started");
    SpireMsg(2,"          $Id:$");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // Move BSM to HOLD
    int bsmHoldChopPosn = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",bsmModel,"chop_0_I",bsmVersion,debug);
    int bsmHoldJiggPosn = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",bsmModel,"jigg_0_I",bsmVersion,debug);
    SpireBsmMove(bsmHoldChopPosn,bsmHoldJiggPosn);
    //
    // set biases and phases - if needed
    if(isBright) {
        SpireProc_Set_PhotBright(obsMode,photVersion,debug);
    } else {
        if(photVersion != "v00") {
            SpireProc_Set_PhotMode(obsMode,isBright,photVersion,comVersion,debug);
        }
    }
    //
    // ..... completion .....
    //
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF5 Configuration ended");
    SpireMsg(1,"  ..POF5 Configuration (" + (time() - t) + " seconds)");
}

// SpireSendDrcuCmd
//
// $Id: SpireSendDrcuCmd.txt,v 1.1 2006/08/10 09:38:59 kking Exp $
//
// Procedure to send a DRCU command
//
//
//
procedure SpireSendDrcuCmd {
    int cmd = 0x0;
    int override = 0;
}{
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    hstr = SpireHexStr(cmd,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SEND_DRCU_COMMAND_RAW(" + hstr + ")");
    Spire_SEND_DRCU_COMMAND_RAW(cmd,override);
}

// CVS comments  : $Id: Array2grp_1.txt,v 1.2 2007/04/25 15:14:03 dcesarsk Exp $ 
// Missionphase  : 
//
// Purpose       : Utility to create  grp_1 tuples out of 1D arrays.
//                 Many PACS TCs require a grp_1 argument. It appears that grp_1 are
//                 defined as "1 element" tuples, which conceptually is the same as a 1D
//                 array. The checksum function, on the other hand, which is used to checksum
//                 some PACS operands, acts on 1D arrays. So a grp_1 list cannot be checksummed
//                 unless a 1D array is created from the grp_1. This is error prone as the
//                 following construct is needed in many CUS instances:
//
//                 // TC operand    
//                   {int}[] spu_par = [{ppf},{ppp},{tfp},{tcp}];
//
//                 // Check sum argument array
//                    int aux = [ppf,ppp,tfp,tcp];
//                    int check_sum = checksum("int",aux);
//
//                 The utility Array2grp_1 will create "spu_par " given the array aux as
//                 input:
//
//                 {int} [] spu_par = Array2grp_1(aux);
//
// TCL author    : N/A
// TCL file      : N/A
// CUS author    : DAC
// Script file   : Array2grp_1.txt 
//
// Input arguments
// type     name         description
// int[]    array_in     Any 1D array containing elements needed as operand for a TC
//
// Return values
// type      Name     Description
// {int} []           A 1D tuple constructed with all the elements of the input array  
//
// Description   : Extract elements from array_in and insert them as "tuples" in tuple_out
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : 
// 
// History       : 0.1 creation by XXX
{int}[] procedure Array2grp_1 {
    int[] array_in = [0,1,2,3];
}{
    // Get dimension of array_in
    int nb_elem = length(array_in);
    // Create output tuple
    {int}[] tuple_out = [{0}];
    {int} aux = {0};
    // and fill it with elements from array_in
    for(int loop = 0 .. nb_elem - 1) {
        aux = {array_in[loop]};
        tuple_out[loop] = aux;
    }

    return tuple_out;
}

// SpirePacsParallel
//
// Proposed signature for PACS-SPIRE parallel observing mode
//
// v0.1, Initial version for ICD v1.01, 22-Aug-2006, Roland Vavrek  
// v0.2, 'mapScanRate' inserted, 24-Aug-2006 (RV)
// v0.3  Updated the returned values (AB)
// v0.4  Added 'scanDirection' and extra noise display 01-SEP-2006 (SJL/AB)
// v0.4.1 DAC, 18-oct-2006 Converted debug_print into SpireMsg
// v0.4.2 DAC,  2-mar-2007 New estimate of effective tOBS (SPR-2876)
// v0.4.3 DAC,  9-mar-2007 Red/blue RMS are exchanged (SPR-2876)
// v0.4.4 DAC, 10-mar-2007 Aclaratory e-mail from AB: return tuple
//                         contains extended sensitivities
// v0.4.4.1    22-mar-2007 DAC: Had forgotten to reset verbose=false
//
// 18/01/07: v1.8:  updated call to SpirePOF5Estimate to pass obsMode
// 16/02/07: V1.9:  SPR2836 - updated to correct calculation of efficiency
// 20/04/07: v1.14: Updated to use new interface with SpirePOF5Estimate
//           v1.15: SCR3012
//  9/10/07: v1.16: SCR3628. Get PACS defaults for parallel mode 
//
//  04 November 2008: added data_rate commands (SCR0953)
//  07 November 2008: Added isBright input parameters (SPR4136)
// 
//  19/11/2008 MP: added isBrightPacs to call of PacsPhotDefaults
//  05/07/2009 KJK:
//         SPR-1593 - Added flashVersion input parameter
//                         - Updated calls to SpirePOF5Pointing and SpireBbPcalFlash to use flashVersion 
//  15/08/2009 MP (SCR-SPIRE-1818): Needs change of call to SpirePOF5Pointing
//  16/08/2009 MP (SCR-SPIRE-1818): Change call to SpirePOF5Observing
//  25-Aug-2009 KJK:
//                        - Updated calls to OpsParms Table to use new version (SpireTable_OpsParms.txt)
//                        - Updated calls to SpireParms Table to use new version (SpireTable_SpireParams.txt)
//                        - SCR PHS-214 updated PACS code
//                        - SCR PHS-1156 updated PACS code - note this removes previous additional script (OBCP_TimeSynch3.cus)
// 15/09/2009 KJK:
//                        -SPR Spire-1924: call SpireBbPhotSerendipity with ParSer opsMode
//                        - modified call to SpirePacsBbParallel Init
// 07/12/2009 VD         -SPR PHS-1279 (Pacs favour) remove PacsPhotSlewCal from Hold state
// 15/02/2010 KJK: SCR Spire-1887:
//                     Added spireVersion to input parameters for call to SpirePOF5Observing
// 16/02/2010 KJK: SCR PHS-1324 :
//                     Updated to include PACS calibration block at end of observation
// 08/04/2010 SDS: SCR Spire-1887:
//                     Previous fix was not implemented correctly and caused no detector data to be generated in ODs 314-315.
//                     In Initial HOLD moved SpireBbStartDcuData(obsMode) outside the initFlash if-block.
//            
// 10/05/2010 SDS: SCR PHS-1314:
//                     Re-inserted the input parameters mapOffsetY and mapOffsetZ
//                     Removed the hard-coded zero values for mapOffsetY and mapOffsetZ
//                     Added the messages lines for yOffset and zOffset
// 22/06/2010 SCR PHS-1325                      
//
// 06/07/2010 SDS: SCR PHS-1485
//                    This script is now the same as attachment SpirePacsParallel_new.cus in SCR PHS-1485
// 31/01/2011 SDS: SCR SPIRE-3160
//                     Allow the expert user to specify the map length and height by setting pDouble1 and pDouble2 respectively.
//                     Only valid if pBool1 is also set to true.
//
///////////////////////////////////////////////////////////////////////////
{{string,double,double}[],double,double,int} obs SpirePacsParallel {
    double ra = 0.0 in [0.0,360.0]; // RA of Target
    double dec = 0.0 in [-90.0,90.0]; // DEC of Target
    string blue = "blue1" in ["blue1","blue2"]; // PACS blue filter selection
    double mapSize1 = 30.0 in [30.0,1200.0]; // map length (arcminutes)
    double mapSize2 = 30.0 in [30.0,1200.0]; // map height (arcminutes)
    double mapOffsetY = 0.0 in [-300.0,300.0]; // offset to observation position from target in Y direction (arcmins)
    double mapOffsetZ = 0.0 in [-300.0,300.0]; // offset to observation position from target in Z direction (arcmins)
    bool mapOrientationArray = true; // The map orientation reference frame is 'array'  (rather than array with sky constraints)
    double mapOrientationConFrom = 0.0 in [0.0,360.0];
    double mapOrientationConTo = 360.0 in [0.0,360.0];
    string mapScanRate = "fast" in ["fast","slow"];
    string scanDirection = "nominal" in ["nominal","orthogonal"];
    bool isBrightPacs = false; // Use settings for bright source (==tick)
    bool isBrightSpire = false; // Use settings for bright source (==tick)
    string bsmModel = "initial";
    string bsmVersion = "v00"; // Version in cal table SpireTable_BsmNominalSettings.txt
    string flashVersion = "v00"; // Version in cal table SPireTable_Flash.txt
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParams.txt
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms.txt
    string photVersion = "v00"; // Version in cal table SpireTable_PhotModeParams.txt
    string comVersion = "v00"; // Version in cal table SpireTable_CommonModeParams.txt
    bool debug = false;
    bool pBool1 = false; // If true the map length and height are set by the user
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 4.0; // Map length (arcminutes) - if pBool1 is true
    double pDouble2 = 4.0; // Map height (arcminutes) - if pBool1 is true
}{
    bool verbose = true;
    // Debug print verbosity
    if(pBool1) {
        mapSize1 = pDouble1;
        mapSize2 = pDouble2;
        SpireMsg(3,"Expert mode requested - pBool1 is set to " + pBool1);
        SpireMsg(3,"Map length set to: " + mapSize1);
        SpireMsg(3,"Map height set to: " + mapSize2);
    }
    //
    // *********************************************
    //      pointing mode parameters for SPIRE   
    // *********************************************
    //
    //
    string obsMode = "Par";
    if(mapScanRate == "fast") {
        obsMode = obsMode + "_F";
    } else {
        obsMode = obsMode + "_S";
    }
    if(scanDirection == "nominal") {
        obsMode = obsMode + "_N";
    } else {
        obsMode = obsMode + "_O";
    }
    SpireMsg(3,"  Observation Mode:" + obsMode);
    int nMaps = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NMaps",opsVersion,debug);
    int nRepetitions = 1;
    //
    // ***** observing mode parameters *****
    {double,double,int,int,int,int} pof5Obs = SpirePOF5Observing(obsMode,nRepetitions * nMaps,mapSize1,mapSize2,opsVersion,spireVersion,debug);
    double mapOsit = pof5Obs{0};
    int nRepeats = pof5Obs{2};
    int nLines = pof5Obs{3};
    int nCal = pof5Obs{4};
    int nFlash = pof5Obs{5};
    //
    // pointing mode input parameters:
    {int,int,int,int,int,double,double} pof5Point = SpirePOF5Pointing(obsMode,nRepeats,nLines,nCal,nFlash,isBrightSpire,bsmModel,bsmVersion,spireVersion,flashVersion,photVersion,comVersion,opsVersion,debug);
    //
    //
    // *********************************************
    //      pointing mode parameters for PACS   
    // *********************************************
    // Before issue PointReq need to do some nitty-gritty for PACS
    // NOTE: Re-use as much as possible code from PacsPhoto AOT.
    // NOTE: the conf arrays are inherited from PacsSpec, where the [0] element
    //       represented the default values, and the [n] element represented values
    //       to be used with the n-th wavelength. For PHOT, [0] still represents
    //       the default values and [1] values corresponding to the chosen filter.
    // NOTE: In this version BOLOs acquire data all the time, no OBCP is needed
    //       to start data taking
    {int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int}[] confOBCP = [{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}];
    // Define confPHOTblu and confPHOTred
    {int,int,int,int,int,int,int,int,int}[] confPHOTblu = [{0,0,0,0,0,0,0,0,0}];
    {int,int,int,int,int,int,int,int,int}[] confPHOTred = [{0,0,0,0,0,0,0,0,0}];
    // Define paramsPHOT, a "tuple of tuples"
    // Estimator module returns {confPHOTblu,confPHOTred,confOBCP}
    {{int,int,int,int,int,int,int,int,int},{int,int,int,int,int,int,int,int,int},{int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int}} paramsPHOT = {clone(confPHOTblu[0]),clone(confPHOTred[0]),clone(confOBCP[0])};
    // Obtain default values (here for largeSRC)
    paramsPHOT = PacsPhotDefaults("largeSRC","Parallel",isBrightPacs,verbose);
    // Array [0] of paramsPHOT contains the default values; array [1]
    // will contain the values based on HSPOT input. Array [1] is a copy of [0];
    // only elements depending on HSPOT will be updated
    // Copy default values to individual "conf" tuples
    confPHOTblu[0] = paramsPHOT{0};
    confPHOTred[0] = paramsPHOT{1};
    confOBCP[0] = paramsPHOT{2};
    // Get the durations of each activity:
    // - AOT prologue
    // - CAL observation
    // - Start OBCP (not really needed since BOLO acquires data non-stop)
    // - Possible CAL during "hold"
    // - AOT epilogue
    // Start computations for the "pre-calibration" cycle. This cycle to be
    // performed during the slew to the source.
    // First TC is associated with setting OBSID
    int timeSetOBSID = duration(WriteOBSID($OBSID));
    // Next call PacsPhotSlewCal. This script conditions the BOLO if doProlog is
    // set to true or just performs a calibration using an alredy conditioned BOLO
    // The time needed to perform these activities during slew is
    // Calibration alone:
    bool doProlog = false;
    int timeSlewCal = duration(PacsPhotSlewCal(verbose,confPHOTblu,confPHOTred,confOBCP,doProlog,blue));
    if(verbose) {
        SpireMsg(3,"Duration of SlewCal: " + timeSlewCal);
    }
    // Same but including prologue
    doProlog = true;
    int timeSlewCalProlog = duration(PacsPhotSlewCal(verbose,confPHOTblu,confPHOTred,confOBCP,doProlog,blue));
    int tWrite = duration(PacsBbWriteIdBB());
    int tWriteEnd = duration(PacsSpireBbWriteEndBB(0));
    if(verbose) {
        SpireMsg(3,"Duration of SlewCalProlog: " + timeSlewCalProlog);
    }
    // The total PACS time needed during slew is timeSlewCalProlog + timeSetOBSID;
    // Do not lose time with OBCPs. BOLOs are only stopped with AOT_epilogue
    // Deal with PHOT_aot_epilogue and WriteEndID
    int timeEpilogue = duration(PHOT_aot_epilogue());
    int timeEndID = duration(WriteEndID());
    timeEpilogue = timeEpilogue + timeEndID;
    if(verbose) {
        SpireMsg(3,"Duration aot_epilogue: " + timeEpilogue);
    }
    // *********************************************
    //      set up telescope pointing mode    
    // *********************************************
    // default values
    int naifid = 0;
    // no tracking in this mode
    // fixed parameters
    string ib = SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode",obsMode,"Boresight",opsVersion,debug);
    // Use SPIRE instrument boresight
    double deltaY = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"DeltaY",opsVersion,debug);
    // offset to pixel centre from boresight in Y direction (arcsecs)
    double deltaZ = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"DeltaZ",opsVersion,debug);
    // offset to pixel centre from boresight in Z direction (arcsecs)
    bool fixed = SpireProc_GetTableEntryBool("SpireTable_OpsParms.txt","mode",obsMode,"Fixed",opsVersion,debug);
    // pattern angle definition
    double patt = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"Patt",opsVersion,debug);
    // direction of scan lines in instrument coordinates 
    double yOffset = mapOffsetY * 60.0 + deltaY;
    // offset to observation position from target in Y direction (arcsecs)
    double zOffset = mapOffsetZ * 60.0 + deltaZ;
    // offset to observation position from target in Z direction (arcsecs)
    // calculated parameters
    int tSlewMin = timeSetOBSID + timeSlewCalProlog + pof5Point{0};
    int tih = pof5Point{1};
    // PHS-1324
    //    int tfh = timeEpilogue + pof5Point{2};
    int tfh = timeEpilogue + pof5Point{2} + timeSlewCal;
    int n = nLines;
    double scanLength = pof5Obs{1};
    double d2 = pof5Point{5};
    double rate = pof5Point{6};
    //
    // PHS-1279
    //    int tHold = timeSlewCal + pof5Point{3};
    int tHold = pof5Point{3};
    int nHold = pof5Point{4};
    int nRepeat = nRepeats;
    int[] ts = line_scan_pointing(true,tSlewMin,tih,tfh,ib,naifid,ra,dec,fixed,patt,yOffset,zOffset,n,scanLength,d2,rate,tHold,nHold,nRepeat);
    //Info from API (nomenclature from Jon Br)
    int tobs = ts[0];
    int tslew = ts[1];
    int tacc = ts[2];
    int tdec = ts[3];
    int tl = ts[4];
    int tll = ts[5];
    int trep = ts[6];
    int tend = ts[7];
    if(verbose) {
        SpireMsg(3,"##### line_scan_with_hold");
        SpireMsg(3,"##### rate: " + rate + " arcsec/sec");
        SpireMsg(3,"##### PntReq: " + ts);
        SpireMsg(3,"##### tobs : " + tobs);
        SpireMsg(3,"##### tslew: " + tslew);
        SpireMsg(3,"##### tacc : " + tacc);
        SpireMsg(3,"##### tdec : " + tdec);
        SpireMsg(3,"##### tl   : " + tl);
        SpireMsg(3,"##### tll  : " + tll);
        SpireMsg(3,"##### trep : " + trep);
        SpireMsg(3,"##### tend : " + tend);
    }
    //   How long it takes to scan a line [sec]
    int scanTime = tl;
    //   Gather the overheads
    int scanOVER = tacc + tdec;
    // fetch timing information
    //
    bool initFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"InitFlash",spireVersion,debug);
    // initial flash flag
    bool endFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"EndFlash",spireVersion,debug);
    // final flash flag
    int tFlash = duration(SpireBbPcalFlash("PFlash",flashVersion,0,debug));
    // time for a PCAL flash
    int tSerendipity = duration(SpireBbPhotSerendipity(obsMode,0));
    // minimum time for a serendipity observation
}{
    // *****************************************
    //   Display input parameters
    // *****************************************
    SpireMsg(3,"     Parallel Mode Input values:");
    SpireMsg(3,"     ..RA: " + ra);
    SpireMsg(3,"     ..Dec: " + dec);
    SpireMsg(3,"     ..blue: " + blue);
    SpireMsg(3,"     ..mapSize1: " + mapSize1);
    SpireMsg(3,"     ..mapSize2: " + mapSize2);
    SpireMsg(3,"     ..Y Offset: " + yOffset);
    SpireMsg(3,"     ..Z Offset: " + zOffset);
    SpireMsg(3,"     ..mapOrientationArray: " + mapOrientationArray);
    SpireMsg(3,"     ..mapOrientationConFrom: " + mapOrientationConFrom);
    SpireMsg(3,"     ..mapOrientationConTo: " + mapOrientationConTo);
    SpireMsg(3,"     ..mapScanRate: " + mapScanRate);
    SpireMsg(3,"     ..scanDirection: " + scanDirection);
    SpireMsg(3,"     Fixed values:");
    SpireMsg(3,"     ..ib: " + ib);
    SpireMsg(3,"     ..patt: " + patt);
    SpireMsg(3,"     ..d2: " + d2);
    SpireMsg(3,"     ..rate: " + rate);
    SpireMsg(3,"     PACS Parms:");
    SpireMsg(3,"     SPIRE Parms:");
    SpireMsg(3,"     ..initFlash: " + initFlash);
    SpireMsg(3,"     ..endFlash: " + endFlash);
    SpireMsg(3,"     Line Scan with Hold Pointing Mode Input values:");
    SpireMsg(3,"     ..tSlewMin: " + tSlewMin);
    SpireMsg(3,"     ..tInitHold: " + tih);
    SpireMsg(3,"     ..tFInalHold: " + tfh);
    SpireMsg(3,"     ..nLines: " + nLines);
    SpireMsg(3,"     ..scanLength: " + scanLength);
    SpireMsg(3,"     ..tHold: " + tHold);
    SpireMsg(3,"     ..nHold: " + nHold);
    SpireMsg(3,"     Line Scan Pointing Mode Output values:");
    SpireMsg(3,"     ..tobs: " + tobs);
    SpireMsg(3,"     ..tslew: " + tslew);
    SpireMsg(3,"     ..tacc: " + tacc);
    SpireMsg(3,"     ..tdec: " + tdec);
    SpireMsg(3,"     ..tl: " + tl);
    SpireMsg(3,"     ..tll: " + tll);
    SpireMsg(3,"     ..trep: " + trep);
    SpireMsg(3,"     ..tend: " + tend);
    // *****************************************
    //   execute observation
    // *****************************************
    SpireMsg(0,"Observation Start");
    SpireMsg(0,"  Uses SPIRE observing mode POF5 (Scan Map)");
    SpireMsg(3,"       $Id$");
    data_rate(0.0);
    double chkrate = SpireProc_GetTableEntryDouble("SpireTable_Datarates.txt","mode",obsMode,"CHK","v00",debug);
    ess_hk_data_rate(chkrate);
    double nhkrate = SpireProc_GetTableEntryDouble("SpireTable_Datarates.txt","mode",obsMode,"NHK","v00",debug);
    non_ess_hk_data_rate(nhkrate);
    //
    // State machine
    ///////////////////////// start of "commanding" section //////////////////////
    SpireMsg(3,"++++++++++++++++++++++++ Start Command Section");
    SpireMsg(3,"$$$$$$$$$$$$$$$$ State Machine $$$$$$$$$$$$$$$$$$");
    // Initialize some "global" variables
    int totalOBStime = 0;
    int totalOBSover = 0;
    int totalCALtime = 0;
    int totalCALover = 0;
    int nbSCANlegs = 0;
    string tstr = "";
    // time string
    int otf = 0x8000;
    // On Target Flag
    double srcTime = 0.0;
    //  total on source integration time
    int nl = 0;
    // line counter
    double s = 0.0;
    // Issue TCs
    int[] state = [0];
    int nbOBS = 0;
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // ***********************  SLEWING
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Slewing to start position");
            if(verbose) {
                int tNOW = time();
                SpireMsg(3,"=== SLEW/CAL starts at: " + tNOW);
            }
            // set up observation parameters
            SpireBbObsConfig(0x500);
            WriteOBSID($OBSID);
            // perform serendipity operation if possible
            if(tslew > tSerendipity + tSlewMin) {
                SpireBbPhotSerendipity("ParSer",tslew - tSlewMin - 2);
            }
            // configure instrument for operations
            SpirePacsBbParallelConfig(obsMode,isBrightSpire,bsmModel,bsmVersion,photVersion,comVersion,debug);
            doProlog = true;
            int[] calTime = PacsPhotSlewCal(verbose,confPHOTblu,confPHOTred,confOBCP,doProlog,blue);
            totalCALtime = totalCALtime + calTime[3];
            totalCALover = totalCALover + calTime[0];
            //
            if(verbose) {
                tNOW = time();
                SpireMsg(3,"=== SLEW/CAL ends at: " + tNOW);
                SpireMsg(3,"    TotalCalTime: " + totalCALtime);
            }
        }
        if(state[0] == 2) {
            // ***********************  INITIAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Initialising Instrument");
            if(verbose) {
                tNOW = time();
                SpireMsg(3,"=== INIT_HOLD starts at: " + tNOW);
            }
            // initialise instrument
            SpirePacsBbParallelInit(obsMode,debug);
            // calibrate if necessary
            if(initFlash || nFlash < nLines) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireBbPcalFlash("ParPFlash",flashVersion,otf,debug);
            }
            SpireBbStartDcuData(obsMode);
            //
            if(verbose) {
                tNOW = time();
                SpireMsg(3,"=== INIT_HOLD ends at: " + tNOW);
            }
        }
        if(state[0] == 3) {
            // ***********************  POINT
            if(verbose) {
                tNOW = time();
                SpireMsg(3,"=== INIT_HOLD starts at: " + tNOW);
            }
            // code for things to do during POINT would come here
            nbOBS = nbOBS + 1;
            if(verbose) {
                SpireMsg(3,"POINT: POINTobs: " + nbOBS);
            }
            //
            if(verbose) {
                tNOW = time();
                SpireMsg(3,"=== INIT_HOLD ends at: " + tNOW);
            }
        }
        if(state[0] == 5) {
            // ***********************  FINAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Reconfiguring Instrument");
            if(verbose) {
                tNOW = time();
                SpireMsg(3,"=== FINAL_HOLD starts at: " + tNOW);
            }
            // PHS-1324
            doProlog = false;
            calTime = PacsPhotSlewCal(verbose,confPHOTblu,confPHOTred,confOBCP,doProlog,blue);
            totalCALtime = totalCALtime + calTime[3];
            totalCALover = totalCALover + calTime[0];
            //
            // reconfigure instrument
            SpireBbStopDcuData();
            // calibrate if necessary
            if(endFlash || nFlash < nLines) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireBbPcalFlash("ParPFlash",flashVersion,otf | nl,debug);
            }
            // reconfigure back to PHOT_STBY configuration
            SpirePacsBbParallelEnd("PHTSTBY",isBrightSpire,bsmModel,bsmVersion,photVersion,comVersion,debug);
            //
            PHOT_aot_epilogue();
            WriteEndID();
            //
            if(verbose) {
                tNOW = time();
                SpireMsg(3,"=== FINAL_HOLD ends at: " + tNOW);
            }
        }
        if(state[0] == 6) {
            // ***********************  CAL_HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
            if(verbose) {
                tNOW = time();
                SpireMsg(3,"=== FINAL_HOLD starts at: " + tNOW);
            }
            // Calibrate SPIRE
            SpireBbStopDcuData();
            SpireBbPcalFlash("ParPFlash",flashVersion,otf | nl,debug);
            SpireBbStartDcuData(obsMode);
            // Calibrate PACS
            //            doProlog = false;
            //            calTime = PacsPhotSlewCal(false,confPHOTblu,confPHOTred,confOBCP,doProlog,blue);
            //            totalCALtime = totalCALtime + calTime[3];
            //            totalCALover = totalCALover + calTime[0];
            if(verbose) {
                SpireMsg(3,"Accumulated CALtime: " + totalCALtime);
            }
            //
            if(verbose) {
                tNOW = time();
                SpireMsg(3,"=== FINAL_HOLD ends at: " + tNOW);
            }
        }
        if(state[0] == 7) {
            // ***********************  NOD
            if(verbose) {
                tNOW = time();
                SpireMsg(3,"=== NOD starts at: " + tNOW);
            }
            // code for things to do during POINT would come here
            nbOBS = nbOBS + 1;
            if(verbose) {
                SpireMsg(3,"NOD: NODobs: " + nbOBS);
            }
            //
            if(verbose) {
                tNOW = time();
                SpireMsg(3,"=== NOD ends at: " + tNOW);
            }
        }
        if(state[0] == 8) {
            // ***********************  LINE
            PacsBbWriteIdBB();
            int line = state[2];
            int t = time();
            int tDelay = t + tl - tWriteEnd;
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Instrument scanning");
            SpireMsg(2,"    " + tstr + " Line " + nl);
            if(verbose) {
                tNOW = time();
                SpireMsg(3,"=== LINE starts at: " + tNOW);
                debug_print("LINE starts:" + tNOW);
                debug_print("tl: " + tl);
            }
            s = SpireBbScanLine(tl,otf | nl);
            PacsSpireBbWriteEndBB(tDelay);
            wait_until(t + tl);
            srcTime = srcTime + s;
            nl = nl + 1;
            SpireBbMove(0);
            //
            //    Do we need code to set BBID??
            totalOBStime = totalOBStime + scanTime;
            totalOBSover = totalOBSover + scanTime + scanOVER;
            nbSCANlegs = nbSCANlegs + 1;
            if(verbose) {
                SpireMsg(3,"=== SCAN mode, leg: " + nbSCANlegs);
                SpireMsg(3,"    TotalOBSTime: " + totalOBStime);
            }
            //
            if(verbose) {
                tNOW = time();
                SpireMsg(3,"=== LINE ends at: " + tNOW);
                debug_print("Line stops at: " + tNOW);
            }
        }
    }
    assert (time() == ts[0] + ts[1]);
    if(verbose) {
        tNOW = time();
        SpireMsg(3,"=== END state; time now: " + tNOW);
    }
    int timeObsEnd = time();
    int overOBS = totalOBSover - totalOBStime;
    int overCAL = totalCALover - totalCALtime;
    if(verbose) {
        SpireMsg(3,"+++ OBS ends at " + timeObsEnd + "; NbOBS: " + nbOBS);
        SpireMsg(3,"    totalOBStime :" + totalOBStime);
        SpireMsg(3,"    totalOBSover :" + overOBS);
        SpireMsg(3,"    totalCALtime :" + totalCALtime);
        SpireMsg(3,"    totalCALover :" + overCAL);
    }
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + " Observation Finished");
    // *****************************************
    //   time estimation parameters for SPIRE
    // *****************************************
    double sourceFluxPSW = -1.0;
    double sourceFluxPMW = -1.0;
    double sourceFluxPLW = -1.0;
    double sourceBrightPSW = -1.0;
    double sourceBrightPMW = -1.0;
    double sourceBrightPLW = -1.0;
    {string,double,double,double,double,bool,double,double,double}[] estimates = [];
    estimates = SpirePOF5Estimate(obsMode,double(nRepetitions),rate,sourceFluxPSW,sourceFluxPMW,sourceFluxPLW,sourceBrightPSW,sourceBrightPMW,sourceBrightPLW,isBrightSpire);
    // *****************************************
    //   time estimation parameters for PACS
    // *****************************************
    // Slew overheads: nrepeat*[tacc + (numLegs - 1)*tll]
    int slewOVER = nRepeat * (tacc + (n - 1) * tll);
    SpireMsg(3,"slewOVER/numLegs/nrep: " + slewOVER + "/" + n + "/" + nRepeat);
    // Estimate how long a given sky region has been seen
    // Bolo size: Short Size, i.e. 32 pixels and Long Size [arcsec]
    double boloSSize = 1.75 * 60.0;
    double boloLSize = 3.5 * 60.0;
    double boloArea = boloSSize * boloLSize;
    // Elementary integration time [sec] will be computed as fraction of bolo area
    // wrt to total mapped area
    // The mapped area has dimensions map1 and map2
    double map1 = boloSSize + scanLength;
    double map2 = boloLSize + double(n - 1) * d2;
    double mapArea = map1 * map2;
    double auxTIME = double(totalOBStime) * boloArea / mapArea;
    SpireMsg(3,"    BoloArea: " + boloArea + " [arcsec2]");
    SpireMsg(3,"    MapArea : " + mapArea + " [arcsec2]");
    SpireMsg(3,"    Total tOBS  : " + totalOBStime + " [sec]");
    SpireMsg(3,"    On-SRC tOBS : " + auxTIME + " [sec]");
    // Pass the pointing mode to RMS (may need it for SRC,REF considerations)
    int pointCase = 33;
    double[] pixRMS = PacsPhotNoiseRMS(pointCase,blue,auxTIME);
    SpireMsg(3,"RMS noise: " + pixRMS);
    //
    // *****************************************
    //   return time estimation parameters 
    // *****************************************
    double hLoss = dlookup("OpsParms.txt",obsMode,"HLoss");
    // map height loss  
    int observationOhds = timeObsEnd - iround(srcTime) - tslew;
    double efficiency = mapSize1 * mapSize2 * 3600.0 / (scanLength * (d2 * double(nLines - 1) - hLoss));
    SpireMsg(3,"  Efficiency: " + efficiency);
    SpireMsg(3,"  Overheads: " + observationOhds);
    // Return: band, point source noise, extended source noise
    // SPR-2876: red/blue were exchanged
    // Pnt source sensitivities
    double pntBLU = pixRMS[1];
    double pntRED = pixRMS[0];
    // Add extended source sensitivities (there were place holders because
    // missing "extended" estimate at the time)
    double extBLU = pixRMS[3];
    double extRED = pixRMS[2];
    {string,double,double}[] noiseLevels = [{"PACS Blue",pntBLU,extBLU},{"PACS Red",pntRED,extRED},{"SPIRE 250",estimates[0]{2},estimates[0]{7}},{"SPIRE 350",estimates[1]{2},estimates[1]{7}},{"SPIRE 500",estimates[2]{2},estimates[2]{7}}];

    return {noiseLevels,efficiency,srcTime,observationOhds};
}

//CLName: SpireBb_LoadTableSM01
//VMVersion: 2.8
//CLVersion: 1.1
//CLCVSId: $ID$
//TableId: 0x34
//TableLength: 0x1
//Date: 081103123924
block SpireBb_LoadTableSM01 SPIRE 3346 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableSM01 started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0x34
    Spire_SET_TABLE(0x34,0x1);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x34,0x0,1,[{0x986b9270}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x34,0x0,0x0);
    delay(4);
    //    int t_min = 1;
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableSM01 ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartJfetVssTestC.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpirePhoto_Cal_JfetVssTestC.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/21 V0.1: Initial version adapted from
//                  SpireBb_StartFovMapFpgScan (2009/05/05 V0.1)
// S.D.Sidher:
// 2010/01/11 V0.2: Removed Chop, Jiggle  and SMEC inputs and references
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartJfetVssTestC SPIRE 14071 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    string obsModeQla = "ENG_CAL_OBS16";
    string obsMode = "PEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_Phot/SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartJfetVssTestC configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    if(phot) {
        SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    }
    //delay(timeSlewCal);
    // //
    // //
    // Set Obs step at to 1:
    //
    int obsStep = 1;
    SpireProc_Set_ObsStep(obsStep,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartJfetVssTestC configuration ended");
    SpireMsg(1,"  ..StartJfetVssTestC took " + (time() - t) + " seconds)");
    //
}

// 
// SpireBb_LoadTableSM02
// BSM positions table for testing the effect of change in BSM rest position
// Table contains two BSM positions
// Position 1: Taken from SM01 table
// Position 2: BSM rest position from uplink calibration file SpireTable_BsmNominalSettings.txt
// Table ID: 58
// Sunil Sidher: 
// 19 July2011 V1.0: Initial version
//
block SpireBb_LoadTableSM02 SPIRE 3362 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableSM02 started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0x3a
    Spire_SET_TABLE(0x3a,0x2);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x3a,0x0,2,[{0x986b9270},{0x9a609300}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x3a,0x0,0x0);
    delay(4);
    //    int t_min = 1;
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableSM02 ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

//CLName: SpireBb_LoadTableFunctions
//VMVersion: 2.8
//CLVersion: 1.7
//CLCVSId: $ID$
//TableId: 0x64
//TableLength: 0x260
//Date: 090325130736
block SpireBb_LoadTableFunctions SPIRE 3334 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableFunctions started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0x64
    Spire_SET_TABLE(0x64,0x260);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x64,0x0,6,[{0x30000064},{0x300000f0},{0x30000102},{0x30000116},{0x30000183},{0x30000240}]);
    delay(t_min);
    //update table command call for table index 0x0064
    Spire_UPDATE_TABLE(0x64,0x64,38,[{0x205b0000},{0x205c0001},{0x12000000},{0x5dc},{0x13000000},{0x64},{0x34000001},{0x30000005},{0x1200005a},{0x7702},{0x5303005a},{0x30000079},{0x80005dc},{0x400005b},{0x2001005c},{0x14000001},{0x5dc},{0x9000001},{0x2000000},{0x1200005c},{0x0},{0x2000005b},{0x18000000},{0x40000000},{0x3200006f},{0xa00005c},{0x325c0014},{0x2000005b},{0x18000000},{0x30000000},{0x32000005},{0x1200005a},{0x520},{0x5302005a},{0x30000062},{0x14000000},{0x10000000},{0x32000005}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x64,0x8a,38,[{0x1200005a},{0x521},{0x5302005a},{0x3000005b},{0x1200005a},{0x522},{0x5302005a},{0x30000057},{0x2000005b},{0x18000000},{0x8000000},{0x3200001f},{0x2000005b},{0x18000000},{0xcfffffff},{0x2001005c},{0x18000001},{0xcfffffff},{0x22000001},{0x18000000},{0xcfffffff},{0x32000002},{0x30000032},{0x2000005b},{0x18000000},{0x30000000},{0x32000005},{0x1200005a},{0x50c},{0x5303005a},{0x30000040},{0x14000000},{0x10000000},{0x32000005},{0x1200005a},{0x50d},{0x5303005a},{0x30000039}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x64,0xb0,38,[{0x1200005a},{0x50e},{0x5303005a},{0x30000035},{0x2000005b},{0x18000000},{0xcfff0000},{0x2001005c},{0x18000001},{0xcfff0000},{0x22000001},{0x18000000},{0xcfff0000},{0x32000002},{0x30000014},{0x2000005b},{0x18000000},{0x30000000},{0x32000005},{0x1200005a},{0x50c},{0x5303005a},{0x30000022},{0x14000000},{0x10000000},{0x32000005},{0x1200005a},{0x50d},{0x5303005a},{0x3000001b},{0x1200005a},{0x50e},{0x5303005a},{0x30000017},{0x2000005c},{0x18000000},{0x30000000},{0x32000002}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x64,0xd6,38,[{0x30000015},{0x14000000},{0x10000000},{0x32000005},{0x1200005a},{0x509},{0x5303005a},{0x3000000b},{0x14000000},{0x10000000},{0x32000005},{0x1200005a},{0x50a},{0x5303005a},{0x30000004},{0x1200005a},{0x50b},{0x5303005a},{0x12000000},{0xffff},{0x30000006},{0x12000000},{0x0},{0x2001005c},{0x18000001},{0xffff},{0x41000000},{0x18000000},{0xf},{0x1b00001c},{0x18000000},{0xf0000000},{0x18000001},{0xfff},{0x1b010010},{0x18000001},{0xfff0000},{0x18000002}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x64,0xfc,38,[{0xffff},{0x21000001},{0x21000002},{0x19000000},{0x80000000},{0x20010003},{0x40000064},{0x41000000},{0x20280000},{0x20290001},{0x202a0002},{0x202b0003},{0x202c0004},{0x202d0005},{0x202e0006},{0x202f0007},{0x20300008},{0x20310009},{0x2032000a},{0x2033000b},{0x2034000c},{0x2035000d},{0x2036000e},{0x2037000f},{0x20380010},{0x20390011},{0x203a0012},{0x203b0013},{0x41000000},{0x40000104},{0x12000014},{0x7d0},{0x20170004},{0x14000017},{0xffff},{0x20150003},{0x14000015},{0x7d0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x64,0x122,38,[{0x14000015},{0x7d0},{0x32170002},{0x30000007},{0x14000015},{0x7d0},{0x14000015},{0x7d0},{0x14000015},{0x7d0},{0x32020002},{0x30000003},{0x14000015},{0x7d0},{0x35150014},{0x30000005},{0x12000000},{0x7000},{0x53010000},{0x3000004e},{0x20160000},{0x16000016},{0x2},{0x22161603},{0x14000016},{0x7d0},{0x14000016},{0x7d0},{0x14000016},{0x7d0},{0x32020002},{0x30000003},{0x14000016},{0x7d0},{0x35160014},{0x30000005},{0x12000000},{0x7001}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x64,0x148,38,[{0x53010000},{0x3000003a},{0x80007d0},{0x1000001},{0x12000003},{0x7d0},{0x9000003},{0x12000000},{0x0},{0x12000001},{0x43e},{0x12000002},{0x0},{0x400000f1},{0x12000000},{0x0},{0x12000001},{0x43d},{0x2002002a},{0x400000f1},{0x12000000},{0x0},{0x12000001},{0x43c},{0x20020029},{0x400000f1},{0x32020008},{0x12000000},{0x0},{0x12000001},{0x43e},{0x12000002},{0x1},{0x400000f1},{0x12000000},{0x1},{0x12000001},{0x1c1}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x64,0x16e,38,[{0x12000002},{0x0},{0x400000f1},{0x12000000},{0x1},{0x12000001},{0x1c3},{0x2002002c},{0x400000f1},{0x32170008},{0x12000000},{0x1},{0x12000001},{0x1c1},{0x12000002},{0x1},{0x400000f1},{0x20010015},{0x20020016},{0x12000000},{0x0},{0x80007d0},{0x1000000},{0x80007d0},{0x41000000},{0x40000104},{0x20140004},{0x20170007},{0x14000017},{0xffff},{0x80007d0},{0x1000001},{0x12000003},{0x7d0},{0x9000003},{0x12000000},{0x1},{0x12000001}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x64,0x194,38,[{0xc3},{0x20020028},{0x400000f1},{0x12000000},{0x1},{0x12000001},{0x143},{0x20020029},{0x400000f1},{0x12000000},{0x1},{0x12000001},{0xc6},{0x12000002},{0x1},{0x400000f1},{0x32170002},{0x30000015},{0x12000000},{0x1},{0x12000001},{0x1c1},{0x12000002},{0x0},{0x400000f1},{0x12000000},{0x1},{0x12000001},{0x1c3},{0x2002002f},{0x400000f1},{0x12000000},{0x1},{0x12000001},{0x1c1},{0x12000002},{0x1},{0x400000f1}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x64,0x1ba,38,[{0x9000005},{0x1000000},{0x80007d0},{0x1000001},{0x80007d0},{0x32080002},{0x3000000f},{0x12000000},{0x0},{0x12000001},{0x43e},{0x12000002},{0x0},{0x400000f1},{0x12000000},{0x0},{0x12000001},{0x43e},{0x12000002},{0x1},{0x400000f1},{0x9000006},{0x1000000},{0x80007d0},{0x1000001},{0x9000003},{0x12000000},{0x1},{0x12000001},{0xc3},{0x2002002a},{0x400000f1},{0x12000000},{0x1},{0x12000001},{0x143},{0x2002002b},{0x400000f1}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x64,0x1e0,38,[{0x12000000},{0x1},{0x12000001},{0xc6},{0x12000002},{0x1},{0x400000f1},{0x32170002},{0x30000015},{0x12000000},{0x1},{0x12000001},{0x1c1},{0x12000002},{0x0},{0x400000f1},{0x12000000},{0x1},{0x12000001},{0x1c3},{0x2002002f},{0x400000f1},{0x12000000},{0x1},{0x12000001},{0x1c1},{0x12000002},{0x1},{0x400000f1},{0x9000005},{0x1000000},{0x80007d0},{0x1000001},{0x80007d0},{0x32080002},{0x3000000f},{0x12000000},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x64,0x206,38,[{0x12000001},{0x43e},{0x12000002},{0x0},{0x400000f1},{0x12000000},{0x0},{0x12000001},{0x43e},{0x12000002},{0x1},{0x400000f1},{0x9000006},{0x1000000},{0x80007d0},{0x1000001},{0x9000003},{0x11000014},{0x3214ff79},{0x32080002},{0x30000008},{0x12000000},{0x0},{0x12000001},{0x43e},{0x12000002},{0x0},{0x400000f1},{0x32170002},{0x30000008},{0x12000000},{0x1},{0x12000001},{0x1c1},{0x12000002},{0x0},{0x400000f1},{0x12000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x64,0x22c,38,[{0x1},{0x12000001},{0xc3},{0x20020028},{0x400000f1},{0x12000000},{0x1},{0x12000001},{0x143},{0x20020029},{0x400000f1},{0x90c60001},{0x12000000},{0x1},{0x12000001},{0xc6},{0x12000002},{0x1},{0x400000f1},{0x12000000},{0x0},{0x80007d0},{0x1000000},{0x80007d0},{0x41000000},{0x22140706},{0x23141402},{0x22150006},{0x23151505},{0x23151503},{0x21160707},{0x22161606},{0x22161608},{0x23161604},{0x24161605},{0x20170014},{0x21171715},{0x21171716}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x64,0x252,14,[{0x1a170010},{0x21010117},{0x12000017},{0x0},{0x34010017},{0x20010017},{0x12000017},{0xffff},{0x35010017},{0x20010017},{0x12000000},{0x0},{0x41000000},{0x7f000000}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x64,0x0,0x0);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableFunctions ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

//CLName: SpireBb_LoadTableSM04
//VMVersion: 2.8
//CLVersion: 1.3
//CLCVSId: $ID$
//TableId: 0x36
//TableLength: 0x4
//Date: 100115132735
block SpireBb_LoadTableSM04 SPIRE 3347 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableSM04 started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    //set table command call for table id 0x36
    Spire_SET_TABLE(0x36,0x4);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x36,0x0,4,[{0x9a2a92fc},{0x9c1581bd},{0x7b6e89aa},{0x79839a87}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x36,0x0,0x0);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableSM04 ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
//
// SpireProc_Set_StartMcuData.txt
//
///////////////////////////////////////////////////////////////////////////
//
// Procedure to start generation of MCU science data (TM packets)
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/31 V0.1: Initial version adapted
//                  SpireProc_Set_StartDcuData (2009/02/18 V0.1)
// S.D.Sidher
// 2010/03/25 V0.2: Inserted command to generate continuous MCU frames
//
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_StartMcuData {
}{
    // //
    // //
    // Start procedure:
    //
    message("4    " + time() + ": SpireProc_Set_StartMcuData started");
    message("4          $Id: $");
    // //
    // //
    // Reset MCU (x2000) fifo:
    //
    message("5          " + time() + "Cmd: Spire_RESET_FIFOS(0x2000)");
    Spire_RESET_FIFOS(0x2000);
    delay(1);
    // //
    // //
    // Set MCU frames to continuous:
    //
    message("5          " + time() + "Cmd: Set MCU frames to continuous");
    SpireSendDrcuCmd(0x91c3ffff,0);
    // //
    // Start data collection:
    //
    SpireSendDrcuCmd(0x91c10001,0);
    sync();
    // //
    // //
    // End procedure:
    //
    message("4    " + time() + ": SpireProc_Set_StartMcuData ended");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_Cal_BsmPcalFlash.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Spec BSM PCAL Flash' 
//
//  in *basic_fine_pointing* or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/04 V0.1: Initial version adapted from 
//                  SpirePhoto_Cal_BsmPcalFlash (2009/03/04 V1.3)
// 2009/05/05 V0.2: Add in move BSM/SMEC to hold/home at start. Add new 
//                  SpireBb_SmecHold to account for the fact that
//                  SpireBb_SmecMove2Home does not stop SMEC.
//                  Gather procedures at start and end in separate BB. 
//
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in SPECSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for all three arrays and could be taken from following cal table: 
//  SpireTable_SpecModeParams.txt
//
//  3) Home position of BSM can be read from SpireTable_BsmNominalSettings.txt
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_Cal_BsmPcalFlash {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; //NAIF identifier: put '0' to use RA/DEC, or correct 'NAIFID'
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    bool isBright = false; // Use settings for bright source (==tick)
    string ib = "S24_0"; // Central aperture (defined in SIAM) of raster
    int c_start = 0x1000 in [0x1000,0xf000]; // RAW chop target start position
    int c_end = 0xf000 in [0x1000,0xf000]; // RAW chop target end position
    int c_step = 0x2000; // RAW chop target step in position
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial"; // Model in cal table SpireTable_BsmNominalSettings
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Check user input for chop/jiggle parameters :
    //
    if(c_end < c_start + c_step) {
        error("End chop is smaller than start chop plus 1*step. Try again!");
    }
    // //
    // //
    // Declare some variable:
    //
    // Spectrometer or FTS:
    bool phot = false;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    string tabName04 = "SpireTable_CommandLists.txt";
    string tabName06 = "SpireTable_SmecNominalSettings.txt";
    //
    // Currently hardcoded version:
    //
    string version06 = "v00";
    // Version in cal table SpireTable_SmecNominalSettings
    //
    // Currently hardcoded parameter:
    // Is (==tick) the DCU currently sampled? 
    bool dcuData = false;
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS42";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "SEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Read nominal bias frequency and bias divider:
    //    
    // Select version flag and set GetTableEntry parameters:
    version = version01;
    tabName = tabName01;
    selCol = "mode";
    // Name of column for selecting 
    selVal = obsMode;
    // Value of 'string' selector
    //
    tarCol = "mclkDiv";
    int mclkDiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "biasDiv";
    int biasDiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Calculate nominal sampling rate from mclkdiv and biasdiv:
    //
    double mclkdivHz = 1.0E7 / (512.0 * double(mclkDiv + 1));
    double biasdivHz = 1.0 / (double(biasDiv) + 1.0) * mclkdivHz;
    if(debug) {
        debug_print("Nominal sampling rate is: " + biasdivHz + " [Hz]");
    }
    // //
    // //
    // Read BSM home position: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version03;
    tabName = tabName03;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set jigg position during test to hold_jigg:
    int jiggPosn = hold_jigg;
    // //
    // //
    // Read VM parameters from calibration table:
    //
    tabName = tabName04;
    selVal = "Flash";
    int vmId = ilookup(tabName,selVal,"Id");
    int vmIndex = ilookup(tabName,selVal,"Index");
    int nParms = ilookup(tabName,selVal,"Nparms");
    // //
    // //
    // Read SMEC home position from calibration file:
    //
    tarCol = "Home";
    tabName = tabName06;
    selVal = version06;
    int smecHomePosn = ilookup(tabName,selVal,tarCol);
    //
    // // // // // // // // // // // // // // // // 
    // // // // // // // // // // // // // // // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartBsmPcalFlash(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug));
    // 
    // BBs carried out when the pointing is reached:
    if(pointing) {
        int tinithold = duration(SpireBb_SpecOffsetAuto(dcuData,debug)) + duration(SpireBb_SmecHold(debug));
    } else {
        tinithold = tslewmin + duration(SpireBb_SpecOffsetAuto(dcuData,debug)) + duration(SpireBb_SmecHold(debug));
    }
    //
    // BB carried out during pointing:
    int tp = duration(SpireProc_Exec_BsmPcalFlash(c_start,c_end,c_step,jiggPosn,mclkDiv,biasDiv,vmId,vmIndex,nParms,fts,debug));
    //
    // BB carried out at the end:
    int tfinalhold = duration(SpireBb_EndBsmPcalFlash(phot,hold_chop,hold_jigg,isBright,version01,version02,debug));
    //
    // Debug_printing?
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // 
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW (Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartBsmPcalFlash(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation:
                //
                SpireBb_StartBsmPcalFlash(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug);
            }
            // //
            // //
            // Set offsets:
            //
            SpireBb_SpecOffsetAuto(dcuData,debug);
            // //
            // //
            // Stop any remaining SMEC movement:
            //
            SpireBb_SmecHold(debug);
            //
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            // //
            // //
            // Execute loop of BSM Pcal flashes:
            //
            SpireProc_Exec_BsmPcalFlash(c_start,c_end,c_step,jiggPosn,mclkDiv,biasDiv,vmId,vmIndex,nParms,fts,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            SpireBb_EndBsmPcalFlash(phot,hold_chop,hold_jigg,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SpecFSetupData.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set bias frequency, amplitude, and phase of spectrometer arrays
//
// Note: Script does also set biasmode to 255 (sine) and frames to 0 (continous)
// 
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/11 V0.1: Initial version adapted from 
//                  SpireBb_PhotFSetupData.txt (2008/07/03 V0.2)
//                  Setup_SF_Data.txt (v1.4 2008/01/31 20:24:36)
// 2009/01/31 V1.0: Add debug_print as input. Change some comments. 
//                  Replace last delay(1) with sync(). Remove unsetting
//                  off BBID at end. 
// 2009/06/05 V1.1: Replace Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd 
//                  as requested in SPR-1482.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SpecFSetupData SPIRE 14013 {
    int mclkdiv = 0x79; //Default (IST) bias freq (==160.1 Hz)
    int biasdiv = 0x1; //Default (IST) sampling freq (==80.0 Hz)
    int ssw_bias = 0x2d; //Default (IST) bias amplitud  (==31.1 mV)
    int slw_bias = 0x2d; //Default (IST) bias amplitud  (==31.1 mV)
    int ssw_phase = 0x83; //Default phase (IST)  (== 184.93 deg)
    int slw_phase = 0x87; //Default phase (IST)  (== 190.59 deg)
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Set fixed (for flight) parameters:
    //
    // Default (IST) sine bias mode generation:
    int biasmode = 0xff;
    //
    // Default (IST) number of frames to request: 
    // (do not use frames, but only ftime to select time)
    int frames = 0;
    // //
    // //
    // Safety checks
    //
    if(biasdiv < 1) {
        biasdiv = 1;
    }
    if(biasdiv > 255) {
        biasdiv = 255;
    }
    if(mclkdiv < 64) {
        mclkdiv = 64;
    }
    if(mclkdiv > 511) {
        mclkdiv = 511;
    }
    // //
    // //
    // Calculate bias and sampling frequencies based on mclkdiv and biasdiv:  
    //
    // Calculate bias frequency Hz:
    double bias_f = 1.0E7 / (512.0 * double(mclkdiv + 1));
    // Calculate sampling rate Hz:
    double s_rate = bias_f / (1.0 + double(biasdiv));
    // //
    // //
    // Verify sampling rate does not exceed 20Hz for full spectrometer array:
    // 
    if(s_rate > 80.5) {
        do {
            biasdiv = biasdiv + 1;
            s_rate = bias_f / (1.0 + double(biasdiv));
            if(debug) {
                debug_print("New bias divisor is: " + biasdiv);
                debug_print("New sampling rate is: " + s_rate);
            }
        } while (s_rate > 80.5);
    }
    // //
    // //
    // Calculate frametime (time between successive frames = 1/sampling rate): 
    //
    // Frametime difference in ms:
    double framerate = 1.0 / s_rate * 1000.0;
    // //
    // //
    // Debug printout:
    //
    if(debug) {
        debug_print("    BIAS FREQUENCY IS : " + bias_f + " [Hz]");
        debug_print("SAMPLING FREQUENCY IS : " + s_rate + " [Hz]");
        debug_print("    FRAMETIME DIFF IS : " + framerate + " [ms]");
    }
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set bias mode:
    //
    SpireSendDrcuCmd(0x84300000 + biasmode,0);
    delay(1);
    // //
    // //
    // Set data mode:
    //
    SpireSendDrcuCmd(0x843c0004,0);
    //delay(1);
    // //
    // //
    // Set number of frames to continuous:
    //
    SpireSendDrcuCmd(0x843d0000 + frames,0);
    delay(1);
    // //
    // //
    // Set mclkdiv and biasdiv:
    //
    SpireSendDrcuCmd(0x84390000 + mclkdiv,0);
    //delay(1);
    SpireSendDrcuCmd(0x84380000 + biasdiv,0);
    delay(1);
    // //
    // //
    // Set bias amplitude:
    //
    SpireSendDrcuCmd(0x84310000 + ssw_bias,0);
    //delay(1);
    SpireSendDrcuCmd(0x84320000 + slw_bias,0);
    delay(1);
    // //
    // //
    // Set phase:
    //
    SpireSendDrcuCmd(0x843a0000 + ssw_phase,0);
    //delay(1);
    SpireSendDrcuCmd(0x843b0000 + slw_phase,0);
    sync();
    //
}

// CVS comments  : $Id: Msec2sec.txt,v 1.2 2007/04/25 15:14:03 dcesarsk Exp $ 
// Missionphase  : 
//
// Purpose       : Convert [msec] into [sec]. This is needed since CUS
//                 granularity is the second. 
//
// Author CUS    : Diego A. Cesarsky (diego.cesarsky@mpe.mpg.de)
//
// Author TCL    : N/A
//
// Original TCL  : N/A
//
// Input arguments
// Type  Name      DefVal  Description
// int   milisec   N/A     A duration [msec] to be converted into [sec]
//
// Description   : Convert int msec into float sec (for instance 1230 msec
//                 gets converted to 1.230 [sec] and take next closest integer
//                 (2 in this example)
//
// Dependencies  : None
//                 
// Comments      : 
//
// Version       : 0.1 13-Aug-2004 First creation
// History       : 
//               :
//
int procedure Msec2sec {
    int milisec = 0;
}{
    double fwait = double(milisec) / 1000.0;
    int secnds = iceil(fwait);

    return secnds;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartDcuData.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to start generation of detector data (TM packets)
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/05/01 V0.1: Initial version adapted from old Start_DCU_Data.txt
//                  templates used in ILT; replaces old 
//                  SpireBbStartDcuData.txt script
// 2008/07/03 V0.2: Renumber version; add RESET_FIFO at start
// 2009/02/18 V1.0: Remove datamode from input. Remove setting of 
//                  #frames, remove unsetting of BB at end. Remaining
//                  commands are now move to low level procedure
//                  SpireProc_Set_StartDcuData now called. 
// 2009/06/05 V1.1: Fix Hspot message at end of script (SPR-1481).
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartDcuData SPIRE 14002 {
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_StartDcuData started");
    SpireMsg(2,"          $Id:$");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Start DCU data:
    //
    SpireProc_Set_StartDcuData();
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_StartDcuData ended");
    SpireMsg(1,"  ..StartDcuData End (" + (time() - t) + " seconds)");
}

//CLName: SpireBb_LoadTableJM07
//VMVersion: 2.8
//CLVersion: 2.5
//CLCVSId: $ID$
//TableId: 0x32
//TableLength: 0x10
//Date: 091123174125
block SpireBb_LoadTableJM07 SPIRE 3341 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableJM07 started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    //

    //set table command call for table id 0x32
    Spire_SET_TABLE(0x32,0x10);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x32,0x0,16,[{0x9a19b5c0},{0x9a196b88},{0xa1cab5c0},{0xa1ca6b88},{0x9df1b836},{0x9df16ecd},{0x9640b836},{0x96406ecd},{0x9267b5c0},{0x92676b88},{0x9640b336},{0x96406847},{0x9df1b336},{0x9df16847},{0x9a19b5c0},{0x9a196b88}]);
    delay(t_min);    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x32,0x0,0x0);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableJM07 ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //


}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Set_DcuFreqSampMode.txt
//
///////////////////////////////////////////////////////////
//
// Procedure to configure the DCU bias frequency, sampling rate, 
// and dcuDatamode 
//
///////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/15 V0.1: Initial version adapted from
//                  SpireProc_Set_PhotPhase (2009/02/14 V0.2) and
//                  SpireBb_PhotFSetupData (2009/01/31 V1.0)
// 2009/06/05 V1.0: Replace Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd 
//                  as requested in SPR-1482.
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_DcuFreqSampMode {
    int mclkDiv = 149; // Bias freq. (for photometer == 130.20833 Hz)
    int biasDiv = 6; // Sampling freq. (for photometer == 18.60119 Hz)
    int dcuDataMode = 0; // Detector data sampling mode [0==Phot,4==FTS]
    bool phot = true; // Set for photometer (==tick) or FTS 
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string tstr = "";
    //
    // Photometer or FTS?:
    bool fts = !phot;
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"     " + tstr + ": SpireProc_Set_DcuFreqSampMode started");
    SpireMsg(4,"          $Id:$");
    // //
    // //
    // Set the selected bias frequency, sampling frequency, and DCU data mode:
    //
    // Set mclkdiv and biasdiv:
    //
    if(phot) {
        SpireSendDrcuCmd(0x84190000 + mclkDiv,0);
        SpireSendDrcuCmd(0x84180000 + biasDiv,0);
    } else {
        SpireSendDrcuCmd(0x84390000 + mclkDiv,0);
        SpireSendDrcuCmd(0x84380000 + biasDiv,0);
    }
    delay(1);
    //
    // Set DCU data mode :
    //
    SpireSendDrcuCmd(0x843c0000 + dcuDataMode,0);
    sync();
    // //
    // //
    // Calculate bias and sampling frequencies based on mclkdiv and biasdiv:  
    //
    // Calculate bias frequency Hz:
    double bias_f = 1.0E7 / (512.0 * double(mclkDiv + 1));
    //
    // Calculate sampling rate Hz:
    double s_rate = bias_f / (1.0 + double(biasDiv));
    // //
    // //
    // Calculate frametime (time between successive frames = 1/sampling rate): 
    //
    //Frametime difference in ms:
    double framerate = 1.0 / s_rate * 1000.0;
    // //
    // //
    // Debug Printing:
    //
    //
    if(debug) {
        debug_print("    BIAS FREQUENCY IS : " + bias_f + " [Hz]");
        debug_print("SAMPLING FREQUENCY IS : " + s_rate + " [Hz]");
        debug_print("    FRAMETIME DIFF IS : " + framerate + " [ms]");
        debug_print("     DCU DATA MODE IS : " + dcuDataMode);
    }
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"      " + tstr + ": SpireProc_Set_DcuFreqSampMode ended");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndBsmAngleCal.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of SpireProc_Exec_BsmAngleCal
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/01/30 V1.0: Initial version
// 2009/02/14 V1.1: Set instrument back to Phot/Spec-STBY. Move BSM back 
//                  to its hold position. 
// 2009/05/05 V1.2: Include setting of SpireBb_EndObsAll. 
// 2009/05/07 V1.3: Set dcuFrameNumber and mcuFrameNumber back to continuous
//                  to unset setting passed to VM. 
// 2009/06/05 V1.4: Replace Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd 
//                  as requested in SPR-1482.
// 2009/07/12 V1.5: Set SMEC framerate back to nominal. (SPR-SPIRE-1551).
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndBsmAngleCal SPIRE 14026 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    int hold_chop = 37632; // Chop hold position [Dec(Hex)]
    int hold_jigg = 39520; // Jiggle hod position [Dec(Hex)]
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndBsmAngleCal reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set obsstep back to 0:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP(0)");
    Spire_SET_OBS_STEP(0);
    // //
    // //
    // Set instrument back to Phot/Spec-STBY:
    //
    if(phot) {
        SpireProc_Set_PhotMode("PHTSTBY",isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Set number of DCU frames to continuous:
    //
    int dcuFrameNumber = 0;
    if(phot) {
        dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","PHTSTBY","dcuFrameNumber","v00",debug);
    } else {
        dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuFrameNumber","v00",debug);
    }
    //
    SpireSendDrcuCmd(0x843d0000 + dcuFrameNumber,0);
    // //
    // //
    // Set number of MCU frames to continuous:
    //
    int mcuFrameNumber = 0;
    if(phot) {
        mcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","PHTSTBY","mcuFrameNumber","v00",debug);
    } else {
        mcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","mcuFrameNumber","v00",debug);
    }
    SpireSendDrcuCmd(0x91c30000 + mcuFrameNumber,0);
    delay(1);
    // //
    // //
    // Set SMEC framerate (== SMEC sampling rate) back to SPEC_STBY:
    // (Note, hardcoded version to go back to STBY)
    //
    if(!phot) {
        int smecFrameRate = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","smecFrameRate","v00",debug);
        SpireProc_Set_SmecFramerate(smecFrameRate,debug);
    }
    // //
    // End observation:
    //
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndBsmAngleCal reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

// SpireEngUpdateTables
//
// $id$
//
// This observation updates OBS tables
// 
// The instrument should normally be in REDY mode before execution 
// of this observation.
//
//
// 09/11/2009 SDS: First Version 1.0  (Copied from SpireEngLoadtables)
// 10/11/2009 SDS: Version 1.1
//                            Set the size of the VM TM storage table (SPIRE-SCR-2144)
//
// 23/11/2009 SDS: Version 1.2
//                             Load new JM07 and JM64 tables (SPIRE-SCR-2195)
// 15/01/2010 SDS: Version 1.3
//                             Load new SM04 and SM16 tables (SPIRE-SCR-2308)
// 28/01/2010 SDS: Version 1.4
//                             1) Inserted BB to stop the on-board monitoring 
//                             2) Load new Actions, Monitor, SCAL and PTC tables:
//                             Temperature limits in the Monitor table updated (SPIRE-SCR-2187)
//                             FDIR actions enabled in the Monitor table (SPIRE-SCR-2176)
//                             PTC table updated (SPIRE-SCR-2239)
//                             SCAL table updated (SPIRE-SCR-2333)
//                             Actions table updated (SPIRE-SCR-2239, SPIRE-SCR-2317, SPIRE-SCR-2333 
//                             3) Insert BB to start on-board monitoring with FDIR actions enabled 
// 19/07/2011 SDS: Version 1.5
//                             Inserted new BB for loading SM02 table (SPIRE-SCR-3622)
///////////////////////////////////////////////////////////////////////////
obs SpireEngUpdateTables {
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int t = duration(SpireBbStartObs()) + duration(SpireBbEndObs());
    // ********* update for tables to be loaded *******
    // SCR-SPIRE-1828 in MC 37 for OD100 
    //t = t + duration(SpireBb_LoadTable_050());
    //t = t + duration(SpireBb_LoadTable_075());
    // SCR-SPIRE-1883 in MC 40 for OD113  
    //t = t + duration(SpireBb_LoadTable_075());
    //t = t + duration(SpireBb_LoadTable_102());
    // SCR-SPIRE-1683 in MC 44 for OD122
    //t = t + duration(SpireBb_LoadTable_054());
    //t = t + duration(SpireBb_LoadTable_053());
    // SCRs Spire-2104 and Spire-2105
    //t = t + duration(SpireBb_LoadTable_050());
    //t = t + duration(SpireBb_LoadTable_051());
    // SCRs Spire-2130
    //t = t + duration(SpireBb_LoadTable_050());
    //
    //t = t + duration(SpireBb_SetVMStorage());
    //t = t + duration(SpireBb_LoadTableJM07()) + duration(SpireBb_LoadTableJM64());
    //t = t + duration(SpireBb_LoadTableSM04()) + duration(SpireBb_LoadTableSM16());
    // t = t + duration(SpireBb_StopMonitoring()) + duration(SpireBb_LoadTableMonitor()) + duration(SpireBb_LoadTableSCAL()) + duration(SpireBb_LoadTablePTC()) + duration(SpireBb_LoadTableActions()) + duration(SpireBb_StartMonitoring());
    // SCR-SPIRE-3622
    t = t + duration(SpireBb_LoadTableSM02());
    // ***********************************************
    int[] ts = no_pointing(true,0,0,t);
}{
    SpireMsg(0,"Observation Start");
    SpireMsg(3,"       $Id:$");
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            SpireBbStartObs();
            // SCR-SPIRE-1828 in MC 37 for OD100
            //SpireBb_LoadTable_050();
            //SpireBb_LoadTable_075();
            // SCR-SPIRE-1883 in MC 40 for OD113
            //SpireBb_LoadTable_075();
            //SpireBb_LoadTable_102();
            // SCR-SPIRE-1683 in MC 44 for OD122
            //SpireBb_LoadTable_054();
            // SpireBb_LoadTable_053();
            // SCR Spire-1933 in MC 51 for OD151
            // SCR Spire-2104 in MC 53 for OD167 - updated JM07 table
            //SpireBb_LoadTable_050();
            // SCR Spire-2105 in MC 53 for OD167 - updated JM64 table
            //SpireBb_LoadTable_051();
            // SCR-SPIRE-2130 in MC58 for OD180/181:
            //SpireBb_LoadTable_050();
            // SCR-SPIRE-2144
            //SpireBb_SetVMStorage();
            // SCR-SPIRE-2195
            //SpireBb_LoadTableJM07();
            //SpireBb_LoadTableJM64();
            //SpireBb_LoadTableSM04();
            //SpireBb_LoadTableSM16();
            //SpireBb_StopMonitoring();
            //SpireBb_LoadTableMonitor();
            //SpireBb_LoadTableSCAL();
            //SpireBb_LoadTablePTC();
            //SpireBb_LoadTableActions();
            //SpireBb_StartMonitoring();
            // SCR-SPIRE-3622 - New table SM02
            SpireBb_LoadTableSM02();
            SpireBbEndObs();
        }
    }
    SpireMsg(0,"Observation Completed  (" + time() + " seconds)");
    SpireMsg(0,"Note: Total time (s) = Observation Completed time - slew time + Observatory Overheads");
}

// $Id: WriteEndBB.txt,v 1.2 2007/08/22 10:21:52 dcesarsk Exp $ 
// Purpose       : Set BBID to its default value to indicate the end
//                 of current BB execution (see FIRST-FSC-DOC-0200) 
//
// CUS script    : Diego A. Cesarsky (diego.cesarsky@mpe.mpg.de)
//
// Input arguments N/A
//
// Description   : BBID will be set to its default value
//
// Comments      : Needed for SCR-3507
//
// Version       : 0.1 21-aug-2007 First creation
//
procedure WriteEndBB {
}{
    int iBBID = 0x40000000;
    // Write BBID to DEC/MEC
    Pacs_DMC_SET_BBID(iBBID);
}

//CLName: SpireBb_LoadTableJM64
//VMVersion: 2.8
//CLVersion: 2.2
//CLCVSId: $ID$
//TableId: 0x33
//TableLength: 0x80
//Date: 091123174345
block SpireBb_LoadTableJM64 SPIRE 3345 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableJM64 started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    //
    //set table command call for table id 0x33
    Spire_SET_TABLE(0x33,0x80);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x33,0x0,38,[{0x9204cc65},{0x920443e2},{0x89f0cb4c},{0x89f041c9},{0x81dccc65},{0x81dc43e2},{0x71b4cc65},{0x71b443e2},{0x79c8cb4c},{0x79c841c9},{0x81dcca22},{0x81dc3fb8},{0x79c8c8e8},{0x79c83db2},{0x81dcc79e},{0x81dc3bb6},{0x81dcc4db},{0x81dc37dd},{0x89f0c363},{0x89f03601},{0x9204c4db},{0x920437dd},{0x89f0c644},{0x89f039c4},{0x9204c79e},{0x92043bb6},{0x89f0c8e8},{0x89f03db2},{0x9204ca22},{0x92043fb8},{0x9a19cb4c},{0x9a1941c9},{0xa22dcc65},{0xa22d43e2},{0xaa41cb4c},{0xaa4141c9},{0xa22dca22},{0xa22d3fb8}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x33,0x26,38,[{0x9a19c8e8},{0x9a193db2},{0xa22dc79e},{0xa22d3bb6},{0x9a19c644},{0x9a1939c4},{0x9a19c363},{0x9a193601},{0xa22dc4db},{0xa22d37dd},{0xaa41c363},{0xaa413601},{0xaa41c644},{0xaa4139c4},{0xb255c79e},{0xb2553bb6},{0xaa41c8e8},{0xaa413db2},{0xb255ca22},{0xb2553fb8},{0xba69cb4c},{0xba6941c9},{0xb255cc65},{0xb25543e2},{0xaa41cd6d},{0xaa414604},{0x89f0cd6d},{0x89f04604},{0x81dcce63},{0x81dc482e},{0x79c8cd6d},{0x79c84604},{0x71b4ce63},{0x71b4482e},{0x79c8cf47},{0x79c84a61},{0x81dcd019},{0x81dc4c9b}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x33,0x4c,38,[{0x79c8d0d8},{0x79c84edc},{0x81dcd184},{0x81dc5124},{0x81dcd29f},{0x81dc55c7},{0x89f0d21c},{0x89f05373},{0x9204d29f},{0x920455c7},{0x9204d184},{0x92045124},{0x89f0d0d8},{0x89f04edc},{0x9204d019},{0x92044c9b},{0x89f0cf47},{0x89f04a61},{0x9204ce63},{0x9204482e},{0xa22dce63},{0xa22d482e},{0xaa41cf47},{0xaa414a61},{0xb255ce63},{0xb255482e},{0xba69cd6d},{0xba694604},{0xba69cf47},{0xba694a61},{0xb255d019},{0xb2554c9b},{0xaa41d0d8},{0xaa414edc},{0xb255d184},{0xb2555124},{0xaa41d21c},{0xaa415373}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x33,0x72,14,[{0xa22dd29f},{0xa22d55c7},{0x9a19d21c},{0x9a195373},{0xa22dd184},{0xa22d5124},{0x9a19d0d8},{0x9a194edc},{0xa22dd019},{0xa22d4c9b},{0x9a19cf47},{0x9a194a61},{0x9a19cd6d},{0x9a194604}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x33,0x0,0x0);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableJM64 ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //

}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_SpecBiasConvert.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to translate user input in mV for bias amplitude 
//  into nearest Hex values for ssw_bias,and slw_bias  
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/11 V0.1: Initial version adapted from
//                  SpireProc_CalcParam_PhotBiasConvert (2008/07/03 V0.4) 
//                  Proc_BiasConvertS (v1.4 2008/01/31 20:24:35)
// 2009/02/19 V0.2: Add debug_print as input and implement.
//
///////////////////////////////////////////////////////////////////////////
int[] procedure SpireProc_CalcParam_SpecBiasConvert {
    double input_bias_ssw = 0.0 in [0.0,176.385]; // Input SSW Bias amplitude [0.0 - 176.385] [mV]
    double input_bias_slw = 0.0 in [0.0,176.417]; // Input SLW Bias amplitude [0.0 - 176.417] [mV]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Predefine version:
    //
    string ver_ssw = "v01";
    string ver_slw = "v01";
    if(debug) {
        debug_print("The nominal/hardcoded version is v01");
    }
    // //
    // //
    // Retrieve the maximum bias amplitude:
    //
    double maxbias_ssw = dlookup("SpireTable_SpecSswMaxbias.txt",ver_ssw,"maxbias");
    double maxbias_slw = dlookup("SpireTable_SpecSlwMaxbias.txt",ver_slw,"maxbias");
    // //
    // //
    // Convert from mV to RAW values:
    //
    double conversion_factor_ssw = 255.0 / maxbias_ssw;
    double conversion_factor_slw = 255.0 / maxbias_slw;
    //
    int raw_bias_ssw = iround(conversion_factor_ssw * input_bias_ssw);
    int raw_bias_slw = iround(conversion_factor_slw * input_bias_slw);
    //
    // Safety check:
    if(raw_bias_ssw > 255) {
        raw_bias_ssw = 255;
        if(debug) {
            debug_print("SSW exceeded limit!");
        }
    }
    if(raw_bias_slw > 255) {
        raw_bias_slw = 255;
        if(debug) {
            debug_print("SLW exceeded limit!");
        }
    }
    //
    double bias_ssw = double(raw_bias_ssw) / conversion_factor_ssw;
    double bias_slw = double(raw_bias_slw) / conversion_factor_slw;
    // //
    // //
    // Printout:
    //
    if(debug) {
        debug_print("Input mV value for SSW/SLW bias amplitude: " + input_bias_ssw + "/" + input_bias_slw);
        debug_print("Output Hex values for SSW/SLW: " + raw_bias_ssw + "/" + raw_bias_slw);
        debug_print("Commanded mV values for SSW/SLW: " + bias_ssw + "/" + bias_slw);
    }
    // //
    // //
    // Return required values:
    //

    return [raw_bias_ssw,raw_bias_slw];
}

///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndObs.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure after an engineering observation
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/05/02 V0.1: Initial version adapted from old EndObs.txt 
//                  template used in ILT; replaces old 
//                  SpireBbEndObs.txt script
// 2008/11/12 V0.2: Add re-setting of Obsmode parameter to PHOT/SPEC-STBY
//                  Values fixed for SOVT2
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndObs SPIRE 14004 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
}{
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    Spire_SET_BBID($BBID);
    //delay(1);
    // //
    // //
    // Reset ObsMODE to PHOT/SPEC-STBY:
    //
    // int mode_id = ilookup("InstrumentConfigurations.txt",obsmode,"value");
    if(phot) {
        int mode_id = 768;
        // Set mode back to PHOTSTBY
    } else {
        mode_id = 1024;
        // Set mode back to SPECSTBY
    }
    Spire_SET_OBS_MODE(mode_id);
    delay(1);
    // //
    // //
    // Set the BBID(s) back to null:
    //
    Spire_SET_BBID_RAW(0x80000000);
    //delay(1);
    //
    // //
    // //
    // Set the OBSIDs to null:
    //
    int null_obsid = SpireNullObsid();
    Spire_SET_OBSID(null_obsid);
    delay(1);
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_CalGCO_FpgInitialPointing.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Spec Focal Plane Geometry (Initial Pointing)'
//
//         in *custom_map_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/11/07 V0.1: Initial version adapted from
//                  SpirePhoto_CalGCO_FpgInitialPointing (2008/11/06 V0.11)
// 2008/11/12 V0.2: Implement mode setting; Add isBright 
//                  Implement proper setting of MCU framerate
//                  Change default gyro re-calibration period
// 2009/02/19 V0.3: Add debug_print as input abd pass to low level scripts. 
//                  Replace call to SpireProc_Set_BsmFramerate with call to 
//                  SpireBb_SetBsmFramerate. Set obsStep back to zero at
//                  FINAL_HOLD. Use new SpireBb_EndObsAll and 
//                  SpireBb_StartObsAll. Read nominal bias frequency, bias
//                  divider, and BSM sampling rate from new
//                  SpireTable_SpecModeParams. Implemented setting 
//                  of datarates. Implemented isBright setting. 
//                  Replace SpireBb_BsmMove2Hold with SpireBb_BsmMove.
//                  Add safety check for off chop BSM position. Set limits 
//                  for d1 in input. Use SpireBb_SpecSetMode to set to SPECSTBY
//                  during SLEW and FINAL_HOLD, which replaces unsetting of
//                  framerate at end. Remove cal. table from input. 
//                  Read some VM parameters from cal. table 
//                  SpireTable_CommandLists.txt. Adapt input to updated 
//                  SpireBb_Chop.
// 2009/03/03 V0.4: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. 
// 2009/05/06 V0.5: Add in move BSM/SMEC to hold/home at start. Add new 
//                  SpireBb_SmecHold to account for the fact that
//                  SpireBb_SmecMove2Home does not stop SMEC.
//                  Gather procedures at start and end in separate BB. 
//                  Properly compare input BSM framerate with SPECSTBY value.
// 2009/05/11 V0.6: Allow number of raster points as input. 
// 2009/07/17 V1.0: Change patt from 90 to 0 (SPR-SPIRE-1673)
// Sunil Sidher
// 2009/07/28 V1.1: Change patt from 0 to 180 (SPIRE SPR-1746)
// 
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in SPECSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for all three arrays and could be taken from following cal table: 
//  SpireTable_SpecModeParams.txt
//
//  3) Home position of BSM can be read from SpireTable_BsmNominalSettings.txt
//
//  4) Some VM parameters for chopping are read from following cal table:
//     SpireTable_CommandLists.txt
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_CalGCO_FpgInitialPointing {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; //NAIF identifier: put '0' to use RA/DEC, or correct 'NAIFID'
    bool isBright = false; // Use settings for bright source (==tick)
    /* */
    double raoff = 0.0 in [0.0,360.0]; // RA of GCP position
    double decoff = 0.0 in [-90.0,90.0]; // DEC of GCP position 
    string ib = "S24_0"; // Central aperture (defined in SIAM) of raster
    int m = 5; // Number of points in raster along Y [odd number!]
    int n = 5; // Number of points in raster along Z [odd number!]
    double d1 = 4.0; // Angular stepsize between raster pts [arcsec]
    int ftime = 15; // Read-out time [s]
    double chopf = 2.0 in [0.1,4.0]; // Chop frequency [Hz] 
    int offChopfh = 9600; // off-source chop position (+ or - relative to hold) [Dec(Hex)]
    double framerate = 125.0; // Specifies the MCU framerate [Hz]
    int gcp_time = 20; // Time spend at GCP (gyro calibration position) [s]
    int gcp_period = 600; // Maximum time between successiv GCP visits [s]
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_SpecFpgInitialPointing
    string version05 = "v00"; // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial"; // Model in cal table SpireTable_BsmNominalSetting
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // //
    // //
    // Current restrictions:
    //
    if(naifid != 0) {
        error("Currently no SSO objects are allowed as input!");
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = false;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_SpecFpgInitialPointing.txt";
    string tabName04 = "SpireTable_CommandLists.txt";
    string tabName05 = "SpireTable_BsmNominalSettings.txt";
    string tabName06 = "SpireTable_SmecNominalSettings.txt";
    //
    // Currently hardcoded version parameter:
    //
    string version06 = "v00";
    // Version in cal table SpireTable_SmecNominalSettings
    //
    // Currently hardcoded parameter:
    // Is (==tick) the DCU currently sampled? 
    bool dcuData = false;
    //
    bool setFramerate = true;
    //
    int tslewminadd = 0;
    int tfinalholdadd = 0;
    //
    int obsStep = 0;
    //
    // Start timing of script:
    int start = time();
    //
    // First obsstep [HEX]:
    int obsstep = 0x0;
    //
    // Count raster points: 
    int raster_counter = 0;
    //
    // Angular stepsize along Z axis [arcsec]:
    double d2 = d1;
    // NOTE: Script works only for equidistant raster points in both axes:
    //
    // DCU data mode (0 == Full photometer; 4 == Full spectrometer):
    int dcumode = 4;
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS34";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "SEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Setup parameters for BSM chopping movement: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version05;
    tabName = tabName05;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // on-source Chop position [Dec(Hex)]:
    int onChop = hold_chop;
    // on-source Jiggle position:
    int onJigg = hold_jigg;
    // off-source Chop position:
    int offChop = hold_chop + offChopfh;
    // off-source Jiggle position:
    int offJigg = hold_jigg;
    //
    // Check chop off position:
    //
    if(offChop > 50000) {
        error("Off chop is larger than 50000. Reduce offChopfh");
    }
    //
    // Read VM parameters from calibration table:
    //
    tabName = tabName04;
    selVal = "Chop";
    int vmId = ilookup(tabName,selVal,"Id");
    int vmIndex = ilookup(tabName,selVal,"Index");
    int nParms = ilookup(tabName,selVal,"Nparms");
    // //
    // //
    // Read nominal bias frequency and bias divider:
    // (to determine the sampling rate)
    //    
    // Select version flag and set GetTableEntry parameters:
    version = version01;
    tabName = tabName01;
    selCol = "mode";
    // Name of column for selecting 
    selVal = obsMode;
    // Value of 'string' selector
    //
    tarCol = "mclkDiv";
    int mclkDiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "biasDiv";
    int biasDiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Read SPECSTBY framerate:
    //
    selVal = "SPECSTBY";
    version = version02;
    tabName = tabName02;
    tarCol = "bsmFrameRate";
    int bsmFrameRate = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    double bsmFrameRateHz = 1000000.0 / (double(bsmFrameRate) * 420.0);
    if(debug) {
        debug_print("Nominal BSM sampling rate is: " + bsmFrameRateHz + " [Hz]");
    }
    //
    // Compare nominal with input BSM framerate:
    // 
    int frate = SpireProc_CalcParam_BsmFramerate(framerate,debug);
    if(frate == bsmFrameRate) {
        setFramerate = false;
    }
    //
    // Calculate nominal sampling rate from mclkdiv and biasdiv:
    //
    double mclkDivHz = 1.0E7 / (512.0 * double(mclkDiv + 1));
    double biasDivHz = 1.0 / (double(biasDiv) + 1.0) * mclkDivHz;
    if(debug) {
        debug_print("Nominal sampling rate is: " + biasDivHz + " [Hz]");
    }
    // //
    // //
    // Compare read-out time and dwell time on GCP:
    //
    int dtime = 0;
    // time to be spend on GCP position
    if(gcp_time < ftime) {
        dtime = ftime;
    } else {
        dtime = gcp_time;
    }
    //
    // Calculate BSM chop parameters:
    //
    int[] chopparam1 = SpireProc_CalcParam_BsmSetup(ftime,chopf,biasDivHz,framerate,debug);
    int ncycles = chopparam1[0];
    int chop_period = chopparam1[1];
    int dcusample = chopparam1[2];
    int dcudelay = chopparam1[3];
    int bsmsample = chopparam1[4];
    int[] chopparam2 = SpireProc_CalcParam_BsmSetup(dtime,chopf,biasDivHz,framerate,debug);
    int ncycles_2 = chopparam2[0];
    int chop_period_2 = chopparam2[1];
    int dcusample_2 = chopparam2[2];
    int dcudelay_2 = chopparam2[3];
    int bsmsample_2 = chopparam2[4];
    // //
    // //
    // Read SMEC home position from calibration file:
    //
    tarCol = "Home";
    tabName = tabName06;
    selVal = version06;
    int smecHomePosn = ilookup(tabName,selVal,tarCol);
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    // 
    int tslewmin = duration(SpireBb_StartFpgInitialPointing(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,setFramerate,frate,debug));
    // 
    // BBs carried out when the pointing is reached:
    //
    int tinithold = 0;
    //
    // BB carried out during pointing:
    // 
    int tp_np = duration(SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles,chop_period,dcumode,dcusample,dcudelay,bsmsample,obsstep,debug)) + duration(SpireBb_SpecOffsetAuto(dcuData,debug));
    int tp_gp = duration(SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles_2,chop_period_2,dcumode,dcusample_2,dcudelay_2,bsmsample_2,obsstep,debug)) + duration(SpireBb_SpecOffsetAuto(dcuData,debug));
    //
    // BB carried out at the end:
    //
    int tfinalhold = duration(SpireBb_EndFpgInitialPointing(phot,hold_chop,hold_jigg,isBright,version01,version02,debug));
    // //
    // //
    // Debug printing:
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing normal= " + tp_np);
        debug_print("tpointing @GCP= " + tp_gp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                              */
    // ****************************************************** */
    // //
    // //
    // Fixed parameters for pointing mode:
    //   
    bool fixed = false;
    // Pattern orientation (true==sky; false==array)
    double patt = 180.0;
    // Rotation angle of the pattern
    double yoffset = 0.0;
    // Offset of pattern in the direction of the +Y
    double zoffset = 0.0;
    // Offset of pattern in the direction of the +Z
    int thold = 0;
    // The duration of the hold when nhold>0.
    int nhold = 0;
    // Number of nods or raster points or scan lines before
    //              // performing a hold.
    double pattnod = 0.0;
    //
    double chopthrow = 2.0;
    //
    int nnod = 1;
    //
    int knod = 0;
    //
    int nload = 0;
    //
    int tloadmin = 0;
    //
    // //
    // //
    // Calculate array of points:
    //
    {double[],double[],int} array = SpireProc_CalcParam_FpgInitialPointing(d1,d2,m,n,tabName03,version03,debug);
    double[] zarray_org = array{0};
    double[] yarray_org = array{1};
    int numpixel = array{2};
    int nump_org = length(yarray_org);
    // //
    // //
    // Add GCP visit after every raster point (except first which is GCP)
    // and create tp (duration of fine pointing) vector new raster:
    //
    double[] yarray = [0.0];
    double[] zarray = [0.0];
    int run = 1;
    int aindex = 1;
    int fin = length(yarray_org);
    yarray[0] = yarray_org[0];
    zarray[0] = zarray_org[0];
    bool gcpp = false;
    int[] tpv = [0];
    tpv[0] = tp_gp;
    do {
        if(gcpp) {
            yarray[aindex] = yarray_org[0];
            zarray[aindex] = zarray_org[0];
            tpv[aindex] = tp_gp;
            gcpp = false;
        } else {
            yarray[aindex] = yarray_org[run];
            zarray[aindex] = zarray_org[run];
            tpv[aindex] = tp_np;
            run = run + 1;
            gcpp = true;
        }
        aindex = aindex + 1;
    } while (run < fin);
    // Add GCP visit at end:
    yarray[aindex] = yarray_org[0];
    zarray[aindex] = zarray_org[0];
    tpv[aindex] = tp_gp;
    //
    // //
    // //
    if(debug) {
        debug_print("timing vector : " + tpv);
        debug_print("zarray_org: " + zarray_org);
        debug_print("zarray: " + zarray);
    }
    //
    // Calculate slew times in pointing mode:
    //
    int[] ts_tr = custom_map_pointing(false,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,fixed,patt,yoffset,zoffset,yarray,zarray,tpv,pattnod,chopthrow,nnod,knod,tloadmin,nload,thold,nhold);
    //
    if(debug) {
        debug_print("Pointing vector : " + ts_tr);
    }
    // //
    // //
    // Determine maximal slew to GCP:
    //
    int nump = length(yarray);
    int nslews = nump;
    int nlslews = numpixel;
    int tpp = ts_tr[7];
    int[] tslews = [0];
    tslews[0] = 0;
    for(int j = 1 .. nslews - 1) {
        if(debug) {
            debug_print("entry: " + (j + 6));
        }
        tslews[j] = ts_tr[j + 6];
    }
    //
    int maxslew = 0;
    for(int k = 0 .. length(tslews) - 1) {
        maxslew = iceil(max(double(maxslew),double(tslews[k])));
    }
    if(debug) {
        debug_print("nlslews: " + nlslews);
        debug_print("nslews: " + nslews);
        debug_print("tslews: " + tslews);
        debug_print("maxslew: " + maxslew);
    }
    // //
    // //
    // Determine slew time between small raster points:
    //
    int tppn = tslews[1];
    // == slew beteen first and second raster point
    // //
    // //
    // Decrease frequency of GCP visits until gcp_period matched
    //
    //   
    int kgcp = 1;
    int ktime = 0;
    int ktime_old = 0;
    int nslew = 0;
    do {
        ktime_old = ktime;
        //
        // Count number of slews between the mxn rasters: 
        if(2 * kgcp + 1 > (nslew + 1) * m * n) {
            nslew = nslew + 1;
            if(debug) {
                debug_print("nslew: " + nslew);
            }
        }
        //
        // Calculate approximate(!) time between off visits :
        // [Problem: slews are not 100% predictable with single dummy run]
        //
        ktime = tp_gp + kgcp * tp_np + (kgcp - nslew) * tppn + nslew * maxslew + 2 * maxslew;
        // 
        // Add safety time:
        // [to account for possible longer slews than in dummy run] 
        ktime = ktime + 0;
        int kdiff = ktime - ktime_old;
        //
        // Print out error if gcp_period < ktime for first case 
        // (== having a GCP after each point):
        if(kgcp == 1) {
            if(gcp_period < ktime) {
                if(debug) {
                    debug_print("gcp_period < ktime: " + gcp_period + " < " + ktime);
                }
                error("gcp_period smaller than expected times between GCP visits! Change input parameters!");
            }
        }
        // 
        if(debug) {
            debug_print("tpv[0]: " + tpv[0]);
            debug_print("tp_np: " + tp_np);
            debug_print("tp_gp: " + tp_gp);
            debug_print("tppn: " + tppn);
            debug_print("maxslew: " + maxslew);
            debug_print("nslew: " + nslew);
            debug_print("ktime-ktime_old: " + kdiff);
            debug_print("ktime loop kgcp/ktime: " + kgcp + "/" + ktime);
        }
        //
        //
        // Increment kgcp (i.e delay visit to GCP by one more raster point): 
        if(debug) {
            debug_print("increment kgcp by 1");
        }
        kgcp = kgcp + 1;
        if(debug) {
            debug_print("new kgcp: " + kgcp);
        }
        //
    } while (ktime < gcp_period);
    //
    // Select last kgcp for which condition was fulfilled:
    int kgcp_old = 1;
    if(kgcp > 2) {
        kgcp_old = kgcp - 2;
    }
    message("Return to GCP after every " + kgcp_old + " normal raster point(s)!");
    //
    if(debug) {
        debug_print("values after kgcp selection loop:");
        debug_print("nump: " + nump);
        debug_print("nslews: " + nslews);
        debug_print("tslews: " + tslews);
        debug_print("maxslew: " + maxslew);
        debug_print("ktime loop end: " + ktime);
        debug_print("kgcp loop end:" + kgcp);
        debug_print("ktime_old: " + ktime_old);
        debug_print("kgcp_old:" + kgcp_old);
    }
    // //
    // //
    // Add visits to the GCP tp raster array:
    //
    int counter = 0;
    double[] yarray_new = [0.0];
    double[] zarray_new = [0.0];
    double ygcp = yarray[0];
    double zgcp = zarray[0];
    if(debug) {
        debug_print("ygcp/zgcp: " + ygcp + "/" + zgcp);
        debug_print("zarray: " + zarray);
    }
    //
    // Start loop:
    int end = nump_org;
    int ln = 0;
    int stop = 0;
    int index = 0;
    bool[] raster = [true];
    do {
        if(debug) {
            debug_print("stop : " + stop);
            debug_print("end : " + end);
            debug_print("index : " + index);
            debug_print("counter: " + counter);
        }
        if(counter > kgcp_old - 1) {
            yarray_new[index] = ygcp;
            zarray_new[index] = zgcp;
            ln = ln + 1;
            counter = 0;
            raster[index] = false;
        } else {
            yarray_new[index] = yarray_org[index - ln];
            zarray_new[index] = zarray_org[index - ln];
            if(debug) {
                debug_print("index -ln : " + (index - ln));
            }
            stop = stop + 1;
            counter = counter + 1;
            raster[index] = true;
        }
        index = index + 1;
    } while (stop < end);
    //
    // Define first point always as regular raster point:
    raster[0] = true;
    //
    // Add additional visit to GCP at end:
    // (could give unsymmetric GCP visits but ensures a GCP at start AND end)
    if(debug) {
        debug_print("index : " + index);
    }
    if(yarray_new[index - 1] != ygcp) {
        yarray_new[index] = ygcp;
        zarray_new[index] = zgcp;
        raster[index] = false;
    }
    // 
    if(debug) {
        debug_print("# pts without GCPs: " + length(yarray_org));
        debug_print("# pts with GCPs: " + length(yarray_new));
        debug_print("yarray_org: " + yarray_org);
        debug_print("zarray_org: " + zarray_org);
        debug_print("yarray_new = " + yarray_new);
        debug_print("zarray_new = " + zarray_new);
    }
    //
    // Adapt tp vector to new number of points:
    int[] tpv_new = [0];
    for(int ind = 0 .. length(yarray_new) - 1) {
        if(ind == 0) {
            tpv_new[0] = tpv[0];
        } else {
            if(yarray_new[ind] == ygcp) {
                if(zarray_new[ind] == zgcp) {
                    tpv_new[ind] = tp_gp;
                } else {
                    tpv_new[ind] = tp_np;
                }
            } else {
                tpv_new[ind] = tp_np;
            }
        }
    }
    if(debug) {
        debug_print("raster vector: " + raster);
        debug_print("new timing vector : " + tpv_new);
        debug_print("length(raster): " + length(raster));
        debug_print("length(yarray_new): " + length(yarray_new));
        debug_print("length(tpv_new): " + length(tpv_new));
    }
    // //
    // //
    // Set pointing mode:
    //
    //custom_map_pointing(true, tslewmin, tinithold, tfinalhold, ib, naifid,
    //ra,dec,fixed,patt,yoffset,zoffset,yarray,zarray,tpv, pattnod,chopthrow,
    //nnod,knod,tloadmin,nload, thold, nhold);
    //
    int[] ts = custom_map_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,fixed,patt,yoffset,zoffset,yarray_new,zarray_new,tpv_new,pattnod,chopthrow,nnod,knod,tloadmin,nload,thold,nhold);
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC              */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //     
            SpireBb_StartFpgInitialPointing(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,setFramerate,frate,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            //
            //
            //delay(tinithold);
        }
        if(state[0] == 3) {
            // STATE = POINT (spacecraft is at nominal RA,DEC (staring, raster))
            //
            //delay(tp);
            // //
            // //
            // Set offsets at each raster point:
            //
            SpireBb_SpecOffsetAuto(dcuData,debug);
            // //
            // //
            // Different timings for different raster points (normal vs. GCP):
            // 
            if(raster[raster_counter] == false) {
                // //
                // //
                // Show time elapsed between visits to GCP:
                int t = time() - start;
                message("Time elapsed since last visit to GCP: " + t);
                if(debug) {
                    debug_print("Time elapsed since last visit to GCP: " + t);
                }
                // 
                if(t > gcp_period) {
                    error("Elapsed time between GCP visits larger than gcp_period! Change input parameters.");
                }
                //
                // Reset timer:           
                start = time();
                // //
                // //
                // Run chop VM (includes data taking) and set obs step parameter: 
                //
                SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles_2,chop_period_2,dcumode,dcusample_2,dcudelay_2,bsmsample_2,65535,debug);
                //
            } else {
                // //
                // //
                // Reset timing at first raster point:
                if(obsstep == 0) {
                    start = time();
                }
                // //
                // //
                // Run chop VM (includes data taking) and set obs step parameter: 
                //
                SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles,chop_period,dcumode,dcusample,dcudelay,bsmsample,obsstep,debug);
                obsstep = obsstep + 1;
                //
            }
            raster_counter = raster_counter + 1;
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ("sky" observation ends, performing final activities )
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            SpireBb_EndFpgInitialPointing(phot,hold_chop,hold_jigg,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END (end of the pointing/commanding part of the code)
            //
        }
    }
}

//CLName: SpireBb_LoadTableSM16
//VMVersion: 2.8
//CLVersion: 1.3
//CLCVSId: $ID$
//TableId: 0x35
//TableLength: 0x10
//Date: 100115132916
block SpireBb_LoadTableSM16 SPIRE 3348 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableSM16 started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0x35
    Spire_SET_TABLE(0x35,0x10);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x35,0x0,16,[{0xa9879789},{0xaa7d8f21},{0xab738681},{0xac697dbd},{0x9c1581bc},{0x9b1f8a73},{0x9a2a92fc},{0x99349b45},{0x88e09eef},{0x89d696c9},{0x8acc8e5b},{0x8bc285b7},{0x7b6e89aa},{0x7a789238},{0x79839a87},{0x788da286}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x35,0x0,0x0);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableSM16 ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //

}

///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Exec_Serendipity.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to execute a serendipity observation
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/11/12 V0.1: Initial version
// 2009/03/16 V1.0: Adapt to changed in calls to SpireBb_StartDcuData and
//                  SpireBb_Serendipity. Remove datamode from input.
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Exec_Serendipity {
    int ttime = 0; // Total time available for serendipity  
    bool debug = true; // Print debug information
}{
    // //
    // //
    // Start DCU data before:
    //
    SpireBb_StartDcuData();
    //
    // //
    // //
    // Start serendipity waiting: 
    // 
    // Calculate remaining time:
    int dcu1 = duration(SpireBb_StartDcuData());
    int dcu2 = duration(SpireBb_StopDcuData());
    if(ttime > dcu1 + dcu2) {
        int wtime = ttime - dcu1 - dcu2;
    } else {
        wtime = 0;
    }
    SpireBb_Serendipity(wtime,debug);
    //
    if(debug) {
        debug_print("Serendipity observation done, wtime = " + wtime);
    }
    // //
    // //
    // Stop DCU data before:
    //
    SpireBb_StopDcuData();
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id:$
///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_Cal_BsmAngleCal.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Phot BSM Angle Calibration' 
//
//  in *basic_fine_pointing* mode or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/09/10 V0.1: Initial version 
// 2008/10/13 V0.2: Adapt to name change of calibration file.
// 2008/11/07 V0.3: Change description of bool input. Adapt to
//                  change in low level script.  
// 2008/11/12 V0.4: Implement mode setting; Add isBright 
// 2008/12/10 V0.5: Modify unreasonable default values of ref pos; 
//                  Correct pass-on of chop/fts parameter to low level script;
//                  Correct typo in input description
// 2009/01/27 V1.0: Change call to SpireBb_BsmMove2Hold. Add fixed ranges for 
//                  input chop/jiggle position and add safety check pos1<pos2.
//                  Add debug_print as input and pass it to some low level 
//                  scripts. Read nominal bias frequency and bias divider 
//                  from new SpireTable_DetectorSettings.txt. Use new 
//                  SpireBb_EndObsAll and SpireBb_StartObsAll. Implemented
//                  isBright setting. Implemented setting of datarates. 
// 2009/01/30 V1.1: Reconfigure during FINAL_HOLD 
//                  (i.e reset STEP and BSM framerate)
// 2009/01/31 V1.2: Add debug to SpireBb_PhotOffsetAuto().
// 2009/02/15 V1.3: Replace call to SpireTable_DetectorSettings bu call to
//                  SpireTable_PhotModeParams. Use SpireBb_EndBsmAngleCal
//                  to set instrument back to PHTSTBY and move BSM to hold. 
//                  Use SpireProc_Set_PhotMode to set instrument to PHTSTBY
//                  during SLEW, ditto for isBright. Use new setting of 
//                  datarates. 
// 2009/02/16 V1.4: Adapt call to updated SpireProc_Exec_BsmAngleCal. 
// 2009/03/04 V1.5: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Add no pointing option. 
// 2009/04/01 V1.6: Increased allowed range of BSM inputs.
// 2009/05/05 V1.7: Add in move BSM to hold at start. Gather procedures at 
//                  start and end in separate BB. Add SpireBb_EndObsAll to 
//                  SpireBb_EndBsmAngleCal.                     
// 2009/06/05 V1.8: Hardcode STBY 'v00' in EndBB (SPR-1477)
// 2009/09/05 V1.9: Allow reverse loop through values (SCR-SPIRE-1894)
//                  Throw error if increment is negative. Changed default
//                  input max_chop/max_jigg
// 
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in PHOTSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for all three arrays and could be taken from following cal table: 
//  SpireTable_PhotModeParams.txt 
//
//  3) Further mode dependent parameters can be read from:
//  SpireTable_CommonModeParams.txt           
//
//  4) Hold position of BSM can be read from SpireTable_BsmNominalSettings.txt
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhoto_Cal_BsmAngleCal {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; //NAIF identifier: put '0' to use RA/DEC, or correct 'NAIFID'
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    bool isBright = false; // Use settings for bright source (==tick)
    string ib = "S14_0"; // Central aperture (defined in SIAM) of raster
    bool chop = true; // Tick for scanning chop axis (otherwise jiggle)
    int ref_chop = 16000 in [4096,61440]; // Chop position of BSM reference position [Dec(Hex)]
    int ref_jigg = 17000 in [4096,61440]; // Jiggle position of BSM reference position [Dec(Hex)]
    int max_chop = 54848 in [4096,61440]; // Maximum chop position of BSM to be scanned [Dec(Hex)]
    int max_jigg = 54848 in [4096,61440]; // Maximum jiggle position of BSM to be scanned [Dec(Hex)]
    int min_chop = 8000 in [4096,61440]; // Minimum chop position of BSM to be scanned [Dec(Hex)]
    int min_jigg = 8000 in [4096,61440]; // Minimum jiggle position of BSM to be scanned [Dec(Hex)]
    double chopf = 2.0 in [0.1,4.0]; // Chop frequency [Hz] 
    double framerate = 125.0; // Specifies the MCU framerate [Hz]
    int ftime = 15; // Read-out time [s]
    int increment = 384; // Chop/Jiggle increment along scan axis [Dec(Hex)]
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial"; // Model in cal table SpireTable_BsmNominalSettings
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Scan axis either increasing or decreasing (==tick)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Assign spare parameters:
    //
    bool reverse = pBool1;
    // 
    // //
    // //
    // Declare some variable:
    //
    // FTS or photometer (for dcumode in VM set in SpireProc_Exec_BsmAngleCal):
    bool fts = false;
    // Photometer or FTS (for SpireBb_EndBsmAngleCal)
    bool phot = !fts;
    //
    string version = "";
    string tabName = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int frate = 0;
    int tinithold = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    string tabName04 = "SpireTable_CommandLists.txt";
    //
    // Dummy value for smecHomePosn (needed but not used in phot script!)
    int smecHomePosn = 3500;
    // SMEC home position
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS01";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for setup and datarates:  
    string obsMode = "PEngCalObs";
    // Note: datarates are currently only maximum values
    // //
    // //
    // Check input chop/jiggle parameters :
    //
    if(max_chop < min_chop + increment) {
        error("Max chop is smaller than min chop plus 1*increment!");
    }
    if(max_jigg < min_jigg + increment) {
        error("Max jigg is smaller than min jigg plus 1*increment!");
    }
    // //
    // //
    // Setup parameters for BSM chopping movement: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version03;
    tabName = tabName03;
    string selCol = "model";
    // Name of column for selecting 
    string selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    string tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Read VM parameters from calibration table:
    //
    tabName = tabName04;
    selVal = "Chop";
    int vmId = ilookup(tabName,selVal,"Id");
    int vmIndex = ilookup(tabName,selVal,"Index");
    int nParms = ilookup(tabName,selVal,"Nparms");
    //
    // //
    // //
    // Read nominal bias frequency and bias divider:
    // (to determine the sampling rate)
    //    
    // Select version flag and set GetTableEntry parameters:
    version = version01;
    tabName = tabName01;
    selCol = "mode";
    // Name of column for selecting 
    selVal = obsMode;
    // Value of 'string' selector
    //
    tarCol = "mclkDiv";
    int mclkdiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "biasDiv";
    int biasdiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Calculate nominal sampling rate from mclkdiv and biasdiv:
    //
    double mclkdivHz = 1.0E7 / (512.0 * double(mclkdiv + 1));
    double biasdivHz = 1.0 / (double(biasdiv) + 1.0) * mclkdivHz;
    if(debug) {
        debug_print("Nominal sampling rate is: " + biasdivHz + " [Hz]");
    }
    //
    // // // // // // // // // // // // // // // // 
    // // // // // // // // // // // // // // // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    //
    int tslewmin = duration(SpireBb_StartBsmAngleCal(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,framerate,smecHomePosn,debug));
    // 
    // BBs carried out when the pointing is reached:
    //
    if(pointing) {
        tinithold = duration(SpireBb_PhotOffsetAuto(debug));
    } else {
        tinithold = duration(SpireBb_PhotOffsetAuto(debug)) + tslewmin;
    }
    //
    // BB carried out during pointing:
    //
    int tp = duration(SpireProc_Exec_BsmAngleCal(increment,ref_chop,ref_jigg,hold_chop,hold_jigg,max_chop,max_jigg,min_chop,min_jigg,vmId,vmIndex,nParms,chopf,ftime,framerate,biasdivHz,fts,chop,reverse,debug));
    //
    // BB carried out at the end:
    //
    int tfinalhold = duration(SpireBb_EndBsmAngleCal(phot,hold_chop,hold_jigg,isBright,version01,version02,debug));
    //
    // Debug printing?:
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // 
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ******************************************************* */
    // POINTING STATES WITH OBSERVING MODE LOGIC AND DATARATES */
    // ******************************************************* */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartBsmAngleCal(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,framerate,smecHomePosn,debug);
            //
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation:
                //
                SpireBb_StartBsmAngleCal(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,framerate,smecHomePosn,debug);
                //
            }
            // //
            // //
            // Set offsets:
            //
            SpireBb_PhotOffsetAuto(debug);
            //
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            // //
            // //
            // Execute BSM angle calibration:
            //
            SpireProc_Exec_BsmAngleCal(increment,ref_chop,ref_jigg,hold_chop,hold_jigg,max_chop,max_jigg,min_chop,min_jigg,vmId,vmIndex,nParms,chopf,ftime,framerate,biasdivHz,fts,chop,reverse,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            version03 = "v00";
            model = "initial";
            //
            SpireBb_EndBsmAngleCal(phot,hold_chop,hold_jigg,isBright,version01,version02,debug);
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_ObsStep.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to set OBS_STEP parameter in observing mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/07/04 V0.1: Initial version
// 2008/07/24 V0.2: Remove restriction of step value to 0-255
// 2009/01/27 V1.0: Add debug_print option.
// 2009/02/02 V1.1: Merge with Ken's SpireSetObsStep, i.e add Hspot messages.
//                  Replace delay(1) at end with sync()
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_ObsStep {
    int obsStep = 0; // Obs step parameter [dec]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Declare some variable:
    //
    // A hex string:
    string hstr = "";
    //
    // A time string:
    string tstr = "";
    // //
    // //
    // Set obsstep:
    //
    hstr = SpireHexStr(obsStep,4);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(" + hstr + ")");
    Spire_SET_OBS_STEP_RAW(obsStep);
    sync();
    if(debug) {
        debug_print("The obsstep is: " + obsStep);
    }
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id:$
///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_Cal_JfetVssTestC.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'CoP: Spec Jfet Vss Test C' 
//
//  in *basic_fine_pointing* mode or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// S.D.Sidher:
// 2010/01/06 V0.1: Adapted from SpirePhoto_Cal_JfetVssTestC
//                  For routine phase calibration (see SPIRE SCR-2297)
//                  It calls modified detector switch-on and switch-off scripts
//                  Added BB to set detector sampling back for REDY mode
//                  Added BBs for setting NHK rate at start and end
//                  Removed call to BB SpireBb_StartBsmPidTuning (not needed)
//                  Removed Chop, Jiggle and SMEC references
//                  Pointing boolean set to false
//                  Removed all references to Pointing in the script (but leaving the input to the script)
//                  Revised Vss start and end values (see SPIRE SCR-2297)
//
// 
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in REDY mode
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for both arrays and could be taken from following cal table: 
//  SpireTable_SpecModeParams.txt 
//
//  3) Further mode dependent parameters can be read from:
//  SpireTable_CommonModeParams.txt           
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_Cal_JfetVssTestC {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; //NAIF identifier: put '0' to use RA/DEC, or correct 'NAIFID'
    bool pointing = false; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick) (currently not in use)? 
    /* */
    bool isBright = false; // Use settings for bright source (==tick) (currently not in use)
    double jfet_Vss_start = -1.4; //Starting JFET source voltage
    double jfet_Vss_end = -3.0; //ending JFET source voltage
    double jfet_Vss_step = -0.1; //stepping JFET source volatge
    int ftime = 60; //wait time at each level;
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version05 = "v00"; // Version in cal table SpireTable_OpsParms 
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = "v00"; // detVersion
    string pString2 = "v00"; // vssVersion
    int pInt1 = 0; // Default jfet heater voltage at switch on
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Check for is bright setting: 
    //
    if(isBright) {
        isBright = false;
        error("IsBright does not make sense here. Try again!");
    }
    // //
    // //
    // Declare some variable:
    //
    // FTS:
    bool phot = false;
    //
    string version = "";
    string tabName = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    int frate = 0;
    int tinithold = 0;
    bool setFramerate = true;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    //
    // //
    // //
    // JFET heater and detector settings (as specified by user)
    int jfet_heater_V = pInt1;
    string detVersion = pString1;
    string vssVersion = pString2;
    //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS17";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for setup and datarates:  
    string obsMode = "SEngCalObs";
    // Note: datarates are currently only maximum values
    // //
    // //
    // // // // // // // // // // // // // // // // 
    // // // // // // // // // // // // // // // //
    //
    int tp = duration(SpireBb_StartJfetVssTestC(phot,obsModeQla,obsMode,isBright,version01,version02,debug)) + duration(SpireBbSetNhkSampling("SPECSTBY","v00",debug)) + duration(SpireBb_CalSdetOn(jfet_heater_V,detVersion,vssVersion,debug));
    tp = tp + duration(SpireBb_SpecJfetVssTestC(jfet_Vss_start,jfet_Vss_end,jfet_Vss_step,ftime,debug));
    tp = tp + duration(SpireBb_CalSdetOff());
    tp = tp + duration(SpireBbSetDetSampling("REDY",true,detVersion,false,debug)) + duration(SpireBbSetNhkSampling("REDY","v00",debug));
    tp = tp + duration(SpireBb_EndJfetVssTestC(phot,isBright,version01,version02,debug));
    //
    // Debug printing?:
    if(debug) {
        debug_print("duration = " + tp);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // Lookup boresight:
    // 
    tabName = tabName05;
    string selCol = "mode";
    string selVal = obsMode;
    string tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // 
    int[] ts = no_pointing(true,0,0,tp);
    //
    //
}{
    // ******************************************************* */
    // POINTING STATES WITH OBSERVING MODE LOGIC AND DATARATES */
    // ******************************************************* */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            //
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            // //
            // //
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            // Startup observation: 
            //
            SpireBb_StartJfetVssTestC(phot,obsModeQla,obsMode,isBright,version01,version02,debug);
            // set nominal housekeeping rate
            SpireBbSetNhkSampling("SPECSTBY","v00",debug);
            // // 
            // //
            // //
            // Switch on Spectrometer detectors
            SpireBb_CalSdetOn(jfet_heater_V,detVersion,vssVersion,debug);
            // //
            // //
            // //
            // Execute JFET VSS Test C:
            //
            SpireBb_SpecJfetVssTestC(jfet_Vss_start,jfet_Vss_end,jfet_Vss_step,ftime,debug);
            //
            //delay(tp);
            //
            // Switch off Spectrometer detectors
            SpireBb_CalSdetOff();
            //
            // setup detector sampling for REDY mode
            SpireBbSetDetSampling("REDY",true,detVersion,false,debug);
            //
            // set REDY mode nominal housekeeping rate
            SpireBbSetNhkSampling("REDY","v00",debug);
            // // 
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            //
            SpireBb_EndJfetVssTestC(phot,isBright,version01,version02,debug);
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_IsBrightPhaseShift.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to calculate phase shift for isBright and make sure 
//  the phase is wrapped at boundaries in case. 
// 
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/04 V0.1: Initial version adapted from
//                  SpireProc_CalcParam_PhaseUp (2009/02/01 V1.0)
//
///////////////////////////////////////////////////////////////////////////
//
int procedure SpireProc_CalcParam_IsBrightPhaseShift {
    int inputPhase = 0 in [0,255]; // Input (nominal) phase
    int phaseShift = -50 in [-255,255]; // Phase shift
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Declare some variable:
    //
    int low_limit = 0;
    int high_limit = 255;
    int k = 0;
    // //
    // //
    // Calculate shift:
    //
    int outputPhase = inputPhase + phaseShift;
    // //
    // //
    // Check if phase is 0 <= phase <= 255:
    //
    if(outputPhase < low_limit) {
        k = 1;
    } else {
        if(outputPhase > high_limit) {
            k = -1;
        } else {
            k = 0;
        }
    }
    if(debug) {
        debug_print("The value of k is :" + k);
    }
    //
    // Adapt raw phase list if outside 0 <= phase <= 255:
    //
    outputPhase = outputPhase + k * 255;
    //
    if(debug) {
        debug_print("Input raw phase [Dec(Hex)]: " + inputPhase);
        debug_print("Applied phase shift [Dec(Hex)]: " + phaseShift);
        debug_print("Output raw phase [Dec(Hex)]: " + outputPhase);
    }
    //

    return outputPhase;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_SpecDataRates.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to retrive the datarate from the associated calibration table 
//  for a given spectrometer mode. 
// 
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/19 V1.0: Initial version adapted from
//                  SpireProc_CalcParam_PhotDataRates (2009/02/15 V1.0)
// 2009/05/05 V1.1: Change calibration table where HK are read. 
//                  
///////////////////////////////////////////////////////////////////////////
//
double procedure SpireProc_CalcParam_SpecDataRates {
    string rateType = "chk" in ["chk","nhk","sci"]; // Data rate to be read 
    string obsMode = "Scan"; // Parameter to specify the configuration mode
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variable:
    //
    double rate = 0.0;
    // Name of column for selecting: 
    string selCol = "mode";
    // Value of 'string' selector: 
    string selVal = obsMode;
    // Target column name:
    string tarCol = "";
    string version = "";
    //
    // Hardcoded calibration tables: 
    //
    string tabName = "";
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_DefaultParams.txt";
    //
    // Hardcoded version + mode name: 
    //
    string version03 = "v00";
    // Version in cal table SpireTable_DefaultParams 
    string selValHk = "SPECSTBY";
    // //
    // //
    // Select and set rate:
    //
    if(rateType == "chk") {
        tabName = tabName03;
        version = version03;
        tarCol = "chkDataRate";
        double chkrate = SpireProc_GetTableEntryDouble(tabName,selCol,selValHk,tarCol,version,debug);
        rate = chkrate;
    }
    //
    if(rateType == "nhk") {
        tabName = tabName03;
        version = version03;
        tarCol = "nhkDataRate";
        double nhkrate = SpireProc_GetTableEntryDouble(tabName,selCol,selValHk,tarCol,version,debug);
        rate = nhkrate;
    }
    //
    if(rateType == "sci") {
        string[] tarColSci = ["dcuDataRate","smecDataRate","bsmDataRate","scuDataRate","dpuDataRate"];
        double scirate = 0.0;
        double scirate2add = 0.0;
        for(int i = 1 .. 5) {
            tarCol = tarColSci[i - 1];
            if(tarCol == "dcuDataRate") {
                tabName = tabName01;
                version = version01;
            } else {
                if(tarCol == "smecDataRate") {
                    tabName = tabName01;
                    version = version01;
                } else {
                    tabName = tabName02;
                    version = version02;
                }
            }
            scirate2add = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
            scirate = scirate + scirate2add;
            if(debug) {
                debug_print("Reading target column " + tarCol + " with scirate " + scirate2add);
                debug_print("The new scirate is: " + scirate);
            }
        }
        rate = scirate;
    }
    // //
    // //
    // Return required rate:
    //
    if(debug) {
        debug_print("The " + rateType + " rate is: " + rate + " [kbps]");
    }

    return rate;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_FpgInitialPointing.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to calculate the positions of x small mxn point rasters.
//  The positions of the x pixels are read from a calibration table.    
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/07/25 V0.1: Initial version 
// 2008/07/28 V0.2: Change sequence of visiting the raster points  
// 2008/11/06 V0.3: Move calibration table to input to use same script
//                  for FTS 
// 2009/02/02 V1.0: Add debug_print as input
//
///////////////////////////////////////////////////////////////////////////
//
{double[],double[],int} procedure SpireProc_CalcParam_FpgInitialPointing {
    double d1 = 4.0 in [2.0,480.0]; // Angular stepsize along Y axis [arcsec] 
    double d2 = 4.0 in [2.0,480.0]; // Angular stepsize along Z axis [arcsec]
    int m = 5; // Number of points in a raster line [odd number!]
    int n = 5; // Number of raster lines or scan lines [odd number!]
    string pixels = "SpireTable_PhotFpgInitialPointing.txt"; // Table with pixel coordinates relative to boresight  
    string version = "v00"; // Version parameter defined in calibration table
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Read distance pixel2center from calibration table: 
    //    
    // Read in table columns:
    string tabName = pixels;
    // Table of pixels
    string[] versionCol = scolumn(tabName,"version");
    double[] y_distCol = dcolumn(tabName,"y_dist");
    double[] z_distCol = dcolumn(tabName,"z_dist");
    string[] pixelCol = scolumn(tabName,"pixel");
    //
    // Read table size: 
    int nrows = table_size(tabName);
    // //
    // //
    // Cycle through values to get all rows with correct version tag:
    //
    // Setup:
    {double,double,string}[] rows = [{0.0,0.0,""}];
    int nindex = 0;
    bool match = false;
    //
    for(int j = 0 .. nrows - 1) {
        if(debug) {
            debug_print("versionCol[j]: " + versionCol[j]);
        }
        if(versionCol[j] == version) {
            rows[nindex] = {y_distCol[j],z_distCol[j],pixelCol[j]};
            nindex = nindex + 1;
            match = true;
        }
    }
    //
    if(!match) {
        error("Calibration table empty or wrong version selected!");
    }
    //
    //
    // Number of pixels to visit:
    int numpix = length(rows);
    if(debug) {
        debug_print("rows: " + rows);
    }
    // //
    // //
    // Assign pixel to base pointing array:
    //
    double[] dpr = [0.0];
    double[] dpc = [0.0];
    int size = length(rows);
    for(int jay = 0 .. size - 1) {
        dpr[jay] = rows[jay]{1};
        dpc[jay] = rows[jay]{0};
        if(debug) {
            debug_print("y_dist  :" + rows[jay]{0});
            debug_print("z_dist  :" + rows[jay]{1});
        }
    }
    //
    // number of points in small raster:
    int npoints = size;
    int cs = -1 * iround(0.5 * (double(m) - 1.0));
    int ls = -1 * iround(0.5 * (double(n) - 1.0));
    double colu = 0.0;
    double rowd = 0.0;
    double basecol = 0.0;
    double baserow = 0.0;
    double[] yarray = [0.0];
    double[] zarray = [0.0];
    int index = 0;
    //
    for(int i = 0 .. npoints) {
        bool odd = true;
        if(debug) {
            debug_print("Map point :" + i);
        }
        for(int row = ls .. ls + (n - 1)) {
            row = row * 1;
            if(debug) {
                debug_print("row: " + row);
            }
            rowd = double(row) * d1 + baserow;
            for(int col = cs .. cs + (m - 1)) {
                col = col * -1;
                if(debug) {
                    debug_print("col: " + col);
                }
                if(odd) {
                    colu = double(col) * d2;
                } else {
                    colu = -1.0 * double(col) * d2;
                }
                colu = colu + basecol;
                if(debug) {
                    debug_print("row: " + rowd + " col: " + colu);
                }
                zarray[index] = rowd;
                yarray[index] = colu;
                index = index + 1;
            }
            if(odd) {
                odd = false;
            } else {
                odd = true;
            }
        }
        if(i < npoints) {
            baserow = dpr[i];
            basecol = dpc[i];
        }
    }
    if(debug) {
        debug_print("zarray = " + zarray);
        debug_print("yarray = " + yarray);
        debug_print("Number of points: " + length(zarray));
    }
    // 

    return {zarray,yarray,numpix};
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Exec_PcalLevelCheck.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to execute sequence of PCAL flashes with given input parameters. 
//  Note: Needs correct setting of dcusamples, scusamples, and dcudelay! 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/12 V0.1: Initial version copied/renamed from
//                  SpireProc_Exec_PhotPcalLevelCheck.txt (2008/06/11 V0.1)
//                  based on
//                  SpireProc_Exec_PhotIltPcalFlash.txt (2008/05/02 V0.1)
//                  Rename script, remove 'Phot', change default
// 2008/11/07 V0.2: Adapt to change in name of low level script
// 2009/02/02 V1.0: Add debug_print as input and pass it to low level script.
//                  Adapt input to updated SpireBb_PcalFlash with rate as 
//                  input and step set in loop. Add setting of NHK STEP 
//                  parameter. 
// 2009/02/18 V1.1: Adapt to change in call to SpireBb_PcalFlash.
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Exec_PcalLevelCheck {
    int vmId = 0x46; // Raw VM table number
    int vmIndex = 0; // Raw VM index
    int nParms = 9; // Number of parameters passed to VM
    int[] raw_low_bias = [0,0,0]; // Raw low bias PCAL level list
    int[] raw_high_bias = [0,1111,2176]; // Raw high bias PCAL level list
    int ncycles = 15; // Number of cycles 
    int period = 4000; // Period of cycle [millisec] 
    int ndcumode = 0; // DCU data mode (default = PF)
    int dcusamples = 38; // Number of DCU and SCU samples, and DCU sample delay  mclkdiv/biasdivi (149/6)
    int dcudelay = 10880; // Number of DCU and SCU samples, and DCU sample delay  mclkdiv/biasdiv (149/6)
    int scumode = 0; // SCU sampling rate (f =80Hz/(1+scumode))
    int scusamples = 0; // Number of DCU and SCU samples, and DCU sample delay mclkdiv/biasdiv (149/6)
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Loop of PCAL flashes with increasing high bias level: 
    //
    int microperiod = period * 1000;
    for(int j = 0 .. length(raw_high_bias) - 1) {
        // //
        // //
        // Set STEP:
        //
        int obsStep = j + 1;
        // NHK Step parameter 
        if(j == 1) {
            if(debug) {
                debug_print("First obsStep already set during slew");
            }
        } else {
            SpireBb_SetObsStep(obsStep,debug);
        }
        SpireBb_PcalFlash(vmId,vmIndex,nParms,raw_low_bias[j],raw_high_bias[j],ncycles,microperiod,ndcumode,dcusamples,dcudelay,scumode,scusamples,obsStep,debug);
        if(debug) {
            debug_print("PCAL bias level finished: " + raw_high_bias[j]);
        }
    }
    //
}

//CLName: SpireBb_LoadTableJiggleMap
//VMVersion: 2.8
//CLVersion: 1.8
//CLCVSId: $Id$
//TableId: 0x48
//TableLength: 0x6e
//Date: 090325153531
block SpireBb_LoadTableJiggleMap SPIRE 3331 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableJiggleMap started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    //set table command call for table id 0x48
    Spire_SET_TABLE(0x48,0x6e);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x48,0x0,38,[{0x120000fc},{0x6d},{0x12000026},{0x501},{0x12000027},{0x4801},{0x53020026},{0x2000000},{0x200f0000},{0x20100001},{0x21110102},{0x11000011},{0x20120003},{0x12000026},{0x501},{0x12000027},{0x4802},{0x53020026},{0x2000000},{0x20000004},{0x20010005},{0x20020006},{0x20030007},{0x20040008},{0x60640003},{0x32000050},{0x20210001},{0x20220002},{0x12000026},{0x501},{0x12000027},{0x4803},{0x53020026},{0x2000000},{0x12000020},{0x6b},{0x20070008},{0x20080006}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x48,0x26,38,[{0x20040012},{0x20050021},{0x20060022},{0x12000013},{0x0},{0x35130009},{0x30000022},{0x20ff0010},{0x201e00ff},{0x1aff0001},{0x4bff006d},{0x120000ff},{0x3},{0x6107fc01},{0x20ff001e},{0x650f2002},{0x100000ff},{0x100000ff},{0x491e006b},{0x491f006c},{0x2000001e},{0x18000000},{0xffff},{0x2001001e},{0x1a010010},{0x18000001},{0xffff},{0x2002001f},{0x18000002},{0xffff},{0x2003001f},{0x1a030010},{0x18000003},{0xffff},{0x60640004},{0x32000020},{0x34ff0011},{0x30ffffe3}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x48,0x4c,34,[{0x10000013},{0x30ffffde},{0x80007d0},{0x1000001},{0x80007d0},{0x12000000},{0x0},{0x12000001},{0x43e},{0x12000002},{0x0},{0x60640001},{0x12000000},{0x1},{0x12000001},{0x1c1},{0x12000002},{0x0},{0x60640001},{0x80007d0},{0x1000000},{0x80007d0},{0x12000026},{0x501},{0x12000027},{0x4804},{0x53020026},{0x2000000},{0x30000002},{0x2000000},{0x7f000000},{0x0},{0x0},{0x0}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x48,0x0,0x0);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableJiggleMap ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

// SpireBbObsConfig
//
// $Id: SpireBbObsConfig.txt,v 1.2 2007/10/26 10:20:21 kking Exp $
//
// Building Block to configure an observation
//
// 22 Oct 2007: 
//      Add delay of 1 sec before setting OBSID to allow time for busconfig to be performed
//
//
block SpireBbObsConfig SPIRE 12033 {
    int obsMode = 0;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Obs Config started");
    SpireMsg(2,"          $Id: SpireBbObsConfig.txt,v 1.2 2007/10/26 10:20:21 kking Exp $");
    hstr = SpireHexStr($BBID,8);
    SpireMsg(3,"          BBID = " + hstr);
    hstr = SpireHexStr(obsMode,4);
    SpireMsg(3,"          MODE = " + hstr);
    //
    // Wait for busconfig to be performed
    delay(1);
    //
    // set OBSID
    hstr = SpireHexStr($OBSID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + " Cmd: Spire_SET_OBSID_RAW(" + hstr + ")");
    Spire_SET_OBSID_RAW($OBSID);
    // 
    // set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    // 
    // Set Mode
    hstr = SpireHexStr(obsMode,4);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_MODE_RAW(" + hstr + ")");
    Spire_SET_OBS_MODE_RAW(obsMode);
    //
    // set STEP to zero
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x0000)");
    Spire_SET_OBS_STEP_RAW(0x0);
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Obs Config ended");
    SpireMsg(1,"  ..Observation Configuration (" + (time() - t) + " secs)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndStdLoadCurve.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of 
// SpirePhoto/Spectro_Cal_StdLoadCurve.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V1.0: Initial version adapted from
//                  SpireBb_EndBsmAngleCal (2009/05/05 V1.2),
//                  SpirePhoto_Cal_StdLoadCurve (2009/03/04 V1.3), and
//                  SpireSpectro_Cal_StdLoadCurve (2009/03/04 V0.5)
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndStdLoadCurve SPIRE 14051 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndStdLoadCurve reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set instrument back to Phot/Spec-STBY:
    //
    if(phot) {
        SpireProc_Set_PhotMode("PHTSTBY",isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    }
    // //
    // //
    // End observation:
    //
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndStdLoadCurve reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

// SpireBbPOF3End
//
// $Id:$
//
// Building Block to reconfigure the instrument to PHOT_STBY mode from POF3 (jiggle map) mode
//
//  11 Feb 2008: KK removed resetting of OBSID and BBISD as they are 
//               now done in SpireBb_EndObsAll
//  14 Feb 2009: MP peplace calls to SpireProc_Set_PhotPhase/Bias with 
//               call to SpireProc_Set_PhotBright
//  03/07/2009  KJK:
//         - Replaced version input parameter with photVersion and comVersion
//         - Replaced call to Proc_SetPhotBRight with Proc_SetPhotMode to reset the 
//            detectors if bright setting has been used
//  28/07/2009 SDS:
//         - Added chopVersion input parameter to allow setting of the Chop PID parameters back 
//           to their nominal values (model = "initial").
//  10/08/2009 KJK:
//         SPR-1709:  Updated to execute SpireProc_Set_PhotMode if photversion is not "V00"
//                           Updated to always use photVersion and comVersion = "v00" for all calls - to reset the detectors
//  12/08/2009 KJK:
//         Changed chopVersion to bsmVersion - in line with other scripts
//  17/08/2009 KJK:
//         SPR-1823: Added command to reset MCU Frame Number to default value
//  25-Aug-2009 KJK:
//        SPR Spire-1641: Now read BSM HOLD positions from SpireTable_BsmNominalSettings.txt rather than BSM.txt
//                                 Needed new input parameter bsmModel 
//  10/09/2009 KJK:
//        SCR Spire-1943: call SPireProcSetDetSampling  and SpireProcSetBsmSampling to reset sampling that may have changed
//
block SpireBbPOF3End SPIRE 8242 {
    string obsMode = "PHTSTBY";
    bool isBright = false in [true,false];
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string detVersion = "v00";
    string photVersion = "v00";
    string comVersion = "v00";
    bool debug = false in [true,false];
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF3 Reconfiguration started");
    SpireMsg(2,"          $Id:$");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP to zero
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x0000)");
    Spire_SET_OBS_STEP_RAW(0x0);
    //
    // reset BSM
    //
    // Move BSM to HOLD
    int bsmHoldChopPosn = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",bsmModel,"chop_0_I",bsmVersion,debug);
    int bsmHoldJiggPosn = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",bsmModel,"jigg_0_I",bsmVersion,debug);
    SpireBsmMove(bsmHoldChopPosn,bsmHoldJiggPosn);
    //
    // Reset BSM sampling
    double bsmDataRate = SpireProcSetBsmSampling(obsMode,bsmVersion,debug);
    //
    // Reset PID parameters
    string tabName = "SpireTable_BsmNominalSettings.txt";
    string tarCol = "chop_kp";
    int chopkp = SpireProc_GetTableEntryInt(tabName,"model","initial",tarCol,bsmVersion,debug);
    tarCol = "chop_ki";
    int chopki = SpireProc_GetTableEntryInt(tabName,"model","initial",tarCol,bsmVersion,debug);
    tarCol = "chop_kd";
    int chopkd = SpireProc_GetTableEntryInt(tabName,"model","initial",tarCol,bsmVersion,debug);
    SpireProc_Set_BsmChopPid(chopkp,chopki,chopkd,debug);
    //
    //
    // reset Detectors
    //
    // reset bright-source biases and phases - if needed
    //
    if(isBright) {
        SpireProc_Set_PhotMode(obsMode,isBright,"v00","v00",debug);
    } else {
        if(photVersion != "v00") {
            SpireProc_Set_PhotMode(obsMode,isBright,"v00","v00",debug);
        }
    }
    //
    //  Reset detector sampling
    double dcuDataRate = SpireProcSetDetSampling(obsMode,true,detVersion,false,debug);
    // 
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF3 Reconfiguration ended");
    SpireMsg(1,"  ..POF3 Reconfiguration to PHT_STBY mode (" + (time() - t) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_PhotBiasConvert.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to translate user input in mV for bias amplitude 
//  into nearest Hex values for psw_bias, pmw_bias, plw_bias, and ptc_bias  
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/05/07 V0.1: Initial version adapted from
//                  Proc_BiasConvertP (v1.4 2008/01/31 20:24:35)
// 2008/05/07 V0.2: Add correct upper bias limit, expand printing 
// 2008/06/09 V0.3: Calculate conversion for each array seperately
// 2008/07/03 V0.4: Renumber version; convert also PTC bias
// 2009/02/01 V1.0: Add debug_print as input
//
///////////////////////////////////////////////////////////////////////////
int[] procedure SpireProc_CalcParam_PhotBiasConvert {
    double input_bias_psw = 0.0 in [0.0,127.813]; // Input PSW Bias amplitude [0.0 - 129.159] [mV]
    double input_bias_pmw = 0.0 in [0.0,128.625]; // Input PMW Bias amplitude [0.0 - 129.159] [mV]
    double input_bias_plw = 0.0 in [0.0,129.159]; // Input PLW Bias amplitude [0.0 - 129.159] [mV]
    double input_bias_ptc = 0.0 in [0.0,254.265]; // Input PTC Bias amplitude [0.0 - 254.265] [mV]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Predefine version:
    //
    string ver_psw = "v01";
    string ver_pmw = "v01";
    string ver_plw = "v01";
    string ver_ptc = "v01";
    //debug_print("The nominal version is v01");
    // //
    // //
    // Retrieve the maximum bias amplitude:
    //
    double maxbias_psw = dlookup("SpireTable_PhotPswMaxbias.txt",ver_psw,"maxbias");
    double maxbias_pmw = dlookup("SpireTable_PhotPmwMaxbias.txt",ver_pmw,"maxbias");
    double maxbias_plw = dlookup("SpireTable_PhotPlwMaxbias.txt",ver_plw,"maxbias");
    double maxbias_ptc = dlookup("SpireTable_PhotPtcMaxbias.txt",ver_ptc,"maxbias");
    // //
    // //
    // Convert from mV to RAW values:
    //
    double conversion_factor_psw = 255.0 / maxbias_psw;
    double conversion_factor_pmw = 255.0 / maxbias_pmw;
    double conversion_factor_plw = 255.0 / maxbias_plw;
    double conversion_factor_ptc = 255.0 / maxbias_ptc;
    //
    int raw_bias_psw = iround(conversion_factor_psw * input_bias_psw);
    int raw_bias_pmw = iround(conversion_factor_pmw * input_bias_pmw);
    int raw_bias_plw = iround(conversion_factor_plw * input_bias_plw);
    int raw_bias_ptc = iround(conversion_factor_ptc * input_bias_ptc);
    //
    // Safety check:
    if(raw_bias_psw > 255) {
        raw_bias_psw = 255;
        if(debug) {
            debug_print("PSW exceeded limit!");
        }
    }
    if(raw_bias_pmw > 255) {
        raw_bias_pmw = 255;
        if(debug) {
            debug_print("PMW exceeded limit!");
        }
    }
    if(raw_bias_plw > 255) {
        raw_bias_plw = 255;
        if(debug) {
            debug_print("PLW exceeded limit!");
        }
    }
    if(raw_bias_ptc > 255) {
        raw_bias_ptc = 255;
        if(debug) {
            debug_print("PTC exceeded limit!");
        }
    }
    //
    double bias_psw = double(raw_bias_psw) / conversion_factor_psw;
    double bias_pmw = double(raw_bias_pmw) / conversion_factor_pmw;
    double bias_plw = double(raw_bias_plw) / conversion_factor_plw;
    double bias_ptc = double(raw_bias_ptc) / conversion_factor_ptc;
    // //
    // //
    // Debug printout:
    //
    if(debug) {
        debug_print("Input mV value for PSW/PMW/PLW/PTC bias amplitude: " + input_bias_psw + "/" + input_bias_pmw + "/" + input_bias_plw + "/" + input_bias_ptc);
        debug_print("Output Hex values for PSW/PMW/PLW/PTC: " + raw_bias_psw + "/" + raw_bias_pmw + "/" + raw_bias_plw + "/" + raw_bias_ptc);
        debug_print("Commanded mV values for PSW/PMW/PLW/PTC: " + bias_psw + "/" + bias_pmw + "/" + bias_plw + "/" + bias_ptc);
    }
    // //
    // //
    // Return required values:
    //

    return [raw_bias_psw,raw_bias_pmw,raw_bias_plw,raw_bias_ptc];
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_Cal_PcalLevelCheck.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  CUS script for: 'Spec PCAL Level Ceck' 
//
//  in *basic_fine_pointing* or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/12 V0.1: Initial version adapted from
//                  SpirePhoto_Cal_PcalLevelCheck (2008/08/12 V0.4)
//                  based on 
//                  Mode_ILT_PERF_CPT_S (v 1.4 2008/01/31 20:24:33)
// 2008/11/11 V0.2: Allow 'no pointing' as input option; Adapt debug printing
// 2008/11/12 V0.3: Implement mode setting; Add isBright 
//                  Change 'no pointing' implementation
// 2009/02/19 V0.4: Add debug_print as input and pass it to some low 
//                  level scripts. Add setting of NHK STEP parameter
//                  in SpireProc_Exec_PcalLevelCheck. Set first STEP
//                  already during SLEW and unset at end during INIT_HOLD.   
//                  Use new SpireBb_EndObsAll and SpireBb_StartObsAll. 
//                  Read nominal bias frequency and bias divider from new
//                  SpireTable_SpecModeParams. Implemented setting 
//                  of datarates. Implemented isBright (+!pointing) setting.
//                  Use SpireBb_SpecSetMode to set to SPECSTBY during 
//                  SLEW and FINAL_HOLD. Read boresight/set from 
//                  SpireTable_OpsParms. Read Pcal levels from new calibration 
//                  table. Read VM table parameters now from a cal. table.
//                  Adapt to change in call to SpireProc_Exec_PcalLevelCheck.
// 2009/03/04 V0.5: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Allow isBright for no
//                  pointing observation. 
// 2009/05/07 V0.6: Add in move BSM/SMEC to hold/home at start. Add new 
//                  SpireBb_SmecHold to account for the fact that
//                  SpireBb_SmecMove2Home does not stop SMEC.
//                  Gather procedures at start and end in separate BB. 
// 2009/05/11 V0.7: Elevate Pcal flash period and number of cycles to input. 
//
///////////////////////////////////////////////////////////////////////////
//
//  Script assumes that:
//
//  1)  Instrument is in SPECSTBY at beginning 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Nominal bias frequency and sampling rate are read from
//     following calibration tables: SpireTable_SpecModeParams.txt
//
//  3) PCAL bias calibration coefficients are read from following cal table:
//     SpireTable_PcalCurrentConvCoef.txt
//
//  4) Boresight of array are read from following cal table:
//     SpireTable_OpsParms.txt   
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_Cal_PcalLevelCheck {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    bool isBright = false; // Use settings for bright source (==tick)
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    int period = 4000; // PCAL Flash *FULL* period (high+low bias) [millisec]
    int ncycles = 15; // PCAL Flash Number of cycles
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_PcalLevelCheckLevels
    string version05 = "v00"; // Version in cal table SpireTable_OpsParms.txt
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = false;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_PcalLevelCheckLevels.txt";
    string tabName04 = "SpireTable_CommandLists.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    string tabName06 = "SpireTable_BsmNominalSettings.txt";
    string tabName09 = "SpireTable_SmecNominalSettings.txt";
    //
    // Currently hardcoded version parameter:
    //
    string version09 = "v00";
    // Version in cal table SpireTable_SmecNominalSettings
    string version06 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    //
    // Currently hardcoded parameter:
    // Is (==tick) the DCU currently sampled? 
    bool dcuData = false;
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS38";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "SEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version06;
    tabName = tabName06;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Read SMEC home position from calibration file:
    //
    tarCol = "Home";
    tabName = tabName09;
    selVal = version09;
    int smecHomePosn = ilookup(tabName,selVal,tarCol);
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Read nominal bias frequency and bias divider:
    //    
    // Select version flag and set GetTableEntry parameters:
    version = version01;
    tabName = tabName01;
    selCol = "mode";
    // Name of column for selecting 
    selVal = obsMode;
    // Value of 'string' selector
    //
    tarCol = "mclkDiv";
    int mclkdiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "biasDiv";
    int biasdiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Calculate nominal sampling rate from mclkdiv and biasdiv:
    //
    double mclkdivHz = 1.0E7 / (512.0 * double(mclkdiv + 1));
    double biasdivHz = 1.0 / (double(biasdiv) + 1.0) * mclkdivHz;
    if(debug) {
        debug_print("Nominal sampling rate is: " + biasdivHz + " [Hz]");
    }
    //
    // //
    // //
    // Read VM parameters from calibration table:
    //
    tabName = tabName04;
    selVal = "Flash";
    int vmId = ilookup(tabName,selVal,"Id");
    int vmIndex = ilookup(tabName,selVal,"Index");
    int nParms = ilookup(tabName,selVal,"Nparms");
    // //
    // //
    // Initialize PCAL variables with their default values:
    // 
    // PCAL Flash FULL period (high and low bias) in millisec:
    // int period = 4000;
    //
    // Number of cycles: 
    // V0.2: int ncycles = 7;
    // from V0.3 on:
    // int ncycles = 15;
    //
    // --> PCAL setup parameters now in calibration file or input parameters.   
    //
    // DCU data mode (default = PF == 0; SF == 4)
    int ndcumode = 4;
    //
    // SCU sampling rate (f =80Hz/(1+scumode))  
    int scumode = 0;
    // //
    // //
    // Define/retrieve the list of PCAL biases for each of the flashes in mA:
    // 
    double[] low_bias = [0.0];
    // V0.2:
    //double[] high_bias = [1.0,2.0,3.0,4.0,5.0,6.0,7.0];
    // V0.3:
    //double[] high_bias = [0.35,0.7,1.05,1.4,1.75,2.1,2.45,2.8,3.15,3.5,3.85,4.2,4.55,4.9,5.25,5.6,5.95,6.3,6.65,7.0];
    //
    double[] high_bias = [];
    int index = 0;
    tabName = tabName03;
    selCol = "version";
    selVal = version03;
    tarCol = "level";
    string[] searchCol = scolumn(tabName,selCol);
    double[] targetCol = dcolumn(tabName,tarCol);
    int size = table_size(tabName);
    // 
    // Loop through table to find matching entries:
    //
    for(int j = 0 .. size - 1) {
        if(searchCol[j] == selVal) {
            high_bias[index] = targetCol[j];
            index = index + 1;
        }
    }
    //
    // Safety check:
    //
    if(length(high_bias) == 0) {
        error("No PCAL bias level selected! Check version with entries in calibration table SpireTable_PcalLevelCheckLevels.txt");
    }
    // //
    // //
    // Predefine version in SpireTable_PcalCurrentConvCoef.txt:
    //
    string ver_b = "v01";
    if(debug) {
        debug_print("The nominal version in SpireTable_PcalCurrentConvCoef.txt is v01");
    }
    // //
    // //
    // Retrieve PCAL bias calibration coefficients:
    //
    double[] coeff = [0.0];
    coeff[0] = dlookup("SpireTable_PcalCurrentConvCoef.txt",ver_b,"c_0");
    coeff[1] = dlookup("SpireTable_PcalCurrentConvCoef.txt",ver_b,"c_1");
    // //
    // //
    // Calculate RAW PCAL bias values for each of the flashes from mA list:
    //  
    int[] raw_low_bias = [0];
    int[] raw_high_bias = [0];
    for(int i = 0 .. length(high_bias) - 1) {
        raw_low_bias[i] = 0;
        raw_high_bias[i] = iround((high_bias[i] * 0.0010 - coeff[0]) / coeff[1]);
    }
    if(debug) {
        debug_print("High bias levels in mA are: " + high_bias);
        debug_print("Raw high bias levels to check are: " + raw_high_bias);
        debug_print("Raw low bias level to check is: " + raw_low_bias);
    }
    // //
    // //
    // Deduce number of DCU samples, SCU samples and DCU sample delay based on mclkdiv and biasdiv:
    //
    int[] flash_params = SpireProc_CalcParam_PcalFlash(period,mclkdiv,biasdiv,debug);
    int dcusamples = flash_params[0];
    int scusamples = flash_params[1];
    int dcudelay = flash_params[2];
    if(debug) {
        debug_print("//////////////////////////////////////////////////////////////");
        debug_print("");
        debug_print("CALCULATED DCU SAMPLES : " + dcusamples);
        debug_print("CALCULATED SCU SAMPLES : " + scusamples);
        debug_print("CALCULATED  SAMP DELAY : " + dcudelay + "microsec");
        debug_print("");
        debug_print("//////////////////////////////////////////////////////////");
    }
    //
    // // // // // // // // // // // // // // // // 
    // // // // // // // // // // // // // // // //
    //
    // Calculate timing for the pointing request:
    //
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartPcalLevelCheck(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug));
    // 
    // BBs carried out when the pointing is reached:
    if(pointing) {
        int tinithold = duration(SpireBb_SpecOffsetAuto(dcuData,debug));
    } else {
        tinithold = duration(SpireBb_SpecOffsetAuto(dcuData,debug)) + tslewmin;
    }
    //
    // BB carried out during pointing:
    int tp = duration(SpireProc_Exec_PcalLevelCheck(vmId,vmIndex,nParms,raw_low_bias,raw_high_bias,ncycles,period,ndcumode,dcusamples,dcudelay,scumode,scusamples,debug));
    //
    // BB carried out at the end:
    int tfinalhold = duration(SpireBb_EndPcalLevelCheck(phot,isBright,version01,version02,debug));
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // // 
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // // 
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,0,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartPcalLevelCheck(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            //
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation:
                //
                SpireBb_StartPcalLevelCheck(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug);
            }
            //
            // //
            // //
            // Set offsets:
            //
            SpireBb_SpecOffsetAuto(dcuData,debug);
            // 
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            // //
            // //
            // Execute sequence of PCAL flashes:
            //
            SpireProc_Exec_PcalLevelCheck(vmId,vmIndex,nParms,raw_low_bias,raw_high_bias,ncycles,period,ndcumode,dcusamples,dcudelay,scumode,scusamples,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            SpireBb_EndPcalLevelCheck(phot,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndMultiLevelNoise.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of 
// SpirePhoto/Spectro_Cal_MultiLevelNoise.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V1.0: Initial version adapted from
//                  SpireBb_EndBsmAngleCal (2009/05/05 V1.2),
//                  SpirePhoto_Cal_MultiLevelNoise (2009/03/03 V1.3), and
//                  SpireSpectro_Cal_MultiLevelNoise (2009/03/04 V0.5)
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndMultiLevelNoise SPIRE 14053 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndMultiLevelNoise reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set obsstep back to 0:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP(0)");
    Spire_SET_OBS_STEP(0);
    // //
    // //
    // Set instrument back to Phot/Spec-STBY:
    //
    if(phot) {
        SpireProc_Set_PhotMode("PHTSTBY",isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    }
    // //
    // //
    // End observation:
    //
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndMultiLevelNoise reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Set_SpecMode
//
///////////////////////////////////////////////////////////
//
// Procedure to configure some important instrument parameters
// for the spectrometer depending on the mode. The procedure returns
// the DCU, SMEC, BSM, DPU, and SCU data rate.
//
///////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/15 V0.1: Initial version adapted from
//                  SpireProc_Set_PhotMode (2009/02/15 V0.1)
// 2009/07/10 V1.0: Temporary fix for SPR-SPIRE-1613 (hardcode command)
//
///////////////////////////////////////////////////////////////////////////
//
double[] procedure SpireProc_Set_SpecMode {
    string obsMode = "Scan"; // Obs mode as defined in calibration files
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string tarCol = "";
    string selCol = "mode";
    string tabName = "";
    string version = "";
    string selVal = "";
    string tstr = "";
    //
    // Photometer or FTS?:
    bool phot = false;
    bool fts = !phot;
    //
    // Hardcoded name of calibration tables:
    // 
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"     " + tstr + ":  SpireProc_Set_SpecMode started");
    SpireMsg(4,"          $Id:$");
    // //
    // //
    // In case select isBright:
    // 
    if(obsMode != "SPECSTBY") {
        if(isBright) {
            selVal = obsMode + "_b";
        } else {
            selVal = obsMode;
        }
    } else {
        selVal = obsMode;
    }
    // //
    // //
    // Read parameters from calibration tables:
    //
    // Table SpireTable_SpecModeParams:
    //
    tabName = tabName01;
    version = version01;
    //
    tarCol = "mclkDiv";
    int mclkDiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "biasDiv";
    int biasDiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "sswBias";
    int ssw_bias = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "slwBias";
    int slw_bias = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "sswPhase";
    int ssw_phase = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "slwPhase";
    int slw_phase = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "dcuDataRate";
    double dcuDataRate = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "smecFrameRate";
    int smecFrameRate = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "smecDataRate";
    double smecDataRate = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Table SpireTable_CommonModeParams:
    //
    tabName = tabName02;
    version = version02;
    //
    tarCol = "dcuDataMode";
    int dcuDataMode = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "bsmFrameRate";
    int bsmFrameRate = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "bsmDataRate";
    //
    double bsmDataRate = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "dpuDataRate";
    double dpuDataRate = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "scuFrameRate";
    int scuFrameRate = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "scuDataRate";
    double scuDataRate = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Debug printing of all fetched parameters:
    //
    if(debug) {
        debug_print("      mclkDiv: " + mclkDiv);
        debug_print("      biasDiv: " + biasDiv);
        debug_print("     ssw_bias: " + ssw_bias);
        debug_print("     slw_bias: " + slw_bias);
        debug_print("    ssw_phase: " + ssw_phase);
        debug_print("    slw_phase: " + slw_phase);
        debug_print("  dcuDataRate: " + dcuDataRate);
        debug_print("smecFrameRate: " + smecFrameRate);
        debug_print(" smecDataRate: " + smecDataRate);
        debug_print("  dcuDataMode: " + dcuDataMode);
        debug_print(" bsmFrameRate: " + bsmFrameRate);
        debug_print("  bsmDataRate: " + bsmDataRate);
        debug_print("  dpuDataRate: " + dpuDataRate);
        debug_print(" scuFrameRate: " + scuFrameRate);
        debug_print("  scuDataRate: " + scuDataRate);
    }
    // //
    // //
    // Set the DCU bias frequency, sampling rate, and data mode:
    //
    // Safety checks:
    //
    if(mclkDiv == -1) {
        error("mclkDiv is not defined for this mode. Think again or call help!");
    }
    if(biasDiv == -1) {
        error("biasDiv is not defined for this mode. Think again or call help!");
    }
    if(dcuDataMode == -1) {
        error("dcuDataMode is not defined for this mode. Think again or call help!");
    }
    //
    SpireProc_Set_DcuFreqSampMode(mclkDiv,biasDiv,dcuDataMode,phot,debug);
    // //
    // //
    // Set the phases of the photometer array:
    //
    // Safety checks:
    //
    if(ssw_phase == -1) {
        error("ssw_phase is not defined for this mode. Think again or call help!");
    }
    if(slw_phase == -1) {
        error("slw_phase is not defined for this mode. Think again or call help!");
    }
    //
    SpireProc_Set_SpecPhase(ssw_phase,slw_phase,debug);
    // //
    // //
    // Set the bias amplitud of the spectrometer array:
    //
    // Safety checks:
    //
    if(ssw_bias == -1) {
        error("ssw_bias is not defined for this mode. Think again or call help!");
    }
    if(slw_bias == -1) {
        error("slw_bias is not defined for this mode. Think again or call help!");
    }
    //
    SpireProc_Set_SpecBias(ssw_bias,slw_bias,debug);
    // //
    // //
    // Set the SMEC framerate:
    //
    // Safety checks:
    //
    if(smecFrameRate == -1) {
        error("smecFrameRate is not defined for this mode. Think again or call help!");
    }
    //
    SpireProc_Set_SmecFramerate(smecFrameRate,debug);
    // //
    // //
    // Set the BSM framerate:
    //
    // Safety checks:
    //
    if(bsmFrameRate == -1) {
        error("bsmFrameRate is not defined for this mode. Think again or call help!");
    }
    //
    SpireProc_Set_BsmFramerate(bsmFrameRate,debug);
    // //
    // //
    // Set the SCU framerate
    //
    // Safety checks:
    //
    if(scuFrameRate == -1) {
        error("scuFrameRate is not defined for this mode. Think again or call help!");
    }
    //
    SpireProc_Set_ScuFramerate(scuFrameRate,debug);
    // //
    // //
    // Temporary fix for SPR-SPIRE-1613 (hardcode command):
    //
    // Set sampling to continuous
    SpireSendDrcuCmd(0x843d0000,0);
    sync();
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"      " + tstr + ": SpireProc_Set_SpecMode ended");
    // //
    // //
    // Return data rates:
    //

    return [dcuDataRate,smecDataRate,bsmDataRate,dpuDataRate,scuDataRate];
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndJfetVssTestC.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of 
// SpirePhoto/Spectro_Cal_JfetVssTestC
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/21 V1.0: Initial version adapted from
//                  SpireBb_EndFovMapFpgScan (2009/05/05 V1.0)
// S.D.Sidher:
// 2010/01/11 V1.1: Replaced references to PHOTSTBY or SPECSTBY with REDY
//                              Removed Chop references
//                              Added the commands to reset BBID and OBSID to null at the end
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndJfetVssTestC SPIRE 14072 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndJfetVssTestC reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set obsstep back to 0:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP(0)");
    Spire_SET_OBS_STEP(0);
    // //
    // //
    // Set instrument back to REDY:
    //
    SpireSetObsMode("REDY");
    // //
    // //
    // //
    // //
    tstr = SpireTimeStr(time());
    message("5          " + tstr + "Cmd: Spire_SET_BBID_RAW(0x80000000)");
    Spire_SET_BBID_RAW(0x80000000);
    delay(1);
    //
    int obsId = SpireNullObsid();
    tstr = SpireTimeStr(time());
    hstr = SpireHexStr(obsId,8);
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBSID_RAW(" + hstr + ")");
    Spire_SET_OBSID_RAW(obsId);
    //
    sync();
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndJfetVssTestC reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_StartObsAll.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to configure observation at the start of all AOTs
// (i.e. astronomer, engineering, and calibration ones). 
//
// It sets the OBSIDs for the current observation, sets the BB, 
// resets the DRCU counter, and sets the MODE. This script includes 
// HSPOT messages. 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/05/05 V1.0: First version adapted from 
//                  SpireBb_StartObsAll (2009/01/30 V1.1)
// 
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_StartObsAll {
    string obsmode = "ENG_CAL_OBS"; // Parameter to specify the configuration mode
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string: 
    string hstr = "";
    // 
    // a time string:
    string tstr = "";
    // //
    // //
    // Start procedure:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(3,"      " + tstr + ": Proc StartObsAll started");
    SpireMsg(3,"            $Id: $");
    //
    // Wait for busconfig to be performed:
    // delay(1);
    // Note, this will be set in SpireBb_StartObsAll
    // //
    // //
    // Set the OBSIDs for the current observation:
    //
    hstr = SpireHexStr($OBSID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + " Cmd: Spire_SET_OBSID(" + hstr + ")");
    Spire_SET_OBSID($OBSID);
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    delay(1);
    // //
    // //
    // Reset DRCU counter:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RESET_DRCU_COUNTERS(" + hstr + ")");
    Spire_RESET_DRCU_COUNTERS();
    // //
    // //
    // Set the MODE using the SET_OBS_MODE Spire command: 
    //
    int mode_id = ilookup("SpireTableInstConfigs.txt",obsmode,"value");
    hstr = SpireHexStr(mode_id,4);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_MODE(" + hstr + ")");
    Spire_SET_OBS_MODE(mode_id);
    // //
    // //
    // Round up total duration:
    //
    sync();
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(3,"      " + tstr + ": Proc StartObsAll ended");
    SpireMsg(2,"    Proc StartObsAll (" + (time() - t) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_VmTable.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to update POF2-like VM positions tables
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/07/04 V0.1: Initial version
// 2008/07/24 V0.2: Remove restriction of step value to 0-255
// 2009/09/17 V1.0: Add proper header description. 
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_VmTable {
    int itableID = 0x37; // Table ID to be uploaded 
    string version = "v01"; // Version in calibration file
}{
    // //
    // //
    // Setup:
    //
    bool debug = true;
    //bool debug = false;
    // //
    // //
    // Load values from calibration file:
    //
    string calTable = "SpireTable_Pof2VmTables.txt";
    //
    int tableID = ilookup(calTable,version,"tableID");
    int tableLength = ilookup(calTable,version,"tableLength");
    int pos01 = ilookup(calTable,version,"pos01");
    int pos02 = ilookup(calTable,version,"pos02");
    int pos03 = ilookup(calTable,version,"pos03");
    int pos04 = ilookup(calTable,version,"pos04");
    int pos05 = ilookup(calTable,version,"pos05");
    int pos06 = ilookup(calTable,version,"pos06");
    int pos07 = ilookup(calTable,version,"pos07");
    int pos08 = ilookup(calTable,version,"pos08");
    int pos09 = ilookup(calTable,version,"pos09");
    int pos10 = ilookup(calTable,version,"pos10");
    int pos11 = ilookup(calTable,version,"pos11");
    int pos12 = ilookup(calTable,version,"pos12");
    int pos13 = ilookup(calTable,version,"pos13");
    int pos14 = ilookup(calTable,version,"pos14");
    int pos15 = ilookup(calTable,version,"pos15");
    int pos16 = ilookup(calTable,version,"pos16");
    int pos17 = ilookup(calTable,version,"pos17");
    //
    // Glue values together for UPDATE_TABLE input:
    //
    {int} p01 = {pos01};
    {int} p02 = {pos02};
    {int} p03 = {pos03};
    {int} p04 = {pos04};
    {int} p05 = {pos05};
    {int} p06 = {pos06};
    {int} p07 = {pos07};
    {int} p08 = {pos08};
    {int} p09 = {pos09};
    {int} p10 = {pos10};
    {int} p11 = {pos11};
    {int} p12 = {pos12};
    {int} p13 = {pos13};
    {int} p14 = {pos14};
    {int} p15 = {pos15};
    {int} p16 = {pos16};
    {int} p17 = {pos17};
    {int}[] posarray = [p01,p02,p03,p04,p05,p06,p07,p08,p09,p10,p11,p12,p13,p14,p15,p16,p17];
    //debug_print("posarray: " + posarray);
    // //
    // //
    // Set new table:
    //
    Spire_SET_TABLE(tableID,tableLength);
    delay(1);
    // update table command call for table index 0x0000:
    //Spire_UPDATE_TABLE(0x32,0x0,17,[{0x9a576ae2},{0x9a57b653},{0xa1376ae2},{0xa137b653},{0x9dc76e35},{0x9dc7b8e0},{0x96e66e35},{0x96e6b8e0},{0x93766ae2},{0x9376b653},{0x96e66792},{0x96e6b3b4},{0x9dc76792},{0x9dc7b3b4},{0x9a576ae2},{0x9a57b653},{0x7f000000}]);
    //Spire_UPDATE_TABLE(tinput);
    Spire_UPDATE_TABLE(tableID,0x0,tableLength,posarray);
    delay(1);
}

block Pacs_CcuMonitorDefaultRecycle PACS 2101 {
}{
    PacsCcuMonitorPeriodDefault();
    sync();
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_SmecMove2Home.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to move SMEC to an input home position from a unsecure start 
// position while not allowing for the necessary delay in time to reach 
// position but allowing the movement to continue beyond the end of 
// the procedure!
//
///////////////////////////////////////////////////////////////////////////
//
// KJK:
// 2009/05/05 V0.1: Initial version adapted from 
//                  SpireProc_SmecMove (2009/03/31 V0.3)
//
// Notes:
// 
//  1) When SpireProc_Setup_SmecScan is used, SpireProc_SmecMove2Home needs 
//     to be run before. 
//  2) The procedures leave the SMEC running at end, i.e there is no 
//     finalhold position command! 
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_SmecMove2Home {
    int smecPosn = 13500; // SMEC final position (encoder value) 
    int smecCurrPosn = 3500; // SMEC current position (encoder value)
    bool debug = false;
}{
    // //
    // //
    // Define some variables:
    //
    int t = time();
    //
    // hex string:
    string hstr = "";
    //
    // time string:
    string tstr = "";
    //
    // Hardcoded name and version of calibration tables:
    string tabName = "SpireTable_SmecNominalSettings.txt";
    string version = "v00";
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(3,"      " + tstr + ": Proc SmecMove2Home started");
    SpireMsg(3,"            $Id: $");
    // //
    // //
    // Move to  position (only if we have to):
    //
    if(smecCurrPosn != smecPosn) {
        //
        // fetch SMEC movement parameters
        //    
        int moveCmd = ilookup(tabName,version,"MoveCmd");
        int moveSpeed = ilookup(tabName,version,"MoveSpeed");
        int moveTime = (smecCurrPosn - smecPosn) / moveSpeed;
        if(moveTime < 0) {
            moveTime = moveTime * -1;
        }
        moveTime = moveTime + 2;
        // allow 2 sec to stabilise
        if(debug) {
            debug_print("Movement Time: " + moveTime);
        }
        // //
        // //
        // Set SMEC mode to hold its position:
        //
        SpireSendDrcuCmd(0x90490000,0);
        // //
        // //
        // Move to  position:
        //
        // Set scan speeds:
        SpireSendDrcuCmd(0x90470000 + moveCmd,0);
        delay(1);
        SpireSendDrcuCmd(0x90560000 + moveCmd,0);
        //
        // Set SMEC position:
        SpireSendDrcuCmd(0x90450000 + smecPosn,0);
        delay(1);
        //
        // Move SMEC to position:
        SpireSendDrcuCmd(0x90490001,0);
        sync();
    }
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(3,"      " + tstr + ": Proc SmecMove2Home ended");
    SpireMsg(2,"    Proc SmecMove2Home (" + (time() - t) + " seconds)");
}

// SpireBbFtsScan
//
// $id$
//
// Execute a set of spectrometer scans at a given resolution
//
// This BB assumes that the spectrometer starts at the ScanStart position
// and returns the spectrometer back to the ScanStart position at the end
//
// returns the actual time on-source
//
//  K.J. King
//
//  20/ April 2007: KJK v1.4: 
//            SCR3056 - now read Home position from Spectrometer.txt
//            SPR2835 - now returns the correct on-source integration time for the number of scans requested
//
// 04 November 2008: KJK
//             Added data_rate commands
// 27 January 2009: KJK
//             - Added "C" to available scan resolution options (SCR-1114)
//             - Changed lookup calls to use versioning procedures (SCR-1154)
//             - Added command to set/reset SCANRES parameter (SCR-0605) for each scan
//             - Changed assumed begining and end positions to ScanStart and
//                no longer uses Home position (SCR-3057)
//             
//
double block SpireBbFtsScan SPIRE 8454 {
    string resolution = "" in ["H","M","L","C"];
    int nscans = 0;
    int step = 0;
    string specVersion = "v00";
    bool debug = false;
}{
    // Retrieve required SMEC params
    // 
    int resId = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ResId",specVersion,debug);
    int scanStart = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanStart",specVersion,debug);
    int scanEnd = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanEnd",specVersion,debug);
    int scanFSpeed = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanFSpeed",specVersion,debug);
    int scanRSpeed = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanRSpeed",specVersion,debug);
    int scanFCmd = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanFCmd",specVersion,debug);
    int scanRCmd = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanRCmd",specVersion,debug);
    string waveform = SpireProc_GetTableEntryString("SpireTable_Spectrometer.txt","ResChar",resolution,"Waveform",specVersion,debug);
    //
    //  adjust nscans to obtain correct number of scans at observing speed 
    if(waveform == "SAWTOOTH") {
        nscans = nscans * 2;
    }
    //
    // Calculate the scan 'forward','reverse' travel times 
    int scanFTime = (scanEnd - scanStart) * (nscans / 2) / scanFSpeed;
    int scanRTime = (scanEnd - scanStart) * (nscans / 2) / scanRSpeed;
    //
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": SpireBbFtsScan started");
    SpireMsg(2,"          $Id:$");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP 
    SpireProc_Set_ObsStep(step,debug);
    //
    // Set SCANRES parameter
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_UPDATE_TABLE_RAW(7, 6, 1, " + resId + ")");
    Spire_UPDATE_TABLE_RAW(7,6,1,[{resId}]);
    // Set SMEC to hold its position
    SpireSendDrcuCmd(0x90490000,0);
    // 
    // execute scans
    //
    // Set scan start and ending position
    //
    SpireSendDrcuCmd(0x90460000 + scanStart,0);
    SpireSendDrcuCmd(0x90450000 + scanEnd,0);
    delay(1);
    //
    // Set scan forward and reverse speed (only different if we are performing a saw tooth scan) 
    SpireSendDrcuCmd(0x90470000 + scanFCmd,0);
    SpireSendDrcuCmd(0x90560000 + scanRCmd,0);
    delay(1);
    //
    // Specify number of scans 
    SpireSendDrcuCmd(0x90480000 + nscans,0);
    //
    // Start data collection (DCU frames (assumes everything setup) + SMEC frames (idem)) 
    //
    // Set number of frames to continuous
    SpireSendDrcuCmd(0x843d0000,0);
    SpireSendDrcuCmd(0x91c3ffff,0);
    // Start data collection
    SpireSendDrcuCmd(0x843e0001,0);
    SpireSendDrcuCmd(0x91c10001,0);
    //  set datarate
    double rate = 0.0;
    rate = dlookup("Datarates.txt","Scan","DCU");
    rate = rate + dlookup("Datarates.txt","Scan","BSM");
    rate = rate + dlookup("Datarates.txt","Scan","SMEC");
    data_rate(rate);
    //
    // Start scanning
    SpireSendDrcuCmd(0x90490002,0);
    delay(scanFTime + scanRTime + nscans + 2);
    // allow 1 sec for turnaround at end of each scan
    //
    // When scan is finished stop data generation
    SpireSendDrcuCmd(0x843e0000,0);
    SpireSendDrcuCmd(0x91c10000,0);
    data_rate(0.0);
    delay(1);
    Spire_FLUSH_FIFO(0x3000);
    delay(1);
    // hold position
    SpireSendDrcuCmd(0x90490000,0);
    //
    // reset SCANRES parameter
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_UPDATE_TABLE_RAW(7, 6, 1, " + 0 + ")");
    Spire_UPDATE_TABLE_RAW(7,6,1,[{0}]);
    //
    // calculate actual on source observing time
    double srcTime = SpireProc_GetTableEntryDouble("SpireTable_Spectrometer.txt","ResChar",resolution,"Osit",specVersion,debug);
    // effective on source integration time per scan
    if(waveform == "SAWTOOTH") {
        srcTime = srcTime * double(nscans / 2);
    } else {
        srcTime = srcTime * double(nscans);
    }
    //
    // ..... completion .....
    //
    sync();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Fts Scan ended");
    SpireMsg(1,"  ..Scanning (" + (time() - t) + " seconds)");
    //

    return srcTime;
}

// SpirePOF2Observing
//
// $Id:$
//
// This is the procedure to calculate 
// instrument observing parameters for the 7-point Jiggle observing mode
//
//  12/08/2009 KJK:
//            SPIRE-1804: Added versions and debug as input parameters to enable calling SpireBbJiggle correctly
//            Changed calls to calibration Tables to use versions
//
{double,int,int,int,int,int} procedure SpirePOF2Observing {
    int nRepetitions = 1 in [1,1200]; // number of repeats of basic observing cycle (=1 nod cycle)
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParms
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParm;
    string chopVersion = "v00"; // Version in cal table SpireTable_ChopParams
    bool debug = false;
}{
    SpireMsg(2,"    POF2 Observing Parameters ");
    SpireMsg(2,"    $Id: SpirePOF2Observing.txt,v 1.3 2007/01/15 18:34:14 kking Exp $");
    //
    // fetch operating parameters 
    string obsMode = "POF2";
    int t = 0;
    t = SpireProc_GetTableEntryInt("SpireTable_SpireParams.txt","mode",obsMode,"FlashTime",spireVersion,debug);
    double flashTime = double(t);
    // Optimum time between flashes
    t = SpireProc_GetTableEntryInt("SpireTable_SpireParams.txt","mode",obsMode,"CalTime",spireVersion,debug);
    double calTime = double(t);
    // Minimum time between gyro calibrations
    int jiggleTable = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"TableId",opsVersion,debug);
    // Jiggle Table ID  
    int jiggleSize = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"TableSize",opsVersion,debug);
    // Jiggle Table length 
    int nChops = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NChops",opsVersion,debug);
    // number of chop cycles per jiggle position  
    int nJiggs = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NJiggs",opsVersion,debug);
    // number of jiggle positions per nod position  
    int nNodPosns = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NNodPosns",opsVersion,debug);
    // number of nod positions in a nod cycle 
    int nNodCycles = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NNodCycles",opsVersion,debug);
    // number of nod cycles in a repetition 
    bool initFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"InitFlash",spireVersion,debug);
    // initial flash flag
    bool endFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"EndFlash",spireVersion,debug);
    // final flash flag
    double srcTime = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"SrcTime",opsVersion,debug);
    // effective on source integration time per complete map
    //     
    // *****************************************
    //   Display input parameters
    // *****************************************
    SpireMsg(3,"     POF2 Logic input values:");
    SpireMsg(3,"     ..nRepetitions: " + nRepetitions);
    SpireMsg(3,"     POF2 Fixed values:");
    SpireMsg(3,"     ..jiggleTable: " + jiggleTable);
    SpireMsg(3,"     ..jiggleSize: " + jiggleSize);
    SpireMsg(3,"     ..nChops: " + nChops);
    SpireMsg(3,"     ..nJiggs: " + nJiggs);
    SpireMsg(3,"     ..nNodPosns: " + nNodPosns);
    SpireMsg(3,"     ..nNodCycles: " + nNodCycles);
    SpireMsg(3,"     ..initFlash: " + initFlash);
    SpireMsg(3,"     ..endFlash: " + endFlash);
    SpireMsg(3,"     ..SrcTime: " + srcTime);
    //
    // calculate observing parameters
    SpireMsg(2,"    Calculated Parameters:");
    //
    // number of times to repeat the jiggle cycle at each nod position  
    // Note:  this is currently read from a calibration table but could be calculated 
    // if it is required to dynamically assign integration time to each nod position 
    // rather than by repeating complete nod cycles
    int nNodInts = ilookup("OpsParms.txt","POF2","NNodInts");
    SpireMsg(3,"      Required number of jiggle cycles at each nod position: " + nNodInts);
    //
    //  number of nod cycles to perform
    int nCycles = nRepetitions * nNodCycles;
    SpireMsg(3,"      Required number of Nod cycles: " + nCycles);
    //
    // observing time per nod cycle
    double cycleTime = double(nNodPosns * duration(SpireBbJiggle("POF2",jiggleTable,0,nJiggs,nNodInts,0,opsVersion,chopVersion,debug)));
    SpireMsg(3,"      Time for a Nod cycle: " + cycleTime);
    //
    // total observing time 
    double totalTime = double(nCycles) * cycleTime;
    SpireMsg(3,"      Total observing time: " + totalTime);
    //
    // number of nod cycles per Gyro calibration 
    // Note: this only takes into account on source observing time, not movement between nod positions, 
    // which is assumed to be a small fraction of the observing time, and so the value obtained is approximate 
    int nCals = ifloor(totalTime / calTime);
    // SpireMsg(3,"      Number of Gyro Calibrations: " + nCals);
    int nCal = iceil(totalTime / cycleTime);
    // default is no gyro calibrations during observation 
    if(nCals > 0) {
        nCal = iceil(double(nCycles) / double(nCals + 1));
    }
    if(nCycles % nCal == 0) {
        nCal = nCal + 1;
    }
    // SpireMsg(3,"      Number of Gyro Calibrations(adjusted): " + nCals);
    // SpireMsg(3,"      Number of nod cycles per Gyro calibration: " + nCal);
    //
    // number of nod cycles per PCAL calibration 
    // Note: this only takes into account on source observing time, not movement between nod poditions, 
    // which is assumed to be a small fraction of the observing time, and so the value obtained is approximate 
    int nFlashes = ifloor(totalTime / flashTime);
    SpireMsg(3,"      Number of Flashes: " + nFlashes);
    int nFlash = iceil(totalTime / cycleTime);
    // default is no flashes during observation 
    if(nFlashes > 0) {
        nFlash = iceil(double(nCycles) / double(nFlashes + 1));
    }
    if(nCycles % nFlash == 0) {
        nFlash = nFlash + 1;
    }
    SpireMsg(3,"      Number of Flashes(adjusted): " + nFlashes);
    SpireMsg(3,"      Number of nod cycles per PCAL calibration: " + nFlash);

    return {srcTime,nCycles,nNodPosns,nNodInts,nCal,nFlash};
}

// SpireBbScanLine
//
// $Id: SpireBbScanLine.txt,v 1.2 2006/10/10 10:20:51 kking Exp $
//
// Building Block to execute a scan line operation as part of a scan map:
//     take detector data for a fixed period of time
//
// Note: this BB assumes that the detector bias and sampling frequency and 
//       the BSM sampling frequency have been set appropriately  
//
//       This BB assumes that 2 seconds have been included in the scan time to allow
//       setting of the BB and STEP at the start of the scan.
//       It also assumes that 2 seconds have been included at the end of the scan to 
//       reset the STEP parameter 
//       (see SpirePOF5Observing)
//
double block SpireBbScanLine SPIRE 8451 {
    int len = 0; // total length of scan 
    int step = 0;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB ScanLine started");
    SpireMsg(2,"          $Id: SpireBbScanLine.txt,v 1.2 2006/10/10 10:20:51 kking Exp $");
    //
    // check input values
    int tStart = 2;
    int tEnd = 2;
    int osit = len - tStart - tEnd;
    if(osit < 0) {
        error("time for scan is less than minimum time required to setup scan");
    }
    //
    // ..... configuration .....
    //
    // set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP
    hstr = SpireHexStr(step,4);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(" + hstr + ")");
    Spire_SET_OBS_STEP_RAW(step);
    //
    // ..... execution ..... 
    //
    // wait to end of line
    wait_until(t + tStart + osit);
    //
    // ..... completion .....
    //
    // set STEP
    hstr = SpireHexStr(0,4);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(" + hstr + ")");
    Spire_SET_OBS_STEP_RAW(0);
    //
    wait_until(t + tStart + osit + tEnd);
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB ScanLine ended");
    SpireMsg(1,"  ..Scanning (" + (time() - t) + " seconds)");
    //

    return double(osit);
}

// $Id$
//
// This building block executes the cooler recycle procedure
// 
// The instrument should be in  the REDY mode before execution of this observation
//
// History       6-feb-2008 DAC File renamed to SpireBbParalelCoolerRecycle.txt
//                              Did not change BB name to keep current BBID
//                 25-Aug-2009 KJK
//                            - Updated to get Command List information from SpireTable_CommandLIsts.txt
//                            - Updated to get CREC parameters from new Cal Table (SpireTable_CL_CREC.txt)
//                            - Modified BB completion messages 
//
int block SpirePacsBbCoolerRecycle SPIRE 2569 {
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Cooler Recycle started");
    SpireMsg(2,"          $Id$");
    //
    int cmd = 0x0;
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    //
    // Select  the current instrument in operation (prime/redundant)
    string side = "prime";
    //
    // Get Command List info 
    int tableId = ilookup("SpireTable_CommandLists.txt","CREC","TableId");
    int startIndex = ilookup("SpireTable_CommandLists.txt","CREC","Index");
    int nParams = ilookup("SpireTable_CommandLists.txt","CREC","NParms");
    //
    // Retrieve the VM input parameters 
    int a = ilookup("SpireTable_CL_CREC.txt","a",side);
    // Heat Switch ON current (during Recycling)
    int b = ilookup("SpireTable_CL_CREC.txt","b",side);
    // Heat Switch OFF current
    int c = ilookup("SpireTable_CL_CREC.txt","c",side);
    // Pump Heat Switch Actuation Temperature
    int d = ilookup("SpireTable_CL_CREC.txt","d",side);
    // Pump Heater Dissipation 1
    int e = ilookup("SpireTable_CL_CREC.txt","e",side);
    // Pump Condensation Temperature 1
    int f = ilookup("SpireTable_CL_CREC.txt","f",side);
    // Pump Heater Dissipation 2
    int g = ilookup("SpireTable_CL_CREC.txt","g",side);
    // Pump Condensation Temperature 2
    int h = ilookup("SpireTable_CL_CREC.txt","h",side);
    // Pump Heater Dissipation 3
    int i = ilookup("SpireTable_CL_CREC.txt","i",side);
    // Pump Heater Dissipation 4
    int j = ilookup("SpireTable_CL_CREC.txt","j",side);
    // Pump Condensation Temperature Threshold
    int k = ilookup("SpireTable_CL_CREC.txt","k",side);
    // Evaporator Condensation Temperature
    int l = ilookup("SpireTable_CL_CREC.txt","l",side);
    // Evaporator Heat Switch Actuation Temperature
    int m = ilookup("SpireTable_CL_CREC.txt","m",side);
    // Pump Threshold Temperature
    int n = ilookup("SpireTable_CL_CREC.txt","n",side);
    // Heat Switch ON current
    int o = ilookup("SpireTable_CL_CREC.txt","o",side);
    // Sampling Interval (sec)
    int p = ilookup("SpireTable_CL_CREC.txt","p",side);
    // Heatswitch Timeout (min)
    int q = ilookup("SpireTable_CL_CREC.txt","q",side);
    // Pump Heating Timeout 1 (min)
    int r = ilookup("SpireTable_CL_CREC.txt","r",side);
    // Pump Heating Timeout 2 (min)
    int s = ilookup("SpireTable_CL_CREC.txt","s",side);
    // Evaporator Timeout (min)
    int t = ilookup("SpireTable_CL_CREC.txt","t",side);
    // Pump Cooling Timeout (min)
    int u = ilookup("SpireTable_CL_CREC.txt","u",side);
    // Global Timeout (min)
    //
    // Set Mode to CREC
    mois_comment("Set the SPIRE mode to CREC for Cooler Recycle");
    SpireSetObsMode("CREC");
    //
    // start executing recycle VM
    mois_comment("Execute the SPIRE command to perform Automatic Cooler Recycle");
    mois_spacon("This command will take about " + (u + 1) + " minutes to execute");
    {int}[] crecParams = [{a},{b},{c},{d},{e},{f},{g},{h},{i},{j},{k},{l},{m},{n},{o},{p},{q},{r},{s},{t},{u}];
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM_RAW(" + tableId + "," + startIndex + "," + nParams + "," + crecParams + ")");
    Spire_RUN_VM_RAW(tableId,startIndex,nParams,crecParams);
    //
    // DAC
    // Do not wait here; return needed duration, caller will wait as necessary
    // Wait for completion
    // Insert a delay equal to the CREC VM global time out plus a minute
    int howLong = u * 60 + 58;
    //
    // completion
    ///    tstr = SpireTimeStr(time());
    ///    SpireMsg(2,"    " + tstr + ":  BB Cooler Recycle   Running");
    ///    SpireMsg(1,"  ..Cooler Recycle Startup (" + (time() - t0) + " seconds)");

    return howLong;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_PhotFSetPhase.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set phase of photometer arrays
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/05/07 V0.1: Initial version adapted from 
//                  PF_Phase.txt (v1.4 2008/01/31 20:24:34)
// 2008/05/08 V0.2: Restrict script to send only 2 commands per second 
//                  by moving one delay(1) 
// 2008/07/04 V0.3: Renumber version; add PTC phase
// 2009/01/27 V1.0: Add debug_print; Remove unsetting of BBID at end.
//                  Add HSPOT messages;
// 2009/02/14 V1.1: Instead of using commands call SpireProc_Set_PhotPhase
//                  and add sync() after setBbId 
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_PhotFSetPhase SPIRE 14010 {
    int psw_phase = 0x0 in [0,255]; //Default phase is 0 [Hex]
    int pmw_phase = 0x0 in [0,255]; //Default phase is 0 [Hex]
    int plw_phase = 0x0 in [0,255]; //Default phase is 0 [Hex]
    int ptc_phase = 0x0 in [0,255]; //Default phase is 0 [Hex]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string hstr = "";
    // a hex string
    string tstr = "";
    // a time string
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": SpireBb_PhotFSetPhase started");
    SpireMsg(2,"          $Id: $");
    hstr = SpireHexStr($BBID,8);
    SpireMsg(3,"          BBID = " + hstr);
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    sync();
    // //
    // //
    // Set the phase for the three arrays and the PTC bolometer:
    //
    SpireProc_Set_PhotPhase(psw_phase,pmw_phase,plw_phase,ptc_phase,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_PhotFSetPhase ended");
    SpireMsg(1,"  ..Set Phot phases (" + (time() - t) + " secs)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_Cal_StdLoadCurve.txt
//
///////////////////////////////////////////////////////////////////////////
// 
//  CUS script for: 'Phot Standard Load Curve' 
//
//  in *basic_fine_pointing* or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/06/09 V0.1: Initial version adapted from 
//                  Mode_ILT_PERF_DAB_P_CPS.txt (v 1.3 2008/01/31 23:35:17)
// 2008/06/20 V0.2: Move SpireBb_StartupObs to start
// 2008/07/03 V0.3: Renumber version; SpireProc_Set_PhotNominalbias changed
//                  name; SpireBb_PhotFSetupData has extra parameter; use 
//                  also PTC bolometers
// 2008/07/21 V0.4: Allow nafid as input parameter
// 2008/08/15 V0.5: Change name of default input bias_table;
//                  Remove test number; modify description 
//                  Adapt to change in call to low level script 
//                  SpireProc_CalcParam_BiasFreqSampFreq.txt 
// 2008/11/11 V0.6: Allow 'no pointing' as input option; Adapt debug printing
// 2008/11/12 V0.7: Implement mode setting; Add isBright 
//                  Change 'no pointing' implementation
// 2009/02/01 V1.0: Add debug_print as input and pass it to some low level 
//                  scripts. Use new SpireBb_EndObsAll and SpireBb_StartObsAll. 
//                  Read nominal bias frequency and bias divider from new
//                  SpireTable_DetectorSettings.txt. Implemented message 
//                  if activating isBright setting. Implemented setting 
//                  of datarates. Replace SpireProc_Set_PhotNominal by
//                  SpireProc_Set_FreqSampAmpPhasNominal. Bias levels used 
//                  for the load curve are now calculated in 
//                  SpireProc_CalcParam_LoadCurve.
// 2009/02/17 V1.1: Use SpireBb_PhotSetMode to set to PHOTSTBY during 
//                  SLEW and FINAL_HOLD. Read boresight from 
//                  SpireTable_OpsParms. New setting of datarates. 
//                  Remove cal. table name from input. Replace call to 
//                  SpireBb_PhotFSetupData with call to SpireBb_PhotFSetPhase 
//                  and SpireBb_PhotFSetBiasAmpl to set user requested 
//                  frequency, phase, and first BiasAmpl.
// 2009/02/19 V1.2: Elevate version05 to input.
// 2009/03/04 V1.3: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Replace 'message' by
//                  'error' if isBright is selected. 
// 2009/05/06 V1.4: Add in move BSM to hold at start. Gather procedures at 
//                  start and end in separate BB. 
// 2009/06/05 V1.5: Hardcode STBY 'v00' in EndBB (SPR-1477)
// 2010/01/06 V1.6: Edit default parameters for input phases 
//                  and set version05 to v05 (SCR-SPIRE-2300)
//
///////////////////////////////////////////////////////////////////////////
//
//  Script assumes that:
//
//  1)  Instrument is in PHOTSTBY at beginning 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Phase is kept constant (from input) during this test, i.e no 
//     adjustment of the phase with changing bias amplitude and frequency
//
//  3) Bias frequency, sampling rate, and phase are input parameters
//
//  4) Boresight of array can be read from following cal table:
//     SpireTable_OpsParms.txt   
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhoto_Cal_StdLoadCurve {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; // NAIF identifier
    bool isBright = false; // Use settings for bright source (==tick)
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    double biasfreq = 130.2 in [70.0,200.0]; // Bias frequency [Hz]
    double samplerate = 18.6 in [1.0,20.0]; // Sampling rate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    double phasedeg_psw = 179.294 in [0.0,360.0]; // PSW Bias phase [deg]
    double phasedeg_pmw = 179.294 in [0.0,360.0]; // PMW Bias phase [deg]
    double phasedeg_plw = 183.529 in [0.0,360.0]; // PLW Bias phase [deg]
    double phasedeg_ptc = 203.294 in [0.0,360.0]; // PTC Bias phase [deg]
    int ftime = 10; // Readout time at each bias level [s]
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_StdLoadCurveLevels
    string version05 = "v05"; // Version in cal table SpireTable_OpsParms.txt
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Check for is bright setting: 
    //
    if(isBright) {
        isBright = false;
        error("IsBright does not make sense here. Try again (e.g. subtract the phase shift manually from the input)!");
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = true;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_StdLoadCurveLevels.txt";
    string tabName04 = "SpireTable_BsmNominalSettings.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    //
    // Currently hardcoded version and model parameter:
    //
    string version04 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    //
    // Dummy value for Spec script:
    // (needed but not used in phot script!)
    //
    int smecHomePosn = 3500;
    // SMEC home position
    int ssw_bias = 45;
    //
    int slw_bias = 45;
    //
    int ssw_phase = 128;
    //
    int slw_phase = 128;
    // 
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS12";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "PEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Retrieve bias levels used for the load curve:
    // 
    tabName = tabName03;
    version = version03;
    int[] nbiaslist = SpireProc_CalcParam_LoadCurve(tabName,version,debug);
    //
    // Lookup first bias level:    
    int psw_bias = nbiaslist[0];
    int pmw_bias = nbiaslist[0];
    int plw_bias = nbiaslist[0];
    int ptc_bias = nbiaslist[0];
    // //
    // //
    // Convert user input to Hex values:
    //
    // for bias frequency and sample rate: 
    // 
    int[] hexvalues = SpireProc_CalcParam_BiasFreqSampFreq(biasfreq,samplerate,fts,debug);
    int mclkdiv = hexvalues[0];
    int biasdiv = hexvalues[1];
    if(debug) {
        debug_print("Hex values of mclkdiv/biasdiv are: " + mclkdiv + " " + biasdiv);
    }
    //
    // for bias phase:
    //
    int[] phasehex = SpireProc_CalcParam_PhotPhaseConvert(phasedeg_psw,phasedeg_pmw,phasedeg_plw,phasedeg_ptc,debug);
    int psw_phase = phasehex[0];
    int pmw_phase = phasehex[1];
    int plw_phase = phasehex[2];
    int ptc_phase = phasehex[3];
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version04;
    tabName = tabName04;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // // // // // // // // // // // // // // // // 
    // // // // // // // // // // // // // // // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartStdLoadCurve(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,psw_phase,pmw_phase,plw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug));
    // 
    // BBs carried out when the pointing is reached:
    if(pointing) {
        int tinithold = 0;
    } else {
        tinithold = tslewmin;
    }
    //
    // BB carried out during pointing:
    int tp = duration(SpireProc_Exec_PhotStdLoadCurve(nbiaslist,ftime,debug));
    //
    // BB carried out at the end:  
    int tfinalhold = duration(SpireBb_EndStdLoadCurve(phot,isBright,version01,version02,debug));
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartStdLoadCurve(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,psw_phase,pmw_phase,plw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation:
                //
                SpireBb_StartStdLoadCurve(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,psw_phase,pmw_phase,plw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug);
                //
            }
            //
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            // //
            // //
            // Execute load curve:
            //
            SpireProc_Exec_PhotStdLoadCurve(nbiaslist,ftime,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            //
            SpireBb_EndStdLoadCurve(phot,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_BsmMove.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to return BSM to hold position
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/09/08 V0.1: Initial version adapted from SpireBb_PhotChop 
//                  (2008/08/04 V0.2)
// 2008/10/13 V0.2: Adapt to name change of calibration file.
// 2008/11/06 V0.3: Change name 
// 2009/01/27 V1.0: Change call to calibration file. Add debug_print as input.
//                  Remove unsetting of BBID at end.  
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_BsmMove SPIRE 14028 {
    int chopPosn = 2048 in [0,65535];
    int jiggPosn = 2048 in [0,65535];
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    SpireMsg(4,"    " + time() + ": SpireBb_BsmMove started");
    SpireMsg(4,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    sync();
    //
    // //
    // //
    // Move BSM:
    //
    SpireProc_Set_BsmMove(chopPosn,jiggPosn,debug);
    // //
    // //
    // End BB:
    //
    SpireMsg(4,"    " + time() + ": BB SpireBb_BsmMove ended");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SpecOffsetAuto.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set the detector offset for the spectrometer arrays
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/11 V0.1: Initial version adapted from 
//                  SpireBb_PhotOffsetAuto.txt (2008/07/03 V0.2)
//                  SOffset_Auto.txt (v1.4 2008/01/31 20:24:37)
// 2009/02/19 V0.2: Move all commands in low level procedure
//                  SpireProc_Set_SpecOffsetAuto. This fixes a bug 
//                  detected in FS2 with setting the correct (spec==4) 
//                  datamode at the end. 
// 2009/05/07 V0.3: Fixed bug. Script was not setting BBID. 
// 2009/06/05 V0.4: Fix Hspot message at end of script (SPR-1481).
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SpecOffsetAuto SPIRE 14015 {
    bool dcuData = false; // Is (==tick) the DCU currently sampled? 
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SpecOffsetAuto started");
    SpireMsg(2,"          $Id:$");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    sync();
    // //
    // //
    // Take offset:
    //
    SpireProc_Set_SpecOffsetAuto(dcuData,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SpecOffsetAuto ended");
    SpireMsg(1,"  ..SpecOffsetAuto End (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartFovMapFpgScan.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpirePhoto/Spectro_CalGCO_FovMapFpgScan.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V0.1: Initial version adapted from
//                  SpireBb_StartBsmAngleCal (2009/05/05 V0.1),
//                  SpirePhoto_CalGCO_FovMapFpgScan (2009/03/04 V1.2), and
//                  SpireSpectro_CalGCO_FovMapFpgScan (2009/03/04 V0.4)
//                  BB includes now to move BSM/SMEC to hold/home.  
// 2009/07/10 V1.0: Fix bug SPR-SPIRE-1612
// 
// Notes:
//    1) Scripts assumes that SpireBb_SpecOffsetAuto is run 
//       during INITHOLD or at first POINTING.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartFovMapFpgScan SPIRE 14066 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    string obsModeQla = "ENG_CAL_OBS04";
    string obsMode = "PEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_Phot/SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    int smecHomePosn = 3500; // SMEC home position
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartFovMapFpgScan configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // In case move SMEC to home:
    // 
    if(!phot) {
        //
        // Calculate available time for possible movement:
        //
        int tmove = duration(SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug)) + duration(SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug)) + duration(SpireProc_Set_ObsStep(999,debug)) + duration(SpireBb_SpecOffsetAuto(false,debug));
        //
        // Calculate max offset for which time is available:
        //
        int smecMaxOff = tmove * 500;
        // Note, 500 is maximum possible SMEC speed.
        int smecStart = smecHomePosn + smecMaxOff;
        // Note, formula above only reasonable 
        // when smecHomePosn small compared to 39500  
        // Safety check: 
        if(smecStart > 39500) {
            smecStart = 39500;
        }
        if(debug) {
            debug_print("smecStart: " + smecStart);
            debug_print("smecHomePosn: " + smecHomePosn);
            debug_print("tmove: " + tmove);
        }
        // 
        // Move from maximal offset to home:
        //
        SpireProc_SmecMove2Home(smecHomePosn,smecHomePosn + smecMaxOff,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    if(phot) {
        SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    }
    //delay(timeSlewCal);
    // //
    // //
    // Set Obs step at to fff:
    //
    int obsStep = 4095;
    SpireProc_Set_ObsStep(obsStep,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartFovMapFpgScan configuration ended");
    SpireMsg(1,"  ..StartFovMapFpgScan took " + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Set_PhotMode
//
///////////////////////////////////////////////////////////
//
// Procedure to configure some important instrument parameters
// for the photometer depending on the mode. The procedure returns
// the DCU, BSM, DPU, and SCU data rate.
//
///////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/15 V0.1: Initial version adapted from
//                  SpireProc_Set_PhotPhase (2009/02/14 V0.2)
// 2009/07/10 V1.0: Temporary fix for SPR-SPIRE-1613 (hardcode command)
//
///////////////////////////////////////////////////////////////////////////
//
double[] procedure SpireProc_Set_PhotMode {
    string obsMode = "PHOTSTBY"; // Obs mode as defined in calibration files
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string tarCol = "";
    string selCol = "mode";
    string tabName = "";
    string version = "";
    string selVal = "";
    string tstr = "";
    //
    // Photometer or FTS?:
    bool phot = true;
    bool fts = !phot;
    //
    // Hardcoded name of calibration tables:
    // 
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"     " + tstr + ":  SpireProc_Set_PhotMode started");
    SpireMsg(4,"          $Id:$");
    // //
    // //
    // In case select isBright:
    // 
    if(obsMode != "PHOTSTBY" && obsMode != "PHTSTBY") {
        if(isBright) {
            selVal = obsMode + "_b";
        } else {
            selVal = obsMode;
        }
    } else {
        selVal = obsMode;
    }
    // //
    // //
    // Read parameters from calibration tables:
    //
    // Table SpireTable_PhotModeParams:
    //
    tabName = tabName01;
    version = version01;
    //
    tarCol = "mclkDiv";
    int mclkDiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "biasDiv";
    int biasDiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "pswBias";
    int psw_bias = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "pmwBias";
    int pmw_bias = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "plwBias";
    int plw_bias = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "ptcBias";
    int ptc_bias = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "pswPhase";
    int psw_phase = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "pmwPhase";
    int pmw_phase = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "plwPhase";
    int plw_phase = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "ptcPhase";
    int ptc_phase = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "dcuDataRate";
    double dcuDataRate = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Table SpireTable_CommonModeParams:
    //
    tabName = tabName02;
    version = version02;
    //
    tarCol = "dcuDataMode";
    int dcuDataMode = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "bsmFrameRate";
    int bsmFrameRate = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "bsmDataRate";
    //
    double bsmDataRate = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "dpuDataRate";
    double dpuDataRate = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "scuFrameRate";
    int scuFrameRate = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "scuDataRate";
    double scuDataRate = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Debug printing of all fetched parameters:
    //
    if(debug) {
        debug_print("     mclkDiv: " + mclkDiv);
        debug_print("     biasDiv: " + biasDiv);
        debug_print("    psw_bias: " + psw_bias);
        debug_print("    pmw_bias: " + pmw_bias);
        debug_print("    plw_bias: " + plw_bias);
        debug_print("    ptc_bias: " + ptc_bias);
        debug_print("   psw_phase: " + psw_phase);
        debug_print("   pmw_phase: " + pmw_phase);
        debug_print("   plw_phase: " + plw_phase);
        debug_print("   ptc_phase: " + ptc_phase);
        debug_print(" dcuDataRate: " + dcuDataRate);
        debug_print(" dcuDataMode: " + dcuDataMode);
        debug_print("bsmFrameRate: " + bsmFrameRate);
        debug_print(" bsmDataRate: " + bsmDataRate);
        debug_print(" dpuDataRate: " + dpuDataRate);
        debug_print("scuFrameRate: " + scuFrameRate);
        debug_print(" scuDataRate: " + scuDataRate);
    }
    // //
    // //
    // Set the DCU bias frequency, sampling rate, and data mode:
    //
    // Safety checks:
    //
    if(mclkDiv == -1) {
        error("mclkDiv is not defined for this mode. Think again or call help!");
    }
    if(biasDiv == -1) {
        error("biasDiv is not defined for this mode. Think again or call help!");
    }
    if(dcuDataMode == -1) {
        error("dcuDataMode is not defined for this mode. Think again or call help!");
    }
    //
    SpireProc_Set_DcuFreqSampMode(mclkDiv,biasDiv,dcuDataMode,phot,debug);
    // //
    // //
    // Set the phases of the photometer array:
    //
    // Safety checks:
    //
    if(psw_phase == -1) {
        error("psw_phase is not defined for this mode. Think again or call help!");
    }
    if(pmw_phase == -1) {
        error("pmw_phase is not defined for this mode. Think again or call help!");
    }
    if(plw_phase == -1) {
        error("plw_phase is not defined for this mode. Think again or call help!");
    }
    if(ptc_phase == -1) {
        error("ptc_phase is not defined for this mode. Think again or call help!");
    }
    //
    SpireProc_Set_PhotPhase(psw_phase,pmw_phase,plw_phase,ptc_phase,debug);
    // //
    // //
    // Set the bias amplitud of the photometer array:
    //
    // Safety checks:
    //
    if(psw_bias == -1) {
        error("psw_bias is not defined for this mode. Think again or call help!");
    }
    if(pmw_bias == -1) {
        error("pmw_bias is not defined for this mode. Think again or call help!");
    }
    if(plw_bias == -1) {
        error("plw_bias is not defined for this mode. Think again or call help!");
    }
    if(ptc_bias == -1) {
        error("ptc_bias is not defined for this mode. Think again or call help!");
    }
    //
    SpireProc_Set_PhotBias(psw_bias,pmw_bias,plw_bias,ptc_bias,debug);
    // //
    // //
    // Set the BSM framerate:
    //
    // Safety checks:
    //
    if(bsmFrameRate == -1) {
        error("bsmFrameRate is not defined for this mode. Think again or call help!");
    }
    //
    SpireProc_Set_BsmFramerate(bsmFrameRate,debug);
    // //
    // //
    // Set the SCU framerate
    //
    // Safety checks:
    //
    if(scuFrameRate == -1) {
        error("scuFrameRate is not defined for this mode. Think again or call help!");
    }
    //
    SpireProc_Set_ScuFramerate(scuFrameRate,debug);
    // //
    // //
    // Temporary fix for SPR-SPIRE-1613 (hardcode command):
    //
    // Set sampling to continuous
    SpireSendDrcuCmd(0x843d0000,0);
    sync();
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"      " + tstr + ": SpireProc_Set_PhotMode ended");
    // //
    // //
    // Return data rates:
    //

    return [dcuDataRate,bsmDataRate,dpuDataRate,scuDataRate];
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_Cal_PcalLoadCurve.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  CUS script for: 'Phot PCAL Load Curve'  
//
//  in *basic_fine_pointing* or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/06/09 V0.1: Initial version adapted from 
//                  Mode_ILT_PERF_DAB_P_CPS.txt (v 1.3 2008/01/31 23:35:17)
// 2008/06/20 V0.2: Move SpireBb_StartupObs to start
// 2008/07/03 V0.3: Renumber version; SpireProc_Set_PhotNominalbias changed
//                  name; SpireBb_PhotFSetupData has extra parameter; 
//                  use also PTC as input
// 2008/07/21 V0.4: Allow nafid as input parameter
// 2008/08/15 V0.5: Remove test number; use modified script to do
//                  LC with PCAL flash (SpireProc_Exec_PhotPcalLoadCurve);
//                  Change name of default input table with bias levels;
//                  Adapt to change in call to low level script 
//                  SpireProc_CalcParam_BiasFreqSampFreq.txt 
// 2008/11/11 V0.6: Allow 'no pointing' as input option; Adapt debug printing
// 2008/11/12 V0.7: Implement mode setting; Add isBright 
//                  Change 'no pointing' implementation
// 2009/02/02 V1.0: Add debug_print as input and pass it to some low 
//                  level scripts. Add setting of NHK STEP parameter
//                  in SpireProc_Exec_PhotPcalLoadCurve. Set first STEP
//                  already during SLEW and unset at end during INIT_HOLD.   
//                  Use new SpireBb_EndObsAll and SpireBb_StartObsAll. 
//                  Read nominal bias frequency and bias divider from new
//                  SpireTable_DetectorSettings.txt. Implemented setting 
//                  of datarates. Replace SpireProc_Set_PhotNominal by
//                  SpireProc_Set_FreqSampAmpPhasNominal. Implemented message 
//                  if activating isBright setting.
// 2009/02/16 V1.1: Replace call to SpireTable_DetectorSettings bu call to
//                  SpireTable_PhotModeParams. Remove cal. tables from input
//                  and hardcode them. Read boresight from SpireTable_OpsParms.
//                  Use SpireProc_Set_PhotMode to set instrument to PHTSTBY
//                  during SLEW. Replace call to SpireBb_PhotFSetupData with
//                  call to SpireBb_PhotFSetPhase, SpireBb_PhotFSetBiasAmpl
//                  and SpireBb_DcuSetFreqSamp to set user requested inputs
//                  plus first bias level during SLEW. Use new setting of 
//                  datarates. Unset isBright if set. Use SpireBb_PhotSetMode 
//                  to set back to PHOTSTBY at end.
// 2009/02/18 V1.2: Adapt to change in call to SpireProc_Exec_PhotPcalLoadCurve
// 2009/02/19 V1.3: Elevate version05 to input.
// 2009/03/04 V1.4: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Replace 'message' by
//                  'error' if isBright is selected.
// 2009/05/07 V1.5: Add in move BSM to hold at start. Gather procedures at 
//                  start and end in separate BB. 
// 2009/06/05 V1.6: Hardcode STBY 'v00' in EndBB (SPR-1477)
//
///////////////////////////////////////////////////////////////////////////
//
//  Script assumes that:
//
//  1)  Instrument is in PHOTSTBY at beginning 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Phase is kept constant (from input) during this test, i.e no 
//     adjustment of the phase with changing bias amplitude and frequency
//
//  3) Bias frequency, sampling rate, and phase are input parameters
//
//  4) Boresight of array can be read from following cal table using
//     the mode 'PEngCalObs': SpireTable_OpsParms.txt   
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhoto_Cal_PcalLoadCurve {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; // NAIF identifier
    bool isBright = false; // Use settings for bright source (==tick)
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    double biasfreq = 130.2 in [70.0,200.0]; // Bias frequency [Hz]
    double samplerate = 18.6 in [1.0,20.0]; // Sampling rate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    double phasedeg_psw = 180.7 in [0.0,360.0]; // PSW Bias phase [deg]
    double phasedeg_pmw = 180.7 in [0.0,360.0]; // PMW Bias phase [deg]
    double phasedeg_plw = 180.7 in [0.0,360.0]; // PLW Bias phase [deg]
    double phasedeg_ptc = 180.7 in [0.0,360.0]; // PTC Bias phase [deg]
    int ftime = 10; // Readout time at each bias level [s]
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_PcalLoadCurveLevels
    string version05 = "v00"; // Version in cal table SpireTable_OpsParms.txt
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // //
    // //
    // Check for is bright setting: 
    //
    if(isBright) {
        isBright = false;
        error("IsBright does not make sense here. Try again (e.g. subtract the phase shift manually from the input)!");
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = true;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_PcalLoadCurveLevels.txt";
    string tabName04 = "SpireTable_CommandLists.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    string tabName06 = "SpireTable_BsmNominalSettings.txt";
    //
    // Currently hardcoded version and model parameter:
    //
    string version06 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    //
    // Dummy value for Spec script:
    // (needed but not used in phot script!)
    //
    int smecHomePosn = 3500;
    // SMEC home position
    int ssw_bias = 45;
    //
    int slw_bias = 45;
    //
    int ssw_phase = 128;
    //
    int slw_phase = 128;
    // 
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS10";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "PEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Retrieve bias levels used for the load curve:
    // 
    tabName = tabName03;
    version = version03;
    int[] nbiaslist = SpireProc_CalcParam_LoadCurve(tabName,version,debug);
    //
    // Lookup first bias level:    
    int psw_bias = nbiaslist[0];
    int pmw_bias = nbiaslist[0];
    int plw_bias = nbiaslist[0];
    int ptc_bias = nbiaslist[0];
    // //
    // //
    // Convert user input to Hex values:
    //
    // for bias frequency and sample rate: 
    //
    int[] hexvalues = SpireProc_CalcParam_BiasFreqSampFreq(biasfreq,samplerate,fts,debug);
    int mclkdiv = hexvalues[0];
    int biasdiv = hexvalues[1];
    if(debug) {
        debug_print("Hex values of mclkdiv/biasdiv are: " + mclkdiv + " " + biasdiv);
    }
    //
    // for bias phase:
    //
    int[] phasehex = SpireProc_CalcParam_PhotPhaseConvert(phasedeg_psw,phasedeg_pmw,phasedeg_plw,phasedeg_ptc,debug);
    int psw_phase = phasehex[0];
    int pmw_phase = phasehex[1];
    int plw_phase = phasehex[2];
    int ptc_phase = phasehex[3];
    // //
    // //
    // Read VM parameters from calibration table:
    //
    tabName = tabName04;
    selVal = "Flash";
    int vmId = ilookup(tabName,selVal,"Id");
    int vmIndex = ilookup(tabName,selVal,"Index");
    int nParms = ilookup(tabName,selVal,"Nparms");
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version06;
    tabName = tabName06;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    //
    // BBs called during slew:
    //
    int tslewmin = duration(SpireBb_StartPcalLoadCurve(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,psw_phase,pmw_phase,plw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug));
    // 
    // BBs carried out when the pointing is reached:
    //
    if(pointing) {
        int tinithold = 0;
    } else {
        tinithold = tslewmin;
    }
    //
    // BB carried out during pointing:
    //
    int tp = duration(SpireProc_Exec_PhotPcalLoadCurve(nbiaslist,ftime,mclkdiv,biasdiv,vmId,vmIndex,nParms,debug));
    //
    // BB carried out at the end:
    //
    int tfinalhold = duration(SpireBb_EndPcalLoadCurve(phot,isBright,version01,version02,debug));
    // //
    // //
    // Debug printing:
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartPcalLoadCurve(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,psw_phase,pmw_phase,plw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug);
            //            
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            //
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation:
                //
                SpireBb_StartPcalLoadCurve(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,psw_phase,pmw_phase,plw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug);
                //
            }
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            // //
            // //
            // Execute load curve with PCAL flashes:
            //
            SpireProc_Exec_PhotPcalLoadCurve(nbiaslist,ftime,mclkdiv,biasdiv,vmId,vmIndex,nParms,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            //
            SpireBb_EndPcalLoadCurve(phot,isBright,version01,version02,debug);
            //
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

// SpireBbPhotSerendipity
//
// $Id:$
//
// Building Block to take serendipity data for a specified period of time
//
// If the time specified is less than the minimum then this BB takes the minimum time anyway
//
// Note: this BB assumes that the detector bias and sampling frequency and 
//       the BSM sampling frequency have been set appropriately  
//
//  20/04/07: v1.3: removed check on opsMode value
//
// 04 November 2008: 
//            changed to accept observing mode
//            changed to provide operations mode rather than data mode as a parameter to StartDcuData
// 15/09/2009 KJK:
//            SPR Spire-1924: pass opsMode through to SpireConfigDcuData
// 21/09/2009 KJK:
//            SPR Spire-1993: updated to read SpireTable_SpireParams.txt instead of SpireParms.txt
//
block SpireBbPhotSerendipity SPIRE 8452 {
    string opsMode = "";
    int len = 0 in [0,10000]; // scan length in seconds - maximum determined by max time between Tsync
}{
    string spireVersion = "v00";
    bool debug = false;

    message("2    " + time() + ": BB Phot Serendipity started");
    message("2          $Id:");
    message("3          length = " + len);
    int t = time();
    //
    // find actual length of BB
    int tSerendipity = SpireProc_GetTableEntryInt("SpireTable_SpireParams.txt","mode",opsMode,"TSerendipity",spireVersion,debug);
    // minimum time for Serendipity observation
    if(len < tSerendipity) {
        len = tSerendipity;
    }
    //
    // ..... configuration .....
    //
    // set BBID
    message("5          " + time() + "Cmd: Spire_SET_BBID_RAW(" + $BBID + ")");
    Spire_SET_BBID_RAW($BBID);
    // set value
    delay(2);
    // allow HSK to reflect new value
    //
    // ..... initialisation .....
    //
    //
    // ..... execution ..... 
    //
    // start sampling detectors
    SpireStartDcuData(opsMode);
    //
    // wait to end of time
    int tStop = duration(SpireStopDcuData());
    wait_until(t + len - tStop - 2);
    //
    // stop detector sampling
    SpireStopDcuData();
    //
    // ..... completion .....
    //
    //
    wait_until(t + len);
    message("2    " + time() + ": BB Phot Serendipity ended");
    message("0  Serendipity Mode (" + (time() - t) + " seconds)");
    //
}

// SpirePacsBbParallelEnd
//
// $Id$
//
// Building Block to reconfigure the instrument to PHOT_STBY mode from POF5 (scan map) mode
//
//  25-Aug-2009 KJK:
//                     - Added input parameters to enable selection of versions in Cal Tables
//                     - BSM HOLD position is read from new Cal Table (SpireTable_BsmNominalSettings.txt)
//                     - added code to deal with bright source settings
//  15/09/2009 KJK: added  reconfiguration of  DCU 
//
block SpirePacsBbParallelEnd SPIRE 8338 {
    string obsMode = "PHTSTBY";
    bool isBright = false in [true,false];
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string photVersion = "v00";
    string comVersion = "v00";
    bool debug = false in [true,false];
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Parallel Reconfiguration started");
    SpireMsg(2,"          $Id$");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP to zero
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x0000)");
    Spire_SET_OBS_STEP_RAW(0x0);
    //
    // Move BSM to HOLD
    int bsmHoldChopPosn = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",bsmModel,"chop_0_I",bsmVersion,debug);
    int bsmHoldJiggPosn = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",bsmModel,"jigg_0_I",bsmVersion,debug);
    SpireBsmMove(bsmHoldChopPosn,bsmHoldJiggPosn);
    //
    //
    // reset bright-source biases and phases - if needed
    //
    if(isBright) {
        SpireProc_Set_PhotMode(obsMode,isBright,"v00","v00",debug);
    } else {
        if(photVersion != "v00") {
            SpireProc_Set_PhotMode(obsMode,isBright,"v00","v00",debug);
        }
    }
    SpireConfigDcuData("PHTSTBY");
    //
    // Set Mode to PHT_STBY
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_MODE_RAW(0x0300)");
    Spire_SET_OBS_MODE_RAW(0x300);
    // 
    // Clear OBSID/BBID to null values
    tstr = SpireTimeStr(time());
    message("5          " + tstr + "Cmd: Spire_SET_BBID_RAW(0x80000000)");
    Spire_SET_BBID_RAW(0x80000000);
    int obsId = SpireNullObsid();
    tstr = SpireTimeStr(time());
    hstr = SpireHexStr(obsId,8);
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBSID_RAW(" + hstr + ")");
    Spire_SET_OBSID_RAW(obsId);
    // 
    // ..... completion .....
    //
    sync();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Parallel Reconfiguration ended");
    SpireMsg(1,"  ..Parallel Reconfiguration to PHT_STBY mode (" + (time() - t) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_PtcHtrCurr.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set PTC heater current.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/30 V0.1: Initial version adapted from
//                  PTCHTR_CURR.txt (SDS, email 30.03.2009)
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_PtcHtrCurr SPIRE 14033 {
    int ptc_curr = 0x0; // PTC heater current (Raw)
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string hstr = "";
    // a hex string
    string tstr = "";
    // a time string
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": SpireBb_PtcHtrCurr started");
    SpireMsg(2,"          $Id: $");
    hstr = SpireHexStr($BBID,8);
    SpireMsg(3,"          BBID = " + hstr);
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    sync();
    // //
    // //
    // Set PTC current:
    //
    SpireSendDrcuCmd(0xa0c60000 + ptc_curr,0);
    // //
    // //
    // Reset DRCU counter:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RESET_DRCU_COUNTERS(" + hstr + ")");
    Spire_RESET_DRCU_COUNTERS();
    sync();
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_PtcHtrCurr ended");
    SpireMsg(1,"  ..Set Phot phases (" + (time() - t) + " secs)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_ResetBsm.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to reset BSM parameters after tuning test
//
///////////////////////////////////////////////////////////////////////////
//
// S.D.Sidher:
// 2009/11/15 V0.1: Initial version (reset BSM frame parameters 3 and 6 back to their default values) 
// 
// 2010/03/04 V0.2: Now also resetting CHOPINTLIMIT and CHOPINTREF
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_ResetBsm SPIRE 3406 {
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // Define some variables:
    //
    string hstr = "";
    // a hex string
    string tstr = "";
    // a time string
    //
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": SpireBb_ResetBsm started");
    SpireMsg(2,"          $Id: $");
    hstr = SpireHexStr($BBID,8);
    SpireMsg(3,"          BBID = " + hstr);
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Reset BSM frame parameters back to default value:
    //
    // sample CHOPMOTORVOLT
    SpireSendDrcuCmd(0x91cd0106,0);
    // sample JIGGMOTORVOLT
    SpireSendDrcuCmd(0x91d00186,0);
    // //
    delay(1);
    //
    // Reset Chop integration limit and threshold to default values(CHOPINTLIMIT and CHOPINTREF):
    SpireSendDrcuCmd(0x90ccffff,0);
    SpireSendDrcuCmd(0x90cbffff,0);
    //
    // //
    // //
    // End BB:
    //
    sync();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_ResetBsm ended");
    SpireMsg(1,"  Reset BSM parameters (" + (time() - t) + " secs)");
    //
}

// SpireEngCoolerRecycle
//
// $id$
//
// This observation executes the cooler recycle procedure
// 
// The instrument should be in  the REDY mode before execution of this observation
//
// 03/11/2007 KJK updated to add SpireBbStartOBS and SpireBbEndObs at start and end of the observation
//
// 17/11/2008 KJK updated to include CCU monitoring command (SCR 5446)
//                           this includes bringing the StartOBs and EndObs BBs to the Initail and final hold parst of the observation
// 
obs SpireEngCoolerRecycle {
}{
    int tih = duration(SpireBbStartObs()) + duration(SpireBbCcuMonitorPeriodRecycle());
    int tfh = duration(SpireBbEndObs()) + duration(SpireBbCcuMonitorPeriodDefault());
    int tp = duration(SpireCoolerRecycle());
    int[] ts = no_pointing(true,tih,tfh,tp);
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // ***********************  INITIAL HOLD          
            // set OBSID
            SpireBbStartObs();
            SpireBbCcuMonitorPeriodRecycle();
        }
        if(state[0] == 3) {
            // ***********************  EXECUTE
            SpireCoolerRecycle();
        }
        if(state[0] == 5) {
            // ***********************  FINAL HOLD
            SpireBbCcuMonitorPeriodDefault();
            SpireBbEndObs();
        }
    }
}

// SpireBbBsmOff
//
// $id$
//
// This building block switches off the BSM
// 
//  29/05/2009: KJK
//      Now exits with mode set to REDY (as expected from the IUM)
//
block SpireBbBsmOff SPIRE 267 {
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB BSM Off started");
    SpireMsg(2,"          $Id: SpireBbBsmOff.txt,v 1.1 2007/08/02 10:15:44 kking Exp $");
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    delay(1);
    //
    // set Step to zero
    SpireSetObsStep(0);
    //
    // Flag the current operation
    SpireSetObsMode("REDY");
    delay(1);
    // 
    // Send BSM to chop target position 0
    SpireSendDrcuCmd(0x90c38000,0);
    // Send BSM to jiggle target position 0
    SpireSendDrcuCmd(0x91438000,0);
    // Force Open loop in both axis
    SpireSendDrcuCmd(0x90c20003,0);
    SpireSendDrcuCmd(0x91420003,0);
    // Power off chop axis
    SpireSendDrcuCmd(0x90c00000,0);
    // Power off jiggle axis
    SpireSendDrcuCmd(0x91400000,0);
    delay(1);
    //
    // completion
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB BSM Off   ended");
    SpireMsg(1,"  ..BSM Off (" + (time() - t0) + " seconds)");
}

// Missionphase  : PACS FM Test
//
// Purpose       : Switch on of bolometer groups
//
// Author        : T. Mueller
//
// File          : PHOT_switchon_groups
// Arguments     : none
//                 
//
// Description   : This script will switch on the different groups
//                 of the instrument. BOLC will start in "HK only" mode.
//                              
// Comments      :  Coded based on PhFPU UM, Draft 5
//
// Version       : 1.1
// History       : 1.0 / 08-Nov-2006 initial version by TM
//                    1.1 / 08-Nov-2006 TM: autonomy function 17 added
//                    1.1.1 14-nov-2006 Disable autonomy function for time being
//                    1.2 17-nov-2006 Enable AF with delay after switchon
//                    1.3 09-apr-2007 disable AFs before starting
// 
procedure PHOT_switchon_groups {
}{
    // disable AF 12, AF 15, AF 17
    // disable AF 12 (to check for the protection biases)
    Pacs_DPU_SET_FUNCT("EVENT_BOL_BIAS","DISABLE");
    // disable AF 15 (to check for the VSS currents of groups and BUs)
    Pacs_DPU_SET_FUNCT("EVENT_BOL_I_RO","DISABLE");
    // disable AF 17 (to check for group power)
    Pacs_DPU_SET_FUNCT("EVENT_BOL_V_PWR","DISABLE");
    //
    delay(2);
    // PC103420 "DMC_SEND_COMMAND_BOLC" SEND COMMAND TO BOL CONTROLLER
    //         PP071420 "BOLOMETER_COMMAND"
    //
    // # Execute BOLC initialisation
    // # for CQM we switched on everything at once, now group by
    // # group starting with 1
    // 
    // # Switch-on group 1 The corresponding bits
    // # are (2^0)=1, which is 1 in hex.
    // tcsend PC103420 {PP071420 0x0A000001 LO}
    // waittime 1.0
    int operand = 0xa000001;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    delay(1);
    // # Switch-on groups 1,2. The corresponding bits
    // # are (2^0+2^1)=3, which is 3 in hex.
    // tcsend PC103420 {PP071420 0x0A000003 LO}
    // waittime 1.0
    operand = 0xa000003;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    delay(1);
    // # Switch-on groups 1,2,3. The corresponding bits
    // # are (2^0+2^2+2^3)=7, which is 7 in hex.
    // tcsend PC103420 {PP071420 0x0A000007 LO}
    // waittime 1.0
    operand = 0xa000007;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    delay(1);
    // # Switch-on groups 1,2,3,4. The corresponding bits
    // # are (2^0+2^1+2^2+2^3)=15, which is F in hex.
    // tcsend PC103420 {PP071420 0x0A00000F LO}
    // waittime 1.0
    operand = 0xa00000f;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    delay(1);
    // # Switch-on groups 1,2,3,4,5. The corresponding bits
    // # are (2^0+2^1+2^2+2^3+2^4)=31, which is 1F in hex.
    // tcsend PC103420 {PP071420 0x0A00001F LO}
    // waittime 1.0
    operand = 0xa00001f;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    delay(1);
    // # Switch-on groups 1,2,3,4,5,6. The corresponding bits
    // # are (2^0+2^1+2^2+2^3+2^4+2^5)=63, which is 3F in hex.
    // tcsend PC103420 {PP071420 0x0A00003F LO}
    // waittime 1.0
    operand = 0xa00003f;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    delay(8);
    //------------------------------------
    // autonomy function
    //------------------------------------
    // autonomy function 17 "generate_event_pwr" checks the
    // HK entries: PC_PWR_ANA_P_#, PC_PWR_ANA_N_# and PC_PWR_DIG_#,
    // with # = [1,2,3,4,5,6,7]
    Pacs_DPU_SET_FUNCT("EVENT_BOL_V_PWR","ENABLE");
    // Wait another 2 sec
    delay(2);
    //
    //-----------------
    // End of Procedure
    //-----------------
}

// SpireEngPMDump
//
// $id$
//
// This observation dumps the DPU Program Memory
//
// The instrument should normally be in REDY mode before execution
// of this observation.
//
//
// 23/04/2010 SDS: First Version 1.0 
//
///////////////////////////////////////////////////////////////////////////
obs SpireEngPMDump {
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use)
    int pInt2 = 0; // Spare parameter (currently not in use)
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int t = duration(SpireBbStartObs()) + duration(SpireBbEndObs());
    t = t + duration(SpireBb_PMDump());
    //
    // ***********************************************
    int[] ts = no_pointing(true,0,0,t);
}{
    SpireMsg(0,"Observation Start");
    SpireMsg(3,"       $Id:$");
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            SpireBbStartObs();
            // Perform a PM Dump 
            SpireBb_PMDump();
            // 
            SpireBbEndObs();
        }
    }
    SpireMsg(0,"Observation Completed  (" + time() + " seconds)");
    SpireMsg(0,"Note: Total time (s) = Observation Completed time - slew time + Observatory Overheads");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_SpecPhaseConvert.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to translate user input in deg for bias phase 
//  into nearest Hex values for ssw_phase, pmw_phase, slw_phase, and ptc_phase  
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/12 V0.1: Initial version adapted from
//                  SpireProc_CalcParam_PhotPhaseConvert (2008/07/03 V0.2)
// 2009/02/19 V0.2: Add debug_print as input and implement.
//
///////////////////////////////////////////////////////////////////////////
int[] procedure SpireProc_CalcParam_SpecPhaseConvert {
    double input_phase_ssw = 0.0 in [0.0,360.0]; // Input SSW Bias Phase [0.0 - 360.0] [deg]
    double input_phase_slw = 0.0 in [0.0,360.0]; // Input SLW Bias Phase [0.0 - 360.0] [deg]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Convert from deg to nearest RAW values:
    //
    double conversion_factor = 255.0 / 360.0;
    //
    int raw_phase_ssw = iround(conversion_factor * input_phase_ssw);
    int raw_phase_slw = iround(conversion_factor * input_phase_slw);
    //
    // //
    // //
    // Convert nearest RAW values back to deg:
    //
    double phase_ssw = double(raw_phase_ssw) / conversion_factor;
    double phase_slw = double(raw_phase_slw) / conversion_factor;
    // //
    // //
    // Printout:
    //
    if(debug) {
        debug_print("Input deg value for SSW/SLW phase amplitude: " + input_phase_ssw + "/" + input_phase_slw);
        debug_print("Output Hex values for SSW/SLW: " + raw_phase_ssw + "/" + raw_phase_slw);
        debug_print("Commanded deg values for SSW/SLW: " + phase_ssw + "/" + phase_slw);
    }
    // //
    // //
    // Return required values:
    //

    return [raw_phase_ssw,raw_phase_slw];
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SpecFTakeData.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to start taking data with spectrometer arrays
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/11 V0.1: Initial version adapted from
//                  SpireBb_PhotFTakeData.txt (2008/07/04 V0.2)
//                  SF_Data_QLA (v1.4 2008/01/31 20:24:37)
// 2009/02/19 V0.2: Add debug_print option. Replace delay(1) with delay(2)
//                  after FLUSH_FIFO. Remove unsetting of BBID. Add Hspot
//                  messages. 
//
//  Note: - BB assumes no DCU data is taken when started!
//        - BB still includes nonessential setting of data mode (0x843c0004)
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SpecFTakeData SPIRE 14014 {
    int ftime = 0x0; //Time for data generation (if frames are continuous)
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Define some variables:
    //
    string hstr = "";
    // a hex string
    string tstr = "";
    // a time string
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": SpireBb_SpecFTakeData started");
    SpireMsg(2,"          $Id: $");
    hstr = SpireHexStr($BBID,8);
    SpireMsg(3,"          BBID = " + hstr);
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    //sync();
    // //
    // //
    // Reset DCU (x1000) fifo:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RESET_FIFOS(0x1000)");
    Spire_RESET_FIFOS(0x1000);
    delay(1);
    // //
    // //
    // Set data mode to 'spectrometer full array':
    //
    SpireSendDrcuCmd(0x843c0004,0);
    //delay(1);
    // //
    // //
    // Start data collection:
    //
    SpireSendDrcuCmd(0x843e0001,0);
    // //
    // //
    // Wait for data to be taken:
    //
    delay(ftime);
    // //
    // //
    // Stop data collection:
    //
    SpireSendDrcuCmd(0x843e0000,0);
    //delay(1);
    // //
    // //
    // Flush DCU fifo:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO(0x1000)");
    Spire_FLUSH_FIFO(0x1000);
    delay(2);
    //
}

// SpireBbSmecOn
//
// $id$
//
// This building block switches on the SMEC
// 
// The instrument should be in  the REDY mode before execution of this building block
//
// 29/04/2009 KJK: First Version
// 18/07/2009  MP: Added change made by Sunil on 16th to header 
//                 (see SPR-SPIRE-1638)
// 14/10/2009 SDS/TWG: Removed the setting of Sig1 and Sig2 offsets
//                     Added the setting of FF offset and SMEC derivative filter, rate limit and integration limit
//                     (These settings will be removed from SMEC_INIT)
//                     Replaced Sig1 offset in MCU Eng frame with Sig2 Amplitude
//
block SpireBbSmecOn SPIRE 530 {
    string version = "v00";
    bool debug = false;
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SMEC On started");
    SpireMsg(2,"          $Id$");
    //
    // intialise variables
    int encPwr = ilookup("SpireTable_SmecNominalSettings.txt",version,"encPwr");
    int lvdtScale = ilookup("SpireTable_SmecNominalSettings.txt",version,"lvdtScale");
    int lvdtOff = ilookup("SpireTable_SmecNominalSettings.txt",version,"lvdtOff");
    int ffGain = ilookup("SpireTable_SmecNominalSettings.txt",version,"ffGain");
    int ffOff = ilookup("SpireTable_SmecNominalSettings.txt",version,"ffOff");
    int drvFlt = ilookup("SpireTable_SmecNominalSettings.txt",version,"drvFlt");
    int rteLim = ilookup("SpireTable_SmecNominalSettings.txt",version,"rteLim");
    int intLim = ilookup("SpireTable_SmecNominalSettings.txt",version,"intLim");
    // 
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    delay(1);
    //
    // set Step to zero
    SpireSetObsStep(0);
    //
    // Flag the current operation
    SpireSetObsMode("SMEC_ON");
    delay(1);
    //
    // switch on optical encoder
    SpireSendDrcuCmd(0x90400000 + encPwr,0);
    delay(1);
    //
    // Switch on LVDT		
    SpireSendDrcuCmd(0x90410001,0);
    SpireSendDrcuCmd(0x905f0000 + lvdtScale,0);
    delay(1);
    SpireSendDrcuCmd(0x905e0000 + lvdtOff,0);
    // 
    // Set Feed Forward Gain
    SpireSendDrcuCmd(0x90540000 + ffGain,0);
    delay(1);
    //
    // Set the FF offset to put the SMEC at mechanical stop
    SpireSendDrcuCmd(0x90550000 + ffOff,0);
    delay(15);
    // Set slew rate limiter
    SpireSendDrcuCmd(0x90510000 + rteLim,0);
    // Set integration limit
    SpireSendDrcuCmd(0x904e0000 + intLim,0);
    delay(1);
    // Set derivative filter
    SpireSendDrcuCmd(0x904c0000 + drvFlt,0);
    delay(1);
    //
    // Change contents of MCU engineering frames to contain only SMEC parameters
    // MCU Eng Par #4: SMEC encoder fine position
    SpireSendDrcuCmd(0x91d4006b,0);
    // MCU Eng Par #9: SMEC encoder sig2 amplitude
    SpireSendDrcuCmd(0x91d90059,0);
    delay(1);
    // MCU Eng Par #10: SMEC mean position error
    SpireSendDrcuCmd(0x91da006f,0);
    // MCU Eng Par #11: SMEC encoder sig1 amplitude
    SpireSendDrcuCmd(0x91db0057,0);
    delay(1);
    // MCU Eng Par #12: SMEC mean speed
    SpireSendDrcuCmd(0x91dc006e,0);
    // MCU Eng Par #13: SMEC DAC value
    SpireSendDrcuCmd(0x91dd0069,0);
    delay(1);
    // MCU Eng Par #14: SMEC LVDT position
    SpireSendDrcuCmd(0x91de0065,0);
    //
    // Set MCU Eng sampling to 125Hz and start data generation
    SpireSendDrcuCmd(0x91c40013,0);
    delay(1);
    SpireSendDrcuCmd(0x91c3ffff,0);
    delay(1);
    SpireSendDrcuCmd(0x91c10001,0);
    delay(1);
    //
    // completion
    sync();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB SMEC On   ended");
    SpireMsg(1,"  ..SMEC ON (" + (time() - t0) + " seconds)");
}



///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_SpecOffsetAuto.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set the detector offset for the spectrometer arrays
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/18 V0.1: Initial version adapted 
//                  SpireBb_SpecOffsetAuto (2008/08/11 V0.1)
//                  Add HSpot messages. Increase first delay after 
//                  data collection to 3s (from 2s) to be symmetric 
//                  to photometer script. Increase delay to 2 after 
//                  Spire_FLUSH_FIFO. Fix bug detected in FS2 with 
//                  setting the correct (spec==4) datamode at the end. 
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_SpecOffsetAuto {
    bool dcuData = false; // Is (==tick) the DCU currently sampled? 
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Define some variables:
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start procedure:
    //
    message("4    " + time() + ": SpireProc_Set_SpecOffsetAuto started");
    message("4          $Id: $");
    // //
    // //
    // In case stop data:
    //
    if(dcuData) {
        SpireSendDrcuCmd(0x843e0000,0);
    }
    // //
    // //
    // Reset DCU (x1000) fifo:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RESET_FIFOS(0x1000)");
    Spire_RESET_FIFOS(0x1000);
    sync();
    // //
    // //
    // Set data mode to 'Set automatic offset':
    //
    SpireSendDrcuCmd(0x843c0014,0);
    // //
    // //
    // Start data collection:
    //
    SpireSendDrcuCmd(0x843e0001,0);
    delay(3);
    // //
    // //
    // Stop data collection:
    //
    SpireSendDrcuCmd(0x843e0000,0);
    // //
    // //
    // Set data mode to 'Get offset data':
    //
    SpireSendDrcuCmd(0x843c001c,0);
    delay(1);
    // //
    // //
    // Start data collection:
    //
    SpireSendDrcuCmd(0x843e0001,0);
    delay(3);
    // //
    // //
    // Stop data collection:
    //
    SpireSendDrcuCmd(0x843e0000,0);
    // //
    // //
    // Flush DCU fifo:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO(0x1000)");
    Spire_FLUSH_FIFO(0x1000);
    delay(2);
    // //
    // //
    // Set data mode back to nominal (==spec):
    //
    SpireSendDrcuCmd(0x843c0004,0);
    // //
    // //
    // In case start data collection:
    //
    if(dcuData) {
        SpireSendDrcuCmd(0x843e0001,0);
    }
    sync();
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndIltPcalFlash.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of 
// SpirePhoto/Spectro_Cal_IltPcalFlash.txt
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/06 V1.0: Initial version adapted from
//                  SpireBb_EndBsmAngleCal (2009/05/05 V1.2),
//                  SpirePhoto_Cal_IltPcalFlash (2009/03/04 V1.4), and
//                  SpireSpectro_Cal_IltPcalFlash (2009/03/04 V0.5)
// 2009/05/07 V1.1: Set dcuFrameNumber and scuFrameNumber back to continuous
//                  to unset setting passed to VM. 
// 2009/06/05 V1.2: Replace Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd 
//                  as requested in SPR-1482.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndIltPcalFlash SPIRE 14047 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndIltPcalFlash reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set obsstep back to 0:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP(0)");
    Spire_SET_OBS_STEP(0);
    // //
    // //
    // Set instrument back to Phot/Spec-STBY:
    //
    if(phot) {
        SpireProc_Set_PhotMode("PHTSTBY",isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    }
    // //
    // //
    // Set number of DCU frames to continuous:
    //
    int dcuFrameNumber = 0;
    if(phot) {
        dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","PHTSTBY","dcuFrameNumber","v00",debug);
    } else {
        dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuFrameNumber","v00",debug);
    }
    //
    SpireSendDrcuCmd(0x843d0000 + dcuFrameNumber,0);
    // //
    // //
    // Set number of SCU frames to continuous:
    //
    int scuFrameNumber = 0;
    if(phot) {
        scuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","PHTSTBY","scuFrameNumber","v00",debug);
    } else {
        scuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","scuFrameNumber","v00",debug);
    }
    SpireSendDrcuCmd(0xa0840000 + scuFrameNumber,0);
    delay(1);
    // //
    // //
    // End observation:
    //
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndIltPcalFlash reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_RasterCross.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to calculate the pointing positions of an m x n raster
//  plus an interlaced cross  
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/10/13 V0.1: Initial version adapted from 
//                  SpireProc_CalcParam_FpgInitialPointing (2008/07/28 V0.2)
// 2008/11/03 V0.2: Allow to switch on/off interlaced cross
// 2009/03/30 V0.3: Add header line. Promote debug option to input.
// 2009/09/17 V0.4: Allow # of raster points to be input parameters. 
//
///////////////////////////////////////////////////////////////////////////
//
{double[],double[]} procedure SpireProc_CalcParam_RasterCross {
    int m = 5; // Number of points in raster along Y [odd number!]
    int n = 5; // Number of points in raster along Z [odd number!]
    double d1 = 4.0; // Angular stepsize along Y axis [arcsec] 
    double d2 = 4.0; // Angular stepsize along Z axis [arcsec]
    bool cross = true; // Add interlaced cross or use a simple 11x11 raster? 
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Declare some variables:
    //
    // //
    // //
    // Create m x n raster:
    //
    int npoints = m * n;
    double[] yarray = [0.0];
    double[] zarray = [0.0];
    double z = 0.0;
    double y = 0.0;
    int m2 = iround(double(m - 1) / 2.0);
    int n2 = iround(double(n - 1) / 2.0);
    int index = 0;
    bool odd = true;
    // 
    for(int row = 1 .. n) {
        z = double(-1 * n2 + (row - 1)) * d2;
        if(debug) {
            //debug_print("row: " + row);
            //debug_print("z: " + z);
        }
        for(int col = 1 .. m) {
            if(odd) {
                y = double(-1 * m2 + (col - 1)) * d1;
            } else {
                y = double(m2 - (col - 1)) * d1;
            }
            zarray[index] = z;
            yarray[index] = y;
            index = index + 1;
            if(debug) {
                //debug_print("col: " + col);
                //debug_print("y: " + y);
                //debug_print("z,y: " + z + "," + y);
            }
        }
        if(odd) {
            odd = false;
        } else {
            odd = true;
        }
    }
    // //
    // //
    // Add interlaced cross raster:
    //
    if(cross) {
        for(int yc = 1 .. m - 1) {
            z = 0.0;
            y = (double(m2) - 0.5 - double(yc - 1)) * d1;
            if(debug) {
                //debug_print("yc/y: " + yc + ","+ y);
            }
            zarray[index] = z;
            yarray[index] = y;
            index = index + 1;
        }
        //
        for(int zc = 1 .. n - 1) {
            y = 0.0;
            z = (double(n2) - 0.5 - double(zc - 1)) * d2;
            if(debug) {
                debug_print("zc/z: " + zc + "," + z);
            }
            zarray[index] = z;
            yarray[index] = y;
            index = index + 1;
        }
    }
    //
    if(debug) {
        debug_print("zarray = " + zarray);
        debug_print("yarray = " + yarray);
    }
    // 

    return {zarray,yarray};
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_Cal_LoadCurvePcalOn.txt
//
///////////////////////////////////////////////////////////////////////////
// 
//  CUS script for: 'Spec Load Curve with PCAL on' 
//
//  in *basic_fine_pointing* or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/07/07 V0.1: Initial version adapted from 
//                  SpirePhoto_Cal_LoadCurvePcalOn (2009/06/05 V1.0)
// 2009/07/12 V0.2: Changed default values (SCR-SPIRE-1631)
//
// Sunil Sidher:
// 2009/08/03 V0.3: Changed input PCAL bias current from 3.8mA to 6.0mA (SPIRE SCR-1768)
//
// M.Pohlen:
// 2010/01/06 V1.0: Edit default parameters for input phases (SCR-SPIRE-2300)
//
///////////////////////////////////////////////////////////////////////////
//
//  Script assumes that:
//
//  1)  Instrument is in SPECSTBY at beginning 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Phase is kept constant (from input) during this test, i.e no 
//     adjustment of the phase with changing bias amplitude and frequency
//
//  3) Bias frequency, sampling rate, and phase are input parameters
//
//  4) Boresight of array can be read from following cal table:
//     SpireTable_OpsParms.txt   
//
//  5) PCAL bias calibration coefficients are read from following cal table:
//     SpireTable_PcalCurrentConvCoef.txt
//
//  6) List of bias amplitudes are read from same calibration file as for the 
//     SpireSpectro_Cal_StdLoadCurve, i.e. SpireTable_StdLoadCurveLevels.txt
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_Cal_LoadCurvePcalOn {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; // NAIF identifier
    bool isBright = false; // Use settings for bright source (==tick)
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    double biasfreq = 160.09 in [80.0,240.0]; // Bias frequency [Hz]
    double samplerate = 80.05 in [1.0,80.5]; // Sampling rate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    double phasedeg_ssw = 186.353 in [0.0,360.0]; // SSW Bias phase [deg]
    double phasedeg_slw = 190.588 in [0.0,360.0]; // SLW Bias phase [deg]
    int ftime = 10; // Readout time at each bias level [s]
    double pcal_bias = 6.0 in [0.0,7.0]; // PCAL bias level [mA]
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_StdLoadCurveLevels
    string version05 = "v00"; // Version in cal table SpireTable_OpsParms.txt
    string version09 = "v01"; // Version in cal table SpireTable_PcalCurrentConvCoef  
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Check for is bright setting: 
    //
    if(isBright) {
        isBright = false;
        error("IsBright does not make sense here. Try again (e.g. subtract the phase shift manually from the input)!");
    }
    // //
    // //
    // Declare some variable:
    //
    // Spectrometer or FTS:
    bool phot = false;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_StdLoadCurveLevels.txt";
    string tabName04 = "SpireTable_BsmNominalSettings.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    string tabName06 = "SpireTable_SmecNominalSettings.txt";
    string tabName09 = "SpireTable_PcalCurrentConvCoef.txt";
    // Currently hardcoded version and model parameter:
    //
    string version06 = "v00";
    // Version in cal table SpireTable_SmecNominalSettings
    string version04 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    //
    // Dummy value for Phot script:
    // (needed but not used in spec script!)
    //
    int psw_bias = 62;
    int pmw_bias = 62;
    int plw_bias = 62;
    int ptc_bias = 62;
    int psw_phase = 127;
    int pmw_phase = 127;
    int plw_phase = 127;
    int ptc_phase = 127;
    //
    // Currently hardcoded parameter:
    // Is (==tick) the DCU currently sampled? 
    bool dcuData = false;
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS44";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "SEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Retrieve bias levels used for the load curve:
    // 
    tabName = tabName03;
    version = version03;
    int[] nbiaslist = SpireProc_CalcParam_LoadCurve(tabName,version,debug);
    //
    // Lookup first bias level:    
    int ssw_bias = nbiaslist[0];
    int slw_bias = nbiaslist[0];
    // //
    // //
    // Convert user input to Hex values:
    //
    // for bias frequency and sample rate: 
    // 
    int[] hexvalues = SpireProc_CalcParam_BiasFreqSampFreq(biasfreq,samplerate,fts,debug);
    int mclkdiv = hexvalues[0];
    int biasdiv = hexvalues[1];
    if(debug) {
        debug_print("Hex values of mclkdiv/biasdiv are: " + mclkdiv + " " + biasdiv);
    }
    //
    // for bias phase:
    //
    int[] phasehex = SpireProc_CalcParam_SpecPhaseConvert(phasedeg_ssw,phasedeg_slw,debug);
    int ssw_phase = phasehex[0];
    int slw_phase = phasehex[1];
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version04;
    tabName = tabName04;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Read SMEC home position from calibration file:
    //
    tarCol = "Home";
    tabName = tabName06;
    selVal = version06;
    int smecHomePosn = ilookup(tabName,selVal,tarCol);
    //
    // // // // // // // // // // // // // // // // 
    // // // // // // // // // // // // // // // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartLoadCurvePcalOn(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,ssw_bias,pmw_bias,slw_bias,ptc_bias,ssw_phase,pmw_phase,slw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug));
    // 
    // BBs carried out when the pointing is reached:
    if(pointing) {
        int tinithold = 0;
    } else {
        tinithold = tslewmin;
    }
    //
    // BB carried out during pointing:
    int tp = duration(SpireProc_Exec_SpecLoadCurvePcalOn(nbiaslist,ftime,dcuData,pcal_bias,version09,debug));
    //
    // BB carried out at the end:  
    int tfinalhold = duration(SpireBb_EndLoadCurvePcalOn(phot,isBright,version01,version02,debug));
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartLoadCurvePcalOn(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,psw_phase,pmw_phase,plw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation:
                //
                SpireBb_StartLoadCurvePcalOn(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,ssw_bias,pmw_bias,slw_bias,ptc_bias,ssw_phase,pmw_phase,slw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug);
                //
            }
            //
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            // //
            // //
            // Execute load curve with PCAL on:
            //
            SpireProc_Exec_SpecLoadCurvePcalOn(nbiaslist,ftime,dcuData,pcal_bias,version09,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            //
            SpireBb_EndLoadCurvePcalOn(phot,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_SmecFramerate.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Set MCU framerate (SMEC sampling rate) 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/15 V0.1: Initial version adapted from
//                  SpireProc_Set_BsmFramerate (2009/02/15 V0.2)
// 2009/03/31 V0.2: Fix bug in calculation of framerateHz if input is 0. 
// 2009/06/05 V0.3: Replace Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd 
//                  as requested in SPR-1482.
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_SmecFramerate {
    int frate = 149; // Specifies the frame rate [Dec(Hex)]
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    string tstr = "";
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"     " + tstr + ": SpireProc_Set_SmecFramerate started");
    SpireMsg(4,"          $Id:$");
    // //
    // //
    // Calculate Hex value from user input:
    //
    double framerateHz = 0.0;
    if(frate != 0) {
        framerateHz = 1000000.0 / (double(frate) * 420.0);
    }
    SpireSendDrcuCmd(0x91c00000 + frate,0);
    delay(1);
    //
    if(debug) {
        debug_print("Set MCU framerate (==SMEC ampling rate) to " + frate + " [dec(Hex)]");
        debug_print("Set MCU framerate (==SMEC ampling rate) to " + framerateHz + " [Hz]");
    }
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"      " + tstr + ": SpireProc_Set_SmecFramerate ended");
    //
}

// 
// SDS 13/11/2009: First Version: Performs a reset of the DRCU time counters 
block SpireBb_TReset SPIRE 3405 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_TReset started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    // //
    // Reset DRCU counters:
    //
    Spire_RESET_DRCU_COUNTERS();
    delay(1);
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_TReset ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_Cal_NonLinearity.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Spec Non Linearity'
//
//         in *basic_fine_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/11/23 V0.1: Initial version adapted from
//                  SpireSpectro_CalGCO_ScannedSmecBeamProfile (2009/11/16 V1.1)
//
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in SPECSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for all three arrays and could be taken from following cal table: 
//   SpireTable_SpecModeParams.txt
//
//  3) SMEC scan parameters can be read from calibration table:
//     SpireTable_Spectrometer.txt
// 
//  4) SMEC move parameters can be read from calibration table:
//     SpireTable_SpecSmecNominalSettings.txt
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_Cal_NonLinearity {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; //NAIF identifier: put '0' to use RA/DEC, or correct 'NAIFID'
    bool isBright = false; // Use settings for bright source (==tick)
    /* */
    string ib = "S24_0"; // Central aperture (defined in SIAM) of raster
    string resolution = "M" in ["L","M","H","C"]; // Resolution (low, medium, high,calibration)
    int nscans = 1; // Number of SMEC scans (back+forth==1)
    double smecFrateInput = 238.08; // Specifies the SMEC framerate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParam
    string version03 = "v00"; // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial"; // Model in cal table SpireTable_BsmNominalSettings 
    string version05 = "v03"; // Version in cal table SpireTable_Spectrometer (v03 == 0.250 mm/s)
    string version06 = "v00"; // Version in cal table SpireTable_SmecNominalSettings
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = false;
    bool fts = !phot;
    //
    // Start timing of script:
    int start = time();
    //
    // DCU data mode (0 == Full photometer; 4 == Full spectrometer)
    int dcumode = 4;
    //
    bool setFramerate = true;
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    string tabName05 = "SpireTable_Spectrometer.txt";
    string tabName06 = "SpireTable_SmecNominalSettings.txt";
    string tabName07 = "SpireTable_Flash.txt";
    string tabName08 = "SpireTable_PcalCurrentConvCoef.txt";
    //
    // Currently hardcoded parameter:
    //
    string version07 = "v00";
    // flash parameters version in tabName07
    string version08 = "v01";
    // version in SpireTable_PcalCurrentConvCoef.txt
    //
    // Is (==tick) the DCU currently sampled?:
    bool dcuData = false;
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS45";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "SEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Read SMEC home position from calibration file:
    //
    tarCol = "Home";
    tabName = tabName06;
    selVal = version06;
    int smecHomePosn = ilookup(tabName,selVal,tarCol);
    // //
    // //
    // Retrieve SMEC scanStart parameters from calibration table: 
    // 
    tarCol = "ScanStart";
    selVal = "ResChar";
    tabName = tabName05;
    version = version05;
    int scanStart = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt",selVal,resolution,tarCol,version,debug);
    // //
    // //
    // Retrieve SMEC SPECSTBY framerate from calibration table: 
    // 
    version = version01;
    tabName = tabName01;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "smecFrameRate";
    int smecFrameRate = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    double smecFrameRateHz = 0.0;
    if(smecFrameRate != 0) {
        smecFrameRateHz = 1000000.0 / (double(smecFrameRate) * 420.0);
    }
    if(debug) {
        debug_print("Nominal SMEC sampling rate is: " + smecFrameRateHz + " [Hz]");
    }
    // //
    // //
    // Calculate commanded framerates for SMEC from user input: 
    //
    int smecFrate = SpireProc_CalcParam_McuFramerate(smecFrateInput,debug);
    //
    // //
    // //
    // Read hold position from calibration table:  
    //
    // Name of column for selecting: 
    selCol = "model";
    // Value of 'string' selector:
    selVal = model;
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName03,selCol,selVal,tarCol,version03,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName03,selCol,selVal,tarCol,version03,debug);
    // //
    // //
    // Define flashMode:
    // 
    string flashMode = "";
    if(isBright) {
        flashMode = "SFlash_b";
    } else {
        flashMode = "SFlash";
    }
    // //
    // //
    // Read parameters for AOT PCAL flash from calibration files:
    // 
    //  Number of table containing the flash command list:
    int id = ilookup("SpireTable_CommandLists.txt","Flash","Id");
    //
    //  Istart point in table containing the flash command list:
    int index = ilookup("SpireTable_CommandLists.txt","Flash","Index");
    //  
    //  Number of parameters to the flash command list:
    int nParms = ilookup("SpireTable_CommandLists.txt","Flash","Nparms");
    //
    int lowBias = SpireProc_GetTableEntryInt(tabName07,"Mode",flashMode,"LowBias",version07,debug);
    int highBias = SpireProc_GetTableEntryInt(tabName07,"Mode",flashMode,"HighBias",version07,debug);
    int cycles = SpireProc_GetTableEntryInt(tabName07,"Mode",flashMode,"Cycles",version07,debug);
    int period = SpireProc_GetTableEntryInt(tabName07,"Mode",flashMode,"Period",version07,debug);
    int dcuMode = SpireProc_GetTableEntryInt(tabName07,"Mode",flashMode,"DcuFrame",version07,debug);
    int dcuSamples = SpireProc_GetTableEntryInt(tabName07,"Mode",flashMode,"DcuSamples",version07,debug);
    int dcuDelay = SpireProc_GetTableEntryInt(tabName07,"Mode",flashMode,"DcuDelay",version07,debug);
    int scuMode = SpireProc_GetTableEntryInt(tabName07,"Mode",flashMode,"ScuMode",version07,debug);
    int scuSamples = SpireProc_GetTableEntryInt(tabName07,"Mode",flashMode,"ScuSamples",version07,debug);
    // //
    // //
    // Calculate pcal_bias in [mA] for SpireBb_PcalFlash:
    // 
    // Retrieve PCAL bias calibration coefficients:
    double[] coeff = [0.0];
    coeff[0] = dlookup(tabName08,version08,"c_0");
    coeff[1] = dlookup(tabName08,version08,"c_1");
    // 
    // Calculate RAW PCAL bias values for each of the flashes from mA list: 
    double pcal_bias = (double(highBias) * coeff[1] + coeff[0]) / 0.0010;
    if(debug) {
        debug_print("Output pcal_bias: " + pcal_bias);
    }
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    // 
    int tslewmin = duration(SpireBb_StartSpecNonLinearity(obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,debug));
    // 
    // BBs carried out when the pointing is reached:
    //
    int tinithold = duration(SpireBbSmecInit(resolution,version03,version06,version05,debug));
    //
    // BB carried out during pointing:
    // 
    int tp = duration(SpireProc_Exec_SpecNonLinearity(dcuData,flashMode,version01,version02,id,index,nParms,lowBias,highBias,cycles,period,dcuMode,dcuSamples,dcuDelay,scuMode,scuSamples,smecFrate,scanStart,smecHomePosn,resolution,version05,nscans,pcal_bias,version08,debug));
    //
    // BB carried out at the end:
    //
    int tfinalhold = duration(SpireBb_EndSpecNonLinearity(resolution,smecHomePosn,isBright,version01,version02,version05,debug));
    // //
    // //
    // Debug printing:
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing normal= " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                              */
    // ****************************************************** */
    // //
    // //
    // Fixed parameters for pointing mode:
    //   
    // Rotation angle of the pattern
    double yoffset = 0.0;
    // Offset of pattern in the direction of the +Y
    double zoffset = 0.0;
    // //
    // //
    // Set pointing mode:
    //
    // int[] ts = basic_fine_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,yOffset + deltaY,zOffset + deltaZ,tp);
    int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,yoffset,zoffset,tp);
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC              */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Prepare observation: 
            //     
            SpireBb_StartSpecNonLinearity(obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // Initialise SMEC (close loop) (new for SPR-SPIRE-2062)
            //
            SpireBbSmecInit(resolution,version03,version06,version05,debug);
            //
            //delay(tinithold);
        }
        if(state[0] == 3) {
            // STATE = POINT (spacecraft is at nominal RA,DEC (staring, raster))
            //
            //delay(tp);
            // //
            // //
            // Execute test:
            //
            SpireProc_Exec_SpecNonLinearity(dcuData,flashMode,version01,version02,id,index,nParms,lowBias,highBias,cycles,period,dcuMode,dcuSamples,dcuDelay,scuMode,scuSamples,smecFrate,scanStart,smecHomePosn,resolution,version05,nscans,pcal_bias,version08,debug);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ("sky" observation ends, performing final activities )
            // //
            // //
            // End observation:
            //
            SpireBb_EndSpecNonLinearity(resolution,smecHomePosn,isBright,version01,version02,version05,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END (end of the pointing/commanding part of the code)
            //
        }
    }
}

// SpirePhotoPointJiggle
//
// $id$
//
// The high level script for the Spire Photometer Point Source observing mode using a 7-pnt jiggle map
//
// 07 Nov 2007  KJK  removed the current point number (np) from the STEP value set during Final Hold. 
//                  This value is not set in any other STEP value 
// 15 Feb 2008:  KJK    Now sets np in the STEP value for the FINAL_HOLD PCalFlash
// 04 Nov 2008: KJK
//         added data_rate commands
//         added commands to setup the detector sampling beofre starting operations
// 26 Jan 2008: KJK
//         Now uses general observation start Bb (SpireBb_StartObsAll) 
//         Now uses general observation end Bb (SpireBb_EndObsAll
// 07/02/2009 V0.1: KJK added new parameters to SpirePOF2Pointing, SpirePOF2Config, SpirePOF2End
// 10/03/2009 KJK: 
//         SCR 1274, add additional dummy parameters 
//         Update input API to include versions for all cal tables
//  02/07/2009  KJK:
//         Added configuration input parameters to pass to SpirePOF2Config, SpirePOF2Pointing and SpirePOF2End
//  05/07/2009 KJK:
//         SPR-1593 - Updated calls to SpirePOF2Pointing and SpireBbPcalFlash to use flashVersion 
//                    
//  30/07/2009 SDS:
//         SPR-1752 - Updated to allow the loading of a new JM07 table (uses the boolean pBool1)
//                    Now references SpireTable_OpsParms.txt (previously OpsParms.txt)
//                    Booleans InitFlash and EndFlash now read from SpireTable_SpireParams.txt (previously OpsParms.txt)
//  10/08/2009 KJK:
//         SPR-1709:  Added new input parameter, comVersion to call to SpreBbPOF2Config
//  12/08/2009 KJK:
//         SPIRE-1804:Added opsVersion, chopVersion and debug as input parameters to calls to SpireBbJiggle
//   14/08/2009 KJK:
//         Spire-1759: Now load new jigglemap in separate BB
//  25-Aug-2009 KJK:
//        SPR Spire-1641: Needed new input parameters bsmModel and bsmVersion
//  10-Sep-2009 KJK:
//        SCR Spire-1943: Needed new input parameter detVersion
//  16-Feb-2010 KJK:
//       SCR Spire-648: added call to SpireBb_BsmMove2Hold before each PCAL flash, except the initial
//
{int,int,int,int} obs SpirePhotoPointJiggle {
    double ra = 0.0 in [0.0,360.0]; // RA of Target
    double dec = 0.0 in [-90.0,90.0]; // Dec of Target
    int naifid = 0; // NAIF identifier
    string source = "point" in ["point","small","large"]; // source type
    bool choppingAvoidOn = false; // is chopping avoidance selected
    int choppingAvoidNumber = 0 in [0,3]; // the number of chopping avoid angles selected
    double choppingAvoidFrom1 = 0.0 in [0.0,360.0];
    double choppingAvoidTo1 = 0.0 in [0.0,360.0];
    double choppingAvoidFrom2 = 0.0 in [0.0,360.0];
    double choppingAvoidTo2 = 0.0 in [0.0,360.0];
    double choppingAvoidFrom3 = 0.0 in [0.0,360.0];
    double choppingAvoidTo3 = 0.0 in [0.0,360.0];
    int nRepetitions = 1 in [1,600]; // number of repeats of basic observing cycle 
    double sourceFluxPSW = -1.0;
    double sourceFluxPMW = -1.0;
    double sourceFluxPLW = -1.0;
    bool isBright = false; // Use settings for bright source (==tick)
    bool isJiggleMap = true;
    int nCycles = 1; // total number of nod cycles to perform
    int nNodInts = 1; // number of times to repeat NJigg jiggles at each nod position 
    int nCal = 999999; // number of nod cycles per Gyro calibration 
    int nFlash = 999999; // number of nod cycles per PCAL flash
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string detVersion = "v00"; // Version in cal table SpireTable_DefaultParams.txt
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParams
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    string flashVersion = "v00"; // Version in cal table SpireTable_FlashParms
    string chopVersion = "v00"; // Version in cal table SpireTable_ChopParams
    string photVersion = "v00"; // Version in cal table SpireTable_PhotModeParams.txt
    string comVersion = "v00"; // Version in cal table SpireTable_CommonModeParams.txt
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Load 7-Point Jiggle Map Table?
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // *****************
    // check user inputs
    // *****************
    if(source != "point") {
        error("SpirePhotoPointJiggle: Source is not a point");
    }
    //
    // *****************
    // set constants
    // *****************
    string obsMode = "POF2";
    bool isPhot = true;
    // is a photometer observation
    double yOffset = 0.0;
    //  offset to observation position from target in Y direction (arcsecs)
    double zOffset = 0.0;
    // offset to observation position from target in Z direction (arcsecs)
    //   
    // *****************************************
    //      set up telescope pointing mode    
    // *****************************************
    //
    // *****  operating mode parameters *****
    // instrument boresight
    string ib = SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode",obsMode,"Boresight",opsVersion,debug);
    // offset to pixel centre from boresight in Y direction (arcsecs)
    double deltaY = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"DeltaY",opsVersion,debug);
    // offset to pixel centre from boresight in Z direction (arcsecs)
    double deltaZ = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"DeltaZ",opsVersion,debug);
    // pattern angle definition
    bool fixed = SpireProc_GetTableEntryBool("SpireTable_OpsParms.txt","mode",obsMode,"Fixed",opsVersion,debug);
    // direction of nod
    double pattNod = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"Patt",opsVersion,debug);
    double chopThrow = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"D1",opsVersion,debug);
    // Jiggle Table ID
    int jiggleTable = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"TableId",opsVersion,debug);
    // Jiggle Table length
    int jiggleSize = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"TableSize",opsVersion,debug);
    // number of chop cycles per jiggle position
    int nChops = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NChops",opsVersion,debug);
    // number of jiggle positions per nod position
    int nJiggs = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NJiggs",opsVersion,debug);
    // number of nod positions in a nod cycle
    int nNodPosns = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NNodPosns",opsVersion,debug);
    // initial flash flag
    bool initFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"InitFlash",spireVersion,debug);
    // final flash flag
    bool endFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"EndFlash",spireVersion,debug);
    // effective on source integration time per nod cycle
    double cycTime = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"SrcTime",opsVersion,debug);
    //
    // ***** pointing mode timing parameters *****
    {int,int,int,int,int,int} pof2Point = SpirePOF2Pointing(nCycles,nNodInts,nCal,nFlash,isBright,bsmModel,bsmVersion,detVersion,spireVersion,opsVersion,flashVersion,chopVersion,photVersion,comVersion,debug,pBool1);
    int tSlewMin = pof2Point{0};
    int tInitHold = pof2Point{1};
    int tFinalHold = pof2Point{2};
    int tp = pof2Point{3};
    int tHold = pof2Point{4};
    int nHold = pof2Point{5};
    //
    // ***** fetch timing information *****
    int tFlash = duration(SpireBbPcalFlash("PFlash",flashVersion,0,debug));
    // time for a PCAL flash
    int tSerendipity = duration(SpireBbPhotSerendipity(obsMode,0));
    // minimum time for a serendipity observation
    //
    //
    // ****** execute telescope pointing mode ******
    //
    int[] ts = nodding_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,fixed,pattNod,yOffset + deltaY,zOffset + deltaZ,nCycles * nNodPosns / 2,chopThrow,tp,tp,0,0,tHold,nHold,false);
    //
}{
    // *****************************************
    //   Display input parameters
    // *****************************************
    SpireMsg(3,"     Using MODE " + obsMode);
    SpireMsg(3,"     Input values:");
    SpireMsg(3,"     ..RA: " + ra);
    SpireMsg(3,"     ..Dec: " + dec);
    SpireMsg(3,"     ..NAIF ID: " + naifid);
    SpireMsg(3,"     ..Y Offset: " + yOffset);
    SpireMsg(3,"     ..Z Offset: " + zOffset);
    SpireMsg(3,"     ..No of Nod Cycles: " + nCycles);
    SpireMsg(3,"     ..No of Ints per Nod Posn: " + nNodInts);
    // SpireMsg(3,"     ..No of  Nod Cycles between Gyro Calibrations: " + nCal);
    SpireMsg(3,"     ..No of  Nod Cycles between Flashes: " + nFlash);
    SpireMsg(3,"     POF2 Fixed values:");
    SpireMsg(3,"     ..ib: " + ib);
    SpireMsg(3,"     ..deltaY: " + deltaY);
    SpireMsg(3,"     ..deltaZ: " + deltaZ);
    SpireMsg(3,"     ..fixed: " + fixed);
    SpireMsg(3,"     ..pattNod: " + pattNod);
    SpireMsg(3,"     ..chopThrow: " + chopThrow);
    SpireMsg(3,"     ..jiggleTable: " + jiggleTable);
    SpireMsg(3,"     ..jiggleSize: " + jiggleSize);
    SpireMsg(3,"     ..nChops: " + nChops);
    SpireMsg(3,"     ..nJiggs: " + nJiggs);
    SpireMsg(3,"     ..nNods: " + nNodPosns);
    SpireMsg(3,"     ..initFlash: " + initFlash);
    SpireMsg(3,"     ..endFlash: " + endFlash);
    SpireMsg(3,"    Composite Nodding Pointing Mode Input values:");
    SpireMsg(3,"    ..tSlewMin: " + tSlewMin);
    SpireMsg(3,"    ..tInitHold: " + tInitHold);
    SpireMsg(3,"    ..tFInalHold: " + tFinalHold);
    SpireMsg(3,"    ..tp: " + tp);
    SpireMsg(3,"    ..tHold: " + tHold);
    SpireMsg(3,"    ..nHold: " + nHold);
    SpireMsg(3,"    Composite Nodding Pointing Mode Output values:");
    SpireMsg(3,"    ..tobs: " + ts[0]);
    SpireMsg(3,"    ..tslew: " + ts[1]);
    SpireMsg(3,"    ..tnod: " + ts[2]);
    SpireMsg(3,"    ..tss: " + ts[3]);
    SpireMsg(3,"    ..tload: " + ts[4]);
    SpireMsg(3,"    ..tend: " + ts[5]);
    // *****************************************
    //   execute observation
    // *****************************************
    SpireMsg(0,"Observation Start");
    SpireMsg(0,"  Uses observing mode POF2 (7-pnt Jiggle Map)");
    SpireMsg(3,"       $Id:$");
    data_rate(0.0);
    double chkrate = dlookup("Datarates.txt",obsMode,"CHK");
    ess_hk_data_rate(chkrate);
    double nhkrate = dlookup("Datarates.txt",obsMode,"NHK");
    non_ess_hk_data_rate(nhkrate);
    //
    //??p pointing file generation ------------------------------
    double pos = 90.0;
    //??p double[] rdp0 = PtOffset([ra,dec,pos],zOffset,yOffset,0.0,false);
    //??p pointing file generation ------------------------------
    //
    int tslew = ts[1];
    // slew time
    string tstr = "";
    // time string
    bool holdFlag = false;
    // true when holding at nod position
    int otf = 0x8000;
    // On Target Flag
    int nf = 0x4000;
    // Nod Flag
    int step = 0x0;
    // value of STEP parameter
    double srcTime = 0.0;
    //  total on source integration time
    int np = 0;
    // pointing counter
    double s = 0.0;
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // ***********************  SLEWING
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Slewing to start position");
            // set up observation parameters
            SpireBb_StartObsAll(obsMode);
            // perform serendipity operation if possible
            if(tslew > tSerendipity + tSlewMin) {
                SpireBbPhotSerendipity(obsMode,tslew - tSlewMin - 2);
            }
            // configure instrument for operations
            if(pBool1) {
                SpireBb_LoadTableJM07b();
            }
            SpireBbPOF2Config(obsMode,isBright,photVersion,comVersion,debug);
        }
        if(state[0] == 2) {
            // ***********************  INITIAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Initialising Instrument");
            // initialise instrument
            SpireBbPOF2Init();
            // calibrate if necessary
            if(initFlash || nFlash < nCycles) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireBbPcalFlash("PFlash",flashVersion,otf,debug);
            }
        }
        if(state[0] == 5) {
            // ***********************  FINAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Reconfiguring Instrument");
            // calibrate if necessary
            if(endFlash || nFlash < nCycles) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireBb_BsmMove2Hold(bsmModel,bsmVersion,debug);
                SpireBbPcalFlash("PFlash",flashVersion,otf | np,debug);
            }
            // reconfigure back to PHOT_STBY configuration
            SpireBbPOF2End("PHTSTBY",isBright,bsmModel,bsmVersion,detVersion,photVersion,comVersion,debug);
            SpireBb_EndObsAll(isPhot);
        }
        if(state[0] == 6) {
            // ***********************  HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
            SpireBb_BsmMove2Hold(bsmModel,bsmVersion,debug);
            SpireBbPcalFlash("PFlash",flashVersion,otf,debug);
        }
        if(state[0] == 3) {
            // ***********************  POINTING
            //??p pointing file generation ------------------------------
            //??p PtOutput(rdp0);
            //??p pointing file generation ------------------------------
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Instrument at Pointing Position");
            SpireMsg(2,"    " + tstr + " Start Jiggles " + np);
            step = otf;
            s = SpireBbJiggle("POF2",jiggleTable,0,nJiggs,nNodInts,step,opsVersion,chopVersion,debug);
            srcTime = srcTime + s;
            np = np + 1;
            step = 0;
            SpireBbMove(step);
        }
        if(state[0] == 7) {
            // ***********************  NOD
            //??p pointing file generation ------------------------------
            //??p PtNod(rdp0,patt,d1,patt,false,false);
            //??p pointing file generation ------------------------------
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Instrument at Nod Position");
            SpireMsg(2,"    " + tstr + " Start Jiggles " + np);
            step = nf | otf;
            s = SpireBbJiggle("POF2",jiggleTable,0,nJiggs,nNodInts,step,opsVersion,chopVersion,debug);
            srcTime = srcTime + s;
            np = np + 1;
            step = 0;
            SpireBbMove(step);
        }
        if(state[0] == 9) {
            // ***********************  LOAD
        }
    }
    assert (time() == ts[0] + ts[1]);
    //
    // finish observation
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + " Instrument Reconfigured");
    //
    //
    SpireMsg(0,"Observation Completed  (" + time() + " seconds)");
    SpireMsg(0,"Note: Total time (s) = Observation Completed time - slew time + Observatory Overheads");

    return {nCycles,iround(cycTime),iround(srcTime),time() - iround(srcTime) - tslew};
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_BsmFramerate.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to translate user input in mV for bias amplitude 
//  into nearest Hex values for psw_bias, pmw_bias, plw_bias, and ptc_bias  
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/15 V0.1: Initial version adapted from 
//                  SpireProc_Set_BsmFramerate (2008/11/13 V0.1)
//
///////////////////////////////////////////////////////////////////////////
int procedure SpireProc_CalcParam_BsmFramerate {
    double frateHz = 0.0; // Input BSM framerate [Hz]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Convert from Hz to RAW values:
    //
    int frateInt = iround(1000000.0 / (frateHz * 420.0));
    // //
    // //
    // Debug printout:
    //
    if(debug) {
        debug_print("Input Hz value for BSM framerate: " + frateHz);
        debug_print("Output Dec(Hex) values for BSM framerate: " + frateInt);
    }
    // //
    // //
    // Return required values:
    //

    return frateInt;
}

// SpireBbCoolerRecycle
//
// $id$
//
// This building block executes the cooler recycle procedure
// 
// The instrument should be in  the REDY mode before execution of this observation
//
// 17-Nov-2008 KJK: added sync command
// 25-Aug-2009 KJK:
//                            - Updated to get Command List information from SpireTable_CommandLIsts.txt
//                            - Updated to get CREC parameters from new Cal Table (SpireTable_CL_CREC.txt)
//                            - Modified BB completion messages 
//
block SpireBbCoolerRecycle SPIRE 2568 {
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Cooler Recycle started");
    SpireMsg(2,"          $Id$");
    //
    int cmd = 0x0;
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    //
    // Select  the current instrument in operation (prime/redundant)
    string side = "prime";
    //
    // Get Command List info 
    int tableId = ilookup("SpireTable_CommandLists.txt","CREC","TableId");
    int startIndex = ilookup("SpireTable_CommandLists.txt","CREC","Index");
    int nParams = ilookup("SpireTable_CommandLists.txt","CREC","NParms");
    //
    // Retrieve the VM input parameters 
    int a = ilookup("SpireTable_CL_CREC.txt","a",side);
    // Heat Switch ON current (during Recycling)
    int b = ilookup("SpireTable_CL_CREC.txt","b",side);
    // Heat Switch OFF current
    int c = ilookup("SpireTable_CL_CREC.txt","c",side);
    // Pump Heat Switch Actuation Temperature
    int d = ilookup("SpireTable_CL_CREC.txt","d",side);
    // Pump Heater Dissipation 1
    int e = ilookup("SpireTable_CL_CREC.txt","e",side);
    // Pump Condensation Temperature 1
    int f = ilookup("SpireTable_CL_CREC.txt","f",side);
    // Pump Heater Dissipation 2
    int g = ilookup("SpireTable_CL_CREC.txt","g",side);
    // Pump Condensation Temperature 2
    int h = ilookup("SpireTable_CL_CREC.txt","h",side);
    // Pump Heater Dissipation 3
    int i = ilookup("SpireTable_CL_CREC.txt","i",side);
    // Pump Heater Dissipation 4
    int j = ilookup("SpireTable_CL_CREC.txt","j",side);
    // Pump Condensation Temperature Threshold
    int k = ilookup("SpireTable_CL_CREC.txt","k",side);
    // Evaporator Condensation Temperature
    int l = ilookup("SpireTable_CL_CREC.txt","l",side);
    // Evaporator Heat Switch Actuation Temperature
    int m = ilookup("SpireTable_CL_CREC.txt","m",side);
    // Pump Threshold Temperature
    int n = ilookup("SpireTable_CL_CREC.txt","n",side);
    // Heat Switch ON current
    int o = ilookup("SpireTable_CL_CREC.txt","o",side);
    // Sampling Interval (sec)
    int p = ilookup("SpireTable_CL_CREC.txt","p",side);
    // Heatswitch Timeout (min)
    int q = ilookup("SpireTable_CL_CREC.txt","q",side);
    // Pump Heating Timeout 1 (min)
    int r = ilookup("SpireTable_CL_CREC.txt","r",side);
    // Pump Heating Timeout 2 (min)
    int s = ilookup("SpireTable_CL_CREC.txt","s",side);
    // Evaporator Timeout (min)
    int t = ilookup("SpireTable_CL_CREC.txt","t",side);
    // Pump Cooling Timeout (min)
    int u = ilookup("SpireTable_CL_CREC.txt","u",side);
    // Global Timeout (min)
    //
    // Set Mode to CREC
    mois_comment("Set the SPIRE mode to CREC for Cooler Recycle");
    SpireSetObsMode("CREC");
    //
    // start executing recycle VM
    mois_comment("Execute the SPIRE command to perform Automatic Cooler Recycle");
    mois_spacon("This command will take about " + (u + 1) + " minutes to execute");
    {int}[] crecParams = [{a},{b},{c},{d},{e},{f},{g},{h},{i},{j},{k},{l},{m},{n},{o},{p},{q},{r},{s},{t},{u}];
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM_RAW(" + tableId + "," + startIndex + "," + nParams + "," + crecParams + ")");
    Spire_RUN_VM_RAW(tableId,startIndex,nParams,crecParams);
    // Wait for completion
    // Insert a delay equal to the CREC VM global time out plus a minute
    delay(u * 60 + 58);
    //
    // Set MODE to REDY
    mois_comment("Set the SPIRE mode to REDY");
    SpireSetObsMode("REDY");
    //
    sync();
    //
    // completion
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB Cooler Recycle   ended");
    SpireMsg(1,"  ..Cooler Recycle (" + (time() - t0) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_BsmChop.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to execute chopping or jiggling operations. Script returns 
// the actual time on-source. It sets the obsStep, resets the FIFOs,
// runs the VM, and flushes the FIFOs. It does not set the datarate. 
//
// Note: VM does not reset dcusample/bsmsample at end, so this needs 
//       to be done in the surrounding end script.         
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/16 V0.1: Initial version adapted from
//                  SpireBb_Chop (2009/01/27 V1.0) 
//                  Added VM table parameters as input and removed
//                  BSM framerate from input. Round wait_time up and 
//                  removed the adding of 3s for saftey.  
//
// Sunil Sidher
// 2009/07/28 V0.2: Added 2s to the wait_time to prevent the step changing too
//                  soon (Recommendation 3 in SPIRE SCR-1710)  
///////////////////////////////////////////////////////////////////////////
//
double procedure SpireProc_Set_BsmChop {
    int vmId = 71; // Raw VM table number [Dec(Hex)]
    int vmIndex = 0; // Raw VM index [Dec(Hex)]
    int nParms = 10; // Number of parameters passed to VM
    int onChop = 0; // on-source Chop position
    int onJigg = 0; // on-source Jiggle positio
    int offChop = 0; // off-source Chop position
    int offJigg = 0; // off-source Jiggle position
    int ncycles = 50; // Number of chop cycles [#]
    int chop_period = 500000; //period of chop cycles in [microsec]
    int dcumode = 0; // DCU data mode (e.g. 0 == Full photometer)
    int dcusample = 4; //Number of DCU samples per chop position [#]
    int dcudelay = 34959; //Dealy to start sampling the DCU [microsec]
    int bsmsample = 31; //Number of BSM samples per position  [#]
    int step = 0; // Step number [dec]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    int t = time();
    string tstr = "";
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"     " + tstr + ":  SpireProc_Set_BsmChop started");
    SpireMsg(4,"          $Id:$");
    // //
    // //
    // Set obsstep:
    //
    SpireProc_Set_ObsStep(step,debug);
    // //
    // //
    // Reset DCU and MCU (x3000) fifo:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RESET_FIFOS(0x3000)");
    Spire_RESET_FIFOS(0x3000);
    delay(1);
    // //
    // //
    // Setup VM parameters:
    //
    {int}[] chopparams = [{onChop},{onJigg},{offChop},{offJigg},{ncycles},{chop_period},{dcumode},{dcusample},{dcudelay},{bsmsample}];
    // //
    // //
    // Execute VM:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM_RAW(" + vmId + "," + vmIndex + "," + nParms + "," + chopparams + ")");
    Spire_RUN_VM(vmId,vmIndex,nParms,chopparams);
    // //
    // //
    // Finish VM:
    //
    // Calculate time for VM to finish (add 0s for safety):
    //
    int wait_time = iceil(double(chop_period + dcudelay) * double(ncycles) / 1000000.0 + 2.0);
    if(debug) {
        debug_print("Wait time will be :" + " " + wait_time + " " + "sec");
    }
    delay(wait_time);
    // //
    // //
    // Flush DCU and MCU fifos:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x3000)");
    Spire_FLUSH_FIFO(0x3000);
    delay(2);
    // //
    // //
    // Calculate time on source:
    //
    if(debug) {
        debug_print("chop_period: " + chop_period);
        debug_print("ncycles: " + ncycles);
        debug_print("dcudelay: " + dcudelay);
    }
    double srcTime = double(ncycles) * ((0.5 * double(chop_period) - double(dcudelay)) / 1000000.0);
    if(debug) {
        debug_print("On source time: " + srcTime + " [s]");
    }
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"      " + tstr + ": SpireProc_Set_BsmChop ended");
    SpireMsg(1,"  ..Chop/Jigg (" + (time() - t) + " seconds)");
    //

    return srcTime;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_Cal_BsmAngleCal.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Spec BSM Angle Calibration' 
//
//  in *basic_fine_pointing* mode or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/11/07 V0.1: Initial version adapted from
//                  SpirePhoto_Cal_BsmAngleCal (2008/11/07 V0.3)
// 2008/11/12 V0.2: Implement mode setting; Add isBright 
// 2009/01/21 V0.3: Modify unreasonable default values of ref pos; 
//                  Correct pass-on of chop/fts parameter to low level script;
//                  Correct typo in input description; Add ranges for 
//                  input positions; Add safety check pos1<pos2
// 2009/02/19 V0.4: Move actual setting of BSM framerate to high level script. 
//                  Add debug_print as input and pass it to some low level 
//                  scripts. Read nominal bias frequency and bias divider 
//                  from new SpireTable_SpecModeParams. Use new 
//                  SpireBb_EndObsAll and SpireBb_StartObsAll. Implemented
//                  isBright setting. Implemented setting of datarates. 
//                  Use SpireBb_EndBsmAngleCal to set instrument back to 
//                  SPECSTBY and move BSM to hold during FINAL_HOLD. Use 
//                  SpireProc_Set_SpecMode to set instrument to SPECSTBY
//                  during SLEW, ditto for isBright. Adapt call to updated 
//                  SpireProc_Exec_BsmAngleCal. 
// 2009/03/04 V0.5: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Add no pointing option.
// 2009/05/05 V0.6: Add in move BSM/SMEC to hold/home at start. Add new 
//                  SpireBb_SmecHold to account for the fact that
//                  SpireBb_SmecMove2Home does not stop SMEC.
//                  Gather procedures at start and end in separate BB. Add 
//                  SpireBb_EndObsAll to SpireBb_EndBsmAngleCal. 
//                  Fix bug with fts parameter. 
// 2009/09/05 V1.0: Allow reverse loop through values (SCR-SPIRE-1894)
//                  Throw error if increment is negative. Changed default
//                  input max_chop/max_jigg
//
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in SPECSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for both arrays and could be taken from following cal table: 
//  SpireTable_SpecModeParams.txt 
//
//  3) Further mode dependent parameters can be read from:
//  SpireTable_CommonModeParams.txt           
//
//  4) Hold position of BSM can be read from SpireTable_BsmNominalSettings.txt
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_Cal_BsmAngleCal {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; //NAIF identifier: put '0' to use RA/DEC, or correct 'NAIFID'
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    bool isBright = false; // Use settings for bright source (==tick)
    /* */
    string ib = "S24_0"; // Central aperture (defined in SIAM) of raster
    bool chop = true; // Tick for scanning chop axis (otherwise jiggle)
    int ref_chop = 16000 in [8000,55000]; // Chop position of BSM reference position [Dec(Hex)]
    int ref_jigg = 17000 in [8000,55000]; // Jiggle position of BSM reference position [Dec(Hex)]
    int max_chop = 54848 in [8000,55000]; // Maximum chop position of BSM to be scanned [Dec(Hex)]
    int max_jigg = 54848 in [8000,55000]; // Maximum jiggle position of BSM to be scanned [Dec(Hex)]
    int min_chop = 8000 in [8000,55000]; // Minimum chop position of BSM to be scanned [Dec(Hex)]
    int min_jigg = 8000 in [8000,55000]; // Minimum jiggle position of BSM to be scanned [Dec(Hex)]
    double chopf = 2.0 in [0.1,4.0]; // Chop frequency [Hz] 
    double framerate = 125.0; // Specifies the MCU framerate [Hz]
    int ftime = 15; // Read-out time [s]
    int increment = 384; // Chop/Jiggle increment along scan axis [Dec(Hex)]
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial"; // Model in cal table SpireTable_BsmNominalSettings
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Scan axis either increasing or decreasing (==tick)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Assign spare parameters:
    //
    bool reverse = pBool1;
    // 
    // //
    // //
    // Declare some variable:
    //
    // FTS or photometer (for dcumode in VM set in SpireProc_Exec_BsmAngleCal):
    bool fts = true;
    // Photometer or FTS (for SpireBb_EndBsmAngleCal)
    bool phot = !fts;
    //
    string version = "";
    string tabName = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int frate = 0;
    int tinithold = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    string tabName04 = "SpireTable_CommandLists.txt";
    string tabName06 = "SpireTable_SmecNominalSettings.txt";
    //
    // Currently hardcoded version:
    //
    string version06 = "v00";
    // Version in cal table SpireTable_SmecNominalSettings
    //
    // Currently hardcoded parameter:
    // Is (==tick) the DCU currently sampled? 
    bool dcuData = false;
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS31";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for setup and datarates:  
    string obsMode = "SEngCalObs";
    // Note: datarates are currently only maximum values
    // //
    // //
    // Check input chop/jiggle parameters :
    //
    if(max_chop < min_chop + increment) {
        error("Max chop is smaller than min chop plus 1*increment!");
    }
    if(max_jigg < min_jigg + increment) {
        error("Max jigg is smaller than min jigg plus 1*increment!");
    }
    // //
    // //
    // Setup parameters for BSM chopping movement: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version03;
    tabName = tabName03;
    string selCol = "model";
    // Name of column for selecting 
    string selVal = model;
    // Value of 'string' selector
    //
    // Read BSM hold position from calibration table:  
    //
    string tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Read VM parameters from calibration table:
    //
    tabName = tabName04;
    selVal = "Chop";
    int vmId = ilookup(tabName,selVal,"Id");
    int vmIndex = ilookup(tabName,selVal,"Index");
    int nParms = ilookup(tabName,selVal,"Nparms");
    // //
    // //
    // Read SMEC home position from calibration file:
    //
    tarCol = "Home";
    tabName = tabName06;
    selVal = version06;
    int smecHomePosn = ilookup(tabName,selVal,tarCol);
    // //
    // //
    // Read nominal bias frequency and bias divider:
    // (to determine the sampling rate)
    //    
    // Select version flag and set GetTableEntry parameters:
    version = version01;
    tabName = tabName01;
    selCol = "mode";
    // Name of column for selecting 
    selVal = obsMode;
    // Value of 'string' selector
    //
    tarCol = "mclkDiv";
    int mclkdiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "biasDiv";
    int biasdiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Calculate nominal sampling rate from mclkdiv and biasdiv:
    //
    double mclkdivHz = 1.0E7 / (512.0 * double(mclkdiv + 1));
    double biasdivHz = 1.0 / (double(biasdiv) + 1.0) * mclkdivHz;
    if(debug) {
        debug_print("Nominal sampling rate is: " + biasdivHz + " [Hz]");
    }
    //
    // // // // // // // // // // // // // // // // 
    // // // // // // // // // // // // // // // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    //
    int tslewmin = duration(SpireBb_StartBsmAngleCal(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,framerate,smecHomePosn,debug));
    // 
    // BBs carried out when the pointing is reached:
    //
    if(pointing) {
        tinithold = duration(SpireBb_SpecOffsetAuto(dcuData,debug)) + duration(SpireBb_SmecHold(debug));
    } else {
        tinithold = duration(SpireBb_SpecOffsetAuto(dcuData,debug)) + duration(SpireBb_SmecHold(debug)) + tslewmin;
    }
    //
    // BB carried out during pointing:
    //
    int tp = duration(SpireProc_Exec_BsmAngleCal(increment,ref_chop,ref_jigg,hold_chop,hold_jigg,max_chop,max_jigg,min_chop,min_jigg,vmId,vmIndex,nParms,chopf,ftime,framerate,biasdivHz,fts,chop,reverse,debug));
    //
    // BB carried out at the end:
    //
    int tfinalhold = duration(SpireBb_EndBsmAngleCal(phot,hold_chop,hold_jigg,isBright,version01,version02,debug));
    // //
    // //
    // Debug printing?:
    // 
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // 
    // Set pointing mode:
    //
    int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartBsmAngleCal(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,framerate,smecHomePosn,debug);
            //
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation: 
                //
                SpireBb_StartBsmAngleCal(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,framerate,smecHomePosn,debug);
            }
            // //
            // //
            // Set offsets:
            //
            SpireBb_SpecOffsetAuto(dcuData,debug);
            // //
            // //
            // Stop any remaining SMEC movement:
            //
            SpireBb_SmecHold(debug);
            //
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            // //
            // //
            // Execute BSM angle calibration:
            //
            SpireProc_Exec_BsmAngleCal(increment,ref_chop,ref_jigg,hold_chop,hold_jigg,max_chop,max_jigg,min_chop,min_jigg,vmId,vmIndex,nParms,chopf,ftime,framerate,biasdivHz,fts,chop,reverse,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            SpireBb_EndBsmAngleCal(phot,hold_chop,hold_jigg,isBright,version01,version02,debug);
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

//$Id: PHOT_dpu_dmc_setup.txt,v 1.5 2008/05/28 09:27:05 vanessad Exp $
// Missionphase  : 
//
// Purpose       : Prepare DPU and DMC for photometry
//
// TCL author    : TM
// TCL file      : tm_phot_dpu_dmc_setup.tcl
// CUS author    : DAC
// Script file   : PHOT_dpu_dmc_setup.txt 
//
// Input arguments
// type    name         description
//
// Return values
// Type    Name      Default      Description
//
// Description   : This script will set the DPU HK list, write and set the
//                 FPGA timing parameters (if necessary), set the
//                 synchronization source for the sequencer, forward data
//                 to the packet encoder and validate the sciece data
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : 
// 
// Version       : 1.1
// History       : 0.1 11-apr-2005 creation by DAC; based on V1.2 of TM
//                 0.2 13-apr-2005 DAC Graded as a procedure
//                 0.3 20-oct-2005 DAC Use FPGA parameters from SPEC
//               : 1.0 12-apr-2006 update by TM for new FPGA parameter settings
//                                 taking out switch-on of temp sensors
//                 1.1 11-aug-2006 TM delay(1) introduced between sequential
//                                 FPGA parameter settings
//                 2.0 21-nov-2006 Removed "duree" information; introduced
//                                 CAL file holding FPGA parametrer phase_inc
//                                 Spelled out FPGA parameters
//                 2.1 15-jan-2008 Script renamed *txt for PV database, added
//                                 demanded TC as per SCR-0797  
//		   2.2 15-Jul-2008 update IA_CHOP address
//		   2.3 11-nov-2008 change phase_shift_reg to 1
procedure PHOT_dpu_dmc_setup {
    string hk_list = "BOTH Array" in ["BOTH Array","BLUE Array","RED Array"];
    /* sync source                                  */
    /* 1 = synchronize on blue spectrometer ramps   */
    /* 2 = synchronize on red spectrometer ramps    */
    /* 4 = synchronize on BOL readouts              */
    int sync_srce = 4;
}{
    // Start regular HK
    Pacs_DPU_SET_HK_LIST("PHOT",hk_list);
    // Add chop_ia information as per SCR-0797 
    // Description of DMC_WRT_DIAG_HK_CONF_TAB from DEC/MEC User Manual:
    //
    // Custom Hk Configuration Table : This buffer contains configuration data
    // allowing us to increase the number of available HK measure without 
    // recompiling the application. The table is composed of 10 entries each of 
    // them being 5 words long:
    //f1. the address of the memory area to monitor
    //    int f1 = 0x3469f;
    int f1 = 0x346ab;
    //f2. the size (in words) of the memory area to monitor
    int f2 = 0x1;
    //f3. the size (in bytes) of the memory area to monitor
    int f3 = 0x2;
    //f4. a pointer to a function performing the monitoring (if you want to use this
    //    field, it is highly probable that you need to patch your code anyway to 
    //    upload the new monitoring function).
    int f4 = 0x0;
    //f5. the validity at startup (0 = invalid, 1 = valid)
    int f5 = 0x1;
    // All the fields are initialized to zero at startup. (for advanced users only)   
    {int}[] params = [{f1},{f2},{f3},{f4},{f5}];
    int[] forsum = [f1,f2,f3,f4,f5];
    int check_sum = checksum("int",forsum);
    int wrdLen = 5;
    Pacs_DMC_WRT_DIAGHK_CONF_TAB(wrdLen,params,check_sum);
    int iBOL = 4;
    params = [{iBOL}];
    check_sum = checksum("int",[iBOL]);
    Pacs_DMC_WRT_BOL_REC_OPT(params,check_sum);
    // DEC/MEC User Manual; section 4.4.3
    // 1. and 2. Stop forwarding data to packet encoder (bit 2 set)
    int iPAR = 4;
    params = [{iPAR}];
    check_sum = checksum("int",[iPAR]);
    Pacs_DMC_WRT_B_DEC_REC_OPT(params,check_sum);
    Pacs_DMC_WRT_R_DEC_REC_OPT(params,check_sum);
    // 3. Upload DMC_WRT_TIMING_FPGA_PAR with {0,1,0,26,0x977602A,0x32}
    // Write and set FPGA timing parameters
    // DMC_WRT_TIMING_FPGA_PAR
    int sync_src_det = 0;
    // changes for Phase shift from 0 to 1
    int phase_shift_reg = 1;
    int bolc_freq_div = 0;
    int pd5_reg = 26;
    //int phase_inc: read from CAL-U file FPGA_params
    int ctrl_reg = 0x32;
    // Read phase_inc from CAL-U file FPGA_params. 
    // Here we always read the row "Plast". When updating the CAL-U file rename 
    // the existing "Plast" row to "Pold1", "Pold2", etc. and add the latest 
    // phase_inc in the new row "Plast" 
    int phase_inc = ilookup("FPGA_params","Plast","phase_inc");
    int[] aux = [sync_src_det,phase_shift_reg,bolc_freq_div,pd5_reg,phase_inc,ctrl_reg];
    check_sum = checksum("int",aux);
    {int}[] parlist = Array2grp_1(aux);
    // Write to register and activate
    Pacs_DMC_WRT_TIMING_FPGA_PAR(parlist,check_sum);
    // 4. Apply the new parameters
    Pacs_DMC_SET_TIMING_FPGA_PAR();
    // 5. Change the sync signal  
    Pacs_DMC_SYNCHRONIZE_ON_DET(sync_srce);
    // 6. Wait 1 second  
    delay(1);
    //7. Upload WRT_TIMING_FPGA_PAR with {0,1,0,26,0x977602A,0x22}
    ctrl_reg = 0x22;
    aux = [sync_src_det,phase_shift_reg,bolc_freq_div,pd5_reg,phase_inc,ctrl_reg];
    check_sum = checksum("int",aux);
    parlist = Array2grp_1(aux);
    // Write to register and activate
    Pacs_DMC_WRT_TIMING_FPGA_PAR(parlist,check_sum);
    // 8. Apply the new parameters
    Pacs_DMC_SET_TIMING_FPGA_PAR();
    // 9. Start forwarding data from BOL to SPU (bit 2 is clear)
    iBOL = 0;
    params = [{iBOL}];
    check_sum = checksum("int",[iBOL]);
    Pacs_DMC_WRT_BOL_REC_OPT(params,check_sum);
    // Validate science data photometry
    Pacs_DMC_VAL_SCI_DATA_BOTH();
}

// SpireBbEndObs
//
// $Id: SpireBbEndObs.txt,v 1.1 2007/08/02 10:15:44 kking Exp $
//
// Building Block to reconfigure after an engineering observation
//
//  17/11/2008 KJK: added sync() statement to round up total duration
//
block SpireBbEndObs SPIRE 3 {
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB End Obs  started");
    SpireMsg(2,"          $Id: SpireBbEndObs.txt,v 1.1 2007/08/02 10:15:44 kking Exp $");
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    delay(1);
    //
    // set STEP to one
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x0001)");
    Spire_SET_OBS_STEP_RAW(0x1);
    delay(1);
    //
    // Clear OBSID/BBID/STEP to null values
    //
    // set STEP to zero
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x0000)");
    Spire_SET_OBS_STEP_RAW(0x0);
    //
    tstr = SpireTimeStr(time());
    message("5          " + tstr + "Cmd: Spire_SET_BBID_RAW(0x80000000)");
    Spire_SET_BBID_RAW(0x80000000);
    delay(1);
    //
    int obsId = SpireNullObsid();
    tstr = SpireTimeStr(time());
    hstr = SpireHexStr(obsId,8);
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBSID_RAW(" + hstr + ")");
    Spire_SET_OBSID_RAW(obsId);
    //
    sync();
    //
    // ..... completion .....
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB End Obs   ended");
    SpireMsg(1,"  ..Obs Reconfiguration (" + (time() - t) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_PhotJfetVssTestC.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to perfomr VSS C test for photometer
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/21 V0.1: Initial version adapted from PJFET_Vss_TestC.txt 
//                  (undated, as of 2009/05/21 in fs2_test@lichfield by SDS)
//  
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_PhotJfetVssTestC SPIRE 14070 {
    double jfet_Vss_start = -1.0; //Starting JFET source voltage
    double jfet_Vss_end = -2.0; //ending JFET source voltage
    double jfet_Vss_step = -0.5; //steping JFET source volatge
    int ftime = 30; //wait time at each level;
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB PhotJfetVssTestC started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Calculate the number of levels:
    //     
    int n_levels = iround(abs((jfet_Vss_end - jfet_Vss_start) / jfet_Vss_step));
    int[] jfet_Vss_levels = [0x0];
    for(int j = 0 .. n_levels) {
        jfet_Vss_levels[j] = iround((jfet_Vss_start + jfet_Vss_step * double(j)) / -5.0 * 255.0);
    }
    // //
    // //
    // Set data mode to nominal:
    //
    SpireSendDrcuCmd(0x843c0000,0);
    // //
    // //
    // Start data generation:
    // 
    SpireSendDrcuCmd(0x843e0001,0);
    delay(1);
    // //
    // //
    // Do loop over Jfet values:
    //
    int loop_cnt = 0;
    while(loop_cnt != n_levels + 1) {
        delay(1);
        for(int k = 0 .. 11) {
            SpireSendDrcuCmd(0x84050000 + 0x10000 * k + jfet_Vss_levels[loop_cnt],0);
            delay(1);
            if(debug) {
                debug_print("levels is:" + jfet_Vss_levels[loop_cnt]);
            }
        }
        // Now set the TC JFET Vss
        SpireSendDrcuCmd(0x84140000 + jfet_Vss_levels[loop_cnt],0);
        delay(1);
        Spire_SET_OBS_STEP(0x2 + loop_cnt);
        delay(ftime);
        Spire_SET_OBS_STEP(0xffff);
        loop_cnt = loop_cnt + 1;
    }
    // Set Vss back to nominal value of -1.5 V
    for(int l = 0 .. 11) {
        SpireSendDrcuCmd(0x8405004c + 0x10000 * l,0);
        delay(1);
    }
    // Now set TC JFET Vss back to nominal value of -1.5 V
    SpireSendDrcuCmd(0x8414004c,0);
    delay(1);
    // Stop data generation and flush DCU FIFO  
    SpireSendDrcuCmd(0x843e0000,0);
    delay(1);
    message("5          " + time() + "Cmd: Spire_FLUSH_FIFO(0x1000)");
    Spire_FLUSH_FIFO(0x1000);
    delay(3);
    message("5          " + time() + "Cmd: Spire_RESET_FIFOS(0x7000)");
    Spire_RESET_FIFOS(0x7000);
    delay(1);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB PhotJfetVssTestC ended");
    SpireMsg(1,"  .. BB PhotJfetVssTestC took " + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartupObs.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Script will set OBSID and reset the DRCU counter 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/05/01 V0.1: Initial version adapted from old StartObs.txt and 
//                  ClearObs.txt templates used in ILT; replaces old 
//                  SpireBbStartObs.txt script
// 2008/11/12 V0.2: Add setting of Obsmode parameter
//                  currently (for SOVT2) fixed to 0x3E8  == ENG_CAL_OBS 
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartupObs SPIRE 14001 {
    string obsmode = "ENG_CAL_OBS"; // Parameter to specify the configuration mode
}{
    // //
    // //
    // Set the OBSIDs for the current observation:
    //
    Spire_SET_OBSID($OBSID);
    //delay(1);
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    Spire_SET_BBID($BBID);
    delay(1);
    // //
    // //
    // Reset DRCU counter:
    //
    Spire_RESET_DRCU_COUNTERS();
    //delay(1);
    //
    // //
    // //
    // Set the MODE using the SET_OBS_MODE Spire command 
    //
    // int mode_id = ilookup("InstrumentConfigurations.txt",obsmode,"value");
    int mode_id = 1000;
    // Fixed for SOVT2
    Spire_SET_OBS_MODE(mode_id);
    // //
    // //
    // Set the BBID(s) to null:
    //
    Spire_SET_BBID(0x80000000);
    delay(1);
    //
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_CalGCO_FovMapFpgScan.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Spec FOV Mapping Line Scan (FPG Scan)'   
//
//         in * line_scan_with_off_pointing * mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/11/06 V0.1: Initial version, adapted from
//                  SpirePhoto_CalGCO_FovMapFpgScan (2008/09/16 V0.2)
// 		    allow scan along 60deg symmetry line
// 2008/11/12 V0.2: Implement mode setting; Add isBright 
// 2009/03/02 V0.3: Add debug_print as input abd pass to low level scripts. 
//                  Use new SpireBb_EndObsAll and SpireBb_StartObsAll. Read 
//                  nominal bias frequency and bias dividerfrom new
//                  SpireTable_SpecModeParams. Implemented setting of
//                  datarates. Implemented isBright setting. Change call to 
//                  SpireBb_StartDcuData. Replace call to SpireProc_Set_ObsStep 
//                  with call to SpireBb_SetObsStep. Introduce
//                  SpireBb_WaitAtGcp at GCP and use SpireBbScanLine during 
//                  the line scanning to collect data within defined BBIDs. 
//                  Use SpireBb_SpecSetMode to set to SPECSTBY during SLEW and 
//                  FINAL_HOLD. Change calculation of gcp_period_min to match 
//                  SpirePhoto_CalGCO_FovMapFpgScan. Do no set obsStep to zero 
//                  in FINAL_HOLD this is already done in SpireBb_WaitAtGcp.
// 2009/03/04 V0.4: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Set gcp_time to 
//                  20 (desired value for SOVT2).
// 2009/05/07 V0.5: Add in move BSM/SMEC to hold/home at start. Add new 
//                  SpireBb_SmecHold to account for the fact that
//                  SpireBb_SmecMove2Home does not stop SMEC.
//                  Gather procedures at start and end in separate BB. 
// 2009/10/28 V1.0: (SCR-SPIRE-2118) Allow SSO. Hardcode gcp_period for SSOs. 
//
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in SPECSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for all three arrays and could be taken from following cal table: 
//   SpireTable_SpecModeParams.txt
//
//  3) That currently the gyro reconstruction is only available for 
//     non-SSO targets.  
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_CalGCO_FovMapFpgScan {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target [deg]
    double dec = 0.0 in [-90.0,90.0]; // DEC of target [deg]
    int naifid = 0; // Put '0' to use RA and DEC, otherwise put correct 'NAFID'
    bool isBright = false; // Use settings for bright source (==tick)
    /* */
    bool refSelected = true; // ExpHSpot (refSelected) parameter
    bool refByOffset = true; // ExpHSpot (refByOffset) parameter   
    double raoff = 0.0 in [0.0,360.0]; // RA of GCP position, or relative offset [deg]
    double decoff = 0.0 in [-90.0,90.0]; // DEC of GCP position, or relative offset [deg]
    string ib = "S24_0"; // Central aperture (defined in SIAM) of raster
    double d1 = 500.0 in [20.0,7200.0]; // Length of the scan line along scan axis [arcsec] 
    double d2 = 31.4 in [2.0,480.0]; // Spacing of adjacent scan lines along orthogonal axis [arcsec]
    int n = 9 in [1,240]; // Number of raster lines or scan lines.
    double rate = 30.0 in [0.1,60.0]; // Scan rate of a line scan [arcsec/s]
    string scan_dir = "plusY" in ["plusY","minusY","plusZ","minusZ","30degplusYZ","210degminusYZ","60degplusYZ","240degminusYZ"]; // Scan direction of first line 
    int gcp_time = 20; // Time spend at GCP (gyro calibration position) [s]
    int gcp_period = 600; // Maximum time between successiv GCP visits (Note, set to 64800 for SSOs!)[s]
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParam    
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Current restrictions:
    //
    if(naifid != 0) {
        message("Note, currently no SSO objects are allowed if gyro reconstruction is needed. Using SSO tracking the visists to the OFF position are minimised by setting gcp_period to 18h.");
        gcp_period = 64800;
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = false;
    bool fts = !phot;
    //
    // Start timing of script:
    int start = time();
    int linestart = time();
    //
    // Line counter (start at 1): 
    int linecount = 1;
    //
    // GCP counter (start at 1):
    int gcpcounter = 1;
    //
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_PcalLevelCheckLevels.txt";
    string tabName06 = "SpireTable_BsmNominalSettings.txt";
    string tabName09 = "SpireTable_SmecNominalSettings.txt";
    //
    // Currently hardcoded version parameter:
    //
    string version09 = "v00";
    // Version in cal table SpireTable_SmecNominalSettings
    string version06 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    //
    // Currently hardcoded parameter:
    // Is (==tick) the DCU currently sampled? 
    bool dcuData = false;
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS33";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "SEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Increase scan length to allow time to mark start/end of the scan:
    //
    int tStart = 2;
    int tEnd = 2;
    // Note: the two 2 seconds are justified in SpireBbScanLine.txt
    d1 = d1 + double(tStart + tEnd) * rate;
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version06;
    tabName = tabName06;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Read SMEC home position from calibration file:
    //
    tarCol = "Home";
    tabName = tabName09;
    selVal = version09;
    int smecHomePosn = ilookup(tabName,selVal,tarCol);
    //
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartFovMapFpgScan(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug));
    // 
    // BBs carried out when the pointing is reached:
    int tinithold = duration(SpireBb_SpecOffsetAuto(dcuData,debug)) + duration(SpireBb_StartDcuData());
    //
    // BB carried out during pointing:
    //int tp = 0;
    //
    // BB carried at off position:
    int top = duration(SpireBb_WaitAtGcp(gcp_time,debug));
    // == Time spent at the OFF position.
    //
    // BB carried out at the end:
    int tfinalhold = duration(SpireBb_EndFovMapFpgScan(phot,hold_chop,hold_jigg,isBright,version01,version02,debug)) + duration(SpireBb_StopDcuData());
    // 
    // Debug_printing?
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        //debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // Fixed parameters for pointing mode:
    //  
    bool fixed = false;
    // Pattern orientation (true==sky; false==array)
    double yoff = 0.0;
    // Offset of pattern in the direction of the +Y
    double zoff = 0.0;
    // Offset of pattern in the direction of the +Z
    int nrepeat = 1;
    // [1,1200] Number of repetitions of the pattern.
    int thold = 0;
    // The duration of the hold when nhold>0.
    int nhold = 0;
    // Number of nods or raster points or scan lines before
    //              // performing a hold.
    int nload = 0;
    // The number of slews (e.g. nods) before performing 
    //             // a load operation
    int tloadmin = 0;
    // The minimum duration of a load operation.
    // //
    // //
    // Select scan direction: 
    //
    double patt = 90.0;
    // Rotation angle of the pattern
    //
    if(scan_dir == "plusY") {
        patt = 90.0;
    }
    if(scan_dir == "minusY") {
        patt = 270.0;
    }
    if(scan_dir == "plusZ") {
        patt = 0.0;
    }
    if(scan_dir == "minusZ") {
        patt = 180.0;
    }
    if(scan_dir == "30degplusYZ") {
        patt = 30.0;
    }
    if(scan_dir == "210degminusYZ") {
        patt = 210.0;
    }
    if(scan_dir == "60degplusYZ") {
        patt = 60.0;
    }
    if(scan_dir == "240degminusYZ") {
        patt = 240.0;
    }
    // //
    // //
    // Select the number (k) of scan lines before performing a measurement
    // at the GCP: 
    //
    // Start with k=1:
    //
    int k = 1;
    //
    // Calculate times in pointing mode:
    //
    int[] ts_tr = line_scan_with_off_pointing(false,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,fixed,patt,yoff,zoff,n,d1,d2,rate,k,top,raoff,decoff,nrepeat,thold,nhold,tloadmin,nload);
    // returns: {tobs, tslew, tacc, tdec, tl, tll, tsop, tload, tend}
    if(debug) {
        debug_print("Pointing vector for k=1: " + ts_tr);
    }
    int tacc = ts_tr[2];
    // acceleration time
    int tdec = ts_tr[3];
    // deceleration time
    int tl = ts_tr[4];
    // time for actual scan of single line in map area 
    int tll = ts_tr[5];
    // turnaround time bewteen 2 lines 
    int tsop = ts_tr[6];
    // slew time from/to OFF position 
    //                      Note: 'tsop' includes acceleration/deceleration time
    //
    // Calculate/check minimum time between successive visits to GCP position:
    //
    int gcp_period_min = tl + 2 * tsop + top;
    //
    if(debug) {
        debug_print("gcp_period_min: " + gcp_period_min);
    }
    if(gcp_period_min > gcp_period) {
        error("Maximum time between successiv GCP visits smaller than minimum time between two possible visits!");
    }
    //
    // Loop to find best k:
    //
    // Calculate time between two offset positions:  
    int tboff = k * tl + (k - 1) * tll + (k - 1) * (tacc + tdec) + 2 * tsop + gcp_time;
    if(debug) {
        debug_print("Time between two offset positions: " + tboff);
    }
    //
    do {
        k = k + 1;
        //      
        // Calculate new time between two offset positions:  
        tboff = k * tl + (k - 1) * tll + 0 * (tacc + tdec) + 2 * tsop + gcp_time;
        if(debug) {
            debug_print("k is now: " + k);
            debug_print("New time between two offset positions: " + tboff);
        }
    } while (tboff < gcp_period);
    //
    // Set best k:
    //
    if(k > 1) {
        // use previous k values
        k = k - 1;
    }
    if(k > n) {
        // k must not be larger than number of lines
        k = n;
    }
    if(debug) {
        debug_print("selected k is: " + k);
    }
    // //
    // //
    // Set pointing mode:
    //
    //int[] ts = line_scan_with_off_pointing(true,tslewmin,tih,tfh,ib,naifid,
    // ra,dec,fixed,patt,yoff,zoff,n,d1,d2,rate,k,top,raoff,decoff,nrepeat,
    // thold,nhold,tloadmin,nload);
    //
    int[] ts = line_scan_with_off_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,fixed,patt,yoff,zoff,n,d1,d2,rate,k,top,raoff,decoff,nrepeat,thold,nhold,tloadmin,nload);
    //
    // //
    // //
    // Fill in timings of actual pointing mode:
    tacc = ts[2];
    // acceleration time
    tdec = ts[3];
    // deceleration time
    tl = ts[4];
    // time for actual scan of single line in map area 
    tll = ts[5];
    // turnaround time bewteen 2 lines 
    tsop = ts[6];
    // slew time from/to OFF position 
    //                      Note: 'tsop' includes acceleration/deceleration time
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
        debug_print("Time for actual scan of single line in requested area: " + tl);
    }
    // //
    // //
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //     
            SpireBb_StartFovMapFpgScan(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD (spacecraft is idling at source)
            //
            //delay(tinithold);
            // //
            // //
            // Set offsets:
            //
            SpireBb_SpecOffsetAuto(dcuData,debug);
            // //
            // //
            // Start data generation before scan: 
            //
            SpireBb_StartDcuData();
            //
        }
        if(state[0] == 4) {
            // STATE = OFF position
            // //
            // //
            // Show time elapsed between visits to GCP:
            //
            int t = time() - start;
            if(gcpcounter > 1) {
                message("Time elapsed since last visit to GCP: " + t);
                if(debug) {
                    debug_print("Time elapsed since last visit to GCP: " + t);
                }
            }
            gcpcounter = gcpcounter + 1;
            //
            // Reset timer:           
            start = time();
            // //
            // //
            // Wait at GCP:
            //
            SpireBb_WaitAtGcp(gcp_time,debug);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activities )
            // //
            // //
            // Stop data generation after scan: 
            //
            SpireBb_StopDcuData();
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            SpireBb_EndFovMapFpgScan(phot,hold_chop,hold_jigg,isBright,version01,version02,debug);
            //
        }
        if(state[0] == 6) {
            //delay(thold);
        }
        if(state[0] == 8) {
            // STATE =  ( line )
            //
            // //
            // //
            // Start timing:
            //
            int tscan = time();
            // //
            // //
            // Debug printing
            //
            if(debug) {
                debug_print("state[0]: " + state[0]);
                debug_print("state[1]: " + state[1]);
                debug_print("state[2]: " + state[2]);
                debug_print("linecount: " + linecount);
            }
            // 
            if(linecount == 1) {
                linestart = time();
            } else {
                int tline = time() - linestart;
                if(debug) {
                    debug_print("Time elapsed since first line: " + tline);
                }
            }
            // //
            // //
            // Wait while scan is performed:
            //
            SpireBbScanLine(tl,linecount);
            linecount = linecount + 1;
            //
            //
        }
        if(state[0] == 9) {
            //delay(tloadmin);
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_Cal_PhaseUp.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Phot Phase Up' 
//
//  in *basic_fine_pointing* or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/05/07 V0.1: Initial version adapted from 
//                  Mode_ILT_PERF_DPH_P.txt (v1.4 2008/01/31 20:24:33)
// 2008/05/08 V0.2: Add proper limit for bias amplitude, frequency, and 
//                              sampling rate
// 2008/06/09 V0.3: Changed name to be conform with new naming convention.
//                  Allow to input different bias amplitude for each array. 
// 2008/06/20 V0.4: Move SpireBb_StartupObs to start
// 2008/07/03 V0.5: Renumber version; add limits for number_steps and 
//                  step_size; change default biasfreq; 
//                  SpireProc_Set_PhotNominalbias changed name; 
//                  SpireBb_PhotFSetupData has extra parameter;
//                  add PTC bolometers to input
// 2008/08/15 V0.6: Remove test number; Adapt to change of name  
//                  of low level script SpireProc_CalcParam_PhotPhaseUp.txt
//                  Adapt to change in call to low level script 
//                  SpireProc_CalcParam_BiasFreqSampFreq.txt 
// 2008/09/22 V0.7: Allow 'no pointing' as input option; Adapt debug printing
// 2008/11/11 V0.8: Improve 'no pointing' HSpot pop-up info at tick mark
// 2008/11/12 V0.9: Implement mode setting; Add isBright 
//                  Change ENGCALOBS to ENG_CAL_OBS 
// 2009/02/01 V1.0: Add debug_print as input and pass it to some low level 
//                  scripts. Use new SpireBb_EndObsAll and SpireBb_StartObsAll. 
//                  Read nominal bias frequency and bias divider from new
//                  SpireTable_DetectorSettings.txt. Implemented message 
//                  if activating isBright setting. Implemented setting 
//                  of datarates. Replace SpireProc_Set_PhotNominal by
//                  SpireProc_Set_FreqSampAmpPhasNominal. Change Hspot 
//                  description of ftime.
// 2009/02/17 V1.1: Use SpireBb_PhotSetMode to set to PHOTSTBY during 
//                  SLEW and FINAL_HOLD. Read boresight from 
//                  SpireTable_OpsParms. New setting of datarates. 
//                  Replace call to SpireBb_PhotFSetupData by call to 
//                  SpireBb_DcuSetFreqSamp, SpireBb_PhotFSetPhase, and 
//                  SpireBb_PhotFSetBiasAmpl. Correct first phase is now 
//                  set during SLEW instead of target phase 
// 2009/02/19 V1.2: Elevate version05 to input.
// 2009/03/04 V1.3: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Replace 'message' with
//                  'error' when isBright is used.
// 2009/03/30 V1.4: Fix bug in call to SpireBb_StartObsAll (see SCR-1329).
//                  Updated unit in description of input biasmV_p.. 
// 2009/05/06 V1.5: Add in move BSM to hold at start. Gather procedures at 
//                  start and end in separate BB. 
// 2009/06/05 V1.6: Hardcode STBY 'v00' in EndBB (SPR-1477)
// 2010/01/06 V1.7: Edit default parameters for input bias ampl. and number 
//                  of steps to one size = 16, raw step size=4 (SCR-SPIRE-2300)
//
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in PHOTSTBY at beginning 
//  (i.e. bias amplitude, phase, frequency [mclkdiv,biasdiv] are nominal)
//
//  2) Phases are user input  
//
//  3) Bias frequency and sampling rate are user inputs both in Hz. They
//     are translated in the script to the Hex values of mclkdiv and biasdiv.
//
//  4) Boresight of array can be read from following cal table:
//     SpireTable_OpsParms.txt  
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhoto_Cal_PhaseUp {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    bool isBright = false; // Use settings for bright source (==tick)
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    double biasfreq = 130.2 in [70.0,200.0]; // Bias frequency [Hz]
    double samplerate = 18.6 in [1.0,20.0]; // Sampling rate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    double biasmV_psw = 23.056 in [0.0,127.813]; // PSW Bias amplitude (zero2peak) [mV]
    double biasmV_pmw = 25.221 in [0.0,128.625]; // PMW Bias amplitude (zero2peak) [mV]
    double biasmV_plw = 22.793 in [0.0,129.159]; // PLW Bias amplitude (zero2peak) [mV]
    double biasmV_ptc = 127.631 in [0.0,254.265]; // PTC Bias amplitude (zero2peak) [mV]
    double target_phase = 183.0 in [0.0,360.0]; // Central phase shift (target phase) [degree]
    int number_steps = 16 in [1,127]; // Number of steps to one side [int]
    int step_size = 4 in [1,20]; // Raw step size (1 step==1.411 degrees) [dec(HEX)]
    int ftime = 10; // Time at each phase [s]
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version05 = "v00"; // Version in cal table SpireTable_OpsParms.txt
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Check for is bright setting: 
    //
    if(isBright) {
        isBright = false;
        error("IsBright does not make sense while doing phase ups. Try again!");
    }
    // //
    // //
    // Declare some variable:
    //
    //
    // Photometer or FTS:
    bool phot = true;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    //
    // Currently hardcoded version and model parameter:
    //
    string version03 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    //
    // Dummy value for Spec script:
    // (needed but not used in phot script!)
    //
    int smecHomePosn = 3500;
    // SMEC home position
    int ssw_bias = 45;
    //
    int slw_bias = 45;
    //
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS11";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "PEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Calculate a raw phase value used for the initial setup:
    // 
    int target_phase_raw = iround(target_phase * 255.0 / 360.0);
    // //
    // //
    // Calculate list of phases:
    //
    int[] raw_phase_list = SpireProc_CalcParam_PhaseUp(target_phase,number_steps,step_size,debug);
    if(debug) {
        debug_print("Phase list [dec(HEX)]: " + raw_phase_list);
    }
    // //
    // //
    // Convert user input to Hex values:
    //
    // for bias frequency and sample rate: 
    //  
    int[] hexvalues = SpireProc_CalcParam_BiasFreqSampFreq(biasfreq,samplerate,fts,debug);
    int mclkdiv = hexvalues[0];
    int biasdiv = hexvalues[1];
    if(debug) {
        debug_print("Hex values of mclkdiv/biasdiv are: " + mclkdiv + " " + biasdiv);
    }
    //
    // for bias amplitude:
    //
    int[] biashex = SpireProc_CalcParam_PhotBiasConvert(biasmV_psw,biasmV_pmw,biasmV_plw,biasmV_ptc,debug);
    int psw_bias = biashex[0];
    int pmw_bias = biashex[1];
    int plw_bias = biashex[2];
    int ptc_bias = biashex[3];
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version03;
    tabName = tabName03;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // // // // // // // // // // // // // // // // 
    // // // // // // // // // // // // // // // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    //
    int tslewmin = duration(SpireBb_StartPhaseUp(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,ssw_bias,slw_bias,raw_phase_list,debug));
    // 
    // BBs carried out when the pointing is reached:
    if(pointing) {
        int tinithold = 0;
    } else {
        tinithold = tslewmin;
    }
    //
    // BB carried out during pointing:
    int tp = duration(SpireProc_Exec_PhotPhaseUp(raw_phase_list,ftime,debug));
    //
    // BB carried out at the end:
    int tfinalhold = duration(SpireBb_EndPhaseUp(phot,isBright,version01,version02,debug));
    // 
    // Debug_printing?
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // // 
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,0,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartPhaseUp(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,ssw_bias,slw_bias,raw_phase_list,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            //
            if(!pointing) {
                // //
                // //
                // Startup observation: 
                //
                SpireBb_StartPhaseUp(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,ssw_bias,slw_bias,raw_phase_list,debug);
                //
            }
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            // //
            // //
            // Execute stepping through phase list:
            //
            SpireProc_Exec_PhotPhaseUp(raw_phase_list,ftime,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            //
            SpireBb_EndPhaseUp(phot,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Exec_BsmPidTuning.txt
//
///////////////////////////////////////////////////////////
//
//  Procedure to tune BSM PID
//
///////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/30 V0.1: Initial version adapted from
//                  SPIRE_IST_BSM_CHOP_POS1.txt (SDS, email 30.03.2009)
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Exec_BsmPidTuning {
    int vmId = 71; // Raw VM table number [Dec(Hex)]
    int vmIndex = 0; // Raw VM index [Dec(Hex)]
    int nParms = 10; // Number of parameters passed to VM
    double chopf = 2.0; // Chop frequency [Hz] 
    int ftime = 15; // Read-out time [s]
    double framerate = 125.0; // Specifies the MCU framerate [Hz] (photometer)
    double biasdivHz = 18.6; // Sampling rate [Hz] (photometer)
    bool fts = false; // FTS or photometer (for dcumode)
    int on_source_chop = 0xb600; // On source chop position
    int on_source_jiggle = 0x9a60; // On source jiggle position
    int off_source_chop = 0x6a28; // Off source chop position
    int off_source_jiggle = 0x9a60; // Off source jiggle position
    double chopkp_range = 1.0; // Percentage half-range for tuning Chop Kp around ILT nominal values (+/1%)
    double chopki_range = 10.0; // Percentage half-range for tuning Chop Ki around ILT nominal values (+/1%)
    double chopkd_range = 10.0; // Percentage half-range for tuning Chop Kd around ILT nominal values (+/1%)
    int nkp = 1; // Number of steps for Chop Kp for half-range
    int nki = 3; // Number of steps for Chop Ki for half-range
    int nkd = 3; // Number of steps for Chop Kd for half-range
    string version03 = "v00"; // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial"; // Model in cal table SpireTable_BsmNominalSettings
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string version = "";
    string tabName = "";
    string tarCol = "";
    //
    if(fts) {
        // DCU data mode (4 == Full spectrometer):
        int dcumode = 4;
    } else {
        // DCU data mode (0 == Full photometer):
        dcumode = 0;
    }
    //
    // Hardcoded calibration tables:
    //
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    // //
    // //
    // Retrieve Nominal BSMPID parameter for close loop operation from caltable:
    //
    version = version03;
    tabName = tabName03;
    //
    // Name of column for selecting:
    string selCol = "model";
    //
    // Value of 'string' selector:
    string selVal = model;
    //
    // Read chopkp from calibration table:  
    //
    tarCol = "chop_kp";
    int chopkp = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Read chopki from calibration table:  
    //
    tarCol = "chop_ki";
    int chopki = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Read chopkd from calibration table:  
    //
    tarCol = "chop_kd";
    int chopkd = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    if(debug) {
        debug_print("chopkp: " + chopkp);
        debug_print("chopki: " + chopki);
        debug_print("chopkd: " + chopkd);
    }
    // //
    // //
    //
    // Calculate step sizes for Chop Kp, Ki and Kd:
    //
    int kpstep = iround(chopkp_range * double(chopkp) / (double(nkp) * 100.0));
    int kistep = iround(chopki_range * double(chopki) / (double(nki) * 100.0));
    int kdstep = iround(chopkd_range * double(chopkd) / (double(nkd) * 100.0));
    if(debug) {
        debug_print("kpstep, kistep, kdstep: " + kpstep + " " + kistep + " " + kdstep);
    }
    // //
    // //    
    // Calculate BSM chop parameters:
    //
    int[] chopparam1 = SpireProc_CalcParam_BsmSetup(ftime,chopf,biasdivHz,framerate,debug);
    int ncycles = chopparam1[0];
    int chop_period = chopparam1[1];
    int dcusample = chopparam1[2];
    int dcudelay = chopparam1[3];
    int bsmsample = chopparam1[4];
    // //
    // //
    // For each set of PID parameters, perform a number fo chop cycles 
    //      to establish the optimum PID values:
    //
    // First obsstep:
    int obsstep = 1;
    //
    for(int i = -nkp .. nkp) {
        int kp = chopkp + i * kpstep;
        for(int j = -nki .. nki) {
            int ki = chopki + j * kistep;
            for(int k = -nkd .. nkd) {
                int kd = chopkd + k * kdstep;
                if(debug) {
                    debug_print("kp, ki, kd: " + kp + " " + ki + " " + kd);
                }
                SpireBb_SetBsmChopPid(kp,ki,kd,debug);
                //
                SpireBb_Chop(vmId,vmIndex,nParms,on_source_chop,on_source_jiggle,off_source_chop,off_source_jiggle,ncycles,chop_period,dcumode,dcusample,dcudelay,bsmsample,obsstep,debug);
                obsstep = obsstep + 1;
            }
        }
    }
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Set_SpecDetOffsets
//
///////////////////////////////////////////////////////////
//
// Procedure to set the spectrometer detector offsets 
//
//
//
///////////////////////////////////////////////////////////
//
// K.King:  
// 2010/03/31 V1.0: Initial version created for SCR Spire-2459
//
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_SpecDetOffsets {
    bool debug = false;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"    " + tstr + ": Proc SetSpecOffsets started");
    SpireMsg(4,"          $Id:$");
    //
    // set detector offsets
    //
    // set DCU data mode  to Auto Offset 
    SpireSendDrcuCmd(0x843c0014,0);
    // start auto offset generation
    SpireSendDrcuCmd(0x843e0001,0);
    delay(15);
    // stop auto offset generation
    SpireSendDrcuCmd(0x843e0000,0);
    //
    // dump detector offsets
    //
    // set DCU data mode to get offset data
    SpireSendDrcuCmd(0x843c001c,0);
    // start offset data dump
    SpireSendDrcuCmd(0x843e0001,0);
    //  set datarate
    double rate = SpireProc_GetTableEntryDouble("SpireTable_Datarates.txt","mode","SOffsets","DCU","v00",debug);
    data_rate(rate);
    delay(5);
    // stop offset data dump 
    SpireSendDrcuCmd(0x843e0000,0);
    data_rate(0.0);
    //
    // flush offset data
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(2);
    //
    //  reset detectors for operations
    //
    int datamode = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","Scan","dcuDataMode","v00",debug);
    SpireSendDrcuCmd(0x843c0000 + datamode,0);
    //
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"    " + tstr + ": Proc SetSpecOffsets ended");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_Cal_PtcPwr.txt
//
///////////////////////////////////////////////////////////////////////////
// 
//  CUS script for: 'CoP: PtcPwr' 
//
//  in *basic_fine_pointing* or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/30 V0.1: Initial version adapted from
//                  SPIRE_IST_PTC_PWR (SDS, email 30.03.2009)
// 2009/05/06 V0.2: Add in move BSM to hold at start. Gather procedures at 
//                  start and end in separate BB. 
// 2009/06/05 V1.0: Hardcode STBY 'v00' in EndBB (SPR-1477)
//
///////////////////////////////////////////////////////////////////////////
//
//  Script assumes that:
//
//  1)  Instrument is in PHOTSTBY at beginning 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Boresight of array can be read from following cal table:
//     SpireTable_OpsParms.txt   
//
//  Note: Script is written for no_pointing as baseline, i.e. it is 
//        not properly using the SLEW time to setup.
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhoto_Cal_PtcPwr {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; // NAIF identifier
    bool isBright = false; // Use settings for bright source (==tick)
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    int[] ptc_curr = [0x0,0x200,0x400,0x600,0x800,0xa00,0xc00,0xe00,0xfff,0x0]; // IST default values for the PTC current levels
    int ftime = 1400; // Time at each PTC Heater setting [s]
    int twait = 600; // Wait time between setting PTC current and resetting offsets [s]
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version05 = "v00"; // Version in cal table SpireTable_OpsParms.txt
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = false; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Check for is isPcal setting: 
    //
    if(isPcal) {
        isPcal = false;
        error("IsPcal does not make sense here! Try again or file your complaintand send it to Sunil.");
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = true;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_StdLoadCurveLevels.txt";
    string tabName04 = "SpireTable_BsmNominalSettings.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    //
    // Currently hardcoded version and model parameter:
    //
    string version04 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS13";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "PEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version04;
    tabName = tabName04;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // // // // // // // // // // // // // // // // 
    // // // // // // // // // // // // // // // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartPtcPwr(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,debug));
    // 
    // BBs carried out when the pointing is reached:
    if(pointing) {
        int tinithold = duration(SpireBb_PhotOffsetAuto(debug));
    } else {
        tinithold = tslewmin + duration(SpireBb_PhotOffsetAuto(debug));
    }
    //
    // BB carried out during pointing:
    int tp = duration(SpireProc_Exec_PtcPwr(ptc_curr,ftime,twait,debug));
    //
    // BB carried out at the end:  
    int tfinalhold = duration(SpireBb_EndPtcPwr(phot,isBright,version01,version02,debug));
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartPtcPwr(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation:
                //
                SpireBb_StartPtcPwr(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,debug);
                //
            }
            // //
            // //
            // Set offsets:
            //
            SpireBb_PhotOffsetAuto(debug);
            //
            //
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            // //
            // //
            // Execute loop:
            //
            SpireProc_Exec_PtcPwr(ptc_curr,ftime,twait,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            //
            SpireBb_EndPtcPwr(phot,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

//CLName: SpireBb_LoadTableMonitor
//VMVersion: 2.8
//CLVersion: 2.8
//CLCVSId: $ID$
//TableId: 0x05
//TableLength: 0x91a
//Date: 100726152800
// 26/07/2010: SDS
//                      Manually lowered the SHUNTTEMP low warning limit from 1.6K to 1.44K
//                       - equivalent to altering the RAW high warning limit from 0xFFFFEE08 to 0xFFFFF054) 
//                      Did not generate the new Monitor table using wincomp because the update is minor.
//                      See SPIRE-SCR-2572
//
block SpireBb_LoadTableMonitor SPIRE 3800 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableMonitor started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0x05
    Spire_SET_TABLE(0x5,0x91a);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x5,0x0,38,[{0x1},{0x40060000},{0x8080ffff},{0x2},{0x9000000},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x2},{0x40060000},{0xc080ffff},{0x500},{0x500},{0x1ff},{0x1ff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0x3},{0x40060000},{0x40c0ffff}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x26,38,[{0x500},{0x500},{0x3ff},{0x3ff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0x4},{0x40060000},{0xc080ffff},{0x500},{0x500},{0x2ff},{0x2ff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0x5},{0x40060000},{0xc080ffff},{0x601},{0x601}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x4c,38,[{0x5ff},{0x5ff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0x6},{0x40060000},{0x8080ffff},{0x1},{0x600},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0x7},{0x40060000},{0xc080ffff},{0x501},{0x501},{0x2ff},{0x2ff}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x72,38,[{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0x8},{0x40060000},{0x40c0ffff},{0x400},{0x400},{0x2ff},{0x2ff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0x9},{0x4320000},{0x40c0ffff},{0x51},{0x51},{0x4f},{0x4f},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x98,38,[{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0xa},{0x4320000},{0xc0ffff},{0x1},{0x50},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0xb},{0xa8870000},{0x80800001},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0xbe,38,[{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0xc},{0xa8870000},{0x80800002},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0xd},{0xa8870000},{0xc00004},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0xe4,38,[{0x0},{0x0},{0x0},{0x1},{0x1},{0xe},{0xa8850000},{0x80800001},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0xf},{0xa8850000},{0x80800002},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x10a,38,[{0x0},{0x10},{0xa8850000},{0x80800004},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x11},{0xa8850000},{0x80800008},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x12},{0xa8850000},{0x80800010}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x130,38,[{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x13},{0xa8850000},{0x80800020},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x14},{0xa8850000},{0x80800040},{0x1},{0x0},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x156,38,[{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x15},{0xa8850000},{0x80800080},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x16},{0xa8850000},{0x80800100},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x17c,38,[{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x17},{0xa8850000},{0x80800200},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x18},{0xa8850000},{0x80800400},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x1a2,38,[{0x0},{0x0},{0x19},{0xa8850000},{0x80800800},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1a},{0xa8850000},{0x80801000},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1b},{0xa8850000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x1c8,38,[{0x80802000},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1c},{0xa8850000},{0x80804000},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1d},{0xa8850000},{0x80808000},{0x1},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x1ee,38,[{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1e},{0xa8860000},{0x80800001},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1f},{0xa8d00000},{0xc0c0ffff},{0x6d86},{0x6b83},{0x677e},{0x657c},{0xc0000000},{0xc0000000},{0xe0ff0000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x214,38,[{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x20},{0xa8cf0000},{0xc0c0ffff},{0x6b23},{0x69fc},{0x67ae},{0x6687},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x21},{0xa8ce0000},{0xc0c0ffff},{0xffff9979},{0xffff9852},{0xffff9604},{0xffff94dd},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x23a,38,[{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x22},{0xa8d10000},{0xc0c0ffff},{0x4665},{0x4332},{0x3ccc},{0x3998},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x23},{0x99e00000},{0xc0c0ffff},{0xffff9c5b},{0xffff9bae},{0xffff9a55},{0xffff99a9},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x260,38,[{0x0},{0x0},{0x1},{0x2},{0x24},{0x99e30000},{0xc0c0ffff},{0xffff9b17},{0xffff9ac0},{0xffff9a12},{0xffff99bb},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x2},{0x25},{0x99e40000},{0xc0c0ffff},{0x6622},{0x65cb},{0x651d},{0x64c6},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x286,38,[{0x1},{0x2},{0x26},{0x99e10000},{0xc0c0ffff},{0xffff98b6},{0xffff985f},{0xffff97b1},{0xffff975a},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x2},{0x27},{0x99e20000},{0xc0c0ffff},{0x6813},{0x67c4},{0x6716},{0x66bf},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x2}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x2ac,38,[{0x28},{0x8c3f000e},{0xc0c0ffff},{0xffffad40},{0xffffac66},{0xffffaab1},{0xffffa9d6},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x29},{0x8c3f000f},{0xc0c0ffff},{0xffffce89},{0xffffcdaf},{0xffffcbfa},{0xffffcb1f},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x2a},{0x8c3f0010}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x2d2,38,[{0xc0c0ffff},{0x34ea},{0x3410},{0x325b},{0x3180},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x2b},{0x8c3f0011},{0xc100ffff},{0xffffadad},{0xffffacd3},{0xffffab1e},{0xffffaa44},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0xb},{0x2c},{0x8c3f0012},{0xc100ffff},{0xffffe3df}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x2f8,38,[{0xffffe305},{0xffffe150},{0xffffe075},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0xb},{0x2d},{0x8c3f0013},{0xc100ffff},{0x1f94},{0x1eb9},{0x1d04},{0x1c2a},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0xb},{0x2e},{0x8c3f0014},{0xc100ffff},{0xffffae1b},{0xffffad40},{0xffffab8b}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x31e,38,[{0xffffaab1},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0xc},{0x2f},{0x8c3f0015},{0xc100ffff},{0xffffe3df},{0xffffe305},{0xffffe150},{0xffffe075},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0xc},{0x30},{0x8c3f0016},{0xc100ffff},{0x1f94},{0x1eb9},{0x1d04},{0x1c2a},{0xc0000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x344,38,[{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0xc},{0x31},{0x4210000},{0xc0c0ffff},{0xeaa},{0xe00},{0xcaa},{0xc00},{0xc0000000},{0xc0000000},{0xe0fe6701},{0xc0000000},{0xe0fe6701},{0xc0000000},{0x0},{0x0},{0x0},{0x0},{0x32},{0x4220000},{0xc0c0ffff},{0xea9},{0xdff},{0xcaa},{0xbff},{0xc0000000},{0xc0000000},{0xe0fe6701},{0xc0000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x36a,38,[{0xe0fe6701},{0xc0000000},{0x0},{0x0},{0x0},{0x0},{0x33},{0x4230000},{0xc0c0ffff},{0xea9},{0xe38},{0xcaa},{0xbff},{0xc0000000},{0xc0000000},{0xe0fe6701},{0xc0000000},{0xe0fe6701},{0xc0000000},{0x0},{0x0},{0x0},{0x0},{0x34},{0x4270000},{0xc0c0ffff},{0x8cc},{0x866},{0x799},{0x733},{0xc0000000},{0xc0000000},{0xe0fe6701},{0xc0000000},{0xe0fe6701},{0xc0000000},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x390,38,[{0x0},{0x0},{0x35},{0xa8c00000},{0xc0c0ffff},{0x886},{0x845},{0x67a},{0x659},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x36},{0xa8c10000},{0xc0c0ffff},{0x886},{0x845},{0x67a},{0x659},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x3b6,38,[{0x37},{0xa8c20000},{0xc0c0ffff},{0x886},{0x845},{0x67a},{0x659},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x38},{0xa8c30000},{0xc0c0ffff},{0x886},{0x845},{0x67a},{0x659},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x39},{0x99e50000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x3dc,38,[{0xc0c0ffff},{0xffff99ce},{0xffff9908},{0xffff939b},{0xffff9338},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x2},{0x3a},{0x99e60000},{0xc0c0ffff},{0xffff99ce},{0xffff9908},{0xffff939b},{0xffff9338},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x2},{0x3b},{0x99e70000},{0xc0c0ffff},{0xffff99ce}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x402,38,[{0xffff9908},{0xffff939b},{0xffff9338},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x2},{0x3c},{0x8c3f000d},{0xc0c0ffff},{0xffffd53b},{0xffffd2ac},{0xffffc0c1},{0xffffbf79},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x3d},{0x8c3f0000},{0xc0c0ffff},{0xffffd53b},{0xffffd2ac},{0xffffc0c1}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x428,38,[{0xffffbf79},{0xc0000000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x3e},{0x8c3f000c},{0xc0c0ffff},{0xffffd53b},{0xffffd2ac},{0xffffc0c1},{0xffffbf79},{0xc0000000},{0xc0000000},{0xe0fe6703},{0xc0000000},{0xe0fe6703},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x3f},{0x8c3f000b},{0xc0c0ffff},{0xffffd53b},{0xffffd2ac},{0xffffc0c1},{0xffffbf79},{0xc0000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x44e,38,[{0xc0000000},{0xe0fe6703},{0xc0000000},{0xe0fe6703},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x40},{0x8c3f000a},{0xc0c0ffff},{0xffffd53b},{0xffffd2ac},{0xffffc0c1},{0xffffbf79},{0xc0000000},{0xc0000000},{0xe0fe6703},{0xc0000000},{0xe0fe6703},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x41},{0x8c3f0009},{0xc0c0ffff},{0xffffd53b},{0xffffd2ac},{0xffffc0c1},{0xffffbf79},{0xc0000000},{0xc0000000},{0xe0fe6703}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x474,38,[{0xc0000000},{0xe0fe6703},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x42},{0x8c3f0008},{0xc0c0ffff},{0xffffd53b},{0xffffd2ac},{0xffffc0c1},{0xffffbf79},{0xc0000000},{0xc0000000},{0xe0fe6703},{0xc0000000},{0xe0fe6703},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x43},{0x8c3f0007},{0xc0c0ffff},{0xffffd53b},{0xffffd2ac},{0xffffc0c1},{0xffffbf79},{0xc0000000},{0xc0000000},{0xe0fe6703},{0xc0000000},{0xe0fe6703}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x49a,38,[{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x44},{0x8c3f0006},{0xc0c0ffff},{0xffffd53b},{0xffffd2ac},{0xffffc0c1},{0xffffbf79},{0xc0000000},{0xc0000000},{0xe0fe6703},{0xc0000000},{0xe0fe6703},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x45},{0x8c3f0005},{0xc0c0ffff},{0xffffd53b},{0xffffd2ac},{0xffffc0c1},{0xffffbf79},{0xc0000000},{0xc0000000},{0xe0fe6703},{0xc0000000},{0xe0fe6703},{0xc0000000},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x4c0,38,[{0x0},{0x0},{0x1},{0x1},{0x46},{0x8c3f0004},{0xc0c0ffff},{0xffffd53b},{0xffffd2ac},{0xffffc0c1},{0xffffbf79},{0xc0000000},{0xc0000000},{0xe0fe6703},{0xc0000000},{0xe0fe6703},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x47},{0x8c3f0001},{0xc0c0ffff},{0xffffd53b},{0xffffd2ac},{0xffffc0c1},{0xffffbf79},{0xc0000000},{0xc0000000},{0xe0fe6703},{0xc0000000},{0xe0fe6703},{0xc0000000},{0x0},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x4e6,38,[{0x1},{0x1},{0x48},{0x8c3f0002},{0xc0c0ffff},{0xffffd53b},{0xffffd2ac},{0xffffc0c1},{0xffffbf79},{0xc0000000},{0xc0000000},{0xe0fe6703},{0xc0000000},{0xe0fe6703},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1},{0x49},{0x8c3f0003},{0xc0c0ffff},{0xffffd53b},{0xffffd2ac},{0xffffc0c1},{0xffffbf79},{0xc0000000},{0xc0000000},{0xe0fe6703},{0xc0000000},{0xe0fe6703},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x50c,38,[{0x4a},{0x4240000},{0xc0c0ffff},{0xc4e},{0xc0f},{0x2b5},{0x256},{0xc0000000},{0xc0000000},{0xe0fe6701},{0xc0000000},{0xe0fe6701},{0xc0000000},{0x0},{0x0},{0x0},{0x0},{0x4b},{0xa8e00000},{0xc0c0ffff},{0xfffff68e},{0xfffff4be},{0xffff8300},{0xffff8001},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0x0},{0x0},{0x0},{0x2},{0xe},{0x6},{0x4c},{0xa8e00000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x532,38,[{0xc0c0ffff},{0xfffff68e},{0xfffff4be},{0xffff8300},{0xffff8001},{0xc0000000},{0xc0000000},{0xe0fe6709},{0xc0000000},{0xe0fe6709},{0xc0000000},{0x0},{0x0},{0x0},{0x2},{0xe},{0x5},{0x4d},{0xa8e10000},{0xc0c0ffff},{0xfffff79d},{0xfffff5ad},{0xffff99ba},{0xffff8001},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0x0},{0x0},{0x0},{0x2},{0xf},{0x6},{0x4e},{0xa8e10000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x558,38,[{0xc0c0ffff},{0xfffff79d},{0xfffff5ad},{0xffff99ba},{0xffff8001},{0xc0000000},{0xc0000000},{0xe0fe6709},{0xc0000000},{0xe0fe6709},{0xc0000000},{0x0},{0x0},{0x0},{0x2},{0xf},{0x5},{0x4f},{0xa8e20000},{0xc0c0ffff},{0xfffff76f},{0xfffff574},{0xffff98e4},{0xffff8001},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0x0},{0x0},{0x0},{0x2},{0x10},{0x6},{0x50},{0xa8e20000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x57e,38,[{0xc0c0ffff},{0xfffff76f},{0xfffff574},{0xffff98e4},{0xffff8001},{0xc0000000},{0xc0000000},{0xe0fe6709},{0xc0000000},{0xe0fe6709},{0xc0000000},{0x0},{0x0},{0x0},{0x2},{0x10},{0x5},{0x51},{0xa8e30000},{0xc0c0ffff},{0xfffff3b9},{0xfffff054},{0xffffb403},{0xffffa803},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x11},{0x52},{0xa8e40000},{0xc0c0ffff}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x5a4,38,[{0xfffffc1a},{0xfffff65d},{0xfffff281},{0xfffff007},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x12},{0x53},{0xa8e50000},{0xc0c0ffff},{0xfffff39a},{0xffffede4},{0xffffe3b3},{0xffffd198},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x13},{0x54},{0xa8e60000},{0xc0c0ffff},{0xfffff4a2},{0xffffef4a}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x5ca,38,[{0xffffe582},{0xffffd3e0},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x14},{0x55},{0xa8e70000},{0xc0c0ffff},{0xfffffb48},{0xfffff201},{0xffffec02},{0xffffe81f},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x15},{0x56},{0xa8e80000},{0xc0c0ffff},{0xfffffcdf},{0xfffff56e},{0xfffff058},{0xffffe432}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x5f0,38,[{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x16},{0x57},{0xa8e90000},{0xc0c0ffff},{0xfffffb31},{0xfffff0b1},{0xffffe9a2},{0xffffe4ee},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x17},{0x58},{0xa8ea0000},{0xc0c0ffff},{0xfffff448},{0xfffff2fa},{0xffffa62f},{0xffffa33f},{0xc0000000},{0xc0000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x616,38,[{0xe0fe6710},{0xc0000000},{0xe0fe6710},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x18},{0x59},{0xa8eb0000},{0xc0c0ffff},{0xfffff448},{0xfffff2f1},{0xffffa4c0},{0xffffa1be},{0xc0000000},{0xc0000000},{0xe0fe6711},{0xc0000000},{0xe0fe6711},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x19},{0x5a},{0xa8ec0000},{0xc0c0ffff},{0xfffffa4e},{0xfffff30a},{0xffffec15},{0xffffe754},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x63c,38,[{0xc0000000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1a},{0x5b},{0xa8ed0000},{0xc0c0ffff},{0xfffff9a0},{0xffffef0d},{0xffffe86f},{0xffffe432},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1b},{0x5c},{0xa8ee0000},{0xc0c0ffff},{0xfffff39b},{0xffffd9fa},{0xffffc93f},{0xffffbe61},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x662,38,[{0x0},{0x0},{0x0},{0x1},{0x1c},{0x5d},{0xa8ef0000},{0xc0c0ffff},{0xffffe459},{0xffffbeb2},{0xffffa81c},{0xffff99e7},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x1d},{0x5e},{0xa8c40000},{0x40c0ffff},{0x8000},{0x8000},{0xffff7fff},{0xffff7fff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x688,38,[{0x0},{0x2},{0x1},{0x5},{0x5f},{0xa8c40000},{0x40c0ffff},{0x8000},{0x8000},{0xffff7fff},{0xffff7fff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x2},{0x1},{0x6},{0x60},{0xa8c50000},{0x40c0ffff},{0x8000},{0x8000},{0xffff7fff},{0xffff7fff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x6ae,38,[{0x0},{0x2},{0x1},{0x5},{0x61},{0xa8c50000},{0x40c0ffff},{0x8000},{0x8000},{0xffff7fff},{0xffff7fff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x2},{0x1},{0x6},{0x62},{0xa8c70000},{0x40c0ffff},{0x8000},{0x8000},{0xffff7fff},{0xffff7fff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x6d4,38,[{0x0},{0x2},{0x1},{0x5},{0x63},{0xa8c70000},{0x40c0ffff},{0x8000},{0x8000},{0xffff7fff},{0xffff7fff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x2},{0x1},{0x6},{0x64},{0xa8c60000},{0x40c0ffff},{0x8000},{0x8000},{0xffff7fff},{0xffff7fff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x6fa,38,[{0x0},{0x1},{0x1},{0x65},{0xa8c90000},{0x40c0ffff},{0x8000},{0x8000},{0xffff7fff},{0xffff7fff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0x66},{0xa8c80000},{0x40c0ffff},{0x8000},{0x8000},{0xffff7fff},{0xffff7fff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x720,38,[{0x1},{0x67},{0xa8cd0000},{0x40c0ffff},{0x8000},{0x8000},{0xffff7fff},{0xffff7fff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0x68},{0xa8cc0000},{0x40c0ffff},{0x8000},{0x8000},{0xffff7fff},{0xffff7fff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0x69}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x746,38,[{0xa8cb0000},{0x40c0ffff},{0x8000},{0x8000},{0xffff7fff},{0xffff7fff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0x6a},{0xa8ca0000},{0x40c0ffff},{0x8000},{0x8000},{0xffff7fff},{0xffff7fff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0x6b},{0xa8f00000},{0xc0c0ffff}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x76c,38,[{0x7fee},{0x7fe0},{0xfffffc18},{0xffffb1e0},{0xc0000000},{0xc0000000},{0xf067000d},{0xc0000000},{0xf067000d},{0xc0000000},{0x0},{0x0},{0x0},{0x2},{0x1e},{0x7},{0x6c},{0x98600000},{0x80800001},{0x1},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0xe0fe6706},{0xc0000000},{0x0},{0x0},{0x1},{0x3},{0x6d},{0x98600000},{0xc20001},{0x1}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x792,38,[{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x3},{0x6e},{0x99020000},{0x40c0ffff},{0x8000},{0x8000},{0xffff7fff},{0xffff7fff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x4},{0x6f},{0x99820000},{0x40c0ffff},{0x8000},{0x8000},{0xffff7fff}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x7b8,38,[{0xffff7fff},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x4},{0x70},{0x98200000},{0xc0ffff},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x2},{0x71},{0x98200000},{0x40c800ff},{0x1},{0x1},{0xffffffff},{0xffffffff},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x7de,38,[{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x2},{0x72},{0x8c3f0017},{0x80800010},{0x1},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0xf067000e},{0xc0000000},{0x0},{0x0},{0x1},{0xc},{0x73},{0x8c3f0017},{0x80800020},{0x1},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x804,38,[{0x0},{0x0},{0xf067000e},{0xc0000000},{0x0},{0x0},{0x1},{0xc},{0x74},{0x8c3f0017},{0x80800040},{0x1},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0xf067000e},{0xc0000000},{0x0},{0x0},{0x1},{0xc},{0x75},{0x8c3f0017},{0x80800080},{0x1},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x82a,38,[{0xf067000e},{0xc0000000},{0x0},{0x0},{0x1},{0xb},{0x76},{0x8c3f0017},{0x80800100},{0x1},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0xf067000e},{0xc0000000},{0x0},{0x0},{0x1},{0xb},{0x77},{0x8c3f0017},{0x80800200},{0x1},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0xf067000e},{0xc0000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x850,38,[{0x0},{0x0},{0x1},{0xb},{0x78},{0x8c3f0017},{0x80800400},{0x1},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0xf067000e},{0xc0000000},{0x0},{0x0},{0x1},{0xb},{0x79},{0x8c3f0017},{0x80800800},{0x1},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0xf067000e},{0xc0000000},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x876,38,[{0x1},{0xb},{0x7a},{0x8c3f0017},{0x80801000},{0x1},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0xf067000e},{0xc0000000},{0x0},{0x0},{0x1},{0xb},{0x7b},{0x8c3f0017},{0x80802000},{0x1},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0xf067000e},{0xc0000000},{0x0},{0x0},{0x1},{0xb}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x89c,38,[{0x7c},{0x8c3f0017},{0x80804000},{0x1},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0xf067000e},{0xc0000000},{0x0},{0x0},{0x1},{0xb},{0x7d},{0x8c3f0017},{0x80808000},{0x1},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0xf067000e},{0xc0000000},{0x0},{0x0},{0x1},{0xb},{0x7e},{0x40070004}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x8c2,38,[{0x8080000f},{0xe},{0xe000f},{0xc000d},{0xa000b},{0x80009},{0x60007},{0x40005},{0x20003},{0x0},{0xe0fe6706},{0xc0000000},{0x0},{0x0},{0x1},{0x3},{0x7f},{0x40070005},{0x8080000f},{0xe},{0xe000f},{0xc000d},{0xa000b},{0x80009},{0x60007},{0x40005},{0x20003},{0x0},{0xe0ff0000},{0xc0000000},{0x0},{0x0},{0x1},{0x1},{0x80},{0x40070009},{0x8080000f},{0xe}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x8e8,38,[{0xe000f},{0xc000d},{0xa000b},{0x80009},{0x60007},{0x40005},{0x20003},{0x0},{0xf067000f},{0xc0000000},{0x0},{0x0},{0x1},{0x1},{0x81},{0x98410000},{0x80800001},{0x1},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x1},{0x1},{0x82},{0x98700000},{0xc301fff7},{0x5e24},{0x5e0b},{0x3e99}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x5,0x90e,12,[{0x3e80},{0xc0000000},{0xc0000000},{0xe0fe6703},{0xc0000000},{0xe0fe6703},{0xc0000000},{0x0},{0x0},{0x0},{0x1},{0x81}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x5,0x0,0x0);
    delay(10);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableMonitor ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StopSmecEngData.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to stop generation of MCUengineering dataTM packets
//
//
///////////////////////////////////////////////////////////////////////////
//
// K. King:
// 2009/10/21: First Version 
//                  Created for SPR Spire-2062
///
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StopMcuEngData SPIRE 3401 {
}{
    // 
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // 
    // 
    // Start BB:
    //
    message("4    " + time() + ": SpireBb_StopMcuEngData started");
    message("4          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    delay(1);
    // //
    // //
    // Stop data collection:
    //
    SpireProc_Set_StopMcuEngData();
    // //
    // //
    // End BB:
    //
    SpireMsg(4,"    " + time() + ": BB SpireBb_StopMcuEngData ended");
    //
}

// $Id: WriteEndBB.txt,v 1.2 2007/08/22 10:21:52 dcesarsk Exp $ 
// Purpose       : Set BBID to its required value to indicate the end
//                 of current BB execution (see FIRST-FSC-DOC-0200) 
//
// CUS script    : Diego A. Cesarsky (diego.cesarsky@mpe.mpg.de)
//
// Input arguments N/A
//
// Description   : BBID will be set to its LEG value
//
// Comments      : Needed for SCR-3507
//
// Version       : 0.1 21-aug-2007 First creation
// 		 : 1.0 derived from ...made it a block
//
block PacsBbWriteIdBB PACS 1102 {
}{
    int iBBID = 0xcd2a4a5;
    // Write BBID to DEC/MEC
    Pacs_DMC_SET_BBID(iBBID);
}

// CVS comments  : $Id: DMC_fixed_fixed_photo.txt,v 1.6 2007/04/25 15:14:03 dcesarsk Exp $ 
// Script file   : DMC_fixed_fixed_photo.txt
// Purpose       : Compute execution time of DMC #??
//
// TCL author    : N/A Pseudo code by HF
// TCL file      : N/A
// CUS author    : DAC
//
// Input arguments
// type    name         description
//
// Return values
// Type    Name      Default      Description
//
// Description   : DMC 4.1.8 Fixed-Fixed Chopping in Photometry
//                 Chopping is done to a set (3 pairs) of positions in order
//                 to place positive and negative beams on different
//                 pixels on the array, where the distance between 2 respective
//                 positions stays constant for a while and then the next
//                 position pair is being measured.
//                 The chopper performs the following pattern
//
//                 P#2      take nb_rdouts
//                 P#2+P#5  take nb_rdouts  }           }
//                 P#2+P#6  take nb_rdouts  } P#4 times }
//                                          }
//                 P#7      take nb_rdouts              }
//                 P#7+P#5  take nb_rdouts  }           }
//                 P#7+P#6  take nb_rdouts  } P#4 times } P#1 times
//                                          }
//                 P#8      take nb_rdouts              }
//                 P#8+P#5  take nb_rdouts  }           }
//                 P#8+P#6  take nb_rdouts  } P#4 times }
//
// TOTAL readouts (2*P#4 + 1)*3*nb_rdouts
// 
//      Usually P#6 = -P#5 so that chopper comes back to starting postion
//
// Dependencies  :
//
// Preconditions : None.
//
// Comments      : No TC are generated; only times are computed
//
// History       : 0.1 26-jun-2006 DAC
//                 0.2 22-nov-2006 Removed debug_print
//                 0.3 14-mar-2007 WAIT=1 is now considered useful data
int[] procedure DMC_fixed_fixed_photo {
    int nb_main_loops = 1; // Seq P#1   Nb of of main loops
    int nb_rdouts = 159; // Seq P#3   Nb of rdouts per chopper position
    int nb_chop_cycle = 2; // Seq P#4   Nb of chops per incremental step
}{
    // Define variables to communicate various durations to HSPOT.
    // NOTE: all time variables in units of number of ramps (SPEC) or
    //       number of readouts (BOLO). The calling program must convert this
    //       count into actual duration in true time units [seconds].
    //       SRC, REF, CAL, OVR stand for time spent on SRC, REF (on sky),
    //       CAL source, and overheads (wait for something). Total
    //       duration is given by duree_num. If no error, this duration
    //       must be equal to the sum of all others
    int duree_num = 0;
    int duree_SRC = 0;
    int duree_REF = 0;
    int duree_CAL = 0;
    int duree_OVR = 0;
    int time_start = time();
    // WAIT 1                                ; have a defined start
    duree_num = duree_num + 1;
    duree_OVR = duree_OVR + 1;
    // LABEL 0                               ; set Label to 0
    // WAIT 1                                ; have a defined start
    duree_num = duree_num + 1;
    duree_OVR = duree_OVR + 1;
    // LOOP P#1                             ; main loop measurement
    for(int loop0 = 1 .. nb_main_loops) {
        //    WAIT 1                             ; sync. for chopper
        duree_num = duree_num + 1;
        duree_SRC = duree_SRC + 1;
        //    MOVE_CHOPPER_ABSOLUTE P#2          ; start pos. chopper
        //    LABEL 3                            ; 1st chopper position
        //    WAIT P#3                           ; take P#3 images
        duree_num = duree_num + nb_rdouts;
        duree_SRC = duree_SRC + nb_rdouts;
        //    LOOP P#4                           ; do P#4 chops per step
        for(int loop1 = 1 .. nb_chop_cycle) {
            //       WAIT 1                          ; sync. for chopper
            duree_num = duree_num + 1;
            duree_SRC = duree_SRC + 1;
            //       MOVE_CHOPPER_RELATIVE P#5       ; go to other chop position
            //       LABEL 5                         ; 2nd chopper position
            //       WAIT P#3                        ; take P#3 images
            duree_num = duree_num + nb_rdouts;
            duree_SRC = duree_SRC + nb_rdouts;
            //       WAIT 1                          ; sync. for chopper
            duree_num = duree_num + 1;
            duree_SRC = duree_SRC + 1;
            //       MOVE_CHOPPER_RELATIVE P#6       ; go back to previous position
            //       LABEL 3                         ; 1st chopper position
            //       WAIT P#3                        ; take P#3 images
            duree_num = duree_num + nb_rdouts;
            duree_SRC = duree_SRC + nb_rdouts;
        }
        //    END_LOOP                           ; end of chop
        //    WAIT 1                             ; sync. for chopper
        duree_num = duree_num + 1;
        duree_SRC = duree_SRC + 1;
        //    MOVE_CHOPPER_ABSOLUTE P#7          ; go to next position pair
        //    LABEL 7                            ; 3rd chopper position
        //    WAIT P#3                           ; take P#3 images
        duree_num = duree_num + nb_rdouts;
        duree_SRC = duree_SRC + nb_rdouts;
        //    LOOP P#4                           ; do P#4 chops per step
        for(int loop2 = 1 .. nb_chop_cycle) {
            //       WAIT 1                          ; sync. for chopper
            duree_num = duree_num + 1;
            duree_SRC = duree_SRC + 1;
            //       MOVE_CHOPPER_RELATIVE P#5       ; go to other chop position
            //       LABEL 9                         ; 4th chopper position
            //       WAIT P#3                        ; take P#3 images
            duree_num = duree_num + nb_rdouts;
            duree_SRC = duree_SRC + nb_rdouts;
            //       WAIT 1                          ; sync. for chopper
            duree_num = duree_num + 1;
            duree_SRC = duree_SRC + 1;
            //       MOVE_CHOPPER_RELATIVE P#6       ; go back to previous position
            //       LABEL 7                         ; 3rd chopper position
            //       WAIT P#3                        ; take P#3 images
            duree_num = duree_num + nb_rdouts;
            duree_SRC = duree_SRC + nb_rdouts;
        }
        //    END_LOOP                           ; end of chop
        //    WAIT 1                             ; sync. for chopper
        duree_num = duree_num + 1;
        duree_SRC = duree_SRC + 1;
        //    MOVE_CHOPPER_ABSOLUTE P#8          ; go to next position pair
        //    LABEL 11                           ; 5th chopper position
        //    WAIT P#3                           ; take P#3 images
        duree_num = duree_num + nb_rdouts;
        duree_SRC = duree_SRC + nb_rdouts;
        //    LOOP P#4                           ; do P#4 chops per step
        for(int loop3 = 1 .. nb_chop_cycle) {
            //       WAIT 1                          ; sync. for chopper
            duree_num = duree_num + 1;
            duree_SRC = duree_SRC + 1;
            //       MOVE_CHOPPER_RELATIVE P#5       ; go to other chop position
            //       LABEL 13                        ; 6th chopper position
            //       WAIT P#3                        ; take P#3 images
            duree_num = duree_num + nb_rdouts;
            duree_SRC = duree_SRC + nb_rdouts;
            //       WAIT 1                          ; sync. for chopper
            duree_num = duree_num + 1;
            duree_SRC = duree_SRC + 1;
            //       MOVE_CHOPPER_RELATIVE P#6       ; go back to previous position
            //       LABEL 11                        ; 5th chopper position
            //       WAIT P#3                        ; take P#3 images
            duree_num = duree_num + nb_rdouts;
            duree_SRC = duree_SRC + nb_rdouts;
        }
        //    END_LOOP                           ; end of chop
        // END_LOOP                              ; end main loop
    }
    // WAIT 1                                ; complete last plateau
    duree_num = duree_num + 1;
    duree_OVR = duree_OVR + 1;
    // LABEL 0                               ; no sequence anymore
    // END_SEQUENCE
    // 8 Parameters: # of main loops (P#1);
    // Chopper start positions P#2, P#7, P#8;
    // Size of Relative chopper moves P#5, P#6;
    // # of chops per incremental step (P#4);
    // # of readouts per chopper plateau (P#3)
    // Note: P#3 must be defined such that: (P#3 + 1) mod 4 = 0; P#5 = -P#6;
    //       Sequence duration, in readouts :
    //       3 + P#1 * 3 * {(1 + P#3) + P#4 * (2 * (1+P#3))}
    int dur_theor = 3 + nb_main_loops * 3 * (1 + nb_rdouts + nb_chop_cycle * 2 * (1 + nb_rdouts));
    // debug_print("Theor duration: " + dur_theor);
    int[] duree = [duree_num,duree_SRC,duree_REF,duree_CAL,duree_OVR];
    //  debug_print("++DMC_fixed_fixed: " + duree + " [rdouts]");

    return duree;
}

// SpireEngPTCOn
//
// $id$
//
// This observation switches on the PTC
// 
// The instrument should be in PHOTSTBY mode before execution of this observation
// Final Configuration: Instrument is still in PHOTSTBY mode after execution of this observation
//
//
// 05/08/2009 SDS: First Version 0.1 
//
obs SpireEngPTCOn {
    int stabilisationTime = 1200; // time (secs) to allow Detectors to stabilise before starting observations
    bool sampleDetectors = true; // sample detectors during the stabilisation period
    string ptcVersion = "v00";
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int t = duration(SpireBbStartObs()) + duration(SpireProc_PTCOn(stabilisationTime,sampleDetectors,ptcVersion,debug)) + duration(SpireBbEndObs());
    int[] ts = no_pointing(true,0,0,t);
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            SpireBbStartObs();
            SpireProc_PTCOn(stabilisationTime,sampleDetectors,ptcVersion,debug);
            SpireBbEndObs();
        }
    }
}

//CLName: SpireBb_LoadTableCtrlOff
//VMVersion: 2.8
//CLVersion: 1.0
//CLCVSId: $ID$
//TableId: 0x3c
//TableLength: 0x8
//Date: 090107170144
block SpireBb_LoadTableCtrlOff SPIRE 3801 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableCtrlOff started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0x3c
    Spire_SET_TABLE(0x3c,0x8);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x3c,0x0,8,[{0x120000ff},{0x0},{0x12000000},{0x7},{0x61060001},{0x60660006},{0x7f000000},{0x0}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x3c,0x0,0x0);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableCtrlOff ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

// Set CCU monitoring period for cooler recycling
//
command SpireCcuMonitorPeriodRecycle HFKACQP2 {
} {
    bus_schedule(SC, 6);
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_BsmMove.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to move BSM in jiggle and chop
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/02 V1.0: Initial version adapted from
//                  SpireBsmMove (KK, v 1.1 2006/08/10) and 
//                  SpireBb_BsmMove2Hold (2009/01/27 V1.0)
// 2009/02/15 V1.1: Add 0x90c60001 at end to start movement.
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_BsmMove {
    int chopPosn = 2048 in [0,65535];
    int jiggPosn = 2048 in [0,65535];
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    int cmd = 0;
    //
    // a hex string: 
    string hstr = "";
    // 
    // a time string:
    string tstr = "";
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"    " + tstr + ": SpireProc_Set_BsmMove started");
    SpireMsg(4,"          $Id: $");
    SpireMsg(3,"         ChopPosn = " + chopPosn);
    SpireMsg(3,"         JIggPosn = " + jiggPosn);
    // //
    // //
    // Move BSM:
    //
    // set Chop position:
    cmd = 0x90c30000 + chopPosn;
    SpireSendDrcuCmd(cmd,0);
    //
    // set Jiggle Position:
    cmd = 0x91430000 + jiggPosn;
    SpireSendDrcuCmd(cmd,0);
    //
    // One-off synchronous movement to the current Chop and Jiggle position:
    cmd = 0x90c60001;
    SpireSendDrcuCmd(cmd,0);
    // //
    // //
    // Add delay to wait for BSM to settle (TBC):
    //
    delay(3);
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"    " + tstr + ": SpireProc_Set_BsmMove ended");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Exec_PhotPhaseUp.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to loop through a list of phase values 
//  for the 'Phot Phase Up' task
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/05/07 V0.1: Initial version adapted from
//                  Mode_ILT_PERF_DPH_P.txt (v1.4 2008/01/31 20:24:33)
// 2008/07/03 V0.2: Renumber version; change description;
//                  SpireBb_PhotFSetPhase now with PTC phase
// 2008/11/07 V0.3: Remove test number from script
// 2009/02/01 V1.0: Add debug_print as input and pass to low level scripts.
// 2009/02/17 V1.1: Do not set first phase, now done during SLEW.
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Exec_PhotPhaseUp {
    int[] raw_phase_list = [127,128,129,130,131,132,133]; // Raw phase list (0-255) [dec(HEX)]
    int ftime = 10; // Time at each bias level [sec]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Setup bias amplitude and frequency:
    // --> during slew!!
    //
    // //
    // //
    // Start the phase loop:
    //
    for(int l = 0 .. length(raw_phase_list) - 1) {
        // //
        // //
        // Set phases for arrays:
        //
        if(l > 0) {
            SpireBb_PhotFSetPhase(raw_phase_list[l],raw_phase_list[l],raw_phase_list[l],raw_phase_list[l],debug);
        }
        // //
        // //
        // Stop DCU data before resetting offsets:
        //
        SpireBb_StopDcuData();
        // //
        // //
        // Set offsets:
        //
        SpireBb_PhotOffsetAuto(debug);
        // //
        // //
        // Take data:
        //
        SpireBb_PhotFTakeData(ftime,debug);
        // //
        // //
        // Debug printing:
        //
        if(debug) {
            debug_print("Phase finished is: " + raw_phase_list[l]);
        }
    }
    //
    //
}

// SpireBbMove
//
// $id$
//
// telescope movement BB
//
//  K.J. King
//
block SpireBbMove SPIRE 12032 {
    int step = 0;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Move started");
    SpireMsg(2,"          $Id: SpireBbMove.txt,v 1.1 2006/08/10 09:38:57 kking Exp $");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP 
    hstr = SpireHexStr(step,4);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(" + hstr + ")");
    Spire_SET_OBS_STEP_RAW(step);
    //
    // execute 
    //
    delay(2);
    //
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Move ended");
    SpireMsg(1,"  ..Moving (" + (time() - t) + " seconds)");
    //
}

// CVS comments  : $Id: OBCP_fixed_fixed_photo.txt,v 1.6 2007/08/22 10:18:28 dcesarsk Exp $ 
// Script file   : OBCP_fixed_fixed_photo.txt
// Purpose       :
// OBCP author   : HF
// CUS author    : DAC
//
// Input arguments
// type    name         description
//
// Return values
// Type    Name      Default      Description
//
// Description   : Belongs to Section 3.1: Two or three position chop PHOTO
//                 of PACS-ME-LI-005, issue 1.4
//                 This is OBCP 3.1.3, calling DMC sequence
//                 14 (in 4.1.8). DMC  performs the following chopper
//                 pattern:
//
//                 P#2      take nb_rdouts
//                 P#2+P#5  take nb_rdouts  }           }
//                 P#2+P#6  take nb_rdouts  } P#4 times }
//                                                      }
//                 P#7      take nb_rdouts              }
//                 P#7+P#5  take nb_rdouts  }           }
//                 P#7+P#6  take nb_rdouts  } P#4 times } P#1 times
//                                                      }
//                 P#8      take nb_rdouts              }
//                 P#8+P#5  take nb_rdouts  }           }
//                 P#8+P#6  take nb_rdouts  } P#4 times }
//
// TOTAL readouts (2*P#4 + 1)*3*nb_rdouts
// 
//      Usually P#6 = -P#5 so that chopper comes back to starting postion
//
// Dependencies  :
//
// Preconditions :
//
// Comments      :
//
// History       : 0.1 26-jun-2006 DAC
// 1.0 31-aug-2006 Return the TOTAL duration including TC timing
// 1.1 22-nov-2006 Removed debug_print
// 1.2 21-aug-2007 SRC-3507 Indicate end of BB
int[] block OBCP_fixed_fixed_photo PACS 3 {
    int nb_main_loops = 1; // Nb of main loops                     (P#1)
    int chop_pos_1 = -100; // First chopper position               (P#2)
    int nb_rdouts = 159; // Nb of readouts/chopper plateau       (P#3)
    int nb_chop_cycle = 2; // Nb of chopps per pair of positions   (P#4)
    int chop_throw_1 = 2000; // Chopper throw away from 1st position (P#5)
    int chop_throw_2 = -2000; // Chopper throw back to 1st position   (P#6)
    int chop_pos_2 = 0; // Second chopper position              (P#7)
    int chop_pos_3 = 100; // Third chopper position               (P#8)
    int comp_mode_blu = 0; // "Blue" compression
    int comp_mode_red = 0; // "Red" compression
}{
    // Starting time
    int time_start = time();
    // Register start of BB
    WriteBBID($BBID);
    // Variables that may be used to define various times
    int duree_rdouts = 0;
    int duree_SRC = 0;
    int duree_REF = 0;
    int duree_CAL = 0;
    int duree_OVR = 0;
    // Obtain some parameters from table PACSparams
    // BOL readout frequency [Hz] and readout period [msec]
    double bol_freq = dlookup("PACSparams","bolo_sample","freq_time");
    string bol_unit = slookup("PACSparams","bolo_sample","unit");
    double bol_period = 1000.0 / bol_freq;
    // debug_print("Bolo sample: " + bol_freq + " " + bol_unit);
    // debug_print("Bolo period: " + bol_period + "[msec]");
    // Obtain duration of an "internal" command [msec]
    int t_cmd = iceil(dlookup("PACSparams","int_cmd","freq_time"));
    // Obtain duration of DEC/MEC "communication jitter" [msec]
    int dmc_margin = iceil(dlookup("PACSparams","dmc_margin","freq_time"));
    // Obtain duration of OBCP "communication jitter" [msec]
    int obcp_margin = iceil(dlookup("PACSparams","obcp_margin","freq_time"));
    // Start tallying the duration of this script [msec]
    int duree_msec = 0;
    // OBCP Pseudo Code starts here (accumulate duree_msec [msec] as it goes)
    // Begin
    // OBCP_GRATING_Fixed_Fixed_PHOTOMETRY(seq, seq_time,
    //   P#1...P#8, cmp_par_blue, cmp_par_red)
    // DMC_WRT_TIME (DPU_TIME in standard 48 bit format according to PS-ICD)
    duree_msec = duree_msec + t_cmd;
    duree_OVR = duree_OVR + t_cmd;
    // DMC_SET_TIME
    duree_msec = duree_msec + t_cmd;
    duree_OVR = duree_OVR + t_cmd;
    // DMC_WRT_SEQ_BUFFER(ID, LENGTH, DATA, CHECKSUM) ; (all parameters filled
    // by DPU based on seq parameter)
    duree_msec = duree_msec + t_cmd;
    duree_OVR = duree_OVR + t_cmd;
    // DMC_SYNCHRONIZE_ON_DET(detector)
    duree_msec = duree_msec + t_cmd;
    duree_OVR = duree_OVR + t_cmd;
    // DMC_WRT_SPU_TRAN_MODE(ID, 2, cmp_par_blue, cmp_par_red, CHHKSUM)
    duree_msec = duree_msec + t_cmd;
    duree_OVR = duree_OVR + t_cmd;
    // DMC_START_SEQUENCE
    //////////////////////////////////////////////////////////////////////////
    // Call DEC/MEC code to estimate its duration
    duree_msec = duree_msec + t_cmd;
    duree_OVR = duree_OVR + t_cmd;
    int[] duree1 = DMC_fixed_fixed_photo(nb_main_loops,nb_rdouts,nb_chop_cycle);
    // Convert array "duree1" into [msec]
    int seq_time = iround(double(duree1[0]) * bol_period) + dmc_margin;
    duree_SRC = iround(double(duree1[1]) * bol_period);
    duree_REF = iround(double(duree1[2]) * bol_period);
    duree_CAL = iround(double(duree1[3]) * bol_period);
    duree_OVR = duree_OVR + iround(double(duree1[4]) * bol_period) + dmc_margin;
    //  debug_print("Execution time [msec] from DMC: " + seq_time);
    // duree_msec(seq_time)
    duree_msec = duree_msec + t_cmd + seq_time;
    // WAIT(seq_time) ; Check execution status of the sequence and in case of
    // failure stop OBCP and issue TM(1,8)+event
    // Issue TM(1,7)
    // End
    // Now trigger execution of OBCP
    // This OBCP is number 3, requires 12 parameters and calls DEC/MEC #??
    string obcp_ID = "FIXED_CHOP_PHOT";
    int obcp_par_nb = 12;
    int seq_DMC = 14;
    {int,int}[] grp = [{1,seq_DMC},{2,seq_time},{3,nb_main_loops},{4,chop_pos_1},{5,nb_rdouts},{6,nb_chop_cycle},{7,chop_throw_1},{8,chop_throw_2},{9,chop_pos_2},{10,chop_pos_3},{11,comp_mode_blu},{12,comp_mode_red}];
    Pacs_DPU_START_OBCP(obcp_ID,obcp_par_nb,grp);
    // Add the "communication jitter"
    duree_msec = duree_msec + obcp_margin;
    duree_OVR = duree_OVR + obcp_margin;
    // Define time_array (return to caller)
    int[] time_array = [duree_msec,duree_SRC,duree_REF,duree_CAL,duree_OVR];
    // and convert from [msec] to [sec]
    for(int aux = 0 .. 4) {
        time_array[aux] = Msec2sec(time_array[aux]);
    }
    //  debug_print(obcp_ID + "; duration: " + time_array);
    delay(time_array[0]);
    // Mark end of BB
    WriteEndBB();
    // Return actual duration
    time_array[0] = time() - time_start;
    // Return the array of times

    return time_array;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SpecSetMode.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to configure some important instrument parameters
// for the spectrometer depending on the mode. 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/19 V0.1: Initial version adapted from
//                  SpireBb_PhotSetMode (2009/02/15 V0.1)
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SpecSetMode SPIRE 14032 {
    string obsMode = "SPECSTBY"; // Obs mode as defined in calibration files
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string hstr = "";
    // a hex string
    string tstr = "";
    // a time string
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": SpireBb_SpecSetMode started");
    SpireMsg(2,"          $Id: $");
    hstr = SpireHexStr($BBID,8);
    SpireMsg(3,"          BBID = " + hstr);
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    sync();
    // //
    // //
    // Call procedure to set parameters:
    //
    SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SpecSetMode ended");
    SpireMsg(1,"  ..Set Phot phases (" + (time() - t) + " secs)");
    //
}

// SpireBbPOF2Init
//
// $Id: SpireBbPOF2Init.txt,v 1.1 2006/08/10 09:38:57 kking Exp $
//
// Building Block to initialise the instrument for POF2 (7-point jiggle) operation
//
// The complete instrument setup operation is divided into two parts:
//   Configuration: actions that can be executed during the slew to the start
//          position of the S/C pointing mode.
//   Initialisation: actions that must be carried out at the S/C intial pointing
//          position before any observational operations are executed.   
//
// This building Block implements the second part of the setup 
// 
// 04 November 2008: 
//         added data_rate commands
//         added commands to setup the detector sampling
//
block SpireBbPOF2Init SPIRE 8225 {
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF2 Initialisation started");
    SpireMsg(2,"          $Id: SpireBbPOF2Init.txt,v 1.1 2006/08/10 09:38:57 kking Exp $");
    //
    // ..... configuration .....
    //
    int cmd = 0x0;
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP  to On Target
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x8000)");
    Spire_SET_OBS_STEP_RAW(0x8000);
    //
    // set detector offsets
    // set DCU data mode  to Auto Offset 
    cmd = 0x843c0010;
    SpireSendDrcuCmd(cmd,0);
    // start auto offset generation
    cmd = 0x843e0001;
    SpireSendDrcuCmd(cmd,0);
    delay(15);
    //
    // dump detector offsets
    // stop auto offset generation
    cmd = 0x843e0000;
    SpireSendDrcuCmd(cmd,0);
    // set DCU data mode to get offset data
    cmd = 0x843c0018;
    SpireSendDrcuCmd(cmd,0);
    // start offset data dump
    cmd = 0x843e0001;
    SpireSendDrcuCmd(cmd,0);
    //  set datarate
    double rate = 0.0;
    rate = dlookup("Datarates.txt","POffsets","DCU");
    data_rate(rate);
    delay(5);
    // stop offset data dump 
    cmd = 0x843e0000;
    SpireSendDrcuCmd(cmd,0);
    data_rate(0.0);
    //
    // flush data
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(2);
    //
    //  set up detectors for operations
    //
    SpireConfigDcuData("POF2");
    sync();
    //
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF2 Initialisation ended");
    SpireMsg(1,"  ..POF2 Initialisation (" + (time() - t) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SmecMove2Home.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to return SMEC to home position
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/11/02 V0.1: Initial version adapted from SpireBb_MoveBsm2Hold
//                  (2008/10/13 V0.2)
// 2009/02/02 V0.2: (KJK) Updated to be used in all scripts
//                   - added smecCurrposn input parameter to allow calculation 
//                     of time to move to Home from current SMEC position
//                   - read HOME parameter from SMECNominalSettings Table
//                   - generate messages for all DRCU commands
// 2009/02/15 V0.3: (MP) Made some cosmetic changes
// 2009/09/15 V 0.4: KJK added sync() at end, just to be sure
//                
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SmecMove2Home SPIRE 14018 {
    int smecCurrPosn = 1000;
    bool debug = false;
}{
    // //
    // //
    // Define some variables:
    //
    int t = time();
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    //
    // Hardcoded calibration file and version:
    string tabName = "SpireTable_SmecNominalSettings.txt";
    string version = "v00";
    // //
    // //
    // Start BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SmecMove2Home started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBID:
    // 
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    // //
    // //
    // Fetch Home position:
    //    
    int smecHome = ilookup(tabName,version,"Home");
    if(debug) {
        debug_print("Setting SMEC back to home position: " + smecHome);
    }
    // //
    // //
    // Move to Home position:
    //
    SpireProc_SmecMove(smecHome,smecCurrPosn,debug);
    // //
    // //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SmecMove2Home ended");
    SpireMsg(1,"  BB SmecMove2Home (" + (time() - t) + " seconds)");
}

// SpireBbBsmMove
//
// $id$
//
// move the BSM to a position given in a jiggle table
//
//  K.J. King
//
block SpireBbBsmMove SPIRE 8455 {
    int jiggleTable = 0;
    int position = 0;
    int step = 0;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Bsm Move started");
    SpireMsg(2,"          $Id: SpireBbBsmMove.txt,v 1.2 2007/01/11 16:14:51 kking Exp $");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP 
    hstr = SpireHexStr(step,4);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(" + hstr + ")");
    Spire_SET_OBS_STEP_RAW(step);
    delay(2);
    //
    // execute 
    //
    int id = ilookup("CommandLists.txt","BSMMove","Id");
    //  number of table containing the BSMMove command list
    int index = ilookup("CommandLists.txt","BSMMove","Index");
    //  start point in table containing the BSMMove command list
    int nParms = ilookup("CommandLists.txt","BSMMove","Nparms");
    //  number of parameters to the BSMMove command list
    {int}[] parms = [{jiggleTable},{position}];
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM_RAW(" + id + "," + index + "," + nParms + "," + parms + ")");
    Spire_RUN_VM_RAW(id,index,nParms,parms);
    delay(2);
    //
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Bsm Move ended");
    SpireMsg(1,"  ..Moving (" + (time() - t) + " seconds)");
    //
}

// SpireEngSlowPMDump
//
// $id$
//
// This observation dumps the DPU Program Memory at the rate of one TM(6,6) packet every two seconds 
// Intended for use during DTCP without the need to switch to SPIRE bus profile
//
// The instrument should normally be in REDY mode before execution
// of this observation.
//
//
// 04/08/2010 SDS: First Version 1.0 
//                 See SPIRE-SCR-2763
//
///////////////////////////////////////////////////////////////////////////
obs SpireEngSlowPMDump {
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use)
    int pInt2 = 0; // Spare parameter (currently not in use)
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int t = duration(SpireBbStartObs()) + duration(SpireBbEndObs());
    t = t + duration(SpireBb_SlowPMDump());
    //
    // ***********************************************
    int[] ts = no_pointing(true,0,0,t);
}{
    SpireMsg(0,"Observation Start");
    SpireMsg(3,"       $Id:$");
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            SpireBbStartObs();
            // Perform a slow PM Dump 
            SpireBb_SlowPMDump();
            // 
            SpireBbEndObs();
        }
    }
    SpireMsg(0,"Observation Completed  (" + time() + " seconds)");
    SpireMsg(0,"Note: Total time (s) = Observation Completed time - slew time + Observatory Overheads");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartStdLoadCurve.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpirePhoto/Spectro_Cal_StdLoadCurve.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V0.1: Initial version adapted from
//                  SpireBb_StartBsmAngleCal (2009/05/05 V0.1),
//                  SpirePhoto_Cal_StdLoadCurve (2009/03/04 V1.3), and
//                  SpireSpectro_Cal_StdLoadCurve (2009/03/04 V0.5)
//                  BB includes now to move BSM/SMEC to hold/home.  
// 2009/07/03 V1.0: Fix bug to allow spectrometer to use script.   
// 2009/07/05 V1.1: Properly fix it, so that BOTH spec and phot can use
//                  script.
// 2009/07/10 V1.2: Fix bug SPR-SPIRE-1612
// 
// Notes:
//    1) Scripts assumes that SpireBb_SpecOffsetAuto is run 
//       during INITHOLD or at first POINTING.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartStdLoadCurve SPIRE 14050 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    string obsModeQla = "ENG_CAL_OBS12";
    string obsMode = "PEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_Phot/SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    int smecHomePosn = 3500; // SMEC home position
    int mclkdiv = 149; // mclkdiv (spec ==~ 121)
    int biasdiv = 6; // biasdiv (spec ==~ 1)
    int psw_bias = 62; //
    int pmw_bias = 62; //
    int plw_bias = 62; //
    int ptc_bias = 62; //
    int psw_phase = 127; //
    int pmw_phase = 127; //
    int plw_phase = 127; //
    int ptc_phase = 127; //
    int ssw_bias = 45; //
    int slw_bias = 45; //
    int ssw_phase = 128; //
    int slw_phase = 128; // 
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartStdLoadCurve configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // In case move SMEC to home:
    // 
    if(!phot) {
        //
        // Calculate available time for possible movement:
        //
        int tmove = duration(SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug)) + duration(SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug)) + duration(SpireProc_Set_DcuFreqSamp(mclkdiv,biasdiv,phot,debug)) + duration(SpireProc_Set_PhotPhase(psw_phase,pmw_phase,plw_phase,ptc_phase,debug)) + duration(SpireProc_Set_PhotBias(psw_bias,pmw_bias,plw_bias,ptc_bias,debug)) + duration(SpireBb_SpecOffsetAuto(false,debug));
        //
        // Calculate max offset for which time is available:
        //
        int smecMaxOff = tmove * 500;
        // Note, 500 is maximum possible SMEC speed.
        int smecStart = smecHomePosn + smecMaxOff;
        // Note, formula above only reasonable 
        // when smecHomePosn small compared to 39500  
        // Safety check: 
        if(smecStart > 39500) {
            smecStart = 39500;
        }
        if(debug) {
            debug_print("smecStart: " + smecStart);
            debug_print("smecHomePosn: " + smecHomePosn);
            debug_print("tmove: " + tmove);
        }
        // 
        // Move from maximal offset to home:
        //
        SpireProc_SmecMove2Home(smecHomePosn,smecHomePosn + smecMaxOff,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    if(phot) {
        SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    }
    //delay(timeSlewCal);
    // //
    // //
    // Set requested frequency and phase plus first bias level:
    //
    SpireProc_Set_DcuFreqSamp(mclkdiv,biasdiv,phot,debug);
    if(phot) {
        SpireProc_Set_PhotPhase(psw_phase,pmw_phase,plw_phase,ptc_phase,debug);
        SpireProc_Set_PhotBias(psw_bias,pmw_bias,plw_bias,ptc_bias,debug);
    } else {
        SpireProc_Set_SpecBias(ssw_bias,slw_bias,debug);
        SpireProc_Set_SpecPhase(ssw_phase,slw_phase,debug);
    }
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartStdLoadCurve configuration ended");
    SpireMsg(1,"  ..StartStdLoadCurve took " + (time() - t) + " seconds)");
    //
}

// File          : CONF_chopper.cus
// Missionphase  : PACS FM Test
//
// Purpose       : Configure the chopper servo loop 
//
// Author        : DAC/MN
// CUSification  : DAC/MN
// Arguments     : 
// string calUfile  CAL-U file
// string calUcol   Column identifier
//                 
//
// Description   : Read servo loop parameters off a CALU table; a set
//                 of parameters is arranged as a column; different
//                 columns list different sets. Must specify the CALU
//                 file name and the column identification string.
//                 Example: CONF_chopper ("CONFChopper","nom_sky")
//                              
// Comments      :      
//
// Version       : 0.4
// History       : 0.1  9-nov-2006 Initial version
//                 0.2 22-feb-2007 Adapted to revised CONFChopper table
//                                (PosLimit  <=> Scaling
//                 0.3  8-mar-2007 Added 2sec delay at end per HD's mail
//                 0.4  9-jun-2007 Changed entries for new DECMEC (MN)
//                 0.4  9-jun-2007 newly optimised parameters (MN)
procedure CONF_chopper {
    string fileU = "CONFChopper"; // CAL-U file
    string calUcol = "nom_sky"; // Column identifier
}{
    // # DMC_WRT_CHOP_CONF_PAR (21 params). Use  values
    //   obtaied from CALU file
    int aKp = ilookup(fileU,"Kp",calUcol);
    int aKi = ilookup(fileU,"Ki",calUcol);
    int aKd = ilookup(fileU,"Kd",calUcol);
    int aKf = ilookup(fileU,"Kf",calUcol);
    int aRate = ilookup(fileU,"Rate",calUcol);
    int aAccumLimit = ilookup(fileU,"AccumLimit",calUcol);
    int aOutputLimit = ilookup(fileU,"OutputLimit",calUcol);
    int aPosLimit = ilookup(fileU,"PosLimit",calUcol);
    int aErrorLimit = ilookup(fileU,"ErrorLimit",calUcol);
    int aPosOffset = ilookup(fileU,"PosOffset",calUcol);
    int aKiCurr = ilookup(fileU,"KiCurr",calUcol);
    int aSelectFieldPlateLUT = ilookup(fileU,"SelectFieldPlateLUT",calUcol);
    int aSpare = ilookup(fileU,"Spare",calUcol);
    int aFilterN1 = ilookup(fileU,"FilterN1",calUcol);
    int aFilterN2 = ilookup(fileU,"FilterN2",calUcol);
    int aFilterN3 = ilookup(fileU,"FilterN3",calUcol);
    int aFilterD1 = ilookup(fileU,"FilterD1",calUcol);
    int aFilterD2 = ilookup(fileU,"FilterD2",calUcol);
    int aInductance = ilookup(fileU,"Inductance",calUcol);
    int aResistance = ilookup(fileU,"Resistance",calUcol);
    int aControlLoopGain = ilookup(fileU,"ControlLoopGain",calUcol);
    // Create tuple array and int array
    {int}[] list_tuple = [{aKp},{aKi},{aKd},{aKf},{aRate},{aAccumLimit},{aOutputLimit},{aPosLimit},{aErrorLimit},{aPosOffset},{aKiCurr},{aSelectFieldPlateLUT},{aSpare},{aFilterN1},{aFilterN2},{aFilterN3},{aFilterD1},{aFilterD2},{aInductance},{aResistance},{aControlLoopGain}];
    // Define as int [] to compute check sum
    int[] list_int = [aKp,aKi,aKd,aKf,aRate,aAccumLimit,aOutputLimit,aPosLimit,aErrorLimit,aPosOffset,aKiCurr,aSelectFieldPlateLUT,aSpare,aFilterN1,aFilterN2,aFilterN3,aFilterD1,aFilterD2,aInductance,aResistance,aControlLoopGain];
    int chksum = checksum("int",list_int);
    Pacs_DMC_WRT_CHOP_CONF_PAR(list_tuple,chksum);
    delay(2);
}

///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_CalGCO_FovMapCrossRaster.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Phot FOV Mapping Cross Raster' 
//
//         in *custom_map_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/09/16 V0.1: Initial version renamed from 
//                  SpirePhoto_CalGCO_PhotFovMapCrossRaster (2008/09/16 V0.2)
//                  Restrict input chopf.
// 2008/10/13 V0.2: Adapt to name changes in low level scripts. Remove
//                  stepsize restrictions.
// 2008/11/06 V0.3: Adapt to name change in low level script
// 2008/11/12 V0.4: Add serendipity mode; Mark missing debug_print
//                  Implement mode setting; Add isBright 
//                  Implement proper setting of MCU framerate
//                  Change default gyro re-calibration period
// 2009/03/17 V1.0: Use SpireBb_PhotSetMode to set to PHOTSTBY during 
//                  SLEW and FINAL_HOLD. Move debug parameter to
//                  input and pass to low level scripts. Replace call to 
//                  SpireProc_Set_BsmFramerate with call to 
//                  SpireBb_SetBsmFramerate (fixing SPR5890). 
//                  Set obsStep back to zero at FINAL_HOLD. Use new 
//                  SpireBb_EndObsAll and SpireBb_StartObsAll. 
//                  Implement setting of datarates. Add debug to 
//                  SpireBb_PhotOffsetAuto(). Remove unsetting of framerate 
//                  at FINAL_HOLD, now done in SpireBb_PhotSetMode. 
//                  Adapt new inputs by updated SpireBb_Chop. Replace
//                  SpireBb_BsmMove2Hold by SpireBb_BsmMove.
//                  Implement proper setting of MCU framerate, i.e. only set 
//                  if user request differenet value from default. Add 
//                  isSerendipity (replacing serendipity), isPcal, and 8 more 
//                  dummy parameters to the script for future use. Replaced 
//                  call to SpireProc_CalcParam_PhotFovMapCrossRaster with
//                  call to  SpireProc_CalcParam_FovMapCrossRaster.
//                  Adapt to modification in SpireProc_Exec_Serendipity. Make
//                  change to description of k. 
// 2009/05/05 V1.1: Add in move BSM to hold at start. Gather procedures at 
//                  start and end in separate BB. Remove isSerendipity approach.
// 2009/06/05 V1.2: Hardcode STBY 'v00' in EndBB (SPR-1477)
// 2009/09/05 V1.3: Allow to visit raster points in reverse order. 
//                  (SCR-SPIRE-1915)
// 
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in PHOTSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for all three arrays and could be taken from following cal table: 
//  SpireTable_PhotModeParams.txt
// 
//  3) Home position of BSM can be read from SpireTable_BsmNominalSettings.txt
//
//  4) Some VM parameters for chopping are read from following cal table:
//     SpireTable_CommandLists.txt
// 
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhoto_CalGCO_FovMapCrossRaster {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; //NAIF identifier: put '0' to use RA/DEC, or correct 'NAIFID'
    /* */
    bool isBright = false; // Use settings for bright source (==tick)
    string ib = "S14_0"; // Central aperture (defined in SIAM) of raster
    double d1 = 4.0; // Angular stepsize along Y axis [arcsec] 
    double d2 = 4.0; // Angular stepsize along Z axis [arcsec]
    int m = 9 in [3,2997]; // Total number of points in Y/Z [odd number, symmetric!]
    int k = 0; // Additional visits to GCP on each arm of the cross
    int ftime = 60; // Read-out time [s]
    double chopf = 2.0 in [0.1,4.0]; // Chop frequency [Hz] 
    int offChopfh = 9600; // off-source chop position (+ or - relative to hold) [Dec(Hex)]
    double framerate = 125.0; // Specifies the MCU framerate [Hz]
    int gcp_time = 20; // Time spend at GCP (gyro calibration position) [s]
    int gcp_period = 600; // Maximum time between successiv GCP visits [s]
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParas    
    string version03 = "v00"; // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial"; // Model in cal table SpireTable_BsmNominalSettings
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Visit raster pts in reverse order (==tick)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // //
    // //
    // Current restrictions:
    //
    if(naifid != 0) {
        error("Currently no SSO objects are allowed as input!");
    }
    // //
    // //
    // Assign spare parameters:
    //
    bool reverse = pBool1;
    // 
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = true;
    bool fts = !phot;
    //
    // Start timing of script:
    int start = time();
    //
    // Keep track of actual visits to GCP: 
    double maxgcp_period = 0.0;
    //
    // First obsstep [HEX]:
    int obsstep = 0x0;
    //
    // Count raster points: 
    int raster_counter = 0;
    //
    int obsStep = 0;
    int tslewminadd = 0;
    bool setFramerate = true;
    string version = "";
    string tabName = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    // DCU data mode (0 == Full photometer; 4 == Full spectrometer):
    int dcumode = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    string tabName04 = "SpireTable_CommandLists.txt";
    //
    // Dummy value for smecHomePosn (needed but not used in phot script!)
    int smecHomePosn = 3500;
    // SMEC home position
    //
    // Currently hardcoded parameter:
    // Useful length of serendipity observation
    int limit = 20;
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS03";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for setup and datarates:  
    string obsMode = "PEngCalObs";
    // Note: datarates are currently only maximum values
    // //
    // //
    // Setup parameters for BSM chopping movement: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version03;
    tabName = tabName03;
    string selCol = "model";
    // Name of column for selecting 
    string selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    string tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set chop/jigg positions:
    //    
    // on-source Chop position [Dec(Hex)]:
    int onChop = hold_chop;
    //
    // on-source Jiggle position:
    int onJigg = hold_jigg;
    //
    // off-source Chop position:
    int offChop = hold_chop + offChopfh;
    //
    // off-source Jiggle position:
    int offJigg = hold_jigg;
    // 
    // Read VM parameters from calibration table:
    //
    tabName = tabName04;
    selVal = "Chop";
    int vmId = ilookup(tabName,selVal,"Id");
    int vmIndex = ilookup(tabName,selVal,"Index");
    int nParms = ilookup(tabName,selVal,"Nparms");
    // //
    // //
    // Read nominal bias frequency and bias divider:
    //    
    // Select version flag and set GetTableEntry parameters:
    version = version01;
    tabName = tabName01;
    selCol = "mode";
    // Name of column for selecting 
    selVal = obsMode;
    // Value of 'string' selector
    //
    tarCol = "mclkDiv";
    int mclkdiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "biasDiv";
    int biasdiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Calculate nominal sampling rate from mclkdiv and biasdiv:
    //
    double mclkdivHz = 1.0E7 / (512.0 * double(mclkdiv + 1));
    double biasdivHz = 1.0 / (double(biasdiv) + 1.0) * mclkdivHz;
    if(debug) {
        debug_print("Nominal sampling rate is: " + biasdivHz + " [Hz]");
    }
    //
    // //
    // //
    // Compare read-out time and dwell time on GCP:
    //
    int dtime = 0;
    // time to be spend on GCP position
    if(gcp_time < ftime) {
        dtime = ftime;
    } else {
        dtime = gcp_time;
    }
    if(debug) {
        debug_print("ftime: " + ftime);
        debug_print("gcp_time: " + gcp_time);
        debug_print("dtime: " + dtime);
    }
    // //
    // //
    // Calculate BSM chop parameters:
    //
    int[] chopparam1 = SpireProc_CalcParam_BsmSetup(ftime,chopf,biasdivHz,framerate,debug);
    int ncycles = chopparam1[0];
    int chop_period = chopparam1[1];
    int dcusample = chopparam1[2];
    int dcudelay = chopparam1[3];
    int bsmsample = chopparam1[4];
    //
    int[] chopparam2 = SpireProc_CalcParam_BsmSetup(dtime,chopf,biasdivHz,framerate,debug);
    int ncycles_2 = chopparam2[0];
    int chop_period_2 = chopparam2[1];
    int dcusample_2 = chopparam2[2];
    int dcudelay_2 = chopparam2[3];
    int bsmsample_2 = chopparam2[4];
    // //
    // //
    // Compare user input of BSM framerate with default value:
    //
    version = version02;
    tabName = tabName02;
    tarCol = "bsmFrameRate";
    int bsmFrameRate = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    double bsmFrameRateHz = 1000000.0 / (double(bsmFrameRate) * 420.0);
    if(debug) {
        debug_print("Nominal BSM sampling rate is: " + bsmFrameRateHz + " [Hz]");
    }
    //
    // Compare nominal with input BSM framerate:
    // 
    int frate = SpireProc_CalcParam_BsmFramerate(framerate,debug);
    if(frate == bsmFrameRate) {
        setFramerate = false;
    }
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    // 
    int tslewmin = duration(SpireBb_StartFovMapCrossRaster(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,setFramerate,frate,smecHomePosn,debug));
    //
    //BBs carried out when the pointing is reached:
    //
    int tinithold = 0;
    //
    // BB carried out during pointing:
    // 
    int tp_np = duration(SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles,chop_period,dcumode,dcusample,dcudelay,bsmsample,9999,debug)) + duration(SpireBb_PhotOffsetAuto(debug));
    int tp_gp = duration(SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles_2,chop_period_2,dcumode,dcusample_2,dcudelay_2,bsmsample_2,9999,debug)) + duration(SpireBb_PhotOffsetAuto(debug));
    //    
    // BB carried out at the end:
    //
    int tfinalhold = duration(SpireBb_EndFovMapCrossRaster(phot,hold_chop,hold_jigg,isBright,version01,version02,debug));
    // //
    // //
    // Debug printing:
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing normal= " + tp_np);
        debug_print("tpointing @GCP= " + tp_gp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                              */
    // ****************************************************** */
    // //
    // //
    // Fixed parameters for pointing mode:
    //   
    // Pattern orientation (true==sky; false==array):
    bool fixed = false;
    //
    // Rotation angle of the pattern:
    double patt = 90.0;
    //
    // Offset of pattern in the direction of the +Y:
    double yoffset = 0.0;
    //
    // Offset of pattern in the direction of the +Z:
    double zoffset = 0.0;
    //
    // The duration of the hold when nhold>0:
    int thold = 0;
    //
    // Number of nods or raster points or scan lines before
    // performing a hold.
    int nhold = 0;
    //              
    double pattnod = 0.0;
    //
    double chopthrow = 2.0;
    //
    int nnod = 1;
    //
    int knod = 0;
    //
    int nload = 0;
    //
    int tloadmin = 0;
    //
    // //
    // //
    // Calculate array of points:
    //
    {double[],double[],bool[]} array = SpireProc_CalcParam_FovMapCrossRaster(d1,d2,m,k,reverse,debug);
    double[] zarray = array{0};
    double[] yarray = array{1};
    bool[] raster = array{2};
    int nump = length(yarray);
    // //
    // //
    // Set pointing vector: 
    //
    int[] tpv = [0];
    for(int index = 0 .. nump - 1) {
        if(raster[index]) {
            tpv[index] = tp_np;
        } else {
            tpv[index] = tp_gp;
        }
        index = index + 1;
    }
    if(debug) {
        debug_print("tpv = " + tpv);
    }
    // //
    // //
    // Set pointing mode:
    //
    //custom_map_pointing(true, tslewmin, tinithold, tfinalhold, ib, naifid,
    //ra,dec,fixed,patt,yoffset,zoffset,yarray,zarray,tpv, pattnod,chopthrow,
    //nnod,knod,tloadmin,nload, thold, nhold);
    //
    int[] ts = custom_map_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,fixed,patt,yoffset,zoffset,yarray,zarray,tpv,pattnod,chopthrow,nnod,knod,tloadmin,nload,thold,nhold);
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC              */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //     
            SpireBb_StartFovMapCrossRaster(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,setFramerate,frate,smecHomePosn,debug);
            // //
            // //
            // Perform serendipity operation if possible:
            //
            //
            // Read slew time from pointing mode:
            //int tslew = ts[1];
            // Slew time    
            //
            // Minimum time for a serendipity observation:
            //int tSerendipity = duration(SpireProc_Exec_Serendipity(0,debug));
            //if(debug) {
            //    debug_print("Minimum time for a serendipity observation: " + tSerendipity);
            //}
            // 
            //if(tslew > tSerendipity + tslewmin + 20) {
            //    // Time remaining for serendipity observation:
            //    int stime = tslew - tslewmin;
            //    // 
            //    // Execute observation: 
            //    if(isSerendipity) {
            //        SpireProc_Exec_Serendipity(stime,debug);
            //    }
            //}
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            //
            //
            //delay(tinithold);
        }
        if(state[0] == 3) {
            // STATE = POINT (spacecraft is at nominal RA,DEC (staring, raster))
            // //
            // //
            // Set offsets at each raster point:
            //
            SpireBb_PhotOffsetAuto(debug);
            // //
            // //
            // Different timings for different raster points (normal vs. GCP):
            // 
            if(raster[raster_counter] == false) {
                // //
                // //
                // Show time elapsed between visits to GCP:
                //
                if(raster_counter == 0) {
                    // Reset timer:
                    start = time();
                } else {
                    int t = time() - start;
                    // Check elapsed time and give out error:
                    maxgcp_period = max(maxgcp_period,double(t));
                    if(maxgcp_period > double(gcp_period)) {
                        error("gcp_period constraint violated!! Increase k parameter by 1");
                    }
                    message("Time elapsed since last visit to GCP: " + t);
                    if(debug) {
                        debug_print("Time elapsed since last visit to GCP: " + t);
                        debug_print("Maximum time between two GCPs: " + maxgcp_period);
                    }
                    //
                    // Reset timer:           
                    start = time();
                }
                // //
                // //
                // Run chop VM (includes data taking) and set obs step parameter: 
                //
                if(debug) {
                    debug_print("Chop on GCP raster point!");
                }
                SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles_2,chop_period_2,dcumode,dcusample_2,dcudelay_2,bsmsample_2,65535,debug);
                //
            } else {
                // //
                // //
                // Run chop VM (includes data taking) and set obs step parameter: 
                //
                if(debug) {
                    debug_print("Chop on regular raster point!");
                }
                SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles,chop_period,dcumode,dcusample,dcudelay,bsmsample,obsstep,debug);
                obsstep = obsstep + 1;
                //
            }
            raster_counter = raster_counter + 1;
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ("sky" observation ends, performing final activities )
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            version03 = "v00";
            model = "initial";
            //
            SpireBb_EndFovMapCrossRaster(phot,hold_chop,hold_jigg,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END (end of the pointing/commanding part of the code)
            //
        }
    }
}

// SpireEngDumpMemory
//
// $id$
//
// This observation dumps the entire DPU Memory (DM, PM and EEPROM)
//
// The instrument should normally be in REDY mode before execution
// of this observation.
//
//
// 17/05/2010 SDS: First Version 1.0 
//                 Created in response to SCR-SPIRE-2589
//
///////////////////////////////////////////////////////////////////////////
obs SpireEngDumpMemory {
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use)
    int pInt2 = 0; // Spare parameter (currently not in use)
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int t = duration(SpireBbStartObs()) + duration(SpireBbEndObs());
    t = t + duration(SpireBb_DumpMemory());
    //
    // ***********************************************
    int[] ts = no_pointing(true,0,0,t);
}{
    SpireMsg(0,"Observation Start");
    SpireMsg(3,"       $Id:$");
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            SpireBbStartObs();
            // Perform a full Memory Dump 
            SpireBb_DumpMemory();
            // 
            SpireBbEndObs();
        }
    }
    SpireMsg(0,"Observation Completed  (" + time() + " seconds)");
    SpireMsg(0,"Note: Total time (s) = Observation Completed time - slew time + Observatory Overheads");
}

// Missionphase  : 
//
// Purpose       : Move the PHOT filter wheel to one of the two defined
//                 positions
//                  
// TCL script    : N/A
// CUS script    : Diego A. Cesarsky
//
// CVS file      : PHOT_fltw_move.txt 
//
// Arguments     : 
// Type    Name      DefVal  Description
// string  flt_id    POS A   One of two preset positions [POS A, POS B]
//
// Description   : Switch ON filter controller, move wheel, switch OFF
//                  
// Dependencies  : Low level PACS TCs
//
// Preconditions : Servo loop already configured
//                 
// Comments      : useless comment by Bart
//                        Quite useless indeed!
//
// Version       : 0.1 13-Aug-2004 Creation by DAC
// History       : 0.2 28-Oct-2004 Renamed from FLTW_move.txt; demoded
//                                 from BB to simple procedure
//                 0.3 13-apr-2005 DAC Renamed from BOLO_flt_move, filter_id
//                                 is now a string (ENG value)
//                 0.4 20-1pr-2005 DAC Read wheel move time from PACSparams 
//                 0.5 19-feb-2008 Return time in sec
//               :
int procedure PHOT_fltw_move {
    string filter_id = "POS A" in ["POS A","POS B"];
}{
    // Get the duration of the move
    int move_time = iceil(dlookup("PACSparams","fltw_time","freq_time"));
    // Same in [sec]
    int move_time_sec = Msec2sec(move_time);
    //  debug_print("PHOT fltw moves to " + filter_id + 
    //              "; " + move_time_sec + " [sec]");
    // Set the filter wheel: switch on the filter/grating controller
    Pacs_DMC_SWON_FW_PHOTO();
    // Move filter to desired position 
    Pacs_DMC_MOVE_PHOT_FW_LOC(filter_id);
    // Wait move_time_sec sec for wheel to end its movement
    delay(move_time_sec);
    // Switch off the controller
    Pacs_DMC_SWOF_GRAT_CONT();
    // Return duration

    return move_time_sec;
}

// SpirePOF3Estimate
//
// $Id: SpirePOF3Estimate.txt,v 1.5 2007/04/20 16:05:49 kking Exp $
//
// This procedure calculates the estimated noise and signal/noise
//  for the given observing time.
//
//  for input values, a value less than 0 indicates value unknown
//
//  20/04/07: v1.3: SCR3054
//            v1.5: SCR3012
//
{string,double,double,double,double,bool,double,double,double}[] procedure SpirePOF3Estimate {
    double osit = 0.0; // on-source integration time
    double sourceFluxPSW = -1.0;
    double sourceFluxPMW = -1.0;
    double sourceFluxPLW = -1.0;
    double sourceBrightPSW = -1.0;
    double sourceBrightPMW = -1.0;
    double sourceBrightPLW = -1.0;
    bool isBright = false;
}{
    SpireMsg(3,"          Calculating POF3 noise estimates");
    SpireMsg(3,"          $Id: SpirePOF3Estimate.txt,v 1.5 2007/04/20 16:05:49 kking Exp $");
    SpireMsg(3,"          Input:");
    SpireMsg(3,"            Osit: " + osit);
    SpireMsg(3,"            PSW Flux density: " + sourceFluxPSW);
    SpireMsg(3,"            PMW Flux density: " + sourceFluxPMW);
    SpireMsg(3,"            PLW Flux density: " + sourceFluxPLW);
    SpireMsg(3,"            PSW Surface Brightness: " + sourceBrightPSW);
    SpireMsg(3,"            PMW Surface Brightness: " + sourceBrightPMW);
    SpireMsg(3,"            PLW Surface Brightness: " + sourceBrightPLW);
    SpireMsg(3,"            isBright: " + isBright);
    //
    // fetch the flux uncertainty information for POF3
    string tabName = "Phot_Sensitivities.txt";
    if(isBright) {
        tabName = "Phot_BrightSensitivities.txt";
    }
    double psw_func = dlookup(tabName,"POF3","PSWFluxUnc");
    double pmw_func = dlookup(tabName,"POF3","PMWFluxUnc");
    double plw_func = dlookup(tabName,"POF3","PLWFluxUnc");
    // fetch the surface brightness uncertainty information for POF3
    double psw_bunc = dlookup(tabName,"POF3","PSWBrightUnc");
    double pmw_bunc = dlookup(tabName,"POF3","PMWBrightUnc");
    double plw_bunc = dlookup(tabName,"POF3","PLWBrightUnc");
    // fetch confusion limits
    double psw_conf = dlookup(tabName,"POF3","PSWConfLim");
    double pmw_conf = dlookup(tabName,"POF3","PMWConfLim");
    double plw_conf = dlookup(tabName,"POF3","PLWConfLim");
    SpireMsg(3," Input Sensitivity Values:");
    SpireMsg(3,"            Band:                                                               PSW                   PMW                        PLW");
    SpireMsg(3,"            Flux Uncertainty:                                    " + psw_func + "            " + pmw_func + "          " + plw_func);
    SpireMsg(3,"            SUrface Brightness Uncertainty:        " + psw_bunc + "            " + pmw_bunc + "          " + plw_bunc);
    SpireMsg(3,"            Conf Limit:                                              " + psw_conf + "            " + pmw_conf + "          " + plw_conf);
    //
    // calculate noise estimates
    {string,double,double,double,double,bool,double,double,double}[] estimates = [{"250",sourceFluxPSW,-1.0,-1.0,psw_conf,false,sourceBrightPSW,-1.0,-1.0},{"350",sourceFluxPMW,-1.0,-1.0,pmw_conf,false,sourceBrightPMW,-1.0,-1.0},{"500",sourceFluxPLW,-1.0,-1.0,plw_conf,false,sourceBrightPLW,-1.0,-1.0}];
    estimates[0]{2} = psw_func / sqrt(osit);
    if(estimates[0]{2} < psw_conf) {
        estimates[0]{5} = true;
    }
    if(sourceFluxPSW >= 0.0) {
        estimates[0]{3} = sourceFluxPSW / estimates[0]{2};
        if(estimates[0]{3} > 200.0) {
            estimates[0]{3} = 200.0;
        }
    }
    estimates[0]{7} = psw_bunc / sqrt(osit);
    if(sourceBrightPSW >= 0.0) {
        estimates[0]{8} = sourceBrightPSW / estimates[0]{7};
        if(estimates[0]{8} > 200.0) {
            estimates[0]{8} = 200.0;
        }
    }
    estimates[1]{2} = pmw_func / sqrt(osit);
    if(estimates[1]{2} < pmw_conf) {
        estimates[1]{5} = true;
    }
    if(sourceFluxPMW >= 0.0) {
        estimates[1]{3} = sourceFluxPMW / estimates[1]{2};
        if(estimates[1]{3} > 200.0) {
            estimates[1]{3} = 200.0;
        }
    }
    estimates[1]{7} = pmw_bunc / sqrt(osit);
    if(sourceBrightPMW >= 0.0) {
        estimates[1]{8} = sourceBrightPMW / estimates[1]{7};
        if(estimates[1]{8} > 200.0) {
            estimates[1]{8} = 200.0;
        }
    }
    estimates[2]{2} = plw_func / sqrt(osit);
    if(estimates[2]{2} < plw_conf) {
        estimates[2]{5} = true;
    }
    if(sourceFluxPLW >= 0.0) {
        estimates[2]{3} = sourceFluxPLW / estimates[2]{2};
        if(estimates[2]{3} > 200.0) {
            estimates[2]{3} = 200.0;
        }
    }
    estimates[2]{7} = plw_bunc / sqrt(osit);
    if(sourceBrightPLW >= 0.0) {
        estimates[2]{8} = sourceBrightPLW / estimates[2]{7};
        if(estimates[2]{8} > 200.0) {
            estimates[2]{8} = 200.0;
        }
    }
    //
    // return values          
    SpireMsg(3," Output Estimates:");
    SpireMsg(3,"            Band:                                   " + estimates[0]{0} + "            " + estimates[1]{0} + "            " + estimates[2]{0});
    SpireMsg(3,"            Source Flux                        " + estimates[0]{1} + "            " + estimates[1]{1} + "            " + estimates[2]{1});
    SpireMsg(3,"            1 Sigma  Flux Noise:        " + estimates[0]{2} + "            " + estimates[1]{2} + "            " + estimates[2]{2});
    SpireMsg(3,"            Flux Signal/Noise:             " + estimates[0]{3} + "            " + estimates[1]{3} + "            " + estimates[2]{3});
    SpireMsg(3,"            Conf Level:                          " + estimates[0]{4} + "            " + estimates[1]{4} + "            " + estimates[2]{4});
    SpireMsg(3,"            Conf Flag:                           " + estimates[0]{5} + "            " + estimates[1]{5} + "            " + estimates[2]{5});
    SpireMsg(3,"            1 Sigma  Brightness Noise:        " + estimates[0]{7} + "            " + estimates[1]{7} + "            " + estimates[2]{7});
    SpireMsg(3,"            Brightness Signal/Noise: " + estimates[0]{8} + "            " + estimates[1]{8} + "            " + estimates[2]{8});
    //

    return estimates;
}

//CLName: SpireBb_LoadTableJM64b
//VMVersion: 2.8
//CLVersion: 1.0
//CLCVSId: $ID$
//TableId: 0x39
//TableLength: 0x80
//Date: 090814140348
block SpireBb_LoadTableJM64b SPIRE 3360 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableJM64b started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0x39
    Spire_SET_TABLE(0x39,0x80);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x39,0x0,38,[{0xa192d122},{0xa192d122},{0xa922d27e},{0xa922d27e},{0xb0b2d122},{0xb0b2d122},{0xbfd2d122},{0xbfd2d122},{0xb842d27e},{0xb842d27e},{0xb0b2d3ce},{0xb0b2d3ce},{0xb842d513},{0xb842d513},{0xb0b2d64d},{0xb0b2d64d},{0xb0b2d89c},{0xb0b2d89c},{0xa922d9b1},{0xa922d9b1},{0xa192d89c},{0xa192d89c},{0xa922d77a},{0xa922d77a},{0xa192d64d},{0xa192d64d},{0xa922d513},{0xa922d513},{0xa192d3ce},{0xa192d3ce},{0x9a02d27e},{0x9a02d27e},{0x9271d122},{0x9271d122},{0x8ae1d27e},{0x8ae1d27e},{0x9271d3ce},{0x9271d3ce}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x39,0x26,38,[{0x9a02d513},{0x9a02d513},{0x9271d64d},{0x9271d64d},{0x9a02d77a},{0x9a02d77a},{0x9a02d9b1},{0x9a02d9b1},{0x9271d89c},{0x9271d89c},{0x8ae1d9b1},{0x8ae1d9b1},{0x8ae1d77a},{0x8ae1d77a},{0x8351d64d},{0x8351d64d},{0x8ae1d513},{0x8ae1d513},{0x8351d3ce},{0x8351d3ce},{0x7bc1d27e},{0x7bc1d27e},{0x8351d122},{0x8351d122},{0x8ae1cfbb},{0x8ae1cfbb},{0xa922cfbb},{0xa922cfbb},{0xb0b2ce49},{0xb0b2ce49},{0xb842cfbb},{0xb842cfbb},{0xbfd2ce49},{0xbfd2ce49},{0xb842cccd},{0xb842cccd},{0xb0b2cb46},{0xb0b2cb46}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x39,0x4c,38,[{0xb842c9b5},{0xb842c9b5},{0xb0b2c81a},{0xb0b2c81a},{0xb0b2c4c7},{0xb0b2c4c7},{0xa922c675},{0xa922c675},{0xa192c4c7},{0xa192c4c7},{0xa192c81a},{0xa192c81a},{0xa922c9b5},{0xa922c9b5},{0xa192cb46},{0xa192cb46},{0xa922cccd},{0xa922cccd},{0xa192ce49},{0xa192ce49},{0x9271ce49},{0x9271ce49},{0x8ae1cccd},{0x8ae1cccd},{0x8351ce49},{0x8351ce49},{0x7bc1cfbb},{0x7bc1cfbb},{0x7bc1cccd},{0x7bc1cccd},{0x8351cb46},{0x8351cb46},{0x8ae1c9b5},{0x8ae1c9b5},{0x8351c81a},{0x8351c81a},{0x8ae1c675},{0x8ae1c675}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x39,0x72,14,[{0x9271c4c7},{0x9271c4c7},{0x9a02c675},{0x9a02c675},{0x9271c81a},{0x9271c81a},{0x9a02c9b5},{0x9a02c9b5},{0x9271cb46},{0x9271cb46},{0x9a02cccd},{0x9a02cccd},{0x9a02cfbb},{0x9a02cfbb}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x39,0x0,0x0);
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableJM64b ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

// CVS comments  : $Id: PacsPhotDefaults.txt,v 1.1 2008/05/26 15:12:49 vanessad Exp $ 
// Purpose       : Fill index=0 of OBCP and PHOTxxx tuples with known
//                 sensible default values
//
// CUS author    : DAC
// Script file   : PacsPhotDefaults.txt 
//
// Input arguments
// type           name     Description
// string         srcID    HSPOT define source ID
//
// Return values
// Type    Name                  Description
// tuple   confPHOTx & confOBCP  electronics and OBCP default parameters
//
// Description   : Give default values to tuples OBCP and PHOT. May
// use more information from yet to be created CAL-U files. So far
// only "throw" (HSPOT defined) appears necessary as a call argument
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : 
// 
// History       : 0.1 29-nov-2005 DAC. Based on PacsSpecDefaults
// 0.2 18-jan-2006 Introduced string calU variable
// 0.3 20-jan-2006 Use new PHOT_CHOP_params table where chopper positions
//     are defined in arcsec; added verbose
// 1.0  1-sep-2006 - Use sourceID instead of "throw" since chopper 
//                   throw depends on SRCE
//                 - editorial clean
// 2.0 10-oct-2007 Implemented SCR-3628: introduction of CAL-U file
//                 CONF_PHOT_params. This requires adding a new input
//                 variable: primePar
// 2.1 18-jun-2009 VD implement SCR PACS-1722
//
{{int,int,int,int,int,int,int,int,int},{int,int,int,int,int,int,int,int,int},{int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int}} procedure PacsPhotDefaults {
    string srcID = "pointSRC" in ["pointSRC","smallSRC","largeSRC"]; // SourceID
    string primePar = "Prime" in ["Prime","Parallel"]; // Observing mode
    bool isBrightPacs = false;
    bool verbose = true; // Generate bla-bla
}{
    // Define variables to be used here
    {int,int,int,int,int,int,int,int,int} confPHOTblu = {0,0,0,0,0,0,0,0,0};
    {int,int,int,int,int,int,int,int,int} confPHOTred = {0,0,0,0,0,0,0,0,0};
    {int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int} confOBCP = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    // Open CAL-U with compression, raw pixels, etc. information
    if(isBrightPacs) {
        if(primePar == "Parallel") {
            string modePar = "ParBright";
        } else {
            if(primePar == "Prime") {
                modePar = "BrightPacs";
            }
        }
    } else {
        modePar = primePar;
    }
    int gain_red = ilookup("CONF_PHOT_params","gain_red",modePar);
    confPHOTred{0} = gain_red;
    int gain_blu = ilookup("CONF_PHOT_params","gain_blu",modePar);
    confPHOTblu{0} = gain_blu;
    int comp_mode_red = ilookup("CONF_PHOT_params","comp_mode_red",modePar);
    confPHOTred{3} = comp_mode_red;
    int comp_mode_blu = ilookup("CONF_PHOT_params","comp_mode_blu",modePar);
    confPHOTblu{3} = comp_mode_blu;
    int nb_raw_red = ilookup("CONF_PHOT_params","nb_raw_red",modePar);
    confPHOTred{6} = nb_raw_red;
    int nb_raw_blu = ilookup("CONF_PHOT_params","nb_raw_blu",modePar);
    confPHOTblu{6} = nb_raw_blu;
    // Chopper and grating expected at their default positions
    string calU = "SPEC_MEC_Defaults";
    int chop_def = ilookup(calU,"Photometry","chopper");
    confOBCP{17} = chop_def;
    // Position filter wheel at default position
    //   int fw_pos       = ilookup(calU,"Photometry","FW");
    // Initialize to don't care/don't know
    int fw_pos = 1;
    confOBCP{19} = fw_pos;
    int nb_cycles_obs_cal = 1;
    confOBCP{0} = nb_cycles_obs_cal;
    int nb_SRC_OFF = 1;
    confOBCP{3} = nb_SRC_OFF;
    int nb_rdouts_plateau = 4;
    confOBCP{4} = nb_rdouts_plateau;
    int nb_CS1_CS2 = 0;
    confOBCP{5} = nb_CS1_CS2;
    // Read chopper positions [arcsec] and convert to ENG units
    calU = "PHOT_CHOP_params";
    string convU = "PHOT_CHOP_sky";
    double auxSRC = dlookup(calU,srcID,"SRC");
    int onSRC = PacsReadChopSky(convU,auxSRC);
    double auxREF1 = dlookup(calU,srcID,"REF1");
    int onREF1 = PacsReadChopSky(convU,auxREF1);
    double auxREF2 = dlookup(calU,srcID,"REF2");
    int onREF2 = PacsReadChopSky(convU,auxREF2);
    // Report settings if verbose
    if(verbose) {
        debug_print("++PhotDefaults CHOPPER: " + auxSRC + " [arcsec] -> " + onSRC + " [ENG]");
        debug_print("++PhotDefaults CHOPPER: " + auxREF1 + " [arcsec] -> " + onREF1 + " [ENG]");
        debug_print("++PhotDefaults CHOPPER: " + auxREF2 + " [arcsec] -> " + onREF2 + " [ENG]");
    }
    confOBCP{12} = onSRC;
    confOBCP{13} = onREF1;
    confOBCP{14} = onREF2;
    // chop_pos_CS1     = confOBCP[0]{15};
    // chop_pos_CS2     = confOBCP[0]{16};
    int detector = 1;
    confOBCP{18} = detector;

    return {confPHOTblu,confPHOTred,confOBCP};
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Exec_SpecMultiLevelNoise.txt
//
///////////////////////////////////////////////////////////
//
//  Procedure to loop through a list of bias amplitudes for
//  the 'Spec Multi-Level Noise ' task setting the correct 
//  phase included in calibration table. 
//
///////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/09/09 V0.1: Initial version adapted from
//                  SpireProc_Exec_PhotMultiLevelNoise (2008/08/04 V0.3)
// 2009/02/19 V0.2: Adapt to change in cal table setup. Add debug_print 
//                  option (also to low level scripts). Fixed bug, 
//                  biasfreq and samplerate were not set each time in the loop. 
//                  SpireProc_CalcParam_SpecMultiLevelNoiseLevels changed,
//                  adapt reading of return values. 
// 2009/03/04 V0.3: Implement isBright setting in the way of adapting
//                  the phase at each bias amplitude level. 
//
// Sunil Sidher 
// 2009/07/21 V0.4: Implemented isPcal flag to perform standard AOT style PCAL flashes after each bias setting
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Exec_SpecMultiLevelNoise {
    double biasfreq = 160.09; // Bias frequency (Hz)
    double samplerate = 80.05; // Sampling frequency (Hz)
    string tabName01 = "SpireTable_SpecMultiLevelNoiseLevels.txt"; // Calibration table name 
    string version01 = "v00"; // Version parameter defined in calibration table
    bool isBright = false; // Use settings for bright source (==tick)
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it?
    string tabName02 = "SpireTable_IsBrightPhaseShift.txt"; // Calibration table name 
    string version02 = "v00"; // Version parameter defined in calibration table
    int ftime = 300; // Readout time at each bias level [s]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = false;
    bool fts = !phot;
    // //
    // //
    // Read isBright phase shift from calibration table:
    //
    int specPhaseShift = ilookup(tabName02,version02,"specPhaseShift");
    // //
    // //
    // Convert input and read correct levels from calibration table:  
    //
    {string,int,int,int,double,double}[] level_table = SpireProc_CalcParam_SpecMultiLevelNoiseLevels(biasfreq,samplerate,tabName01,version01,debug);
    int size = length(level_table);
    if(debug) {
        debug_print("size = " + size);
        debug_print("Version selector used in calibration table: " + version01);
    }
    // //
    // //
    // Create list of bias levels and associated phases:
    //
    int[] nbiaslist = [];
    int[] sswnphaselist = [];
    int[] slwnphaselist = [];
    //
    for(int j = 0 .. size - 1) {
        if(debug) {
            debug_print("level_table = " + level_table[j]);
        }
        {string,int,int,int,double,double} row = level_table[j];
        int mclkDiv = row{1};
        int biasDiv = row{2};
        nbiaslist[j] = row{3};
        double sswphase = row{4};
        sswnphaselist[j] = iround(sswphase * 255.0 / 360.0);
        double slwphase = row{5};
        slwnphaselist[j] = iround(slwphase * 255.0 / 360.0);
        if(isBright) {
            sswnphaselist[j] = SpireProc_CalcParam_IsBrightPhaseShift(sswnphaselist[j],specPhaseShift,debug);
            slwnphaselist[j] = SpireProc_CalcParam_IsBrightPhaseShift(slwnphaselist[j],specPhaseShift,debug);
        }
    }
    if(debug) {
        debug_print("mclkdiv/biasdiv = " + mclkDiv + "/" + biasDiv);
    }
    // //
    // //
    // Set selected bias frequency and sampling rate before loop:
    //
    SpireBb_DcuSetFreqSamp(mclkDiv,biasDiv,phot,debug);
    // //
    // //
    // Start the bias loop:
    //
    for(int l = 0 .. length(nbiaslist) - 1) {
        // //
        // //
        // Safety checks:
        //
        if(nbiaslist[l] > 255) {
            nbiaslist[l] = 255;
            debug_print("Input bias amplitude list is corrupt! Raw value > 255 requested!");
        }
        if(sswnphaselist[l] > 255) {
            sswnphaselist[l] = 255;
            debug_print("Input SSW bias phase list is corrupt! Raw value > 255 requested!");
        }
        if(slwnphaselist[l] > 255) {
            slwnphaselist[l] = 255;
            debug_print("Input SLW bias phase list is corrupt! Raw value > 255 requested!");
        }
        // //
        // //
        // Set bias amplitude and phase:
        //
        if(debug) {
            debug_print("the biaslevel is :" + nbiaslist[l] + " SSW phase is: " + sswnphaselist[l] + "; SLW phase is: " + slwnphaselist[l]);
        }
        //
        // Set bias amplitude:
        SpireBb_SpecFSetBiasAmpl(nbiaslist[l],nbiaslist[l],debug);
        //
        // Set phase:
        SpireBb_SpecFSetPhase(sswnphaselist[l],slwnphaselist[l],debug);
        // //
        // //
        // Stop DCU data before resetting offsets:
        //
        SpireBb_StopDcuData();
        //
        // //
        // //
        // Set offsets:
        //
        // DCU data is stopped:
        bool dcuData = false;
        SpireBb_SpecOffsetAuto(dcuData,debug);
        // //
        // //
        // Take data:
        //
        SpireBb_SpecFTakeData(ftime,debug);
        //
        // //
        // //
        // Perform standard AOT style PCAL flash
        if(isPcal) {
            SpireBbPcalFlash("SFlashEng","v00",0,false);
        }
        // //
        // //
        // Printing: 
        //
        if(debug) {
            debug_print("Bias level " + nbiaslist[l] + " done.");
        }
    }
    //
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Exec_PhotLoadCurvePcalOn.txt
//
///////////////////////////////////////////////////////////
//
//  Procedure to loop through a list of bias amplitudes 
//  for the 'Phot Load Curve Pcal On' task 
//
///////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/04/01 V0.1: Initial version adapted from
//                  SpireProc_Exec_PhotStdLoadCurve (2009/02/01 V1.0)
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Exec_PhotLoadCurvePcalOn {
    int[] nbiaslist = [0,50,100,255]; // List of raw bias levels in range (0-255)
    int ftime = 10; // Readout time at each bias level [s]
    double pcal_bias = 3.8 in [0.0,7.0]; // PCAL bias level [mA]
    string version = "v01"; // Version in cal table SpireTable_PcalCurrentConvCoef
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Switch on PCAL:
    //
    SpireBb_PcalOn(pcal_bias,version,debug);
    // //
    // //
    // Start the LC bias loop:
    //
    for(int l = 0 .. length(nbiaslist) - 1) {
        // //
        // //
        // Safety check:
        //
        if(nbiaslist[l] > 255) {
            nbiaslist[l] = 255;
            if(debug) {
                debug_print("Input bias list is corrupt! Raw value > 255 requested!");
            }
        }
        // //
        // //
        // Set bias amplitude:
        //
        if(l == 0) {
            if(debug) {
                debug_print("Bias already set during slew");
            }
        } else {
            SpireBb_PhotFSetBiasAmpl(nbiaslist[l],nbiaslist[l],nbiaslist[l],nbiaslist[l],debug);
        }
        // //
        // //
        // Stop DCU data before resetting offsets:
        //
        SpireBb_StopDcuData();
        // //
        // //
        // Set offsets:
        //
        SpireBb_PhotOffsetAuto(debug);
        // //
        // //
        // Take data:
        //
        SpireBb_PhotFTakeData(ftime,debug);
        // //
        // //
        // Debug printing: 
        //
        if(debug) {
            debug_print("Bias level " + nbiaslist[l] + " done.");
        }
    }
    // //
    // //
    // Switch off PCAL:
    //
    SpireBb_PcalOn(0.0,version,debug);
    //
}

// CVS comments  : $Id: PacsDureeOBCP4.txt,v 1.2 2007/04/25 15:14:04 dcesarsk Exp $ 
// Purpose       : Estimate duration of OBCP4 with input parameters
//
// CUS author    : 
// Script file   : PacsDureeOBCP4.txt 
//
// Input arguments
// type    name         description
//
// Return values
// Type          Description
//
// Description   : 
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : 
// 
// History       : V0.1  24-nov-2005 DAC
// V0.2  1-Dec-2005 Add OBCP's 5 [sec] overhead to estimate based on DMC duration
int[] procedure PacsDureeOBCP4 {
    int nb_SRC_REF = 4; // p01 Nb of cycles SRC->REF1->SRC->REF2
    int nb_rdouts_plateau = 4; // p03 Nb of readouts per chopper plateau
    int nb_cycles_obs_cal = 1; // p06 Nb of repetions of OBS-CAL cycle
    int nb_CS1_CS2 = 0; // p07 Nb of cycles CS1->CS2
}{
    // Call the corresponding DMC sequence
    int[] duree = DMC_phot_2_3_chop(nb_SRC_REF,nb_rdouts_plateau,nb_cycles_obs_cal,nb_CS1_CS2);
    // Convert number of readouts into seconds
    // Obtain system parameter from PACSparams
    // BOL readout frequency [Hz] and readout period [msec]
    double bol_freq = dlookup("PACSparams","bolo_sample","freq_time");
    // string bol_unit = slookup("PACSparams","bolo_sample","unit");
    double bol_period = 1000.0 / bol_freq;
    // debug_print("Bolo sample: " + bol_freq + " " + bol_unit);
    // debug_print("Bolo period: " + bol_period + "[msec]");
    // Convert duration [rdouts] into [msec]
    // Create return time array; convert into [sec]
    int[] time_array = [0,0,0,0,0];
    for(int aux = 0 .. 4) {
        time_array[aux] = ifloor(double(duree[aux]) * bol_period);
        time_array[aux] = Msec2sec(time_array[aux]);
    }
    //
    // V0.2 correction
    time_array[0] = time_array[0] + 5;
    time_array[4] = time_array[4] + 5;
    // Return total duration [sec] to calling program

    return time_array;
}

// CVS comments  : $Id: PacsDureeOBCP3.txt,v 1.2 2007/04/25 15:14:04 dcesarsk Exp $ 
// Purpose       : Estimate duration of OBCP3 with input parameters
//
// CUS author    : 
// Script file   : PacsDureeOBCP3.txt 
//
// Input arguments
// type    name         description
//
// Return values
// Type          Description
//
// Description   : Compute duration of DEC/MEC sequence associated to OBCP3.
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      :
// 
// History       : 0.1  10-aug-2006 DAC
int[] procedure PacsDureeOBCP3 {
    int nb_main_loops = 1; // p01 Nb of main loops
    int nb_rdouts_plateau = 159; // p03 Nb of readouts per chopper plateau
    int nb_chop_cycles = 2; // p04 Nb of chop_cycles
}{
    // Call the corresponding DMC sequence
    int[] duree = DMC_fixed_fixed_photo(nb_main_loops,nb_rdouts_plateau,nb_chop_cycles);
    // Convert number of readouts into seconds
    // Obtain system parameter from PACSparams
    // BOL readout frequency [Hz] and readout period [msec]
    double bol_freq = dlookup("PACSparams","bolo_sample","freq_time");
    // string bol_unit = slookup("PACSparams","bolo_sample","unit");
    double bol_period = 1000.0 / bol_freq;
    // debug_print("Bolo sample: " + bol_freq + " " + bol_unit);
    // debug_print("Bolo period: " + bol_period + "[msec]");
    // Convert duration [rdouts] into [msec]
    // Create return time array; convert into [sec]
    int[] time_array = [0,0,0,0,0];
    for(int aux = 0 .. 4) {
        time_array[aux] = ifloor(double(duree[aux]) * bol_period);
        time_array[aux] = Msec2sec(time_array[aux]);
    }
    //
    // V0.2 correction: add OBCP overheads
    time_array[0] = time_array[0] + 4;
    time_array[4] = time_array[4] + 4;
    // Return total duration [sec] to calling program

    return time_array;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_PhotOffsetAuto.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set the detector offset for the photometer arrays
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/05/02 V0.1: Initial version adapted from 
//                  POffset_Auto (v1.4 2008/01/31 20:24:35)
// 2008/07/03 V0.2: Renumber version; Add comments to replace '?'s; 
//                  add RESET_FIFO at start
// 2008/08/11 V0.3: Change description
// 2009/01/31 V1.0: Add debug_print option. Remove unsetting of BBID.
//                  Increased delay to 2 after FLUSH_FIFO. Replace last
//                  delay(1) with sync(). 
// 2009/02/19 V1.1: Move all commands in low level procedure
//                  SpireProc_Set_PhotOffsetAuto. 
// 2009/05/07 V1.2: Fixed bug. Script was not setting BBID. 
// 2009/06/05 V1.3: Fix Hspot message at end of script (SPR-1481).
//
//  Note currently BB hardcodes the DCU data to be unsampled when 
//  BB is started. Low level script already has option to account
//  for a continous sampling during STBY.  
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_PhotOffsetAuto SPIRE 14007 {
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_PhotOffsetAuto started");
    SpireMsg(2,"          $Id:$");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    sync();
    // //
    // //
    // Take offset:
    //
    // currently hardcoded parameter:
    bool dcuData = false;
    //
    SpireProc_Set_PhotOffsetAuto(dcuData,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_PhotOffsetAuto ended");
    SpireMsg(1,"  ..PhotOffsetAuto End (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProcSetSmecSampling.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedute to set the SMECsampling  
//
///////////////////////////////////////////////////////////////////////////
//
// 04/09/2009 v1.0 KJK: First version adapted from 
//                 SpireBbSetSmecSampling(03/09/2009 KJK)
// 14/09/2009 KJK:
//                 Updated to use v00 for REDY rather than smecVersion
//
///////////////////////////////////////////////////////////////////////////
//
double procedure SpireProcSetSmecSampling {
    string opsMode = "SPECSTBY";
    string smecVersion = "v00";
    bool debug = false; // Allow debug_print statements 
}{
    // 
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    //
    // Start procedure:
    //
    message("4    " + time() + ": SpireProcSetSmecSampling started");
    message("4          $Id: $");
    // //
    // //
    // deal with Observing Mode transitions
    //
    if(opsMode == "REDY" || opsMode == "PHTSTBY" || opsMode == "SPECSTBY") {
        //
        // setup SMEC packet type
        //
        // disable SMEC selected frame definition
        tstr = SpireTimeStr(time());
        SpireMsg(5,"          " + tstr + "Cmd: Spire_DISABLE_SELECTION(0x10)");
        Spire_DISABLE_SELECTION(0x10);
        //
        int smecTelemetryType = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",opsMode,"smecTelemetryType","v00",debug);
        if(smecTelemetryType == 1) {
            //
            // use SMEC selected packets 
            //
            // Define contents of SMEC selected frames
            tstr = SpireTimeStr(time());
            SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_TABLE(0xa,12)");
            Spire_SET_TABLE(0xa,12);
            tstr = SpireTimeStr(time());
            SpireMsg(5,"          " + tstr + "Cmd: Spire_UPDATE_TABLE(0xa,0x0,12,[{0},{0},{1},{1},{1},{1},{1},{0},{1},{0},{0},{0}])");
            Spire_UPDATE_TABLE(0xa,0x0,12,[{0},{0},{1},{1},{1},{1},{1},{0},{1},{0},{0},{0}]);
            delay(1);
            tstr = SpireTimeStr(time());
            SpireMsg(5,"          " + tstr + "Cmd: Spire_ENABLE_SELECTION(0x10,0x1410,0xa)");
            Spire_ENABLE_SELECTION(0x10,0x1410,0xa);
        }
        //
        // Set number of samples
        int smecFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",opsMode,"mcuFrameNumber","v00",debug);
        SpireSendDrcuCmd(0x91c30000 + smecFrameNumber,0);
        //
        //  set TM Packet 10 sample rate
        int smecFrameRate = 0;
        if(opsMode == "REDY") {
            smecFrameRate = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",opsMode,"smecFrameRate",smecVersion,debug);
        } else {
            smecFrameRate = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode",opsMode,"smecFrameRate",smecVersion,debug);
        }
        SpireSendDrcuCmd(0x91c00000 + smecFrameRate,0);
        //
        // Start/Stop Data Generation
        int smecDataGen = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",opsMode,"mcuDataGen","v00",debug);
        SpireSendDrcuCmd(0x91c10000 + smecDataGen,0);
        //
        // read datarate
        double smecDataRate = 0.0;
        if(opsMode == "REDY") {
            smecDataRate = SpireProc_GetTableEntryDouble("SpireTable_DefaultParams.txt","mode",opsMode,"smecDataRate","v00",debug);
        } else {
            smecDataRate = SpireProc_GetTableEntryDouble("SpireTable_SpecModeParams.txt","mode",opsMode,"smecDataRate",smecVersion,debug);
        }
        // //
        // //
        // Disable SMEC selected frame definition if used in SPEC_STBYtoREDY:
        //
        // hardcode mode for selection:
        string selMode = "REDY";
        //
        if(opsMode == selMode) {
            tstr = SpireTimeStr(time());
            SpireMsg(5,"          " + tstr + "Cmd: Spire_DISABLE_SELECTION(0x10)");
            Spire_DISABLE_SELECTION(0x10);
        }
    } else {
        // operating mode transitions
        smecFrameRate = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode",opsMode,"smecFrameRate",smecVersion,debug);
        SpireSendDrcuCmd(0x91c00000 + smecFrameRate,0);
        smecDataRate = SpireProc_GetTableEntryDouble("SpireTable_SpecModeParams.txt","mode",opsMode,"smecDataRate",smecVersion,debug);
    }
    sync();
    //
    // End procedure:
    //
    SpireMsg(4,"    " + time() + ": procedure SpireProcSetSmecSampling ended");

    return smecDataRate;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndBsmPidTuning.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of SpirePhoto_Cal_BsmPidTuning.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/06 V1.0: Initial version adapted from
//                  SpireBb_EndBsmAngleCal (2009/05/05 V1.2) and
//                  SpirePhoto_Cal_BsmPidTuning (2009/04/01 V0.2).
// 2009/05/07 V1.1: Set dcuFrameNumber and mcuFrameNumber back to continuous
//                  to unset setting passed to VM. 
// 2009/06/05 V1.2: SPR-1476: Set PID parameters back to nominal. To do this
//                  input parameters need to be changed. SPR-1482: 
//                  Replace 2 Spire_SEND_DRCU_COMMANDs with SpireSendDrcuCmd.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndBsmPidTuning SPIRE 14057 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial"; // Model in cal table SpireTable_BsmNominalSettings
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // Hardcoded calibration tables:
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    //
    string version = version03;
    string tabName = tabName03;
    string selCol = "model";
    string selVal = model;
    string tarCol = "chop_0_I";
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndBsmPidTuning reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set obsstep back to 0:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP(0)");
    Spire_SET_OBS_STEP(0);
    // //
    // //
    // Set instrument back to Phot/Spec-STBY:
    //
    if(phot) {
        SpireProc_Set_PhotMode("PHTSTBY",isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    }
    // //
    // //
    // Read BSM hold position from calibration table: 
    //
    version = version03;
    tabName = tabName03;
    selCol = "model";
    selVal = model;
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Set number of DCU frames to continuous:
    //
    int dcuFrameNumber = 0;
    if(phot) {
        dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","PHTSTBY","dcuFrameNumber","v00",debug);
    } else {
        dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuFrameNumber","v00",debug);
    }
    //
    SpireSendDrcuCmd(0x843d0000 + dcuFrameNumber,0);
    // //
    // //
    // Set number of MCU frames to continuous:
    //
    int mcuFrameNumber = 0;
    if(phot) {
        mcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","PHTSTBY","mcuFrameNumber","v00",debug);
    } else {
        mcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","mcuFrameNumber","v00",debug);
    }
    SpireSendDrcuCmd(0x91c30000 + mcuFrameNumber,0);
    delay(1);
    // //
    // //
    // Read nominal PID parameters from calibration file:
    //
    version = version03;
    tabName = tabName03;
    selCol = "model";
    selVal = model;
    //
    tarCol = "chop_kp";
    int kp = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "chop_ki";
    int ki = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "chop_kd";
    int kd = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Set PID parameters back to nominal (STBY) values:
    //
    SpireProc_Set_BsmChopPid(kp,ki,kd,debug);
    // //
    // //
    // End observation:
    //
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndBsmPidTuning reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

//CLName: SpireBb_LoadTableAutonomy
//VMVersion: 2.8
//CLVersion: 1.5
//CLCVSId: $ID$
//TableId: 0x66
//TableLength: 0x196
//Date: 091109114558
block SpireBb_LoadTableAutonomy SPIRE 3803 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_Load_TableAutonomy started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //
    //set table command call for table id 0x66
    Spire_SET_TABLE(0x66,0x196);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x66,0x0,14,[{0x30000064},{0x30000070},{0x3000007c},{0x30000088},{0x30000094},{0x300000f1},{0x300000f1},{0x300000fe},{0x30000109},{0x3000010c},{0x3000011e},{0x30000145},{0x30000120},{0x30000171}]);
    delay(t_min);
    //update table command call for table index 0x0064
    Spire_UPDATE_TABLE(0x66,0x64,38,[{0x120000fd},{0x100},{0x12000000},{0x200},{0x12000001},{0xc100},{0x12000002},{0x5200},{0x12000003},{0x0},{0x63fd001f},{0x2000000},{0x41000000},{0x120000fd},{0x100},{0x12000000},{0x200},{0x12000001},{0xc110},{0x12000002},{0x5200},{0x12000003},{0x0},{0x63fd001f},{0x2000000},{0x41000000},{0x120000fd},{0x100},{0x12000000},{0x200},{0x12000001},{0xc000},{0x12000002},{0x5200},{0x12000003},{0x0},{0x63fd001f},{0x2000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x66,0x8a,38,[{0x41000000},{0x120000fd},{0x100},{0x12000000},{0x200},{0x12000001},{0xc010},{0x12000002},{0x5200},{0x12000003},{0x0},{0x63fd001f},{0x2000000},{0x41000000},{0x80007d0},{0x120000fd},{0x100},{0x843e0000},{0x91c10000},{0x91c00000},{0x91c20000},{0xa0820000},{0x12000000},{0x7000},{0x63fd000a},{0x2000000},{0x12000000},{0x0},{0x12000001},{0xc13},{0x4000017e},{0x18000000},{0x3f},{0x41300},{0x84140000},{0x84120000},{0x84050000},{0x84060000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x66,0xb0,38,[{0x84070000},{0x84080000},{0x84090000},{0x840a0000},{0x18000000},{0x30},{0x41300},{0x840b0000},{0x840c0000},{0x840d0000},{0x840e0000},{0x84130000},{0x840f0000},{0x84100000},{0x841a0000},{0x841b0000},{0x841c0000},{0x841d0000},{0x84010000},{0x84020000},{0x84030000},{0x84040000},{0x12000000},{0x2},{0x12000001},{0x887},{0x4000017e},{0x18000000},{0x6},{0x208700},{0x12000000},{0x0},{0x12000001},{0xc37},{0x4000017e},{0x18000000},{0x1},{0x43700}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x66,0xd6,38,[{0x84350000},{0x84360000},{0x84370000},{0x84340000},{0x843a0000},{0x843b0000},{0x84310000},{0x84320000},{0x12000000},{0x2},{0x12000001},{0x887},{0x4000017e},{0x18000000},{0x4},{0x208700},{0x90490000},{0x90440006},{0x90450dac},{0x90490001},{0x90400000},{0x90410000},{0x90c38000},{0x91438000},{0x90c20003},{0x91420003},{0x90c00000},{0x91400000},{0xa0c80000},{0xa0ca0000},{0xa0cc0000},{0x41000000},{0x41000000},{0x80007d0},{0x2000000},{0x40000098},{0xa0850000},{0xa0860000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x66,0xfc,38,[{0xa0c40000},{0xa0c50000},{0xa0c60000},{0xa0c70000},{0xa0c80000},{0xa0ca0000},{0xa0cc0000},{0xa0870000},{0x41000000},{0x120000fd},{0x100},{0x12000000},{0x3},{0x12000001},{0x1900},{0x12000002},{0x301},{0x12000003},{0x0},{0x63fd000f},{0x41000000},{0x120000fd},{0x100},{0x63fd001e},{0x7f000000},{0x120000fd},{0x100},{0x120000ff},{0x0},{0x12000000},{0x127},{0x61060001},{0x12000000},{0x3},{0x12000001},{0x1900},{0x12000002},{0x301}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x66,0x122,38,[{0x12000003},{0x1},{0x63fd000f},{0x40000150},{0x7f000000},{0x0},{0x120000fd},{0x100},{0x63fd000e},{0x7f000000},{0x12000001},{0x176},{0x20020000},{0x18000002},{0x6},{0x34000002},{0x30000007},{0x120000ff},{0x8},{0x61060102},{0x120000ff},{0xd},{0x61060103},{0x20020000},{0x18000002},{0x5},{0x34000002},{0x30000007},{0x120000ff},{0x10},{0x61060102},{0x120000ff},{0x15},{0x61060103},{0x20020000},{0x18000002},{0x3},{0x34000002}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x66,0x148,38,[{0x30000007},{0x120000ff},{0x18},{0x61060102},{0x120000ff},{0x1d},{0x61060103},{0x41000000},{0x12000001},{0x179},{0x12000002},{0x17b},{0x20030000},{0x18000003},{0x6},{0x34000003},{0x30000007},{0x120000ff},{0x8},{0x61060102},{0x120000ff},{0xd},{0x61060203},{0x20030000},{0x18000003},{0x5},{0x34000003},{0x30000007},{0x120000ff},{0x10},{0x61060102},{0x120000ff},{0x15},{0x61060203},{0x20030000},{0x18000003},{0x3},{0x34000003}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x66,0x16e,38,[{0x30000007},{0x120000ff},{0x18},{0x61060102},{0x120000ff},{0x1d},{0x61060203},{0x41000000},{0xffffffff},{0xffffffff},{0xffffffff},{0x3},{0x3},{0xffffffff},{0xffffffff},{0xffffffff},{0x18000000},{0xf},{0x1b00001c},{0x18000000},{0xf0000000},{0x18000001},{0xfff},{0x1b010010},{0x18000001},{0xfff0000},{0x21000001},{0x19000000},{0x80000000},{0x80005dc},{0x4000000},{0x80007d0},{0x2000000},{0x12000000},{0x0},{0xa000000},{0x18000000},{0xffff}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x66,0x194,2,[{0x41000000},{0x7f000000}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x66,0x0,0x0);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_Load_TableAutonomy ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_Serendipity.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to wait while doing a serendipity observation
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/11/12 V0.1: Initial version 
// 2009/03/16 V1.1: Remove unsetting of BBID. Add sync. Add debug as option.
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_Serendipity SPIRE 14021 {
    int wtime = 0; // Waiting time for observation to finish
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    Spire_SET_BBID($BBID);
    sync();
    // //
    // //
    // Waiting time:
    //
    // Take setting of BBID into account:
    if(wtime == 0) {
        wtime = 0;
    } else {
        wtime = wtime - 1;
    }
    //
    // wait (and take data):
    delay(wtime);
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_PcalOn.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to set PCAL to input PCAL bias level.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/04/01 V0.1: Initial version adapted from
//                  SpireProc_PcalFlash (2008/11/07 V0.1)
// 2009/11/23 V1.0: Improve debugging messages (SCR-SPIRE-2038)
// 2009/12/14 V1.1: Hardcode setting of raw=0 if input 0.0 (SPR-SPIRE-2294)
//
// Note, by setting pcal_bias to 0.0 the same script switches OFF PCAL.
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_PcalOn {
    double pcal_bias = 3.8 in [0.0,7.0]; // PCAL bias level [mA]
    string version = "v01"; // Version in cal table SpireTable_PcalCurrentConvCoef
    bool debug = false;
}{
    // //
    // //
    // Define some variables:
    //
    string tstr = "";
    //
    // Hardcoded calibration tables:
    //
    string tabName = "SpireTable_PcalCurrentConvCoef.txt";
    // //
    // //
    // Start procedure:
    //
    message("4    " + time() + ": SpireProc_PcalON started");
    message("4          $Id: $");
    // //
    // //
    // Retrieve PCAL bias calibration coefficients:
    //
    double[] coeff = [0.0];
    coeff[0] = dlookup(tabName,version,"c_0");
    coeff[1] = dlookup(tabName,version,"c_1");
    // //
    // //
    // Calculate RAW PCAL bias values for each of the flashes from mA list:
    //  
    int raw_level = 0;
    raw_level = iround((pcal_bias * 0.0010 - coeff[0]) / coeff[1]);
    if(debug) {
        debug_print("raw_level selected: " + raw_level);
    }
    // //
    // //
    // Hardcode 0 setting if 0.0 input:
    //
    if(pcal_bias == 0.0) {
        raw_level = 0;
    }
    // //
    // //
    // Set PCAL bias to input bias level:
    //
    SpireSendDrcuCmd(0xa0c80000 + raw_level,0);
    // Note, reduced wait time from IST 10sec to 5secs:
    delay(5);
    // //
    // //
    // End procedure:
    //
    message("4    " + time() + ": SpireProc_Set_PcalOn ended");
    //
}

// CVS comments  : $Id: PHOT_aot_epilogue.txt,v 1.2 2007/04/25 15:14:03 dcesarsk Exp $ 
// Missionphase  : 
// Purpose       : Stop PHOTOmeter observations at end of AOT
//                  
// TCL author    : 
// TCL file      : 
// CUS author    : Diego Cesarsky
// Script file   : PHOT_aot_epilogue.txt 
//
// Input arguments
// Type Name           Default   Description
//
// Description   : Not much for now (just STOP SPU)
//                  
// Dependencies  : PACS TCs
//
// Preconditions :
//                 
// Comments      :
//
// History       : 0.1 19-apr-2006 First creation
// 		   1.0 23-sep-2008 SCR 4431 data_rate
procedure PHOT_aot_epilogue {
}{
    // Stop the Long and Short SPUs
    Pacs_SPUS_STOP_REDUCT_COMPR();
    Pacs_SPUL_STOP_REDUCT_COMPR();
    data_rate(0.0);
    // Sync the bus (function duration will get the "true" duration)
    sync();
    // end of procedure
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndFixedSmecBeamProfile.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of 
// Spectro_CalGCO_FixedSmecBeamProfile.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/09/16 V0.1: Initial version adapted from
//                  SpireBb_EndScannedSmecBeamProfile(2009/09/15 V0.1) and
//                  SpireSpectro_CalGCO_FixedSmecBeamProfile (2008/11/06 V0.3)
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndFixedSmecBeamProfile SPIRE 14078 {
    int smec_pos = 1000; // SMEC position in encoder values 
    int hold_chop = 37632; // Chop hold position [Dec(Hex)]
    int hold_jigg = 39520; // Jiggle hod position [Dec(Hex)]
    int smecHomePosn = 3500; // SMEC home position
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndFixedSmecBeamProfile reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set obsstep back to 0:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP(0)");
    Spire_SET_OBS_STEP(0);
    // //
    // //
    // Move SMEC from input to home position (leave SMEC running beyond proc.):
    //
    SpireProc_SmecMove2Home(smecHomePosn,smec_pos,debug);
    // //
    // //
    // Set instrument back to Spec-STBY:
    //
    SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    // //
    // //
    // Set number of DCU frames to continuous:
    //
    int dcuFrameNumber = 0;
    dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuFrameNumber","v00",debug);
    //
    SpireSendDrcuCmd(0x843d0000 + dcuFrameNumber,0);
    // //
    // //
    // Set number of MCU frames to continuous:
    //
    int mcuFrameNumber = 0;
    mcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","mcuFrameNumber","v00",debug);
    SpireSendDrcuCmd(0x91c30000 + mcuFrameNumber,0);
    delay(1);
    // //
    // //
    // Stop any remaining SMEC movement:
    //
    SpireProc_SmecHold(debug);
    // //
    // //
    // Set scientific datarate back to zero:
    //
    data_rate(0.0);
    // //
    // //
    // End observation:
    //
    bool phot = false;
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndFixedSmecBeamProfile reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

// CVS comments  : $Id: WriteBBID.txt,v 1.6 2007/04/26 15:44:10 dcesarsk Exp $
// Missionphase  : 
//
// Purpose       :
//
// CUS script    : Diego A. Cesarsky (diego.cesarsky@mpe.mpg.de)
// CVS file      : WriteBBID.txt
//
// Input arguments
// Type  Name    DefVal  Description
// int   iBBID   N/A     BBID obtained from environment
//
// Description   : Write BBID to DEC/MEC; print decoded BBID
//                 to output log  
//
// Dependencies  : Pacs_DMC_SET_BBID
//                 DecodeBBID   
//                 
// Comments      : 
//
// Version      : 0.1 23-Sep-2004 First creation
// History      : 0.2 28-Sep-2004 Show BBID "decoded" on output screen.
//                                Remove set_unset choice 
//                0.3  7-Oct-2004 Rationalize name convention: renamed to
//                                WriteBBID (idem with file name)
//                0.4 12-Oct-2004 Added write to EGSE equipment (will have to
//                                add later writes to IST equipment ??)
//                0.5 21-Oct-2004 Added write to CDMS     
//                0.6  9-May-2005 Remove write to EGSE and to CDMS     
//                0.7 22-nov-2006 Removed debug statement
//               :
//
procedure WriteBBID {
    int iBBID = 0x40000000; // Building Block ID  
}{
    // Write BBID to DEC/MEC and to output log
    Pacs_DMC_SET_BBID(iBBID);
    ///   DecodeBBID(iBBID);
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartScannedSmecBeamProfile.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpireSpectro_CalGCO_ScannedSmecBeamProfile
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/09/15 V0.1: Initial version adapted from
//                  SpireBb_StartFovMapCrossRaster (2009/07/12 V1.0) and 
//                  SpireSpectro_CalGCO_ScannedSmecBeamProfile (2009/09/11 V0.5)
// 2009/09/16 V0.2: Replaced last SpireProc_SmecMove2Home with 
//                  SpireProc_SmecMove to allow to end SMEC movement
// 2009/10/28 V1.0: (SPR-SPIRE-2062) Remove SMEC stuff during slew. This 
//                  means there is no more move SMEC to home at start. 
// 
// Notes:
//    1) Scripts assumes that SpireBb_SpecOffsetAuto is run 
//       during INITHOLD or at first POINTING.
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartScannedSmecBeamProfile SPIRE 14075 {
    string obsModeQla = "ENG_CAL_OBS35";
    string obsMode = "SEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    bool setFramerate = true; // Set BSM framerate (==tick)?
    int frate = 0; // BSM framerate 
    int smecFrate = 0; // Commanded SMEC framerate rate
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartScannedSmecBeamProfile configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    //delay(timeSlewCal);
    // //
    // //
    // Set user requested framerate:
    //
    if(setFramerate) {
        SpireProc_Set_BsmFramerate(frate,debug);
    }
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartScannedSmecBeamProfile configuration ended");
    SpireMsg(1,"  ..StartScannedSmecBeamProfile took " + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Exec_PhotPcalLoadCurve.txt
//
///////////////////////////////////////////////////////////
//
//  Procedure to loop through a list of bias amplitudes and flashing
//  PCAL for the 'Phot PCAL Load Curve' task 
//
///////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/06/09 V0.1: Initial version adapted from
//                  Mode_ILT_PERF_DAB_P_CPS.txt (v1.3 2008/01/31 23:35:17)
// 2008/07/04 V0.2: Renumber version; include PTC in loop; skip first setup in
//                  SpireBb_PhotFSetupData, as it is already done during slew
// 2008/08/15 V0.3: Remove test number; Move calculation of flash parameters 
//                  from SpireProc_CalcParam_PhotIltPcalFlash to here 
// 2009/02/02 V1.0: Add debug_print as input and pass it to low level script.
//                  Replace SpireProc_Exec_PcalFlash by direct call to 
//                  SpireBb_PcalFlash. Adapt input to updated SpireBb_PcalFlash
//                  with rate and step.
// 2009/02/16 V1.1: Promote new VM table parameters of SpireBb_PcalFlash
//                  to input. 
// 2009/02/18 V1.2: Adapt to change in call to SpireBb_PcalFlash.
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Exec_PhotPcalLoadCurve {
    int[] nbiaslist = [0,50,100,255]; // List of raw bias levels in range (0-255)
    int ftime = 10; // Readout time at each bias level [s]
    int mclkdiv = 149; //Default (IST) bias freq (== 130.20833 Hz)
    int biasdiv = 6; //Default (IST) sampling freq (== 18.60119 Hz)
    int vmId = 70; // Raw VM table number [Dec(Hex)]
    int vmIndex = 0; // Raw VM index [Dec(Hex)]
    int nParms = 9; // Number of parameters passed to VM
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Predefine version in SpireTable_PhotPcalCurrentConvCoef.txt:
    //
    string ver_a = "v01";
    if(debug) {
        debug_print("The nominal version in SpireTable_PcalCurrentConvCoef.txt is v01");
    }
    // //
    // //
    // Retrieve PCAL bias calibration coefficients:
    //
    double[] coeff = [0.0];
    coeff[0] = dlookup("SpireTable_PcalCurrentConvCoef.txt",ver_a,"c_0");
    coeff[1] = dlookup("SpireTable_PcalCurrentConvCoef.txt",ver_a,"c_1");
    // //
    // //
    // Set some ILT standard values for PCAL flash:
    //
    // Period of cycle in microsec:
    int flashperiod = 4000000;
    // Period of cycle in millisec:
    int period = flashperiod / 1000;
    // Number of cycles:
    int ncycles = 15;
    // DCU data mode (default = PF ==0; FTS = SF == 4):
    int ndcumode = 0;
    // SCU sampling rate (f =80Hz/(1+scumode)):
    int scumode = 0;
    // //
    // //
    // Calculate the RAW bias levels:
    //
    //[mA] Low Level for 1st PCAL flash:
    double lowbias_0 = 0.0;
    //[mA] High Level for 1st PCAL flash:
    double highbias_0 = 3.8;
    //[mA] Low Level for 2nd PCAL flash:
    double lowbias_1 = 0.0;
    //[mA] High Level for 2nd PCAL flash:
    double highbias_1 = 4.8;
    //
    int pcal_low_bias_0 = iround((lowbias_0 * 0.0010 - coeff[0]) / coeff[1]);
    int pcal_high_bias_0 = iround((highbias_0 * 0.0010 - coeff[0]) / coeff[1]);
    int pcal_low_bias_1 = iround((lowbias_1 * 0.0010 - coeff[0]) / coeff[1]);
    int pcal_high_bias_1 = iround((highbias_1 * 0.0010 - coeff[0]) / coeff[1]);
    // //
    // //
    // Deduce number of DCU samples, SCU samples and DCU sample delay based on mclkdiv and biasdiv:
    //
    int[] flash_params = SpireProc_CalcParam_PcalFlash(period,mclkdiv,biasdiv,debug);
    int dcusamples = flash_params[0];
    int scusamples = flash_params[1];
    int dcudelay = flash_params[2];
    if(debug) {
        debug_print("//////////////////////////////////////////////////////////////");
        debug_print("");
        debug_print("CALCULATED DCU SAMPLES : " + dcusamples);
        debug_print("CALCULATED SCU SAMPLES : " + scusamples);
        debug_print("CALCULATED  SAMP DELAY : " + dcudelay + "microsec");
        debug_print("");
        debug_print("//////////////////////////////////////////////////////////");
    }
    // //
    // //
    // Start the LC bias loop:
    //
    for(int l = 0 .. length(nbiaslist) - 1) {
        // //
        // //
        // Safety check:
        //
        if(nbiaslist[l] > 255) {
            nbiaslist[l] = 255;
            error("Input bias list is corrupt! Raw value > 255 requested!");
        }
        // //
        // //
        // Set STEP:
        //
        int obsStep = l + 1;
        // NHK Step parameter 
        if(obsStep == 1) {
            if(debug) {
                debug_print("First obsStep already set during slew");
            }
        } else {
            SpireBb_SetObsStep(obsStep,debug);
        }
        // //
        // //
        // Set bias amplitude:
        //
        if(l == 0) {
            if(debug) {
                debug_print("Bias already set during slew");
            }
        } else {
            SpireBb_PhotFSetBiasAmpl(nbiaslist[l],nbiaslist[l],nbiaslist[l],nbiaslist[l],debug);
        }
        // //
        // //
        // Stop DCU data before resetting offsets:
        //
        SpireBb_StopDcuData();
        //
        // //
        // //
        // Set offsets:
        //
        SpireBb_PhotOffsetAuto(debug);
        //
        // //
        // //
        // Execute PCAL flashes:
        //
        // First PCAL Flash: 
        // 
        SpireBb_PcalFlash(vmId,vmIndex,nParms,pcal_low_bias_0,pcal_high_bias_0,ncycles,flashperiod,ndcumode,dcusamples,dcudelay,scumode,scusamples,obsStep,debug);
        //
        // Second PCAL Flash: 
        //
        SpireBb_PcalFlash(vmId,vmIndex,nParms,pcal_low_bias_1,pcal_high_bias_1,ncycles,flashperiod,ndcumode,dcusamples,dcudelay,scumode,scusamples,obsStep,debug);
        // //
        // Take data:
        //
        SpireBb_PhotFTakeData(ftime,debug);
        //
        // //
        // //
        // Debug printing: 
        //
        if(debug) {
            debug_print("Bias level " + nbiaslist[l] + " done.");
        }
    }
    //
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_Cal_PcalLoadCurve.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  CUS script for: 'Spec PCAL Load Curve'  
//
//  in *basic_fine_pointing* or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/09/16 V0.1: Initial version adapted from 
//                  SpirePhoto_Cal_PcalLoadCurve (2008/08/15 V0.5)
// 2008/11/11 V0.2: Allow 'no pointing' as input option; Adapt debug printing
// 2008/11/12 V0.3: Implement mode setting; Add isBright 
//                  Change 'no pointing' implementation
// 2009/02/19 V0.4: Add debug_print as input and pass it to some low 
//                  level scripts. Add setting of NHK STEP parameter
//                  in SpireProc_Exec_PhotPcalLoadCurve. Set first STEP
//                  already during SLEW and unset at end during INIT_HOLD.   
//                  Use new SpireBb_EndObsAll and SpireBb_StartObsAll. 
//                  Read nominal bias frequency and bias divider from new
//                  SpireTable_SpecModeParams.txt. Implemented setting 
//                  of datarates. Implemented message if activating isBright 
//                  setting. Remove cal. tables from input and hardcode them. 
//                  Read boresight from SpireTable_OpsParms. Use
//                  SpireProc_Set_SpecMode to set instrument to SPECSTBY
//                  during SLEW. Replace call to SpireBb_SpecFSetupData with
//                  call to SpireBb_SpecFSetPhase, SpireBb_SpecFSetBiasAmpl
//                  and SpireBb_DcuSetFreqSamp to set user requested inputs
//                  plus first bias level during SLEW. Unset isBright if set. 
//                  Use SpireBb_SpecSetMode to set back to SPECSTBY at end.
//                  Adapt to change in call to SpireProc_Exec_SpecPcalLoadCurve.
// 2009/03/04 V0.5: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Replace 'message' by
//                  'error' if isBright is selected.
// 2009/05/07 V0.6: Add in move BSM/SMEC to hold/home at start. Add new 
//                  SpireBb_SmecHold to account for the fact that
//                  SpireBb_SmecMove2Home does not stop SMEC.
//                  Gather procedures at start and end in separate BB. 
//
///////////////////////////////////////////////////////////////////////////
//
//  Script assumes that:
//
//  1)  Instrument is in SPECSTBY at beginning 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Phase is kept constant (from input) during this test, i.e no 
//     adjustment of the phase with changing bias amplitude and frequency
//
//  3) Bias frequency, sampling rate, and phase are input parameters
//
//  4) Boresight of array can be read from following cal table using
//     the mode 'SEngCalObs': SpireTable_OpsParms.txt   
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_Cal_PcalLoadCurve {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; // NAIF identifier
    bool isBright = false; // Use settings for bright source (==tick)
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    double biasfreq = 160.1 in [80.0,240.0]; // Bias frequency [Hz]
    double samplerate = 80.0 in [1.0,80.5]; // Sampling rate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    double phasedeg_ssw = 184.9 in [0.0,360.0]; // SSW Bias phase [deg]
    double phasedeg_slw = 190.6 in [0.0,360.0]; // SLW Bias phase [deg]
    int ftime = 10; // Readout time at each bias level [s]
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_PcalLoadCurveLevels
    string version05 = "v00"; // Version in cal table SpireTable_OpsParms.txt
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // //
    // //
    // Check for is bright setting: 
    //
    if(isBright) {
        isBright = false;
        error("IsBright does not make sense here. Try again (e.g. subtract the phase shift manually from the input)!");
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = false;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_PcalLoadCurveLevels.txt";
    string tabName04 = "SpireTable_CommandLists.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    string tabName06 = "SpireTable_BsmNominalSettings.txt";
    string tabName09 = "SpireTable_SmecNominalSettings.txt";
    //
    // Currently hardcoded version and model parameter:
    //
    string version09 = "v00";
    // Version in cal table SpireTable_SmecNominalSettings
    string version06 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    //
    // Dummy value for Phot script:
    // (needed but not used in spec script!)
    //
    int psw_bias = 62;
    //
    int pmw_bias = 62;
    //
    int plw_bias = 62;
    //
    int ptc_bias = 62;
    //
    int psw_phase = 127;
    //
    int pmw_phase = 127;
    //
    int plw_phase = 127;
    //
    int ptc_phase = 127;
    //
    //
    // Currently hardcoded parameter:
    // Is (==tick) the DCU currently sampled? 
    bool dcuData = false;
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS39";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "SEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Retrieve bias levels used for the load curve:
    // 
    tabName = tabName03;
    version = version03;
    int[] nbiaslist = SpireProc_CalcParam_LoadCurve(tabName,version,debug);
    //
    // Lookup first bias level:    
    int ssw_bias = nbiaslist[0];
    int slw_bias = nbiaslist[0];
    // //
    // //
    // Convert user input to Hex values:
    //
    // for bias frequency and sample rate: 
    //
    int[] hexvalues = SpireProc_CalcParam_BiasFreqSampFreq(biasfreq,samplerate,fts,debug);
    int mclkdiv = hexvalues[0];
    int biasdiv = hexvalues[1];
    if(debug) {
        debug_print("Hex values of mclkdiv/biasdiv are: " + mclkdiv + " " + biasdiv);
    }
    //
    // for bias phase:
    //
    int[] phasehex = SpireProc_CalcParam_SpecPhaseConvert(phasedeg_ssw,phasedeg_slw,debug);
    int ssw_phase = phasehex[0];
    int slw_phase = phasehex[1];
    // //
    // //
    // Read VM parameters from calibration table:
    //
    tabName = tabName04;
    selVal = "Flash";
    int vmId = ilookup(tabName,selVal,"Id");
    int vmIndex = ilookup(tabName,selVal,"Index");
    int nParms = ilookup(tabName,selVal,"Nparms");
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version06;
    tabName = tabName06;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Read SMEC home position from calibration file:
    //
    tarCol = "Home";
    tabName = tabName09;
    selVal = version09;
    int smecHomePosn = ilookup(tabName,selVal,tarCol);
    //
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // // 
    // // 
    // Calculate timing for the pointing request:
    //
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartPcalLoadCurve(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,psw_phase,pmw_phase,plw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug));
    // 
    // BBs carried out when the pointing is reached:
    if(pointing) {
        int tinithold = 0;
    } else {
        tinithold = tslewmin;
    }
    //
    // BB carried out during pointing:
    int tp = duration(SpireProc_Exec_SpecPcalLoadCurve(nbiaslist,ftime,mclkdiv,biasdiv,vmId,vmIndex,nParms,dcuData,debug));
    //
    // BB carried out at the end:
    int tfinalhold = duration(SpireBb_EndPcalLoadCurve(phot,isBright,version01,version02,debug));
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartPcalLoadCurve(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,psw_phase,pmw_phase,plw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug);
            //            
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            //
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation: 
                //
                SpireBb_StartPcalLoadCurve(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,psw_phase,pmw_phase,plw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug);
                //            
            }
        }
        //
        //delay(tinithold);
        //
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            // //
            // //
            // Execute load curve with PCAL flashes:
            //
            SpireProc_Exec_SpecPcalLoadCurve(nbiaslist,ftime,mclkdiv,biasdiv,vmId,vmIndex,nParms,dcuData,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ("sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            SpireBb_EndPcalLoadCurve(phot,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

// SpireSpectroRasterLogic
//
// $Id:$
//
// This procedure selectes the SPIRE observing mode and calculates its instrument parameters  
//  for raster spectrometer observations
//
// This type of observation may be executed using either the SOF1 or SOF2 observing modes
//
// 10/03/2009 KJK: 
//         SCR 1274, add additional dummy parameters 
//         Update input API to include versions for all cal tables
//  17/03/2009 KJK:
//         Updated return values to put nCycles1 in nHCycles and nCycles2 in nLCycles 
//         Modified to set nCycles2 = 0 if only single resolution scans are requested
//  25-Aug-2009 KJK:
//        SPR Spire-1641: Needed new input parameters bsmModel and bsmVersion
// 03/09/2009 KJK: 
//       Added smecVersion to input parameters
// 24/09/2009 KJK: Updated call to SpireSOF12Pointing
// 29/09/2009 MP: SPR-SPIRE-2048
//            Fix bug with hardcoded SFlash for isBright. Here, update call to
//            SpireSOF12Observing.
// 16/02/2010 KJK: SCR Spire-2341:
//       Updated to call SpireSOF12Observing and SpireSOF12Pointing with additional parameter
//  20/07/2011 SDS:  SCR Spire-2563:
//                              opsVersion added in call to SpireSOF12Pointing
////////////////////////////////////////////////////////////////////////////
{{double,double,double,double,double,double}[],{double,double,double,double,double,double}[],bool,int,int,int,int,int,int,int,double,int,double} obs SpireSpectroRasterLogic {
    double ra = 0.0 in [0.0,360.0]; // RA of Target
    double dec = 0.0 in [-90.0,90.0]; // DEC of Target
    int naifid = 0; // NAIF identifier
    string pointing = "raster" in ["single","raster"]; // pointing type
    string sampling = "sparse" in ["sparse","intermediate","full"]; // spatial sampling
    string resolution = "H" in ["H","M","L","H+L"]; // spectral resolution
    double mapSize1 = 0.0 in [0.0,30.0]; // arc minutes
    double mapSize2 = 0.0 in [0.0,30.0]; // arc minutes
    double mapOffsetY = 0.0 in [-300.0,300.0]; // arc minutes
    double mapOffsetZ = 0.0 in [-300.0,300.0]; // arc minutes
    bool mapOrientationArray = true; // is the map orientation an array (rather than array with constraints)
    double mapOrientationConFrom = 0.0 in [0.0,360.0];
    double mapOrientationConTo = 360.0 in [0.0,360.0];
    int nRepetitions1 = 2 in [2,1200]; // number of times to repeat spectral scan pairs for single resolution scan modes and high resolution in H+L mode
    int nRepetitions2 = 2 in [2,1200]; // number of times to repeat spectral scan pairs for low resolution scans for 'H+L" mode
    double wavelength1 = -1.0; // wavelength
    double wavelength2 = -1.0; // wavelength
    double wavelength3 = -1.0; // wavelength
    double wavelength4 = -1.0; // wavelength
    double wavelength5 = -1.0; // wavelength
    double wavelength6 = -1.0; // wavelength
    double wavelength7 = -1.0; // wavelength
    double wavelength8 = -1.0; // wavelength
    double lineFlux1 = -1.0; // line flux estimate
    double lineFlux2 = -1.0; // line flux estimate
    double lineFlux3 = -1.0; // line flux estimate
    double lineFlux4 = -1.0; // line flux estimate
    double lineFlux5 = -1.0; // line flux estimate
    double lineFlux6 = -1.0; // line flux estimate
    double lineFlux7 = -1.0; // line flux estimate
    double lineFlux8 = -1.0; // line flux estimate
    bool isJyContinuum = true; // is continuum specified in Jy rather than Wm-2um-1
    double contFlux1 = -1.0; // continuum flux estimate
    double contFlux2 = -1.0; // continuum flux estimate
    double contFlux3 = -1.0; // continuum flux estimate
    double contFlux4 = -1.0; // continuum flux estimate
    double contFlux5 = -1.0; // continuum flux estimate
    double contFlux6 = -1.0; // continuum flux estimate
    double contFlux7 = -1.0; // continuum flux estimate
    double contFlux8 = -1.0; // continuum flux estimate
    bool isBright = false;
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParms
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    string flashVersion = "v00"; // Version in cal table SpireTable_FlashParms
    string smecVersion = "v00"; // Version in cal table SpireTable_SpecModeParams
    string specVersion = "v00"; // Version in cal table SpireTable_Spectrometer
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // unused parameters
    string comVersion = "v00";
    string smodeVersion = smecVersion;
    smecVersion = "v00";
    //
    // check inputs
    if(pointing != "raster") {
        error("SpireSpectroRasterLogic: Pointing is not set to raster");
    }
    SpireMsg(0,"Spectrometer Raster Observation");
    // ********************************************
    //  Calculate possible pointing parameters
    // ********************************************
    //
    int nCycles1 = 0;
    int nCycles2 = 0;
    double tCycle1 = 0.0;
    double tCycle2 = 0.0;
    int scansPerCycle1 = 0;
    int scansPerCycle2 = 0;
    double osit1 = 0.0;
    double osit2 = 0.0;
    int nRasters = 1;
    int nMaps = 1;
    int nCycles = 1;
    int nFlashes = 0;
    double tFlash = 0.0;
    int nCals = 0;
    double tCal = 0.0;
    int tSlewMin = 0;
    int tInitHold = 0;
    int tFinalHold = 0;
    string ib = "";
    // instrument boresight
    double yOffset = 0.0;
    // offset to observation position from target in Y direction (arcsecs)
    double zOffset = 0.0;
    // offset to observation position from target in Z direction (arcsecs)
    double deltaY = 0.0;
    // offset to pixel centre from boresight in Y direction (arcsecs)
    double deltaZ = 0.0;
    // offset to pixel centre from boresight in Z direction (arcsecs)
    int tHold = 0;
    int nHold = 0;
    //
    double[] wavelength = [wavelength1,wavelength2,wavelength3,wavelength4,wavelength5,wavelength6,wavelength7,wavelength8];
    double[] lineFlux = [lineFlux1,lineFlux2,lineFlux3,lineFlux4,lineFlux5,lineFlux6,lineFlux7,lineFlux8];
    double[] contFlux = [contFlux1,contFlux2,contFlux3,contFlux4,contFlux5,contFlux6,contFlux7,contFlux8];
    //
    // *****************************************
    //      select instrument ops mode    
    // *****************************************
    //       
    string opsMode = "";
    // opsMode
    int md = 0;
    // value of MODE parameter
    if(sampling == "sparse") {
        opsMode = "SOF1";
        md = 0x410;
    } else {
        if(sampling == "intermediate") {
            opsMode = "SOF2_int";
        } else {
            if(sampling == "full") {
                opsMode = "SOF2";
            } else {
                error("SpireSpectroPoint: Unknown sampling");
            }
        }
        md = 0x420;
    }
    //
    // *****************************************
    //      set up scan sets  
    // *****************************************
    //       
    string res1 = resolution;
    if(resolution == "H+L") {
        res1 = "H";
    }
    string res2 = "L";
    if(resolution != "H+L") {
        nRepetitions2 = 0;
    }
    // *****************************************
    // get observing parameters
    // *****************************************
    //
    ib = slookup("OpsParms.txt",opsMode,"Boresight");
    deltaY = dlookup("OpsParms.txt",opsMode,"DeltaY");
    // offset to pixel centre from boresight in Y direction (arcsecs)
    deltaZ = dlookup("OpsParms.txt",opsMode,"DeltaZ");
    // offset to pixel centre from boresight in Z direction (arcsecs)
    bool fixed = blookup("OpsParms.txt",opsMode,"Fixed");
    // pattern angle definition
    double pattNod = dlookup("OpsParms.txt",opsMode,"Patt");
    // direction of nod 
    double chopThrow = dlookup("OpsParms.txt",opsMode,"D1");
    yOffset = mapOffsetY * 60.0 + deltaY;
    // offset to observation position from target in Y direction (arcsecs)
    zOffset = mapOffsetZ * 60.0 + deltaZ;
    // offset to observation position from target in Z direction (arcsecs)
    {int,double,int,double,int,double,int,double,int,int,double,int,double} sofObs = SpireSOF12Observing(opsMode,res1,res2,nRepetitions1,nRepetitions2,bsmVersion,smecVersion,specVersion,opsVersion,spireVersion,flashVersion,isBright,debug);
    nCycles1 = sofObs{0};
    tCycle1 = sofObs{1};
    scansPerCycle1 = sofObs{2};
    osit1 = sofObs{3};
    nCycles2 = sofObs{4};
    tCycle2 = sofObs{5};
    scansPerCycle2 = sofObs{6};
    osit2 = sofObs{7};
    nMaps = sofObs{8};
    nFlashes = sofObs{9};
    tFlash = sofObs{10};
    nCals = sofObs{11};
    tCal = sofObs{12};
    //
    {int,int,int,int,int,int} sofPoint = SpireSOF12Pointing(opsMode,res1,nCycles1,tCycle1,scansPerCycle1,res2,nCycles2,tCycle2,scansPerCycle2,nMaps,nFlashes,tFlash,isBright,bsmModel,bsmVersion,comVersion,spireVersion,smodeVersion,smecVersion,specVersion,flashVersion,opsVersion,debug);
    tSlewMin = sofPoint{0};
    tInitHold = sofPoint{1};
    tFinalHold = sofPoint{2};
    tHold = sofPoint{4};
    nHold = sofPoint{5};
    // *****************************************
    // set telescope pointing mode
    // *****************************************
    //
    // calculate raster positions
    {double[],double[]} sofRaster = SpireSpecRasterPositions(opsMode,0.0,0.0,mapSize1 * 60.0,mapSize2 * 60.0);
    double[] yArray = sofRaster{0};
    double[] zArray = sofRaster{1};
    int[] tp = [];
    int nPoints = length(yArray);
    for(int n = 0 .. nPoints - 1) {
        tp[n] = sofPoint{3};
    }
    if(nHold > nPoints) {
        nHold = 0;
    }
    //
    int[] ts = custom_map_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,fixed,pattNod,yOffset,zOffset,yArray,zArray,tp,pattNod,chopThrow,1,0,0,0,tHold,nHold);
}{
    // *********************************
    // Return instrument parameters
    // *********************************
    {{double,double,double,double,double,double}[],{double,double,double,double,double,double}[]} estimates = SpireSOF12Estimate(resolution,osit1,osit2,wavelength1,wavelength2,wavelength3,wavelength4,wavelength5,wavelength6,wavelength7,wavelength8,lineFlux1,lineFlux2,lineFlux3,lineFlux4,lineFlux5,lineFlux6,lineFlux7,lineFlux8,isJyContinuum,contFlux1,contFlux2,contFlux3,contFlux4,contFlux5,contFlux6,contFlux7,contFlux8,isBright,specVersion,debug);
    //
    bool isChopped = false;
    //
    int nHCycles = nCycles1;
    int nMCycles = 0;
    int nLCycles = nCycles2;

    return {estimates{0},estimates{1},isChopped,nRasters,nPoints,nMaps,nHCycles,nMCycles,nLCycles,nCals,tCal,nFlashes,tFlash};
}

// SpireBbStartDcuData
//
// $Id: SpireBbStartDcuData.txt,v 1.1 2006/08/10 09:38:58 kking Exp $
//
// Building Block to start generation of detector data TM packets
//
//
// 04 November 2008: 
//           changed to use the SpireStartDrcuData procedure
//            changed to receive operations mode rather than data mode as a parameter
//
block SpireBbStartDcuData SPIRE 8456 {
    string opsMode = "";
}{
    message("4    " + time() + ": SpireBbStartDcuData started");
    message("4          $Id: SpireBbStartDcuData.txt,v 1.1 2006/08/10 09:38:58 kking Exp $");
    //
    SpireStartDcuData(opsMode);
    //
    message("4    " + time() + ": SpireBbStartDcuData ended");
    //
}

// SpireStopDcuData
//
// $Id: SpireStopDcuData.txt,v 1.3 2007/04/02 09:50:56 kking Exp $
//
// Procedure to stop generation of detector data TM packets
//
// 30 March 2007:   Added additional parameter to RESET_FIFOS message
// 02 April 2007:   Added additional parameter to RESET_FIFOS cmd
// 04 November 2008: added data_rate command
//
//
procedure SpireStopDcuData {
}{
    message("4    " + time() + ": SpireStopDcuData started");
    message("4          $Id: SpireStopDcuData.txt,v 1.3 2007/04/02 09:50:56 kking Exp $");
    //
    // stop data collection
    SpireSendDrcuCmd(0x843e0000,0);
    data_rate(0.0);
    //
    // flush data from FIFOs
    message("5          " + time() + "Cmd: Spire_FLUSH_FIFO(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(3);
    message("5          " + time() + "Cmd: Spire_RESET_FIFOS(0x1000)");
    Spire_RESET_FIFOS(0x1000);
    //
    delay(1);
    message("4    " + time() + ": SpireStopDcuData ended");
    //
}

// SpireBbSetPtc
//
// $id$
//
// This building block starts or stops the  PTC PID Command List
//
// 09/06/2009 KJK:  First Version
//
block SpireBbSetPtc SPIRE 1611 {
    string ptc = "Off" in ["On","Off"];
    string version = "v00";
    bool debug = false;
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Set PTC started");
    SpireMsg(2,"          $Id: $");
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    //
    // stop PTC VM
    // this stops the VM from another command list - this stops the possibility of a TC execution error if the 
    // VM is not running
    int vm = ilookup("SpireTable_CommandLists.txt","PTC","Vm");
    tstr = SpireTimeStr(time());
    {int}[] cl = [{0x58000000 + vm},{0x7f000000}];
    SpireMsg(5,"          " + tstr + "Cmd: Spire_EXECUTE_COMMAND_LIST_RAW(" + 2 + "," + cl + ")");
    Spire_EXECUTE_COMMAND_LIST_RAW(2,cl);
    delay(2);
    //
    // ensure PTC bias is zero
    SpireSendDrcuCmd(0xa0c60000,0);
    // set PTC HTR bias to zero
    delay(2);
    //
    if(ptc == "On") {
        // start PTC VM, if required
        //
        // Get Command List info 
        int tableId = ilookup("SpireTable_CommandLists.txt","PTC","TableId");
        int startIndex = ilookup("SpireTable_CommandLists.txt","PTC","Index");
        int nParams = ilookup("SpireTable_CommandLists.txt","PTC","NParms");
        //
        // Retrieve the input parameters 
        int deltaTemp = ilookup("SpireTable_CL_PTC.txt",version,"DeltaTemp");
        int ptcTempCmd = ilookup("SpireTable_CL_PTC.txt",version,"PtcTempCmd");
        int loopPeriod = ilookup("SpireTable_CL_PTC.txt",version,"LoopPeriod");
        int kp = ilookup("SpireTable_CL_PTC.txt",version,"Kp");
        int ki = ilookup("SpireTable_CL_PTC.txt",version,"Ki");
        int kd = ilookup("SpireTable_CL_PTC.txt",version,"Kd");
        int kiLimit = ilookup("SpireTable_CL_PTC.txt",version,"KiLimit");
        int lpFiltGain = ilookup("SpireTable_CL_PTC.txt",version,"LpFiltGain");
        int lpFiltB1 = ilookup("SpireTable_CL_PTC.txt",version,"LpFiltB1");
        int lpFiltB2 = ilookup("SpireTable_CL_PTC.txt",version,"LpFiltB2");
        int dacOffset = ilookup("SpireTable_CL_PTC.txt",version,"DacOffset");
        int maxDac = ilookup("SpireTable_CL_PTC.txt",version,"MaxDac");
        int pwmFlag = ilookup("SpireTable_CL_PTC.txt",version,"PwmFlag");
        int frameCount = ilookup("SpireTable_CL_PTC.txt",version,"FrameCount");
        int initCount = ilookup("SpireTable_CL_PTC.txt",version,"InitCount");
        int errorComp = ilookup("SpireTable_CL_PTC.txt",version,"ErrorComp");
        //
        // start executing Command List
        {int}[] params = [{deltaTemp},{ptcTempCmd},{loopPeriod},{kp},{ki},{kd},{kiLimit},{lpFiltGain},{lpFiltB1},{lpFiltB2},{dacOffset},{maxDac},{pwmFlag},{frameCount},{initCount},{errorComp}];
        tstr = SpireTimeStr(time());
        if(vm == 1) {
            SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM1_RAW(" + tableId + "," + startIndex + "," + nParams + "," + params + ")");
            Spire_RUN_VM1_RAW(tableId,startIndex,nParams,params);
        }
        if(vm == 2) {
            SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM2_RAW(" + tableId + "," + startIndex + "," + nParams + "," + params + ")");
            Spire_RUN_VM2_RAW(tableId,startIndex,nParams,params);
        }
        if(vm == 3) {
            SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM3_RAW(" + tableId + "," + startIndex + "," + nParams + "," + params + ")");
            Spire_RUN_VM3_RAW(tableId,startIndex,nParams,params);
        }
        //
        delay(2);
    }
    //
    sync();
    //
    // completion
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB Set PTC   ended");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndSpecNonLinearity.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of 
// Spectro_CalGCO_ScannedSmecBeamProfile.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/09/15 V0.1: Initial version adapted from
//                  SpireBb_EndScannedSmecBeamProfile (2009/10/28 V1.0)
// 2009/12/03 V0.2: Removed unnecessary move of SMEC to home. 
// 2009/12/14 V0.3: Change BBid to free slot. 
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndSpecNonLinearity SPIRE 3409 {
    string resolution = "M" in ["L","M","H","C"]; // Resolution (low, medium, high,calibration)
    int smecHomePosn = 3500; // SMEC home position
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    string version05 = "v00"; // Version in cal table SpireTable_Spectrometer
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndSpecNonLinearity reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set obsstep back to 0:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP(0)");
    Spire_SET_OBS_STEP(0);
    // //
    // //
    // Move SMEC back to home position:
    //
    // Hardcoded calibration tables:
    //string tabName = "SpireTable_Spectrometer.txt";
    // Retrieve required SMEC end from calibration tables: 
    //int scanEnd = SpireProc_GetTableEntryInt(tabName,"ResChar",resolution,"ScanEnd",version05,debug);
    //
    //SpireProc_SmecMove(smecHomePosn,scanEnd,debug);
    //
    // ===> Not necessary, SMEC is at home at the end of 
    //      SpireProc_Exec_SpecNonLinearity.txt
    //
    // //
    // //
    // Set instrument back to Spec-STBY:
    //
    SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    // //
    // //
    // Set number of DCU frames to continuous:
    //
    int dcuFrameNumber = 0;
    dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuFrameNumber","v00",debug);
    //
    SpireSendDrcuCmd(0x843d0000 + dcuFrameNumber,0);
    // //
    // //
    // Set number of MCU frames to continuous:
    //
    int mcuFrameNumber = 0;
    mcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","mcuFrameNumber","v00",debug);
    SpireSendDrcuCmd(0x91c30000 + mcuFrameNumber,0);
    delay(1);
    // //
    // //
    // Set SMEC framerate (== SMEC sampling rate) back to SPEC_STBY:
    // (Note, hardcoded version to go back to STBY)
    //
    int smecFrameRate = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","smecFrameRate","v00",debug);
    SpireProc_Set_SmecFramerate(smecFrameRate,debug);
    // //
    // //
    // Stop any remaining SMEC movement:
    //
    SpireProc_SmecHold(debug);
    // //
    // //
    //  Open SMEC control loop:
    //
    SpireSendDrcuCmd(0x90440006,0);
    delay(4);
    // //
    // //
    // Set scientific datarate back to zero:
    //
    data_rate(0.0);
    // //
    // //
    // End observation:
    //
    bool phot = false;
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndSpecNonLinearity reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_GetTableEntryInt.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to select a double entry in a calibration table
//  giving a string input as selector using the versioning approach. 
//
//  Note: Currently script is restricted to a 'string' selector!
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/01/26 V0.1: Initial version adapted from 
//                  SpireProc_CalcParam_FpgInitialPointing.txt (2008/11/06 V0.3)
// 2009/07/12 V1.0: Fix SPR-SPIRE-1636 (reduce number of debug printouts)
//                  Change default values for testing. 
// 2009/08/15 V1.1: Fix SPR-SPIRE-1819 (add proper error message and report 
//                  table name)
//
///////////////////////////////////////////////////////////////////////////
//
int procedure SpireProc_GetTableEntryInt {
    string tabName = "SpireTable_PhotModeParams.txt"; // Name of the table to be selected from
    string selCol = "mode"; // Name of column for selecting 
    string selVal = "PHTSTBY"; // Value of 'string' selector 
    string tarCol = "mclkDiv"; // Target column name     
    string version = "v00"; // Version parameter defined in calibration table
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variable:
    //
    int intVar = 0;
    //
    // Define columns:
    string[] versionCol = scolumn(tabName,"version");
    int[] targetCol = icolumn(tabName,tarCol);
    string[] selectorCol = scolumn(tabName,selCol);
    //
    // Read table size: 
    int nrows = table_size(tabName);
    // //
    // //
    // Cycle through values to get all rows with correct version tag:
    //
    //Setup:
    {int,string}[] rows = [{0,""}];
    int nindex = 0;
    bool match = false;
    //
    for(int j = 0 .. nrows - 1) {
        //if(debug) {
        //    debug_print("versionCol[j]: " + versionCol[j]);
        //}
        if(versionCol[j] == version) {
            rows[nindex] = {targetCol[j],selectorCol[j]};
            nindex = nindex + 1;
            match = true;
        }
    }
    //if(debug) {
    //    debug_print("selected rows: " + rows);
    //}
    // Safety check: 
    if(!match) {
        error("Calibration table empty or wrong version selected!");
    }
    // //
    // //
    // Make final selection from all rows (selected by version):
    //
    int nentries = length(rows);
    int counter = 0;
    match = false;
    for(int i = 0 .. nentries - 1) {
        //if(debug) {
        //    debug_print("rows sliced:" + rows[i]{0} + "/" + rows[i]{1});
        //}
        if(rows[i]{1} == selVal) {
            intVar = rows[i]{0};
            match = true;
            counter = counter + 1;
        }
    }
    // Safety checks: 
    if(!match) {
        error("Entry " + selVal + " not found in calibration table (" + tabName + "). Call for help and wait to be rescued!");
    }
    //
    if(counter > 1) {
        error("Selector string " + selVal + " is present at least twice in the versioned calibration table(" + tabName + "). Please report this bug to the relevant authorities!");
    }
    // //
    // //
    // Return required value:
    //
    if(debug) {
        debug_print(" If you believe it of not, I found " + tarCol + "=" + intVar + " as version " + version + " when selecting for " + selCol + "=" + selVal + " in table " + tabName);
    }

    return intVar;
}

// SpireBbSmecOff
//
// $id$
//
// This building block switches off the SMEC
// 
//  07/05/2009: KJK
//      First Version
//
//  27/05/2009: SDS
//      Updated for SPIRE SCR-1719 to set Kp and Ki to zero at SMEC switch-off
//  14/10/2009: SDS/TWG
//      Included commands to stop MCU Eng data after switch-off (for SPR-2062 investigations) 
//      Now moves the SMEC to home in open loop in order to avoid a jump in the motor current
//
block SpireBbSmecOff SPIRE 532 {
    string version = "v00";
    bool debug = false;
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SMEC Off started");
    SpireMsg(2,"          $Id:$");
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    delay(1);
    //
    // set Step to zero
    SpireSetObsStep(0);
    //
    // Flag the current operation
    SpireSetObsMode("SMEC_OFF");
    delay(1);
    // 
    // Set SMEC to Home position
    int smecHome = ilookup("SpireTable_SmecNominalSettings.txt",version,"Home");
    // hold current position
    SpireSendDrcuCmd(0x90490000,0);
    // set Home position
    SpireSendDrcuCmd(0x90450000 + smecHome,0);
    SpireSendDrcuCmd(0x90460000,0);
    delay(1);
    // set movement speed
    int moveCmd = ilookup("SpireTable_SmecNominalSettings.txt",version,"MoveCmd");
    SpireSendDrcuCmd(0x90470000 + moveCmd,0);
    SpireSendDrcuCmd(0x90560000 + moveCmd,0);
    delay(1);
    //
    // Open the control loop
    SpireSendDrcuCmd(0x90440006,0);
    delay(4);
    // move it
    SpireSendDrcuCmd(0x90490001,0);
    delay(20);
    // hold current position
    SpireSendDrcuCmd(0x90490000,0);
    delay(1);
    //
    // switch off position sensors
    SpireSendDrcuCmd(0x90400000,0);
    SpireSendDrcuCmd(0x90410000,0);
    delay(1);
    //
    // Set SMEC Kp and Ki to 0 (SPIRE SCR-1719)
    SpireSendDrcuCmd(0x904a0000,0);
    SpireSendDrcuCmd(0x904d0000,0);
    delay(1);
    //
    // Stop MCU Eng data, flush MCU FIFO and set MCU Eng sampling to off
    //SpireSendDrcuCmd(0x91c10000,0);
    //delay(2);
    //Spire_FLUSH_FIFO(0x2000);
    //delay(1);
    //SpireSendDrcuCmd(0x91c40000,0);
    //
    //
    // completion
    sync();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB SMEC Off   ended");
    SpireMsg(1,"  ..SMEC Off (" + (time() - t0) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
//
// SpireProc_Set_DcuFreqSamp.txt
//
///////////////////////////////////////////////////////////////////////////
//
// Procedure to configure the DCU bias frequency and sampling rate. 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/17 V0.1: Initial version adapted from
//                  SpireProc_Set_DcuFreqSampMode (2009/02/15 V0.1)
//                  removing the setting of the dcuDataMode
// 2009/06/05 V1.0: Replace Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd 
//                  as requested in SPR-1482.
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_DcuFreqSamp {
    int mclkDiv = 149; // Bias freq. (for photometer == 130.20833 Hz)
    int biasDiv = 6; // Sampling freq. (for photometer == 18.60119 Hz)
    bool phot = true; // Set for photometer (==tick) or FTS 
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string tstr = "";
    //
    // Photometer or FTS?:
    bool fts = !phot;
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"     " + tstr + ": SpireProc_Set_DcuFreqSampMode started");
    SpireMsg(4,"          $Id:$");
    // //
    // //
    // Set the selected bias frequency, sampling frequency, and DCU data mode:
    //
    // Set mclkdiv and biasdiv:
    //
    if(phot) {
        SpireSendDrcuCmd(0x84190000 + mclkDiv,0);
        SpireSendDrcuCmd(0x84180000 + biasDiv,0);
    } else {
        SpireSendDrcuCmd(0x84390000 + mclkDiv,0);
        SpireSendDrcuCmd(0x84380000 + biasDiv,0);
    }
    sync();
    // //
    // //
    // Calculate bias and sampling frequencies based on mclkdiv and biasdiv:  
    //
    // Calculate bias frequency Hz:
    double bias_f = 1.0E7 / (512.0 * double(mclkDiv + 1));
    //
    // Calculate sampling rate Hz:
    double s_rate = bias_f / (1.0 + double(biasDiv));
    // //
    // //
    // Calculate frametime (time between successive frames = 1/sampling rate): 
    //
    //Frametime difference in ms:
    double framerate = 1.0 / s_rate * 1000.0;
    // //
    // //
    // Debug Printing:
    //
    //
    if(debug) {
        debug_print("    BIAS FREQUENCY IS : " + bias_f + " [Hz]");
        debug_print("SAMPLING FREQUENCY IS : " + s_rate + " [Hz]");
        debug_print("    FRAMETIME DIFF IS : " + framerate + " [ms]");
    }
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"      " + tstr + ": SpireProc_Set_DcuFreqSampMode ended");
}

// SpireBbStartPtc
//
// $id$
//
// This building block starts the PTC VM without switching off the PTC heater first (Needed for SPIRE SCR-2186)
//
// 23/11/2009 SDS:  First Version
//
block SpireBbStartPtc SPIRE 3407 {
    int stabilisationTimeThermistor = 120; // time (secs) to allow detectors to stabilise after starting PTC Thermistor VM (Detector data will also be stopped at this time)    
    string version = "v00";
    bool debug = false;
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Start PTC started");
    SpireMsg(2,"          $Id: $");
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    //
    // stop PTC VM
    // this stops the VM from another command list - this stops the possibility of a TC execution error if the 
    // VM is not running
    int vm = ilookup("SpireTable_CommandLists.txt","PTC","Vm");
    tstr = SpireTimeStr(time());
    {int}[] cl = [{0x58000000 + vm},{0x7f000000}];
    SpireMsg(5,"          " + tstr + "Cmd: Spire_EXECUTE_COMMAND_LIST_RAW(" + 2 + "," + cl + ")");
    Spire_EXECUTE_COMMAND_LIST_RAW(2,cl);
    delay(2);
    //
    //
    //
    // Get Command List info 
    int tableId = ilookup("SpireTable_CommandLists.txt","PTC","TableId");
    int startIndex = ilookup("SpireTable_CommandLists.txt","PTC","Index");
    int nParams = ilookup("SpireTable_CommandLists.txt","PTC","NParms");
    //
    // Retrieve the input parameters 
    int deltaTemp = ilookup("SpireTable_CL_PTC.txt",version,"DeltaTemp");
    int ptcTempCmd = ilookup("SpireTable_CL_PTC.txt",version,"PtcTempCmd");
    int loopPeriod = ilookup("SpireTable_CL_PTC.txt",version,"LoopPeriod");
    int kp = ilookup("SpireTable_CL_PTC.txt",version,"Kp");
    int ki = ilookup("SpireTable_CL_PTC.txt",version,"Ki");
    int kd = ilookup("SpireTable_CL_PTC.txt",version,"Kd");
    int kiLimit = ilookup("SpireTable_CL_PTC.txt",version,"KiLimit");
    int lpFiltGain = ilookup("SpireTable_CL_PTC.txt",version,"LpFiltGain");
    int lpFiltB1 = ilookup("SpireTable_CL_PTC.txt",version,"LpFiltB1");
    int lpFiltB2 = ilookup("SpireTable_CL_PTC.txt",version,"LpFiltB2");
    int dacOffset = ilookup("SpireTable_CL_PTC.txt",version,"DacOffset");
    int maxDac = ilookup("SpireTable_CL_PTC.txt",version,"MaxDac");
    int pwmFlag = ilookup("SpireTable_CL_PTC.txt",version,"PwmFlag");
    int frameCount = ilookup("SpireTable_CL_PTC.txt",version,"FrameCount");
    int initCount = ilookup("SpireTable_CL_PTC.txt",version,"InitCount");
    int errorComp = ilookup("SpireTable_CL_PTC.txt",version,"ErrorComp");
    //
    // start executing Command List
    {int}[] params = [{deltaTemp},{ptcTempCmd},{loopPeriod},{kp},{ki},{kd},{kiLimit},{lpFiltGain},{lpFiltB1},{lpFiltB2},{dacOffset},{maxDac},{pwmFlag},{frameCount},{initCount},{errorComp}];
    tstr = SpireTimeStr(time());
    if(vm == 1) {
        SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM1_RAW(" + tableId + "," + startIndex + "," + nParams + "," + params + ")");
        Spire_RUN_VM1_RAW(tableId,startIndex,nParams,params);
    }
    if(vm == 2) {
        SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM2_RAW(" + tableId + "," + startIndex + "," + nParams + "," + params + ")");
        Spire_RUN_VM2_RAW(tableId,startIndex,nParams,params);
    }
    if(vm == 3) {
        SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM3_RAW(" + tableId + "," + startIndex + "," + nParams + "," + params + ")");
        Spire_RUN_VM3_RAW(tableId,startIndex,nParams,params);
    }
    //
    delay(2+stabilisationTimeThermistor);
    //
    sync();
    //
    // completion
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB Start PTC   ended");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_GetTableEntryDouble.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to select a double entry in a calibration table
//  giving a string input as selector using the versioning approach. 
//
//  Note: Currently script is restricted to a 'string' selector!
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/01/26 V0.1: Initial version adapted from 
//                  SpireProc_CalcParam_FpgInitialPointing.txt (2008/11/06 V0.3)
// 2009/07/12 V1.0: Fix SPR-SPIRE-1636 (reduce number of debug printouts)
//                  Change default values for testing. 
// 2009/08/15 V1.1: Fix SPR-SPIRE-1819 (add proper error message and report 
//                  table name)
//
///////////////////////////////////////////////////////////////////////////
//
double procedure SpireProc_GetTableEntryDouble {
    string tabName = "SpireTable_PhotModeParams.txt"; // Name of the table to be selected from
    string selCol = "mode"; // Name of column for selecting 
    string selVal = "PHTSTBY"; // Value of 'string' selector 
    string tarCol = "dcuDataRate"; // Target column name     
    string version = "v00"; // Version parameter defined in calibration table
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variable:
    //
    double doubleVar = 0.0;
    //
    // Define columns:
    string[] versionCol = scolumn(tabName,"version");
    double[] targetCol = dcolumn(tabName,tarCol);
    string[] selectorCol = scolumn(tabName,selCol);
    //
    // Read table size: 
    int nrows = table_size(tabName);
    // //
    // //
    // Cycle through values to get all rows with correct version tag:
    //
    //Setup:
    {double,string}[] rows = [{0.0,""}];
    int nindex = 0;
    bool match = false;
    //
    for(int j = 0 .. nrows - 1) {
        //if(debug) {
        //    debug_print("versionCol[j]: " + versionCol[j]);
        //}
        if(versionCol[j] == version) {
            rows[nindex] = {targetCol[j],selectorCol[j]};
            nindex = nindex + 1;
            match = true;
        }
    }
    //if(debug) {
    //    debug_print("selected rows: " + rows);
    //}
    // Safety check: 
    if(!match) {
        error("Calibration table empty or wrong version selected!");
    }
    // //
    // //
    // Make final selection from all rows (selected by version):
    //
    int nentries = length(rows);
    int counter = 0;
    match = false;
    for(int i = 0 .. nentries - 1) {
        //if(debug) {
        //    debug_print("rows sliced:" + rows[i]{0} + "/" + rows[i]{1});
        //}
        if(rows[i]{1} == selVal) {
            doubleVar = rows[i]{0};
            match = true;
            counter = counter + 1;
        }
    }
    // Safety checks: 
    if(!match) {
        error("Entry " + selVal + " not found in calibration table (" + tabName + "). Call for help and wait to be rescued!");
    }
    //
    if(counter > 1) {
        error("Selector string " + selVal + " is present at least twice in the versioned calibration table(" + tabName + "). Please report this bug to the relevant authorities!");
    }
    // //
    // //
    // Return required value:
    //
    if(debug) {
        debug_print(" If you believe it of not, I found " + tarCol + "=" + doubleVar + " as version " + version + " when selecting for " + selCol + "=" + selVal + " in table " + tabName);
    }

    return doubleVar;
}

// Missionphase  : 
//
// Purpose       : Perform the cooler recycling
//
// TCL author    : TM
// TCL file      : tm_phot_cooler_recycling.tcl
// CUS author    : DAC
// Script file   : BOLO_cool_recycle.txt 
//
// Input arguments
// type    name         description
// N/A 
//
// Return values
// Type        Description
// int []      Several duration times
//
// Description   : see PhFPU UM, chapter 4
//
// Dependencies  : 
//
// Preconditions :
//
// Comments      : Based on the PhFPU UM Draft 6.0 and abundant e-mail
//                 exchanges with SAp
// 
// Version       : 2.0
// History       : 0.1 08-Apr-2005 creation by DAC; based on TM's
//                     version 1.0 of 24-Sep-2004
//                 0.2 15-apr-2005 DAC Forgot WriteBBID!!
//                 0.3 18-apr-2005 DAC Added Switch Off All Groups
//                                 and SetOn All Temp Probes
//                 0.4 20-sep-2005 Added DPU_SET_HK_LIST to "PHOT"
//                                 and to "NO_PRIME" 
//                 0.5 21-sep-2005 Zeroed several HEATER currents
//                 1.0 26-sep-2005 Added delay(600) as the last operation
//                 1.1 28-sep-2005 Modified as per Marcs's mail:
//                                "replace:
//          step 0 (1.18 mA on HSE, 0.0 mA on HSP, wait 300 sec)
//          step 1 (1.4 mA on HSE, wait 600 sec)
//                                 by
//          step 1(1.4 mA on HSE, 0.0 mA on HSP, wait 600 sec)"
//                 1.2  7-mar-2006 ....HEATER_CURR renamed to HEATER_CUR
//                 1.3 26-apr-2006  update with respect to 
//                                  Preparation_au_recyclage.txt  and
//                                  Recyclage_Auto_Time.txt       and
//                                  starting out of SAFE mode (groups
//                                  are on, but not biases are set and
//                                  temperature sensors are on)
//                 1.4 10-oct-2006  autonomy function added
//                 1.5 08-nov-2006  TM: checked for groups off
//                 1.6 13-nov-2006  TM: cleaning of SP and HSP to zero
//                 1.7 14-nov-2006 Wait 15 minutes before enabling autonomy function
//                 1.8 30-nov-2006 Wait 20 minutes before enabling autonomy function
//                 1.9 09-apr-2007 Modifications of AFs
//                 2.0 11-apr-2007 SP heater current set explicitly to zero
//                 2.1 17-oct-2008 KO, extra_cool_time and extra_stab_time variables added
//
int[] block BOLO_cool_recycle PACS 2003 {
    int extra_cool_time = 0; // in second before disconnecting the evaporator from 2K
    int extra_stab_time = 0; // in second after the end of the recycling procedure
}{
    // disable AF 14 (to check for TEMP_EV < 0.3 K)
    Pacs_DPU_SET_FUNCT("EVENT_BOL_T_FPU","DISABLE");
    // disable AF 21 (to check if the absolute value of the HSP current is below 2*10^(-5)A)
    Pacs_DPU_SET_FUNCT("EVENT_BOL_I_SP1","DISABLE");
    // enable AF 18 (to check if the current of the sorption pump heater is below 30mA)
    Pacs_DPU_SET_FUNCT("EVENT_BOL_I_SP2","ENABLE");
    //
    // Obtain and set Block ID
    WriteBBID($BBID);
    // Define variables to communicate various durations to HSPOT.
    // NOTE: all time variables in units of number of ramps (SPEC) or
    //       number of readouts (BOLO). The calling program must convert this
    //       count into actual duration in true time units [seconds].
    //       SRC, REF, CAL, OVR stand for time spent on SRC, REF (on sky),
    //       CAL source, and overheads (wait for something). Total
    //       duration is given by duree_num. If no error, this duration
    //       must be equal to the sum of all others
    // NOTE: here all durations are given in [sec]
    int duree_num = 0;
    int duree_SRC = 0;
    int duree_REF = 0;
    int duree_CAL = 0;
    int duree_OVR = 0;
    // Set HK to PHOT
    Pacs_DPU_SET_HK_LIST("PHOT","BOTH Array");
    // content of "Preparation_au_recyclage.txt"
    // Set SP heater current to  to 0.00000000 amperes (0)
    // # P 07 01 0000
    int operand = 0x7010000;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    int t_wait = 1;
    delay(t_wait);
    duree_num = t_wait;
    duree_OVR = t_wait;
    // Set HSP heater current to  to 0.00000000 amperes (0)
    // # P 07 02 0000
    operand = 0x7020000;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    t_wait = 1;
    delay(t_wait);
    duree_num = duree_num + t_wait;
    duree_OVR = duree_OVR + t_wait;
    // Set HSE heater current to  to 0.00140000 amperes (3572)
    // # P 07 03 0DF4
    // Attendre 300000 ms
    // # S 01 0493E0
    operand = 0x7030df4;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    t_wait = 300;
    delay(t_wait);
    duree_num = duree_num + t_wait;
    duree_OVR = duree_OVR + t_wait;
    // Set HSE heater current to  to 0.00118000 amperes (3011)
    // # P 07 03 0BC3
    // Attendre 900000 ms
    // # S 01 0DBBA0
    operand = 0x7030bc3;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    t_wait = 900;
    delay(t_wait);
    duree_num = duree_num + t_wait;
    duree_OVR = duree_OVR + t_wait;
    //*****************************************************************
    //**                                                             **
    //**     Automatic Cooling reclycling                            **
    //**     ("Recyclage_Auto_Time.txt")                             **
    //**                                                             **
    //*****************************************************************
    //
    // - 23/01/06 Procedure of reclycling in Saclay cryostat with Phfpu MV
    // - note : this is timing version without temperature test
    //
    //         Initialisation of BOLC
    //
    // Set temp probe on/off FF hexa
    // # P 07 00 00 FF
    // 
    //         Initialisation of LTU
    //
    // Inhiber enregistrement TM
    // # S 08 
    // Valider enregistrement TM
    // # S 09
    //
    // Initial conditions
    // TEMP_SP < 10K
    // TEMP_EV < 2K
    //
    // Set SP heater current to  to 0.02730000 amperes (2231)
    // # P 07 01 08B7
    //
    // Attendre 2100000 ms
    // # S 01 200B20
    operand = 0x70108b7;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    t_wait = 2100;
    delay(t_wait);
    duree_num = duree_num + t_wait;
    duree_OVR = duree_OVR + t_wait;
    //
    // Set SP heater current to  to 0.00700000 amperes (580)
    // # P 07 01 0244
    // 
    // Attendre 2820000 ms
    // # S 01 2B07A0
    operand = 0x7010244;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    t_wait = 2820;
    delay(t_wait);
    duree_num = duree_num + t_wait;
    duree_OVR = duree_OVR + t_wait;
    //
    // Additional wait time for the evaporator cooling down
    delay(extra_cool_time);
    duree_num = duree_num + extra_cool_time;
    duree_OVR = duree_OVR + extra_cool_time;
    //
    // Set HSE heater current to  to 0.00000000 amperes (0)
    // # P 07 03 0000 
    //
    // Attendre 720000 ms
    // # S 01 0AFC80 
    operand = 0x7030000;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    t_wait = 720;
    delay(t_wait);
    duree_num = duree_num + t_wait;
    duree_OVR = duree_OVR + t_wait;
    //
    // Set SP heater current to  to 0.00000000 amperes (0)
    // # P 07 01 0000
    operand = 0x7010000;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    t_wait = 1;
    delay(t_wait);
    duree_num = duree_num + t_wait;
    duree_OVR = duree_OVR + t_wait;
    //
    // Set HSP heater current to  to 0.00140000 amperes (3569)
    // # P 07 02 0DF1
    // 
    // Attendre 480000 ms
    // # S 01 075300 
    operand = 0x7020df1;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    t_wait = 480;
    delay(t_wait);
    duree_num = duree_num + t_wait;
    duree_OVR = duree_OVR + t_wait;
    //
    // Set HSP heater current to  to 0.00118000 amperes (3010)
    // # P 07 02 0BC2 
    operand = 0x7020bc2;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    t_wait = 1;
    delay(t_wait);
    duree_num = duree_num + t_wait;
    duree_OVR = duree_OVR + t_wait;
    //
    // ************************	
    // **                    **
    // ** end recycling      **
    // **                    **
    // ************************	
    //  Last message
    debug_print("Recycling completed, in about 20 min, TEMP_EV < 0.3 K");
    t_wait = 1200;
    duree_num = duree_num + t_wait;
    duree_OVR = duree_OVR + t_wait;
    delay(t_wait);
    //
    // AF settings
    //
    // disable AF 18 (to check if the current of the sorption pump heater is below 30mA)
    Pacs_DPU_SET_FUNCT("EVENT_BOL_I_SP2","DISABLE");
    // enable AF 21 (to check if the absolute value of the HSP current is below 2*10^(-5)A)
    Pacs_DPU_SET_FUNCT("EVENT_BOL_I_SP1","ENABLE");
    //
    // Set HK to NO PRIME (to have the clean SAFE settings again)
    Pacs_DPU_SET_HK_LIST("NO_PRIME","BOTH Array");
    //
    // Additional wait time for the evaporator temperature stabilisation
    delay(extra_stab_time);
    duree_num = duree_num + extra_stab_time;
    duree_OVR = duree_OVR + extra_stab_time;
    //
    // Return the array of times
    int[] time_array = [duree_num,duree_SRC,duree_REF,duree_CAL,duree_OVR];

    return time_array;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SetupSmecScan.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Prepare SMEC for scanning
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/30 V0.1: Initial version adapted for 
//                  SpireProc_Setup_SmecScan.txt (2009/03/25 V0.1)
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SetupSmecScan SPIRE 14035 {
    string resolution = "L" in ["L","M","H","C"]; // Resolution (low, medium, high,calibration)
    string version = "v00"; // Version in cal table SpireTable_Spectrometer
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SetupSmecScan started");
    SpireMsg(2,"          $Id:$");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Call low level procedure to do scan::
    //
    SpireProc_Setup_SmecScan(resolution,version,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SetupSmecScan ended");
    SpireMsg(1,"  ..BBSetupSmecScan (" + (time() - t) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Setup_SmecScan.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Prepare SMEC for scanning 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/25 V0.1: Initial version adapted from
//                  SpireBb_SmecScan (2008/11/03 V0.1)
//                  SpireBbFtsScan (KJK, 2009/01/01)
// 2009/03/31 V0.2: Add important note to header. 
//
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1) SMEC scan parameters can be read from calibration table:
//     SpireTable_Spectrometer.txt 
//
// Note, when SpireProc_Setup_SmecScan is used it needs to be run
//  after the SpireProc_SmecMove! 
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Setup_SmecScan {
    string resolution = "L" in ["L","M","H","C"]; // Resolution (low, medium, high,calibration)
    string version = "v00"; // Version in cal table SpireTable_Spectrometer
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Define some variables:
    //
    string tstr = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    //
    // Hardcoded calibration tables:
    //
    string tabName = "SpireTable_Spectrometer.txt";
    //
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"     " + tstr + ": SpireProc_Setup_SmecScan started");
    SpireMsg(4,"          $Id:$");
    // //
    // //
    // Retrieve required SMEC parameters from calibration tables: 
    // 
    int resId = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ResId",version,debug);
    int scanStart = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanStart",version,debug);
    int scanEnd = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanEnd",version,debug);
    int scanFCmd = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanFCmd",version,debug);
    int scanRCmd = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanRCmd",version,debug);
    //
    if(debug) {
        debug_print("resId: " + resId);
        debug_print("scanStart: " + scanStart);
        debug_print("scanEnd: " + scanEnd);
        debug_print("scanFCmd: " + scanFCmd);
        debug_print("scanRCmd: " + scanRCmd);
    }
    // //
    // //
    // Set SCANRES HSK parameter:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_UPDATE_TABLE_RAW(7, 6, 1, " + resId + ")");
    Spire_UPDATE_TABLE_RAW(7,6,1,[{resId}]);
    // //
    // //
    // Set SMEC to hold its position (stop trajectory generation)
    SpireSendDrcuCmd(0x90490000,0);
    // //
    // //
    // Set scan start and ending position:
    //
    SpireSendDrcuCmd(0x90450000 + scanEnd,0);
    delay(1);
    SpireSendDrcuCmd(0x90460000 + scanStart,0);
    // //
    // //
    // Set scan forward and reverse speed 
    // (only different if we are performing a saw tooth scan): 
    //
    SpireSendDrcuCmd(0x90470000 + scanFCmd,0);
    delay(1);
    SpireSendDrcuCmd(0x90560000 + scanRCmd,0);
    sync();
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"      " + tstr + ": SpireProc_Setup_SmecScan ended");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SmecScan.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Scan SMEC N-times at input spectral resolution
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/11/03 V0.1: Initial version adapted from 
//                  SFBeamPeakUp_SMECScan.txt (v 1.4 2008/01/31 20:24:37) and
//                  SpireBbFtsScan.txt (20/04/07: v1.4)
// 2009/03/30 V0.2: Move all commands to new low level script 
//                  SpireProc_SmecScan. Add header line. 
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SmecScan SPIRE 14020 {
    string resolution = "L" in ["L","M","H","C"]; // Resolution (low, medium, high,calibration)
    int nscans = 1; // Number of SMEC scans (back+forth == 1)
    string version = "v00"; // Version in cal table SpireTable_Spectrometer
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SmecScan started");
    SpireMsg(2,"          $Id:$");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Call low level procedure to do scan::
    //
    SpireProc_SmecScan(resolution,nscans,version,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SmecScan ended");
    SpireMsg(1,"  ..SmecScan (" + (time() - t) + " seconds)");
}

// SpireProc_PTCOn
//
// $id$
//
// This procedure switches on the PTC
// 
// The instrument should be in PHOTSTBY mode before execution of this observation
// Final Configuration: Instrument is still in PHOTSTBY mode after execution of this observation
//
// 05/08/2009 SDS: First Version 0.1 
// 17/02/2010 SDS:  Version 0.2
//                             Replaced procedures SpireProc_Set_StartDcuData & SpireProc_Set_StopDcuData with BBs 
//                             SpireBbStartDcuData and SpireBbStopDcuData (SPIRE SPR-1832)
//
procedure SpireProc_PTCOn {
    int stabilisationTime = 120; // time (secs) to allow Detectors to stabilise before starting observations
    bool sampleDetectors = true; // sample detectors during the stabilisation period
    string ptcVersion = "v00";
    bool debug = false;
}{
    if(sampleDetectors) {
         SpireBbStartDcuData("PHTSTBY");
    }
    delay(2);
    SpireBbSetPtc("On",ptcVersion,debug);
    delay(1);
    //
    if(sampleDetectors) {
        //
        // Reset the Photometer detector offsets 
        //
        SpireBb_PhotOffsetAuto(debug);
        //
        // Restart DCU PF data 
        //
        SpireBbStartDcuData("PHTSTBY");
    }
    // ----------------
    // Stabilisation
    // ----------------
    delay(stabilisationTime);
    //
    // Stop DCU PF data
    //
    if(sampleDetectors) {
        SpireBbStopDcuData();
    }
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
//
// SpireProc_Exec_SpecStdLoadCurve.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to loop through a list of bias amplitudes for
//  the 'Spec Standard Load Curve' task 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/12 V0.1: Initial version adapted from 
//                  SpireProc_Exec_PhotStdLoadCurve (2008/07/04 V0.2)
//                  based on
//                  Mode_ILT_PERF_DAB_S_Levels (v1.3 2008/01/31 23:35:17)
// 2009/02/19 V0.2: Add debug_print as input. Add dcuData to input. 
//
///////////////////////////////////////////////////////////////////////////
procedure SpireProc_Exec_SpecStdLoadCurve {
    int[] nbiaslist = [0,50,100,255]; // List of raw bias levels in range (0-255)
    int ftime = 10; // Readout time at each bias level [s]
    bool dcuData = false; // Is (==tick) the DCU currently sampled? 
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    //
    //
    // Start the LC bias loop:
    //
    for(int l = 0 .. length(nbiaslist) - 1) {
        // //
        // //
        // Safety check:
        //
        if(nbiaslist[l] > 255) {
            nbiaslist[l] = 255;
            if(debug) {
                debug_print("Input bias list is corrupt! Raw value > 255 requested!");
            }
        }
        // //
        // //
        // Set bias amplitude:
        //
        if(l == 0) {
            if(debug) {
                debug_print("Bias already set during slew");
            }
        } else {
            SpireBb_SpecFSetBiasAmpl(nbiaslist[l],nbiaslist[l],debug);
        }
        // //
        // //
        // Stop DCU data before resetting offsets:
        //
        SpireBb_StopDcuData();
        //
        // //
        // //
        // Set offsets:
        //
        SpireBb_SpecOffsetAuto(dcuData,debug);
        // //
        // //
        // Take data:
        //
        SpireBb_SpecFTakeData(ftime,debug);
        //
        // //
        // //
        // Printing: 
        //
        if(debug) {
            debug_print("Bias level " + nbiaslist[l] + " done.");
        }
    }
    //
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartFpgInitialPointing.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpirePhoto/Spectro_CalGCO_FpgInitialPointing.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V0.1: Initial version adapted from
//                  SpireBb_StartBsmAngleCal (2009/05/05 V0.1),
//                  SpirePhoto_CalGCO_FpgInitialPointing (2009/03/03 V1.3), and
//                  SpireSpectro_CalGCO_FpgInitialPointing (2009/03/03 V0.4)
//                  BB includes now to move BSM/SMEC to hold/home.  
// 2009/07/03 V1.0: Set SMEC framerate to zero so VM will NOT generate 
//                  BSM and SMEC data. This is needed for running the 
//                  Spec FpgInitialPointing.  
// 2009/07/10 V1.1: Fix bug SPR-SPIRE-1612
//
// Notes:
//    1) Scripts assumes that SpireBb_SpecOffsetAuto is run 
//       during INITHOLD or at first POINTING.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartFpgInitialPointing SPIRE 14054 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    string obsModeQla = "ENG_CAL_OBS01";
    string obsMode = "PEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_Phot/SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    int smecHomePosn = 3500; // SMEC home position
    bool setFramerate = true; //
    int frate = 0; //
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartFpgInitialPointing configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // In case move SMEC to home:
    // 
    if(!phot) {
        //
        // Calculate available time for possible movement:
        //
        int tmove = duration(SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug)) + duration(SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug)) + duration(SpireBb_SpecOffsetAuto(false,debug));
        if(setFramerate) {
            tmove = tmove + duration(SpireProc_Set_BsmFramerate(frate,debug));
        }
        //
        // Calculate max offset for which time is available:
        //
        int smecMaxOff = tmove * 500;
        // Note, 500 is maximum possible SMEC speed.
        int smecStart = smecHomePosn + smecMaxOff;
        // Note, formula above only reasonable 
        // when smecHomePosn small compared to 39500  
        // Safety check: 
        if(smecStart > 39500) {
            smecStart = 39500;
        }
        if(debug) {
            debug_print("smecStart: " + smecStart);
            debug_print("smecHomePosn: " + smecHomePosn);
            debug_print("tmove: " + tmove);
        }
        // 
        // Move from maximal offset to home:
        //
        SpireProc_SmecMove2Home(smecHomePosn,smecHomePosn + smecMaxOff,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    if(phot) {
        SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    }
    //delay(timeSlewCal);
    // //
    // //
    // Set BSM framerate (==BSM sampling rate):
    //
    if(setFramerate) {
        SpireProc_Set_BsmFramerate(frate,debug);
    }
    // //
    // //
    // Set SMEC framerate (== SMEC sampling rate) to zero:
    //
    if(!phot) {
        SpireProc_Set_SmecFramerate(0,debug);
    }
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartFpgInitialPointing configuration ended");
    SpireMsg(1,"  ..StartFpgInitialPointing took " + (time() - t) + " seconds)");
    //
}

// SpireBbBsmJiggInit
//
// $id$
//
// This building block initialises the BSM jiggle axis
// 
// The BSM should be switched on (SpireBbBsmOn) before execution of this building block
//
// 27/04/2009 KJK: 
//         Updated to use new NominalSettings Cal Tables
//         model, version and debug passed as parameters
// 07/05/2009 KJK:
//         Added opsMode as input parameter to allow setting of bsmMoveMode from DefaultParams.txt calibration table
//
// 09/04/2010 SDS:
//         Added the setting of Jiggle FF offset (SPIRE-SCR-2490)
block SpireBbBsmJiggInit SPIRE 270 {
    string opsMode = "PHTSTBY";
    string model = "initial";
    string version = "v00";
    bool debug = false;
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB BSM Jigg Init started");
    SpireMsg(2,"          $Id$");
    //
    // 
    // intialise variables
    int jigglekd = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",model,"jigg_kd",version,debug);
    int jigglekp = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",model,"jigg_kp",version,debug);
    int jiggleki = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",model,"jigg_ki",version,debug);
    int jiggle_t1 = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",model,"jigg_filt1",version,debug);
    int jiggle_hold = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",model,"jigg_0_I",version,debug);
    //
    // Additional parameter
    int jiggffoffset = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",model,"jigg_ff_offset",version,debug);
    //
    // 
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    delay(1);
    //
    // set Step to zero
    SpireSetObsStep(0);
    //
    // flag the current operation
    SpireSetObsMode("BSM_INIT");
    delay(1);
    //
    // Set Movement Mode for initialisation
    SpireSendDrcuCmd(0x90c60000,0);
    //
    // Set the Jiggle FF offset
    //
    SpireSendDrcuCmd(0x91470000 + jiggffoffset,0);
    delay(1);
    //
    // Set jiggle Kd parameter
    SpireSendDrcuCmd(0x91490000 + jigglekd,0);
    delay(1);
    //
    // Set jiggle Kp parameter
    SpireSendDrcuCmd(0x91480000 + jigglekp,0);
    delay(1);
    //
    // Set jiggle Ki parameter
    SpireSendDrcuCmd(0x914a0000 + jiggleki,0);
    delay(1);
    //
    // Set jiggle derivative filtering parameter 1
    SpireSendDrcuCmd(0x914f0000 + jiggle_t1,0);
    delay(1);
    //
    // Remove slew rate limiter
    SpireSendDrcuCmd(0x9151ffff,0);
    delay(1);
    //
    // Set target position to HOLD
    SpireSendDrcuCmd(0x91430000 + jiggle_hold,0);
    delay(1);
    //
    // Close loop on jiggle axis
    SpireSendDrcuCmd(0x91420001,0);
    delay(1);
    //
    // Set Default Movement Mode
    int bsmMoveMode = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",opsMode,"bsmMoveMode",version,debug);
    SpireSendDrcuCmd(0x90c60000 + bsmMoveMode,0);
    //
    // completion
    sync();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB BSM Jigg Init   ended");
    SpireMsg(1,"  ..BSM Jiggle Axis Initialisation (" + (time() - t0) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartTransRespoAndDynBeamProf.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpirePhoto_CalGCO_TransRespoAndDynBeamProf.txt
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/07 V0.1: Initial version adapted from
//                  SpireBb_StartBsmAngleCal (2009/05/05 V0.1),
//                  SpirePhoto_CalGCO_TransRespoAndDynBeamProf (2009/03/04 V1.2)
//                  BB includes now to move BSM to hold.  
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartTransRespoAndDynBeamProf SPIRE 14062 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    string obsModeQla = "ENG_CAL_OBS06";
    string obsMode = "PEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_Phot/SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartTransRespoAndDynBeamProf configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    if(phot) {
        SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    }
    //delay(timeSlewCal);
    // //
    // //
    // Set Obs step at to fff:
    //
    int obsStep = 4095;
    SpireProc_Set_ObsStep(obsStep,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartTransRespoAndDynBeamProf configuration ended");
    SpireMsg(1,"  ..StartTransRespoAndDynBeamProf took " + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_PhotFSetBiasAmpl.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set bias amplitude of photometer arrays
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/05/02 V0.1: Initial version adapted from 
//                  PFBias_Ampl.txt (v1.4 2008/01/31 20:24:34)
// 2008/05/08 V0.2: Restrict script to send only 2 commands per second 
//                  by adding delay(1)'s 
// 2008/07/03 V0.3: Renumber version; Set also PTC bias properly
// 2009/01/27 V1.0: Add debug_print; Remove unsetting of BBID at end.
//                  Add HSPOT messages;
// 2009/02/14 V1.1: Instead of using commands call SpireProc_Set_PhotBias
//                  and add sync() after setBbId 
// 2009/05/07 V1.2: Fixed copy/paste bug to set bias instead of phase
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_PhotFSetBiasAmpl SPIRE 14006 {
    int psw_bias = 0x3e; //Default (IST) bias amplitud  (==31.0761 mV)
    int pmw_bias = 0x3e; //Default (IST) bias amplitud  (==31.2735 mV)
    int plw_bias = 0x3e; //Default (IST) bias amplitud  (==31.4033 mV)
    int ptc_bias = 0x80; //Default (IST) bias amplitud  (==127.6311 mV)
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string hstr = "";
    // a hex string
    string tstr = "";
    // a time string
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": SpireBb_PhotFSetBiasAmpl started");
    SpireMsg(2,"          $Id: $");
    hstr = SpireHexStr($BBID,8);
    SpireMsg(3,"          BBID = " + hstr);
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    sync();
    // //
    // //
    // Set the bias levels for the three arrays and the PTC:
    //
    SpireProc_Set_PhotBias(psw_bias,pmw_bias,plw_bias,ptc_bias,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_PhotFSetPhase ended");
    SpireMsg(1,"  ..Set Phot phases (" + (time() - t) + " secs)");
    //
}

// SpirePOF3Observing
//
// $Id:$
//
// This is the procedure to calculate 
// instrument observing parameters for the n-point Jiggle map observing mode
//
//  12/08/2009 KJK:
//            SPIRE-1804: Added versions and debug as input parameters to enable calling SpireBbJiggle correctly
//            Changed calls to calibration Tables to use versions
//
{double,int,int,int,int,int} procedure SpirePOF3Observing {
    int nRepetitions = 1; // requested number of repetitions
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParms
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParm;
    string chopVersion = "v00"; // Version in cal table SpireTable_ChopParams
    bool debug = false;
}{
    SpireMsg(2,"    POF3 Observing Parameters ");
    SpireMsg(2,"    $Id:$");
    //
    // fetch operating parameters 
    string obsMode = "POF3";
    int t = 0;
    t = SpireProc_GetTableEntryInt("SpireTable_SpireParams.txt","mode",obsMode,"FlashTime",spireVersion,debug);
    double flashTime = double(t);
    // Optimum time between flashes
    t = SpireProc_GetTableEntryInt("SpireTable_SpireParams.txt","mode",obsMode,"CalTime",spireVersion,debug);
    double calTime = double(t);
    // Minimum time between gyro calibrations
    int jiggleTable = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"TableId",opsVersion,debug);
    // Jiggle Table ID  
    int jiggleSize = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"TableSize",opsVersion,debug);
    // Jiggle Table length 
    int nChops = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NChops",opsVersion,debug);
    // number of chop cycles per jiggle position  
    int nJiggs = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NJiggs",opsVersion,debug);
    // number of jiggle positions per nod position  
    int nNodPosns = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NNodPosns",opsVersion,debug);
    // number of nod positions in a nod cycle 
    int nNodCycles = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NNodCycles",opsVersion,debug);
    // number of nod cycles in a repetition 
    bool initFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"InitFlash",spireVersion,debug);
    // initial flash flag
    bool endFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"EndFlash",spireVersion,debug);
    // final flash flag
    double srcTime = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"SrcTime",opsVersion,debug);
    // effective on source integration time per complete map
    //     
    // *****************************************
    //   Display input parameters
    // *****************************************
    SpireMsg(3,"     POF3 Observing input values:");
    SpireMsg(3,"     ..nRepetitions: " + nRepetitions);
    SpireMsg(3,"     POF3 Fixed values:");
    SpireMsg(3,"     ..jiggleTable: " + jiggleTable);
    SpireMsg(3,"     ..jiggleSize: " + jiggleSize);
    SpireMsg(3,"     ..nChops: " + nChops);
    SpireMsg(3,"     ..nJiggs: " + nJiggs);
    SpireMsg(3,"     ..nNodPosns: " + nNodPosns);
    SpireMsg(3,"     ..flashTime: " + flashTime);
    SpireMsg(3,"     ..calTime: " + calTime);
    SpireMsg(3,"     ..initFlash: " + initFlash);
    SpireMsg(3,"     ..endFlash: " + endFlash);
    SpireMsg(3,"     ..srcTime: " + srcTime);
    //
    // calculate observing parameters
    SpireMsg(2,"    Calculated Parameters:");
    //
    // number of times to repeat the jiggle cycle at each nod position  
    // Note:  this is currently read from a calibration table but could be calculated 
    // if it is required to dynamically assign integration time to each nod position
    // rather than by repeating complete nod cycles
    int nNodInts = ilookup("OpsParms.txt","POF3","NNodInts");
    SpireMsg(3,"      Required number of jiggle cycles at each nod position: " + nNodInts);
    //
    // number of nod cycles to perform per map
    int nCycles = jiggleSize / nJiggs;
    SpireMsg(3,"      Number of nod cycles per Map: " + nCycles);
    //
    //  number of maps to perform
    int nMaps = nRepetitions * nNodCycles / nCycles;
    //
    SpireMsg(3,"      Required number of Maps: " + nMaps);
    //
    // observing time per nod cycle
    double cycleTime = double(nNodPosns * duration(SpireBbJiggle("POF3",jiggleTable,0,nJiggs,nNodInts,0,opsVersion,chopVersion,debug)));
    SpireMsg(3,"      Time for a Nod cycle: " + cycleTime);
    //
    // total observing time 
    double totalTime = double(nMaps) * double(nCycles) * cycleTime;
    SpireMsg(3,"      Total observing time: " + totalTime);
    //
    // number of nod cycles per Gyro calibration 
    // Note: this only takes into account on source observing time, not movement between nod positions, 
    // which is assumed to be a small fraction of the observing time, and so the value obtained is approximate 
    int nCals = ifloor(totalTime / calTime);
    // SpireMsg(3,"      Number of Gyro Calibrations: " + nCals);
    int nCal = iceil(totalTime / cycleTime);
    // default is no gyro calibrations during observation 
    if(nCals > 0) {
        nCal = iceil(double(nCycles) * double(nMaps) / double(nCals + 1));
    }
    if(nCycles % nCal == 0) {
        nCal = nCal + 1;
    }
    // SpireMsg(3,"      Number of Gyro Calibrations(adjusted): " + nCals);
    // SpireMsg(3,"      Number of nod cycles per Gyro calibration: " + nCal);
    //
    // number of cycles per PCAL calibration 
    // Note: this only takes into account on source observing time, not movement between nod positions, 
    // which is assumed to be a small fraction of the observing time, and so the value obtained is approximate 
    int nFlashes = ifloor(totalTime / flashTime);
    SpireMsg(3,"      Number of Flashes: " + nFlashes);
    int nFlash = iceil(totalTime / cycleTime);
    // default is no flashes during observation 
    if(nFlashes > 0) {
        nFlash = iceil(double(nCycles) * double(nMaps) / double(nFlashes + 1));
    }
    if(nCycles % nFlash == 0) {
        nFlash = nFlash + 1;
    }
    SpireMsg(3,"      Number of Flashes(adjusted): " + nFlashes);
    SpireMsg(3,"      Number of nod cycles per PCAL calibration: " + nFlash);

    return {srcTime,nMaps,nCycles,nNodInts,nCal,nFlash};
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Exec_SpecPcalLoadCurve.txt
//
///////////////////////////////////////////////////////////
//
//  Procedure to loop through a list of bias amplitudes and flashing
//  PCAL for the 'Spec PCAL Load Curve' task 
//
///////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/09/16 V0.1: Initial version adapted from
//                  SpireProc_Exec_PhotPcalLoadCurve (2008/08/15 V0.3)
// 2009/02/19 V0.2: Add debug_print as input and pass it to low level script.
//                  Replace SpireProc_Exec_PcalFlash by direct call to 
//                  SpireBb_PcalFlash. Adapt input to updated SpireBb_PcalFlash
//                  with rate and step. Promote new VM table parameters of 
//                  SpireBb_PcalFlash. Implement proper setting of FTS 
//                  ILT Pcal highbias levels (bug detected at SDAG#19). 
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Exec_SpecPcalLoadCurve {
    int[] nbiaslist = [0,50,100,255]; // List of raw bias levels in range (0-255)
    int ftime = 10; // Readout time at each bias level [s]
    int mclkdiv = 0x79; //Default (IST) bias freq (== 160.092 Hz)
    int biasdiv = 0x1; //Default (IST) sampling freq (== 80.046 Hz)
    int vmId = 70; // Raw VM table number [Dec(Hex)]
    int vmIndex = 0; // Raw VM index [Dec(Hex)]
    int nParms = 9; // Number of parameters passed to VM
    bool dcuData = false; // Is (==tick) the DCU currently sampled?
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Predefine version in SpireTable_SpecPcalCurrentConvCoef.txt:
    //
    string ver_a = "v01";
    if(debug) {
        debug_print("The nominal version in SpireTable_PcalCurrentConvCoef.txt is v01");
    }
    // //
    // //
    // Retrieve PCAL bias calibration coefficients:
    //
    double[] coeff = [0.0];
    coeff[0] = dlookup("SpireTable_PcalCurrentConvCoef.txt",ver_a,"c_0");
    coeff[1] = dlookup("SpireTable_PcalCurrentConvCoef.txt",ver_a,"c_1");
    // //
    // //
    // Set ILT standard values for PCAL flash:
    //
    // Period of cycle in microsec:
    int flashperiod = 4000000;
    // Period of cycle in millisec:
    int period = flashperiod / 1000;
    // Number of cycles:
    int ncycles = 15;
    // DCU data mode (default = PF == 0; SF == 0):
    int ndcumode = 4;
    // SCU sampling rate (f =80Hz/(1+scumode)):
    int scumode = 0;
    // //
    // //
    // Calculate the RAW bias levels:
    //
    //[mA] Low Level for 1st PCAL flash:
    double lowbias_0 = 0.0;
    //[mA] High Level for 1st PCAL flash:
    double highbias_0 = 4.8;
    //[mA] Low Level for 2nd PCAL flash:
    double lowbias_1 = 0.0;
    //[mA] High Level for 2nd PCAL flash:
    double highbias_1 = 6.0;
    //
    int pcal_low_bias_0 = iround((lowbias_0 * 0.0010 - coeff[0]) / coeff[1]);
    int pcal_high_bias_0 = iround((highbias_0 * 0.0010 - coeff[0]) / coeff[1]);
    int pcal_low_bias_1 = iround((lowbias_1 * 0.0010 - coeff[0]) / coeff[1]);
    int pcal_high_bias_1 = iround((highbias_1 * 0.0010 - coeff[0]) / coeff[1]);
    // //
    // //
    // Deduce number of DCU samples, SCU samples and DCU sample delay based on mclkdiv and biasdiv:
    //
    int[] flash_params = SpireProc_CalcParam_PcalFlash(period,mclkdiv,biasdiv,debug);
    int dcusamples = flash_params[0];
    int scusamples = flash_params[1];
    int dcudelay = flash_params[2];
    if(debug) {
        debug_print("//////////////////////////////////////////////////////////////");
        debug_print("");
        debug_print("CALCULATED DCU SAMPLES : " + dcusamples);
        debug_print("CALCULATED SCU SAMPLES : " + scusamples);
        debug_print("CALCULATED  SAMP DELAY : " + dcudelay + "microsec");
        debug_print("");
        debug_print("//////////////////////////////////////////////////////////");
    }
    // //
    // //
    // Start the LC bias loop:
    //
    for(int l = 0 .. length(nbiaslist) - 1) {
        // //
        // //
        // Safety check:
        //
        if(nbiaslist[l] > 255) {
            nbiaslist[l] = 255;
            if(debug) {
                debug_print("Input bias list is corrupt! Raw value > 255 requested!");
            }
        }
        // //
        // //
        // Set STEP:
        //
        int obsStep = l + 1;
        // NHK Step parameter 
        if(obsStep == 1) {
            if(debug) {
                debug_print("First obsStep already set during slew");
            }
        } else {
            SpireBb_SetObsStep(obsStep,debug);
        }
        // //
        // //
        // Set bias amplitude:
        //
        if(l == 0) {
            if(debug) {
                debug_print("Bias already set during slew");
            }
        } else {
            SpireBb_SpecFSetBiasAmpl(nbiaslist[l],nbiaslist[l],debug);
        }
        // //
        // //
        // Stop DCU data before resetting offsets:
        //
        SpireBb_StopDcuData();
        //
        // //
        // //
        // Set offsets:
        //
        SpireBb_SpecOffsetAuto(dcuData,debug);
        //
        // //
        // //
        // Execute PCAL flashes:
        //
        // First PCAL Flash: 
        // 
        SpireBb_PcalFlash(vmId,vmIndex,nParms,pcal_low_bias_0,pcal_high_bias_0,ncycles,flashperiod,ndcumode,dcusamples,dcudelay,scumode,scusamples,obsStep,debug);
        //
        // Second PCAL Flash: 
        //
        SpireBb_PcalFlash(vmId,vmIndex,nParms,pcal_low_bias_1,pcal_high_bias_1,ncycles,flashperiod,ndcumode,dcusamples,dcudelay,scumode,scusamples,obsStep,debug);
        // //
        // Take data:
        //
        SpireBb_SpecFTakeData(ftime,debug);
        //
        // //
        // //
        // Printing: 
        //
        if(debug) {
            debug_print("Bias level " + nbiaslist[l] + " done.");
        }
    }
    //
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_StopMcuData.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to stop generation of MCU data TM packets
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/31 V1.0: Initial version adapted from
//                  SpireProc_Set_StopDcuData (2009/01/30 V1.1)
// 2009/06/05 V1.1: Remove wrong Hspot message. 
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_StopMcuData {
}{
    // //
    // //
    // Start procedure:
    //
    message("4    " + time() + ": SpireProc_Set_StopMcuData started");
    message("4          $Id: $");
    // //
    // //
    // Stop data collection:
    //
    SpireSendDrcuCmd(0x91c10000,0);
    // //
    // //
    // Flush MCU (x2000) fifo:
    //
    message("5          " + time() + "Cmd: Spire_FLUSH_FIFO(0x2000)");
    Spire_FLUSH_FIFO(0x2000);
    delay(2);
    // //
    // //
    // End procedure:
    //
    message("4    " + time() + ": SpireProc_Set_StopMcuData ended");
    //
}

// SpireTimeStr
//
// a procedure to convert a time into a string in the form
//     [nnnnn]
// 
string procedure SpireTimeStr {
    int t = 0;
}{
    string s = "";
    if(t < 10) {
        s = "[0000";
    } else {
        if(t < 100) {
            s = "[000";
        } else {
            if(t < 1000) {
                s = "[00";
            } else {
                if(t < 10000) {
                    s = "[0";
                }
            }
        }
    }
    //

    return s + t + "]";
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
//
// SpireProc_Exec_BsmPcalFlash.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to loop through a list of BSM settings and flash PCAL 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/12/12 V0.1: Initial version adapted from
//                  SPIRE_IST_BSM_PCALFLASH.txt and Proc_BSMStep.txt
//                  (Sunil email 09/12/08 19:10) using as template:
//                  SpireProc_Exec_PhotPcalLoadCurve (2008/08/15 V0.3)
// 2009/02/02 V1.0: Pass debug_print to low level scripts.
//                  Replace SpireProc_Exec_PcalFlash by direct call to 
//                  SpireBb_PcalFlash. Adapt input to updated SpireBb_PcalFlash
//                  with rate and step. Rate is input, step set in loop.
//                  Replace erroneous 0x90c3 by correct call to BB.
// 2009/02/16 V1.1: Promote new VM table parameters of SpireBb_PcalFlash
//                  to input. 
// 2009/02/18 V1.2: Adapt to change in call to SpireBb_PcalFlash.
// 2009/03/04 V1.3: Make sure the correct ILT levels are used when
//                  using with the FTS. Set default fts to false.
// 2009/06/08 V1.4: Add in offset setting after each BSM movement just
//                  before the Pcal Flash (see SPR-1496). 
// 2009/07/12 V1.5: Remove reference (in text only) to PhotPcalCurrentConvCoef
//                  (SCR-SPIRE-1640).
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Exec_BsmPcalFlash {
    int c_start = 0x1000; // RAW chop target start position
    int c_end = 0xf000; // RAW chop target end position
    int c_step = 0x2000; // RAW chop target step in position
    int jiggPosn = 0x9a60; // Jiggle position used. 
    int mclkdiv = 0x95; //Default (IST) bias freq (== 130.20833 Hz)
    int biasdiv = 0x6; //Default (IST) sampling freq (== 18.60119 Hz)
    int vmId = 70; // Raw VM table number [Dec(Hex)]
    int vmIndex = 0; // Raw VM index [Dec(Hex)]
    int nParms = 9; // Number of parameters passed to VM
    bool fts = false; // FTS or photometer (tick==FTS, needed for dcumode)
    bool debug = true; //Print-out debug statements (tick==Yes)? 
}{
    // //
    // //
    // Predefine version in SpireTable_PcalCurrentConvCoef.txt:
    //
    string ver_a = "v01";
    if(debug) {
        debug_print("The nominal version in SpireTable_PcalCurrentConvCoef.txt is v01");
    }
    // //
    // //
    // Hardcoded parameter:
    //
    bool dcuData = false;
    // Is (==tick) the DCU currently sampled? 
    // //
    // //
    // Retrieve PCAL bias calibration coefficients:
    //
    double[] coeff = [0.0];
    coeff[0] = dlookup("SpireTable_PcalCurrentConvCoef.txt",ver_a,"c_0");
    coeff[1] = dlookup("SpireTable_PcalCurrentConvCoef.txt",ver_a,"c_1");
    // //
    // //
    // Set ILT standard values for PCAL flash:
    //
    // Period of cycle in microsec:
    int flashperiod = 4000000;
    // Period of cycle in millisec:
    int period = flashperiod / 1000;
    // Number of cycles:
    int ncycles = 15;
    // DCU data mode:
    if(fts) {
        int ndcumode = 4;
        // DCU data mode (4 == Full spectrometer)
    } else {
        ndcumode = 0;
        // DCU data mode (0 == Full photometer)
    }
    // SCU sampling rate (f =80Hz/(1+scumode)):
    int scumode = 0;
    // //
    // //
    // Calculate the RAW bias levels:
    //
    //[mA] Low Level for 1st PCAL flash:
    double lowbias_0 = 0.0;
    //[mA] High Level for 1st PCAL flash:
    double highbias_0 = 0.0;
    if(fts) {
        highbias_0 = 4.8;
    } else {
        highbias_0 = 3.8;
    }
    //[mA] Low Level for 2nd PCAL flash:
    double lowbias_1 = 0.0;
    //[mA] High Level for 2nd PCAL flash:
    double highbias_1 = 0.0;
    if(fts) {
        highbias_1 = 4.8;
    } else {
        highbias_1 = 6.0;
    }
    //
    int pcal_low_bias_0 = iround((lowbias_0 * 0.0010 - coeff[0]) / coeff[1]);
    int pcal_high_bias_0 = iround((highbias_0 * 0.0010 - coeff[0]) / coeff[1]);
    int pcal_low_bias_1 = iround((lowbias_1 * 0.0010 - coeff[0]) / coeff[1]);
    int pcal_high_bias_1 = iround((highbias_1 * 0.0010 - coeff[0]) / coeff[1]);
    // //
    // //
    // Deduce number of DCU samples, SCU samples and DCU sample delay based on mclkdiv and biasdiv:
    //
    int[] flash_params = SpireProc_CalcParam_PcalFlash(period,mclkdiv,biasdiv,debug);
    int dcusamples = flash_params[0];
    int scusamples = flash_params[1];
    int dcudelay = flash_params[2];
    if(debug) {
        debug_print("//////////////////////////////////////////////////////////////");
        debug_print("");
        debug_print("CALCULATED DCU SAMPLES : " + dcusamples);
        debug_print("CALCULATED SCU SAMPLES : " + scusamples);
        debug_print("CALCULATED  SAMP DELAY : " + dcudelay + "microsec");
        debug_print("");
        debug_print("//////////////////////////////////////////////////////////");
    }
    // //
    // //
    // Execute the BSM/Flash loop:
    //
    // Calculate number of steps: 
    int n_steps = (c_end - c_start) / c_step;
    // Define chop position:
    int chop_posn = 0;
    // Start loop:
    for(int i = 0 .. n_steps) {
        // //
        // //
        // Set STEP:
        //
        int obsStep = i + 1;
        // NHK Step parameter 
        if(obsStep == 1) {
            if(debug) {
                debug_print("First obsStep already set during slew");
            }
        } else {
            SpireBb_SetObsStep(obsStep,debug);
        }
        // //
        // //
        // Set BSM to position:
        //
        chop_posn = c_start + c_step * i;
        SpireBb_BsmMove(chop_posn,jiggPosn,debug);
        // //
        // //
        // Set detector offsets:
        //
        SpireBb_PhotOffsetAuto(debug);
        // //
        // //
        // Execute PCAL flashes:
        //
        // First PCAL Flash: 
        // 
        SpireBb_PcalFlash(vmId,vmIndex,nParms,pcal_low_bias_0,pcal_high_bias_0,ncycles,flashperiod,ndcumode,dcusamples,dcudelay,scumode,scusamples,obsStep,debug);
        //
        // Second PCAL Flash: 
        //
        SpireBb_PcalFlash(vmId,vmIndex,nParms,pcal_low_bias_1,pcal_high_bias_1,ncycles,flashperiod,ndcumode,dcusamples,dcudelay,scumode,scusamples,obsStep,debug);
        // //
        // //
        // Printing: 
        //
        if(debug) {
            debug_print("BSM position " + chop_posn + " done.");
        }
    }
    //
    //
}

// CVS comments  : $Id: PacsMessageCenter.txt,v 1.3 2007/04/25 15:14:04 dcesarsk Exp $ 
// Purpose       : 
//
// CUS author    : 
// Script file   : PacsMessageCenter.txt 
//
// Input arguments
// type    name         description
//
// Return values
// Type          Description
//
// Description   : 
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : 
// 
// History       : 0.1  2-Sep-2005 DAC
// 13-oct-2005 Try different HTML directives
procedure PacsMessageCenter {
    string who = "From where"; // who issues the message(s)
    int nbRows = 0; // number of rows
    string[] msgLine = ["Line1"]; // one line of text
}{
    // No empty messages!
    if(nbRows > 0) {
        message("<h2> " + who + " </h2>");
        //     message(" ");
        for(int rows = 0 .. nbRows - 1) {
            //        message("<p> " + msgLine[rows] + "</p>");
            message(msgLine[rows]);
        }
    }
}

//CLName: SpireBb_LoadTableJM07b
//VMVersion: 2.8
//CLVersion: 1.0
//CLCVSId: $ID$
//TableId: 0x38
//TableLength: 0x10
//Date: 090814140315
// 
// 2009/08/15: MP (SPR-SPIRE-1752) Changed wrong table entries.
//
block SpireBb_LoadTableJM07b SPIRE 3359 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableJm07b started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //
    //set table command call for table id 0x38
    Spire_SET_TABLE(0x38,0x10);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x38,0x0,16,[{0x9a026a90},{0x9a026a90},{0x92ce6a90},{0x92ce6a90},{0x96686750},{0x96686750},{0x9d9b6750},{0x9d9b6750},{0xa1356a90},{0xa1356a90},{0x9d9b6dcf},{0x9d9b6dcf},{0x96686dcf},{0x96686dcf},{0x9a026a90},{0x9a026a90}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x38,0x0,0x0);
    delay(4);
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableJM07b ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

// SpireBbSOF2Init
//
// $Id:$
//
// Building Block to initialise the instrument for SOF2 operation
//
// The complete instrument setup operation is divided into two parts:
//   Configuration: actions that can be executed during the slew to the start
//          position of the S/C pointing mode.
//   Initialisation: actions that must be carried out at the S/C intial pointing
//          position before any observational operations are executed.   
//
// This building Block implements the second part of the setup 
// 
// 04 November 2008: 
//         added data_rate commands
//         added commands to setup the detector sampling
// 14/09/2009 KJK:
//         SCR Spire-1953: updated to take smodeVersion as input parameter
//                                   uses this to set phases
//  24/09/2009 KJK: SPR Spire-1978: 
//         remove setting of phases, as these are already setup in Config
//  29/09/2099 MP: SPR-SPIRE-2048
//         Script needs to take isBright as input to pass mode on. 
// 31/03/2010 KJK: SCR-SPIRE_2459:
//         Replace commands with SpireProc_Set_SpecDetOffsets
// 
/////////////////////////////////////////////////////////////////////////////
block SpireBbSOF2Init SPIRE 8385 {
    string smodeVersion = "v00";
    bool isBright = false;
    bool debug = false;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SOF2 Initialisation started");
    SpireMsg(2,"          $Id:$");
    //
    // ..... configuration .....
    //
    int cmd = 0x0;
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP  to On Target
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x8000)");
    Spire_SET_OBS_STEP_RAW(0x8000);
    //
    // set offsets
    //
    if(!isBright) {
        SpireProc_Set_SpecDetOffsets(debug);
    }
    //
    //  set up detectors for operations
    //
    if(isBright) {
        SpireConfigDcuData("Scan_b");
    } else {
        SpireConfigDcuData("Scan");
    }
    sync();
    //
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SOF2 Initialisation ended");
    SpireMsg(1,"  ..SOF2 Initialisation (" + (time() - t) + " seconds)");
}

// SpireMsg 
//
// $id$
//
// Output a string as a message and optionally as a debug string
//
// This procedure allows message strings to be output to the debug_print
//  stream as well as the message stream. This allows the developer to 
// see messages even if the calling procedure stops or crashes before
// it ends
// 
procedure SpireMsg {
    int level = 0 in [0,5]; // message level
    string msg = "";
}{
    int debugLevel = -1;
    // debug level - all messages with a level <= to this are out put to the debug_print stream
    //
    // output message
    message("" + level + msg);
    //
    // output debug string, if required
    if(level <= debugLevel) {
        debug_print(msg);
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SetObsMode.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set NHK MODE parameter
//
///////////////////////////////////////////////////////////////////////////
//
// K. King:
// 17/02/2010 KJK: Initial version (Spire-2391)
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SetObsMode SPIRE 3418 {
    string obsMode = "REDY"; // name of the  mode
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    message("4    " + time() + ": SpireBb_SetObsMode started");
    message("4          $Id: $");
    // //
    // //
    // Set ObsMode:
    //
    SpireSetObsMode(obsMode);
    // //
    // //
    // End BB:
    //
    SpireMsg(4,"    " + time() + ": BB SpireBbSetObsMode ended");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id:$
///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_Cal_JfetVssTestC.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'CoP: Phot Jfet Vss Test C' 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/05/21 V0.1: Initial version adapted from Mode_ILT_PERF_VSS_PC
//                  (undated, as of 2009/05/21 in fs2_test@lichfield by SDS)
// 2009/06/05 V1.0: Hardcode STBY 'v00' in EndBB (SPR-1477)
//
// S.D.Sidher:
// 2010/01/14 V1.1: Updated for routine phase calibration (see SPIRE SCR-2297)
//                  It calls modified detector switch-on and switch-off scripts
//                  Added BB to set detector sampling back for REDY mode
//                  Added BBs for setting NHK rate at start and end
//                  Removed call to BB SpireBb_StartBsmPidTuning (not needed)
//                  Removed Chop, Jiggle and SMEC references
//                  Pointing boolean set to false
//                  Removed all references to Pointing in the script (but leaving the inputs to the script)
//                  Revised Vss start and end values (see SPIRE SCR-2297)
//
// 
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in PHOTSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for all three arrays and could be taken from following cal table: 
//  SpireTable_PhotModeParams.txt 
//
//  3) Further mode dependent parameters can be read from:
//  SpireTable_CommonModeParams.txt           
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhoto_Cal_JfetVssTestC {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; //NAIF identifier: put '0' to use RA/DEC, or correct 'NAIFID'
    bool pointing = false; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick) (currently not in use)? 
    /* */
    bool isBright = false; // Use settings for bright source (==tick) (currently not in use)
    double jfet_Vss_start = -0.5; //Starting JFET source voltage
    double jfet_Vss_end = -3.0; //ending JFET source voltage
    double jfet_Vss_step = -0.1; //stepping JFET source volatge
    int ftime = 60; //wait time at each level;
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version05 = "v00"; // Version in cal table SpireTable_OpsParms 
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = "v00"; // detVersion
    string pString2 = "v00"; // vssVersion
    int pInt1 = 0; // Default jfet heater voltage at switch on
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Check for is bright setting: 
    //
    if(isBright) {
        isBright = false;
        error("IsBright does not make sense here. Try again!");
    }
    // //
    // //
    // Declare some variable:
    //
    // FTS or photometer:
    bool fts = false;
    // Photometer or FTS 
    bool phot = !fts;
    //
    string version = "";
    string tabName = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    int frate = 0;
    int tinithold = 0;
    bool setFramerate = true;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    //
    //
    // //
    // //
    // JFET heater and detector settings (as specified by user)
    int jfet_heater_V = pInt1;
    string detVersion = pString1;
    string vssVersion = pString2;
    //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS16";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for setup and datarates:  
    string obsMode = "PEngCalObs";
    // Note: datarates are currently only maximum values
    // //
    // //
    // // // // // // // // // // // // // // // // 
    // // // // // // // // // // // // // // // //
    //
    int tp = duration(SpireBb_StartJfetVssTestC(phot,obsModeQla,obsMode,isBright,version01,version02,debug)) + duration(SpireBbSetNhkSampling("PHTSTBY","v00",debug)) + duration(SpireBb_CalPdetOn(jfet_heater_V,detVersion,vssVersion,debug));
    tp = tp + duration(SpireBb_PhotJfetVssTestC(jfet_Vss_start,jfet_Vss_end,jfet_Vss_step,ftime,debug));
    tp = tp + duration(SpireBb_CalPdetOff());
    tp = tp + duration(SpireBbSetDetSampling("REDY",true,detVersion,false,debug)) + duration(SpireBbSetNhkSampling("REDY","v00",debug));
    tp = tp + duration(SpireBb_EndJfetVssTestC(phot,isBright,version01,version02,debug));
    //
    // Debug printing?:
    if(debug) {
        debug_print("duration = " + tp);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // Lookup boresight:
    // 
    tabName = tabName05;
    string selCol = "mode";
    string selVal = obsMode;
    string tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    //
    int[] ts = no_pointing(true,0,0,tp);
    //
    //
}{
    // ******************************************************* */
    // POINTING STATES WITH OBSERVING MODE LOGIC AND DATARATES */
    // ******************************************************* */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            // //
            // //
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            //
            // Startup observation: 
            //
            SpireBb_StartJfetVssTestC(phot,obsModeQla,obsMode,isBright,version01,version02,debug);
            //
            // set nominal housekeeping rate
            SpireBbSetNhkSampling("PHTSTBY","v00",debug);
            // // 
            // //
            // //
            // Switch on Photometer detectors
            SpireBb_CalPdetOn(jfet_heater_V,detVersion,vssVersion,debug);
            // //
            // //
            // //
            // Execute JFET VSS Test C:
            //
            SpireBb_PhotJfetVssTestC(jfet_Vss_start,jfet_Vss_end,jfet_Vss_step,ftime,debug);
            //
            //delay(tp);
            //
            // Switch off Photometer detectors
            SpireBb_CalPdetOff();
            //
            // setup detector sampling for REDY mode
            SpireBbSetDetSampling("REDY",true,detVersion,false,debug);
            //
            // set REDY mode nominal housekeeping rate
            SpireBbSetNhkSampling("REDY","v00",debug);
            // // 
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            //
            SpireBb_EndJfetVssTestC(phot,isBright,version01,version02,debug);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

// SpireNullObsid
//
// $Id: SpireNullObsid.txt,v 1.1 2006/08/10 09:38:58 kking Exp $
//
// A procedure to return the value of the null OBSID for this observation. 
//   This entails taking the current OBSID and zeroing the lowest 28 bits
//   leaving the location bits in place.
//
//
int procedure SpireNullObsid {
}{
    message("4    " + time() + ": NuLL_OBSID started");
    message("4          $Id: SpireNullObsid.txt,v 1.1 2006/08/10 09:38:58 kking Exp $");
    message("3               OBSID = " + $OBSID);
    //
    int obsId = $OBSID & 0xf0000000;
    //
    message("3          SpireNullObsid = " + obsId);
    message("4    " + time() + ": SpireNullObsid ended");
    //

    return obsId;
}

// CVS comments  : $Id: PacsPhotNoiseRMS.txt,v 1.6 2007/04/25 15:14:04 dcesarsk Exp $ 
// CVS file      : PacsPhotNoiseRMS.txt
//
// Purpose       : Returns minimum detectable flux [mJy] for S/N=1
//
// Author        : Diego A. Cesarsky
// CUS script    : DAC
//
// Arguments     : pointCase
//                 filterID
//                 time_on
//
// Description   : Noise computation based on sensitivity for time_on = 1 [sec]
//
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : Based on D. Lutz's "Guesstimator.pro"
//                 Newer version based on Alpog's 22-may-2006 e-mail
//
// Version       : 0.1  6-Dec-2004 Creation by DAC
// History       : 0.2  4-sep-2006 
// - Use new PHOTnoise table (based on alpog's e-mail 22-may-2006).
// - Accept PointCase (may need it for SRC,REF considerations)
//                 0.3 10-oct-2006 SPR-2378
// - the factors sqrt(2) in point source and scan map mode
//   and and 1/sqrt(2) in small and large raster shall be removed, 
//   as these factors are already taken into account in the values provided 
//   by Albrecht Poglitsch (photometer_noise.txt) to account for (chopped) 
//   background subtraction, where TIME is the pure "science time"
//  1.0  3-nov-2006 Compute also extended source RMS reading updated
//                  PHOTnoise CAL-U table; module returns now 4 values:
//                  rms[0], rms[1] : point source BLU and RED
//                  rms[2], rms[3] : extended source BLU and RED
//               :
double[] procedure PacsPhotNoiseRMS {
    int pointCase = 21; // The PointCase code of PacsPhoto
    string filter = "blue1" in ["blue1","blue2"]; // Filter ID
    double intTIME = 1.0; // ON source time [sec] 
}{
    // Sensitivity [Jy] per filter, i.e. flux for which S/N=1 is obtained in 1 sec 
    // assuming the source is always seen on the detector (excludes the noise 
    // from 'off' subtraction)
    string calU = "PHOTnoise";
    // Point Source. Here the SRC is always in view
    if(pointCase == 11 || pointCase == 12) {
        double sensRED = dlookup(calU,"red","point");
        double sensBLU = dlookup(calU,filter,"point");
        //    Compute "noise" after intTIME [sec] of integration [mJy]
        double pntRMSred = 1000.0 * sensRED / sqrt(intTIME);
        double pntRMSblu = 1000.0 * sensBLU / sqrt(intTIME);
        double extRMSred = 0.0;
        double extRMSblu = 0.0;
    }
    // Small source or raster map. Here the SRC is in view 1/2 time
    if(pointCase == 21 || pointCase == 22 || pointCase == 31 || pointCase == 32) {
        //    Point source
        sensRED = dlookup(calU,"red","small");
        sensBLU = dlookup(calU,filter,"small");
        //    Extended source
        double extsensRED = dlookup(calU,"red","EXTsmall");
        double extsensBLU = dlookup(calU,filter,"EXTsmall");
        //    Compute "noise" after intTIME [sec] of integration [mJy]
        pntRMSred = 1000.0 * sensRED / sqrt(intTIME);
        pntRMSblu = 1000.0 * sensBLU / sqrt(intTIME);
        extRMSred = extsensRED / sqrt(intTIME);
        extRMSblu = extsensBLU / sqrt(intTIME);
    }
    // Scan mode. Here the SRC is always in view
    if(pointCase == 33) {
        //    Point source     
        sensRED = dlookup(calU,"red","scan");
        sensBLU = dlookup(calU,filter,"scan");
        //    Extended source
        extsensRED = dlookup(calU,"red","EXTscan");
        extsensBLU = dlookup(calU,filter,"EXTscan");
        //    Compute "noise" after intTIME [sec] of integration [mJy]
        pntRMSred = 1000.0 * sensRED / sqrt(intTIME);
        pntRMSblu = 1000.0 * sensBLU / sqrt(intTIME);
        extRMSred = extsensRED / sqrt(intTIME);
        extRMSblu = extsensBLU / sqrt(intTIME);
    }

    return [pntRMSred,pntRMSblu,extRMSred,extRMSblu];
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_PhotDataRates.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to retrive the datarate from the associated calibration table 
//  for a given photometer mode. 
// 
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/15 V1.0: Initial version adapted from
//                  SpireProc_CalcParam_Datarates (2009/01/26 V1.0)
// 2009/05/05 V1.1: Change calibration table where HK are read. 
//                  
///////////////////////////////////////////////////////////////////////////
//
double procedure SpireProc_CalcParam_PhotDataRates {
    string rateType = "chk" in ["chk","nhk","sci"]; // Data rate to be read 
    string obsMode = "POF2"; // Parameter to specify the configuration mode
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variable:
    //
    double rate = 0.0;
    // Name of column for selecting: 
    string selCol = "mode";
    // Value of 'string' selector: 
    string selVal = obsMode;
    // Target column name:
    string tarCol = "";
    string version = "";
    //
    // Hardcoded calibration tables: 
    //
    string tabName = "";
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_DefaultParams.txt";
    //
    // Hardcoded version + mode name: 
    //
    string version03 = "v00";
    // Version in cal table SpireTable_DefaultParams 
    string selValHk = "PHTSTBY";
    // //
    // //
    // Select and set rate:
    //
    if(rateType == "chk") {
        tabName = tabName03;
        version = version03;
        tarCol = "chkDataRate";
        double chkrate = SpireProc_GetTableEntryDouble(tabName,selCol,selValHk,tarCol,version,debug);
        rate = chkrate;
    }
    //
    if(rateType == "nhk") {
        tabName = tabName03;
        version = version03;
        tarCol = "nhkDataRate";
        double nhkrate = SpireProc_GetTableEntryDouble(tabName,selCol,selValHk,tarCol,version,debug);
        rate = nhkrate;
    }
    //
    if(rateType == "sci") {
        string[] tarColSci = ["dcuDataRate","bsmDataRate","scuDataRate","dpuDataRate"];
        double scirate = 0.0;
        double scirate2add = 0.0;
        for(int i = 1 .. 4) {
            tarCol = tarColSci[i - 1];
            if(tarCol == "dcuDataRate") {
                tabName = tabName01;
                version = version01;
            } else {
                tabName = tabName02;
                version = version02;
            }
            scirate2add = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
            scirate = scirate + scirate2add;
            if(debug) {
                debug_print("Reading target column " + tarCol + " with scirate " + scirate2add);
                debug_print("The new scirate is: " + scirate);
            }
        }
        rate = scirate;
    }
    // //
    // //
    // Return required rate:
    //
    if(debug) {
        debug_print("The " + rateType + " rate is: " + rate + " [kbps]");
    }

    return rate;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_RepTabAndMemChecksum.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to report tables and memory checksums
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/06/24 V0.1: Initial version following SPIRE-SCR-1527
//
// S.D.Sidher
// 2009/11/26 V0.2: Updated version after upload of OBS 4.0.0
//                              Modified address ranges for PM checksum calculations 
//                              See SPIRE-SCR-2212
//                              Other relevant SXRs: SPIRE-SCR-2127 and SPIRE-SCR-2144
//                              Now also reporting tables 55-57, 73-75
// S.D.Sidher
// 2010/08/11 V0.3: Updated to report only the static sections of the BSMMove, REDY, SMEC, SCAL, and PTC VM tables
//                  See SPIRE-SCR-2761 
//
// S.D.Sidher V0.4: Updated to report the new SM02 table (Table ID 58) SPIRE-SCR-3622
//                  Updated to only report the static section of CREC VM table (Table ID 83) SPIRE-SCR-3624                  
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_RepTabAndMemChecksum SPIRE 14073 {
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_RepTabAndMemChecksum started");
    SpireMsg(2,"          $Id:$");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Report on all the updated tables, including the HK report:
    //
    //
    Spire_REPORT_TABLE(0,0,0);
    delay(2);
    Spire_REPORT_TABLE(1,0,0);
    delay(4);
    Spire_REPORT_TABLE(5,0,0);
    delay(6);
    Spire_REPORT_TABLE(10,0,0);
    delay(2);
    //
    Spire_REPORT_TABLE(50,0,0);
    delay(2);
    Spire_REPORT_TABLE(51,0,0);
    delay(2);
    Spire_REPORT_TABLE(52,0,0);
    delay(2);
    Spire_REPORT_TABLE(53,0,0);
    delay(2);
    Spire_REPORT_TABLE(54,0,0);
    delay(2);
    //
    Spire_REPORT_TABLE(55,0,0);
    delay(2);
    //
    Spire_REPORT_TABLE(56,0,0);
    delay(2);
    //
    Spire_REPORT_TABLE(57,0,0);
    delay(2);
    //
    Spire_REPORT_TABLE(58,0,0);
    delay(2);
    //
    Spire_REPORT_TABLE(60,0,0);
    delay(4);
    Spire_REPORT_TABLE(61,0,27);
    delay(2);
    //
    Spire_REPORT_TABLE(70,0,0);
    delay(4);
    Spire_REPORT_TABLE(71,0,0);
    delay(2);
    Spire_REPORT_TABLE(72,0,0);
    delay(4);
    Spire_REPORT_TABLE(73,0,35);
    delay(4);
    //
    Spire_REPORT_TABLE(74,0,0);
    delay(4);
    //
    Spire_REPORT_TABLE(75,0,130);
    delay(2);
    Spire_REPORT_TABLE(75,132,117);
    delay(2);
    //
    Spire_REPORT_TABLE(80,0,387);
    delay(4);
    Spire_REPORT_TABLE(81,0,435);
    delay(4);
    Spire_REPORT_TABLE(82,0,0);
    delay(4);
    Spire_REPORT_TABLE(83,0,383);
    delay(4);
    Spire_REPORT_TABLE(100,0,0);
    delay(4);
    //
    Spire_REPORT_TABLE(102,0,0);
    delay(4);
    Spire_REPORT_TABLE(103,0,0);
    delay(4);
    Spire_REPORT_TABLE(212,0,0);
    delay(4);
    Spire_REPORT_TABLE(213,0,0);
    delay(4);
    // //
    // //
    // Do checksum:
    //
    Spire_CHECK_MEMORY("Program Memory",0x4000,0x174b);
    delay(2);
    //
    Spire_CHECK_MEMORY("Program Memory",0x6000,0xffff);
    delay(2);
    //
    Spire_CHECK_MEMORY("Program Memory",0x15fff,0x59);
    delay(2);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_RepTabAndMemChecksum ended");
    SpireMsg(1,"  ..RepTabAndMemChecksum End (" + (time() - t) + " seconds)");
}

/// $Id: SpireEngParallelCoolerRecycle.txt,v 1.1 2008/02/06 14:59:25 dcesarsk Exp $
//
// Missionphase  : FM RMS
//
// Purpose       : Pacs/Spire cooler recycling as an OBS
//                 
// Author        : Diego A. Cesarsky
//
// Arguments     : None
//
// Description   : Merge of Spire's and PACS cooler recycling scripts
//
// Dependencies  : SpirePacsCoolerRecycle 
//
// Comments      : Renamed SpireEng from PacsEng script to avoid PACS
//                 depending on SPIRE
//
// Version       : 0.1 
// History        : 0.1  16-jan-2008 DAC Rename from
//                                  PacsEng_PacsSpire_cool_recycle
//                     0.2   6-feb-2008 DAC Renamed to
//                                  SpireEngParallelCoolerRecycle.txt 
//                                  Renamed called procedure to
//                                  SpireParallelCoolerRecycle
//	  0.3 14-nov-2008 VD include CcuMonitor for MOC
//                            17-Nov-2008 KJK included setting/resetting of SPIRE OBSID before/after setting CCU Monitoring
//
obs SpireEngParallelCoolerRecycle {
}{
    bool execute = true;
    int tobsId = duration(WriteOBSID($OBSID)) + duration(SpireBbStartObs());
    int tCcu = duration(Pacs_CcuMonitorStartRecycle());
    int tih = tobsId + tCcu;
    int tendId = duration(WriteEndID()) + duration(SpireBbEndObs());
    int tCcuDefault = duration(Pacs_CcuMonitorDefaultRecycle());
    int tfh = tendId + tCcuDefault;
    int tp = duration(SpireParallelCoolerRecycle());
    // Issue PointReq       
    int[] ts = no_pointing(execute,tih,tfh,tp);
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // ***********************  INITIAL HOLD          
            // set OBSID
            WriteOBSID($OBSID);
            SpireBbStartObs();
            Pacs_CcuMonitorStartRecycle();
        }
        if(state[0] == 3) {
            // ***********************  EXECUTE
            //     Call the cooler Block
            SpireParallelCoolerRecycle();
        }
        if(state[0] == 5) {
            // ***********************  FINAL HOLD
            Pacs_CcuMonitorDefaultRecycle();
            SpireBbEndObs();
            WriteEndID();
        }
    }
}

// SpireBbPdetOff
//
// $id$
//
// This building block switches off the photometer detectors
//
//  07/04/2009 KJK:
//          removed setting o fmode to REDY as this BB should leave the mode as PDET_OFF
// 
block SpireBbPdetOff SPIRE 1284 {
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB PdetOff started");
    SpireMsg(2,"          $Id: SpireBbPdetOff.txt,v 1.1 2007/08/02 10:15:58 kking Exp $");
    //
    int cmd = 0x0;
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // Set STEP to 0
    SpireSetObsStep(0x0);
    delay(1);
    //
    // Set MODE to PDET_OFF
    SpireSetObsMode("PDET_OFF");
    delay(1);
    //
    // Switch off TC Vdd and Vss
    //
    SpireSendDrcuCmd(0x8413003f,0);
    SpireSendDrcuCmd(0x84140000,0);
    delay(1);
    // 
    // Switch off  PSW VDD and VSS
    SpireSendDrcuCmd(0x84120000,0);
    for(int i = 0 .. 5) {
        SpireSendDrcuCmd(0x84050000 + 0x10000 * i,0);
        delay(1);
    }
    //
    // Switch off  PMW VDD and VSS
    SpireSendDrcuCmd(0x84130030,0);
    for(int j = 0 .. 3) {
        SpireSendDrcuCmd(0x840b0000 + 0x10000 * j,0);
        delay(1);
    }
    //
    // Switch off  PLW VDD and VSS
    SpireSendDrcuCmd(0x84130000,0);
    for(int k = 0 .. 1) {
        SpireSendDrcuCmd(0x840f0000 + 0x10000 * k,0);
    }
    delay(1);
    // 
    // Set DEMOD PHASE TO ZERO
    SpireSendDrcuCmd(0x841a0000,0);
    SpireSendDrcuCmd(0x841b0000,0);
    delay(1);
    SpireSendDrcuCmd(0x841c0000,0);
    SpireSendDrcuCmd(0x841d0000,0);
    delay(1);
    //
    // Set BIAS TO ZERO
    SpireSendDrcuCmd(0x84010000,0);
    SpireSendDrcuCmd(0x84020000,0);
    delay(1);
    SpireSendDrcuCmd(0x84030000,0);
    SpireSendDrcuCmd(0x84040000,0);
    delay(1);
    //
    // Switch OFF PLIAs 
    SpireSendDrcuCmd(0xa0870004,0);
    delay(1);
    //
    // completion
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB PdetOff   ended");
    SpireMsg(1,"  ..PDET Switch Off (" + (time() - t0) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_Cal_IltPcalFlash.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Spec ILT PCAL Flash' 
//
//  in *basic_fine_pointing* or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/15 V0.1: Initial version adapted from
//                  SpirePhoto_Cal_IltPcalFlash (2008/08/14 V0p5) 
//                  based on
//                  Mode_ILT_PERF_DAB_S_CPS.txt (v1.3 2008/01/31 23:35:17)
// 2008/11/11 V0.2: Allow 'no pointing' as input option; Adapt debug printing
// 2008/11/12 V0.3: Implement mode setting; Add isBright 
//                  Change 'no pointing' implementation
// 2009/02/19 V0.4: Add debug_print as input and pass it to some low 
//                  level scripts. Add setting of NHK STEP parameter
//                  in  SpireProc_Exec_IltPcalFlash and unset at end.   
//                  Use new SpireBb_EndObsAll and SpireBb_StartObsAll. 
//                  Implemented setting of datarates. Implemented message 
//                  if activating isBright setting. Remove cal table name 
//                  from input and hardcode. Replace call to 
//                  SpireBb_SpecFSetupData by call to SpireBb_DcuSetFreqSamp
//                  SpireBb_SpecFSetPhase and SpireBb_SpecFSetBiasAmpl. 
//                  Use SpireBb_SpecSetMode to set to SPECSTBY during SLEW 
//                  and FINAL_HOLD. Unset isBright if set. Read boresight 
//                  from SpireTable_OpsParms. Update call to 
//                  SpireProc_Exec_IltPcalFlash to include proper setting
//                  of FTS ILT Pcal highbias levels (bug detected at SDAG#19). 
// 2009/03/04 V0.5: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Change isBright behaviour.
//                  Use maxbias for amplitude and subtract isBright phase
//                  shift read from calibration file from the user input phase.
// 2009/05/06 V0.6: Add in move BSM/SMEC to hold/home at start. Add new 
//                  SpireBb_SmecHold to account for the fact that
//                  SpireBb_SmecMove2Home does not stop SMEC.
//                  Gather procedures at start and end in separate BB. 
//
// Caveat: isBright bias amplitude is hardcoded in script!
//
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in SPECSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Boresight of array can be read from following cal table:
//     SpireTable_OpsParms.txt  
//
//  3) Phase shift for isBright setting can be read from following
//     cal table: SpireTable_IsBrightPhaseShift.txt 
//
//  4) Needs additional procedure SpireProc_Exec_IltPcalFlash.txt and 
//     SpireProc_CalcParam_IltPcalFlash to execute ILT PCAL flash.  
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_Cal_IltPcalFlash {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; // NAIF identifier
    bool isBright = false; // Use settings for bright source (==tick)
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    double biasfreq = 160.09 in [80.0,240.0]; // Bias frequency [Hz]
    double samplerate = 80.05 in [1.0,80.5]; // Sampling rate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    double biasmV_ssw = 31.13 in [0.0,176.385]; // SSW Bias amplitude (peak2peak) [mV]
    double biasmV_slw = 31.13 in [0.0,176.417]; // SLW Bias amplitude (peak2peak) [mV]
    double phasedeg_ssw = 184.9 in [0.0,360.0]; // SSW Bias phase [deg]
    double phasedeg_slw = 190.6 in [0.0,360.0]; // SLW Bias phase [deg]
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version05 = "v00"; // Version in cal table SpireTable_OpsParms    
    string version06 = "v00"; // Version in cal table SpireTable_IsBrightPhaseShift
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // //
    // //
    // Check for is bright setting: 
    //
    if(isBright) {
        message("IsBright selected! SxW bias amplitude is unchanged but isBright phase-shift is subtracted.");
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = false;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string tarCol = "";
    string selVal = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    string tabName06 = "SpireTable_IsBrightPhaseShift.txt";
    string tabName09 = "SpireTable_SmecNominalSettings.txt";
    //
    // Currently hardcoded version and model parameter:
    //
    string version09 = "v00";
    // Version in cal table SpireTable_SmecNominalSettings
    string version03 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    //
    // Dummy value for Phot script:
    // (needed but not used in spec script!)
    //
    int bias_psw = 62;
    //
    int bias_pmw = 62;
    //
    int bias_plw = 62;
    //
    int bias_ptc = 62;
    //
    int phase_psw = 127;
    //
    int phase_pmw = 127;
    //
    int phase_plw = 127;
    //
    int phase_ptc = 127;
    //
    //
    // Currently hardcoded parameter:
    // Is (==tick) the DCU currently sampled? 
    bool dcuData = false;
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS36";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "SEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Read isBright phase shift from calibration table:
    //
    int specPhaseShift = ilookup(tabName06,version06,"specPhaseShift");
    // //
    // //
    // Convert user input to Hex values:
    //
    // for bias frequency and sample rate: 
    //
    int[] hexvalues = SpireProc_CalcParam_BiasFreqSampFreq(biasfreq,samplerate,fts,debug);
    int mclkdiv = hexvalues[0];
    int biasdiv = hexvalues[1];
    if(debug) {
        debug_print("Hex values of mclkdiv/biasdiv are: " + mclkdiv + " " + biasdiv);
    }
    //
    // for bias phase:
    //
    int[] phasehex = SpireProc_CalcParam_SpecPhaseConvert(phasedeg_ssw,phasedeg_slw,debug);
    int phase_ssw = phasehex[0];
    int phase_slw = phasehex[1];
    if(isBright) {
        phase_ssw = SpireProc_CalcParam_IsBrightPhaseShift(phase_ssw,specPhaseShift,debug);
        phase_slw = SpireProc_CalcParam_IsBrightPhaseShift(phase_slw,specPhaseShift,debug);
    }
    //
    // for bias amplitude:
    //
    int[] biashex = SpireProc_CalcParam_SpecBiasConvert(biasmV_ssw,biasmV_slw,debug);
    int bias_ssw = biashex[0];
    int bias_slw = biashex[1];
    // //
    // //
    // Set PCAL Flash values to the once fixed used during ILT: 
    //
    int period = 4000000;
    //PCAL Flash FULL period (high and low bias) [microsec]
    int ndcumode = 4;
    // DCU data mode (0 == PF; 4 == SF)
    // //
    // //
    // Read SMEC home position from calibration file:
    //
    tarCol = "Home";
    tabName = tabName09;
    selVal = version09;
    int smecHomePosn = ilookup(tabName,selVal,tarCol);
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version03;
    tabName = tabName03;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartIltPcalFlash(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,bias_psw,bias_pmw,bias_plw,bias_ptc,phase_psw,phase_pmw,phase_plw,phase_ptc,bias_ssw,bias_slw,phase_ssw,phase_slw,debug));
    // 
    // BBs carried out when the pointing is reached:
    if(pointing) {
        int tinithold = duration(SpireBb_SpecOffsetAuto(dcuData,debug));
    } else {
        tinithold = duration(SpireBb_SpecOffsetAuto(dcuData,debug)) + tslewmin;
    }
    //
    // BB carried out during pointing:
    int tp = duration(SpireProc_Exec_IltPcalFlash(period,mclkdiv,biasdiv,ndcumode,phot,debug));
    //
    // BB carried out at the end:
    int tfinalhold = duration(SpireBb_EndIltPcalFlash(phot,isBright,version01,version02,debug));
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                              */
    // ****************************************************** */
    // //
    // //
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartIltPcalFlash(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,bias_psw,bias_pmw,bias_plw,bias_ptc,phase_psw,phase_pmw,phase_plw,phase_ptc,bias_ssw,bias_slw,phase_ssw,phase_slw,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation:
                //
                SpireBb_StartIltPcalFlash(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,bias_psw,bias_pmw,bias_plw,bias_ptc,phase_psw,phase_pmw,phase_plw,phase_ptc,bias_ssw,bias_slw,phase_ssw,phase_slw,debug);
                // 
            }
            // //
            // //
            // Set offsets: 
            //
            SpireBb_SpecOffsetAuto(dcuData,debug);
            //
            //
            //delay(tinithold);
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            //delay(tp);
            //
            // //
            // //
            // Execute ILT PCAL flashes:
            //
            SpireProc_Exec_IltPcalFlash(period,mclkdiv,biasdiv,ndcumode,phot,debug);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activities )
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            SpireBb_EndIltPcalFlash(phot,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

// SpireREDYtoSMEC_INIT
//
// $id$
//
// This procedure configures the instrument into the SMEC_INIT mode
// 
// The instrument should be in the REDY mode before execution of this observation
//
// This procedure is for initial testing of the new Smec Init procedure during PV Phase
//
// 28/08/2009 TWG:  first version
// 20/10/2009 KJK:  added bsmVersion= "v00" in call to SpireBbSmecInit
//
procedure SpireREDYtoSMEC_INIT {
    int smecWait = 30; // Wait time after switch-on of SMEC [s]
    string smecVersion = "v00";
    bool debug = false;
}{
    string res = "H";
    string  bsmVersion = "v00";
    string specVersion = "v00";
    // set nominal housekeeping rate
    SpireBbSetNhkSampling("SPECSTBY","v00",debug);
    // // 
    //
    // -------------
    // configure SMEC
    // -------------
    //
    // switch on SMEC
    mois_comment("Procedure SPIRE_SMEC_ON: to switch on the SPIRE SMEC");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    mois_tmcheck("Check that parameter SMECENCPWR is set to 0");
    mois_tmcheck("Check that parameter SMECLVDTPWR is set to 0");
    SpireBbSmecOn(smecVersion,debug);
    mois_tmcheck("Check that parameter SMECENCPWR is set to 1");
    mois_tmcheck("Check that parameter SMECLVDTPWR is set to 1");
    mois_tmcheck("Check that parameter MODE is set to SMEC_ON");
    // //
    // //
    // Wait time after SMEC on before SMEC initialisation:
    //
    delay(smecWait);
    //
    // initialise SMEC
    mois_comment("Procedure SPIRE_SMEC_INIT: to initialise the SPIRE SMEC");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    SpireBbSmecInit(res,bsmVersion,smecVersion,specVersion,debug);
    mois_tmcheck("Check that parameter MODE is set to SMEC_INIT");
    //
    //
    // Setup SMEC sampling
    SpireBbSetSmecSampling("SPECSTBY",smecVersion,debug);
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
//
// SpireProc_Exec_SpecNonLinearity.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to do the 'Spec NonLinearity' (SCR-SPIRE-2038)
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/11/23 V0.1: Initial version adapted from 
//                  SpireProc_Exec_SpecStdLoadCurve (2009/02/19 V0.2)
// 2009/12/14 V0.2: Move SMEC to home before 1.PCAL flash. Added setup SMEC Scan
//                  before PCAL on.
//
///////////////////////////////////////////////////////////////////////////
procedure SpireProc_Exec_SpecNonLinearity {
    bool dcuData = false; // Is (==tick) the DCU currently sampled? 
    string flashMode = "SFlash";
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParam
    int id = 0x46; // SpireBb_PcalFlash parameter
    int index = 0; // SpireBb_PcalFlash parameter
    int nParms = 9; // SpireBb_PcalFlash parameter
    int lowBias = 100; // SpireBb_PcalFlash parameter
    int highBias = 2000; // SpireBb_PcalFlash parameter
    int cycles = 8; // SpireBb_PcalFlash parameter
    int period = 250000; // SpireBb_PcalFlash parameter
    int dcuMode = 3; // SpireBb_PcalFlash parameter
    int dcuSamples = 11; // SpireBb_PcalFlash parameter
    int dcuDelay = 12000; // SpireBb_PcalFlash parameter
    int scuMode = 0; // SpireBb_PcalFlash parameter
    int scuSamples = 9; // SpireBb_PcalFlash parameter
    int smecFrate = 149; // Specifies the frame rate [Dec(Hex)]
    int scanStart = 5000; // 
    int smecHomePosn = 1000; // 
    string resolution = "L" in ["L","M","H","C"]; // Resolution (low, medium, high,calibration)
    string version05 = "v00"; // Version in cal table SpireTable_Spectrometer
    int nscans = 1; // Number of SMEC scans (back+forth==1)
    double pcal_bias = 3.8 in [0.0,7.0]; // PCAL bias level [mA]
    string version = "v01"; // Version in cal table SpireTable_PcalCurrentConvCoef
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    int step = 1;
    // Note: Start with 1, step 0 set in SmecInit
    // //
    // //
    // Set offsets at raster point:
    //
    SpireBb_SpecOffsetAuto(dcuData,debug);
    //
    //
    // SCR-SPIRE-2038: ii) PCAL flash
    //
    //
    // //
    // //
    // Move SMEC to HOME from scanStart (i.e. where it was left in SpireBbSmecInit
    //
    SpireBb_SmecMove(smecHomePosn,scanStart,debug);
    // //
    // //
    // Set BSM/SMEC sampling for flash:
    //
    SpireBbSetBsmSampling(flashMode,version02,debug);
    SpireBbSetSmecSampling(flashMode,version01,debug);
    // //
    // //
    // Do AOT PCAL flash:
    //
    SpireBb_PcalFlash(id,index,nParms,lowBias,highBias,cycles,period,dcuMode,dcuSamples,dcuDelay,scuMode,scuSamples,step,debug);
    step = step + 1;
    // //
    // //
    // Reset BSM to STBY:
    //
    SpireBbSetBsmSampling("SPECSTBY","v00",debug);
    // //
    // //
    // Set SMEC framerate (== SMEC sampling rate) to input:
    //
    SpireBb_SetSmecFramerate(smecFrate,debug);
    //
    //
    // SCR-SPIRE-2038: iii) Take a medium resolution interferogram with 10 repeats at 250 um/s
    //
    //
    // //
    // //
    // Move SMEC to start of scan 
    //
    SpireBb_SmecMove(scanStart,smecHomePosn,debug);
    // //
    // //
    // Setup SMEC Scan:
    //
    SpireBb_SetupSmecScan(resolution,version05,debug);
    // //
    // //
    // Start DCU+MCU data generation:
    //
    SpireBb_StartDcuMcuData();
    // //
    // //
    // Perform SMEC scan:
    //
    SpireBb_SmecScan(resolution,nscans,version05,debug);
    // //
    // //
    // Stop DCU+MCU data generation:
    //
    SpireBb_StopDcuMcuData();
    //
    //
    // SCR-SPIRE-2038: iv) PCAL Flash
    //
    //
    // //
    // //
    // Move SMEC from start to home: 
    //
    SpireBb_SmecMove(smecHomePosn,scanStart,debug);
    // //
    // //
    // Set BSM/SMEC sampling for flash:
    //
    SpireBbSetBsmSampling(flashMode,version02,debug);
    SpireBbSetSmecSampling(flashMode,version01,debug);
    // //
    // //
    // Do AOT PCAL flash:
    //
    SpireBb_PcalFlash(id,index,nParms,lowBias,highBias,cycles,period,dcuMode,dcuSamples,dcuDelay,scuMode,scuSamples,step,debug);
    step = step + 1;
    // //
    // //
    // Reset BSM to STBY:
    //
    SpireBbSetBsmSampling("SPECSTBY","v00",debug);
    // //
    // //
    // Set SMEC framerate (== SMEC sampling rate) to input:
    //
    SpireBb_SetSmecFramerate(smecFrate,debug);
    // //
    // //
    // Move SMEC to start of scan 
    //
    SpireBb_SmecMove(scanStart,smecHomePosn,debug);
    // //
    // //
    // Setup SMEC Scan (to prepare the SMEC for next scan):
    //
    SpireBb_SetupSmecScan(resolution,version05,debug);
    //
    //
    // SCR-SPIRE-2038: v) Set PCAL to the AOT nominal current setting
    //
    //
    // //
    // //
    // Switch PCAL on at AOT current:
    //
    SpireBb_PcalOn(pcal_bias,version,debug);
    //
    //
    // SCR-SPIRE-2038: vi) Take a medium resolution interferogram with 10 repeats at 250 um/s
    //
    //
    // //
    // //
    // Start DCU+MCU data generation:
    //
    SpireBb_StartDcuMcuData();
    // //
    // //
    // Perform SMEC scan:
    //
    SpireBb_SmecScan(resolution,nscans,version05,debug);
    // //
    // //
    // Stop DCU+MCU data generation:
    //
    SpireBb_StopDcuMcuData();
    // //
    // //
    // Switch PCAL off:
    //
    SpireBb_PcalOn(0.0,version,debug);
    //
    //
    // SCR-SPIRE-2038: vii) PCAL Flash
    //
    //
    // //
    // //
    // Move SMEC from start to home: 
    //
    SpireBb_SmecMove(smecHomePosn,scanStart,debug);
    // //
    // //
    // Set BSM/SMEC sampling for flash:
    //
    SpireBbSetBsmSampling(flashMode,version02,debug);
    SpireBbSetSmecSampling(flashMode,version01,debug);
    // //
    // //
    // Do AOT PCAL flash:
    //
    SpireBb_PcalFlash(id,index,nParms,lowBias,highBias,cycles,period,dcuMode,dcuSamples,dcuDelay,scuMode,scuSamples,step,debug);
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_ScuFramerate.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Set SCU framerate (e.g. PCAL sampling rate) 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/15 V0.1: Initial version adapted from
//                  SpireProc_Set_BsmFramerate (2008/11/13 V0.1)
//                  Add HSpot printing to script. 
// 2009/06/05 V0.2: Replace Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd 
//                  as requested in SPR-1482.
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_ScuFramerate {
    int frate = 0; // Specifies the SCU frame rate [Dec(Hex)]
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    string tstr = "";
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"     " + tstr + ":  SpireProc_Set_ScuFramerate started");
    SpireMsg(4,"          $Id:$");
    // //
    // //
    // Set framerate:
    //
    SpireSendDrcuCmd(0xa0830000 + frate,0);
    sync();
    //
    // //
    // //
    // Debug printing:
    //
    double frateHz = 80.0 / (1.0 + double(frate));
    if(debug) {
        debug_print("Set SCU framerate to " + frate + " [dec(Hex)]");
        debug_print("Set SCU framerate to " + frateHz + " [Hz]");
    }
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"      " + tstr + ": SpireProc_Set_ScuFramerate ended");
    //
}

// SpireBbSmecInit
//
// $id$
//
// This building block initialises the SMEC
// 
// The SMECshould be switched on (SpireBbSmecOn) before execution of this building block
//
// 29/04/2009 KJK: First Version
// 18/07/2009  MP: Added change made by Sunil on 16th to header 
//                 (see SPR-SPIRE-1638)
// 17/08/2009 SDS: Temporarily comment out the SMEC close loop command (SPIRE SPR-1824)
//
// 18/08/2009 SDS: Major update to include the use of a VM to determine encoder signal 1 & 2 offsets
//
// 21/08/2009 TWG: Updates for latest usage of the SMEC VM - running on VM1 and scan durations increased
//
// 28/08/2009 TWG: Updated to use the Ki value from the table
// 02/09/2009 KJK: edited to print VM commands in messages
// 14/10/2009 SDS/TWG: Modifications prompted by SPR-2062:
//                                     Removed commands to set FF offset, FF gain, rate limit, derivative filter and integration limit
//                                     and LVDT scale factor (now being set in SpireBbSmecOn)
//                                     Added the restarting of MCU Eng data 
//                                     Added the setting of scan forward and reverse speeds 
//                                     Clear BSM and SMAC sampling before initialisation
//                                     Reset BSM and SMEC sampling to SPECSTBY mode after initialisation
// 23/10/2009 SDS/TWG: Removed command to set the MODE to SMEC_INIT and associated wait
//
block SpireBbSmecInit SPIRE 531 {
    string res = "H";
    string bsmVersion = "v00";
    string smecVersion = "v00";
    string specVersion = "v00";
    bool debug = false;
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SMEC Initialisation started");
    SpireMsg(2,"          $Id$");
    //
    // 
    // intialise variables
    int kp = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"kp");
    int ki = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"ki");
    int kd = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"kd");
    int smecHome = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"Home");
    int moveCmd = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"MoveCmd");
    //
    // 
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set Step to zero
    SpireSetObsStep(0);
    delay(1);
    //
    // Stop MCU data, flush MCU FIFO, set MCU Eng sampling to 125Hz and start data generation
    SpireSendDrcuCmd(0x91c10000,0);
    // stop MCU data
    SpireSendDrcuCmd(0x91c20000,0);
    // clear BSM sampling
    delay(1);
    SpireSendDrcuCmd(0x91c00000,0);
    // clear SMEC sampling
    Spire_FLUSH_FIFO(0x2000);
    delay(1);
    SpireSendDrcuCmd(0x91c40013,0);
    SpireSendDrcuCmd(0x91c3ffff,0);
    delay(1);
    SpireSendDrcuCmd(0x91c10001,0);
    delay(1);
    //
    // Set scan speeds:
    SpireSendDrcuCmd(0x90470000 + moveCmd,0);
    SpireSendDrcuCmd(0x90560000 + moveCmd,0);
    delay(1);
    //
    //
    //
    // Set the Signal 1 & Signal 2 offsets to be outside the valid range
    SpireSendDrcuCmd(0x90588000,0);
    SpireSendDrcuCmd(0x905a8000,0);
    delay(1);
    //
    // Stop trajectory generation
    SpireSendDrcuCmd(0x90490000,0);
    delay(1);
    // Move the SMEC to 3mm
    SpireSendDrcuCmd(0x90450bb8,0);
    SpireSendDrcuCmd(0x90490001,0);
    // Allow enough time for SMEC to move from MR scan end
    delay(24);
    // 
    //
    // Stop trajectory generation
    SpireSendDrcuCmd(0x90490000,0);
    delay(1);
    //
    // Set the scan start and end positions to 3mm and 4mm
    SpireSendDrcuCmd(0x90460bb8,0);
    SpireSendDrcuCmd(0x90450fa0,0);
    delay(1);
    //
    // Set the number of scans to 4  - (TWG, 21-Aug-09 - increased from 2 scans)
    SpireSendDrcuCmd(0x90480004,0);
    delay(1);
    //
    // Run the SMEC offset VM to start scanning, determine and set the Signal 1 & Signal 2 offsets
    // Changed to run on VM1, with updated sample parameters (TWG, 21-Aug-09)
    //
    tstr = SpireTimeStr(time());
    {int}[] params = [{80},{100000}];
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM1(75,0,2," + params + ")");
    Spire_RUN_VM1(75,0,2,params);
    delay(10);
    //
    // Set Ki to 0
    SpireSendDrcuCmd(0x904d0000,0);
    delay(2);
    //
    // Stop trajectory generation
    SpireSendDrcuCmd(0x90490000,0);
    delay(1);
    //
    // Go to Mechanical Stop
    //
    SpireSendDrcuCmd(0x90450000,0);
    delay(1);
    SpireSendDrcuCmd(0x90490001,0);
    delay(10);
    //
    // Reset Encoder
    SpireSendDrcuCmd(0x90490004,0);
    delay(1);
    //
    // Start trajectory generation
    SpireSendDrcuCmd(0x90490001,0);
    // 
    // Set Kd
    SpireSendDrcuCmd(0x904b0000 + kd,0);
    delay(1);
    //
    // Set Kp
    SpireSendDrcuCmd(0x904a0000 + kp,0);
    delay(1);
    //
    // Close loop on encoder signals 
    SpireSendDrcuCmd(0x90440001,0);
    delay(2);
    //
    // Move the SMEC to 0.1mm
    SpireSendDrcuCmd(0x90450064,0);
    delay(4);
    //
    // Run the SMEC VM to set Ki if the encoder position is 0.1mm +/- 0.02mm
    // Changed to run on VM1 (TWG, 21-Aug-09)
    //
    tstr = SpireTimeStr(time());
    params = [{100},{20},{ki}];
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM1(75,1,3," + params + ")");
    Spire_RUN_VM1(75,1,3,params);
    delay(10);
    //
    // Move mechanism to scan start position ready to scan
    int scanStart1 = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",res,"ScanStart",specVersion,debug);
    SpireProc_SmecMove(scanStart1,100,debug);
    delay(3);
    //
    // Stop MCU Eng data, flush MCU FIFO and set MCU Eng sampling to off 
    //
    SpireSendDrcuCmd(0x91c10000,0);
    delay(2);
    Spire_FLUSH_FIFO(0x2000);
    delay(1);
    SpireSendDrcuCmd(0x91c40000,0);
    //
    // restart BSM and SMEC sampling 
    SpireProcSetBsmSampling("SPECSTBY",bsmVersion,debug);
    SpireProcSetSmecSampling("SPECSTBY",smecVersion,debug);
    //
    // completion
    sync();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB SMEC Init   ended");
    SpireMsg(1,"  ..SMEC Initialisation (" + (time() - t0) + " seconds)");
}

// SpireEngSPEC_STBYtoREDY
//
// $id$
//
// This observation puts the instrument into the REDY mode
// 
// The instrument should be in  the SPEC_STBY mode before execution of this observation
//
//  07/05/2009  KJK: explicitly run StartObs and EndObs building blocks around the engineering procedure
//  08/06/2009  KJK: modified to allow input of SCAL version
//
obs SpireEngSPEC_STBYtoREDY {
    string bsmVersion = "v00";
    string smecVersion = "v00";
    string detVersion = "v00";
    string scalVersion = "v00";
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int t = duration(SpireBbStartObs()) + duration(SpireSPEC_STBYtoREDY(bsmVersion,smecVersion,detVersion,scalVersion,debug)) + duration(SpireBbEndObs());
    int[] ts = no_pointing(true,0,0,t);
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            SpireBbStartObs();
            SpireSPEC_STBYtoREDY(bsmVersion,smecVersion,detVersion,scalVersion,debug);
            SpireBbEndObs();
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_PhotPcalFlash.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to deduce number of DCU samples, SCU samples and DCU sample 
//  delay based on inputs period,mclkdiv and biasdiv
// 
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/05/05 V0.1: Initial version adapted from
//                  Proc_PCALFlashCalc.txt (v1.4 2008/01/31 20:24:35)
//                  
///////////////////////////////////////////////////////////////////////////
//
int[] procedure SpireProc_CalcParam_PhotPcalFlash {
    int period = 4000; //PCAL Flash FULL period (high and low bias) in millisec
    int mclkdiv = 60; // Fetched master clock divisor
    int biasdiv = 3; // Fetched bias divisor
}{
    // //
    // //
    // Calculate bias frequency Hz:
    //
    double bias_f = 1.0E7 / (512.0 * double(mclkdiv));
    // //
    // //
    // Calculate sampling rate Hz:
    //
    double s_rate = bias_f / (1.0 + double(biasdiv));
    // //
    // //
    // Calculate frame time difference in ms:
    double framerate = 1.0 / s_rate * 1000.0;
    // //
    // //
    // Calculate dcusamples, scusamples, and dcudelay parameters:
    //
    int dcusamples = iround(double(period) / 2.0 / framerate) - 1;
    int scusamples = iround(double(period) / 2.0 / 12.5) - 1;
    int dcudelay = iround((double(period) / 2.0 - double(dcusamples) * framerate) * 1000.0);
    if(dcudelay < 0) {
        do {
            dcusamples = dcusamples - 1;
            dcudelay = iround((2000.0 - double(dcusamples) * framerate) * 1000.0);
            debug_print("New number of dcu samples is: " + dcusamples);
            debug_print("New dcu_sample_delay rate is: " + dcudelay);
        } while (dcudelay < 0);
    }
    scusamples = 0x0;
    //

    return [dcusamples,scusamples,dcudelay];
}

// SpireBb_LvdtScans
//
// $id$
//
// This building block switches on the SMEC
// 
// The instrument should be in  the REDY mode before execution of this building block
//
// 17/07/2009 SDS:
//         First Version 0.1
//
// 27/07/2009 SDS:
//         v0.2: Fix for SPIRE SCR-1725
//               Option to select version of SpireTable_SmecNominalSettings.txt
// 29/07/2009 SDS:
//         v0.3: Hardcoded version "v00" for SpireTable_SpecModeParams.txt
block SpireBb_LvdtScans SPIRE 14074 {
    int nScans = 32;
    string pString1 = "v00";
    string version02 = "v00";
    bool debug = false;
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB LvdtScans started");
    SpireMsg(2,"          $Id$");
    //
    // Read Kp/Ki/Kd
    //    
    int kp = ilookup("SpireTable_SmecNominalSettings.txt",pString1,"kp");
    int ki = ilookup("SpireTable_SmecNominalSettings.txt",pString1,"ki");
    int kd = ilookup("SpireTable_SmecNominalSettings.txt",pString1,"kd");
    int speed = ilookup("SpireTable_SmecNominalSettings.txt",pString1,"MoveSpeed");
    int home = ilookup("SpireTable_SmecNominalSettings.txt",pString1,"Home");
    int smecrate_lvdt = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SEngCalObs_45","smecFrameRate","v00",debug);
    int smecrate_specstby = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","smecFrameRate","v00",debug);
    int bsmrate = SpireProc_GetTableEntryInt("SpireTable_CommonModeParams.txt","mode","SPECSTBY","bsmFrameRate",version02,debug);
    // 
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    delay(1);
    //
    // set Step to zero
    SpireSetObsStep(0);
    //
    // Set BSM sampling to 0
    SpireSendDrcuCmd(0x91c20000,0);
    // 
    // Set SMEC science frame rate for LVDT scans
    SpireSendDrcuCmd(0x91c00000 + smecrate_lvdt,0);
    delay(1);
    //
    // Start SMEC selected data generation in continuous mode    
    //
    SpireSendDrcuCmd(0x91c3ffff,0);
    delay(1);
    SpireSendDrcuCmd(0x91c10001,0);
    delay(1);
    //
    // Start DCU SF data 
    SpireSendDrcuCmd(0x843e0001,0);
    // Open the SMEC loop and set Kp/Ki to 0
    SpireSendDrcuCmd(0x90440006,0);
    delay(4);
    SpireSendDrcuCmd(0x904a0000,0);
    delay(1);
    SpireSendDrcuCmd(0x904d0000,0);
    delay(1);
    // Move the SMEC to ZPD (8mm) - allow 20 seconds to reach
    SpireSendDrcuCmd(0x90490001,0);
    delay(1);
    SpireSendDrcuCmd(0x90451f40,0);
    delay(20);
    //
    // Stop trajectory and set Kd
    SpireSendDrcuCmd(0x90490000,0);
    delay(1);
    SpireSendDrcuCmd(0x904b0000 + kd,0);
    delay(1);
    //
    // Close the loop on LVDT and set Kp/Ki
    SpireSendDrcuCmd(0x90440004,0);
    delay(1);
    SpireSendDrcuCmd(0x904a0000 + kp,0);
    delay(1);
    SpireSendDrcuCmd(0x904d0000 + ki,0);
    delay(1);
    //
    // Move the SMEC to 4.6mm - allow 20 seconds to reach
    SpireSendDrcuCmd(0x904511f8,0);
    delay(1);
    SpireSendDrcuCmd(0x90490001,0);
    delay(20);
    //
    // Set the Scan start and End Positions to 4.6mm and 11.4mm
    SpireSendDrcuCmd(0x90490000,0);
    delay(1);
    SpireSendDrcuCmd(0x904611f8,0);
    delay(1);
    SpireSendDrcuCmd(0x90452c88,0);
    delay(1);
    //
    // Set the number of Up/Down scans
    SpireSendDrcuCmd(0x90480000 + nScans,0);
    delay(1);
    // Start scanning in LVDT closed loop mode
    SpireSendDrcuCmd(0x90490002,0);
    int scanwait = iround(1.025 * double(nScans) * 8000.0 / double(speed));
    delay(scanwait);
    //
    // Move the SMEC to Home - allow 10 seconds to reach
    SpireSendDrcuCmd(0x90490001,0);
    delay(1);
    SpireSendDrcuCmd(0x90450000 + home,0);
    delay(10);
    //
    // Stop SMEC selected science data generation 
    SpireSendDrcuCmd(0x91c10000,0);
    delay(2);
    //
    // Stop DCU SF data generation and flush DCU/MCU FIFOs
    SpireSendDrcuCmd(0x843e0000,0);
    delay(1);
    Spire_FLUSH_FIFO(0x3000);
    delay(2);
    //    
    // Set BSM and SMEC sampling to default value
    SpireSendDrcuCmd(0x91c20000 + bsmrate,0);
    SpireSendDrcuCmd(0x91c00000 + smecrate_specstby,0);
    delay(1);
    // completion
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB SMEC On   ended");
    SpireMsg(1,"  ..SMEC ON (" + (time() - t0) + " seconds)");
}

// CVS comments  : $Id: PacsPhotSlewCal.txt,v 1.10 2008/05/06 13:34:53 vanessa Exp $ 
// Purpose       : Invoke a PACS calibration OBCP during slew to source;
//                 leave PACS ready to start observations once in source
//
// CUS author    : DAC
// Script file   : PacsPhotSlewCal.txt 
//
// Input arguments
// Type                      Description
//
// Return values
// Type    Name      Default      Description
//
// Description   : Perform AOT prologue and then OBCP #13.
//
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : 
// 
// History       : 0.1 DAC  30-Nov-2005 (inspired by PacsSpecSlewCal)
// 0.2 DAC 20-sep-2006 Clean up leftovers from SPEC script 
// 0.3 DAC  6-dec-2006 Adapted to simpler PHOT_fltw_move
// 0.4 DAC 27-jun-2007 SPR-3339 Always move filter wheel
// 1.0 DAC 10-oct-2007 SCR-3628 Added arguments to call aot_prologue
// 1.1 JVP 28-apr-2008 ERROR in filter_id assignation: POS A is LW for the
//     	   	       photometer (remind POS A = SW for spectro)
// 1.2 DAC 20-may-2008 Moved FLTW move into DO_PROLOGUE section                
// 2.0 SCR 4431 VDO: implemetation of data_rates
// 2.1 16-sep-2009 VD implementation 5sec delay post-cal: PACS-2039
// 
int[] procedure PacsPhotSlewCal {
    bool verbose = true; // Debug_print or not 
    {int,int,int,int,int,int,int,int,int}[] confPHOTblu = [{0,64,0,0,0,0,0,0,0}]; // BLUE SPU parameters
    {int,int,int,int,int,int,int,int,int}[] confPHOTred = [{0,64,0,0,0,0,0,0,0}]; // RED  SPU parameters
    {int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int}[] confOBCP = [{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}]; // OBCP parameters
    bool doPROLOG = true; // Perform/don't AOT prologue
    string filter = "blue2"; // PHOT filter
}{
    // Array to collect OBCP times per line
    int duree_num = 0;
    int duree_SRC = 0;
    int duree_REF = 0;
    int duree_CAL = 0;
    int duree_OVR = 0;
    int time_start = time();
    int[] totalDUREE = [0,0,0,0,0];
    // Table of filter wheel positions as per MIB
    // Actually originally not blue1 = SW = POS B, and blue2 = LW = POS A for
    // the photmeter
    if(filter == "blue1") {
        string filterID = "POS B";
    }
    if(filter == "blue2") {
        filterID = "POS A";
    }
    // Long sequence to "unpack" default values from tuples
    int gain_blu = confPHOTblu[0]{0};
    int comp_mode_blu = confPHOTblu[0]{3};
    int glitch_det_blu = confPHOTblu[0]{4};
    int nb_raw_blu = confPHOTblu[0]{6};
    int gain_red = confPHOTred[0]{0};
    int comp_mode_red = confPHOTred[0]{3};
    int glitch_det_red = confPHOTred[0]{4};
    int nb_raw_red = confPHOTred[0]{6};
    int nb_cycles_obs_cal = confOBCP[0]{0};
    int nb_SRC_REF = confOBCP[0]{3};
    int nb_rdouts_plateau = confOBCP[0]{4};
    int nb_CS1_CS2 = confOBCP[0]{5};
    int chop_pos_SRC = confOBCP[0]{12};
    int chop_pos_REF1 = confOBCP[0]{13};
    int chop_pos_REF2 = confOBCP[0]{14};
    int chop_def = confOBCP[0]{17};
    int detector = confOBCP[0]{18};
    int filterPOS = confOBCP[0]{19};
    if(gain_blu == 1 && gain_red == 1) {
        string set_gain = "LOW";
    } else {
        if(gain_blu == 0 || gain_red == 0) {
            set_gain = "HIGH";
        }
    }
    // Issue PHOT_aot_prologue if demanded
    if(doPROLOG) {
        totalDUREE = PHOT_aot_prologue(set_gain,comp_mode_blu,comp_mode_red,nb_raw_blu,nb_raw_red,verbose);
        // Turn the filter wheel
        int timeFLTW = PHOT_fltw_move(filterID);
        //  increment total duration and overheads
        totalDUREE[0] = totalDUREE[0] + timeFLTW;
        totalDUREE[4] = totalDUREE[4] + timeFLTW;
    }
    // Issue now OBCP4 for demanded filter
    // Table OBCP4params has parameter values for CAL using blue1 or blue2
    // Get params for demanded filter from OBCP4params
    string calNAME = "OBCP4params";
    // Table acces key is "cal1" or "cal2", corresponding to blue1 and blue2
    // respectively.
    string key = "cal1";
    if(filter == "blue2") {
        key = "cal2";
    }
    nb_cycles_obs_cal = ilookup(calNAME,key,"nb_cycles_obs_cal");
    nb_SRC_REF = ilookup(calNAME,key,"nb_SRC_REF");
    nb_rdouts_plateau = ilookup(calNAME,key,"nb_rdouts_plateau");
    nb_CS1_CS2 = ilookup(calNAME,key,"nb_CS1_CS2");
    // Read CS positions from CHOPPERCSparams
    int pos_CS1 = ilookup("CHOPPERCSparams","PHOT","pos_CS1");
    int pos_CS2 = ilookup("CHOPPERCSparams","PHOT","pos_CS2");
    // Update OBCP[0] tuple with CAL-U values
    confOBCP[0]{0} = nb_cycles_obs_cal;
    confOBCP[0]{3} = nb_SRC_REF;
    confOBCP[0]{4} = nb_rdouts_plateau;
    confOBCP[0]{5} = nb_CS1_CS2;
    confOBCP[0]{15} = pos_CS1;
    confOBCP[0]{16} = pos_CS2;
    // Call now OBCP with derived parameters
    int[] dureeOBCP = OBCP_chopped_photometry(nb_SRC_REF,chop_pos_SRC,nb_rdouts_plateau,chop_pos_REF1,chop_pos_REF2,nb_cycles_obs_cal,nb_CS1_CS2,pos_CS1,pos_CS2,comp_mode_blu,comp_mode_red,chop_def);
    if(verbose) {
        debug_print("*** SlewCal OBCP: " + confOBCP[0]);
        debug_print("*** SlewCal OBCP returns: " + dureeOBCP);
    }
    // Tally total durations
    for(int loop0 = 0 .. 4) {
        totalDUREE[loop0] = totalDUREE[loop0] + dureeOBCP[loop0];
    }
    if(verbose) {
        debug_print("***** SlewCal performed CAL: " + key + " requires " + totalDUREE[0] + " [sec]");
    }
    // here we have to add 5sec delay
    // this 5 sec MUST be labeled soooooo 
    PacsBbDelayScience(4);
    // Leave bus scheduler in a known state (SP1707)
    sync();

    return totalDUREE;
}

// SpireEngREDYtoPHOT_STBY
//
// $id$
//
// This observation puts the instrument into the PHOT_STBY mode
// 
// The instrument should be in  the REDY mode before execution of this observation
//
//
// 08/11/2007 KJK: explicitly run StartObs and EndObs building blocks around the engineering procedure
// 27/04/2009  KJK: bsmModel, bsmVersion and debug passed as parameters
// 09/06/2009  KJK: added parameter and commands to switch on PTC PID, if required
// 12/07/2009 MP: Changed default stabilisationTime (SCR-SPIRE-1632)
// 09/04/2010 SDS: Changed input for bsmModel from "initial" to "phot" (SCR-SPIRE-2490)
//
obs SpireEngREDYtoPHOT_STBY {
    int jfet_heater_V = 0; // Default jfet heater voltage at switch on
    string ptc = "Default" in ["Default","On","Off"]; // PTC status
    int ptcHold = 0; // time to wait for detectors to settle before starting PTC 
    int stabilisationTime = 120; // time (secs) to allow Detectors to stabilise before starting observations
    bool sampleDetectors = false; // sample detectors during the stabilisation period
    string bsmModel = "phot";
    string bsmVersion = "v00";
    string detVersion = "v00";
    string vssVersion = "v00";
    string ptcVersion = "v00";
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int t = duration(SpireBbStartObs()) + duration(SpireREDYtoPHOT_STBY(jfet_heater_V,ptc,ptcHold,stabilisationTime,sampleDetectors,bsmModel,bsmVersion,detVersion,vssVersion,ptcVersion,debug)) + duration(SpireBbEndObs());
    int[] ts = no_pointing(true,0,0,t);
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            SpireBbStartObs();
            SpireREDYtoPHOT_STBY(jfet_heater_V,ptc,ptcHold,stabilisationTime,sampleDetectors,bsmModel,bsmVersion,detVersion,vssVersion,ptcVersion,debug);
            SpireBbEndObs();
        }
    }
}

//CLName: SpireBb_LoadTableREDY
//VMVersion: 2.8
//CLVersion: 1.1
//CLCVSId: $ID$
//TableId: 0x3d
//TableLength: 0x1c
//Date: 090326153808
// 23/07/2010: SDS
//                      Now reporting one word less than the length of table (static part of table) 
//                      See SPIRE-SCR-2761
block SpireBb_LoadTableREDY SPIRE 3802 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableREDY started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0x3d
    Spire_SET_TABLE(0x3d,0x1c);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x3d,0x0,28,[{0x80007d0},{0x1000001},{0x80007d0},{0x120000ff},{0x0},{0x12000000},{0x1b},{0x62060001},{0x4900001b},{0x12000001},{0x200},{0x34000001},{0x3000000b},{0x120000ff},{0x0},{0x12000001},{0x200},{0x4b01001b},{0x12000000},{0x1b},{0x61060001},{0x60660004},{0x60660005},{0x80007d0},{0x1000000},{0x80007d0},{0x7f000000},{0x0}]);
    delay(t_min);
    //
    //  Dump table contents - report one word less than the length of table. 
    //  Final word in table is the MODE parameter.
    //
    Spire_REPORT_TABLE(0x3d,0x0,0x1b);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableREDY ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_CalGCO_FpgInitialPointing.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Phot Focal Plane Geometry (Initial Pointing)'
//
//         in *custom_map_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/06/10 V0.1: Initial version 
// 2008/06/19 V0.2: Exclude moving objects as input; add correct tasks to
//                  be performed at each pointing; replace OFF after every 
//                  point with an OFF after certain time
// 2008/06/19 V0.3: Add in ExpertHSPot parameters for OFF position as 
//                  described in DOC002387_SPIRE_HSpot_ICD_Issue_2_1.pdf
// 2008/06/30 V0.4: Renumber version; add offset at each raster point;
//                  use pointing mode to automatically calculate k in dry run
// 2008/07/04 V0.5: Take data at GCP position; Remove StopDcuData before offset
//                  Add OBS_STEP to identify raster points
// 2008/07/25 V0.6: Major change: use custom map instead of raster pointing
// 2008/07/28 V0.7: Include BSM movement; Allow nafid as input parameter;
//                  Change sequence of raster point visits; remove bug in
//                  assigning return of SpireProc_CalcParam_FpgInitialPointing
// 2008/09/12 V0.8: Remove test number; Adapt to name change in lowlevel script
//                  Adapt to changes in SpireBb_PhotChop (remove ver param);
//                  Add move to BSM hold to INIT_HOLD; Restrict chop frequency
//                  Write out error message if elasped tim > gcp_period and
//                  gcp_period < estimated GCP visit time
// 2008/09/16 V0.9: Change kgcp_old formula; Set correct defaults; Add
//                  temporary restriction to non-SSOs 
// 2008/10/13 V0.10: Set 5x5 as default; Clean up input section; Leave
//                   stepsize unrestricted; Adapt to name changes in low level
//                   scripts.
// 2008/11/06 V0.11: Adapt to name change in low level script; Add table of
//                   pixles to visit to input; Change in debug_print 
// 2008/11/12 V0.12: Implement mode setting; Add isBright 
//                   Implement proper setting of MCU framerate
//                   Change default gyro re-calibration period
// 2009/02/02 V1.0: Add debug_print as input abd pass to low level scripts. 
//                  Replace call to SpireBb_SetBsmFramerate with call to 
//                  SpireBb_SetBsmFramerate. Set obsStep back to zero at
//                  FINAL_HOLD. Use new SpireBb_EndObsAll and 
//                  SpireBb_StartObsAll. Read nominal bias frequency, bias
//                  divider, and BSM sampling rate from new
//                  SpireTable_DetectorSettings.txt. Implemented setting 
//                  of datarates. Implemented isBright setting. 
//                  Replace SpireBb_BsmMove2Hold with SpireBb_BsmMove.
//                  Add safety check for off chop BSM position. 
// 2009/02/03 V1.1: Set limits for d1 in input. 
// 2009/02/17 V1.2: Use SpireBb_PhotSetMode to set to PHOTSTBY during 
//                  SLEW and FINAL_HOLD, which replaces unsetting of
//                  framerate at end. Remove cal. table from input. 
//                  Read some VM parameters from cal. table 
//                  SpireTable_CommandLists.txt. Adapt input to updated 
//                  SpireBb_Chop. Update setting of datarates.
// 2009/03/03 V1.3: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. 
// 2009/05/06 V1.4: Add in move BSM to hold at start. Gather procedures at 
//                  start and end in separate BB. Properly compare input
//                  BSM framerate with PHOTSTBY value.
// 2009/05/11 V1.5: Allow number of raster points as input. 
// 2009/06/05 V1.6: Hardcode STBY 'v00' in EndBB (SPR-1477)
// 2009/07/13 V1.7: Change patt from 90 to 0 (SPR-SPIRE-1643)
// Sunil Sidher
// 2009/07/28 V1.8: Change patt from 0 to 180 (SPIRE SPR-1746)
// 
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in PHOTSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for all three arrays and could be taken from following cal table: 
//  SpireTable_PhotModeParams.txt
//
//  3) Home position of BSM can be read from SpireTable_BsmNominalSettings.txt
//
//  4) Some VM parameters for chopping are read from following cal table:
//     SpireTable_CommandLists.txt
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhoto_CalGCO_FpgInitialPointing {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; //NAIF identifier: put '0' to use RA/DEC, or correct 'NAIFID'
    /* */
    bool isBright = false; // Use settings for bright source (==tick)
    double raoff = 0.0 in [0.0,360.0]; // RA of GCP position
    double decoff = 0.0 in [-90.0,90.0]; // DEC of GCP position 
    string ib = "S14_0"; // Central aperture (defined in SIAM) of raster
    int m = 5; // Number of points in raster along Y [odd number!]
    int n = 5; // Number of points in raster along Z [odd number!]
    double d1 = 4.0 in [2.0,480.0]; // Angular stepsize between raster pts [arcsec]
    int ftime = 15; // Read-out time [s]
    double chopf = 2.0 in [0.1,4.0]; // Chop frequency [Hz] 
    int offChopfh = 9600; // off-source chop position (+ or - relative to hold) [Dec(Hex)]
    double framerate = 125.0; // Specifies the MCU framerate [Hz]
    int gcp_time = 20; // Time spend at GCP (gyro calibration position) [s]
    int gcp_period = 600; // Maximum time between successiv GCP visits [s]
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_PhotFpgInitialPointing
    string version05 = "v00"; // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial"; // Model in cal table SpireTable_BsmNominalSetting
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // //
    // //
    // Current restrictions:
    //
    if(naifid != 0) {
        error("Currently no SSO objects are allowed as input!");
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = true;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_PhotFpgInitialPointing.txt";
    string tabName04 = "SpireTable_CommandLists.txt";
    string tabName05 = "SpireTable_BsmNominalSettings.txt";
    //
    // Dummy value for Spec script:
    // (needed but not used in phot script!)
    //
    int smecHomePosn = 3500;
    // SMEC home position
    //
    bool setFramerate = true;
    //
    int tslewminadd = 0;
    int tfinalholdadd = 0;
    //
    int obsStep = 0;
    //
    // Start timing of script:
    int start = time();
    //
    // First obsstep [HEX]:
    int obsstep = 0x0;
    //
    // Count raster points: 
    int raster_counter = 0;
    //
    // Angular stepsize along Z axis [arcsec]:
    double d2 = d1;
    // NOTE: Script works only for equidistant raster points in both axes:
    //
    // DCU data mode (0 == Full photometer):
    int dcumode = 0;
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS02";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "PEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Setup parameters for BSM chopping movement: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version05;
    tabName = tabName05;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // on-source Chop position [Dec(Hex)]:
    int onChop = hold_chop;
    // on-source Jiggle position:
    int onJigg = hold_jigg;
    // off-source Chop position:
    int offChop = hold_chop + offChopfh;
    // off-source Jiggle position:
    int offJigg = hold_jigg;
    //
    // Check chop off position:
    //
    if(offChop > 50000) {
        error("Off chop is larger than 50000. Reduce offChopfh");
    }
    //
    // Read VM parameters from calibration table:
    //
    tabName = tabName04;
    selVal = "Chop";
    int vmId = ilookup(tabName,selVal,"Id");
    int vmIndex = ilookup(tabName,selVal,"Index");
    int nParms = ilookup(tabName,selVal,"Nparms");
    // //
    // //
    // Read nominal bias frequency and bias divider:
    // (to determine the sampling rate)
    //    
    // Select version flag and set GetTableEntry parameters:
    version = version01;
    tabName = tabName01;
    selCol = "mode";
    // Name of column for selecting 
    selVal = obsMode;
    // Value of 'string' selector
    //
    tarCol = "mclkDiv";
    int mclkDiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "biasDiv";
    int biasDiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Read PHOTSTBY framerate:
    //
    selVal = "PHTSTBY";
    version = version02;
    tabName = tabName02;
    tarCol = "bsmFrameRate";
    int bsmFrameRate = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    double bsmFrameRateHz = 1000000.0 / (double(bsmFrameRate) * 420.0);
    if(debug) {
        debug_print("Nominal BSM sampling rate is: " + bsmFrameRateHz + " [Hz]");
    }
    //
    // Compare nominal with input BSM framerate:
    // 
    int frate = SpireProc_CalcParam_BsmFramerate(framerate,debug);
    if(frate == bsmFrameRate) {
        setFramerate = false;
    }
    //
    // Calculate nominal sampling rate from mclkdiv and biasdiv:
    //
    double mclkDivHz = 1.0E7 / (512.0 * double(mclkDiv + 1));
    double biasDivHz = 1.0 / (double(biasDiv) + 1.0) * mclkDivHz;
    if(debug) {
        debug_print("Nominal sampling rate is: " + biasDivHz + " [Hz]");
    }
    // //
    // //
    // Compare read-out time and dwell time on GCP:
    //
    int dtime = 0;
    // time to be spend on GCP position
    if(gcp_time < ftime) {
        dtime = ftime;
    } else {
        dtime = gcp_time;
    }
    //
    // Calculate BSM chop parameters:
    //
    int[] chopparam1 = SpireProc_CalcParam_BsmSetup(ftime,chopf,biasDivHz,framerate,debug);
    int ncycles = chopparam1[0];
    int chop_period = chopparam1[1];
    int dcusample = chopparam1[2];
    int dcudelay = chopparam1[3];
    int bsmsample = chopparam1[4];
    int[] chopparam2 = SpireProc_CalcParam_BsmSetup(dtime,chopf,biasDivHz,framerate,debug);
    int ncycles_2 = chopparam2[0];
    int chop_period_2 = chopparam2[1];
    int dcusample_2 = chopparam2[2];
    int dcudelay_2 = chopparam2[3];
    int bsmsample_2 = chopparam2[4];
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    // 
    int tslewmin = duration(SpireBb_StartFpgInitialPointing(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,setFramerate,frate,debug));
    // 
    // BBs carried out when the pointing is reached:
    //
    int tinithold = 0;
    //
    // BB carried out during pointing:
    // 
    int tp_np = duration(SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles,chop_period,dcumode,dcusample,dcudelay,bsmsample,obsstep,debug)) + duration(SpireBb_PhotOffsetAuto(debug));
    int tp_gp = duration(SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles_2,chop_period_2,dcumode,dcusample_2,dcudelay_2,bsmsample_2,obsstep,debug)) + duration(SpireBb_PhotOffsetAuto(debug));
    //
    // BB carried out at the end:
    //
    int tfinalhold = duration(SpireBb_EndFpgInitialPointing(phot,hold_chop,hold_jigg,isBright,version01,version02,debug));
    // //
    // //
    // Debug printing:
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing normal= " + tp_np);
        debug_print("tpointing @GCP= " + tp_gp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                              */
    // ****************************************************** */
    // //
    // //
    // Fixed parameters for pointing mode:
    //   
    bool fixed = false;
    // Pattern orientation (true==sky; false==array)
    double patt = 180.0;
    // Rotation angle of the pattern
    double yoffset = 0.0;
    // Offset of pattern in the direction of the +Y
    double zoffset = 0.0;
    // Offset of pattern in the direction of the +Z
    int thold = 0;
    // The duration of the hold when nhold>0.
    int nhold = 0;
    // Number of nods or raster points or scan lines before
    //              // performing a hold.
    double pattnod = 0.0;
    //
    double chopthrow = 2.0;
    //
    int nnod = 1;
    //
    int knod = 0;
    //
    int nload = 0;
    //
    int tloadmin = 0;
    //
    // //
    // //
    // Calculate array of points:
    //
    {double[],double[],int} array = SpireProc_CalcParam_FpgInitialPointing(d1,d2,m,n,tabName03,version03,debug);
    double[] zarray_org = array{0};
    double[] yarray_org = array{1};
    int numpixel = array{2};
    int nump_org = length(yarray_org);
    // //
    // //
    // Add GCP visit after every raster point (except first which is GCP)
    // and create tp (duration of fine pointing) vector new raster:
    //
    double[] yarray = [0.0];
    double[] zarray = [0.0];
    int run = 1;
    int aindex = 1;
    int fin = length(yarray_org);
    yarray[0] = yarray_org[0];
    zarray[0] = zarray_org[0];
    bool gcpp = false;
    int[] tpv = [0];
    tpv[0] = tp_gp;
    do {
        if(gcpp) {
            yarray[aindex] = yarray_org[0];
            zarray[aindex] = zarray_org[0];
            tpv[aindex] = tp_gp;
            gcpp = false;
        } else {
            yarray[aindex] = yarray_org[run];
            zarray[aindex] = zarray_org[run];
            tpv[aindex] = tp_np;
            run = run + 1;
            gcpp = true;
        }
        aindex = aindex + 1;
    } while (run < fin);
    // Add GCP visit at end:
    yarray[aindex] = yarray_org[0];
    zarray[aindex] = zarray_org[0];
    tpv[aindex] = tp_gp;
    //
    // //
    // //
    if(debug) {
        debug_print("timing vector : " + tpv);
        debug_print("zarray_org: " + zarray_org);
        debug_print("zarray: " + zarray);
    }
    //
    // Calculate slew times in pointing mode:
    //
    int[] ts_tr = custom_map_pointing(false,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,fixed,patt,yoffset,zoffset,yarray,zarray,tpv,pattnod,chopthrow,nnod,knod,tloadmin,nload,thold,nhold);
    //
    if(debug) {
        debug_print("Pointing vector : " + ts_tr);
    }
    // //
    // //
    // Determine maximal slew to GCP:
    //
    int nump = length(yarray);
    int nslews = nump;
    int nlslews = numpixel;
    int tpp = ts_tr[7];
    int[] tslews = [0];
    tslews[0] = 0;
    for(int j = 1 .. nslews - 1) {
        if(debug) {
            debug_print("entry: " + (j + 6));
        }
        tslews[j] = ts_tr[j + 6];
    }
    //
    int maxslew = 0;
    for(int k = 0 .. length(tslews) - 1) {
        maxslew = iceil(max(double(maxslew),double(tslews[k])));
    }
    if(debug) {
        debug_print("nlslews: " + nlslews);
        debug_print("nslews: " + nslews);
        debug_print("tslews: " + tslews);
        debug_print("maxslew: " + maxslew);
    }
    // //
    // //
    // Determine slew time between small raster points:
    //
    int tppn = tslews[1];
    // == slew beteen first and second raster point
    // //
    // //
    // Decrease frequency of GCP visits until gcp_period matched
    //
    //   
    int kgcp = 1;
    int ktime = 0;
    int ktime_old = 0;
    int nslew = 0;
    do {
        ktime_old = ktime;
        //
        // Count number of slews between the mxn rasters: 
        if(2 * kgcp + 1 > (nslew + 1) * m * n) {
            nslew = nslew + 1;
            if(debug) {
                debug_print("nslew: " + nslew);
            }
        }
        //
        // Calculate approximate(!) time between off visits :
        // [Problem: slews are not 100% predictable with single dummy run]
        //
        ktime = tp_gp + kgcp * tp_np + (kgcp - nslew) * tppn + nslew * maxslew + 2 * maxslew;
        // 
        // Add safety time:
        // [to account for possible longer slews than in dummy run] 
        ktime = ktime + 0;
        int kdiff = ktime - ktime_old;
        //
        // Print out error if gcp_period < ktime for first case 
        // (== having a GCP after each point):
        if(kgcp == 1) {
            if(gcp_period < ktime) {
                debug_print("gcp_period < ktime: " + gcp_period + " < " + ktime);
                error("gcp_period smaller than expected times between GCP visits! Change input parameters!");
            }
        }
        // 
        if(debug) {
            debug_print("tpv[0]: " + tpv[0]);
            debug_print("tp_np: " + tp_np);
            debug_print("tp_gp: " + tp_gp);
            debug_print("tppn: " + tppn);
            debug_print("maxslew: " + maxslew);
            debug_print("nslew: " + nslew);
            debug_print("ktime-ktime_old: " + kdiff);
            debug_print("ktime loop kgcp/ktime: " + kgcp + "/" + ktime);
        }
        //
        //
        // Increment kgcp (i.e delay visit to GCP by one more raster point): 
        if(debug) {
            debug_print("increment kgcp by 1");
        }
        kgcp = kgcp + 1;
        if(debug) {
            debug_print("new kgcp: " + kgcp);
        }
        //
    } while (ktime < gcp_period);
    //
    // Select last kgcp for which condition was fulfilled:
    int kgcp_old = 1;
    if(kgcp > 2) {
        kgcp_old = kgcp - 2;
    }
    message("Return to GCP after every " + kgcp_old + " normal raster point(s)!");
    //
    if(debug) {
        debug_print("values after kgcp selection loop:");
        debug_print("nump: " + nump);
        debug_print("nslews: " + nslews);
        debug_print("tslews: " + tslews);
        debug_print("maxslew: " + maxslew);
        debug_print("ktime loop end: " + ktime);
        debug_print("kgcp loop end:" + kgcp);
        debug_print("ktime_old: " + ktime_old);
        debug_print("kgcp_old:" + kgcp_old);
    }
    // //
    // //
    // Add visits to the GCP tp raster array:
    //
    int counter = 0;
    double[] yarray_new = [0.0];
    double[] zarray_new = [0.0];
    double ygcp = yarray[0];
    double zgcp = zarray[0];
    if(debug) {
        debug_print("ygcp/zgcp: " + ygcp + "/" + zgcp);
        debug_print("zarray: " + zarray);
    }
    //
    // Start loop:
    int end = nump_org;
    int ln = 0;
    int stop = 0;
    int index = 0;
    bool[] raster = [true];
    do {
        if(debug) {
            debug_print("stop : " + stop);
            debug_print("end : " + end);
            debug_print("index : " + index);
            debug_print("counter: " + counter);
        }
        if(counter > kgcp_old - 1) {
            yarray_new[index] = ygcp;
            zarray_new[index] = zgcp;
            ln = ln + 1;
            counter = 0;
            raster[index] = false;
        } else {
            yarray_new[index] = yarray_org[index - ln];
            zarray_new[index] = zarray_org[index - ln];
            if(debug) {
                debug_print("index -ln : " + (index - ln));
            }
            stop = stop + 1;
            counter = counter + 1;
            raster[index] = true;
        }
        index = index + 1;
    } while (stop < end);
    //
    // Define first point always as regular raster point:
    raster[0] = true;
    //
    // Add additional visit to GCP at end:
    // (could give unsymmetric GCP visits but ensures a GCP at start AND end)
    if(debug) {
        debug_print("index : " + index);
    }
    if(yarray_new[index - 1] != ygcp) {
        yarray_new[index] = ygcp;
        zarray_new[index] = zgcp;
        raster[index] = false;
    }
    // 
    if(debug) {
        debug_print("# pts without GCPs: " + length(yarray_org));
        debug_print("# pts with GCPs: " + length(yarray_new));
        debug_print("yarray_org: " + yarray_org);
        debug_print("zarray_org: " + zarray_org);
        debug_print("yarray_new = " + yarray_new);
        debug_print("zarray_new = " + zarray_new);
    }
    //
    // Adapt tp vector to new number of points:
    int[] tpv_new = [0];
    for(int ind = 0 .. length(yarray_new) - 1) {
        if(ind == 0) {
            tpv_new[0] = tpv[0];
        } else {
            if(yarray_new[ind] == ygcp) {
                if(zarray_new[ind] == zgcp) {
                    tpv_new[ind] = tp_gp;
                } else {
                    tpv_new[ind] = tp_np;
                }
            } else {
                tpv_new[ind] = tp_np;
            }
        }
    }
    if(debug) {
        debug_print("raster vector: " + raster);
        debug_print("new timing vector : " + tpv_new);
        debug_print("length(raster): " + length(raster));
        debug_print("length(yarray_new): " + length(yarray_new));
        debug_print("length(tpv_new): " + length(tpv_new));
    }
    // //
    // //
    // Set pointing mode:
    //
    //custom_map_pointing(true, tslewmin, tinithold, tfinalhold, ib, naifid,
    //ra,dec,fixed,patt,yoffset,zoffset,yarray,zarray,tpv, pattnod,chopthrow,
    //nnod,knod,tloadmin,nload, thold, nhold);
    //
    int[] ts = custom_map_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,fixed,patt,yoffset,zoffset,yarray_new,zarray_new,tpv_new,pattnod,chopthrow,nnod,knod,tloadmin,nload,thold,nhold);
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC              */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //     
            SpireBb_StartFpgInitialPointing(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,setFramerate,frate,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            //
            //
            //delay(tinithold);
        }
        if(state[0] == 3) {
            // STATE = POINT (spacecraft is at nominal RA,DEC (staring, raster))
            //
            //delay(tp);
            // //
            // //
            // Set offsets at each raster point:
            //
            SpireBb_PhotOffsetAuto(debug);
            // //
            // //
            // Different timings for different raster points (normal vs. GCP):
            // 
            if(raster[raster_counter] == false) {
                // //
                // //
                // Show time elapsed between visits to GCP:
                int t = time() - start;
                message("Time elapsed since last visit to GCP: " + t);
                if(debug) {
                    debug_print("Time elapsed since last visit to GCP: " + t);
                }
                // 
                if(t > gcp_period) {
                    error("Elapsed time between GCP visits larger than gcp_period! Change input parameters.");
                }
                //
                // Reset timer:           
                start = time();
                // //
                // //
                // Run chop VM (includes data taking) and set obs step parameter: 
                //
                SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles_2,chop_period_2,dcumode,dcusample_2,dcudelay_2,bsmsample_2,65535,debug);
                //
            } else {
                // //
                // //
                // Reset timing at first raster point:
                if(obsstep == 0) {
                    start = time();
                }
                // //
                // //
                // Run chop VM (includes data taking) and set obs step parameter: 
                //
                SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles,chop_period,dcumode,dcusample,dcudelay,bsmsample,obsstep,debug);
                obsstep = obsstep + 1;
                //
            }
            raster_counter = raster_counter + 1;
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ("sky" observation ends, performing final activities )
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            version03 = "v00";
            model = "initial";
            //
            SpireBb_EndFpgInitialPointing(phot,hold_chop,hold_jigg,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END (end of the pointing/commanding part of the code)
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_BsmFramerate.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Set MCU framerate (==BSM ampling rate) 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/11/13 V0.1: Initial version
// 2009/02/15 V0.2: Replaced input in Hz by input in Dec(Hex), conversion done
//                  in SpireProc_CalcParam_BsmFramerate. Replace final
//                  delay(1) with sync(). Add Hspot printouts 
// 2009/06/05 V1.0: Replace Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd 
//                  as requested in SPR-1482.
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_BsmFramerate {
    int frate = 37; // Specifies the frame rate [Dec(Hex)]
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    string tstr = "";
    double framerateHz = 0.0;
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"     " + tstr + ": SpireProc_Set_BsmFramerate started");
    SpireMsg(4,"          $Id:$");
    // //
    // //
    // Calculate Hex value from user input:
    //
    if(frate != 0) {
        framerateHz = 1000000.0 / (double(frate) * 420.0);
    } else {
        framerateHz = 0.0;
    }
    SpireSendDrcuCmd(0x91c20000 + frate,0);
    delay(1);
    //
    if(debug) {
        debug_print("Set MCU framerate (==BSM ampling rate) to " + frate + " [dec(Hex)]");
        debug_print("Set MCU framerate (==BSM ampling rate) to " + framerateHz + " [Hz]");
    }
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"      " + tstr + ": SpireProc_Set_BsmFramerate ended");
    //
}

// SpireSpectroPointLogic
//
// $Id:$
//
// This procedure selectes the SPIRE observing mode and calculates its instrument parameters  
//  for single pointing spectrometer observations
//
// This type of observation may be executed using either the SOF1 or SOF2 observing modes
//
// 10/03/2009 KJK: 
//       SCR 1274, add additional dummy parameters 
//       Update input API to include versions for all cal tables
// 17/03/2009 KJK:
//       Updated return values to put nCycles1 in nHCycles and nCycles2 
//       in nLCycles. Modified to set nCycles2 = 0 if only single resolution 
//       scans are requested.
// 25/08/2009 KJK:
//       SPR Spire-1641: Needed new input parameters bsmModel and bsmVersion
// 03/09/2009 KJK: 
//       Added smecVersion to input parameters
// 04/09/2009 MP:
//       Polish the header a bit ;-)
// 24/09/2009 KJK:
//       Updated call to SpireSOF12Pointing
// 29/09/2009 MP: SPR-SPIRE-2048
//       Fix bug with hardcoded SFlash for isBright. Here, update call to
//       SpireSOF12Observing.
// 16/02/2010 KJK: SCR Spire-2341:
//       Updated to call SpireSOF12Observing and SpireSOF12Pointing with additional parameter
//  20/07/2011 SDS:  SCR Spire-2563:
//                              opsVersion added in call to SpireSOF12Pointing
// 
/////////////////////////////////////////////////////////////////////////////
{{double,double,double,double,double,double}[],{double,double,double,double,double,double}[],bool,int,int,int,int,int,double,int,double} obs SpireSpectroPointLogic {
    double ra = 0.0 in [0.0,360.0]; // RA of Target
    double dec = 0.0 in [-90.0,90.0]; // DEC of Target
    int naifid = 0; // NAIF identifier
    string pointing = "single" in ["single","raster"]; // pointing type
    string sampling = "sparse" in ["sparse","intermediate","full"]; // spatial sampling
    string resolution = "H" in ["H","M","L","H+L"]; // spectral resolution
    bool choppingAvoidOn = false; // is chopping avoidance selected
    int choppingAvoidNumber = 0 in [0,3]; //  the number of chopping avoid angles selected
    double choppingAvoidFrom1 = 0.0 in [0.0,360.0];
    double choppingAvoidTo1 = 0.0 in [0.0,360.0];
    double choppingAvoidFrom2 = 0.0 in [0.0,360.0];
    double choppingAvoidTo2 = 0.0 in [0.0,360.0];
    double choppingAvoidFrom3 = 0.0 in [0.0,360.0];
    double choppingAvoidTo3 = 0.0 in [0.0,360.0];
    int nRepetitions1 = 2 in [2,1200]; // number of times to repeat spectral scan pairs for single resolution scan modes and high resolution in H+L mode
    int nRepetitions2 = 2 in [2,1200]; // number of times to repeat spectral scan pairs for low resolution scans for 'H+L" mode
    double wavelength1 = -1.0; // wavelength
    double wavelength2 = -1.0; // wavelength
    double wavelength3 = -1.0; // wavelength
    double wavelength4 = -1.0; // wavelength
    double wavelength5 = -1.0; // wavelength
    double wavelength6 = -1.0; // wavelength
    double wavelength7 = -1.0; // wavelength
    double wavelength8 = -1.0; // wavelength
    bool isJyContinuum = true; // is continuum specified in Jy rather than Wm-2um-1
    double lineFlux1 = -1.0; // line flux estimate
    double lineFlux2 = -1.0; // line flux estimate
    double lineFlux3 = -1.0; // line flux estimate
    double lineFlux4 = -1.0; // line flux estimate
    double lineFlux5 = -1.0; // line flux estimate
    double lineFlux6 = -1.0; // line flux estimate
    double lineFlux7 = -1.0; // line flux estimate
    double lineFlux8 = -1.0; // line flux estimate
    double contFlux1 = -1.0; // continuum flux estimate
    double contFlux2 = -1.0; // continuum flux estimate
    double contFlux3 = -1.0; // continuum flux estimate
    double contFlux4 = -1.0; // continuum flux estimate
    double contFlux5 = -1.0; // continuum flux estimate
    double contFlux6 = -1.0; // continuum flux estimate
    double contFlux7 = -1.0; // continuum flux estimate
    double contFlux8 = -1.0; // continuum flux estimate
    bool isBright = false;
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParms
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    string flashVersion = "v00"; // Version in cal table SpireTable_FlashParms
    string smecVersion = "v00"; // Version in cal table SpireTable_SpecModeParams
    string specVersion = "v00"; // Version in cal table SpireTable_Spectrometer
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // unused parameters
    string comVersion = "v00";
    string smodeVersion = smecVersion;
    smecVersion = "v00";
    //
    // check inputs
    if(pointing != "single") {
        error("SpireSpectroPointLogic: Pointing is not set to single");
    }
    SpireMsg(0,"Spectrometer Single Point Observation");
    // ********************************************
    //  Calculate possible pointing parameters
    // ********************************************
    //
    int nCycles1 = 0;
    int nCycles2 = 0;
    double tCycle1 = 0.0;
    double tCycle2 = 0.0;
    int scansPerCycle1 = 0;
    int scansPerCycle2 = 0;
    double osit1 = 0.0;
    double osit2 = 0.0;
    int nMaps = 0;
    int nFlashes = 0;
    double tFlash = 0.0;
    int nCals = 0;
    double tCal = 0.0;
    int tSlewMin = 0;
    int tInitHold = 0;
    int tFinalHold = 0;
    string ib = "";
    // instrument boresight
    double yOffset = 0.0;
    // offset to observation position from target in Y direction (arcsecs)
    double zOffset = 0.0;
    // offset to observation position from target in Z direction (arcsecs)
    double deltaY = 0.0;
    // offset to pixel centre from boresight in Y direction (arcsecs)
    double deltaZ = 0.0;
    // offset to pixel centre from boresight in Z direction (arcsecs)
    int tp = 0;
    // time per point
    //
    double[] wavelength = [wavelength1,wavelength2,wavelength3,wavelength4,wavelength5,wavelength6,wavelength7,wavelength8];
    double[] lineFlux = [lineFlux1,lineFlux2,lineFlux3,lineFlux4,lineFlux5,lineFlux6,lineFlux7,lineFlux8];
    double[] contFlux = [contFlux1,contFlux2,contFlux3,contFlux4,contFlux5,contFlux6,contFlux7,contFlux8];
    //
    // *****************************************
    //      select instrument ops mode    
    // *****************************************
    //       
    string opsMode = "";
    // opsMode
    int md = 0;
    // value of MODE parameter
    if(sampling == "sparse") {
        opsMode = "SOF1";
        md = 0x410;
    } else {
        if(sampling == "intermediate") {
            opsMode = "SOF2_int";
        } else {
            if(sampling == "full") {
                opsMode = "SOF2";
            } else {
                error("SpireSpectroPoint: Unknown sampling");
            }
        }
        md = 0x420;
    }
    //
    // *****************************************
    //      set up scan sets  
    // *****************************************
    //       
    string res1 = resolution;
    if(resolution == "H+L") {
        res1 = "H";
    }
    string res2 = "L";
    if(resolution != "H+L") {
        nRepetitions2 = 0;
    }
    // *****************************************
    // get observing parameters
    // *****************************************
    //
    ib = slookup("OpsParms.txt",opsMode,"Boresight");
    deltaY = dlookup("OpsParms.txt",opsMode,"DeltaY");
    // offset to pixel centre from boresight in Y direction (arcsecs)
    deltaZ = dlookup("OpsParms.txt",opsMode,"DeltaZ");
    // offset to pixel centre from boresight in Z direction (arcsecs)
    {int,double,int,double,int,double,int,double,int,int,double,int,double} sofObs = SpireSOF12Observing(opsMode,res1,res2,nRepetitions1,nRepetitions2,bsmVersion,smecVersion,specVersion,opsVersion,spireVersion,flashVersion,isBright,debug);
    nCycles1 = sofObs{0};
    tCycle1 = sofObs{1};
    scansPerCycle1 = sofObs{2};
    osit1 = sofObs{3};
    nCycles2 = sofObs{4};
    tCycle2 = sofObs{5};
    scansPerCycle2 = sofObs{6};
    osit2 = sofObs{7};
    nMaps = sofObs{8};
    nFlashes = sofObs{9};
    tFlash = sofObs{10};
    nCals = sofObs{11};
    tCal = sofObs{12};
    //
    {int,int,int,int,int,int} sofPoint = SpireSOF12Pointing(opsMode,res1,nCycles1,tCycle1,scansPerCycle1,res2,nCycles2,tCycle2,scansPerCycle2,nMaps,nFlashes,tFlash,isBright,bsmModel,bsmVersion,comVersion,spireVersion,smodeVersion,smecVersion,specVersion,flashVersion,opsVersion,debug);
    tSlewMin = sofPoint{0};
    tInitHold = sofPoint{1};
    tFinalHold = sofPoint{2};
    tp = sofPoint{3};
    // *****************************************
    // set telescope pointing mode
    // *****************************************
    //
    int[] ts = basic_fine_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,yOffset + deltaY,zOffset + deltaZ,tp);
}{
    // *********************************
    // Return instrument parameters
    // *********************************
    //
    {{double,double,double,double,double,double}[],{double,double,double,double,double,double}[]} estimates = SpireSOF12Estimate(resolution,osit1,osit2,wavelength1,wavelength2,wavelength3,wavelength4,wavelength5,wavelength6,wavelength7,wavelength8,lineFlux1,lineFlux2,lineFlux3,lineFlux4,lineFlux5,lineFlux6,lineFlux7,lineFlux8,isJyContinuum,contFlux1,contFlux2,contFlux3,contFlux4,contFlux5,contFlux6,contFlux7,contFlux8,isBright,specVersion,debug);
    //
    bool isChopped = false;
    //
    int nHCycles = nCycles1;
    int nMCycles = 0;
    int nLCycles = nCycles2;

    return {estimates{0},estimates{1},isChopped,nMaps,nHCycles,nMCycles,nLCycles,nCals,tCal,nFlashes,tFlash};
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Exec_SpecLoadCurvePcalOn.txt
//
///////////////////////////////////////////////////////////
//
//  Procedure to loop through a list of bias amplitudes 
//  for the 'Spec Load Curve Pcal On' task 
//
///////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/07/07 V0.1: Initial version adapted from
//                  SpireProc_Exec_PhotLoadCurvePcalOn (2009/04/01 V0.1)
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Exec_SpecLoadCurvePcalOn {
    int[] nbiaslist = [0,50,100,255]; // List of raw bias levels in range (0-255)
    int ftime = 10; // Readout time at each bias level [s]
    bool dcuData = false; // Is (==tick) the DCU currently sampled? 
    double pcal_bias = 3.8 in [0.0,7.0]; // PCAL bias level [mA]
    string version = "v01"; // Version in cal table SpireTable_PcalCurrentConvCoef
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Switch on PCAL:
    //
    SpireBb_PcalOn(pcal_bias,version,debug);
    // //
    // //
    // Start the LC bias loop:
    //
    for(int l = 0 .. length(nbiaslist) - 1) {
        // //
        // //
        // Safety check:
        //
        if(nbiaslist[l] > 255) {
            nbiaslist[l] = 255;
            if(debug) {
                debug_print("Input bias list is corrupt! Raw value > 255 requested!");
            }
        }
        // //
        // //
        // Set bias amplitude:
        //
        if(l == 0) {
            if(debug) {
                debug_print("Bias already set during slew");
            }
        } else {
            SpireBb_SpecFSetBiasAmpl(nbiaslist[l],nbiaslist[l],debug);
        }
        // //
        // //
        // Stop DCU data before resetting offsets:
        //
        SpireBb_StopDcuData();
        // //
        // //
        // Set offsets:
        //
        SpireBb_SpecOffsetAuto(dcuData,debug);
        // //
        // //
        // Take data:
        //
        SpireBb_SpecFTakeData(ftime,debug);
        // //
        // //
        // Debug printing: 
        //
        if(debug) {
            debug_print("Bias level " + nbiaslist[l] + " done.");
        }
    }
    // //
    // //
    // Switch off PCAL:
    //
    SpireBb_PcalOn(0.0,version,debug);
    //
}

//CLName: SpireBb_LoadTableSAFE
//VMVersion: 2.8
//CLVersion: 1.2
//CLCVSId: $ID$
//TableId: 0xd4
//TableLength: 0x19
//Date: 090306121957
block SpireBb_LoadTableSAFE SPIRE 3804 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableSAFE started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0xd4
    Spire_SET_TABLE(0xd4,0x19);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0xd4,0x0,25,[{0x60660000},{0x80007d0},{0x1000001},{0x80007d0},{0x120000ff},{0x0},{0x12000000},{0x18},{0x61060001},{0x12000000},{0x7},{0x6066000c},{0x60660006},{0xb002710},{0x1000000},{0x80007d0},{0x1000001},{0x80007d0},{0x60660002},{0x60660007},{0x80007d0},{0x1000000},{0x80007d0},{0x7f000000},{0x900}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0xd4,0x0,0x0);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableSAFE ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartSpecNonLinearity.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpireSpectro_Cal_NonLinearity
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/11/23 V0.1: Initial version adapted from
//                  SpireBb_StartScannedSmecBeamProfile (2009/10/28 V1.0)
// 2009/12/14 V0.2: Change BBid to free slot. 
// 
// Notes:
//    1) Scripts assumes that SpireBb_SpecOffsetAuto is run 
//       during INITHOLD or at first POINTING.
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartSpecNonLinearity SPIRE 3408 {
    string obsModeQla = "ENG_CAL_OBS45";
    string obsMode = "SEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartSpecNonLinearity configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    //delay(timeSlewCal);
    // //
    // //
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartSpecNonLinearity configuration ended");
    SpireMsg(1,"  ..StartScannedSmecBeamProfile took " + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_BsmMove2Hold.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to return BSM to hold position
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/09/08 V0.1: Initial version adapted from SpireBb_PhotChop 
//                  (2008/08/04 V0.2)
// 2008/10/13 V0.2: Adapt to name change of calibration file.
// 2008/11/06 V0.3: Change name 
// 2009/01/27 V1.0: Change call to calibration file. Add debug_print as input.
//                  Remove unsetting of BBID at end.  
// 2010/02/16 V1.1 KJK: SCR Spire-648: 
//                                  changed calls to Spire_SEND_DRCU_COMMAND to SpireSendDrcuCmd in order to generate messages
//                                  added start and end messages
//                                  added generation of Building Block messages
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_BsmMove2Hold SPIRE 14017 {
    string model = "initial"; // Model in calibration table
    string version = "v00"; // Version in cal file with nominal position
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_BsmMove2Hold started");
    SpireMsg(2,"          $Id$");
    // //
    // //
    // Define some variable:
    //
    string tabName = "SpireTable_BsmNominalSettings.txt";
    string selCol = "model";
    // Name of column for selecting 
    string selVal = model;
    // Value of 'string' selector
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    // //
    // //
    // Return BSM to hold position
    //  
    // Read hold position from calibration table:  
    string tarCol = "chop_0_I";
    int chop_hold = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int jigg_hold = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    if(debug) {
        debug_print("Setting BSM back to nominal position (chop/jigg): " + chop_hold + "/" + jigg_hold);
    }
    //
    // Set Jiggle Position:
    SpireSendDrcuCmd(0x91430000 + jigg_hold,0);
    delay(1);
    //
    // Set Chop position:
    SpireSendDrcuCmd(0x90c30000 + chop_hold,0);
    // 
    // Move BSM:
    // Move along the chop and jiggle axes independently:
    // SpireSendDrcuCmd(0x90c60001,0);
    // Move along the chop and jiggle axes synchrously:
    SpireSendDrcuCmd(0x90c60000,0);
    delay(1);
    //
    // completion
    sync();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB SpireBb_BsmMove2Hold  ended");
    SpireMsg(1,"  ..BSM Move2Hold (" + (time() - t0) + " seconds)");
}

command PacsCcuMonitorPeriodRecycle HFKACQP2 {
} {
    bus_schedule(SC, 6);
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartBsmPidTuning.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of SpirePhoto_Cal_BsmPidTuning.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/06 V0.1: Initial version adapted from
//                  SpireBb_StartBsmAngleCal (2009/05/05 V0.1) and
//                  SpirePhoto_Cal_BsmPidTuning (2009/04/01 V0.2).
//                  BB includes now to move BSM to hold.  
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartBsmPidTuning SPIRE 14056 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    string obsModeQla = "ENG_CAL_OBS14";
    string obsMode = "PEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_Phot/SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    bool setFramerate = true; //
    int frate = 0; //
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartBsmPidTuning configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    if(phot) {
        SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    }
    //delay(timeSlewCal);
    // //
    // //
    // Set MCU framerate (==BSM ampling rate):
    //
    if(setFramerate) {
        SpireProc_Set_BsmFramerate(frate,debug);
    }
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartBsmPidTuning configuration ended");
    SpireMsg(1,"  ..StartBsmPidTuning took " + (time() - t) + " seconds)");
    //
}

// SpireSOF2End
//
// $Id:$
//
// Building Block to reconfigure the instrument to SPEC_STBY mode from SOF2 mode
//
// 07/02/2009: KJK 
//       Now assumes SMEC is at scan start position (SPR-591)
// 25/08/2009: KJK
//       SPR Spire-1641: Now read BSM HOLD positions from 
//       SpireTable_BsmNominalSettings.txt rather than BSM.txt
//       Needed new input parameters bsmModel and bsmVersion
// 04/09/2009: MP 
//       SPR-SPIRE-1763 (problem1) Set MCU sampling rates back to STBY values;
//        Accept smecVersion as input. 
// 14/09/2009 KJK:
//       SCR Spire-1953: updated to reset detector phases
// 19/09/2009 KJK:  
//       SPR Spire-1979: Added call to SpireConfigDcuData to reset detector frequencies
// 24/09/2009 KJK:vSPR Spire-1978
//            reset biases if bright source settings used
// 29/09/2009 MP: SPR-SPIRE-2048
//       Fix bug with hardcoded SFlash for isBright, hardcode smodeVersion=v00 
//       in call to SpireProcSetBsmSampling and SpireProcSetSmecSampling.
// 20/10/2009 KJK: SPR Spire-2062
//       Open SMEC loop 
//
/////////////////////////////////////////////////////////////////////////////
block SpireBbSOF2End SPIRE 8386 {
    string res = "H";
    bool isBright = false in [true,false];
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string comVersion = "v00";
    string smodeVersion = "v00";
    string smecVersion = "v00";
    string specVersion = "v00";
    bool debug = false;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SOF2 Reconfiguration started");
    SpireMsg(2,"          $Id:$");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP to zero
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x0000)");
    Spire_SET_OBS_STEP_RAW(0x0);
    //
    // Move SMEC to HOME position
    int scanStart1 = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",res,"ScanStart",specVersion,debug);
    int smecHome = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"Home");
    SpireProc_SmecMove(smecHome,scanStart1,debug);
    //
    //  Open SMEC control loop
    SpireSendDrcuCmd(0x90440006,0);
    delay(4);
     //  
    // Move BSM to HOLD
    int bsmHoldChopPosn = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",bsmModel,"chop_0_I",bsmVersion,debug);
    int bsmHoldJiggPosn = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",bsmModel,"jigg_0_I",bsmVersion,debug);
    SpireBsmMove(bsmHoldChopPosn,bsmHoldJiggPosn);
    //
    // Set MCU sampling back to STBY
    //
    SpireProcSetBsmSampling("SPECSTBY","v00",debug);
    SpireProcSetSmecSampling("SPECSTBY","v00",debug);
    //
    //  reset detectors 
    //
    // reset bright-source biases and phases - if needed
    if(isBright) {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,"v00","v00",debug);
    } else {
        if(smodeVersion != "v00") {
            SpireProc_Set_SpecMode("SPECSTBY",isBright,"v00","v00",debug);
        } else {
            if(comVersion != "v00") {
                SpireProc_Set_SpecMode("SPECSTBY",isBright,"v00","v00",debug);
            }
        }
    }
    //
    // Set Mode to SPEC_STBY
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_MODE_RAW(0x0400)");
    Spire_SET_OBS_MODE_RAW(0x400);
    // 
    // Clear OBSID/BBID to null values
    tstr = SpireTimeStr(time());
    message("5          " + tstr + "Cmd: Spire_SET_BBID_RAW(0x80000000)");
    Spire_SET_BBID_RAW(0x80000000);
    int obsId = SpireNullObsid();
    tstr = SpireTimeStr(time());
    hstr = SpireHexStr(obsId,8);
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBSID_RAW(" + hstr + ")");
    Spire_SET_OBSID_RAW(obsId);
    sync();
    //
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SOF2 Reconfiguration ended");
    SpireMsg(1,"  ..SOF2 Reconfiguration to SPEC_STBY mode (" + (time() - t) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Exec_PtcPwr.txt
//
///////////////////////////////////////////////////////////
//
//  Procedure to loop through a list 
//
///////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/30 V0.1: Initial version adapted from
//                  SPIRE_IST_PTC_PWR (SDS, email 30.03.2009)
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Exec_PtcPwr {
    int[] ptc_curr = [0x0,0x200,0x400,0x600,0x800,0xa00,0xc00,0xe00,0xfff,0x0]; // 
    int ftime = 1200; // Time at each PTC Heater setting
    int twait = 300; // Wait time between setting PTC current and resetting offsets
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    int nptc = length(ptc_curr);
    int frames = 0;
    // //
    // //
    // Start DCU data:
    //
    SpireBb_StartDcuData();
    delay(30);
    // //
    // //
    // Loop over PTC heater current settings, starting DCU PF data first 
    //
    for(int i = 0 .. nptc - 1) {
        //
        SpireBb_PtcHtrCurr(ptc_curr[i],debug);
        // Wait for twait seconds before resetting offsets
        delay(twait);
        // //
        // //
        // Stop DCU data before resetting offsets:
        //
        SpireBb_StopDcuData();
        // //
        // //
        // Set offsets:
        //
        SpireBb_PhotOffsetAuto(debug);
        //
        // Take data for ftime-twait seconds, except at the start:
        //
        SpireBb_StartDcuData();
        //
        if(i == 0) {
            delay(twait);
        } else {
            delay(ftime - twait);
        }
    }
    // //
    // //
    // Stop DCU data at end:
    //
    SpireBb_StopDcuData();
    //
}

///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_PhotFovMapCrossRaster.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to calculate the positions of a cross raster to be used
//  in a custom_map pointing mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/04 V0.1: Initial version adapted from 
//                  SpireProc_CalcParam_FpgInitialPointing (V0.2)
//
///////////////////////////////////////////////////////////////////////////
//
{double[],double[],bool[]} procedure SpireProc_CalcParam_PhotFovMapCrossRaster {
    double d1 = 4.0 in [2.0,480.0]; // Angular stepsize along Y axis [arcsec] 
    double d2 = 4.0 in [2.0,480.0]; // Angular stepsize along Z axis [arcsec]
    int m = 5 in [3,2997]; // Number of points in the Y direction [odd number!]
    int k = 0 in [0,999]; // Additional visits to GCP on each hand of the cross
}{
    // //
    // //
    // Debug?
    //
    bool debug = true;
    //bool debug = false; 
    // //
    // //
    // Set fixed parameters:
    //
    int n = m;
    // Number of points in the Z direction [odd number!]
    // --> only symmetric cross raster allowed
    // //
    // //
    // Calculate arrays for custom_map pointing:
    //
    double[] yarray = [0.0];
    double[] zarray = [0.0];
    bool[] raster = [false];
    //
    // Set center as starting point:
    //
    yarray[0] = 0.0;
    zarray[0] = 0.0;
    raster[0] = false;
    //
    // Setup:
    //
    int index = 1;
    int zindex = 1;
    int ystart = -1 * iceil(0.5 * double(m - 1));
    int zstart = -1 * iceil(0.5 * double(n - 1));
    int numtrue = iceil(0.5 * double(m - 1) / double(k + 1));
    int nysteps = -2 * ystart + 1;
    int nzsteps = -2 * zstart + 1;
    if(debug) {
        debug_print("ystart/zstart: " + ystart + "/" + zstart);
        debug_print("numtrue: " + numtrue);
    }
    //
    // Y-axis:
    //
    do {
        if(debug) {
            debug_print("Setting up Y-axis");
        }
        yarray[index] = double(ystart) * d1 + double(index - 1) * d1;
        zarray[index] = 0.0;
        // Mark GCPs:
        if(yarray[index] == 0.0) {
            raster[index] = false;
        } else {
            raster[index] = true;
        }
        index = index + 1;
    } while (index < nysteps + 1);
    //
    // Add visit to center at end of Y-raster:
    //
    yarray[index] = 0.0;
    zarray[index] = 0.0;
    raster[index] = false;
    index = index + 1;
    //
    // Z-axis:
    //
    do {
        if(debug) {
            debug_print("Setting up Z-axis");
        }
        zarray[index] = double(zstart) * d2 + double(zindex - 1) * d2;
        yarray[index] = 0.0;
        if(zarray[index] == 0.0) {
            raster[index] = false;
        } else {
            raster[index] = true;
        }
        index = index + 1;
        zindex = zindex + 1;
    } while (zindex < nzsteps + 1);
    //
    // Add visit to center at end:
    //
    yarray[index] = 0.0;
    zarray[index] = 0.0;
    raster[index] = false;
    //
    // printing:
    //
    if(debug) {
        debug_print("yarray: " + yarray);
        debug_print("zarray: " + zarray);
        debug_print("raster: " + raster);
        debug_print("length(ystart/zstart/raster): " + length(yarray) + "/" + length(zarray) + "/" + length(raster));
    }
    // //
    // //
    // Add additional visits to GCP:
    //
    double[] yarray_new = [0.0];
    double[] zarray_new = [0.0];
    bool[] raster_new = [false];
    //
    int end = length(raster);
    int nindex = 0;
    int tcount = 0;
    for(int counter = 1 .. end) {
        if(debug) {
            debug_print("Loop number: " + counter);
            debug_print("end: " + end);
            debug_print("nindex: " + nindex);
            debug_print("tcount: " + tcount);
        }
        if(raster[counter - 1] == true) {
            if(tcount == numtrue) {
                // Check if next point is not a visit to GCP:
                //if (raster[(counter)] == true)
                //{
                debug_print("Add visit to GCP!");
                yarray_new[nindex] = 0.0;
                zarray_new[nindex] = 0.0;
                raster_new[nindex] = false;
                nindex = nindex + 1;
                //}
                yarray_new[nindex] = yarray[counter - 1];
                zarray_new[nindex] = zarray[counter - 1];
                raster_new[nindex] = true;
                nindex = nindex + 1;
                // Reset tcount
                tcount = 0;
            } else {
                yarray_new[nindex] = yarray[counter - 1];
                zarray_new[nindex] = zarray[counter - 1];
                raster_new[nindex] = true;
                nindex = nindex + 1;
            }
            tcount = tcount + 1;
        } else {
            // reset true counter:
            tcount = 0;
            yarray_new[nindex] = yarray[counter - 1];
            zarray_new[nindex] = zarray[counter - 1];
            raster_new[nindex] = false;
            nindex = nindex + 1;
        }
        counter = counter + 1;
    }
    //
    if(debug) {
        debug_print("yarray: " + yarray_new);
        debug_print("zarray: " + zarray_new);
        debug_print("raster: " + raster_new);
        debug_print("length(ystart/zstart/raster): " + length(yarray_new) + "/" + length(zarray_new) + "/" + length(raster_new));
    }
    //

    return {zarray_new,yarray_new,raster_new};
}

block SpireBb_StopMonitoring SPIRE 3411 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_StopMonitoring started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    // //
    // Start on-board monitoring:
    //
    Spire_STOP_MONITORING_RAW();
    delay(5);
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_StopMonitoring ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_PcalFlash.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to perform photometer PCAL flash via VM 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/11/07 V0.1: Initial version adapted from
//                  SpireBb_PcalFlash (2009/02/13 V1.3)
//
// Note: VM does not reset dcusample/bsmsample at end, so this needs 
//       to be done in the surrounding end script. 
// Sunil Sidher:
// 2009/07/31 V0.2: Inserted command to set DCU sampling to continuous  after PCAL Flash (to fix SPIRE SPR-1587)        
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_PcalFlash {
    int vmId = 0x46;
    int vmIndex = 0;
    int nParms = 9;
    int pcal_lowbias = 100;
    int pcal_highbias = 2000;
    int pcal_ncycles = 8;
    int pcal_period = 250000;
    int pcal_dcumode = 3;
    int pcal_ndcusamples = 11;
    int pcal_dcudelay = 12000;
    int pcal_scumode = 0;
    int pcal_scusamples = 9;
    int step = 0;
    bool debug = false;
}{
    // //
    // //
    // Define some variables:
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start procedure:
    //
    message("4    " + time() + ": SpireProc_PcalFlash started");
    message("4          $Id: $");
    // //
    // //
    // Set HSK OBSTEP parameter:
    //
    SpireProc_Set_ObsStep(step,debug);
    // //
    // //
    // Reset all fifos:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RESET_FIFOS(0x7000)");
    Spire_RESET_FIFOS(0x7000);
    delay(1);
    // //
    // //
    // Setup VM:
    //
    {int}[] pcalParams = [{pcal_lowbias},{pcal_highbias},{pcal_ncycles},{pcal_period},{pcal_dcumode},{pcal_ndcusamples},{pcal_dcudelay},{pcal_scumode},{pcal_scusamples}];
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM_RAW(" + vmId + "," + vmIndex + "," + nParms + "," + pcalParams + ")");
    // //
    // //
    // Start VM:
    //
    Spire_RUN_VM(vmId,vmIndex,nParms,pcalParams);
    //
    // Calculate wait time:
    int wait_time = pcal_period * pcal_ncycles / 1000000 + 1;
    if(debug) {
        debug_print("Wait time will be :" + " " + wait_time + " " + "sec");
    }
    // //
    // //
    // Wait for VM to finish (exclude data rate setting):
    //
    delay(wait_time);
    // //
    // //
    // Flush all fifos (all, in case MCU data is being generated)
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFOS(0x7000)");
    Spire_FLUSH_FIFO(0x7000);
    delay(2);
    // //
    // //
    // Set PCAL bias to zero:
    //
    SpireSendDrcuCmd(0xa0c80000,0);
    SpireSendDrcuCmd(0x843d0000,0);
    delay(1);
    // //
    // //
    // Round up total duration:
    //
    sync();
    // //
    // //
    // End procedure:
    //
    message("4    " + time() + ": SpireProc_Set_PcalFlash ended");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_PhotFTakeData.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to start taking data with photometer arrays
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/05/02 V0.1: Initial version adapted from 
//                  PF_Data_QLA (v1.4 2008/01/31 20:24:34)
// 2008/07/04 V0.2: Renumber version; Add comment to replace '?'; 
//                  add RESET_FIFO at start
// 2009/01/31 V1.0: Add debug_print option. Replace delay(1) with delay(2)
//                  after FLUSH_FIFO. Remove unsetting of BBID.
// 2009/06/05 V1.1: Replace Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd 
//                  as requested in SPR-1482.
//
//  Note: - BB assumes no DCU data is taken when started!
//        - BB still includes nonessential setting of data mode (0x843c0000)
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_PhotFTakeData SPIRE 14008 {
    int ftime = 0x0; //Time for data generation (if frames are continuous)
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Set fixed (for flight) parameters:
    //
    // int frames = 0; //Default (IST) number of frames to request 
    //                (do not use frames, but only ftime to select time)
    // --> frames was not used in original PF_Data_QLA script!
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    Spire_SET_BBID($BBID);
    //delay(1);
    // //
    // //
    // Reset DCU (x1000) fifo:
    //
    Spire_RESET_FIFOS(0x1000);
    delay(1);
    // //
    // //
    // Set data mode to 'photometer full array':
    //
    SpireSendDrcuCmd(0x843c0000,0);
    //delay(1);
    // //
    // //
    // Start data collection:
    //
    SpireSendDrcuCmd(0x843e0001,0);
    // //
    // //
    // Wait for data to be taken:
    //
    delay(ftime);
    // //
    // //
    // Stop data collection:
    //
    SpireSendDrcuCmd(0x843e0000,0);
    //delay(1);
    // //
    // //
    // Flush DCU fifo:
    //
    Spire_FLUSH_FIFO(0x1000);
    delay(2);
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StopDcuData.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to stop generation of detector data TM packets
//
// Note: Script calls the procedure SpireProc_Set_StopDcuData.  
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/01/26 V1.0: Initial version adapted from 
//                  SpireBb_StopDcuData (2008/07/03 V0.2) merging it with
//                  SpireBbStopDcuData.txt (KK, 02 April 2007) and removing
//                  the un-setting of the BBID. 
// 2009/01/30 V1.1: Minor change in placing script comments. Added delay(1)
//                  after SET_BBID.
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StopDcuData SPIRE 14003 {
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    message("4    " + time() + ": SpireBb_StopDcuData started");
    message("4          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    delay(1);
    // //
    // //
    // Stop data collection:
    //
    SpireProc_Set_StopDcuData();
    // //
    // //
    // End BB:
    //
    SpireMsg(4,"    " + time() + ": BB SpireBb_StopDcuData ended");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_PhaseUp.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to calculate the parameters needed for a Phot/Spec Phase Up.  
//  It creates and returns a list of raw phases to be stepped through,
// 
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/11 V0.1: Initial version renamed from
//                  SpireProc_CalcParam_PhotPhaseUp (2008/07/03 V0.2)
//                  which was adapted from 
//                  Mode_ILT_PERF_DPH_P.txt (v1.4 2008/01/31 20:24:33)
// 2009/02/01 V1.0: Add debug_print as input
//
///////////////////////////////////////////////////////////////////////////
//
int[] procedure SpireProc_CalcParam_PhaseUp {
    double target_phase = 0.0 in [0.0,360.0]; // Central phase shift (target phase) [degree]
    int number_steps = 1 in [1,127]; // Number of steps to one side [int]
    int step_size = 1 in [1,20]; // Raw step size (1 step==1.411 degrees) [dec(HEX)]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Calculate total number of steps:
    //
    int n_steps = 2 * number_steps + 1;
    if(debug) {
        debug_print("Numbers of steps requested: " + n_steps);
    }
    //
    // //
    // //
    // Get the central point of the list in raw units:
    //
    int raw_target_phase = iround(target_phase * 255.0 / 360.0);
    if(debug) {
        debug_print("The requested phase is: " + target_phase);
        debug_print("The associated raw value is: " + raw_target_phase);
    }
    //
    // //
    // //
    // Get the starting point of the list in raw units:
    //
    int raw_start_phase = raw_target_phase - number_steps * step_size;
    if(debug) {
        debug_print("the raw phase @start is :" + raw_start_phase);
    }
    //
    // //
    // //
    // Create list of phases:
    //
    int[] raw_phase_list = [0];
    double[] phase_list = [0.0];
    double low_limit = 0.0;
    double high_limit = 360.0;
    double resol = 360.0 / 255.0;
    double k = 0.0;
    //
    for(int i = 0 .. n_steps - 1) {
        raw_phase_list[i] = raw_start_phase + step_size * i;
        phase_list[i] = double(raw_phase_list[i]) * resol;
        if(debug) {
            debug_print("the phase for step " + i + " is: " + phase_list[i]);
        }
        // //
        // //
        // Check if phase is 0 <= phase <= 2*pi:
        //
        if(phase_list[i] < low_limit) {
            k = 1.0;
        } else {
            if(phase_list[i] > high_limit) {
                k = -1.0;
            } else {
                k = 0.0;
            }
        }
        if(debug) {
            debug_print("The value of k for step" + " " + i + " " + "  is :" + k);
        }
        //
        // Adapt raw phase list if outside 0 <= phase <= 2*pi:
        //
        raw_phase_list[i] = iround((phase_list[i] + k * 360.0) * (255.0 / 360.0));
    }
    //
    if(debug) {
        debug_print("Final raw phase list: " + raw_phase_list);
        debug_print("Imput phase list in [deg]: " + phase_list);
    }
    //

    return raw_phase_list;
}

// SpirePhotoLargeScan
//
// $Id: $
//
// Implementation of a scan map observation without chopping
//
// Assumptions:
//    1. the instrument is in the PHOT_STBY configuration on entry
//
//  13/04/07:  v1.11: SPR 3010 - added option to select between two scan rates
//                    SPR 3043 - added option to select scan direction(s)
//  20/04/07:  v1.12: SPR 3125 - return values based on mapOsit, not SrcTime
//  26/04/07:  v1.13: SPR 3148 - calculate patt correctly for each mode
//  27/04/07:  v1.14: SPR 3150 
//  14/02/07:  v1.15:          - moved StartDCU Data building block from optional part of initial_hold activities to be always executed
//                               otherwise detectordata taking will not be started at all
//
// 04 November 2008: added data_rate commands
// 10/03/2009 KJK: 
//         SCR 1274, add additional dummy parameters 
//         Update input API to include versions for all cal tables
//  02/07/2009  KJK:
//         Added configuration input parameters to pass to SpirePOF5Config, SpirePOF5Pointing and SpirePOF5End
//  05/07/2009 KJK:
//         SPR-1593 - Updated calls to SpirePOF5Pointing and SpireBbPcalFlash to use flashVersion 
//  10/08/2009 KJK:
//         SPR-1709:  Added new input parameter, comVersion to call to SpreBbPOF5Config
//  15/08/2009 MP (SCR-SPIRE-1818): Allow selection of scan angle/speed 
//             via version; needs change to SpirePOF5Pointing
//  16/08/2009 MP (SCR-SPIRE-1818): Change call to SpirePOF5Observing
//  10/09/2009 KJK: Modified call to SpirePOF5Pointing
//  15/09/2009 KJK: Update to call SpireBbPOF5Init with obsMode parameter
//  15/02/2010 KJK: SCR Spire-1887:
//                             Updated to use SpireTable_SpireParams to determine the initFlash and endFlash flags status
//                             Added spireVersion to input parameters for call to SpirePOF5Observing
//
///////////////////////////////////////////////////////////////////////////////
{int,int,int,int} obs SpirePhotoLargeScan {
    double ra = 0.0 in [0.0,360.0]; // RA of Target
    double dec = 0.0 in [-90.0,90.0]; // DEC of Target
    int naifid = 0; // NAIF identifier
    string source = "large" in ["point","small","large"]; // source type
    string scanDirection = "scanab" in ["scana","scanb","scanab"];
    double mapSize1 = 4.0 in [4.0,1200.0]; // mapSize1 [arc minutes]
    double mapSize2 = 0.0 in [0.0,240.0]; // mapSize2 [arc minutes]
    double mapOffsetY = 0.0 in [-300.0,300.0]; // mapOffsetY [arc minutes]
    double mapOffsetZ = 0.0 in [-300.0,300.0]; // mapOffsetZ [arc minutes]
    string mapScanRate = "nominal" in ["nominal","fast"]; // selected scan rate
    bool mapOrientationArray = true; // is the map orientation an array (rather than array with constraints)
    double mapOrientationConFrom = 0.0 in [0.0,360.0];
    double mapOrientationConTo = 360.0 in [0.0,360.0];
    int nRepetitions = 1 in [1,100]; // number of  map repeats
    double sourceFluxPSW = -1.0;
    double sourceFluxPMW = -1.0;
    double sourceFluxPLW = -1.0;
    double sourceBrightPSW = -1.0;
    double sourceBrightPMW = -1.0;
    double sourceBrightPLW = -1.0;
    bool isBright = false; // Use settings for bright source (==tick)
    bool isRasterMap = false;
    int nRasters = 1; // number of times to repeat map
    int nPoints = 1; // not used
    int nMaps = 1; // not used
    int nCycles = 1; // not used
    int nNodInts = 1; // not used
    int nLines = 1; // number of scan lines in map
    int nCal = 999999; // number of lines between Gyro calibrations
    int nFlash = 999999; // number of lines between PCAL flashes
    int nLinesx = 1; // number of scan lines in cross scan map
    int nCalx = 999999; // number of lines between Gyro calibrations in cross scan map
    int nFlashx = 999999; // number of lines between PCAL flashes in cross scan map
    string bsmModel = "initial";
    string bsmVersion = "v00"; // Version in cal table SpireTable_BsmNominalSettings.txt
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParms
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    string flashVersion = "v00"; // Version in cal table SpireTable_FlashParms
    string photVersion = "v00"; // Version in cal table SpireTable_PhotModeParams.txt
    string comVersion = "v00"; // Version in cal table SpireTable_CommonModeParams.txt
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // check inputs
    if(source != "large") {
        error("SpirePhotoLargeScan: Source is not a large map");
    }
    if(isRasterMap) {
        error("SpirePhotoLargeScan: Raster Map Selected");
    }
    if(scanDirection == "scanab" && mapSize1 > 240.0) {
        error("SpirePhotoLargeLogic: Scan length too big (>240.0 arcmin) ");
    }
    // //
    // //
    // Declare some variables:
    //
    int tSlewMin = 0;
    int tInitHold = 0;
    int tFinalHold = 0;
    int tHold = 0;
    int nHold = 0;
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string selValN = "";
    string selValO = "";
    string tarCol = "";
    string version = "";
    double patt = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName05 = "SpireTable_OpsParms.txt";
    //
    // *****************************************
    //      set up telescope pointing mode    
    // *****************************************
    //
    string obsMode = "POF5";
    if(mapScanRate == "fast") {
        obsMode = obsMode + "_F";
    } else {
        obsMode = obsMode + "_S";
    }
    string obsModeN = obsMode + "_N";
    string obsModeO = obsMode + "_O";
    if(debug) {
        debug_print("Selected obsMode: " + obsModeN + "/" + obsModeO);
    }
    // //
    // //
    // Select scan angle from calibration table:
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "Patt";
    version = opsVersion;
    //
    // Selection depending on direction of scan:
    // 
    if(scanDirection == "scana") {
        patt = SpireProc_GetTableEntryDouble(tabName,selCol,selValN,tarCol,version,debug);
    }
    if(scanDirection == "scanb") {
        patt = SpireProc_GetTableEntryDouble(tabName,selCol,selValO,tarCol,version,debug);
    }
    if(scanDirection == "scanab") {
        patt = SpireProc_GetTableEntryDouble(tabName,selCol,selValN,tarCol,version,debug);
    }
    // //
    // //
    // Select number of map repetitions (nMaps) from calibration table:
    // (incl. calculation of pof5Obs parameters)
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "NMaps";
    version = opsVersion;
    //
    // Selection depending on direction of scan:
    //  
    {double,double,int,int,int,int} pof5Obs = {0.0,0.0,0,0,0,0};
    if(scanDirection == "scana") {
        nMaps = SpireProc_GetTableEntryInt(tabName,selCol,selValN,tarCol,version,debug);
        pof5Obs = SpirePOF5Observing(obsModeN,nRepetitions * nMaps,mapSize1,mapSize2,opsVersion,spireVersion,debug);
    }
    if(scanDirection == "scanb") {
        nMaps = SpireProc_GetTableEntryInt(tabName,selCol,selValO,tarCol,version,debug);
        pof5Obs = SpirePOF5Observing(obsModeO,nRepetitions * nMaps,mapSize1,mapSize2,opsVersion,spireVersion,debug);
    }
    if(scanDirection == "scanab") {
        if(debug) {
            debug_print("nMaps/scanab path:");
            debug_print("tabName: " + tabName);
            debug_print("selCols: " + selCol);
            debug_print("selValN: " + selValN);
            debug_print("selValN: " + selValN);
            debug_print("tarCol: " + tarCol);
            debug_print("version: " + version);
        }
        nMaps = SpireProc_GetTableEntryInt(tabName,selCol,selValN,tarCol,version,debug);
        pof5Obs = SpirePOF5Observing(obsModeN,nMaps,mapSize1,mapSize2,opsVersion,spireVersion,debug);
    }
    double mapOsit = pof5Obs{0};
    double d1 = pof5Obs{1};
    int nRepeats = pof5Obs{2};
    //
    // //
    // //
    // Calculate further pointing mode input parameters:
    //
    {int,int,int,int,int,double,double} pof5Point = {0,0,0,0,0,0.0,0.0};
    if(scanDirection == "scanb") {
        pof5Point = SpirePOF5Pointing(obsModeO,nRepeats,nLines,nCal,nFlash,isBright,bsmModel,bsmVersion,spireVersion,flashVersion,photVersion,comVersion,opsVersion,debug);
    } else {
        pof5Point = SpirePOF5Pointing(obsModeN,nRepeats,nLines,nCal,nFlash,isBright,bsmModel,bsmVersion,spireVersion,flashVersion,photVersion,comVersion,opsVersion,debug);
    }
    tSlewMin = pof5Point{0};
    tInitHold = pof5Point{1};
    tFinalHold = pof5Point{2};
    tHold = pof5Point{3};
    nHold = pof5Point{4};
    double d2 = pof5Point{5};
    double rate = pof5Point{6};
    // //
    // //
    // Calculate further cross scan parameters:
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "NMaps";
    version = opsVersion;
    //
    if(scanDirection == "scanab") {
        if(debug) {
            debug_print("x calculation");
        }
        nMaps = SpireProc_GetTableEntryInt(tabName,selCol,selValO,tarCol,version,debug);
        double mapOsitx = 0.0;
        // observing mode parameters
        {double,double,int,int,int,int} pof5Obsx = {0.0,0.0,0,0,0,0};
        pof5Obsx = SpirePOF5Observing(obsModeO,nMaps,mapSize2,mapSize1,opsVersion,spireVersion,debug);
        mapOsitx = pof5Obsx{0};
        double d1x = pof5Obsx{1};
        int nRepeatsx = pof5Obsx{2};
        //
        // pointing mode input parameters:
        {int,int,int,int,int,double,double} pof5Pointx = {0,0,0,0,0,0.0,0.0};
        pof5Pointx = SpirePOF5Pointing(obsModeO,nRepeatsx,nLinesx,nCalx,nFlashx,isBright,bsmModel,bsmVersion,spireVersion,flashVersion,photVersion,comVersion,opsVersion,debug);
        int nHoldx = pof5Pointx{4};
        double d2x = pof5Pointx{5};
        //
        // Lookup direction of cross scan:
        //
        tabName = tabName05;
        selCol = "mode";
        selValN = obsModeN;
        selValO = obsModeO;
        tarCol = "Patt";
        version = opsVersion;
        double pattx = SpireProc_GetTableEntryDouble(tabName,selCol,selValO,tarCol,version,debug);
    }
    // //
    // //
    // Calculate further pointing mode pointing parameters:
    //
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "Boresight";
    version = opsVersion;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selValN,tarCol,version,debug);
    //
    // Lookup offset to pixel centre from boresight in Y direction (arcsecs):
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "DeltaY";
    version = opsVersion;
    double deltaY = SpireProc_GetTableEntryDouble(tabName,selCol,selValN,tarCol,version,debug);
    //
    // Lookup offset to pixel centre from boresight in Z direction (arcsecs)
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "DeltaZ";
    version = opsVersion;
    double deltaZ = SpireProc_GetTableEntryDouble(tabName,selCol,selValN,tarCol,version,debug);
    //
    // Lookup pattern angle definition:
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "Fixed";
    version = opsVersion;
    bool fixed = SpireProc_GetTableEntryBool(tabName,selCol,selValN,tarCol,version,debug);
    // //
    // //
    // Calculate further offsets:
    //
    // offset to observation position from target in Y direction (arcsecs):
    //
    double yOffset = mapOffsetY * 60.0 + deltaY;
    //
    // offset to observation position from target in Z direction (arcsecs):
    //
    double zOffset = mapOffsetZ * 60.0 + deltaZ;
    //
    // fetch timing information
    //
    if(debug) {
        debug_print("fetch timing information");
    }
    // initial flash flag
    bool initFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsModeN,"InitFlash",spireVersion,debug);
    // final flash flag
    bool endFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsModeN,"EndFlash",spireVersion,debug);
    int tFlash = duration(SpireBbPcalFlash("PFlash",flashVersion,0,debug));
    // time for a PCAL flash
    if(debug) {
        debug_print("Calculate tSerendipity");
    }
    int tSerendipity = duration(SpireBbPhotSerendipity(obsModeN,0));
    // minimum time for a serendipity observation
    //
    //
    // ****** execute telescope pointing mode ******
    //
    int[] ts = [];
    if(scanDirection == "scanab") {
        ts = cross_scan_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,fixed,patt,yOffset,zOffset,nLines,d1,d2,rate,tHold,nHold,nRepetitions,nMaps,pattx,nLinesx,d1x,d2x,nHoldx);
    } else {
        ts = line_scan_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,fixed,patt,yOffset,zOffset,nLines,d1,d2,rate,tHold,nHold,nRepeats);
    }
    //
}{
    // *****************************************
    //   Display input parameters
    // *****************************************
    SpireMsg(3,"     POF5 Input values:");
    SpireMsg(3,"     ..RA: " + ra);
    SpireMsg(3,"     ..Dec: " + dec);
    SpireMsg(3,"     ..NAIF ID: " + naifid);
    SpireMsg(3,"     ..mapSize1: " + mapSize1);
    SpireMsg(3,"     ..mapSize2: " + mapSize2);
    SpireMsg(3,"     ..Y Offset: " + yOffset);
    SpireMsg(3,"     ..Z Offset: " + zOffset);
    SpireMsg(3,"     ..No of Map Repeats: " + nRepeats);
    SpireMsg(3,"     ..No of Lines: " + nLines);
    // SpireMsg(3,"     ..No of lines between Gyro Calibrations: " + nCal);
    SpireMsg(3,"     ..No of lines between Flashes: " + nFlash);
    SpireMsg(3,"     ..No of Map Repeats: " + nRepeats);
    SpireMsg(3,"     ..No of Lines in cross-scan map: " + nLines);
    // SpireMsg(3,"     ..No of lines between Gyro Calibrations in cross-scan map: " + nCal);
    SpireMsg(3,"     ..No of lines between Flashes in cross-scan map: " + nFlash);
    SpireMsg(3,"     POF5 Fixed values:");
    SpireMsg(3,"     ..ib: " + ib);
    SpireMsg(3,"     ..patt: " + patt);
    SpireMsg(3,"     ..d2: " + d2);
    SpireMsg(3,"     ..rate: " + rate);
    SpireMsg(3,"     ..initFlash: " + initFlash);
    SpireMsg(3,"     ..endFlash: " + endFlash);
    if(scanDirection == "scanab") {
        SpireMsg(3,"     Cross Scan Pointing Mode Input values:");
        SpireMsg(3,"     ..tSlewMin: " + tSlewMin);
        SpireMsg(3,"     ..tInitHold: " + tInitHold);
        SpireMsg(3,"     ..tFInalHold: " + tFinalHold);
        SpireMsg(3,"     ..nLines: " + nLines);
        SpireMsg(3,"     ..d1: " + d1);
        SpireMsg(3,"     ..tHold: " + tHold);
        SpireMsg(3,"     ..nHold: " + nHold);
        SpireMsg(3,"     ..nLinesx: " + nLinesx);
        SpireMsg(3,"     ..d1x: " + d1x);
        SpireMsg(3,"     ..nHoldx: " + nHoldx);
        SpireMsg(3,"     Cross Scan Pointing Mode Output values:");
        SpireMsg(3,"     ..tobs: " + ts[0]);
        SpireMsg(3,"     ..tslew: " + ts[1]);
        SpireMsg(3,"     ..tacc: " + ts[2]);
        SpireMsg(3,"     ..tdec: " + ts[3]);
        SpireMsg(3,"     ..tl: " + ts[4]);
        SpireMsg(3,"     ..tll: " + ts[5]);
        SpireMsg(3,"     ..trep: " + ts[6]);
        SpireMsg(3,"     ..tlx: " + ts[7]);
        SpireMsg(3,"     ..tllx: " + ts[8]);
        SpireMsg(3,"     ..tcross: " + ts[9]);
        SpireMsg(3,"     ..trev: " + ts[10]);
        SpireMsg(3,"     ..tend: " + ts[11]);
    } else {
        SpireMsg(3,"     Line Scan with Hold Pointing Mode Input values:");
        SpireMsg(3,"     ..tSlewMin: " + tSlewMin);
        SpireMsg(3,"     ..tInitHold: " + tInitHold);
        SpireMsg(3,"     ..tFInalHold: " + tFinalHold);
        SpireMsg(3,"     ..nLines: " + nLines);
        SpireMsg(3,"     ..d1: " + d1);
        SpireMsg(3,"     ..tHold: " + tHold);
        SpireMsg(3,"     ..nHold: " + nHold);
        SpireMsg(3,"     Line Scan Pointing Mode Output values:");
        SpireMsg(3,"     ..tobs: " + ts[0]);
        SpireMsg(3,"     ..tslew: " + ts[1]);
        SpireMsg(3,"     ..tacc: " + ts[2]);
        SpireMsg(3,"     ..tdec: " + ts[3]);
        SpireMsg(3,"     ..tl: " + ts[4]);
        SpireMsg(3,"     ..tll: " + ts[5]);
        SpireMsg(3,"     ..trep: " + ts[6]);
        SpireMsg(3,"     ..tend: " + ts[7]);
    }
    // *****************************************
    //   execute observation
    // *****************************************
    SpireMsg(0,"Observation Start");
    SpireMsg(0,"  Uses observing mode POF5 (Scan Map)");
    SpireMsg(3,"       $Id: $");
    data_rate(0.0);
    double chkrate = SpireProc_GetTableEntryDouble("SpireTable_Datarates.txt","mode",obsModeN,"CHK","v00",debug);
    ess_hk_data_rate(chkrate);
    double nhkrate = SpireProc_GetTableEntryDouble("SpireTable_Datarates.txt","mode",obsModeN,"NHK","v00",debug);
    non_ess_hk_data_rate(nhkrate);
    //
    //??p pointing file generation ------------------------------
    //??double pos = 90.0;
    //??double[] rdp0 = PtOffset([ra,dec,pos],zOffset,yOffset,0.0,false);
    //??p pointing file generation ------------------------------
    //
    bool relative = true;
    int tslew = ts[1];
    // slew time
    int tl = ts[4];
    // time for line scan
    int tlx = ts[7];
    // time for cross-scan line scan
    string tstr = "";
    // time string
    int otf = 0x8000;
    // On Target Flag
    double srcTime = 0.0;
    //  total on source integration time
    int nl = 0;
    // line counter
    double s = 0.0;
    int x = 0;
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // ***********************  SLEWING
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Slewing to start position");
            // set up observation parameters
            SpireBbObsConfig(0x350);
            // perform serendipity operation if possible
            if(tslew > tSerendipity + tSlewMin) {
                SpireBbPhotSerendipity(obsModeN,tslew - tSlewMin - 2);
            }
            // configure instrument for operations
            SpireBbPOF5Config(obsModeN,isBright,bsmModel,bsmVersion,photVersion,comVersion,debug);
        }
        if(state[0] == 2) {
            // ***********************  INITIAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Initialising Instrument");
            // initialise instrument
            SpireBbPOF5Init(obsModeN);
            // calibrate if necessary
            if(initFlash || nFlash < nLines) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireBbPcalFlash("PFlash",flashVersion,otf,debug);
            }
            SpireBbStartDcuData(obsModeN);
        }
        if(state[0] == 5) {
            // ***********************  FINAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Reconfiguring Instrument");
            SpireBbStopDcuData();
            // calibrate if necessary
            if(endFlash && nHold != nLines) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireBbPcalFlash("PFlash",flashVersion,otf | nl,debug);
            }
            // reconfigure back to PHOT_STBY configuration
            SpireBbPOF5End("PHTSTBY",isBright,bsmModel,bsmVersion,photVersion,comVersion,debug);
        }
        if(state[0] == 6) {
            // ***********************  HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
            SpireBbStopDcuData();
            SpireBbPcalFlash("PFlash",flashVersion,otf | nl,debug);
            SpireBbStartDcuData(obsModeN);
        }
        if(state[0] == 8) {
            // ***********************  SCAN
            //??p pointing file generation ------------------------------
            int line = state[2];
            if(scanDirection == "scanab") {
                x = state[4];
            } else {
                x = 0;
            }
            int t = time();
            //??p pointing file generation ------------------------------
            //??p PtScanStart(rdp0,line,nCycles,d1,d2,patt,relative);
            tstr = SpireTimeStr(time());
            if(x == 0) {
                SpireMsg(2,"    " + tstr + " Instrument scanning");
                SpireMsg(2,"    " + tstr + " Line " + line);
                s = SpireBbScanLine(tl,otf | nl);
                wait_until(t + tl);
            } else {
                SpireMsg(2,"    " + tstr + " Instrument cross-scanning");
                SpireMsg(2,"    " + tstr + " Map " + x + ", Line " + line);
                s = SpireBbScanLine(tlx,otf | nl);
                wait_until(t + tlx);
            }
            //??p pointing file generation ------------------------------
            //??p PtScanStop(rdp0,line,nCycles,d1,d2,patt,relative);
            srcTime = srcTime + s;
            nl = nl + 1;
            SpireBbMove(0);
        }
    }
    assert (time() == ts[0] + ts[1]);
    //
    // finish observation
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + " Instrument Reconfigured");
    //
    //
    SpireMsg(0,"Observation Completed  (" + time() + " seconds)");
    SpireMsg(0,"Note: Total time (s) = Observation Completed time - slew time + Observatory Overheads");
    if(scanDirection == "scanab") {
        mapOsit = mapOsit + mapOsitx;
    }
    int mOsit = iround(mapOsit);

    return {nRepetitions,mOsit,mOsit * nRepetitions,time() - mOsit * nRepetitions - tslew};
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_BsmAngleCal.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to calculate list of chop and jiggle positions to
//  be looped through during the 'Phot/Spec BSM Angle Calibration' tests.
// 
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/11/07 V0.1: Initial version adapted from 
//                  SpireProc_CalcParam_PhotBsmAngleCal (2008/09/08 V0.1)
// 2009/01/27 V1.0: Add debug_print as input  
// 2009/09/05 V1.1: Allow reverse loop through values (SCR-SPIRE-1894)
//                  Throw error if increment is negative. 
//                  
///////////////////////////////////////////////////////////////////////////
//
{int,int,int,int}[] procedure SpireProc_CalcParam_BsmAngleCal {
    int increment = 384; // Chop/Jiggle increment along scan axis [Dec(Hex)]
    int ref_chop = 0; // Chop position of BSM reference position 
    int ref_jigg = 0; // Jiggle position of BSM reference position 
    int home_chop = 37632; // Hold chop position of BSM  
    int home_jigg = 39520; // Hold jiggle position of BSM 
    int max_chop = 59752; // Maximum chop position of BSM 
    int max_jigg = 59752; // Minimum jiggle position of BSM 
    int min_chop = 1000; // Maximum chop position of BSM 
    int min_jigg = 1000; // Minimum jiggle position of BSM
    bool chop = true; // Scan chop (==tick) or jiggle axis  
    bool reverse = false; // Scan axis either increasing or decreasing (==tick)
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Do input checks:
    if(increment < 0) {
        error("Increment must be positive! Try again.");
    }
    //   
    // //
    // //
    // Create list of BSM positions:
    //   
    // Set boundaries:
    int stop = 0;
    int start = 0;
    if(chop) {
        if(reverse) {
            stop = min_chop;
            start = max_chop;
        } else {
            start = min_chop;
            stop = max_chop;
        }
    } else {
        if(reverse) {
            stop = min_jigg;
            start = max_jigg;
        } else {
            start = min_jigg;
            stop = max_jigg;
        }
    }
    //
    //[int,int,int,int] pos = [0,0,0,0];
    //{int, string, int, int, double}[] rows = [{0,"",0,0,0.0}];
    {int,int,int,int}[] pos = [{0,0,0,0}];
    //
    int index = 0;
    int step = 1;
    int angle = 0;
    if(reverse) {
        angle = start;
        while(angle > stop - 1) {
            // MP: (stop-1) used so reverse produces same number pairs
            if(debug) {
                debug_print("index: " + index);
                debug_print("angle: " + angle);
                debug_print("stop: " + stop);
            }
            if(chop) {
                pos[index] = {angle,home_jigg,ref_chop,ref_jigg};
            } else {
                pos[index] = {home_chop,angle,ref_chop,ref_jigg};
            }
            //
            angle = start - step * increment;
            step = step + 1;
            index = index + 1;
        }
    } else {
        angle = start;
        while(angle < stop + 1) {
            if(debug) {
                debug_print("index: " + index);
                debug_print("angle: " + angle);
                debug_print("stop: " + stop);
            }
            if(chop) {
                pos[index] = {angle,home_jigg,ref_chop,ref_jigg};
            } else {
                pos[index] = {home_chop,angle,ref_chop,ref_jigg};
            }
            //
            angle = start + step * increment;
            step = step + 1;
            index = index + 1;
        }
    }

    return pos;
}

// CVS comments  : $Id: PacsReadChopSky.txt,v 1.3 2007/04/25 15:14:04 dcesarsk Exp $ 
// Missionphase  : 
//
// Purpose       : To read with (linear) interpolation the SKY <-> chopper
//                 U-CAL table
//
// CUS author    : 
// Script file   : PacsReadChopSky.txt from AOT code
//
// Input arguments
// type    name      description
// string  uCAL      Name of the U-CAL table
// double  skyOff    Desired sky offset following a chopper move [arcsec]
//
// Return values
// Type         Description
// int chopREF  Chopper command operand (ENG units)
//
// Description   : Read the table XXX_chop_sky with "interpole"
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      :
// 
// Version       : 0.2 
// History       : 0.1 04-apr-2005 DAC
//                 0.2 22-mar-2007 CAL-U files amended to list ENG instead
//                                 of misleading "REF"
int procedure PacsReadChopSky {
    string uCAL = "PHOT_CHOP_sky"; // Name of the U-CAL table
    /*  Watch out! current uCAL extends only to 360 [arcsec */
    double skyOff = 0.0; // Required sky offset
}{
    // Open and read uCAL table with interpolate
    double auxRef = interpolate(uCAL,"ENG",skyOff);
    int ref = iround(auxRef + 0.5);
    if(auxRef < 0.0) {
        ref = iround(auxRef - 0.5);
    }

    return ref;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBbSetDetSampling.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// The Building Block sets the Detector sampling  parameters for the given MODE
// The detectorSampling flag allows overide of the default data generation status 
//    (i.e true means detector data will be generated irrespective of the default setting)
// The parameter isPhot should be set according to the MODE 
//    (for REDY MODE either state is acceptable)
//
//
///////////////////////////////////////////////////////////////////////////
//
// 28/04/2009  KJK: First Version
// 09/06/2009  KJK: 
//                      added isPHot input parameter
//                      removed sampleDecetors input parameter
// 10/09/2009 KJK:
//                      Move commands to procedure SpireProcSetDetSampling and call this here. 
//
///////////////////////////////////////////////////////////////////////////
//
double block SpireBbSetDetSampling SPIRE 1603 {
    string opsMode = "PHTSTBY";
    bool isPhot = true;
    string detVersion = "v00";
    bool sampleDetectors = false;
    bool debug = false; // Allow debug_print statements 
}{
    // 
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    //
    // Start BB:
    //
    message("4    " + time() + ": SpireBbSetDetSampling started");
    message("4          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    delay(1);
    //
    // run procedure
    //
    double dcuDataRate = SpireProcSetDetSampling(opsMode,isPhot,detVersion,sampleDetectors,debug);
    //
    // End BB:
    //
    sync();
    SpireMsg(4,"    " + time() + ": BB SpireBbSetDetSampling ended");
    //

    return dcuDataRate;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_SpecMultiLevelNoiseLevels.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to translate user input in Hz for bias frequency and 
//  sampling rate into nearest Hex values for mclkdiv and biasdiv
//  and then select list of bias amplitudes and phases for the nearest 
//  match to mclkdiv from the input calibration table for the FTS. 
// 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/09/09 V0.1: Initial version adapted from (2008/08/15 V0.3)
//                  SpireProc_CalcParam_SpecMultiLevelNoiseLevels 
// 2009/02/19 V0.2: Include check for non-existing version. Add debug 
//                  parameter and pass also to low level script. Adapt to
//                  removal of 'index' from calibration file, i.e. remove
//                  reading of indexCol. 
// 2009/03/02 V0.3: Uncomment error message
//
///////////////////////////////////////////////////////////////////////////
//
{string,int,int,int,double,double}[] procedure SpireProc_CalcParam_SpecMultiLevelNoiseLevels {
    double biasfreq = 160.09 in [80.0,240.0]; // Bias frequency [Hz]
    double samplerate = 80.05 in [1.0,80.5]; // Sampling rate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    string tabName = "SpireTable_SpecMultiLevelNoiseLevels.txt"; // Calibration table name 
    string version = "v00"; // Version parameter defined in calibration table
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Calculate mclkdiv and biasdiv based on user input in Hz:
    //
    bool fts = true;
    // FTS or photometer limits? 
    int[] hexvalues = SpireProc_CalcParam_BiasFreqSampFreq(biasfreq,samplerate,fts,debug);
    int mclkdiv = hexvalues[0];
    int biasdiv = hexvalues[1];
    // //
    // //
    // Printout:
    //
    if(debug) {
        debug_print("Converted values mclkdiv/biasdiv [raw]: " + mclkdiv + " " + biasdiv);
    }
    // //
    // //
    // Setup variables:
    //
    string colName = "mclkdiv";
    int[] searchCol = icolumn(tabName,colName);
    int size = table_size(tabName);
    // //
    // //
    // Determine closest match: 
    //
    // Start with the first value as the closest:
    int closest = searchCol[0];
    int diff = iround(abs(double(mclkdiv - closest)));
    if(debug) {
        debug_print("diff = " + diff);
    }
    // Run through the values in the column:
    for(int i = 0 .. size - 1) {
        int next = searchCol[i];
        if(debug) {
            debug_print("next = " + next);
        }
        int nextDiff = iround(abs(double(mclkdiv - next)));
        if(debug) {
            debug_print("nextdiff = " + nextDiff);
        }
        if(nextDiff < diff) {
            closest = next;
            if(debug) {
                debug_print("closest = " + closest);
            }
            // Change diff to allow for non-monotonous mclkdiv in cal. tab. :
            diff = nextDiff;
            if(debug) {
                debug_print("diff = " + diff);
            }
        }
    }
    // //
    // //
    // Get all other column information:
    //
    string[] versionCol = scolumn(tabName,"version");
    int[] settingCol = icolumn(tabName,"setting");
    double[] sswphaseCol = dcolumn(tabName,"sswphase");
    double[] slwphaseCol = dcolumn(tabName,"slwphase");
    //
    {string,int,int,int,double,double}[] rows = [{"",0,0,0,0.0,0.0}];
    int index = 0;
    // //
    // //
    // Cycle through values again to get all rows with closest match:
    //
    for(int j = 0 .. size - 1) {
        // If the key matches the closest and has the correct version tag 
        // then we want it:
        if(closest == searchCol[j]) {
            if(versionCol[j] == version) {
                rows[index] = {versionCol[j],searchCol[j],biasdiv,settingCol[j],sswphaseCol[j],slwphaseCol[j]};
                index = index + 1;
            }
        }
    }
    // //
    // //
    // Safety check: Make sure input version parameter is defined in cal. table:
    if(debug) {
        debug_print("rows[0]{0}: " + rows[0]{0});
    }
    if(rows[0]{0} == "") {
        error("Input version parameter is not defined for selected bias frequency in " + tabName + ". Either select another version or change bias frequency!");
    }
    // //
    // //
    // Return values:

    return rows;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_Cal_MultiLevelNoise.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  CUS script for: 'Phot Multi-Level Noise' 
//
//  in *basic_fine_pointing* or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/06/09 V0.1: Initial version adapted from 
//                  Mode_ILT_PERF_DAB_P_Levels.txt (1.3 2008/01/31 23:35:17)
// 2008/07/03 V0.2: Renumber version; SpireProc_Set_PhotNominalbias changed name
// 2008/08/04 V0.3: Allow separate phase for each array (including PTC)
//                  (== change in SpireProc_Exec_PhotMultiLevelNoise.txt)
// 2008/11/11 V0.4: Allow 'no pointing' as input option; Adapt debug printing
// 2008/11/12 V0.5: Implement mode setting; Add isBright 
//                  Change 'no pointing' implementation
// 2008/11/14 V0.6: Change default version selector to 'v00'
// 2009/01/30 V1.0: Remove test number from header. Add debug_print as input 
//                  and pass it to some low level scripts. 
//                  Use new SpireBb_EndObsAll and SpireBb_StartObsAll. 
//                  Read nominal bias frequency and bias divider from new
//                  SpireTable_DetectorSettings.txt Implemented message 
//                  if activating isBright setting. Implemented setting 
//                  of datarates. Replace SpireProc_Set_PhotNominal by
//                  SpireProc_Set_FreqSampAmpPhasNominal. 
// 2009/02/17 V1.1: Remove cal table name from input and hardcode.  
//                  New setting of datarates. Use SpireBb_PhotSetMode to set 
//                  to PHOTSTBY during SLEW and FINAL_HOLD. Unset isBright 
//                  if set. Read boresight from SpireTable_OpsParms. Fixed
//                  bug in low level script SpireProc_Exec_PhotMultiLevelNoise,
//                  biasfreq and samplerate were set each time in loop. 
// 2009/02/19 V1.2: Fixed bug, now use input version05 in script.
// 2009/03/03 V1.3: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Change isBright behaviour.
//                  Subtract isBright phase shift read from one calibration 
//                  file from the nominal phase value in the other calibration 
//                  file.
// 2009/05/06 V1.4: Add in move BSM to hold at start. Gather procedures at 
//                  start and end in separate BB. 
// 2009/06/05 V1.5: Hardcode STBY 'v00' in EndBB (SPR-1477)
//
// Sunil Sidher 
// 2009/07/21 V1.6: Implemented isPcal flag to perform standard AOT style PCAL flashes after each bias setting
// 
///////////////////////////////////////////////////////////////////////////
//
//  Script assumes that:
//
//  1)  Instrument is in PHOTSTBY at beginning 
//  (i.e. bias amplitude, phase, frequency [mclkdiv,biasdiv] are nominal)
//
//  2) Phase is adjusted with changing bias amplitude and frequency.
//     
//  3) Levels/phases are read from CalTable:
//     SpireTable_PhotMultiLevelNoiseLevels.txt
//
//  4) Phase shift for isBright setting can be read from following
//     cal table: SpireTable_IsBrightPhaseShift.txt 
//
//  5) Bias frequency and sampling rate are user inputs.
//
//  6) Boresight of array can be read from following cal table:
//     Spire_TableOpsParms.txt  
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhoto_Cal_MultiLevelNoise {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    bool isBright = false; // Use settings for bright source (==tick) (Note: Only phases values will be changed!)
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    double biasfreq = 130.2 in [70.0,200.0]; // Bias frequency [Hz]
    double samplerate = 18.6 in [1.0,20.0]; // Sampling rate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    int ftime = 300; // Readout time at each bias level [s]
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_PhotMultiLevelNoiseLevels
    string version05 = "v00"; // Version in cal table SpireTable_OpsParms.txt
    string version06 = "v00"; // Version in cal table SpireTable_IsBrightPhaseShift
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it?
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
    /* */
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Check for is bright setting: 
    //
    if(isBright) {
        message("IsBright selected! PxW bias amplitude is unchanged but isBright phase-shift is subtracted.");
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = true;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_PhotMultiLevelNoiseLevels.txt";
    string tabName04 = "SpireTable_BsmNominalSettings.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    string tabName06 = "SpireTable_IsBrightPhaseShift.txt";
    //
    // Currently hardcoded version and model parameter:
    //
    string version04 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    //
    // Dummy value for Spec script:
    // (needed but not used in phot script!)
    //
    int smecHomePosn = 3500;
    // SMEC home position
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS08";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "PEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version04;
    tabName = tabName04;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // // // // // // // // // // // // // // // // 
    // // // // // // // // // // // // // // // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartMultiLevelNoise(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug));
    // 
    // BBs carried out when the pointing is reached:
    if(pointing) {
        int tinithold = 0;
    } else {
        tinithold = tslewmin;
    }
    //
    // BB carried out during pointing:
    int tp = duration(SpireProc_Exec_PhotMultiLevelNoise(biasfreq,samplerate,tabName03,version03,isBright,isPcal,tabName06,version06,ftime,debug));
    //
    // BB carried out at the end:
    int tfinalhold = duration(SpireBb_EndMultiLevelNoise(phot,isBright,version01,version02,debug));
    //
    // Debug_printing?
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                              */
    // ****************************************************** */
    //
    // Lookup boresight:
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,0,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC              */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartMultiLevelNoise(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            //
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation:
                //
                SpireBb_StartMultiLevelNoise(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug);
                //
            }
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            // //
            // //
            // Execute Multi-Level Noise task:
            //
            SpireProc_Exec_PhotMultiLevelNoise(biasfreq,samplerate,tabName03,version03,isBright,isPcal,tabName06,version06,ftime,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            version01 = "v00";
            version02 = "v00";
            //
            SpireBb_EndMultiLevelNoise(phot,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
//
// SpireProc_Set_SpecBright.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to configure instrument for bright source observation
//  while being in any of the spectrometer modes. 
//
///////////////////////////////////////////////////////////////////////////
//
// KJK:
// 2009/09/22 V0.1: Initial version based on SpireProc_Set_PhotBright.txt
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_SpecBright {
    string obsMode = "Scan"; // Mode in cal file with detector settings
    string smodeVersion = "v00"; // Version in cal file with detector settings
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // 
    // 
    // Declare some variable:
    //
    string tarCol = "";
    string tstr = "";
    //
    // Hardcoded name of calibration table: 
    string tabName = "SpireTable_SpecModeParams.txt";
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"     " + tstr + ":  SpireProc_Set_SpecBright started");
    SpireMsg(4,"          $Id:$");
    // //
    // //
    // Read settings (currently phase and bias) from calibration table:
    //
    // Name of column for selecting:
    string selCol = "mode";
    //
    // Value of 'string' selector:
    string selVal = obsMode + "_b";
    //
    tarCol = "sswBias";
    int ssw_bias = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,smodeVersion,debug);
    tarCol = "slwBias";
    int slw_bias = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,smodeVersion,debug);
    tarCol = "sswPhase";
    int ssw_phase = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,smodeVersion,debug);
    tarCol = "slwPhase";
    int slw_phase = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,smodeVersion,debug);
    // //
    // //
    // Set the selected bias values:
    //
    SpireProc_Set_SpecBias(ssw_bias,slw_bias,debug);
    // //
    // //
    // Set the selected phase values:
    //
    SpireProc_Set_SpecPhase(ssw_phase,slw_phase,debug);
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"      " + tstr + ": SpireProc_Set_SpecBright ended");
}

// Missionphase  : PACS AVM ILT
//
// Purpose       : Select the data mode
//
// Author TCL    : T. Mueller
// Author CUS    : DAC
// CUS script    : PHOT_change_data_mode.txt
//
// Arguments     : 
// type    name   default      Description
// string  mode   "Bolo_HK"    Select the data mode for bolometers
//                 
// Description   : This script will select the data mode for the bolometers
//                 After switch on of the bolometers the default data mode
//                 is "HK only", after executing the sequencer setup the
//                 default mode is "Bolo & HK"
//                              
// Comments      : Coded based on PhFPU UM, Draft 2, March 31, 2004
//
// Version       : 1.0 18-apr-2005 DAC Based on TM's V1.0 0f 20-apr-2004
// History       : 
//
int[] procedure PHOT_change_data_mode {
    string data_mode = "Bolo_HK" in ["Bolo_HK","HK_only","Test_Pat_HK"]; //Data mode for the bolometers
}{
    // Define variables to communicate various durations to HSPOT.
    // NOTE: all time variables in units of number of ramps (SPEC) or
    //       number of readouts (BOLO). The calling program must convert this
    //       count into actual duration in true time units [seconds].
    //       SRC, REF, CAL, OVR stand for time spent on SRC, REF (on sky),
    //       CAL source, and overheads (wait for something). Total
    //       duration is given by duree_num. If no error, this duration
    //       must be equal to the sum of all others
    int duree_num = 0;
    int duree_SRC = 0;
    int duree_REF = 0;
    int duree_CAL = 0;
    int duree_OVR = 0;
    int time_start = time();
    //------------------------------------------------
    // SET BOLC Data Mode data & HK
    //------------------------------------------------
    // PC103420 "DMC_SEND_COMMAND_BOLC" SEND COMMAND TO BOL CONTROLLER
    //         PP071420 "BOLOMETER_COMMAND"
    Pacs_BOLC_SET_DATA_MODE(data_mode);
    // Time spent
    int duree_TCs = time() - time_start;
    duree_OVR = duree_TCs;
    duree_num = duree_OVR;
    // Return the array of times
    int[] time_array = [duree_num,duree_SRC,duree_REF,duree_CAL,duree_OVR];

    return time_array;
}

//CLName: SpireBb_LoadTableActions
//VMVersion: 2.8
//CLVersion: 1.13
//CLCVSId: $ID$
//TableId: 0x67
//TableLength: 0x26c
//Date: 100127140108
block SpireBb_LoadTableActions SPIRE 3805 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableActions started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    //
    //set table command call for table id 0x67
    Spire_SET_TABLE(0x67,0x26c);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x67,0x0,21,[{0x31000000},{0x30000063},{0x3000007a},{0x3000009f},{0x300000bf},{0x300000cd},{0x300000d1},{0x300000f6},{0x3000013d},{0x30000159},{0x30000175},{0x30000183},{0x30000191},{0x300001a5},{0x300001bc},{0x300001ce},{0x300001d2},{0x300001d8},{0x300001ed},{0x300001f1},{0x300001f5}]);
    delay(t_min);
    //update table command call for table index 0x001e
    Spire_UPDATE_TABLE(0x67,0x1e,16,[{0x300001f0},{0x300001f2},{0x300001f4},{0x300001f6},{0x300001f8},{0x300001fa},{0x300001fc},{0x300001fe},{0x30000200},{0x30000202},{0x30000204},{0x30000208},{0x3000020c},{0x3000020e},{0x30000210},{0x30000212}]);
    delay(t_min);
    //update table command call for table index 0x0064
    Spire_UPDATE_TABLE(0x67,0x64,38,[{0x60660000},{0x58000001},{0x58000002},{0x58000003},{0x80007d0},{0x1000001},{0x80007d0},{0x120000ff},{0x0},{0x12000000},{0x7b},{0x61060001},{0x12000000},{0x7},{0x6066000c},{0x60660006},{0x60660007},{0xb002710},{0x1000000},{0x80007d0},{0x2000000},{0x60660003},{0x7f000000},{0x900},{0x120000fd},{0x100},{0x60660000},{0xb002710},{0x2000000},{0x80007d0},{0x2000000},{0x80007d0},{0x1000001},{0x80007d0},{0x12000000},{0x2},{0x6066000c},{0x12000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x67,0x8a,38,[{0x2},{0x12000001},{0x887},{0x6066000d},{0x18000000},{0x3},{0x208700},{0x12000000},{0x90000000},{0x12000001},{0x9fff0000},{0x12000002},{0xf0000000},{0x12000003},{0x90000000},{0x12000004},{0x1},{0x63fd0009},{0xb002710},{0x1000000},{0x80007d0},{0x2000000},{0x60660001},{0x7f000000},{0x60660000},{0x58000001},{0x58000002},{0x58000003},{0x80007d0},{0x1000001},{0x80007d0},{0x120000ff},{0x0},{0x12000000},{0xc2},{0x62060001},{0x490000c2},{0x12000001}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x67,0xb0,38,[{0x200},{0x34000001},{0x3000000b},{0x120000ff},{0x0},{0x12000001},{0x200},{0x4b0100c2},{0x12000000},{0xc2},{0x61060001},{0x60660004},{0x60660005},{0xb002710},{0x1000000},{0x80007d0},{0x2000000},{0x7f000000},{0x0},{0x120000fd},{0x100},{0x80007d0},{0x1000001},{0x8000bb8},{0xa0c80000},{0x12000000},{0xa0c80000},{0x12000001},{0x1},{0x63fd0007},{0x80007d0},{0x1000000},{0x8000bb8},{0x7f000000},{0x12000000},{0x3005},{0x53010000},{0x2000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x67,0xd6,38,[{0x7f000000},{0x120000fd},{0x100},{0x60660000},{0x80007d0},{0x1000001},{0x80007d0},{0x843e0000},{0x91c10000},{0x91c00000},{0x91c20000},{0xa0820000},{0x12000000},{0x7000},{0x63fd000a},{0x2000000},{0x90490000},{0x90440006},{0x90450dac},{0x90490001},{0x90400000},{0x90410000},{0x12000000},{0x90400000},{0x12000001},{0x909f0000},{0x12000002},{0xff000000},{0x12000003},{0x90000000},{0x12000004},{0x1},{0x63fd0009},{0xb002710},{0x1000000},{0x80007d0},{0x2000000},{0x60660001}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x67,0xfc,38,[{0x7f000000},{0x120000fd},{0x100},{0x60660000},{0x80007d0},{0x1000001},{0x80007d0},{0x120000ff},{0x4},{0x12000000},{0x144},{0x62070001},{0x49000144},{0x10000000},{0x4b000144},{0x12000000},{0x144},{0x61070001},{0x90490000},{0x90440006},{0x90400000},{0x90410000},{0x90542af8},{0x90400001},{0x9058a7f8},{0x905a8ef8},{0x90410001},{0x905f2af8},{0x905e1f40},{0x904d0000},{0x90557d00},{0xb003a98},{0x1000000},{0x80007d0},{0x1000001},{0x80007d0},{0x90542af8},{0x90450000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x67,0x122,38,[{0x90460000},{0x90490001},{0xb002710},{0x1000000},{0x80007d0},{0x1000001},{0x80007d0},{0x90490004},{0x90490001},{0x905f2af8},{0x9051012c},{0x904e07d0},{0x904c07d0},{0x904b02bc},{0x90440001},{0xb0007d0},{0x1000000},{0x80007d0},{0x1000001},{0x80007d0},{0x90450dac},{0xb001388},{0x1000000},{0x80007d0},{0x1000001},{0x80007d0},{0x904a07d0},{0x904d03e8},{0xb002710},{0x1000000},{0x80007d0},{0x2000000},{0x60660001},{0x7f000000},{0x0},{0x120000fd},{0x100},{0x60660000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x67,0x148,38,[{0x80007d0},{0x1000001},{0x80007d0},{0x90c38000},{0x91438000},{0x90c20003},{0x91420003},{0x90c00000},{0x91400000},{0x12000000},{0x90c00000},{0x12000001},{0x915f0000},{0x12000002},{0xf0000000},{0x12000003},{0x90000000},{0x12000004},{0x1},{0x63fd0009},{0xb002710},{0x1000000},{0x80007d0},{0x2000000},{0x60660001},{0x7f000000},{0x120000fd},{0x100},{0x60660000},{0x80007d0},{0x1000001},{0x80007d0},{0xa0c70000},{0xa0c40000},{0xa0c50000},{0x12000000},{0xa0c70000},{0x12000001}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x67,0x16e,38,[{0x1},{0x63fd0007},{0x12000000},{0xa0c40000},{0x12000001},{0x1},{0x63fd0007},{0x12000000},{0xa0c50000},{0x12000001},{0x1},{0x63fd0007},{0xb002710},{0x1000000},{0x80007d0},{0x2000000},{0x7f000000},{0x120000fd},{0x100},{0x80007d0},{0x1000001},{0x8000bb8},{0xa0c60000},{0x12000000},{0xa0c60000},{0x12000001},{0x1},{0x63fd0007},{0x80007d0},{0x1000000},{0x8000bb8},{0x7f000000},{0x120000fd},{0x100},{0x80007d0},{0x1000001},{0x8000bb8},{0xa0c70000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x67,0x194,38,[{0x12000000},{0xa0c70000},{0x12000001},{0x1},{0x63fd0007},{0x80007d0},{0x1000000},{0x8000bb8},{0x7f000000},{0x120000fd},{0x100},{0x80007d0},{0x1000001},{0x8000bb8},{0xa0c40000},{0xa0c50000},{0x12000000},{0xa0c40000},{0x12000001},{0x1},{0x63fd0007},{0x12000000},{0xa0c50000},{0x12000001},{0x1},{0x63fd0007},{0x80007d0},{0x1000000},{0x8000bb8},{0x7f000000},{0x120000fd},{0x100},{0x80007d0},{0x1000001},{0x8000bb8},{0x120000ff},{0xa},{0x120000fc}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x67,0x1ba,38,[{0x1c8},{0x6207fc01},{0x2000000},{0x490001c8},{0x14000000},{0xa8f00000},{0x32000003},{0x58000001},{0xa0c60000},{0xa0860000},{0x80007d0},{0x1000000},{0x8000bb8},{0x7f000000},{0x0},{0x7f000000},{0x80007d0},{0x1000001},{0x8000bb8},{0x120000ff},{0x5},{0x12000000},{0x1dc},{0x62070001},{0x490001dc},{0x10000000},{0x4b0001dc},{0x12000000},{0x1dc},{0x61070001},{0x80007d0},{0x1000000},{0x8000bb8},{0x7f000000},{0x0},{0x12000000},{0x300f},{0x53010000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x67,0x1e0,38,[{0x2000000},{0x7f000000},{0x12000000},{0xa8ea0000},{0x12000002},{0xfbff},{0x12000003},{0xa0ca0000},{0x30000007},{0x12000000},{0xa8eb0000},{0x12000002},{0xf7ff},{0x12000003},{0xa0cc0000},{0x120000fd},{0x100},{0x120000ff},{0xb},{0x120000fc},{0x1fd},{0x6207fc01},{0x2000000},{0x490401fd},{0x22000004},{0x32000002},{0x58000002},{0x40000252},{0x7f000000},{0x0},{0x7f000000},{0x12000000},{0x3012},{0x53010000},{0x2000000},{0x7f000000},{0x12000000},{0x3013}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x67,0x206,38,[{0x53010000},{0x2000000},{0x7f000000},{0x12000000},{0x3014},{0x53010000},{0x2000000},{0x7f000000},{0x12000002},{0xfffe},{0x30000032},{0x12000002},{0xfffd},{0x3000002f},{0x12000002},{0xfffb},{0x3000002c},{0x12000002},{0xfff7},{0x30000029},{0x12000002},{0xffef},{0x30000026},{0x12000002},{0xffdf},{0x30000023},{0x12000002},{0xffbf},{0x30000020},{0x12000002},{0xff7f},{0x3000001d},{0x12000002},{0xfeff},{0x3000001a},{0x12000002},{0xfdff},{0x30000017}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x67,0x22c,38,[{0x12000002},{0xfbff},{0x12000003},{0xa0ca0000},{0x30000022},{0x12000002},{0xf7ff},{0x12000003},{0xa0cc0000},{0x3000001d},{0x12000002},{0xefff},{0x3000000a},{0x12000002},{0xdfff},{0x30000007},{0x12000002},{0xbfff},{0x30000004},{0x12000002},{0x7fff},{0x30000001},{0x80007d0},{0x1000001},{0x8000bb8},{0x12000000},{0xa8850000},{0x12000001},{0xbb8},{0x60640000},{0x8000bb8},{0x2000000},{0x27000102},{0x208500},{0x80007d0},{0x1000000},{0x8000bb8},{0x7f000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x67,0x252,26,[{0x120000fd},{0x100},{0x80007d0},{0x1000001},{0x8000bb8},{0x12000000},{0xa8850000},{0x12000001},{0xbb8},{0x60640000},{0x8000bb8},{0x2000000},{0x27000102},{0x208500},{0x4000003},{0x8000bb8},{0x2000000},{0x20000003},{0x12000001},{0x1},{0x63fd0007},{0x80007d0},{0x1000000},{0x8000bb8},{0x41000000},{0x7f000000}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x67,0x0,0x0);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableActions ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_StartDcuData.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to start generation of detector data (TM packets)
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/18 V0.1: Initial version adapted
//                  SpireBb_StartDcuData (2008/07/03 V0.2)
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_StartDcuData {
}{
    // //
    // //
    // Start procedure:
    //
    message("4    " + time() + ": SpireProc_Set_StartDcuData started");
    message("4          $Id: $");
    // //
    // //
    // Reset DCU (x1000) fifo:
    //
    message("5          " + time() + "Cmd: Spire_RESET_FIFOS(0x1000)");
    Spire_RESET_FIFOS(0x1000);
    delay(1);
    // //
    // //
    // Start data collection:
    //
    SpireSendDrcuCmd(0x843e0001,0);
    sync();
    // //
    // //
    // End procedure:
    //
    message("4    " + time() + ": SpireProc_Set_StartDcuData ended");
    //
}

//
// Check PM
// 09/08/2010: SDS 
//                      First Version 1.0
//                      For checking the PM from the MTL - to be run during the SOPS window
//                      See SPIRE-SCR-2762
//
block SpireBb_CheckPM SPIRE 3428 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_CheckPM started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // Report the PM checksums
    Spire_CHECK_MEMORY_RAW(0,0x4000,0x174b);
    delay(12);
    Spire_CHECK_MEMORY_RAW(0,0x6000,0xffff);
    delay(12);
    Spire_CHECK_MEMORY_RAW(0,0x15fff,0x59);
    delay(12);
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_CheckPM ended");
    SpireMsg(1,"  ..Bb_CheckPM (" + (time() - t) + " seconds)");
    //
}

// SpireNhkSampling
//
// $id$
//
// This procedure sets the NHK sampling interval
// 
//  11/11/2008  Removed command to stop NHSK when changing sampling rate
//  01/02/2010 Inserted a delay after restarting NHK to match the sampling rate
//
procedure SpireNhkSampling {
    int interval = 0xfa0; // NHK sampling interval (ms)
}{
    //  default NHK parameters
    int pktid = 0x301;
    // packet id
    int sid = 0x301;
    // sid
    int repeat = 1;
    // packet repeat
    int tableid = 1;
    // table id
    //    
    string tstr = "";
    // time string
    string pstr = SpireHexStr(pktid,4);
    string sstr = SpireHexStr(sid,4);
    //
    // start NHK generation at new rate
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_DEFINE_NEW_HK_REPORT(" + pstr + "," + sstr + "," + interval + "," + repeat + "," + tableid + ")");
    Spire_DEFINE_NEW_HK_REPORT(pktid,sid,interval,repeat,tableid);
    int twait = interval / 1000 + 1;
    SpireMsg(5,"      Wait time    " + twait);
    delay(twait);
}

//CLName: SpireBb_LoadTableCREC
//VMVersion: 2.8
//CLVersion: 1.8
//CLCVSId: $ID$
//TableId: 0x53
//TableLength: 0x195
//Date: 081208192120
// S.D.Sidher 19 July 2011: Manually updated to report the static section of table (SPIRE-SCR-3624))
// SPIRE-SCR-3622
//                  Updated to only report the static section of CREC VM table
//                  (Table ID 83) SPIRE-SCR-3624
block SpireBb_LoadTableCREC SPIRE 3342 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableCREC started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0x53
    Spire_SET_TABLE(0x53,0x195);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x53,0x0,38,[{0x4b000180},{0x4b010181},{0x4b020182},{0x4b030183},{0x4b040184},{0x4b050185},{0x4b060186},{0x4b070187},{0x4b080188},{0x4b090189},{0x4b0a018a},{0x4b0b018b},{0x4b0c018c},{0x4b0d018d},{0x4b0e018e},{0x1500000f},{0x3c},{0x4b0f018f},{0x15000010},{0x3c},{0x4b100190},{0x15000011},{0x3c},{0x4b110191},{0x15000012},{0x3c},{0x4b120192},{0x15000013},{0x3c},{0x4b130193},{0x15000014},{0x3c},{0x4b140194},{0x490a018e},{0x1500000a},{0xf4240},{0x490b0194},{0x120000ff}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x53,0x26,38,[{0x0},{0x120000fc},{0x17f},{0x12000000},{0x501},{0x12000001},{0x1},{0x4b01017f},{0x6107fc01},{0x53020000},{0x2000000},{0x49000180},{0x40000139},{0x49000181},{0x4000012c},{0x490c018f},{0x40000154},{0x32000004},{0x49000182},{0x35010000},{0x3000000d},{0x900000a},{0x2000000},{0x12000000},{0x0},{0x4901018e},{0x220c0c01},{0x340c0000},{0x300000d2},{0x220b0b01},{0x340b0000},{0x300000ca},{0x30fffff0},{0x12000000},{0x501},{0x12000001},{0x2},{0x4b01017f}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x53,0x4c,38,[{0x6107fc01},{0x53020000},{0x2000000},{0x49000183},{0x4000011f},{0x490c0190},{0x40000146},{0x32000004},{0x49000184},{0x34010000},{0x3000000d},{0x900000a},{0x2000000},{0x12000000},{0x0},{0x4901018e},{0x220c0c01},{0x340c0000},{0x300000b6},{0x220b0b01},{0x340b0000},{0x300000ae},{0x30fffff0},{0x12000000},{0x501},{0x12000001},{0x3},{0x4b01017f},{0x6107fc01},{0x53020000},{0x2000000},{0x49000185},{0x4000011f},{0x490c0191},{0x40000146},{0x32000004},{0x49000186},{0x34010000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x53,0x72,38,[{0x30000011},{0x900000a},{0x2000000},{0x12000000},{0x0},{0x4901018e},{0x220c0c01},{0x340c0000},{0x30000005},{0x220b0b01},{0x340b0000},{0x30000092},{0x30fffff0},{0x12000000},{0x7025},{0x53010000},{0x2000000},{0x12000000},{0x501},{0x12000001},{0x4},{0x4b01017f},{0x6107fc01},{0x53020000},{0x2000000},{0x49000187},{0x4000011f},{0x490c0192},{0x40000146},{0x32000004},{0x49000184},{0x35010000},{0x30000017},{0x40000162},{0x32000004},{0x4900018a},{0x34010000},{0x30000030}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x53,0x98,38,[{0x900000a},{0x2000000},{0x12000000},{0x0},{0x4901018e},{0x220c0c01},{0x340c0000},{0x30000005},{0x220b0b01},{0x340b0000},{0x3000006d},{0x30ffffeb},{0x12000000},{0x7021},{0x53010000},{0x2000000},{0x3000001f},{0x49000188},{0x4000011f},{0x490c0192},{0x40000146},{0x32000004},{0x49000189},{0x34010000},{0x30ffffdb},{0x40000162},{0x32000004},{0x4900018a},{0x34010000},{0x30000012},{0x900000a},{0x2000000},{0x12000000},{0x0},{0x4901018e},{0x220c0c01},{0x340c0000},{0x30000005}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x53,0xbe,38,[{0x220b0b01},{0x340b0000},{0x3000004f},{0x30ffffeb},{0x12000000},{0x7022},{0x53010000},{0x2000000},{0x30000001},{0x12000000},{0x501},{0x12000001},{0x5},{0x4b01017f},{0x6107fc01},{0x53020000},{0x2000000},{0x49000181},{0x4000011f},{0x49000181},{0x40000139},{0x490c0190},{0x40000170},{0x32000004},{0x4900018b},{0x35010000},{0x3000000d},{0x900000a},{0x2000000},{0x12000000},{0x0},{0x4901018e},{0x220c0c01},{0x340c0000},{0x30000034},{0x220b0b01},{0x340b0000},{0x3000002c}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x53,0xe4,38,[{0x30fffff0},{0x12000000},{0x501},{0x12000001},{0x6},{0x4b01017f},{0x6107fc01},{0x53020000},{0x2000000},{0x49000180},{0x4000012c},{0x490c0193},{0x40000146},{0x32000004},{0x4900018c},{0x35010000},{0x30000011},{0x900000a},{0x2000000},{0x12000000},{0x0},{0x4901018e},{0x220c0c01},{0x340c0000},{0x30000005},{0x220b0b01},{0x340b0000},{0x30000010},{0x30fffff0},{0x12000000},{0x7023},{0x53010000},{0x30000003},{0x4900018d},{0x4000012c},{0x12000000},{0x501},{0x12000001}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x53,0x10a,38,[{0x7},{0x4b01017f},{0x6107fc01},{0x53020000},{0x7f000000},{0x12000000},{0x7024},{0x53010000},{0x2000000},{0x30000005},{0x12000000},{0x7020},{0x53010000},{0x2000000},{0x49000181},{0x4000011f},{0x49000181},{0x4000012c},{0x49000181},{0x40000139},{0x7f000000},{0x80007d0},{0x1000001},{0x12000003},{0x7d0},{0x20020000},{0x12000001},{0xc7},{0x12000000},{0x2},{0x60640001},{0x80007d0},{0x1000000},{0x41000000},{0x80007d0},{0x1000001},{0x12000003},{0x7d0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x53,0x130,38,[{0x20020000},{0x12000001},{0xc4},{0x12000000},{0x2},{0x60640001},{0x80007d0},{0x1000000},{0x41000000},{0x80007d0},{0x1000001},{0x12000003},{0x7d0},{0x20020000},{0x12000001},{0xc5},{0x12000000},{0x2},{0x60640001},{0x80007d0},{0x1000000},{0x41000000},{0x80007d0},{0x1000001},{0x12000000},{0x2},{0x12000001},{0x8e0},{0x12000002},{0x0},{0x12000003},{0x7d0},{0x60640001},{0x80007d0},{0x1000000},{0x41000000},{0x80007d0},{0x1000001}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x53,0x156,38,[{0x12000000},{0x2},{0x12000001},{0x8e1},{0x12000002},{0x0},{0x12000003},{0x7d0},{0x60640001},{0x80007d0},{0x1000000},{0x41000000},{0x80007d0},{0x1000001},{0x12000000},{0x2},{0x12000001},{0x8f0},{0x12000002},{0x0},{0x12000003},{0x7d0},{0x60640001},{0x80007d0},{0x1000000},{0x41000000},{0x80007d0},{0x1000001},{0x12000000},{0x2},{0x12000001},{0x8e2},{0x12000002},{0x0},{0x12000003},{0x7d0},{0x60640001},{0x80007d0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x53,0x17c,25,[{0x1000000},{0x41000000},{0x7f000000},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0}]);
    delay(t_min);
    //
    //  dump table contents (static section only - 383 words) 
    //
    Spire_REPORT_TABLE(0x53,0x0,0x17f);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableCREC ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_IltPcalFlash.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to deduce number of DCU samples, SCU samples and DCU sample 
//  delay based on inputs period,mclkdiv and biasdiv in exactly the same
//  way as for ILT, which had a small bug in the calculation   
// 
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/14 V0.1: Initial version recovered from
//                  SpireProc_CalcParam_PhotPcalFlash (2008/05/05 V0.1)
//                  based upon
//                  Proc_PCALFlashCalc.txt (v1.4 2008/01/31 20:24:35)
// 2009/02/02 V1.0: Add debug_print as input and pass to low level scripts.
//                  
///////////////////////////////////////////////////////////////////////////
//
int[] procedure SpireProc_CalcParam_IltPcalFlash {
    int period = 4000; //PCAL Flash FULL period (high and low bias) in millisec
    int mclkdiv = 149; // Fetched master clock divisor
    int biasdiv = 6; // Fetched bias divisor
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Calculate bias frequency Hz:
    //
    double bias_f = 1.0E7 / (512.0 * double(mclkdiv));
    // //
    // //
    // Calculate sampling rate Hz:
    //
    double s_rate = bias_f / (1.0 + double(biasdiv));
    // //
    // //
    // Calculate frame time difference in ms:
    double framerate = 1.0 / s_rate * 1000.0;
    // //
    // //
    // Calculate dcusamples, scusamples, and dcudelay parameters:
    //
    int dcusamples = iround(double(period) / 2.0 / framerate) - 1;
    int scusamples = iround(double(period) / 2.0 / 12.5) - 1;
    int dcudelay = iround((double(period) / 2.0 - double(dcusamples) * framerate) * 1000.0);
    if(dcudelay < 0) {
        do {
            dcusamples = dcusamples - 1;
            dcudelay = iround((2000.0 - double(dcusamples) * framerate) * 1000.0);
            if(debug) {
                debug_print("New number of dcu samples is: " + dcusamples);
                debug_print("New dcu_sample_delay rate is: " + dcudelay);
            }
        } while (dcudelay < 0);
    }
    scusamples = 0x0;
    //

    return [dcusamples,scusamples,dcudelay];
}

// SpireSpectroScalOff
//
// $id$
//
// This observation switches off the SCAL
// 
// The instrument should be in SPECSTBY mode before execution of this observation
// Final Configuration: Instrument is still in SPECSTBY mode after execution of this observation
//
//
// 26/08/2009 KJK: First Version
//
obs SpireSpectroScalOff {
    int stabilisationTime = 120; // time (secs) to allow SCAL/Detectors to stabilise before starting observations
    bool sampleDetectors = true; // sample detectors during the stabilisation period (assumes detector sampling rate/mode is already configured)
    string scalVersion = "v00";
    string detVersion = "v00";
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int tih = duration(SpireBbStartObs());
    int tfh = duration(SpireBbEndObs()) + duration(SpireBbSetDetSampling("SPECSTBY",false,detVersion,false,debug));
    int tp = duration(SpireProc_Set_Scal("None",-1,stabilisationTime,sampleDetectors,scalVersion,detVersion,debug));
    int[] ts = no_pointing(true,tih,tfh,tp);
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // ***********************  INITIAL HOLD          
            // set OBSID
            SpireBbStartObs();
        }
        if(state[0] == 3) {
            // ***********************  EXECUTE
            SpireProc_Set_Scal("None",-1,stabilisationTime,sampleDetectors,scalVersion,detVersion,debug);
        }
        if(state[0] == 5) {
            // ***********************  FINAL HOLD
            // Return detector sampling to default configuration
            SpireBbSetDetSampling("SPECSTBY",false,detVersion,false,debug);
            SpireBbEndObs();
        }
    }
}

// SpireCoolerRecycle
//
// $id$
//
// This procedure executes the cooler recycle 
// 
// The instrument should be in  the REDY mode before execution of this observation
//
// 08/11/2007 KJK: removed StartObs and EndObs building blocks from the engineering procedure
//
procedure SpireCoolerRecycle {
}{
    //  execute cooler recycle
    mois_comment("Procedure to recycle the SPIRE Sorption Cooler");
    SpireBbCoolerRecycle();
    mois_comment("SPIRE Cooler Recycle Procedure Completed");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SetBsmChopPid.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set BSM PID parameters
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/30 V0.1: Initial version adapted from
//                  Proc_SetChopPID.txt (SDS, email 30.03.2009)
// 2009/06/05 V1.1: Commands moved to new low level procedure 
//                  SpireProc_Set_BsmChopPid.txt. Hspot message 
//                  at level 1 changed. 
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SetBsmChopPid SPIRE 14034 {
    int kp = 1000; // Chop Kp
    int ki = 536; // Chop Ki
    int kd = 3504; // Chop Kd
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string hstr = "";
    // a hex string
    string tstr = "";
    // a time string
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": SpireBb_SetBsmChopPid started");
    SpireMsg(2,"          $Id: $");
    hstr = SpireHexStr($BBID,8);
    SpireMsg(3,"          BBID = " + hstr);
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    sync();
    // //
    // //
    // Set PID parameters:
    //
    SpireProc_Set_BsmChopPid(kp,ki,kd,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SetBsmChopPid ended");
    SpireMsg(1,"  ..Set BSM PID parameters (" + (time() - t) + " secs)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndPcalLevelCheck.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of 
// SpirePhoto/Spectro_Cal_PcalLevelCheck
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/07 V1.1: Initial version adapted from
//                  SpireBb_EndBsmAngleCal (2009/05/05 V1.2),
//                  SpirePhoto_Cal_PcalLevelCheck (2009/03/04 V1.4), and
//                  SpireSpectro_Cal_PcalLevelCheck (2009/03/04 V0.5)
//                  Incl. set dcuFrameNumber and scuFrameNumber back 
//                  to continuous to unset setting passed to VM. 
// 2009/06/05 V1.2: Replace Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd 
//                  as requested in SPR-1482.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndPcalLevelCheck SPIRE 14065 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndPcalLevelCheck reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set obsstep back to 0:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP(0)");
    Spire_SET_OBS_STEP(0);
    // //
    // //
    // Set instrument back to Phot/Spec-STBY:
    //
    if(phot) {
        SpireProc_Set_PhotMode("PHTSTBY",isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    }
    // //
    // //
    // Set number of DCU frames to continuous:
    //
    int dcuFrameNumber = 0;
    if(phot) {
        dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","PHTSTBY","dcuFrameNumber","v00",debug);
    } else {
        dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuFrameNumber","v00",debug);
    }
    //
    SpireSendDrcuCmd(0x843d0000 + dcuFrameNumber,0);
    // //
    // //
    // Set number of SCU frames to continuous:
    //
    int scuFrameNumber = 0;
    if(phot) {
        scuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","PHTSTBY","scuFrameNumber","v00",debug);
    } else {
        scuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","scuFrameNumber","v00",debug);
    }
    SpireSendDrcuCmd(0xa0840000 + scuFrameNumber,0);
    delay(1);
    // //
    // //
    // End observation:
    //
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndPcalLevelCheck reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProcSetDetSampling.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// The procedure sets the Detector sampling  parameters for the given MODE
// The detectorSampling flag allows overide of the default data generation status 
//    (i.e true means detector data will be generated irrespective of the default setting)
// The parameter isPhot should be set according to the MODE 
//    (for REDY MODE either state is acceptable)
//
//
///////////////////////////////////////////////////////////////////////////
//
// 10/09/2009  KJK: First Version created from SpireBbSetDetSampling (09/06/2009)
//
///////////////////////////////////////////////////////////////////////////
//
double procedure SpireProcSetDetSampling {
    string opsMode = "PHTSTBY";
    bool isPhot = true;
    string detVersion = "v00";
    bool sampleDetectors = false;
    bool debug = false; // Allow debug_print statements 
}{
    // 
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    //
    // Start BB:
    //
    message("4    " + time() + ": SpireProcSetDetSampling started");
    message("4          $Id: $");
    // //
    // //
    //
    // Set sampling
    //
    // stop any DCU sampling
    SpireSendDrcuCmd(0x843e0000,0);
    // Set DCU data mode
    int dcuDataMode = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",opsMode,"dcuDataMode",detVersion,debug);
    SpireSendDrcuCmd(0x843c0000 + dcuDataMode,0);
    // start sampling, if required
    if(sampleDetectors) {
        SpireSendDrcuCmd(0x843d0000,0);
        // continuous sampling
        SpireSendDrcuCmd(0x843e0001,0);
        // start sampling
    } else {
        // Read sampling from calibration file
        // Set number of samples
        int dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",opsMode,"dcuFrameNumber",detVersion,debug);
        SpireSendDrcuCmd(0x843d0000 + dcuFrameNumber,0);
        // Start/Stop Data Generation
        int dcuDataGen = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",opsMode,"dcuDataGen",detVersion,debug);
        SpireSendDrcuCmd(0x843e0000 + dcuDataGen,0);
    }
    //
    // get DCU data rate
    double dcuDataRate = 0.0;
    if(opsMode == "REDY") {
        dcuDataRate = SpireProc_GetTableEntryDouble("SpireTable_DefaultParams.txt","mode",opsMode,"dcuDataRate",detVersion,debug);
    } else {
        if(isPhot) {
            dcuDataRate = SpireProc_GetTableEntryDouble("SpireTable_PhotModeParams.txt","mode",opsMode,"dcuDataRate",detVersion,debug);
        } else {
            dcuDataRate = SpireProc_GetTableEntryDouble("SpireTable_SpecModeParams.txt","mode",opsMode,"dcuDataRate",detVersion,debug);
        }
    }
    //
    // End Procedure
    //
    sync();
    SpireMsg(4,"    " + time() + ": SpireProcSetDetSampling ended");
    //

    return dcuDataRate;
}

//CLName: SpireBb_LoadTableStepAndChop
//VMVersion: 2.8
//CLVersion: 1.2
//CLCVSId: $Id$
//TableId: 0x4a
//TableLength: 0x45
//Date: 091106144405
block SpireBb_LoadTableStepAndChop SPIRE 273 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableStepAndChop started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0x4a
    Spire_SET_TABLE(0x4a,0x45);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x4a,0x0,38,[{0x50000000},{0x200f0000},{0x20130000},{0x20100001},{0x20110002},{0x20120003},{0x1200001e},{0x4e20},{0x51000000},{0x20000004},{0x20010005},{0x20020006},{0x20030007},{0x20040008},{0x60640003},{0x32000031},{0x20200001},{0x20210002},{0x51000001},{0x20040012},{0x20050020},{0x20060021},{0x20070008},{0x80007d0},{0x1000001},{0x12000000},{0x1},{0x12000001},{0x49},{0x12000002},{0x1},{0x2003001e},{0x60640001},{0x80007d0},{0x1000000},{0x80007d0},{0x1000001},{0x12000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x4a,0x26,31,[{0x1},{0x12000001},{0x45},{0x20020013},{0x2003001e},{0x60640001},{0x80007d0},{0x1000000},{0x2000000a},{0x2001000b},{0x2002000c},{0x2003000d},{0x60640004},{0x3200000d},{0x350f0010},{0x30000005},{0x21131311},{0x34130010},{0x30ffffeb},{0x30000005},{0x22131311},{0x35130010},{0x30ffffe7},{0x30000001},{0x52000000},{0x30000005},{0x12000000},{0x7030},{0x53010000},{0x2000000},{0x7f000000}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x4a,0x0,0x0);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableStepAndChop ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_GetTableEntryBool.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to select a double entry in a calibration table
//  giving a string input as selector using the versioning approach. 
//
//  Note: Currently script is restricted to a 'string' selector!
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/01/26 V0.1: Initial version adapted from 
//                  SpireProc_CalcParam_FpgInitialPointing.txt (2008/11/06 V0.3)
// 2009/07/12 V1.0: Fix SPR-SPIRE-1636 (reduce number of debug printouts)
//                  Change default values for testing. 
// 2009/08/15 V1.1: Fix SPR-SPIRE-1819 (add proper error message and report 
//                  table name)
//
///////////////////////////////////////////////////////////////////////////
//
bool procedure SpireProc_GetTableEntryBool {
    string tabName = "SpireTable_SpireParams.txt"; // Name of the table to be selected from
    string selCol = "mode"; // Name of column for selecting 
    string selVal = "POF5_S_N"; // Value of 'string' selector 
    string tarCol = "InitFlash"; // Target column name     
    string version = "v00"; // Version parameter defined in calibration table
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variable:
    //
    bool boolVar = true;
    //
    // Define columns:
    string[] versionCol = scolumn(tabName,"version");
    bool[] targetCol = bcolumn(tabName,tarCol);
    string[] selectorCol = scolumn(tabName,selCol);
    //
    // Read table size: 
    int nrows = table_size(tabName);
    // //
    // //
    // Cycle through values to get all rows with correct version tag:
    //
    //Setup:
    {bool,string}[] rows = [{true,""}];
    int nindex = 0;
    bool match = false;
    //
    for(int j = 0 .. nrows - 1) {
        //if(debug) {
        //    debug_print("versionCol[j]: " + versionCol[j]);
        //}
        if(versionCol[j] == version) {
            rows[nindex] = {targetCol[j],selectorCol[j]};
            nindex = nindex + 1;
            match = true;
        }
    }
    //if(debug) {
    //    debug_print("selected rows: " + rows);
    //}
    // Safety check: 
    if(!match) {
        error("Calibration table empty or wrong version selected!");
    }
    // //
    // //
    // Make final selection from all rows (selected by version):
    //
    int nentries = length(rows);
    int counter = 0;
    match = false;
    for(int i = 0 .. nentries - 1) {
        //if(debug) {
        //    debug_print("rows sliced:" + rows[i]{0} + "/" + rows[i]{1});
        //}
        if(rows[i]{1} == selVal) {
            boolVar = rows[i]{0};
            match = true;
            counter = counter + 1;
        }
    }
    // Safety checks: 
    if(!match) {
        error("Entry " + selVal + " not found in calibration table (" + tabName + "). Call for help and wait to be rescued!");
    }
    //
    if(counter > 1) {
        error("Selector string " + selVal + " is present at least twice in the versioned calibration table(" + tabName + "). Please report this bug to the relevant authorities!");
    }
    // //
    // //
    // Return required value:
    //
    if(debug) {
        debug_print(" If you believe it of not, I found " + tarCol + "=" + boolVar + " as version " + version + " when selecting for " + selCol + "=" + selVal + " in table " + tabName);
    }

    return boolVar;
}

// SpireBbPOF3Init
//
// $Id: SpireBbPOF3Init.txt,v 1.1 2006/08/10 09:38:58 kking Exp $
//
// Building Block to initialise the instrument for POF3 (jiggle map) operation
//
// The complete instrument setup operation is divided into two parts:
//   Configuration: actions that can be executed during the slew to the start
//          position of the S/C pointing mode.
//   Initialisation: actions that must be carried out at the S/C intial pointing
//          position before any observational operations are executed.   
//
// This building Block implements the second part of the setup 
// 
// 04 November 2008: 
//         added data_rate commands
//         added commands to setup the detector sampling
//
block SpireBbPOF3Init SPIRE 8241 {
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF3 Initialisation started");
    SpireMsg(2,"          $Id: SpireBbPOF3Init.txt,v 1.1 2006/08/10 09:38:58 kking Exp $");
    //
    // ..... configuration .....
    //
    int cmd = 0x0;
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP  to On Target
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x8000)");
    Spire_SET_OBS_STEP_RAW(0x8000);
    //
    // set detector offsets
    // set DCU data mode  to Auto Offset 
    cmd = 0x843c0010;
    SpireSendDrcuCmd(cmd,0);
    // start auto offset generation
    cmd = 0x843e0001;
    SpireSendDrcuCmd(cmd,0);
    delay(15);
    //
    // dump detector offsets
    // stop auto offset generation
    cmd = 0x843e0000;
    SpireSendDrcuCmd(cmd,0);
    // set DCU data mode to get offset data
    cmd = 0x843c0018;
    SpireSendDrcuCmd(cmd,0);
    // start offset data dump
    cmd = 0x843e0001;
    SpireSendDrcuCmd(cmd,0);
    //  set datarate
    double rate = 0.0;
    rate = dlookup("Datarates.txt","POffsets","DCU");
    data_rate(rate);
    delay(5);
    // stop offset data dump 
    cmd = 0x843e0000;
    SpireSendDrcuCmd(cmd,0);
    data_rate(0.0);
    //
    // flush data
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(2);
    //
    //  set up detectors for operations
    //
    SpireConfigDcuData("POF3");
    sync();
    //
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF3 Initialisation ended");
    SpireMsg(1,"  ..POF3 Initialisation (" + (time() - t) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_CalGCO_FovMapFpgScan.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Phot FOV Mapping Line Scan (FPG Scan)'   
//
//         in * line_scan_with_off_pointing * mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/09/11 V0.1: Initial version, adapted from
//                  SpirePhoto_CalGCO_FovMappingFpgScan (2008/07/29 V0.7) 
//                  Renamed script; removed test number; removed SSOs, allow
//                  scan in z direction; add debug_print switch; add
//                  SpireProc_Set_ObsStep to line observation
// 2008/09/16 V0.2: Add counter to OFF positions and remove first timing
//                  message. Allow scan along 60deg symmetry axis. Change
//                  description of input. Change formula for gcp_period_min.
//                  Add temporary restriction to non-SSOs.
// 2008/11/12 V0.3: Implement mode setting; Add isBright 
// 2009/02/02 V1.0: Add debug_print as input and pass it to some low 
//                  level scripts. Replace call to SpireProc_Set_ObsStep 
//                  with call to SpireBb_SetObsStep. Introduce 
//                  SpireBb_WaitAtGcp at GCP and use SpireBbScanLine during 
//                  the line scanning to collect data within defined BBIDs. 
//                  Use new SpireBb_EndObsAll and SpireBb_StartObsAll. 
//                  Implemented setting of datarates. Implemented isBright 
//                  setting. Read isbright pars fr.SpireTable_DetectorSettings. 
// 2009/02/18 V1.1: Update to new calibration table structure for Mode setting. 
//                  New setting of datarates. Use SpireBb_PhotSetMode to set 
//                  to PHOTSTBY during SLEW and FINAL_HOLD. Change call to 
//                  SpireBb_StartDcuData.
// 2009/03/04 V1.2: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Set gcp_time to 20 (desired
//                  value for SOVT2)
// 2009/05/07 V1.3: Add in move BSM to hold at start. Gather procedures at 
//                  start and end in separate BB. 
// 2009/06/05 V1.4: Hardcode STBY 'v00' in EndBB (SPR-1477)
// 2009/10/28 V1.5: (SCR-SPIRE-2118) Allow SSO. Hardcode gcp_period for SSOs. 
// 
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in PHOTSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for all three arrays and could be taken from following cal table: 
//   SpireTable_PhotModeParams.txt
//
//  3) That currently the gyro reconstruction is only available for 
//     non-SSO targets.  
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhoto_CalGCO_FovMapFpgScan {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target [deg]
    double dec = 0.0 in [-90.0,90.0]; // DEC of target [deg]
    int naifid = 0; // Put '0' to use RA and DEC, otherwise put correct 'NAFID'
    /* */
    bool isBright = false; // Use settings for bright source (==tick)
    bool refSelected = true; // ExpHSpot (refSelected) parameter
    bool refByOffset = true; // ExpHSpot (refByOffset) parameter   
    double raoff = 0.0 in [0.0,360.0]; // RA of GCP position, or relative offset [deg]
    double decoff = 0.0 in [-90.0,90.0]; // DEC of GCP position, or relative offset [deg]
    string ib = "S14_0"; // Central aperture (defined in SIAM) of raster
    double d1 = 500.0 in [20.0,7200.0]; // Length of the scan line along scan axis [arcsec] 
    double d2 = 31.4 in [2.0,480.0]; // Spacing of adjacent scan lines along orthogonal axis [arcsec]
    int n = 9 in [1,240]; // Number of raster lines or scan lines.
    double rate = 30.0 in [0.1,60.0]; // Scan rate of a line scan [arcsec/s]
    string scan_dir = "plusY" in ["plusY","minusY","plusZ","minusZ","30degplusYZ","210degminusYZ"]; // Scan direction of first line 
    int gcp_time = 20; // Time spend at GCP (gyro calibration position) [s]
    int gcp_period = 600; // Maximum time between successiv GCP visits (Note, set to 64800 for SSOs!)[s]
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // //
    // //
    // Current restrictions:
    //
    if(naifid != 0) {
        message("Note, currently no SSO objects are allowed if gyro reconstruction is needed. Using SSO tracking the visists to the OFF position are minimised by setting gcp_period to 18h.");
        gcp_period = 64800;
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = true;
    bool fts = !phot;
    //
    // Start timing of script:
    int start = time();
    int linestart = time();
    //
    // Line counter (start at 1): 
    int linecount = 1;
    //
    // GCP counter (start at 1):
    int gcpcounter = 1;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    //
    // Currently hardcoded version and model parameter:
    //
    string version03 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    //
    // Dummy value for Spec script:
    // (needed but not used in phot script!)
    //
    int smecHomePosn = 3500;
    // SMEC home position
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS04";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "PEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Increase scan length to allow time to mark start/end of the scan:
    //
    int tStart = 2;
    int tEnd = 2;
    // Note: the two 2 seconds are justified in SpireBbScanLine.txt
    d1 = d1 + double(tStart + tEnd) * rate;
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version03;
    tabName = tabName03;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartFovMapFpgScan(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug));
    // 
    // BBs carried out when the pointing is reached:
    int tinithold = duration(SpireBb_PhotOffsetAuto(debug)) + duration(SpireBb_StartDcuData());
    //
    // BB carried out during pointing:
    //int tp = 0;
    //
    // BB carried at off position:
    int top = duration(SpireBb_WaitAtGcp(gcp_time,debug));
    // == Time spent at the OFF position.
    //
    // BB carried out at the end:
    int tfinalhold = duration(SpireBb_EndFovMapFpgScan(phot,hold_chop,hold_jigg,isBright,version01,version02,debug)) + duration(SpireBb_StopDcuData());
    // 
    // Debug_printing?
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        //debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // Fixed parameters for pointing mode:
    //  
    bool fixed = false;
    // Pattern orientation (true==sky; false==array)
    double yoff = 0.0;
    // Offset of pattern in the direction of the +Y
    double zoff = 0.0;
    // Offset of pattern in the direction of the +Z
    int nrepeat = 1;
    // [1,1200] Number of repetitions of the pattern.
    int thold = 0;
    // The duration of the hold when nhold>0.
    int nhold = 0;
    // Number of nods or raster points or scan lines before
    //              // performing a hold.
    int nload = 0;
    // The number of slews (e.g. nods) before performing 
    //             // a load operation
    int tloadmin = 0;
    // The minimum duration of a load operation.
    // //
    // //
    // Select scan direction: 
    //
    double patt = 90.0;
    // Rotation angle of the pattern
    //
    if(scan_dir == "plusY") {
        patt = 90.0;
    }
    if(scan_dir == "minusY") {
        patt = 270.0;
    }
    if(scan_dir == "plusZ") {
        patt = 0.0;
    }
    if(scan_dir == "minusZ") {
        patt = 180.0;
    }
    if(scan_dir == "30degplusYZ") {
        patt = 30.0;
    }
    if(scan_dir == "210degminusYZ") {
        patt = 210.0;
    }
    // //
    // //
    // Select the number (k) of scan lines before performing a measurement
    // at the GCP: 
    //
    // Start with k=1:
    //
    int k = 1;
    //
    // Calculate times in pointing mode:
    //
    int[] ts_tr = line_scan_with_off_pointing(false,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,fixed,patt,yoff,zoff,n,d1,d2,rate,k,top,raoff,decoff,nrepeat,thold,nhold,tloadmin,nload);
    // returns: {tobs, tslew, tacc, tdec, tl, tll, tsop, tload, tend}
    if(debug) {
        debug_print("Pointing vector for k=1: " + ts_tr);
    }
    int tacc = ts_tr[2];
    // acceleration time
    int tdec = ts_tr[3];
    // deceleration time
    int tl = ts_tr[4];
    // time for actual scan of single line in map area 
    int tll = ts_tr[5];
    // turnaround time bewteen 2 lines 
    int tsop = ts_tr[6];
    // slew time from/to OFF position 
    //                      Note: 'tsop' includes acceleration/deceleration time
    //
    // Calculate/check minimum time between successive visits to GCP position:
    //
    int gcp_period_min = tl + 2 * tsop + top;
    if(debug) {
        debug_print("gcp_period_min: " + gcp_period_min);
    }
    if(gcp_period_min > gcp_period) {
        error("Maximum time between successiv GCP visits smaller than minimum time between two possible visits!");
    }
    //
    // Loop to find best k:
    //
    // Calculate time between two offset positions:  
    int tboff = k * tl + (k - 1) * tll + (k - 1) * (tacc + tdec) + 2 * tsop + gcp_time;
    if(debug) {
        debug_print("Time between two offset positions: " + tboff);
    }
    //
    do {
        k = k + 1;
        //      
        // Calculate new time between two offset positions:  
        tboff = k * tl + (k - 1) * tll + 0 * (tacc + tdec) + 2 * tsop + gcp_time;
        if(debug) {
            debug_print("k is now: " + k);
            debug_print("New time between two offset positions: " + tboff);
        }
    } while (tboff < gcp_period);
    //
    // Set best k:
    //
    if(k > 1) {
        // use previous k values
        k = k - 1;
    }
    if(k > n) {
        // k must not be larger than number of lines
        k = n;
    }
    if(debug) {
        debug_print("selected k is: " + k);
    }
    // //
    // //
    // Set pointing mode:
    //
    //int[] ts = line_scan_with_off_pointing(true,tslewmin,tih,tfh,ib,naifid,
    // ra,dec,fixed,patt,yoff,zoff,n,d1,d2,rate,k,top,raoff,decoff,nrepeat,
    // thold,nhold,tloadmin,nload);
    //
    int[] ts = line_scan_with_off_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,fixed,patt,yoff,zoff,n,d1,d2,rate,k,top,raoff,decoff,nrepeat,thold,nhold,tloadmin,nload);
    //
    // //
    // //
    // Fill in timings of actual pointing mode:
    tacc = ts[2];
    // acceleration time
    tdec = ts[3];
    // deceleration time
    tl = ts[4];
    // time for actual scan of single line in map area 
    tll = ts[5];
    // turnaround time bewteen 2 lines 
    tsop = ts[6];
    // slew time from/to OFF position 
    //                      Note: 'tsop' includes acceleration/deceleration time
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
        debug_print("Time for actual scan of single line in requested area: " + tl);
    }
    // //
    // //
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //     
            SpireBb_StartFovMapFpgScan(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD (spacecraft is idling at source)
            //
            //delay(tinithold);
            // //
            // //
            // Set offsets:
            //
            SpireBb_PhotOffsetAuto(debug);
            // //
            // //
            // Start data generation before scan: 
            //
            SpireBb_StartDcuData();
            //
        }
        if(state[0] == 4) {
            // STATE = OFF position
            // //
            // //
            // Show time elapsed between visits to GCP:
            //
            int t = time() - start;
            if(gcpcounter > 1) {
                message("Time elapsed since last visit to GCP: " + t);
                if(debug) {
                    debug_print("Time elapsed since last visit to GCP: " + t);
                }
            }
            gcpcounter = gcpcounter + 1;
            //
            // Reset timer:           
            start = time();
            // //
            // //
            // Wait at GCP:
            //
            SpireBb_WaitAtGcp(gcp_time,debug);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activities )
            // //
            // //
            // Stop data generation after scan: 
            //
            SpireBb_StopDcuData();
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            version03 = "v00";
            model = "initial";
            //
            SpireBb_EndFovMapFpgScan(phot,hold_chop,hold_jigg,isBright,version01,version02,debug);
            //
        }
        if(state[0] == 6) {
            //delay(thold);
        }
        if(state[0] == 8) {
            // STATE =  ( line )
            //
            // //
            // //
            // Start timing:
            //
            int tscan = time();
            // //
            // //
            // Debug printing
            //
            if(debug) {
                debug_print("state[0]: " + state[0]);
                debug_print("state[1]: " + state[1]);
                debug_print("state[2]: " + state[2]);
                debug_print("linecount: " + linecount);
            }
            // 
            if(linecount == 1) {
                linestart = time();
            } else {
                int tline = time() - linestart;
                if(debug) {
                    debug_print("Time elapsed since first line: " + tline);
                }
            }
            // //
            // //
            // Wait while scan is performed:
            //
            SpireBbScanLine(tl,linecount);
            linecount = linecount + 1;
            //
        }
        if(state[0] == 9) {
            //delay(tloadmin);
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndFpgInitialPointing.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of 
// SpirePhoto/Spectro_CalGCO_FpgInitialPointing.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V1.0: Initial version adapted from
//                  SpireBb_EndBsmAngleCal (2009/05/05 V1.2),
//                  SpirePhoto_CalGCO_FpgInitialPointing (2009/03/03 V1.3), and
//                  SpireSpectro_CalGCO_FpgInitialPointing (2009/03/03 V0.4)
// 2009/05/07 V1.1: Set dcuFrameNumber and mcuFrameNumber back to continuous
//                  to unset setting passed to VM. 
// 2009/06/05 V1.2: Replace Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd 
//                  as requested in SPR-1482.
// 2009/07/03 V1.3: Set SMEC framerate back to SPEC_STBY. It was switched off
//                  for this test during SpireBb_StartFpgInitialPointing.txt
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndFpgInitialPointing SPIRE 14055 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    int hold_chop = 37632; // Chop hold position [Dec(Hex)]
    int hold_jigg = 39520; // Jiggle hod position [Dec(Hex)]
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndFpgInitialPointing reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set obsstep back to 0:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP(0)");
    Spire_SET_OBS_STEP(0);
    // //
    // //
    // Set instrument back to Phot/Spec-STBY:
    //
    if(phot) {
        SpireProc_Set_PhotMode("PHTSTBY",isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Set number of DCU frames to continuous:
    //
    int dcuFrameNumber = 0;
    if(phot) {
        dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","PHTSTBY","dcuFrameNumber","v00",debug);
    } else {
        dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuFrameNumber","v00",debug);
    }
    //
    SpireSendDrcuCmd(0x843d0000 + dcuFrameNumber,0);
    // //
    // //
    // Set number of MCU frames to continuous:
    //
    int mcuFrameNumber = 0;
    if(phot) {
        mcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","PHTSTBY","mcuFrameNumber","v00",debug);
    } else {
        mcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","mcuFrameNumber","v00",debug);
    }
    SpireSendDrcuCmd(0x91c30000 + mcuFrameNumber,0);
    delay(1);
    // //
    // //
    // Set SMEC framerate (== SMEC sampling rate) back to SPEC_STBY:
    // (Note, hardcoded version to go back to STBY)
    //
    if(!phot) {
        int smecFrameRate = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","smecFrameRate","v00",debug);
        SpireProc_Set_SmecFramerate(smecFrameRate,debug);
    }
    // //
    // //
    // End observation:
    //
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndFpgInitialPointing reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

//CLName: SpireBb_LoadTableChop
//VMVersion: 2.8
//CLVersion: 1.5
//CLCVSId: $ID$
//TableId: 0x47
//TableLength: 0x32
//Date: 081208133824
block SpireBb_LoadTableChop SPIRE 3335 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableChop started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0x47
    Spire_SET_TABLE(0x47,0x32);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x47,0x0,38,[{0x12000026},{0x501},{0x12000027},{0x4701},{0x53020026},{0x2000000},{0x201e0000},{0x201f0001},{0x20200002},{0x20210003},{0x20220004},{0x20230007},{0x20240009},{0x12000026},{0x501},{0x12000027},{0x4702},{0x53020026},{0x2000000},{0x20000005},{0x20010006},{0x20020007},{0x20030008},{0x20040009},{0x60640003},{0x32000018},{0x12000026},{0x501},{0x12000027},{0x4703},{0x53020026},{0x2000000},{0x20050001},{0x20060002},{0x2000001e},{0x2001001f},{0x20020020},{0x20030021}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x47,0x26,12,[{0x20040022},{0x20070024},{0x20080023},{0x60640004},{0x32000007},{0x12000026},{0x501},{0x12000027},{0x4704},{0x53020026},{0x2000000},{0x7f000000}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x47,0x0,0x0);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableChop ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_PcalOn.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set on PCAL to input PCAL bias level.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/04/01 V0.1: Initial version adapted from
//                  SpireBb_PcalFlash (2009/02/18 V1.4)
//
// Note, by setting pcal_bias to 0.0 the same script switches OFF PCAL.
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_PcalOn SPIRE 14040 {
    double pcal_bias = 3.8 in [0.0,7.0]; // PCAL bias level [mA]
    string version = "v01"; // Version in cal table SpireTable_PcalCurrentConvCoef
    bool debug = false;
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB PcalOn started");
    SpireMsg(2,"          $Id:$");
    // //
    // //
    // Set the BBID and STEP:
    //
    // Set BBID:
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    // //
    // //
    // Set PCAL bias:
    //
    SpireProc_PcalOn(pcal_bias,version,debug);
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB PcalOn ended");
    SpireMsg(1,"  ..PcalOn (" + (time() - t) + " seconds)");
}

// $Id: PacsPhotCommandOBCP3.txt,v 1.6 2007/08/10 10:25:10 dcesarsk Exp $ 
// Purpose       : Execute OBCP#3 with the provided parameters
//
// CUS author    : DAC
//
// Input arguments
// Type                      Description
// tuple  {double,int,int,  {waveLen,order,gratPos,
//         int,int,int}      gratWidth,nbStep,gratStep}  
//
// Return values
// Type    Name      Default      Description
//
// Description   : Calls OBCP#3 (OBCP_fixed_fixed_photo) with given
//                 parameters.
//                 OBCP3 (aka fixed_fixed) performs symmetrical choping of
//                 amplitude around
//                 3 positions (called P2, P7, and P8 in the documentation). 
//                 Here, P7 and P8 are computed as 
//                 P7 = P2 + max_dither/2
//                 P8 = P2 - max_dither/2 
//                 max_dither is stored in a CAL-U file read by 
//                 PacsPhotEstimatorOBCPn
//
// Dependencies  : OBCP_fixed_fixed_phot
//                 DMC_fixed_fixed_phot
//
// Preconditions : 
//                 
// Comments      :
// 
// History       : 
// 0.1 DAC 10-aug-2006. Created from PacsPhotCommandOBCP5
// 0.2 DAC 31-aug-2006 Return actual duration (includes TC)
// 0.3 DAC  1-sep-2006 WARNING: the chopper movements must be given as
//                              relative, i.e. a displacement
// 0.4 DAC 12-jan-2007 Use max_dither and max_dither/2
// 0.5 DAC 19-jan-2007 Use symmetrical dithering: + - max_dither/2
//
int[] procedure PacsPhotCommandOBCP3 {
    {int,int,int,int,int,int,int,int,int} confPHOTblu = {0,0,0,0,0,0,0,0,0}; // BLUE SPU parameters
    {int,int,int,int,int,int,int,int,int} confPHOTred = {0,0,0,0,0,0,0,0,0}; // RED  SPU parameters
    {int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int} confOBCP = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // OBCP parameters
    bool verbose = true; // Print debug information
}{
    // Register starting time
    int start_time = time();
    // Create array of durations
    int[] time_array = [0,0,0,0,0];
    if(verbose) {
        debug_print("+++ Starting PhotCommandOBCP3");
        debug_print("OBCP3: " + confOBCP);
    }
    // Long sequence to "unpack" contents of tuples
    // (indices are not sequential since confXXXX tuples are inherited from
    //  SPECTRO)
    int gain = confPHOTblu{0};
    int comp_mode_blu = confPHOTblu{3};
    int glitch_det_blu = confPHOTblu{4};
    int nb_raw_blu = confPHOTblu{6};
    gain = confPHOTred{0};
    int comp_mode_red = confPHOTred{3};
    int glitch_det_red = confPHOTred{4};
    int nb_raw_red = confPHOTred{6};
    int nb_main_loops = confOBCP{0};
    int max_dither = confOBCP{1};
    int nb_chop_cycle = confOBCP{2};
    int nb_SRC_REF = confOBCP{3};
    int nb_rdouts_plateau = confOBCP{4};
    int nb_CS1_CS2 = confOBCP{5};
    int chop_pos_SRC = confOBCP{12};
    int chop_pos_REF1 = confOBCP{13};
    int chop_pos_REF2 = confOBCP{14};
    int chop_pos_CS1 = confOBCP{15};
    int chop_pos_CS2 = confOBCP{16};
    int chop_def = confOBCP{17};
    int detector = confOBCP{18};
    int filterPOS = confOBCP{19};
    // Call OBCP for the current  S/C position
    // Chop between SRC and REF1
    // Relative displacement
    int chop_REL = chop_pos_REF1 - chop_pos_SRC;
    if(verbose) {
        debug_print("OBCP3 P#2/P#5: " + chop_pos_SRC + "/" + chop_REL);
    }
    time_array = OBCP_fixed_fixed_photo(nb_main_loops,chop_pos_SRC,nb_rdouts_plateau,nb_chop_cycle,chop_REL,-chop_REL,chop_pos_SRC + max_dither / 2,chop_pos_SRC - max_dither / 2,comp_mode_blu,comp_mode_red);
    // Add sync()
    sync();
    // Return elapsed time
    time_array[0] = time() - start_time;
    if(verbose) {
        debug_print("CmdOBCP3 returns " + time_array);
    }

    return time_array;
}

// CVS comments  : $Id: PacsPhotCommandOBCP4.txt,v 1.3 2007/04/25 15:14:04 dcesarsk Exp $ 
// Purpose       : Execute OBCP#4 with the provided parameters
//
// CUS author    : DAC
// Script file   : PacsPhotCommandOBCP4.txt 
//
// Input arguments
// Type                      Description
// tuple  {double,int,int,  {waveLen,order,gratPos,
//         int,int,int}      gratWidth,nbStep,gratStep}  
//
// Return values
// Type    Name      Default      Description
//
// Description   : Calls OBCP#4 (OBCP_chopped_photometry) with given
//                 parameters
// Dependencies  : OBCP_chopped_photometry
//                 DMC_phot_2_3_chop
//
// Preconditions : 
//                 
// Comments      : Filter must be positioned before calling this procedure
// since there is no FLTW move here!! This insures that (eventual) nods have 
// same duration. PacsPhotSlewCal moves filter to needed position and leaves
// it there.
// 
// History       : 
// 0.1 DAC 24-nov-2005
// 0.2 DAC 31-aug-2006 - Return elapsed time
//                     - Editorial cleanup (remove SPECTRO from confXXX)
//
int[] procedure PacsPhotCommandOBCP4 {
    {int,int,int,int,int,int,int,int,int} confPHOTblu = {0,0,0,0,0,0,0,0,0}; // BLUE SPU parameters
    {int,int,int,int,int,int,int,int,int} confPHOTred = {0,0,0,0,0,0,0,0,0}; // RED  SPU parameters
    {int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int} confOBCP = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // OBCP parameters
    bool verbose = true; // Print debug information
}{
    // Register start time
    int start_time = time();
    // Create array of durations
    int[] time_array = [0,0,0,0,0];
    if(verbose) {
        debug_print("+++ Starting PhotCommandOBCP4");
        debug_print("OBCP: " + confOBCP);
    }
    // Long sequence to "unpack" contents of tuples
    // (indices are not sequential since confXXX are inherited from SPECTRO)
    int gain = confPHOTblu{0};
    int comp_mode_blu = confPHOTblu{3};
    int glitch_det_blu = confPHOTblu{4};
    int nb_raw_blu = confPHOTblu{6};
    gain = confPHOTred{0};
    int comp_mode_red = confPHOTred{3};
    int glitch_det_red = confPHOTred{4};
    int nb_raw_red = confPHOTred{6};
    int nb_cycles_obs_cal = confOBCP{0};
    int nb_SRC_REF = confOBCP{3};
    int nb_rdouts_plateau = confOBCP{4};
    int nb_CS1_CS2 = confOBCP{5};
    int chop_pos_SRC = confOBCP{12};
    int chop_pos_REF1 = confOBCP{13};
    int chop_pos_REF2 = confOBCP{14};
    int chop_pos_CS1 = confOBCP{15};
    int chop_pos_CS2 = confOBCP{16};
    int chop_def = confOBCP{17};
    int detector = confOBCP{18};
    int filterPOS = confOBCP{19};
    // Call OBCP for the current  S/C position
    // Chop SRC-REF1-SRC-REF2
    time_array = OBCP_chopped_photometry(nb_SRC_REF,chop_pos_SRC,nb_rdouts_plateau,chop_pos_REF1,chop_pos_REF2,nb_cycles_obs_cal,nb_CS1_CS2,chop_pos_CS1,chop_pos_CS2,comp_mode_blu,comp_mode_red,chop_def);
    // Add sync()
    sync();
    // Return elapsed time
    time_array[0] = time() - start_time;
    if(verbose) {
        debug_print("CmdOBCP4 returns " + time_array);
    }

    return time_array;
}

// Reset default CCU monitoring period after cooler recycling
//
command SpireCcuMonitorPeriodDefault HFKACQP1 {
} {
    bus_schedule(SC, 6);
}

///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_FovMapCrossRaster.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to calculate the positions of a cross raster to be used
//  in a custom_map pointing mode for photometer and spectrometer.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/16 V1.0: Initial version renamed from
//                  SpireProc_CalcParam_PhotFovMapCrossRaster (2008/08/04 V0.1)
//                  Move debug option to input. 
// 2009/09/05 V1.1: Allow to visit raster points in reverse order SCR-SPIRE-1915
//
///////////////////////////////////////////////////////////////////////////
//
{double[],double[],bool[]} procedure SpireProc_CalcParam_FovMapCrossRaster {
    double d1 = 4.0 in [2.0,480.0]; // Angular stepsize along Y axis [arcsec] 
    double d2 = 4.0 in [2.0,480.0]; // Angular stepsize along Z axis [arcsec]
    int m = 5 in [3,2997]; // Number of points in the Y direction [odd number!]
    int k = 0 in [0,999]; // Additional visits to GCP on each hand of the cross
    bool reverse = false; // Visit raster pts in reverse order (==tick)
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Set fixed parameters:
    //
    int n = m;
    // Number of points in the Z direction [odd number!]
    // --> only symmetric cross raster allowed
    // //
    // //
    // Calculate arrays for custom_map pointing:
    //
    double[] yarray = [0.0];
    double[] zarray = [0.0];
    bool[] raster = [false];
    //
    // Set center as starting point:
    //
    yarray[0] = 0.0;
    zarray[0] = 0.0;
    raster[0] = false;
    //
    // Setup:
    //
    int index = 1;
    int zindex = 1;
    int ystart = -1 * iceil(0.5 * double(m - 1));
    int zstart = -1 * iceil(0.5 * double(n - 1));
    int numtrue = iceil(0.5 * double(m - 1) / double(k + 1));
    int nysteps = -2 * ystart + 1;
    int nzsteps = -2 * zstart + 1;
    if(debug) {
        debug_print("ystart/zstart: " + ystart + "/" + zstart);
        debug_print("numtrue: " + numtrue);
    }
    //
    // Y-axis:
    //
    do {
        if(debug) {
            debug_print("Setting up Y-axis");
        }
        yarray[index] = double(ystart) * d1 + double(index - 1) * d1;
        zarray[index] = 0.0;
        // Mark GCPs:
        if(yarray[index] == 0.0) {
            raster[index] = false;
        } else {
            raster[index] = true;
        }
        index = index + 1;
    } while (index < nysteps + 1);
    //
    // Add visit to center at end of Y-raster:
    //
    yarray[index] = 0.0;
    zarray[index] = 0.0;
    raster[index] = false;
    index = index + 1;
    //
    // Z-axis:
    //
    do {
        if(debug) {
            debug_print("Setting up Z-axis");
        }
        zarray[index] = double(zstart) * d2 + double(zindex - 1) * d2;
        yarray[index] = 0.0;
        if(zarray[index] == 0.0) {
            raster[index] = false;
        } else {
            raster[index] = true;
        }
        index = index + 1;
        zindex = zindex + 1;
    } while (zindex < nzsteps + 1);
    //
    // Add visit to center at end:
    //
    yarray[index] = 0.0;
    zarray[index] = 0.0;
    raster[index] = false;
    //
    // printing:
    //
    if(debug) {
        debug_print("yarray: " + yarray);
        debug_print("zarray: " + zarray);
        debug_print("raster: " + raster);
        debug_print("length(ystart/zstart/raster): " + length(yarray) + "/" + length(zarray) + "/" + length(raster));
    }
    // //
    // //
    // Add additional visits to GCP:
    //
    double[] yarray_new = [0.0];
    double[] zarray_new = [0.0];
    bool[] raster_new = [false];
    //
    int end = length(raster);
    int nindex = 0;
    int tcount = 0;
    for(int counter = 1 .. end) {
        if(debug) {
            debug_print("Loop number: " + counter);
            debug_print("end: " + end);
            debug_print("nindex: " + nindex);
            debug_print("tcount: " + tcount);
        }
        if(raster[counter - 1] == true) {
            if(tcount == numtrue) {
                // Check if next point is not a visit to GCP:
                //if (raster[(counter)] == true)
                //{
                debug_print("Add visit to GCP!");
                yarray_new[nindex] = 0.0;
                zarray_new[nindex] = 0.0;
                raster_new[nindex] = false;
                nindex = nindex + 1;
                //}
                yarray_new[nindex] = yarray[counter - 1];
                zarray_new[nindex] = zarray[counter - 1];
                raster_new[nindex] = true;
                nindex = nindex + 1;
                // Reset tcount
                tcount = 0;
            } else {
                yarray_new[nindex] = yarray[counter - 1];
                zarray_new[nindex] = zarray[counter - 1];
                raster_new[nindex] = true;
                nindex = nindex + 1;
            }
            tcount = tcount + 1;
        } else {
            // reset true counter:
            tcount = 0;
            yarray_new[nindex] = yarray[counter - 1];
            zarray_new[nindex] = zarray[counter - 1];
            raster_new[nindex] = false;
            nindex = nindex + 1;
        }
        counter = counter + 1;
    }
    // //
    // //
    // Allow to reverse order:
    //
    if(reverse) {
        double[] yarray_reverse = [0.0];
        double[] zarray_reverse = [0.0];
        end = length(zarray_new);
        index = 0;
        for(int rcount = 1 .. end) {
            yarray_reverse[index] = yarray_new[index] * -1.0;
            zarray_reverse[index] = zarray_new[index] * -1.0;
            index = index + 1;
        }
        yarray_new = yarray_reverse;
        zarray_new = zarray_reverse;
    }
    //
    if(debug) {
        debug_print("yarray: " + yarray_new);
        debug_print("zarray: " + zarray_new);
        debug_print("raster: " + raster_new);
        debug_print("length(ystart/zstart/raster): " + length(yarray_new) + "/" + length(zarray_new) + "/" + length(raster_new));
    }
    //

    return {zarray_new,yarray_new,raster_new};
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SetBsm.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set BSM parameters
//
///////////////////////////////////////////////////////////////////////////
//
// K.King:
// 2009/11/09 V0.1: Initial version adapted from
// 
// 2010/03/04 V0.2: Now also setting CHOPINTLIMIT and CHOPINTREF
// 2010/03/25 V1.3: Removed the setting of CHOPINTLIMIT and CHOPINTREF
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SetBsm SPIRE 3404 {
    int chopFfOffset = 0;
    int chopFfGain = 0;
    int chopKp = 1000; // Chop Kp
    int chopKi = 536; // Chop Ki
    int chopKd = 3504; // Chop Kd
    int jiggFfOffset = 0;
    int jiggFfGain = 0;
    int jiggKp = 1000; // Jiggle Kp
    int jiggKi = 536; // Jiggle Ki
    int jiggKd = 3504; // Jiggle Kd
    int cjCouple = 0; // ChopJiggleCouple
    int cjdCouple = 0;
    int sampFreq = 10;
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // Define some variables:
    //
    string hstr = "";
    // a hex string
    string tstr = "";
    // a time string
    //
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": SpireBb_SetBsmstarted");
    SpireMsg(2,"          $Id: $");
    hstr = SpireHexStr($BBID,8);
    SpireMsg(3,"          BBID = " + hstr);
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set PID parameters:
    //
    SpireProc_Set_Bsm(chopFfOffset,chopFfGain,chopKp,chopKi,chopKd,jiggFfOffset,jiggFfGain,jiggKp,jiggKi,jiggKd,cjCouple,cjdCouple,sampFreq,debug);
    // //
    // //
    // End BB:
    //
    sync();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SetBsm ended");
    SpireMsg(1,"  ..Set BSM parameters (" + (time() - t) + " secs)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_Cal_LoadCurvePcalOn.txt
//
///////////////////////////////////////////////////////////////////////////
// 
//  CUS script for: 'Phot Load Curve with PCAL on' 
//
//  in *basic_fine_pointing* or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/04/01 V0.1: Initial version adapted from 
//                  SpirePhoto_Cal_StdLoadCurve (2009/03/04 V1.3)
// 2009/05/06 V0.2: Add in move BSM to hold at start. Gather procedures at 
//                  start and end in separate BB. 
// 2009/06/05 V1.0: Hardcode STBY 'v00' in EndBB (SPR-1477)
// 2010/01/06 V1.1: Edit default parameters for input phases 
//                  and set version05 to v05 (SCR-SPIRE-2300)
//
///////////////////////////////////////////////////////////////////////////
//
//  Script assumes that:
//
//  1)  Instrument is in PHOTSTBY at beginning 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Phase is kept constant (from input) during this test, i.e no 
//     adjustment of the phase with changing bias amplitude and frequency
//
//  3) Bias frequency, sampling rate, and phase are input parameters
//
//  4) Boresight of array can be read from following cal table:
//     SpireTable_OpsParms.txt   
//
//  5) PCAL bias calibration coefficients are read from following cal table:
//     SpireTable_PcalCurrentConvCoef.txt
//
//  6) List of bias amplitudes are read from same calibration file as for the 
//     SpirePhoto_Cal_StdLoadCurve, i.e. SpireTable_StdLoadCurveLevels.txt
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhoto_Cal_LoadCurvePcalOn {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; // NAIF identifier
    bool isBright = false; // Use settings for bright source (==tick)
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    double biasfreq = 130.2 in [70.0,200.0]; // Bias frequency [Hz]
    double samplerate = 18.6 in [1.0,20.0]; // Sampling rate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    double phasedeg_psw = 179.294 in [0.0,360.0]; // PSW Bias phase [deg]
    double phasedeg_pmw = 179.294 in [0.0,360.0]; // PMW Bias phase [deg]
    double phasedeg_plw = 183.529 in [0.0,360.0]; // PLW Bias phase [deg]
    double phasedeg_ptc = 203.294 in [0.0,360.0]; // PTC Bias phase [deg]
    int ftime = 10; // Readout time at each bias level [s]
    double pcal_bias = 3.8 in [0.0,7.0]; // PCAL bias level [mA]
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_StdLoadCurveLevels
    string version05 = "v05"; // Version in cal table SpireTable_OpsParms.txt
    string version09 = "v01"; // Version in cal table SpireTable_PcalCurrentConvCoef  
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Check for is bright setting: 
    //
    if(isBright) {
        isBright = false;
        error("IsBright does not make sense here. Try again (e.g. subtract the phase shift manually from the input)!");
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = true;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_StdLoadCurveLevels.txt";
    string tabName04 = "SpireTable_BsmNominalSettings.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    string tabName09 = "SpireTable_PcalCurrentConvCoef.txt";
    //
    // Currently hardcoded version and model parameter:
    //
    string version04 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    //
    // Dummy value for Spec script:
    // (needed but not used in phot script!)
    //
    int smecHomePosn = 3500;
    // SMEC home position
    int ssw_bias = 45;
    //
    int slw_bias = 45;
    //
    int ssw_phase = 128;
    //
    int slw_phase = 128;
    // 
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS15";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "PEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Retrieve bias levels used for the load curve:
    // 
    tabName = tabName03;
    version = version03;
    int[] nbiaslist = SpireProc_CalcParam_LoadCurve(tabName,version,debug);
    //
    // Lookup first bias level:    
    int psw_bias = nbiaslist[0];
    int pmw_bias = nbiaslist[0];
    int plw_bias = nbiaslist[0];
    int ptc_bias = nbiaslist[0];
    // //
    // //
    // Convert user input to Hex values:
    //
    // for bias frequency and sample rate: 
    // 
    int[] hexvalues = SpireProc_CalcParam_BiasFreqSampFreq(biasfreq,samplerate,fts,debug);
    int mclkdiv = hexvalues[0];
    int biasdiv = hexvalues[1];
    if(debug) {
        debug_print("Hex values of mclkdiv/biasdiv are: " + mclkdiv + " " + biasdiv);
    }
    //
    // for bias phase:
    //
    int[] phasehex = SpireProc_CalcParam_PhotPhaseConvert(phasedeg_psw,phasedeg_pmw,phasedeg_plw,phasedeg_ptc,debug);
    int psw_phase = phasehex[0];
    int pmw_phase = phasehex[1];
    int plw_phase = phasehex[2];
    int ptc_phase = phasehex[3];
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version04;
    tabName = tabName04;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // // // // // // // // // // // // // // // // 
    // // // // // // // // // // // // // // // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartLoadCurvePcalOn(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,psw_phase,pmw_phase,plw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug));
    // 
    // BBs carried out when the pointing is reached:
    if(pointing) {
        int tinithold = 0;
    } else {
        tinithold = tslewmin;
    }
    //
    // BB carried out during pointing:
    int tp = duration(SpireProc_Exec_PhotLoadCurvePcalOn(nbiaslist,ftime,pcal_bias,version09,debug));
    //
    // BB carried out at the end:  
    int tfinalhold = duration(SpireBb_EndLoadCurvePcalOn(phot,isBright,version01,version02,debug));
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartLoadCurvePcalOn(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,psw_phase,pmw_phase,plw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation:
                //
                SpireBb_StartLoadCurvePcalOn(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,psw_phase,pmw_phase,plw_phase,ptc_phase,ssw_bias,slw_bias,ssw_phase,slw_phase,debug);
                //
            }
            //
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            // //
            // //
            // Execute load curve with PCAL on:
            //
            SpireProc_Exec_PhotLoadCurvePcalOn(nbiaslist,ftime,pcal_bias,version09,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            //
            SpireBb_EndLoadCurvePcalOn(phot,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_PcalFlash.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to perform photometer PCAL flash via VM 
//
// Note: VM does not reset dcusample/bsmsample at end, so this needs 
//       to be done in the surrounding end script.         
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/11/07 V0.1: Initial version adapted from
//                  SpireBb_PCALFlash (2008/08/12 V0.1)
//                  Change name 'PCAL' to 'Pcal'
// 2009/01/27 V1.0: (KJK) Updated for use by Cal and AOT observations.
//                       Added more input parameters (vmId,vmIndex,nParms,
//                       rate, step, debug). Added Hspot messages. Now reset 
//                       and flush all fifos (MCU data could be generated). 
//                       Remove 'set number of frames to continuous' this 
//                       needs to be done at the very end of the observation. 
//                       Replaced delay(1) with sync() at the end. Removed
//                       BBID unsetting. Added more comments. Now include
//                       setting of NHK STEP parameter. Adding setting
//                       and unsetting of datarate.  
// 2009/01/30 V1.1: (MP) Adding more information to header above. 
//                       Adding delay(2) after FLUSH_FIFO.  
// 2009/02/11 V1.2: (KJK) Made some changes.
//                       Fix bug in calculation of wait_time. Removed 
//                       pcal_dcudelay and reduced the 10sec to 1sec. 
//                       The 10 was a left-over from the old IST script.
//                       Replaced call to Spire_SEND_DRCU_COMMAND with
//                       SpireSendDrcuCmd. Ditto for Spire_SET_OBS_STEP_RAW
//                       use now SpireProc_Set_ObsStep. 
// 2009/02/13 V1.3: (MP) Adding more information about changes to header above. 
// 2009/02/18 V1.4: (MP) Replace all commands by call to new low level
//                       procedure SpireProc_PcalFlash. Removing the datarate
//                       setting. 
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_PcalFlash SPIRE 14009 {
    int vmId = 0x46;
    int vmIndex = 0;
    int nParms = 9;
    int pcal_lowbias = 100;
    int pcal_highbias = 2000;
    int pcal_ncycles = 8;
    int pcal_period = 250000;
    int pcal_dcumode = 3;
    int pcal_ndcusamples = 11;
    int pcal_dcudelay = 12000;
    int pcal_scumode = 0;
    int pcal_scusamples = 9;
    int step = 0;
    bool debug = false;
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB PcalFlash started");
    SpireMsg(2,"          $Id:$");
    // //
    // //
    // Set the BBID and STEP:
    //
    // Set BBID:
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    // //
    // //
    // Reset all fifos:
    //
    SpireProc_PcalFlash(vmId,vmIndex,nParms,pcal_lowbias,pcal_highbias,pcal_ncycles,pcal_period,pcal_dcumode,pcal_ndcusamples,pcal_dcudelay,pcal_scumode,pcal_scusamples,step,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB PcalFlash ended");
    SpireMsg(1,"  ..PcalFlash (" + (time() - t) + " seconds)");
}

// SpirePOF2Estimate
//
// $Id:$
//
// This procedure calculates the estimated noise and signal/noise
//  for the given observing time.
//
//  for input values, a value less than 0 indicates value unknown
//
//
//  20/04/07: v1.3: SCR3054
//            v1.4: SCR3012
//  07/02/09: Updated to select sensitivity tables depending on value of isBright
//
//
{string,double,double,double,double,bool}[] procedure SpirePOF2Estimate {
    double osit = 0.0; // on-source integration time
    double sourceFluxPSW = -1.0;
    double sourceFluxPMW = -1.0;
    double sourceFluxPLW = -1.0;
    bool isBright = false;
}{
    SpireMsg(3,"          Calculating POF2 noise estimates");
    SpireMsg(3,"          $Id:$");
    SpireMsg(3,"          Input:");
    SpireMsg(3,"            Osit: " + osit);
    SpireMsg(3,"            PSWFlux: " + sourceFluxPSW);
    SpireMsg(3,"            PMWFlux: " + sourceFluxPMW);
    SpireMsg(3,"            PLWFlux: " + sourceFluxPLW);
    SpireMsg(3,"            isBright: " + isBright);
    //
    // fetch the flux uncertainty information for POF2
    string tabName = "Phot_Sensitivities.txt";
    if(isBright) {
        tabName = "Phot_BrightSensitivities.txt";
    }
    double psw_func = dlookup(tabName,"POF2","PSWFluxUnc");
    double pmw_func = dlookup(tabName,"POF2","PMWFluxUnc");
    double plw_func = dlookup(tabName,"POF2","PLWFluxUnc");
    // fetch confusion limits
    double psw_conf = dlookup(tabName,"POF2","PSWConfLim");
    double pmw_conf = dlookup(tabName,"POF2","PMWConfLim");
    double plw_conf = dlookup(tabName,"POF2","PLWConfLim");
    SpireMsg(3," Input Sensitivity Values:");
    SpireMsg(3,"            Band:                                PSW              PMW             PLW");
    SpireMsg(3,"            Flux Uncertainty:       " + psw_func + "            " + pmw_func + "          " + plw_func);
    SpireMsg(3,"            Conf Limit:                 " + psw_conf + "            " + plw_conf + "          " + plw_conf);
    //
    // calculate noise estimates
    {string,double,double,double,double,bool}[] estimates = [{"250",sourceFluxPSW,-1.0,-1.0,psw_conf,false},{"350",sourceFluxPMW,-1.0,-1.0,pmw_conf,false},{"500",sourceFluxPLW,-1.0,-1.0,plw_conf,false}];
    estimates[0]{2} = psw_func / sqrt(osit);
    if(estimates[0]{2} < psw_conf) {
        estimates[0]{5} = true;
    }
    if(sourceFluxPSW >= 0.0) {
        estimates[0]{3} = sourceFluxPSW / estimates[0]{2};
        if(estimates[0]{3} > 200.0) {
            estimates[0]{3} = 200.0;
        }
    }
    estimates[1]{2} = pmw_func / sqrt(osit);
    if(estimates[1]{2} < pmw_conf) {
        estimates[1]{5} = true;
    }
    if(sourceFluxPMW >= 0.0) {
        estimates[1]{3} = sourceFluxPMW / estimates[1]{2};
        if(estimates[1]{3} > 200.0) {
            estimates[1]{3} = 200.0;
        }
    }
    estimates[2]{2} = plw_func / sqrt(osit);
    if(estimates[2]{2} < plw_conf) {
        estimates[2]{5} = true;
    }
    if(sourceFluxPLW >= 0.0) {
        estimates[2]{3} = sourceFluxPLW / estimates[2]{2};
        if(estimates[2]{3} > 200.0) {
            estimates[2]{3} = 200.0;
        }
    }
    //
    // return values          
    SpireMsg(3," Output Estimates:");
    SpireMsg(3,"            Band:         " + estimates[0]{0} + "            " + estimates[1]{0} + "            " + estimates[2]{0});
    SpireMsg(3,"            Source Flux   " + estimates[0]{1} + "            " + estimates[1]{1} + "            " + estimates[2]{1});
    SpireMsg(3,"            1  Sigma Noise:        " + estimates[0]{2} + "            " + estimates[1]{2} + "            " + estimates[2]{2});
    SpireMsg(3,"            Signal/Noise: " + estimates[0]{3} + "            " + estimates[1]{3} + "            " + estimates[2]{3});
    SpireMsg(3,"            Conf Level:   " + estimates[0]{4} + "            " + estimates[1]{4} + "            " + estimates[2]{4});
    SpireMsg(3,"            Conf Flag:    " + estimates[0]{5} + "            " + estimates[1]{5} + "            " + estimates[2]{5});
    //

    return estimates;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Set_PhotPhase
//
///////////////////////////////////////////////////////////
//
// Procedure to configure the photometer detector phases
//
///////////////////////////////////////////////////////////
//
// KJK:
// 2009/02/11 V0.1: Initial version adapted from
//                  SpireBb_PhotFSetPhase (MP 2009/01/27 V1.0)
// 2009/02/14 V0.2: (MP) Use actual phases as input instead of mode. 
//                  Added delay(1). Add some cosmetics to script.  
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_PhotPhase {
    int psw_phase = 0x0 in [0,255]; //Default phase is 0 [Hex]
    int pmw_phase = 0x0 in [0,255]; //Default phase is 0 [Hex]
    int plw_phase = 0x0 in [0,255]; //Default phase is 0 [Hex]
    int ptc_phase = 0x0 in [0,255]; //Default phase is 0 [Hex]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string tstr = "";
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"     " + tstr + ":  SpireProc_Set_PhotPhase started");
    SpireMsg(4,"          $Id:$");
    // //
    // //
    // Set the selected phases:
    //
    // Set the phases for the three arrays:
    SpireSendDrcuCmd(0x841a0000 + psw_phase,0);
    SpireSendDrcuCmd(0x841b0000 + pmw_phase,0);
    delay(1);
    SpireSendDrcuCmd(0x841c0000 + plw_phase,0);
    //
    // Set the phase for the PTC:
    SpireSendDrcuCmd(0x841d0000 + ptc_phase,0);
    sync();
    // //
    // //
    // Debug Printing:
    //
    double psw_phase_deg = 360.0 * double(psw_phase) / 255.0;
    double pmw_phase_deg = 360.0 * double(pmw_phase) / 255.0;
    double plw_phase_deg = 360.0 * double(plw_phase) / 255.0;
    double ptc_phase_deg = 360.0 * double(ptc_phase) / 255.0;
    if(debug) {
        debug_print("psw phase is set to " + psw_phase + " [Dec(Hex)] " + psw_phase_deg + " [deg]");
        debug_print("pmw phase is set to " + pmw_phase + " [Dec(Hex)] " + pmw_phase_deg + " [deg]");
        debug_print("plw phase is set to " + plw_phase + " [Dec(Hex)] " + plw_phase_deg + " [deg]");
        debug_print("ptc phase is set to " + ptc_phase + " [Dec(Hex)] " + ptc_phase_deg + " [deg]");
    }
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"      " + tstr + ": SpireProc_Set_PhotPhase ended");
}

// SpireEngPTCOff
//
// $id$
//
// This observation switches off the PTC
// 
// The instrument should normally be in PHOTSTBY mode before execution of this observation
// Final Configuration: Instrument is still in PHOTSTBY mode after execution of this observation
//
//
// 05/08/2009 SDS: First Version 0.1 
//
obs SpireEngPTCOff {
    int offTime = 120; // time (secs) to wait after PTC switch off
    bool sampleDetectors = true; // sample detectors during the PTC switch off?
    string ptcVersion = "v00";
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int t = duration(SpireBbStartObs()) + duration(SpireProc_PTCOff(offTime,sampleDetectors,ptcVersion,debug)) + duration(SpireBbEndObs());
    int[] ts = no_pointing(true,0,0,t);
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            SpireBbStartObs();
            SpireProc_PTCOff(offTime,sampleDetectors,ptcVersion,debug);
            SpireBbEndObs();
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Exec_PhotMultiLevelNoise.txt
//
///////////////////////////////////////////////////////////
//
//  Procedure to loop through a list of bias amplitudes for
//  the 'Phot Multi-Level Noise' task setting the correct 
//  phase included in calibration table. 
//
///////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/06/14 V0.1: Initial version adapted from
//                 Mode_ILT_PERF_DAB_P_Levels.txt (v1.3 2008/01/31 23:35:17)
// 2008/07/03 V0.2: Renumber version; SpireBb_PhotFSetupData has extra parameter
// 2008/08/04 V0.3: Allow separate phase for each array (including PTC)
// 2008/09/22 V0.4: Remove test number; Adapt to change in cal table setup
// 2009/01/31 V1.0: Add debug_print option (also to low level scripts). 
//                  In loop only set bias amplitude and phase at each level. 
// 2009/02/17 V1.1: Fixed bug biasfreq and samplerate were set each
//                  time in loop. 
// 2009/03/04 V1.2: Implement isBright setting in the way of adapting
//                  the phase at each bias amplitude level.
// Sunil Sidher 
// 2009/07/21 V1.3: Implemented isPcal flag to perform standard AOT style PCAL flashes after each bias setting
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Exec_PhotMultiLevelNoise {
    double biasfreq = 130.2; // Bias frequency (Hz)
    double samplerate = 18.6; // Sampling frequency (Hz)
    string tabName01 = "SpireTable_PhotMultiLevelNoiseLevels.txt"; // Calibration table name 
    string version01 = "v00"; // Version parameter defined in calibration table
    bool isBright = false; // Use settings for bright source (==tick)
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it?
    string tabName02 = "SpireTable_IsBrightPhaseShift.txt"; // Calibration table name 
    string version02 = "v00"; // Version parameter defined in calibration table
    int ftime = 300; // Readout time at each bias level [s]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = true;
    bool fts = !phot;
    // //
    // //
    // Read isBright phase shift from calibration table:
    //
    int photPhaseShift = ilookup(tabName02,version02,"photPhaseShift");
    // //
    // //
    // Convert input and read correct levels from calibration table:  
    //
    {string,int,int,int,double,double,double,double}[] level_table = SpireProc_CalcParam_PhotMultiLevelNoiseLevels(biasfreq,samplerate,tabName01,version01,debug);
    int size = length(level_table);
    if(debug) {
        debug_print("size = " + size);
        debug_print("Version selector used in calibration table: " + version01);
    }
    // //
    // //
    // Create list of bias levels and associated phases:
    //
    int[] nbiaslist = [];
    int[] pswnphaselist = [];
    int[] pmwnphaselist = [];
    int[] plwnphaselist = [];
    int[] ptcnphaselist = [];
    // //
    // //
    // Loop through the levels to populate lists:
    //
    for(int j = 0 .. size - 1) {
        if(debug) {
            debug_print("level_table = " + level_table[j]);
        }
        {string,int,int,int,double,double,double,double} row = level_table[j];
        int mclkDiv = row{1};
        int biasDiv = row{2};
        nbiaslist[j] = row{3};
        double pswphase = row{4};
        pswnphaselist[j] = iround(pswphase * 255.0 / 360.0);
        double pmwphase = row{5};
        pmwnphaselist[j] = iround(pmwphase * 255.0 / 360.0);
        double plwphase = row{6};
        plwnphaselist[j] = iround(plwphase * 255.0 / 360.0);
        double ptcphase = row{7};
        ptcnphaselist[j] = iround(ptcphase * 255.0 / 360.0);
        if(isBright) {
            pswnphaselist[j] = SpireProc_CalcParam_IsBrightPhaseShift(pswnphaselist[j],photPhaseShift,debug);
            pmwnphaselist[j] = SpireProc_CalcParam_IsBrightPhaseShift(pmwnphaselist[j],photPhaseShift,debug);
            plwnphaselist[j] = SpireProc_CalcParam_IsBrightPhaseShift(plwnphaselist[j],photPhaseShift,debug);
        }
    }
    if(debug) {
        debug_print("mclkDiv/biasDiv = " + mclkDiv + "/" + biasDiv);
    }
    // //
    // //
    // Set selected bias frequency and sampling rate before loop:
    //
    SpireBb_DcuSetFreqSamp(mclkDiv,biasDiv,phot,debug);
    // //
    // //
    // Start the bias loop:
    //
    for(int l = 0 .. length(nbiaslist) - 1) {
        // //
        // //
        // Safety checks:
        //
        if(nbiaslist[l] > 255) {
            nbiaslist[l] = 255;
            if(debug) {
                debug_print("Input bias amplitude list is corrupt! Raw value > 255 requested!");
            }
        }
        if(pswnphaselist[l] > 255) {
            pswnphaselist[l] = 255;
            if(debug) {
                debug_print("Input PSW bias phase list is corrupt! Raw value > 255 requested!");
            }
        }
        if(pmwnphaselist[l] > 255) {
            pmwnphaselist[l] = 255;
            if(debug) {
                debug_print("Input PMW bias phase list is corrupt! Raw value > 255 requested!");
            }
        }
        if(plwnphaselist[l] > 255) {
            plwnphaselist[l] = 255;
            if(debug) {
                debug_print("Input PLW bias phase list is corrupt! Raw value > 255 requested!");
            }
        }
        if(ptcnphaselist[l] > 255) {
            ptcnphaselist[l] = 255;
            if(debug) {
                debug_print("Input PTC bias phase list is corrupt! Raw value > 255 requested!");
            }
        }
        // //
        // //
        // Set bias amplitude and phase:
        //
        if(debug) {
            debug_print("the biaslevel is :" + nbiaslist[l] + " PSW phase is : " + pswnphaselist[l] + " PMW phase is : " + pmwnphaselist[l] + " PLW phase is : " + plwnphaselist[l] + " PTC phase is : " + ptcnphaselist[l]);
        }
        //
        // Set bias amplitude:
        SpireBb_PhotFSetBiasAmpl(nbiaslist[l],nbiaslist[l],nbiaslist[l],nbiaslist[l],debug);
        //
        // Set phase:
        SpireBb_PhotFSetPhase(pswnphaselist[l],pmwnphaselist[l],plwnphaselist[l],ptcnphaselist[l],debug);
        // //
        // //
        // Stop DCU data before resetting offsets:
        //
        SpireBb_StopDcuData();
        //
        // //
        // //
        // Set offsets:
        //
        SpireBb_PhotOffsetAuto(debug);
        // //
        // //
        // Take data:
        //
        SpireBb_PhotFTakeData(ftime,debug);
        // //
        // //
        // //
        // //
        // Perform standard AOT style PCAL flash
        if(isPcal) {
            SpireBbPcalFlash("PFlashEng","v00",0,false);
        }
        // Debug printing: 
        //
        if(debug) {
            debug_print("Bias level " + nbiaslist[l] + " done.");
        }
    }
    //
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SpecJfetVssTestC.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to perform VSS C test for spectrometer
//
///////////////////////////////////////////////////////////////////////////
//
// S.D.Sidher:
//
// 2010/01/06 V0.1: Initial version adapted from SpireBb_PhotJfetVssTestC.txt 
//  
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SpecJfetVssTestC SPIRE 3412 {
    double jfet_Vss_start = -1.0; //Starting JFET source voltage
    double jfet_Vss_end = -2.0; //ending JFET source voltage
    double jfet_Vss_step = -0.5; //steping JFET source volatge
    int ftime = 30; //wait time at each level;
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpecJfetVssTestC started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Calculate the number of levels:
    //     
    int n_levels = iround(abs((jfet_Vss_end - jfet_Vss_start) / jfet_Vss_step));
    int[] jfet_Vss_levels = [0x0];
    for(int j = 0 .. n_levels) {
        jfet_Vss_levels[j] = iround((jfet_Vss_start + jfet_Vss_step * double(j)) / -5.0 * 255.0);
    }
    // //
    // //
    // Set data mode to nominal:
    //
    SpireSendDrcuCmd(0x843c0004,0);
    // //
    // //
    // Start data generation:
    // 
    SpireSendDrcuCmd(0x843e0001,0);
    delay(1);
    // //
    // //
    // Do loop over Jfet values:
    //
    int loop_cnt = 0;
    while(loop_cnt != n_levels + 1) {
        delay(1);
        //
        // SSW JFET1
        SpireSendDrcuCmd(0x84350000 + jfet_Vss_levels[loop_cnt],0);
        delay(1);
        // SSW JFET2
        SpireSendDrcuCmd(0x84360000 + jfet_Vss_levels[loop_cnt],0);
        delay(1);
        // SLW JFET
        SpireSendDrcuCmd(0x84340000 + jfet_Vss_levels[loop_cnt],0);
        delay(1);
        //
        if(debug) {
            debug_print("level is:" + jfet_Vss_levels[loop_cnt]);
        }
        delay(1);
        Spire_SET_OBS_STEP(0x2 + loop_cnt);
        delay(ftime);
        Spire_SET_OBS_STEP(0xffff);
        loop_cnt = loop_cnt + 1;
    }
    // Set Vss back to nominal value of -1.5 V
    // SSW JFET1
    SpireSendDrcuCmd(0x8435004c,0);
    delay(1);
    // SSW JFET2
    SpireSendDrcuCmd(0x8436004c,0);
    delay(1);
    // SLW JFET
    SpireSendDrcuCmd(0x8434004c,0);
    delay(1);
    //
    // Stop data generation and flush DCU FIFO  
    SpireSendDrcuCmd(0x843e0000,0);
    delay(1);
    message("5          " + time() + "Cmd: Spire_FLUSH_FIFO(0x1000)");
    Spire_FLUSH_FIFO(0x1000);
    delay(3);
    message("5          " + time() + "Cmd: Spire_RESET_FIFOS(0x7000)");
    Spire_RESET_FIFOS(0x7000);
    delay(1);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpecJfetVssTestC ended");
    SpireMsg(1,"  ..SpecJfetVssTestC took " + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_PcalFlash.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to deduce number of DCU samples, SCU samples and DCU sample 
//  delay based on inputs period,mclkdiv and biasdiv for a PCAL flash
// 
//  Figure to follow the calculation of the parameters:
//             _______________________________
//            |                             |
//            |                             |
//            |                             |
//            |                             |
//            |                             |
//     --------                             ----------
//          cmdtime(cmdT)             sampdelay (sd)
//            |cmdT|                     |sd|
//                 |---------------------|
//              available time  == samp_period
//     
//                 x   x   x   x   x   x        DCU samples
//                 |---|               |-|
//                 tsamp            remaining time
//     
//              Dcudelay = remaining time + cmdT
//     
//          =====>  Reordered setup:
//                   x   x   x   x   x   x
//         ---|cmdT|-|                   |-|--------
//                dcudelay              sampledelay
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/12 V0.1: Initial version renamed from
//                  SpireProc_CalcParam_PhotPcalFlash (2008/07/29 V0.2)
//                  in original based on 
//                  Proc_PCALFlashCalc.txt (v1.4 2008/01/31 20:24:35)
//                  Add +1 to dcusamples (to count ticks not intervals);
//                  Use different formula to derive dcudelay; 
//                  add extensive debug_printing + comments; change default 
// 2009/02/02 V1.0: Add debug_print as input
// 2009/02/16 V1.1: Fix bug (sampdelay and commanding time missing) in 
//                  dcudelay calculation, detected during 
//                  FS2 testing (3.-5.02.2009). Added extended drawing to 
//                  header. Remove safety check for dcudelay < 0.
// 2009/09/11 V1.2: Fix bug (SPR-SPIRE-1809), dcusample needs to be <=255
//                  
///////////////////////////////////////////////////////////////////////////
//
int[] procedure SpireProc_CalcParam_PcalFlash {
    int period = 4000; //PCAL Flash FULL period (high and low bias) [millisec]
    int mclkdiv = 149; // Fetched master clock divisor
    int biasdiv = 6; // Fetched bias divisor
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Declare some variable:
    // 
    // possible sampling start delay [microsec]:
    int sampdelay = 6000;
    //
    // commanding time at start of half-chop period [microsec]:
    int cmdtime = 8000;
    //
    // //
    // //
    // Calculate bias frequency Hz:
    //
    double bias_f = 1.0E7 / (512.0 * double(mclkdiv + 1));
    // //
    // //
    // Calculate sampling rate Hz:
    //
    double samplerate = bias_f / (1.0 + double(biasdiv));
    // //
    // //
    // Calculate sampling interval in [millisec]:
    // (Time between DCU samples)
    //
    double tsamp = 1000.0 / samplerate;
    if(debug) {
        debug_print("DCU sample interval is: " + tsamp);
    }
    // //
    // //
    // Calculate dcusample, scusamples, and dcudelay parameters:
    // 
    // DCU samples to go into one PCAL half-cycle:
    //
    double dcusamp = (double(period) / 2.0 - double(sampdelay - cmdtime) / 1000.0) / tsamp;
    //double dcusamp = double(period) / 2.0 / tsamp;
    //
    // Number of full DCU samples per half period:
    //
    int dcusample = ifloor(dcusamp) + 1;
    if(debug) {
        debug_print("DCU samples: " + dcusample);
    }
    //
    int scusample = ifloor(double(period) / 2.0 / 12.5);
    // Note: only 1-31 samples can be requested, otherwise command 
    //       continuous frames (see below)   
    if(debug) {
        debug_print("SCU samples: " + scusample);
    }
    // //
    // //
    // Calculate DCU delay:
    //
    // Delay to start sampling the DCU [microsec]:
    //
    int dcudelay = iround((dcusamp - double(dcusample - 1)) * tsamp * 1000.0) + cmdtime;
    //int dcudelay = iround((dcusamp - double(dcusample - 1)) * tsamp * 1000.0);
    if(debug) {
        debug_print("DCU delay is: " + dcudelay);
    }
    // //
    // //
    // Check if dcusample>255 (maximum commanded value == continuous sampling): 
    //
    if(dcusample > 255) {
        debug_print("DCU samples larger than 255 so fix to 255 == continuous sampling");
        dcusample = 255;
    }
    // //
    // //
    // Set SCU sampling to continuous (VM takes care of starting and stoping SCU):
    //
    scusample = 0x0;
    // //
    // //
    // Debug printing:
    //
    if(debug) {
        debug_print("bias frequency Hz: " + bias_f);
        debug_print("sampling rate Hz: " + samplerate);
        debug_print("sampling interval in ms: " + tsamp);
        debug_print("dcusample: " + dcusample);
        debug_print("dcudelay [microsec]: " + dcudelay);
        debug_print("scusample: " + scusample);
    }
    //

    return [dcusample,scusample,dcudelay];
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_Chop.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to execute chopping/jiggling. Script returns the actual time on-source.
//
// Note: VM does not reset dcusample/bsmsample at end, so this needs 
//       to be done in the surrounding end script.  
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/10/13 V0.1: Initial version renamed from 
//                  SpireBb_PhotChop (2008/09/08 V0.3)
//                  Add debug printing option.
// 2009/01/27 V1.0: Move debug_print as input; Remove unsetting of BBID at end. 
//                  Set the delay time after FLUSH_FIFO to 2 sec.
// 2009/02/16 V1.1: Move all commands in lower level procedure
//                  SpireProc_Set_BsmChop. Added VM table parameters 
//                  as input and removed BSM framerate from input.
//                  Add Hspot messages. 
//
///////////////////////////////////////////////////////////////////////////
//
double block SpireBb_Chop SPIRE 14011 {
    int vmId = 71; // Raw VM table number [Dec(Hex)]
    int vmIndex = 0; // Raw VM index [Dec(Hex)]
    int nParms = 10; // Number of parameters passed to VM
    int onChop = 0; // on-source Chop position
    int onJigg = 0; // on-source Jiggle positio
    int offChop = 0; // off-source Chop position
    int offJigg = 0; // off-source Jiggle position
    int ncycles = 50; // Number of chop cycles [#]
    int chop_period = 500000; //period of chop cycles in [microsec]
    int dcumode = 0; // DCU data mode (e.g. 0 == Full photometer)
    int dcusample = 4; //Number of DCU samples per chop position [#]
    int dcudelay = 34959; //Dealy to start sampling the DCU [microsec]
    int bsmsample = 31; //Number of BSM samples per position  [#]
    int step = 0; // Step number [dec]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_Chop started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Run chop VM in procedure:
    // 
    //  Note: This sets the obsStep, resets the FIFOs, runs the VM, 
    //        and flushes the FIFOs. It does not set the datarate. 
    //
    double srcTime = SpireProc_Set_BsmChop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles,chop_period,dcumode,dcusample,dcudelay,bsmsample,step,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_Chop ended");
    SpireMsg(1,"  ..Chop/Jigg (" + (time() - t) + " seconds)");
    //

    return srcTime;
}

// SpireBbStopDcuData
//
// $Id: SpireBbStopDcuData.txt,v 1.3 2007/04/02 09:50:56 kking Exp $
//
// Procedure to stop generation of detector data TM packets
//
// 30 March 2007:   Added additional parameter to RESET_FIFOS cmd
// 02 April 2007:   Added additional parameter to RESET_FIFOS message
//
block SpireBbStopDcuData SPIRE 8457 {
}{
    message("4    " + time() + ": SpireBbStopDcuData started");
    message("4          $Id: SpireBbStopDcuData.txt,v 1.3 2007/04/02 09:50:56 kking Exp $");
    //
    // stop data collection
    SpireSendDrcuCmd(0x843e0000,0);
    //
    // flush data from FIFOs
    message("5          " + time() + "Cmd: Spire_FLUSH_FIFO(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(3);
    message("5          " + time() + "Cmd: Spire_RESET_FIFOS(0x1000)");
    Spire_RESET_FIFOS(0x1000);
    //
    delay(1);
    message("4    " + time() + ": SpireBbStopDcuData ended");
    //
}

// CVS comments  : $Id: WriteOBSID.txt,v 1.7 2007/11/06 08:39:25 dcesarsk Exp $ 
// Missionphase  : 
//
// Purpose       : Set the OBSID via DEC/MEC; show decoded OBSID on
//                 user screen 
//
// CUS script    : Diego A. Cesarsky (diego.cesarsky@mpe.mpg.de)
// Original TCL  : N/A
// CVS file      : WriteOBSID.txt
//
// Input arguments
// Type  Name     DefVal  Description
// int   iOBSID   N/A     OBSID obtained from environment
//
// Description   : Obtain OBSID from run environment and send TC to DMC
//                 Write decoded OBSID to log file
//
// Dependencies  : Pacs_DMC_SET_OBSID
//                 DecodeOBSID
//                 
// Comments      : 
//
// Version       : 2.0
//   		   0.1 23-Sep-2004 First creation
// History       : 0.2 28-Sep-2004 Remove set_unset; write
//                                 decoded OBSID to output log
//                 0.3  7-Oct-2004 Renamed to WriteOBSID to match to names of
//                                 related procedures
//                 0.4 12-Oct-2004 Added write to EGSE environment (need
//                                 to add write to IST environment ??)
//                 0.5 21-Oct-2004 Added write to CDMS
//                 1.0  9-May-2005 DAC Removed write to EGSE and CDMS (not
//                                 needed at Astrium)
//                 1.1 20-oct-2005 Added sync() as I will need the "true"
//                                 duration
//                 1.2  5-nov-2007 Added delay(1) before first TC to wait
//                                 for completion of bus_configure
//		   2.0 23-sep-2008 SCR4431 hk_data_rate
//
procedure WriteOBSID {
    int iOBSID = 0x20000000; // Observation ID  
}{
    // Wait 1 second to allow for bus_configure
    delay(1);
    // Write OBSID to DEC/MEC and decode to output log
    Pacs_DMC_SET_OBSID(iOBSID);
    ess_hk_data_rate(0.31);
    non_ess_hk_data_rate(4.0);
    // sync the bus
    sync();
    // Inform CUS debugger
    //   DecodeOBSID(iOBSID);
}

// SpireBsmMove
//
// $Id: SpireBsmMove.txt,v 1.1 2006/08/10 09:38:58 kking Exp $
//
// Procedure to move the BSM to a given position
//
//
procedure SpireBsmMove {
    int chopPosn = 2048 in [0,65535];
    int jiggPosn = 2048 in [0,65535];
}{
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"    " + tstr + ": SpireBsmMove started");
    SpireMsg(4,"          $Id: SpireBsmMove.txt,v 1.1 2006/08/10 09:38:58 kking Exp $");
    //
    SpireMsg(3,"         ChopPosn = " + chopPosn);
    SpireMsg(3,"         JIggPosn = " + jiggPosn);
    //
    int cmd = 0;
    // set Chop position
    cmd = 0x90c30000 + chopPosn;
    SpireSendDrcuCmd(cmd,0);
    //
    // set Jiggle Position
    cmd = 0x91430000 + jiggPosn;
    SpireSendDrcuCmd(cmd,0);
    //
    // move BSM
    cmd = 0x90c60000;
    SpireSendDrcuCmd(cmd,0);
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"    " + tstr + ": SpireBsmMove ended");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_DcuSetFreqSamp.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to configure the DCU bias frequency and sampling rate. 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/17 V0.1: Initial version adapted surrounding from 
//                  SpireBb_PhotFSetPhase (2009/02/14 V1.1) 
//                  calling SpireProc_Set_DcuFreqSamp.
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_DcuSetFreqSamp SPIRE 14031 {
    int mclkDiv = 149; // Bias freq. (for photometer == 130.20833 Hz)
    int biasDiv = 6; // Sampling freq. (for photometer == 18.60119 Hz)
    bool phot = true; // Set for photometer (==tick) or FTS 
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string hstr = "";
    // a hex string
    string tstr = "";
    // a time string
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": SpireBb_DcuSetFreqSamp started");
    SpireMsg(2,"          $Id: $");
    hstr = SpireHexStr($BBID,8);
    SpireMsg(3,"          BBID = " + hstr);
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    sync();
    // //
    // //
    // Set the phase for the three arrays and the PTC bolometer:
    //
    SpireProc_Set_DcuFreqSamp(mclkDiv,biasDiv,phot,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_DcuSetFreqSamp ended");
    SpireMsg(1,"  ..Set Phot phases (" + (time() - t) + " secs)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_BsmSetup.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to deduce number of chop cycles, the chop period, the number 
//  of DCU samples, BSM samples, and the DCU delay, based on input read 
//  out time, chop frequency, detector sampling rate, and MCU framerate.
// 
//  Figure to follow the calculation of the parameters:
//             _______________________________
//            |                             |
//            |                             |
//            |                             |
//            |                             |
//            |                             |
//     --------                             ----------
//          cmdtime(cmdT)             sampdelay (sd)
//            |cmdT|                     |sd|
//                 |---------------------|
//              available time  == samp_period
//     
//                 x   x   x   x   x   x        DCU samples
//                 |---|               |-|
//                 tsamp            remaining time
//     
//              Dcudelay = remaining time + cmdT
//     
//          =====>  Reordered setup:
//                   x   x   x   x   x   x
//         ---|cmdT|-|                   |-|--------
//                dcudelay              sampledelay
//        
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/10/13 V0.1: Initial version renamed from 
//                  SpireProc_CalcParam_PhotBsmSetup.txt (2008/07/28 V0.2)
//                  Remove sampling rate restriction. Add debug printing option.
// 2009/01/27 V1.0: Add debug_print as input  
// 2009/02/16 V1.1: Fix bug in dcudelay calculation, detected during 
//                  FS2 testing (3.-5.02.2009). Added extended drawing to 
//                  header. According to Ken sampdelay is now 6000 and 
//                  not 7000. 
// 2009/06/26 V1.2: Added temporarily fix for SPR: SPIRE-1551 until 
//                  issue is fully understodd: Hardcode bsmsample to 
//                  FFFFF (65535).     
// 2009/07/03 V1.3: Remove temporal fix, since this will cause problems
//                  during a spec-day and has probably during OD50. I.e
//                  FFFFF in the VM leaves the BSM (and SMEC) data running.
// 2009/09/11 V1.4: (SPR-SPIRE-1809) Restrict dcusample to be <=255
// 
///////////////////////////////////////////////////////////////////////////
//
int[] procedure SpireProc_CalcParam_BsmSetup {
    int rtime = 15; // Readout out time (== total time: ON+OFF) [s] 
    double chopf = 2.0; // Chop frequency [Hz] 
    double samplerate = 18.6; // Sampling rate (18.6 phot; 80.0 spec) [Hz] 
    double framerate = 125.0; // MCU (BSM) frame rate [Hz]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Declare some variable:
    // 
    // possible sampling start delay [microsec]:
    int sampdelay = 6000;
    // commanding time at start of half-chop period [microsec]:
    int cmdtime = 14000;
    // //
    // //
    // Calculate number of chop cycles:
    //
    // Period of chop cycles [microsec]:
    ////
    int chop_period = iround(1.0 / chopf * 1000000.0);
    //
    // Number of chop cycles:
    //
    int ncycles = iceil(double(rtime * 1000000) / double(chop_period));
    // //
    // //
    // Calculate number of DCU samples:
    //
    // Sampling period per half-cycle [microsec]:
    //
    int samp_period = chop_period / 2 - sampdelay - cmdtime;
    //
    // Time between DCU samples:
    //
    double tsamp = 1.0 / samplerate * 1000.0;
    // [millisec]
    // 
    // DCU samples to go into one chop half-cycle:
    //
    double dcusamp = double(samp_period) / 1000.0 / tsamp;
    //
    // Number of full DCU samples to go into one chop half-cycle:
    //
    int dcusample = ifloor(dcusamp) + 1;
    //Number of DCU samples per chop position
    // //
    // //
    // Calculate DCU delay:
    //
    //Dealy to start sampling the DCU [microsec]:
    int dcudelay = iround((dcusamp - double(dcusample - 1)) * tsamp * 1000.0) + cmdtime;
    // //
    // //
    // BSM (MCU) samples:
    //
    // Time between MCU samples:
    //
    double tbsm = 1.0 / framerate * 1000.0;
    // [millisec]
    // 
    // BSM (MCU) samples to go into one chop half-cycle:
    //
    double bsmsamp = double(samp_period) / 1000.0 / tbsm;
    //
    // Number of full BSM (MCU) samples to go into one chop half-cycle:
    //
    int bsmsample = ifloor(bsmsamp);
    //
    // Number of BSM samples per position:
    //
    // temporarily fix for SPR: SPIRE-1551
    // hardcode bsmsample to FFFFF (65535).
    // bsmsample = 65535;
    // //
    // //
    // Check if dcusample>255 (maximum commanded value == continuous sampling): 
    //
    if(dcusample > 255) {
        debug_print("DCU samples larger than 255 so fix to 255 == continuous sampling");
        dcusample = 255;
    }
    // //
    // //
    // Debug printing:
    //
    if(debug) {
        debug_print("chop_period [millisec]: " + double(chop_period) / 1000.0);
        debug_print("samp_period [millisec]: " + double(samp_period) / 1000.0);
        debug_print("ncycles: " + ncycles);
        debug_print("Readout time [s]: " + double(ncycles * chop_period) / 1000000.0);
        debug_print("tsamp [millisec]: " + tsamp);
        debug_print("dcusamp: " + dcusamp);
        debug_print("dcusample: " + dcusample);
        debug_print("dcudelay [microsec]: " + dcudelay);
        debug_print("tbsm: " + tbsm);
        debug_print("bsmsamp: " + bsmsamp);
        debug_print("bsmsample: " + bsmsample);
    }
    //

    return [ncycles,chop_period,dcusample,dcudelay,bsmsample];
}

///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_CalGCO_FixedSmecBeamProfile.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Spec Fixed SMEC Beam Profile'
//
//         in *custom_map_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/10/13 V0.1: Initial version adapted from
//                  SpirePhoto_CalGCO_FpgInitialPointing (2008/09/16 V0.9)
// 2008/11/03 V0.2: Allow to move SMEC to an input fixed position different
//                  from home. 
// 2008/11/06 V0.3: Adapt to name change in low level scripts
// 2009/09/16 V0.4: Copy many necessary changes similar to 
//                  SpireSpectro_CalGCO_ScannedSmecBeamProfile (2009/09/15 V0.5)
// 2009/09/17 V0.5: Allow # of raster points to be input parameters. 
// 2009/10/28 V1.0: (SCR-SPIRE-2118) Allow SSO. Hardcode gcp_period for SSOs. 
// 2009/11/16 V1.1: (SPR-SPIRE-2157) Change default aperture.
//
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in SPECSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for the two FTS arrays and could be taken from following cal table: 
//    SpireTable_SpecSswNominalSettings.txt
//
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_CalGCO_FixedSmecBeamProfile {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; //NAIF identifier: put '0' to use RA/DEC, or correct 'NAIFID'
    bool isBright = false; // Use settings for bright source (==tick)
    /* */
    double raoff = 0.0 in [0.0,360.0]; // RA of GCP position
    double decoff = 0.0 in [-90.0,90.0]; // DEC of GCP position 
    string ib = "S24_0"; // Central aperture (defined in SIAM) of raster
    int m = 11; // Number of points in raster along Y [odd number!]
    int n = 11; // Number of points in raster along Z [odd number!]
    bool cross = true; // Add interlaced cross or use a simple m x n raster? 
    double d1 = 2.0; // Angular stepsize between raster pts [arcsec]
    int ftime = 15; // Read-out time (on+off) [s]
    int smec_pos = 1000 in [100,40000]; // SMEC position in encoder values [raw]
    double chopf = 1.0 in [0.1,4.0]; // Chop frequency [Hz] 
    int offChopfh = 9600; // off-source chop position (+ or - relative to hold) [Dec(Hex)]
    double framerate = 125.0; // Specifies the MCU framerate [Hz]
    int gcp_time = 15; // Time spend at GCP (gyro calibration position) [s]
    int gcp_period = 600; // Maximum time between successiv GCP visits (Note, set to 64800 for SSOs!)[s]
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParas    
    string version03 = "v00"; // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial"; // Model in cal table SpireTable_BsmNominalSettings
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Current restrictions:
    //
    if(naifid != 0) {
        message("Note, currently no SSO objects are allowed if gyro reconstruction is needed. Using SSO tracking the visists to the OFF position are minimised by setting gcp_period to 18h.");
        gcp_period = 64800;
    }
    // //
    // //
    // Declare some variable:
    //
    int start = time();
    // Start timing of script
    int obsstep = 0x0;
    // First obsstep [HEX]
    int raster_counter = 0;
    // Count raster points 
    // Spectrometer or FTS:
    bool phot = false;
    bool fts = !phot;
    bool setFramerate = true;
    string version = "";
    string tabName = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    // DCU data mode (0 == Full spectrometer; 4 == Full spectrometer):
    int dcumode = 4;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    string tabName04 = "SpireTable_CommandLists.txt";
    string tabName06 = "SpireTable_SmecNominalSettings.txt";
    //
    // Currently hardcoded version:
    //
    string version06 = "v00";
    // Version in cal table SpireTable_SmecNominalSettings
    //
    // Currently hardcoded parameter:
    // Is (==tick) the DCU currently sampled? 
    bool dcuData = false;
    //
    //
    // NOTE: Script works only for equidistant raster points in both axes:
    double d2 = d1;
    // Angular stepsize along Z axis [arcsec]
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS32";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for setup and datarates:  
    string obsMode = "SEngCalObs";
    // Note: datarates are currently only maximum values
    // //
    // //
    // Setup parameters for BSM chopping movement: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version03;
    tabName = tabName03;
    string selCol = "model";
    // Name of column for selecting 
    string selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    string tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set chop/jigg positions:
    //    
    int onChop = hold_chop;
    // on-source Chop position [Dec(Hex)]
    int onJigg = hold_jigg;
    // on-source Jiggle position
    int offChop = hold_chop + offChopfh;
    // off-source Chop position
    int offJigg = hold_jigg;
    // off-source Jiggle position
    // 
    // Read VM parameters from calibration table:
    //
    tabName = tabName04;
    selVal = "Chop";
    int vmId = ilookup(tabName,selVal,"Id");
    int vmIndex = ilookup(tabName,selVal,"Index");
    int nParms = ilookup(tabName,selVal,"Nparms");
    // //
    // //
    // Read SMEC home position from calibration file:
    //
    tarCol = "Home";
    tabName = tabName06;
    selVal = version06;
    int smecHomePosn = ilookup(tabName,selVal,tarCol);
    // //
    // //
    // Read nominal bias frequency and bias divider:
    //    
    // Select version flag and set GetTableEntry parameters:
    version = version01;
    tabName = tabName01;
    selCol = "mode";
    // Name of column for selecting 
    selVal = obsMode;
    // Value of 'string' selector
    //
    tarCol = "mclkDiv";
    int mclkdiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    tarCol = "biasDiv";
    int biasdiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Calculate nominal sampling rate from mclkdiv and biasdiv:
    //
    double mclkdivHz = 1.0E7 / (512.0 * double(mclkdiv + 1));
    double biasdivHz = 1.0 / (double(biasdiv) + 1.0) * mclkdivHz;
    if(debug) {
        debug_print("Nominal sampling rate is: " + biasdivHz + " [Hz]");
    }
    //
    // Compare read-out time and dwell time on GCP:
    int dtime = 0;
    // time to be spend on GCP position
    if(gcp_time < ftime) {
        dtime = ftime;
    } else {
        dtime = gcp_time;
    }
    // //
    // //
    // Calculate BSM chop parameters:
    //
    int[] chopparam1 = SpireProc_CalcParam_BsmSetup(ftime,chopf,biasdivHz,framerate,debug);
    int ncycles = chopparam1[0];
    int chop_period = chopparam1[1];
    int dcusample = chopparam1[2];
    int dcudelay = chopparam1[3];
    int bsmsample = chopparam1[4];
    //
    int[] chopparam2 = SpireProc_CalcParam_BsmSetup(dtime,chopf,biasdivHz,framerate,debug);
    int ncycles_2 = chopparam2[0];
    int chop_period_2 = chopparam2[1];
    int dcusample_2 = chopparam2[2];
    int dcudelay_2 = chopparam2[3];
    int bsmsample_2 = chopparam2[4];
    // //
    // //
    // Compare user input of BSM framerate with default value:
    //
    version = version02;
    tabName = tabName02;
    tarCol = "bsmFrameRate";
    int bsmFrameRate = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    double bsmFrameRateHz = 1000000.0 / (double(bsmFrameRate) * 420.0);
    if(debug) {
        debug_print("Nominal BSM sampling rate is: " + bsmFrameRateHz + " [Hz]");
    }
    //
    // Compare nominal with input BSM framerate:
    // 
    int frate = SpireProc_CalcParam_BsmFramerate(framerate,debug);
    if(frate == bsmFrameRate) {
        setFramerate = false;
    }
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // 
    // BBs called during slew:
    // 
    int tslewmin = duration(SpireBb_StartFixedSmecBeamProfile(obsModeQla,obsMode,isBright,version01,version02,smec_pos,hold_chop,hold_jigg,setFramerate,frate,smecHomePosn,debug));
    // 
    // BBs carried out when the pointing is reached:
    //
    int tinithold = 0;
    //
    // BB carried out during pointing:
    // 
    int tp_np = duration(SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles,chop_period,dcumode,dcusample,dcudelay,bsmsample,9999,debug)) + duration(SpireBb_SpecOffsetAuto(dcuData,debug));
    int tp_gp = duration(SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles_2,chop_period_2,dcumode,dcusample_2,dcudelay_2,bsmsample_2,9999,debug)) + duration(SpireBb_SpecOffsetAuto(dcuData,debug));
    //
    // BB carried out at the end:
    //
    int tfinalhold = duration(SpireBb_EndFixedSmecBeamProfile(smec_pos,hold_chop,hold_jigg,smecHomePosn,isBright,version01,version02,debug));
    // //
    // //
    // Debug printing:
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing normal= " + tp_np);
        debug_print("tpointing @GCP= " + tp_gp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                              */
    // ****************************************************** */
    // //
    // //
    // Fixed parameters for pointing mode:
    //   
    bool fixed = false;
    // Pattern orientation (true==sky; false==array)
    double patt = 90.0;
    // Rotation angle of the pattern
    double yoffset = 0.0;
    // Offset of pattern in the direction of the +Y
    double zoffset = 0.0;
    // Offset of pattern in the direction of the +Z
    int thold = 0;
    // The duration of the hold when nhold>0.
    int nhold = 0;
    // Number of nods or raster points or scan lines before
    //              // performing a hold.
    double pattnod = 0.0;
    //
    double chopthrow = 2.0;
    //
    int nnod = 1;
    //
    int knod = 0;
    //
    int nload = 0;
    //
    int tloadmin = 0;
    //
    // //
    // //
    // Calculate array of points:
    //
    {double[],double[]} array = SpireProc_CalcParam_RasterCross(m,n,d1,d2,cross,debug);
    double[] zarray_org = array{0};
    double[] yarray_org = array{1};
    int numpixel = length(yarray_org);
    int nump_org = length(yarray_org);
    // //
    // //
    // Add GCP visit after every raster point (except first which is GCP)
    // and create tp (duration of fine pointing) vector new raster:
    //
    double[] yarray = [0.0];
    double[] zarray = [0.0];
    int run = 1;
    int aindex = 1;
    int fin = length(yarray_org);
    yarray[0] = yarray_org[0];
    zarray[0] = zarray_org[0];
    bool gcpp = false;
    int[] tpv = [0];
    tpv[0] = tp_gp;
    do {
        if(gcpp) {
            yarray[aindex] = yarray_org[0];
            zarray[aindex] = zarray_org[0];
            tpv[aindex] = tp_gp;
            gcpp = false;
        } else {
            yarray[aindex] = yarray_org[run];
            zarray[aindex] = zarray_org[run];
            tpv[aindex] = tp_np;
            run = run + 1;
            gcpp = true;
        }
        aindex = aindex + 1;
    } while (run < fin);
    // Add GCP visit at end:
    yarray[aindex] = yarray_org[0];
    zarray[aindex] = zarray_org[0];
    tpv[aindex] = tp_gp;
    //
    // //
    // //
    if(debug) {
        debug_print("timing vector : " + tpv);
        debug_print("zarray_org: " + zarray_org);
        debug_print("zarray: " + zarray);
    }
    //
    // Calculate slew times in pointing mode:
    //
    int[] ts_tr = custom_map_pointing(false,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,fixed,patt,yoffset,zoffset,yarray,zarray,tpv,pattnod,chopthrow,nnod,knod,tloadmin,nload,thold,nhold);
    //
    if(debug) {
        debug_print("Pointing vector : " + ts_tr);
    }
    // //
    // //
    // Determine maximal slew to GCP:
    //
    int nump = length(yarray);
    int nslews = nump;
    int nlslews = numpixel;
    int tpp = ts_tr[7];
    int[] tslews = [0];
    tslews[0] = 0;
    for(int j = 1 .. nslews - 1) {
        if(debug) {
            debug_print("entry: " + (j + 6));
        }
        tslews[j] = ts_tr[j + 6];
    }
    //
    int maxslew = 0;
    for(int k = 0 .. length(tslews) - 1) {
        maxslew = iceil(max(double(maxslew),double(tslews[k])));
    }
    if(debug) {
        debug_print("nlslews: " + nlslews);
        debug_print("nslews: " + nslews);
        debug_print("tslews: " + tslews);
        debug_print("maxslew: " + maxslew);
    }
    // //
    // //
    // Determine slew time between small raster points:
    //
    int tppn = tslews[1];
    // == slew beteen first and second raster point
    // //
    // //
    // Decrease frequency of GCP visits until gcp_period matched
    //
    //   
    int kgcp = 1;
    int ktime = 0;
    int ktime_old = 0;
    int nslew = 0;
    do {
        ktime_old = ktime;
        //
        // Count number of slews between the mxn rasters: 
        if(2 * kgcp + 1 > (nslew + 1) * m * n) {
            nslew = nslew + 1;
            if(debug) {
                debug_print("nslew: " + nslew);
            }
        }
        //
        // Calculate approximate(!) time between off visits :
        // [Problem: slews are not 100% predictable with single dummy run]
        //
        ktime = tp_gp + kgcp * tp_np + (kgcp - nslew) * tppn + nslew * maxslew + 2 * maxslew;
        // 
        // Add safety time:
        // [to account for possible longer slews than in dummy run] 
        ktime = ktime + 0;
        int kdiff = ktime - ktime_old;
        //
        // Print out error if gcp_period < ktime for first case 
        // (== having a GCP after each point):
        if(kgcp == 1) {
            if(gcp_period < ktime) {
                debug_print("gcp_period < ktime: " + gcp_period + " < " + ktime);
                error("gcp_period smaller than expected times between GCP visits! Change input parameters!");
            }
        }
        // 
        if(debug) {
            debug_print("tpv[0]: " + tpv[0]);
            debug_print("tp_np: " + tp_np);
            debug_print("tp_gp: " + tp_gp);
            debug_print("tppn: " + tppn);
            debug_print("maxslew: " + maxslew);
            debug_print("nslew: " + nslew);
            debug_print("ktime-ktime_old: " + kdiff);
            debug_print("ktime loop kgcp/ktime: " + kgcp + "/" + ktime);
        }
        //
        //
        // Increment kgcp (i.e delay visit to GCP by one more raster point): 
        if(debug) {
            debug_print("increment kgcp by 1");
        }
        kgcp = kgcp + 1;
        if(debug) {
            debug_print("new kgcp: " + kgcp);
        }
        //
    } while (ktime < gcp_period);
    //
    // Select last kgcp for which condition was fulfilled:
    int kgcp_old = 1;
    if(kgcp > 2) {
        kgcp_old = kgcp - 2;
    }
    message("Return to GCP after every " + kgcp_old + " normal raster point(s)!");
    //
    if(debug) {
        debug_print("values after kgcp selection loop:");
        debug_print("nump: " + nump);
        debug_print("nslews: " + nslews);
        debug_print("tslews: " + tslews);
        debug_print("maxslew: " + maxslew);
        debug_print("ktime loop end: " + ktime);
        debug_print("kgcp loop end:" + kgcp);
        debug_print("ktime_old: " + ktime_old);
        debug_print("kgcp_old:" + kgcp_old);
    }
    // //
    // //
    // Add visits to the GCP tp raster array:
    //
    int counter = 0;
    double[] yarray_new = [0.0];
    double[] zarray_new = [0.0];
    double ygcp = yarray[0];
    double zgcp = zarray[0];
    if(debug) {
        debug_print("ygcp/zgcp: " + ygcp + "/" + zgcp);
        debug_print("zarray: " + zarray);
    }
    //
    // Start loop:
    int end = nump_org;
    int ln = 0;
    int stop = 0;
    int index = 0;
    bool[] raster = [true];
    do {
        if(debug) {
            debug_print("stop : " + stop);
            debug_print("end : " + end);
            debug_print("index : " + index);
            debug_print("counter: " + counter);
        }
        if(counter > kgcp_old - 1) {
            yarray_new[index] = ygcp;
            zarray_new[index] = zgcp;
            ln = ln + 1;
            counter = 0;
            raster[index] = false;
        } else {
            yarray_new[index] = yarray_org[index - ln];
            zarray_new[index] = zarray_org[index - ln];
            if(debug) {
                debug_print("index -ln : " + (index - ln));
            }
            stop = stop + 1;
            counter = counter + 1;
            raster[index] = true;
        }
        index = index + 1;
    } while (stop < end);
    //
    // Define first point always as regular raster point:
    raster[0] = true;
    //
    // Add additional visit to GCP at end:
    // (could give unsymmetric GCP visits but ensures a GCP at start AND end)
    if(debug) {
        debug_print("index : " + index);
    }
    if(yarray_new[index - 1] != ygcp) {
        yarray_new[index] = ygcp;
        zarray_new[index] = zgcp;
        raster[index] = false;
    }
    // 
    if(debug) {
        debug_print("# pts without GCPs: " + length(yarray_org));
        debug_print("# pts with GCPs: " + length(yarray_new));
        debug_print("yarray_org: " + yarray_org);
        debug_print("yarray_new: " + yarray_new);
        debug_print("zarray_org: " + zarray_org);
        debug_print("zarray_new: " + zarray_new);
    }
    //
    // Adapt tp vector to new number of points:
    int[] tpv_new = [0];
    for(int ind = 0 .. length(yarray_new) - 1) {
        if(ind == 0) {
            tpv_new[0] = tpv[0];
        } else {
            if(yarray_new[ind] == ygcp) {
                if(zarray_new[ind] == zgcp) {
                    tpv_new[ind] = tp_gp;
                } else {
                    tpv_new[ind] = tp_np;
                }
            } else {
                tpv_new[ind] = tp_np;
            }
        }
    }
    if(debug) {
        debug_print("raster vector: " + raster);
        debug_print("new timing vector : " + tpv_new);
        debug_print("length(raster): " + length(raster));
        debug_print("length(yarray_new): " + length(yarray_new));
        debug_print("length(tpv_new): " + length(tpv_new));
    }
    // //
    // //
    // Set pointing mode:
    //
    //custom_map_pointing(true, tslewmin, tinithold, tfinalhold, ib, naifid,
    //ra,dec,fixed,patt,yoffset,zoffset,yarray,zarray,tpv, pattnod,chopthrow,
    //nnod,knod,tloadmin,nload, thold, nhold);
    //
    int[] ts = custom_map_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,fixed,patt,yoffset,zoffset,yarray_new,zarray_new,tpv_new,pattnod,chopthrow,nnod,knod,tloadmin,nload,thold,nhold);
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC              */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //     
            SpireBb_StartFixedSmecBeamProfile(obsModeQla,obsMode,isBright,version01,version02,smec_pos,hold_chop,hold_jigg,setFramerate,frate,smecHomePosn,debug);
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            //
            //
            //delay(tinithold);
        }
        if(state[0] == 3) {
            // STATE = POINT (spacecraft is at nominal RA,DEC (staring, raster))
            //
            //delay(tp);
            // //
            // //
            // Set offsets at each raster point:
            //
            SpireBb_SpecOffsetAuto(dcuData,debug);
            // //
            // //
            // Different timings for different raster points (normal vs. GCP):
            // 
            if(raster[raster_counter] == false) {
                // //
                // //
                // Show time elapsed between visits to GCP:
                int t = time() - start;
                message("Time elapsed since last visit to GCP: " + t);
                if(debug) {
                    debug_print("Time elapsed since last visit to GCP: " + t);
                }
                // 
                if(t > gcp_period) {
                    error("Elapsed time between GCP visits larger than gcp_period! Change input parameters.");
                }
                //
                // Reset timer:           
                start = time();
                // //
                // //
                // Run chop VM (includes data taking) and set obs step parameter: 
                //
                SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles_2,chop_period_2,dcumode,dcusample_2,dcudelay_2,bsmsample_2,65535,debug);
                //
            } else {
                // //
                // //
                // Reset timing at first raster point:
                if(obsstep == 0) {
                    start = time();
                }
                // //
                // //
                // Run chop VM (includes data taking) and set obs step parameter: 
                //
                SpireBb_Chop(vmId,vmIndex,nParms,onChop,onJigg,offChop,offJigg,ncycles,chop_period,dcumode,dcusample,dcudelay,bsmsample,obsstep,debug);
                obsstep = obsstep + 1;
                //
            }
            raster_counter = raster_counter + 1;
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ("sky" observation ends, performing final activities )
            // //
            // // 
            // End observation and reconfigure:  
            //
            SpireBb_EndFixedSmecBeamProfile(smec_pos,hold_chop,hold_jigg,smecHomePosn,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END (end of the pointing/commanding part of the code)
            //
        }
    }
}

// SpireBbPeakup
//
// Execute a Peakup observation
//
//  K.J. King
//
// 11/11/2008  KJK: first version
// 17/07/2009  MP: Stopped MCU science data and set DCU mode to continuous 
//             following SCR-SPIRE-1644.
// 25/09/2009 KJK: SCR Spire-1932:
//             Changed to read the pixel number from the SpireTable_SIAM table, using the  chosen boresight
//             Added versions and debug to input parameter list
//             Updated to read info from SpireTable_Peakup.txt
// 28/09/2009 SDS: Incremented by 1 the pixel index read from the SIAM table because a DCU frame starts with frame length and frame id. 
//                             
//
block SpireBbPeakup SPIRE 8458 {
    string peakupMode = "PPeakup" in ["PPeakup","SPeakup"]; // Peakup Mode
    string ib = "";
    int step = 0;
    string comVersion = "v00";
    string pmodeVersion = "v00";
    string smodeVersion = "v00";
    string peakVersion = "v00";
    string siamVersion = "v00";
    bool debug = false;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Photometer Peakup started");
    SpireMsg(2,"          $Id:$");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP 
    hstr = SpireHexStr(step,4);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(" + hstr + ")");
    Spire_SET_OBS_STEP_RAW(step);
    //
    // Time synchronisation
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RESET_DRCU_COUNTERS_RAW()");
    Spire_RESET_DRCU_COUNTERS_RAW();
    delay(2);
    //
    // position SMEC, if necessary
    //
    if(peakupMode == "SPeakup") {
        // Move SMEC to HOME position
        int home = ilookup("SMEC.txt","HOME","ivalue");
        SpireSendDrcuCmd(0x90450000 + home,0);
        // set position
        SpireSendDrcuCmd(0x90490001,0);
        // move
        SpireSendDrcuCmd(0x90490000,0);
        // hold position
        delay(2);
    }
    //
    // Set up detector sampling
    //
    if(peakupMode == "SPeakup") {
        SpireConfigDcuData("SPeakup");
    } else {
        SpireConfigDcuData("PPeakup");
    }
    //
    // execute peakup
    //
    string[] packet = ["PhotFull","PSW","PMW","PLW","SpecFull","SLW","SSW"];
    int dcuDataMode = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"DcuDataMode",peakVersion,debug);
    // Find pixel in DCU frame:
    // The pixel indices in the SIAM table start from 1, i.e. PSW-R1 would be at index 1 if it was in the SIAM table
    // The first two words of a DCU frame are Frame Length and Frame ID, i.e. indices 0 and 1 respectively
    // =>> So need to add 1 to the pixel index in the SIAM table to find a pixel's true location in the DCU frame
    int pixel = SpireProc_GetTableEntryInt("SpireTable_SIAM.txt","boresight",ib,packet[dcuDataMode],siamVersion,debug);
    pixel = pixel + 1;
    if(pixel == -1) {
        error("SpireBbPeakup: pixel is not available for boresight " + ib);
    }
    int chopTable = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"ChopTable",peakVersion,debug);
    int chopTableIndex = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"ChopTableIndex",peakVersion,debug);
    int startChopPosn = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"StartChopPosn",peakVersion,debug);
    int chopPosnIncr = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"ChopPosnIncr",peakVersion,debug);
    int nChopPosns = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"NChopPosns",peakVersion,debug);
    int startJiggPosn = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"StartJiggPosn",peakVersion,debug);
    int jiggPosnIncr = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"JiggPosnIncr",peakVersion,debug);
    int nJiggPosns = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"NJiggPosns",peakVersion,debug);
    int chopOffset = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"ChopOffset",peakVersion,debug);
    int jiggOffset = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"JiggOffset",peakVersion,debug);
    int nChopCycles = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"NChopCycles",peakVersion,debug);
    int chopCyclePeriod = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"ChopCyclePeriod",peakVersion,debug);
    int nBsmFrames = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"NBsmFrames",peakVersion,debug);
    int nDcuFrames = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"NDcuFrames",peakVersion,debug);
    int dcuFrameDelay = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"DcuFrameDelay",peakVersion,debug);
    int chopScale = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"ChopScale",peakVersion,debug);
    int jiggScale = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"JiggScale",peakVersion,debug);
    int outputType = SpireProc_GetTableEntryInt("SpireTable_Peakup.txt","mode",peakupMode,"OutputType",peakVersion,debug);
    {int}[] parms = [{dcuDataMode},{pixel},{chopTable},{chopTableIndex},{startChopPosn},{chopPosnIncr},{nChopPosns},{startJiggPosn},{jiggPosnIncr},{nJiggPosns},{chopOffset},{jiggOffset},{nChopCycles},{chopCyclePeriod},{nBsmFrames},{nDcuFrames},{dcuFrameDelay},{chopScale},{jiggScale},{outputType}];
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_PERFORM_PEAKUP_RAW(" + parms + ")");
    Spire_PERFORM_PEAKUP_RAW(dcuDataMode,pixel,chopTable,chopTableIndex,startChopPosn,chopPosnIncr,nChopPosns,startJiggPosn,jiggPosnIncr,nJiggPosns,chopOffset,jiggOffset,nChopCycles,chopCyclePeriod,nBsmFrames,nDcuFrames,dcuFrameDelay,chopScale,jiggScale,outputType);
    //  set datarate
    double dcuRate = 0.0;
    double bsmRate = 0.0;
    if(peakupMode == "PPeakup") {
        dcuRate = SpireProc_GetTableEntryDouble("SpireTable_PhotModeParams.txt","mode",peakupMode,"dcuDataRate",pmodeVersion,debug);
    } else {
        dcuRate = SpireProc_GetTableEntryDouble("SpireTable_SpecModeParams.txt","mode",peakupMode,"dcuDataRate",smodeVersion,debug);
    }
    bsmRate = SpireProc_GetTableEntryDouble("SpireTable_CommonModeParams.txt","mode",peakupMode,"bsmDataRate",comVersion,debug);
    double rate = dcuRate + bsmRate;
    data_rate(rate);
    // wait for peakup operation to finish then set datarate to zero
    delay((nChopPosns + nJiggPosns) * (chopCyclePeriod * nChopCycles / 1000000) + 2);
    data_rate(0.0);
    //
    // wait for calculation of offsets
    delay(60);
    // //
    // //
    // Stop MCU science data collection:
    //
    SpireSendDrcuCmd(0x91c10000,0);
    // //
    // //
    // Set DCU sampling to continuous after VM:
    // 
    SpireSendDrcuCmd(0x843d0000,0);
    sync();
    //
    //
    // ..... completion .....
    //
    // flush data
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x5000)");
    Spire_FLUSH_FIFO_RAW(0x5000);
    delay(2);
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Photometer Peakup ended");
    SpireMsg(1,"  ..Photometer Peakup  (" + (time() - t) + " seconds)");
}

// SpireProc_PTCOff
//
// $id$
//
// This procedure switches off the PTC
// 
// The instrument should normally be in PHOTSTBY mode before execution of this observation
// Final Configuration: Instrument is still in PHOTSTBY mode after execution of this observation
//
// 05/08/2009 SDS: First Version 0.1 
// 17/02/2010 SDS:  Version 0.2
//                             Replaced procedures SpireProc_Set_StartDcuData & SpireProc_Set_StopDcuData with BBs 
//                             SpireBbStartDcuData and SpireBbStopDcuData (SPIRE SPR-1832)
//
procedure SpireProc_PTCOff {
    int offTime = 120; // time (secs) to wait after PTC switch off
    bool sampleDetectors = true; // sample detectors during the PTC switch off?
    string ptcVersion = "v00";
    bool debug = false;
}{
    if(sampleDetectors) {
        SpireBbStartDcuData("PHTSTBY");
    }
    delay(2);
    SpireBbSetPtc("Off",ptcVersion,debug);
    //
    // ----------------
    // Wait time after PTC is switched off
    // ----------------
    delay(offTime);
    //
    // Stop DCU PF data
    //
    if(sampleDetectors) {
        SpireBbStopDcuData();
    }
}

//
// Patch the PM
// 26/04/2010: SDS First Version - in response to SPIRE-SCR-2534
//    
block SpireBb_PatchPM SPIRE 3422 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_PatchPM started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // Report the PM checksums at the start
    Spire_CHECK_MEMORY_RAW(0,0x4000,0x174b);
    delay(4);
    Spire_CHECK_MEMORY_RAW(0,0x6000,0xffff);
    delay(4);
    Spire_CHECK_MEMORY_RAW(0,0x15fff,0x59);
    delay(4);
    // Dump the current contents of PM locations to be patched
    Spire_DUMP_MEMORY_RAW(0,0xbed8,1);
    delay(4);
    Spire_DUMP_MEMORY_RAW(0,0xe7a8,1);
    delay(4);
    // Patch the PM locations 
    Spire_LOAD_PM_RAW(0xbed8,0x0,1,[{"700F81000000"}],0x85f9);
    delay(2);
    Spire_LOAD_PM_RAW(0xe7a8,0x0,1,[{"0F040002FC67"}],0x6698);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xbed8,1);
    delay(4);
    Spire_DUMP_MEMORY_RAW(0,0xe7a8,1);
    delay(4);
    // Report the PM checksums as well
    Spire_CHECK_MEMORY_RAW(0,0x4000,0x174b);
    delay(4);
    Spire_CHECK_MEMORY_RAW(0,0x6000,0xffff);
    delay(4);
    Spire_CHECK_MEMORY_RAW(0,0x15fff,0x59);
    delay(4);
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_PatchPM ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

//CLName: SpireBb_LoadTableBSMMove
//VMVersion: 2.6
//CLVersion: 1.0
//CLCVSId: $ID$
//TableId: 0x49
//TableLength: 0x24
//Date: 060531154711
// 23/07/2010: SDS
//                      Now reporting one word less than the length of table (static part of table) 
//                      See SPIRE-SCR-2761
block SpireBb_LoadTableBSMMove SPIRE 3343 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableBSMMove started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0x49
    Spire_SET_TABLE(0x49,0x24);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x49,0x0,36,[{0x20ff0001},{0x12000001},{0x23},{0x80007d0},{0x1000001},{0x12000003},{0x7d0},{0x9000003},{0x65000101},{0x12000000},{0x1},{0x12000001},{0xc3},{0x49020023},{0x18000002},{0xffff},{0x60640001},{0x12000000},{0x1},{0x12000001},{0x143},{0x49020023},{0x1a020010},{0x18000002},{0xffff},{0x60640001},{0x12000000},{0x1},{0x12000001},{0xc6},{0x12000002},{0x1},{0x60640001},{0x1000000},{0x7f000000},{0x0}]);
    delay(t_min);
    //
    //  Dump table contents - report one word less than the length of table. 
    //  Final word in table is the last requested BSM Jiggle/Chop position to the BSMMove VM.
    //
    Spire_REPORT_TABLE(0x49,0x0,0x23);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableBSMMove ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

//
// Dump PM slowly (One TM(6,6) packet every 2 seconds)
// 04/08/2010: SDS First Version (For slow dumping of OBS 4.0.0 PM during DTCP without changing to SPIRE bus profile)
//                 See SPIRE-SCR-2763
//    
block SpireBb_SlowPMDump SPIRE 3427 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SlowPMDump started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    Spire_DUMP_MEMORY_RAW(0,0x4000,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x40a6,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x414c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x41f2,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x4298,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x433e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x43e4,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x448a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x4530,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x45d6,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x467c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x4722,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x47c8,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x486e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x4914,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x49ba,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x4a60,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x4b06,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x4bac,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x4c52,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x4cf8,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x4d9e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x4e44,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x4eea,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x4f90,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x5036,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x50dc,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x5182,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x5228,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x52ce,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x5374,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x541a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x54c0,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x5566,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x560c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x56b2,0x99);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x6000,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x60a6,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x614c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x61f1,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x6296,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x633b,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x63e0,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x6485,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x652a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x65cf,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x6674,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x6719,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x67be,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x6863,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x6908,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x69ad,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x6a52,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x6af7,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x6b9c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x6c41,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x6ce6,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x6d8b,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x6e30,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x6ed5,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x6f7a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x701f,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x70c4,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x7169,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x720e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x72b3,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x7358,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x73fd,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x74a2,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x7547,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x75ec,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x7691,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x7736,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x77db,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x7880,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x7925,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x79ca,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x7a6f,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x7b14,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x7bb9,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x7c5e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x7d03,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x7da8,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x7e4d,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x7ef2,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x7f97,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x803c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x80e1,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x8186,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x822b,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x82d0,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x8375,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x841a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x84bf,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x8564,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x8609,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x86ae,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x8753,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x87f8,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x889d,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x8942,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x89e7,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x8a8c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x8b31,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x8bd6,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x8c7b,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x8d20,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x8dc5,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x8e6a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x8f0f,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x8fb4,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9059,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x90fe,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x91a3,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9248,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x92ed,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9392,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9437,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x94dc,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9581,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9626,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x96cb,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9770,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9815,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x98ba,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x995f,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9a04,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9aa9,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9b4e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9bf3,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9c98,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9d3d,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9de2,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9e87,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9f2c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x9fd1,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xa076,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xa11b,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xa1c0,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xa265,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xa30a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xa3af,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xa454,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xa4f9,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xa59e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xa643,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xa6e8,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xa78d,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xa832,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xa8d7,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xa97c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xaa21,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xaac6,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xab6b,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xac10,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xacb5,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xad5a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xadff,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xaea4,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xaf49,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xafee,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xb093,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xb138,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xb1dd,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xb282,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xb327,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xb3cc,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xb471,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xb516,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xb5bb,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xb660,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xb705,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xb7aa,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xb84f,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xb8f4,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xb999,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xba3e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xbae3,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xbb88,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xbc2d,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xbcd2,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xbd77,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xbe1c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xbec1,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xbf66,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xc00b,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xc0b0,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xc155,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xc1fa,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xc29f,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xc344,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xc3e9,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xc48e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xc533,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xc5d8,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xc67d,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xc722,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xc7c7,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xc86c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xc911,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xc9b6,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xca5b,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xcb00,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xcba5,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xcc4a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xccef,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xcd94,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xce39,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xcede,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xcf83,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xd028,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xd0cd,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xd172,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xd217,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xd2bc,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xd361,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xd406,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xd4ab,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xd550,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xd5f5,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xd69a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xd73f,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xd7e4,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xd889,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xd92e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xd9d3,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xda78,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xdb1d,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xdbc2,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xdc67,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xdd0c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xddb1,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xde56,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xdefb,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xdfa0,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xe045,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xe0ea,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xe18f,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xe234,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xe2d9,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xe37e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xe423,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xe4c8,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xe56d,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xe612,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xe6b7,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xe75c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xe801,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xe8a6,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xe94b,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xe9f0,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xea95,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xeb3a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xebdf,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xec84,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xed29,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xedce,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xee73,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xef18,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xefbd,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xf062,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xf107,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xf1ac,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xf251,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xf2f6,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xf39b,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xf440,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xf4e5,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xf58a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xf62f,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xf6d4,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xf779,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xf81e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xf8c3,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xf968,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xfa0d,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xfab2,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xfb57,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xfbfc,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xfca1,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xfd46,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xfdeb,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xfe90,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xff35,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0xffda,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1007f,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x10124,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x101c9,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1026e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x10313,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x103b8,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1045d,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x10502,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x105a7,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1064c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x106f1,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x10796,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1083b,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x108e0,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x10985,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x10a2a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x10acf,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x10b74,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x10c19,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x10cbe,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x10d63,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x10e08,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x10ead,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x10f52,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x10ff7,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1109c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x11141,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x111e6,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1128b,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x11330,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x113d5,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1147a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1151f,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x115c4,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x11669,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1170e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x117b3,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x11858,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x118fd,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x119a2,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x11a47,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x11aec,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x11b91,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x11c36,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x11cdb,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x11d80,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x11e25,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x11eca,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x11f6f,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x12014,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x120b9,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1215e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x12203,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x122a8,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1234d,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x123f2,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x12497,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1253c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x125e1,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x12686,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1272b,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x127d0,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x12875,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1291a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x129bf,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x12a64,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x12b09,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x12bae,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x12c53,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x12cf8,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x12d9d,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x12e42,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x12ee7,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x12f8c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x13031,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x130d6,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1317b,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x13220,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x132c5,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1336a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1340f,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x134b4,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x13559,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x135fe,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x136a3,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x13748,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x137ed,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x13892,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x13937,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x139dc,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x13a81,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x13b26,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x13bcb,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x13c70,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x13d15,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x13dba,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x13e5f,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x13f04,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x13fa9,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1404e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x140f3,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x14198,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1423d,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x142e2,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x14387,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1442c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x144d1,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x14576,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1461b,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x146c0,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x14765,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1480a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x148af,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x14954,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x149f9,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x14a9e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x14b43,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x14be8,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x14c8d,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x14d32,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x14dd7,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x14e7c,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x14f21,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x14fc6,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1506b,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15110,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x151b5,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x1525a,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x152ff,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x153a4,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15449,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x154ee,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15593,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15638,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x156dd,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15782,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15827,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x158cc,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15971,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15a16,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15abb,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15b60,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15c05,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15caa,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15d4f,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15df4,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15e99,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15f3e,0xa6);
    delay(2);
    Spire_DUMP_MEMORY_RAW(0,0x15fe3,0x76);
    delay(2);
    // Report the PM checksums as well
    Spire_CHECK_MEMORY_RAW(0,0x4000,0x174b);
    delay(5);
    Spire_CHECK_MEMORY_RAW(0,0x6000,0xffff);
    delay(5);
    Spire_CHECK_MEMORY_RAW(0,0x15fff,0x59);
    delay(5);
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SlowPMDump ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_StopDcuData.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to stop generation of detector data TM packets
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/01/26 V1.0: Initial version adapted from
//                  SpireBb_StopDcuData.txt (2008/07/03 V0.2) merging it with
//                  SpireStopDcuData.txt (KK, v1.3 2007/04/02)            
//                  Script has now no (unnecessary) RESET_FIFO after the 
//                  FLUSH_FIFO and the delay time after FLUSH_FIFO is 
//                  set to 2. Script no longer sets the data rates. 
// 2009/01/30 V1.1: Name in messages commands corrected. 
// 2010/04/21 V1.2: SDS
//                  SPIRE-SCR-2501:
//                  Replaced Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_StopDcuData {
}{
    // //
    // //
    // Start procedure:
    //
    message("4    " + time() + ": SpireProc_Set_StopDcuData started");
    message("4          $Id: $");
    // //
    // //
    // Stop data collection:
    //
    message("5          " + time() + "Cmd: SpireSendDrcuCmd(0x843e0000,0)");
    SpireSendDrcuCmd(0x843e0000,0);
    // //
    // //
    // Flush DCU (x1000) fifo:
    //
    message("5          " + time() + "Cmd: Spire_FLUSH_FIFO(0x1000)");
    Spire_FLUSH_FIFO(0x1000);
    delay(2);
    // //
    // //
    // End procedure:
    //
    message("4    " + time() + ": SpireProc_Set_StopDcuData ended");
    //
}

// SpireSpectroPoint
//
// $Id:$
//
// The high level script for the Spire Spectrometer Single-pointing  observing mode 
//
// This type of observation may be executed using either the SOF1 or SOF2 observing modes
//
// 15/02/2008 KJK: 
//       Added otf flag to step for intermediate PCAL flashes
// 04/11/2008 KJK: 
//       added data_rate commands
// 04/03/2009 MP: 
//       Fixed bug in call to 
//       SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode"...)
// 10/03/2009 KJK: 
//       SCR 1274, add additional dummy parameters 
//       Update input API to include versions for all cal tables
// 17/03/2009 KJK:
//       Update API to read NCycles1 from NHCycles and NCycles2 from NLCycles
// 18/03/2009 KJK:
//       Added inpuit of instrument boresight
// 25/08/2009 KJK:
//       SPR Spire-1641: Needed new input parameters bsmModel and bsmVersion
// 03/09/2009 KJK: 
//       Added input version parameters in calls to SpireProc_Sflash 
//       to fix SPR-1763 (Problem1); Added smecVersion to input parameters
// 04/09/2009 MP: v1
//       Pass smecVersion to SpireBbSOF1End and SpireBbSOF2End
// 04/09/2009 MP: v2
//       Add in move of BSM to home before PCAL flash      
// 06/09/2009 KJK:
//       Modified to pass opsMode to  SpireBbSpecSerendipity rather 
//       than hard coded "SSer"
// 14/09/2009 KJK:
//       SCR Spire-1953: updated calls to pass smodeVersion to 
//       SpireBbSOF1Init, SpireBbSOF2Init, SpireSOF12Pointing
// 15/09/2009 KJK:
//      SPR Spire-1763: changed calls to Proc_Sflash to assume SMEC is at 
//      scanstart position and to leave it at scanstart position
// 24/09/2009 KJK:
//       Updated calls to SpireSOF12Pointing, SpireBbSOF1Config, 
//       SpireBbSOF2Config, SpireBbSOF1End, SpireBbSOF2End
// 29/09/2009 MP: SPR-SPIRE-2048
//       Fix bug with hardcoded SFlash for isBright. Needed to changed
//       call to SOF1/2Init and SpirePointSpectrum. 
// 20/10/2009 KJK SPR Spire-2062:
//       Add call to SpireBbSmecInit in INIT_HOLD
// 16/02/2010 KJK: SCR Spire-2341:
//       Updated to get Flash info from SpireTable_SpireParams rather than SpireParams
//       Updated to call SpireSOF12Pointing with additional parameter
//  31/03/2010 KJK: SCR Spire-2459:
//       Added calls to SpireBb_SetSpecDetOffsets when necessary
//  20/07/2011 SDS:  SCR Spire-2563:
//                              opsVersion added in call to SpireSOF12Pointing
// 
////////////////////////////////////////////////////////////////////////////
{int,int,double,int,double,int,int,int} obs SpireSpectroPoint {
    double ra = 0.0 in [0.0,360.0]; // RA of Target
    double dec = 0.0 in [-90.0,90.0]; // DEC of Target
    int naifid = 0; // NAIF identifier
    string boresight = ""; // Instrument Boresight
    string pointing = "single" in ["single","raster"]; // pointing type
    string sampling = "sparse" in ["sparse","intermediate","full"]; // spatial sampling
    string resolution = "H" in ["H","M","L","C","H+L"]; // spectral resolution
    bool choppingAvoidOn = false; // is chopping avoidance selected
    int choppingAvoidNumber = 0 in [0,3]; //  the number of chopping avoid angles selected
    double choppingAvoidFrom1 = 0.0 in [0.0,360.0];
    double choppingAvoidTo1 = 0.0 in [0.0,360.0];
    double choppingAvoidFrom2 = 0.0 in [0.0,360.0];
    double choppingAvoidTo2 = 0.0 in [0.0,360.0];
    double choppingAvoidFrom3 = 0.0 in [0.0,360.0];
    double choppingAvoidTo3 = 0.0 in [0.0,360.0];
    int nRepetitions1 = 2 in [2,1200]; // number of times to repeat spectral scan pairs for single resolution scan modes and high resolution in H+L mode
    int nRepetitions2 = 2 in [2,1200]; // number of times to repeat spectral scan pairs for low resolution scans for 'H+L" mode
    double wavelength1 = -1.0; // wavelength
    double wavelength2 = -1.0; // wavelength
    double wavelength3 = -1.0; // wavelength
    double wavelength4 = -1.0; // wavelength
    double wavelength5 = -1.0; // wavelength
    double wavelength6 = -1.0; // wavelength
    double wavelength7 = -1.0; // wavelength
    double wavelength8 = -1.0; // wavelength
    bool isJyContinuum = true; // is continuum specified in Jy rather than Wm-2um-1
    double lineFlux1 = -1.0; // line flux estimate
    double lineFlux2 = -1.0; // line flux estimate
    double lineFlux3 = -1.0; // line flux estimate
    double lineFlux4 = -1.0; // line flux estimate
    double lineFlux5 = -1.0; // line flux estimate
    double lineFlux6 = -1.0; // line flux estimate
    double lineFlux7 = -1.0; // line flux estimate
    double lineFlux8 = -1.0; // line flux estimate
    double contFlux1 = -1.0; // continuum flux estimate
    double contFlux2 = -1.0; // continuum flux estimate
    double contFlux3 = -1.0; // continuum flux estimate
    double contFlux4 = -1.0; // continuum flux estimate
    double contFlux5 = -1.0; // continuum flux estimate
    double contFlux6 = -1.0; // continuum flux estimate
    double contFlux7 = -1.0; // continuum flux estimate
    double contFlux8 = -1.0; // continuum flux estimate
    bool isBright = false; // Use settings for bright source (==tick)
    bool isChopped = false;
    int nMaps = 1;
    int nHCycles = 0; // total number of cycles at each pointing and jiggle position for first resolution
    int nMCycles = 0; // Not Used
    int nLCycles = 0; // total number of cycles at each pointing and jiggle position for second resolution (in H+L mode)
    int nCals = 0;
    double tCal = 999999.0; // time between Gyro calibrations within a jiggle point operation
    int nFlashes = 0;
    double tFlash = 999999.0; // time between PCAL flashes within a jiggle point operation
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParms
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    string flashVersion = "v00"; // Version in cal table SpireTable_FlashParms
    string smodeVersion = "v00"; // Version in cal table SpireTable_SpecModeParams
    string specVersion = "v00"; // Version in cal table SpireTable_Spectrometer
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // unused parameters
    string comVersion = "v00";
    string smecVersion = "v00";
    //
    // check inputs
    if(pointing != "single") {
        error("SpireSpectroPoint: Pointing is not set to single");
    }
    SpireMsg(0,"Spectrometer Single Point Observation");
    //
    double[] wavelength = [wavelength1,wavelength2,wavelength3,wavelength4,wavelength5,wavelength6,wavelength7,wavelength8];
    double[] lineFlux = [lineFlux1,lineFlux2,lineFlux3,lineFlux4,lineFlux5,lineFlux6,lineFlux7,lineFlux8];
    double[] contFlux = [contFlux1,contFlux2,contFlux3,contFlux4,contFlux5,contFlux6,contFlux7,contFlux8];
    //
    // *****************************************
    //      select instrument ops mode    
    // *****************************************
    //       
    string opsMode = "";
    // opsMode
    int md = 0;
    // value of MODE parameter
    if(sampling == "sparse") {
        opsMode = "SOF1";
        md = 0x410;
    } else {
        if(sampling == "intermediate") {
            opsMode = "SOF2_int";
        } else {
            if(sampling == "full") {
                opsMode = "SOF2";
            } else {
                error("SpireSpectroPoint: Unknown sampling");
            }
        }
        md = 0x420;
    }
    string flashMode = "";
    if(isBright) {
        flashMode = "SFlash_b";
    } else {
        flashMode = "SFlash";
    }
    //
    // *****************************************
    //      set up scan sets  
    // *****************************************
    // 
    string res1 = resolution;
    string res2 = "L";
    int nCycles1 = nHCycles;
    int nCycles2 = nLCycles;
    if(resolution == "H+L") {
        res1 = "H";
    }
    // *****************************************
    // get observing parameters
    // *****************************************
    //
    double tScan1 = SpireProc_GetTableEntryDouble("SpireTable_Spectrometer.txt","ResChar",res1,"ScanTime",specVersion,debug);
    double tScan2 = SpireProc_GetTableEntryDouble("SpireTable_Spectrometer.txt","ResChar",res2,"ScanTime",specVersion,debug);
    int scansPerCycle1 = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"N" + res1 + "Scans",opsVersion,debug);
    int scansPerCycle2 = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"N" + res2 + "Scans",opsVersion,debug);
    double tCycle1 = tScan1 * double(scansPerCycle1);
    double tCycle2 = tScan2 * double(scansPerCycle2);
    //
    int jiggleTable = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"TableId",opsVersion,debug);
    // Jiggle Table ID
    int jiggleSize = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"TableSize",opsVersion,debug);
    // Jiggle Table length 
    int tSerendipity = duration(SpireBbSpecSerendipity(opsMode,0));
    // minimum time for a serendipity observation
    // initial flash flag
    bool initFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",opsMode,"InitFlash",spireVersion,debug);
    // final flash flag
    bool endFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",opsMode,"EndFlash",spireVersion,debug);
    double perScanOsit1 = SpireProc_GetTableEntryDouble("SpireTable_Spectrometer.txt","ResChar",res1,"Osit",specVersion,debug);
    // effective on source integration time per scan
    double perScanOsit2 = SpireProc_GetTableEntryDouble("SpireTable_Spectrometer.txt","ResChar",res2,"Osit",specVersion,debug);
    // effective on source integration time per scan
    //
    int nScans1 = nCycles1 * scansPerCycle1;
    int nScans2 = nCycles2 * scansPerCycle2;
    //
    int scanStart1 = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",res1,"ScanStart",specVersion,debug);
    int smecHome = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"Home");
    // //
    // //
    // Read BSM hold position from calibration table:  
    //
    string tabName05 = "SpireTable_BsmNominalSettings.txt";
    string version = bsmVersion;
    string tabName = tabName05;
    string selCol = "model";
    string selVal = bsmModel;
    string tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    //
    // *****************************************
    // set telescope pointing mode
    // *****************************************
    //
    // Lookup boresight, if not provided
    string ib = boresight;
    if(boresight == "") {
        ib = SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode",opsMode,"Boresight",opsVersion,debug);
    }
    double deltaY = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",opsMode,"DeltaY",opsVersion,debug);
    // offset to pixel centre from boresight in Y direction (arcsecs)
    double deltaZ = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",opsMode,"DeltaZ",opsVersion,debug);
    // offset to pixel centre from boresight in Z direction (arcsecs)
    //
    double yOffset = 0.0;
    // offset to observation position from target in Y direction (arcsecs)
    double zOffset = 0.0;
    // offset to observation position from target in Z direction (arcsecs)
    //
    {int,int,int,int,int,int} sofPoint = SpireSOF12Pointing(opsMode,res1,nCycles1,tCycle1,scansPerCycle1,res2,nCycles2,tCycle2,scansPerCycle2,nMaps,nFlashes,tFlash,isBright,bsmModel,bsmVersion,comVersion,spireVersion,smodeVersion,smecVersion,specVersion,flashVersion,opsVersion,debug);
    int tSlewMin = sofPoint{0};
    int tInitHold = sofPoint{1};
    int tFinalHold = sofPoint{2};
    int tp = sofPoint{3};
    //
    int[] ts = basic_fine_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,yOffset + deltaY,zOffset + deltaZ,tp);
    //
    int tobs = ts[0];
    int tslew = ts[1];
    int tend = ts[2];
    //
}{
    SpireMsg(0,"Observation Start");
    SpireMsg(0,"  Uses observing mode " + opsMode);
    SpireMsg(3,"       $Id:$");
    //??p pointing file generation ------------------------------
    double pos = 90.0;
    //??p double[] rdp0 = PtOffset([ra,dec,pos],zOffset,yOffset,0.0,false);
    //??p pointing file generation ------------------------------
    //
    // *****************************************
    //   Display input parameters
    // *****************************************
    SpireMsg(3,"     Input values:");
    SpireMsg(3,"     ..RA: " + ra);
    SpireMsg(3,"     ..Dec: " + dec);
    SpireMsg(3,"     ..NAIF ID: " + naifid);
    SpireMsg(3,"     ..Pointing: " + pointing);
    SpireMsg(3,"     ..Sampling: " + sampling);
    SpireMsg(3,"     ..Resolution: " + resolution);
    SpireMsg(3,"     ..Y Offset: " + yOffset);
    SpireMsg(3,"     ..Z Offset: " + zOffset);
    SpireMsg(3,"     ..nMaps: " + nMaps);
    SpireMsg(3,"     ..nHCycles: " + nHCycles);
    SpireMsg(3,"     ..nMCycles: " + nMCycles);
    SpireMsg(3,"     ..nLCycles: " + nLCycles);
    SpireMsg(3,"     ..tCal: " + tCal);
    SpireMsg(3,"     ..tFlash: " + tFlash);
    SpireMsg(3,"     Fixed values:");
    SpireMsg(3,"     ..ib: " + ib);
    SpireMsg(3,"     ..initFlash: " + initFlash);
    SpireMsg(3,"     ..endFlash: " + endFlash);
    SpireMsg(3,"     ..tCycle1: " + tCycle1);
    SpireMsg(3,"     ..tCycle2: " + tCycle2);
    SpireMsg(3,"     Pointing Mode Input values:");
    SpireMsg(3,"     ..tSlewMin: " + tSlewMin);
    SpireMsg(3,"     ..tInitHold: " + tInitHold);
    SpireMsg(3,"     ..tFInalHold: " + tFinalHold);
    SpireMsg(3,"     ..tp: " + tp);
    SpireMsg(3,"     Fine Pointing Mode Output values:");
    SpireMsg(3,"     ..tobs: " + tobs);
    SpireMsg(3,"     ..slew: " + tslew);
    SpireMsg(3,"     ..tend: " + tend);
    // *****************************************
    //   execute observation
    // *****************************************
    //
    data_rate(0.0);
    double chkrate = dlookup("Datarates.txt","Scan","CHK");
    ess_hk_data_rate(chkrate);
    double nhkrate = dlookup("Datarates.txt","Scan","NHK");
    non_ess_hk_data_rate(nhkrate);
    string tstr = "";
    // time string
    int otf = 0x8000;
    // On Target Flag
    double srcTime = 0.0;
    // total on source integration time
    int t = 0;
    //
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // *********************   SLEWING
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Slewing to start position");
            t = time();
            // set up observation parameters
            SpireBb_StartObsAll(opsMode);
            // perform serendipity operation if possible
            if(tslew > tSerendipity + tSlewMin) {
                SpireBbSpecSerendipity(opsMode,tslew - tSlewMin - 2);
            }
            // configure instrument for operations
            if(opsMode == "SOF1") {
                SpireBbSOF1Config(opsMode,res1,isBright,comVersion,smodeVersion,smecVersion,specVersion,debug);
            } else {
                SpireBbSOF2Config(opsMode,res1,isBright,comVersion,smodeVersion,smecVersion,specVersion,debug);
            }
        }
        if(state[0] == 2) {
            // ********************* INITIAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Telescope at start position");
            SpireMsg(0,"  Slew (" + (time() - t) + " secs)");
            SpireMsg(2,"    " + tstr + " Initialising Instrument");
            t = time();
            // initialise instrument
            SpireBbSmecInit(res1,bsmVersion,smecVersion,specVersion,debug);
            if(opsMode == "SOF1") {
                SpireBbSOF1Init(smodeVersion,isBright,debug);
            } else {
                SpireBbSOF2Init(smodeVersion,isBright,debug);
            }
            // calibrate if necessary
            if(initFlash || double(tp) > tFlash) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                if(opsMode != "SOF1" && isBright) {
                    SpireBb_SetSpecDetOffsets(debug);
                }
                SpireProc_SFlash(flashMode,scanStart1,scanStart1,otf,bsmVersion,smodeVersion,flashVersion,debug);
            }
        }
        if(state[0] == 3) {
            // ********************* POINTING
            //??p pointing file generation ------------------------------
            //??p PtOutput(rdp0);
            //??p pointing file generation ------------------------------
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " New Pointing");
            int nPoints = 0;
            int step = 0;
            t = time();
            double s = 0.0;
            //
            for(int j = 0 .. jiggleSize - 1) {
                step = j;
                if(j > 0) {
                    if(nFlashes > 0 || j % nPoints == 0) {
                        SpireBb_BsmMove(hold_chop,hold_jigg,debug);
                        SpireProc_SFlash(flashMode,scanStart1,scanStart1,otf | step,bsmVersion,smodeVersion,flashVersion,debug);
                    }
                }
                SpireBbBsmMove(jiggleTable,j,step);
                if(opsMode != "SOF1" && isBright) {
                    SpireBb_SetSpecDetOffsets(debug);
                }
                s = SpirePointSpectrum(res1,nCycles1,tCycle1,scansPerCycle1,res2,nCycles2,tCycle2,scansPerCycle2,tFlash,otf | step,bsmVersion,smodeVersion,specVersion,flashVersion,isBright,debug);
                srcTime = srcTime + s;
                if(j == 0) {
                    nPoints = ifloor(tFlash / double(time() - t));
                    if(nPoints == 0) {
                        nPoints = jiggleSize;
                    }
                }
            }
        }
        if(state[0] == 5) {
            // ******************** FINAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Reconfiguring Instrument");
            t = time();
            // calibrate if necessary
            if(endFlash || double(tp) > tFlash) {
                SpireBb_BsmMove(hold_chop,hold_jigg,debug);
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireProc_SFlash(flashMode,scanStart1,scanStart1,otf | step,bsmVersion,smodeVersion,flashVersion,debug);
            }
            // reconfigure back to SPEC_STBY configuration
            if(opsMode == "SOF1") {
                SpireBbSOF1End(res1,isBright,bsmModel,bsmVersion,comVersion,smodeVersion,smecVersion,specVersion,debug);
            } else {
                SpireBbSOF2End(res1,isBright,bsmModel,bsmVersion,comVersion,smodeVersion,smecVersion,specVersion,debug);
            }
            // 
        }
    }
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + " Instrument Reconfigured");
    SpireMsg(0,"  Instrument Reset (" + (time() - t) + " secs)");
    //
    SpireMsg(0,"Observation Completed  (" + time() + " seconds)");
    SpireMsg(0,"Note: Total time (s) = Observation Completed time - slew time + Observatory Overheads");
    assert (time() == ts[0] + ts[1]);
    //

    return {1,jiggleSize,perScanOsit1,nScans1,perScanOsit2,nScans2,iround(srcTime),time() - iround(srcTime) - tslew};
}

// SpirePOF5Estimate
//
// $Id:$
//
// This procedure calculates the estimated noise and signal/noise
//  for the given observing time.
//
//  for input values, a value less than 0 indicates value unknown
//
//  18/01/07: v1.4:  updated to work for different opsMOdes and use Teff to calculate sensitivity
//  20/04/07: v1.5:  added rate as an input parameter
//            v1.6: SCR3054
//            v1.7: SCR3012
//  07/02/09: Updated to select sensitivity tables depending on value of isBright
//
//
{string,double,double,double,double,bool,double,double,double}[] procedure SpirePOF5Estimate {
    string obsMode = "POF5_F_scana";
    double tau = 1.0; // integration time factor (number of map repeats)
    double scanRate = 0.0;
    double sourceFluxPSW = -1.0;
    double sourceFluxPMW = -1.0;
    double sourceFluxPLW = -1.0;
    double sourceBrightPSW = -1.0;
    double sourceBrightPMW = -1.0;
    double sourceBrightPLW = -1.0;
    bool isBright = false;
}{
    SpireMsg(3,"          Calculating POF5 noise estimates");
    SpireMsg(3,"          $Id:$");
    SpireMsg(3,"          Input:");
    SpireMsg(3,"            ObsMode: " + obsMode);
    SpireMsg(3,"            Integration time factor: " + tau);
    SpireMsg(3,"            PSW Flux density: " + sourceFluxPSW);
    SpireMsg(3,"            PMW Flux density: " + sourceFluxPMW);
    SpireMsg(3,"            PLW Flux density: " + sourceFluxPLW);
    SpireMsg(3,"            PSW Surface Brightness: " + sourceBrightPSW);
    SpireMsg(3,"            PMW Surface Brightness: " + sourceBrightPMW);
    SpireMsg(3,"            PLW Surface Brightness: " + sourceBrightPLW);
    SpireMsg(3,"            isBright: " + isBright);
    //
    // calculate effective integration times
    //
    string tabName = "Phot_Sensitivities.txt";
    if(isBright) {
        tabName = "Phot_BrightSensitivities.txt";
    }
    double psw_teff = dlookup(tabName,obsMode,"PSWTeff");
    psw_teff = psw_teff / scanRate;
    double pmw_teff = dlookup(tabName,obsMode,"PMWTeff");
    pmw_teff = pmw_teff / scanRate;
    double plw_teff = dlookup(tabName,obsMode,"PLWTeff");
    plw_teff = plw_teff / scanRate;
    //
    // generate sensitivities 
    //
    // fetch the flux uncertainty information for the obsMode
    double psw_func = dlookup(tabName,obsMode,"PSWFluxUnc") / sqrt(psw_teff);
    double pmw_func = dlookup(tabName,obsMode,"PMWFluxUnc") / sqrt(pmw_teff);
    double plw_func = dlookup(tabName,obsMode,"PLWFluxUnc") / sqrt(plw_teff);
    // fetch the surface brightness uncertainty information for the obsMode
    double psw_bunc = dlookup(tabName,obsMode,"PSWBrightUnc") / sqrt(psw_teff);
    double pmw_bunc = dlookup(tabName,obsMode,"PMWBrightUnc") / sqrt(pmw_teff);
    double plw_bunc = dlookup(tabName,obsMode,"PLWBrightUnc") / sqrt(plw_teff);
    // fetch confusion limits
    double psw_conf = dlookup(tabName,obsMode,"PSWConfLim");
    double pmw_conf = dlookup(tabName,obsMode,"PMWConfLim");
    double plw_conf = dlookup(tabName,obsMode,"PLWConfLim");
    SpireMsg(3," Input Sensitivity Values:");
    SpireMsg(3,"            Band:                                                               PSW                   PMW                        PLW");
    SpireMsg(3,"            Flux Uncertainty:                                    " + psw_func + "            " + pmw_func + "          " + plw_func);
    SpireMsg(3,"            Surface Brightness Uncertainty:        " + psw_bunc + "            " + pmw_bunc + "          " + plw_bunc);
    SpireMsg(3,"            Conf Limit:                                              " + psw_conf + "            " + pmw_conf + "          " + plw_conf);
    //
    // calculate noise estimates
    {string,double,double,double,double,bool,double,double,double}[] estimates = [{"250",sourceFluxPSW,-1.0,-1.0,psw_conf,false,sourceBrightPSW,-1.0,-1.0},{"350",sourceFluxPMW,-1.0,-1.0,pmw_conf,false,sourceBrightPMW,-1.0,-1.0},{"500",sourceFluxPLW,-1.0,-1.0,plw_conf,false,sourceBrightPLW,-1.0,-1.0}];
    estimates[0]{2} = psw_func / sqrt(tau);
    if(estimates[0]{2} < psw_conf) {
        estimates[0]{5} = true;
    }
    if(sourceFluxPSW >= 0.0) {
        estimates[0]{3} = sourceFluxPSW / estimates[0]{2};
        if(estimates[0]{3} > 200.0) {
            estimates[0]{3} = 200.0;
        }
    }
    estimates[0]{7} = psw_bunc / sqrt(tau);
    if(sourceBrightPSW >= 0.0) {
        estimates[0]{8} = sourceBrightPSW / estimates[0]{7};
        if(estimates[0]{8} > 200.0) {
            estimates[0]{8} = 200.0;
        }
    }
    estimates[1]{2} = pmw_func / sqrt(tau);
    if(estimates[1]{2} < pmw_conf) {
        estimates[1]{5} = true;
    }
    if(sourceFluxPMW >= 0.0) {
        estimates[1]{3} = sourceFluxPMW / estimates[1]{2};
        if(estimates[1]{3} > 200.0) {
            estimates[1]{3} = 200.0;
        }
    }
    estimates[1]{7} = pmw_bunc / sqrt(tau);
    if(sourceBrightPMW >= 0.0) {
        estimates[1]{8} = sourceBrightPMW / estimates[1]{7};
        if(estimates[1]{8} > 200.0) {
            estimates[1]{8} = 200.0;
        }
    }
    estimates[2]{2} = plw_func / sqrt(tau);
    if(estimates[2]{2} < plw_conf) {
        estimates[2]{5} = true;
    }
    if(sourceFluxPLW >= 0.0) {
        estimates[2]{3} = sourceFluxPLW / estimates[2]{2};
        if(estimates[2]{3} > 200.0) {
            estimates[2]{3} = 200.0;
        }
    }
    estimates[2]{7} = plw_bunc / sqrt(tau);
    if(sourceBrightPLW >= 0.0) {
        estimates[2]{8} = sourceBrightPLW / estimates[2]{7};
        if(estimates[2]{8} > 200.0) {
            estimates[2]{8} = 200.0;
        }
    }
    //
    // return values          
    SpireMsg(3," Output Estimates:");
    SpireMsg(3,"            Band:                                   " + estimates[0]{0} + "            " + estimates[1]{0} + "            " + estimates[2]{0});
    SpireMsg(3,"            Source Flux                        " + estimates[0]{1} + "            " + estimates[1]{1} + "            " + estimates[2]{1});
    SpireMsg(3,"            1 Sigma  Flux Noise:        " + estimates[0]{2} + "            " + estimates[1]{2} + "            " + estimates[2]{2});
    SpireMsg(3,"            Flux Signal/Noise:             " + estimates[0]{3} + "            " + estimates[1]{3} + "            " + estimates[2]{3});
    SpireMsg(3,"            Conf Level:                          " + estimates[0]{4} + "            " + estimates[1]{4} + "            " + estimates[2]{4});
    SpireMsg(3,"            Conf Flag:                           " + estimates[0]{5} + "            " + estimates[1]{5} + "            " + estimates[2]{5});
    SpireMsg(3,"            1 Sigma  Brightness Noise:        " + estimates[0]{7} + "            " + estimates[1]{7} + "            " + estimates[2]{7});
    SpireMsg(3,"            Brightness Signal/Noise: " + estimates[0]{8} + "            " + estimates[1]{8} + "            " + estimates[2]{8});
    //

    return estimates;
}

// CVS comments  : $Id: PacsPhotEstimatorOBCPn.txt,v 1.1 2008/05/26 15:12:49 vanessad Exp $ 
// Missionphase  : Operations
//
// Purpose       : Estimate OBCP parameters for the PointMode and filter
//                 specified by the HSPOT user
//
// CUS author    : DAC
// Script file   : PacsPhotEstimatorOBCPn.txt 
//
// Input arguments
// type           name       Description
//
// Return values
// Type    Description
// tuple  {confPHOTblu,confPHOTred,confOBCP,{extension}}
//
// Description   : 
//
// Dependencies  : 
//
// Preconditions :
//
// Comments      : 
// 
// History       : 0.1  7-Dec-2005 DAC Based on PacsRangeSpecEstimatorOBCP27
// 0.2 15-Dec-2005 Added pos_CS1 and pos_CS2
// 0.3 10-aug-2006 Point source now observed with OBCP3; others with OBCP4
// 1.0 30-aug-2006 - editorial clean up
//                 - use repFactor instead of integrationTime
// 1.1 12-jan-2007 - Improved messages (w/Roland Vavrek)
//                 - added boolean dither to input list
{{int,int,int,int,int,int,int,int,int},{int,int,int,int,int,int,int,int,int},{int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int},{int,int,int,int}} procedure PacsPhotEstimatorOBCPn {
    int pointCase = 11; // Internal code for the pointing mode (see main)
    string filter = "blue1" in ["blue1","blue2"]; // filter from HSPOT
    int repFactor = 1; //Repeat factor, i.e. number of nod cycles
    {{int,int,int,int,int,int,int,int,int},{int,int,int,int,int,int,int,int,int},{int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int}} paramsPHOTdef = {{0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; // Default values
    bool noddingSel = false; // Nodding allowed or not
    bool dither = true; // With/without dithering
    bool verbose = true; // Print bla-bla
}{
    // Define local copy of confXXX tuples
    {int,int,int,int,int,int,int,int,int} confPHOTblu = clone(paramsPHOTdef{0});
    {int,int,int,int,int,int,int,int,int} confPHOTred = clone(paramsPHOTdef{1});
    {int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int} confOBCP = clone(paramsPHOTdef{2});
    // OBCP tuples use several variables, some of them are dedicated to one or
    // another OBCP. Here define all the tuple variables. Later, they may be 
    // updated according to used OBCP
    int nb_main_loops = 0;
    int nb_cycles_obs_cal = 0;
    int nb_rdouts_plateau = 0;
    int nb_chop_cycle = 0;
    int max_dither = 0;
    int nhold = 0;
    int nb_SRC_OFF = 0;
    int nb_CS1_CS2 = 0;
    int pos_CS1 = 0;
    int pos_CS2 = 0;
    // Update corresponding elements of confOBCP
    // Get "duration related" parameters from corresponding OBCPnparams U-CAL table
    if(pointCase == 11 || pointCase == 12) {
        string calNAME = "OBCP3params";
        //  The acces key is the chosen filter: blue1 or blue2
        //  There is a row per filter; it lists main OBCP parameters
        nb_main_loops = ilookup(calNAME,filter,"nb_main_loops");
        //  OBCPconf uses nb_cycles_obs_cal as variable name
        nb_cycles_obs_cal = nb_main_loops;
        nb_rdouts_plateau = ilookup(calNAME,filter,"nb_rdouts_plateau");
        nb_chop_cycle = ilookup(calNAME,filter,"nb_chop_cycle");
        max_dither = ilookup(calNAME,filter,"max_dither");
        nhold = ilookup(calNAME,filter,"nhold");
    }
    if(pointCase == 22 || pointCase == 31) {
        calNAME = "OBCP4params";
        nb_cycles_obs_cal = ilookup(calNAME,filter,"nb_cycles_obs_cal");
        nb_SRC_OFF = ilookup(calNAME,filter,"nb_SRC_REF");
        nb_rdouts_plateau = ilookup(calNAME,filter,"nb_rdouts_plateau");
        nb_CS1_CS2 = ilookup(calNAME,filter,"nb_CS1_CS2");
        nhold = ilookup(calNAME,filter,"nhold");
        //      CS1 and CS2 from dedicated CAL-U file
        pos_CS1 = ilookup("CHOPPERCSparams","PHOT","pos_CS1");
        pos_CS2 = ilookup("CHOPPERCSparams","PHOT","pos_CS2");
    }
    if(pointCase == 33) {
        calNAME = "No CAL file yet";
    }
    if(verbose) {
        debug_print("++PhotEstimator reads CAL-U: " + calNAME);
    }
    // Compute the OBS time for this pointCase and filter
    // Line Scan is not associated to an OBCP yet
    if(pointCase == 33) {
        int[] dureeOBCPn = [1,1,0,0,0];
    }
    // Point source
    if(pointCase == 11 || pointCase == 12) {
        dureeOBCPn = PacsDureeOBCP3(nb_main_loops,nb_rdouts_plateau,nb_chop_cycle);
    }
    // For small and large source use OBCP4
    if(pointCase == 22 || pointCase == 31) {
        dureeOBCPn = PacsDureeOBCP4(nb_SRC_OFF,nb_rdouts_plateau,nb_cycles_obs_cal,nb_CS1_CS2);
    }
    if(verbose) {
        debug_print("++PhotEstimator: dureeOBCP4: " + dureeOBCPn);
    }
    double quantumOBStime = double(dureeOBCPn[1] + dureeOBCPn[2]);
    // Get the "quantum" OBS time for the current order. U-CAL time doubles if 
    // nodding is allowed
    double nodFactor = 1.0;
    if(noddingSel) {
        nodFactor = 2.0;
    } else {
        int nb_nods = 0;
    }
    quantumOBStime = nodFactor * quantumOBStime;
    // Inform user
    string[] msgLine = [" "];
    int lineCnt = 0;
    if(noddingSel) {
        msgLine[lineCnt] = "<p>Shortest SKY time (no overheads) for filter " + filter + ": " + quantumOBStime + " [sec], includes an A=>B nod cycle</p>";
    } else {
        msgLine[lineCnt] = "<p>Shortest SKY time (no overheads) for filter " + filter + ": " + quantumOBStime + " [sec], no nodding demanded</p>";
    }
    lineCnt = lineCnt + 1;
    // Deal with repFactor. In case of noddingSel = false, the repFactor
    // gives the PointReq nrepeat count
    //
    // Re-use the previous logic based on userOBStime...
    // Repeat factor given for current filter.
    // Observing time can be increased by (integer) factor:
    int obsFactor = repFactor;
    double newOBStime = double(obsFactor) * quantumOBStime;
    if(verbose) {
        debug_print("++PhotEstimator: obsFactor: " + obsFactor + "; filter: " + filter);
    }
    // Common part of nodding/no nodding message
    if(repFactor == 1) {
        msgLine[lineCnt] = "<p>You may increase the sensitivity for the current filter by setting";
        lineCnt = lineCnt + 1;
        msgLine[lineCnt] = " the RepetitionFactor = 2,3,.. to obtain OBStime = repFactor*" + quantumOBStime + "</p>";
        lineCnt = lineCnt + 1;
    }
    // If no nodding then we repeat the raster pattern
    if(!noddingSel) {
        int repeat_factor = 1;
        nb_nods = 0;
        if(obsFactor > 1) {
            msgLine[lineCnt] = "<p>You entered repFactor > 1 </p>";
            lineCnt = lineCnt + 1;
            msgLine[lineCnt] = "Since no nodding was requested, we shall repeat";
            lineCnt = lineCnt + 1;
            msgLine[lineCnt] = "the raster pattern " + obsFactor + " times, leading to a total dwell time of " + newOBStime + " [sec]</p>";
            lineCnt = lineCnt + 1;
            repeat_factor = obsFactor;
        }
    } else {
        //    Nodding selected, here we increase newOBStime by increasing the
        //    number of nod cycles
        repeat_factor = 1;
        nb_nods = obsFactor;
        if(obsFactor > 1) {
            msgLine[lineCnt] = "<p>You entered repFactor > 1 </p>";
            lineCnt = lineCnt + 1;
            msgLine[lineCnt] = "Since nodding is allowed, we set the number";
            lineCnt = lineCnt + 1;
            msgLine[lineCnt] = " of nods to " + obsFactor + " cycles; leading to an accumulated dwell time of " + newOBStime + " [sec]</p>";
            lineCnt = lineCnt + 1;
        }
    }
    // Some more Pointing parameters (auxN just in case I need more...)
    int aux2 = 0;
    int aux3 = 0;
    // Pack information into proper tuples
    confOBCP{0} = nb_cycles_obs_cal;
    confOBCP{1} = max_dither;
    if(!dither) {
        confOBCP{1} = 0;
    }
    // Use confOBCP{2} to convey nb_chop_cycle
    confOBCP{2} = nb_chop_cycle;
    confOBCP{3} = nb_SRC_OFF;
    confOBCP{4} = nb_rdouts_plateau;
    confOBCP{5} = nb_CS1_CS2;
    confOBCP{15} = pos_CS1;
    confOBCP{16} = pos_CS2;
    // All these leftovers from SPECTRO code
    //   confOBCP { 6}  =   nb_grat_step_up  ;
    //   confOBCP { 7}  =   nb_grat_step_dn  ;
    //   confOBCP { 8}  =   grat_start_pos   ;
    //   confOBCP { 9}  =   grat_start_time  ;
    //   confOBCP {10}  =   grat_def_pos     ;
    //   confOBCP {11}  =   grat_def_time    ;
    //   confOBCP {12}  =   chop_pos_SRC     ;
    //   confOBCP {13}  =   chop_pos_REF1    ;
    //   confOBCP {14}  =   chop_pos_REF2    ;
    //   confOBCP {17}  =   chop_def         ;
    //   confOBCP {19}  =   order ;
    //   confPHOTred{ 0} =  capa_red;
    //   confPHOTred{ 1} =  nb_rdouts_ramp_red;
    //   confPHOTred{ 2} =  nb_rdouts_subramp_red;
    //   confPHOTred{ 3} =  comp_mode_red;
    //   confPHOTred{ 4} =  glitch_det_red;
    //   confPHOTred{ 5} =  ramp_fit_alg_red;
    //   confPHOTred{ 6  =  nb_raw_red;
    //   confPHOTred{ 7} =  bias_r_red;
    //   confPHOTred{ 8} =  bias_d_red;
    //   confPHOTblu{ 0} =  capa_blu;
    //   confPHOTblu{ 1} =  nb_rdouts_ramp_blu;
    //   confPHOTblu{ 2} =  nb_rdouts_subramp_blu;
    //   confPHOTblu{ 3} =  comp_mode_blu;
    //   confPHOTblu{ 4} =  glitch_det_blu;
    //   confPHOTblu{ 5} =  ramp_fit_alg_blu;
    //   confPHOTblu{ 6  =  nb_raw_blu;
    //   confPHOTblu{ 7} =  bias_r_blu;
    //   confPHOTblu{ 8} =  bias_d_blu;
    if(verbose) {
        debug_print("++PhotEstimator: OBCP: " + confOBCP);
    }
    // Pass messages to user (not in scan mode)
    if(pointCase != 33) {
        PacsMessageCenter("Observing time information",lineCnt,msgLine);
    }

    return {confPHOTblu,confPHOTred,confOBCP,{nb_nods,repeat_factor,nhold,0}};
}

// SpireBbCcuMonitorPeriodDefault
//
// $Id:$
//
// Building Block to set CCU monitoring period for cooler recycling
//
block SpireBbCcuMonitorPeriodDefault SPIRE 11777 {
}{
    SpireCcuMonitorPeriodDefault();
    sync();
}

// SpireEngBsmTuneChopPID
//
// $id$
//
// This observation allows tuning of the BSM Chop PID parameters. 
// Before the PID tuning the procedure also runs the Jiggle Map VM for 7-Point Jiggle Map using the new nominal settings for Chop FF gain and offset 
// 
// The instrument should be in REDY mode before execution of this observation
// Final Configuration: Instrument is still in REDY mode after execution of this observation
//
//
// 15/02/2010 SDS: First Version 1.0 
// 
// 04/03/2010 SDS: Version 1.1
//                             Updated to include the setting of CHOPINTLIMIT (Chop Integration Limit) and CHOPINTREF (Chop Integration Threshold)
// 16/03/2010 SDS: Version 1.2
//                             Changed input Ki limits for test on OD314. Both CHOPINTLIMIT and CHOPINTREF reset back to default value, i.e. 0xFFFF
//  25/03/2010 SDS: Version 1.3
//                             Removed CHOPINTLIMIT and CHOPINTREF from the scripts
//
//
//
obs SpireEngBsmTuneChopPID {
    int chopFfOffsetNom = 0x8f86; // Nominal CHOPFFOFFSET = 36742 determined from SpireEngBsmTuneFf (11th Feb 2010, OD274)
    int chopFfGainNom = 0x92e; // Nominal CHOPFFGAIN = 2350 determined from SpireEngBsmTuneFf (11th Feb 2010, OD274)
    int chopKpNom = 0x64; // 
    double chopKpLow = 0.0; // starting value of CHOPFFOFFSET as a fraction of the nominal value
    double chopKpHigh = 1.0; // end value of CHOPFFOFFSET as a fraction of the nominal value
    double chopKpStep = 1.0; // increment in value of CHOPFFOFFSET as a fraction of the nominal value
    int chopKiNom = 0x64; //// 100
    double chopKiLow = 1.0; // starting value of CHOPFFOFFSET as a fraction of the nominal value
    double chopKiHigh = 21.0; // end value of CHOPFFOFFSET as a fraction of the nominal value
    double chopKiStep = 5.0; // increment in value of CHOPFFOFFSET as a fraction of the nominal value
    int chopKdNom = 0x10b6; // central value 4278
    double chopKdLow = 0.333333; // starting value of CHOPFFOFFSET as a fraction of the nominal value
    double chopKdHigh = 1.666666; // end value of CHOPFFOFFSET as a fraction of the nominal value
    double chopKdStep = 0.333333; // increment in value of CHOPFFOFFSET as a fraction of the nominal value
    int jiggFfOffsetNom = 0x9946;
    int jiggFfGainNom = 0x17d8; // nominal value of JIGGFFGAIN
    int jiggKpNom = 1500;
    int jiggKiNom = 500;
    int jiggKdNom = 0x1b58; // nominal value of JIGGKD
    int cjCoupleNom = 0x8211; // nominal value of CHOPJIGGCOUPLE
    int cjdCoupleNom = 0x8000;
    int jcCoupleNom = 0x8000;
    int chopOn7 = 0xb5ac;
    int chopOff7 = 0x6b90;
    int jigglePosn7 = 0x9a19;
    int nChopCycles = 10;
    int chopPeriod = 500000;
    int dcuMode = 0;
    int dcuSample = 1;
    int dcuDelay = 34959;
    int bsmSample = 0x50;
    int sampFreq = 10;
    string bsmModel = "initial";
    string bsmVersion = "v00";
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0x0; // Spare parameter (currently not in use)
    int pInt2 = 0x0; // Spare parameter (currently not in use)
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // variables
    int chopKp = 0;
    int chopKi = 0;
    int chopKd = 0;
    //
    double kp = 0.0;
    double ki = 0.0;
    double kd = 0.0;
    int s = 0;
    int t = duration(SpireBbStartObs()) + duration(SpireBbSetNhkSampling("PHTSTBY","v00",debug)) + duration(SpireBbBsmOn("PHTSTBY",bsmModel,bsmVersion,debug)) + duration(SpireBbBsmChopInit("PHTSTBY",bsmModel,bsmVersion,debug)) + duration(SpireBbBsmJiggInit("PHTSTBY",bsmModel,bsmVersion,debug)) + duration(SpireBbBsmOff()) + duration(SpireBbSetDetSampling("REDY",true,"v00",false,debug)) + duration(SpireBbSetBsmSampling("REDY","v00",debug)) + duration(SpireBb_ResetBsm(debug)) + duration(SpireBbSetNhkSampling("REDY","v00",debug)) + duration(SpireBbEndObs());
    // Calculate duration for the JM07  
    t = t + duration(SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,chopKiNom,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug));
    t = t + duration(SpireBbJiggle("POF2",50,0,8,2,0,"v00","v00",false));
    //
    // Calculate duration for the PID tuning
    //
    kp = chopKpLow;
    ki = chopKiLow;
    kd = chopKdLow;
    while(kp <= chopKpHigh) {
        ki = chopKiLow;
        while(ki <= chopKiHigh) {
            kd = chopKdLow;
            while(kd <= chopKdHigh) {
                t = t + duration(SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKpNom,chopKiNom,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug));
                t = t + duration(SpireBb_Chop(71,0,10,chopOn7,jigglePosn7,chopOff7,jigglePosn7,nChopCycles,chopPeriod,dcuMode,dcuSample,dcuDelay,bsmSample,0,debug));
                t = t + duration(SpireBb_StopDcuMcuData());
                kd = kd + chopKdStep;
            }
            ki = ki + chopKiStep;
        }
        kp = kp + chopKpStep;
    }
    int[] ts = no_pointing(true,0,0,t);
}{
    int step = 0x0;
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            mois_comment("Procedure SpireEngBsmTuneChopPID: to tune the BSM Chop PID parameters");
            mois_comment("Procedure starts and ends in SPIRE REDY mode");
            mois_comment("The OBSID needs to be set manually in the first TC");
            mois_tmcheck("Verify that the OBSID has been set correctly");
            mois_comment("No other manual TM checks or intervention is necessary");
            mois_comment("Rest of commands in procedure can be executed automatically");
            SpireBbStartObs();
            // set nominal housekeeping rate to PHTSTBY
            SpireBbSetNhkSampling("PHTSTBY","v00",debug);
            // // 
            // switch on BMS in nominal configuration
            SpireBbBsmOn("PHTSTBY",bsmModel,bsmVersion,debug);
            SpireBbBsmChopInit("PHTSTBY",bsmModel,bsmVersion,debug);
            SpireBbBsmJiggInit("PHTSTBY",bsmModel,bsmVersion,debug);
            //
            // Start by doing a 7-Point JM with the nominal settings (All nominal settings except set ChopKp to 0)
            //
            SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,0,chopKiNom,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
            SpireBbJiggle("POF2",50,0,8,2,0,"v00","v00",false);
            //
            // Now do the PID tuning 
            //
            step = 0x0;
            kp = chopKpLow;
            ki = chopKiLow;
            kd = chopKdLow;
            chopKp = 0;
            chopKi = 0;
            chopKd = 0;
            s = 0;
            while(kp <= chopKpHigh) {
                chopKp = ifloor(kp * double(chopKpNom));
                step = step + 0x40;
                s = step;
                ki = chopKiLow;
                while(ki <= chopKiHigh) {
                    chopKi = ifloor(ki * double(chopKiNom));
                    kd = chopKdLow;
                    while(kd <= chopKdHigh) {
                        chopKd = ifloor(kd * double(chopKdNom));
                        s = s + 0x1;
                        SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKp,chopKi,chopKd,jiggFfOffsetNom,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
                        SpireBb_Chop(71,0,10,chopOn7,jigglePosn7,chopOff7,jigglePosn7,nChopCycles,chopPeriod,dcuMode,dcuSample,dcuDelay,bsmSample,s,debug);
                        SpireBb_StopDcuMcuData();
                        kd = kd + chopKdStep;
                    }
                    ki = ki + chopKiStep;
                }
                kp = kp + chopKpStep;
            }
            // switch off BSM
            SpireBbBsmOff();
            // Set the DCU detector sampling for REDY mode
            SpireBbSetDetSampling("REDY",true,"v00",false,debug);
            // Set the BSM sampling for REDY mode (i.e. Off)
            SpireBbSetBsmSampling("REDY","v00",debug);
            // Reset BSM frame parameters back to their default values
            SpireBb_ResetBsm(debug);
            // set nominal housekeeping rate to REDY mode
            SpireBbSetNhkSampling("REDY","v00",debug);
            // // 
            SpireBbEndObs();
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndPhaseUp.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of 
// SpirePhoto/Spectro_Cal_PhaseUp.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V1.0: Initial version adapted from
//                  SpireBb_EndBsmAngleCal (2009/05/05 V1.2),
//                  SpirePhoto_Cal_PhaseUp (2009/03/30 V1.4), and
//                  SpireSpectro_Cal_PhaseUp (2009/03/04 V0.5)
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndPhaseUp SPIRE 14049 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndPhaseUp reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set instrument back to Phot/Spec-STBY:
    //
    if(phot) {
        SpireProc_Set_PhotMode("PHTSTBY",isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    }
    // //
    // //
    // End observation:
    //
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndPhaseUp reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_CrossRasterPositions.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to calculate the pointing positions of a cross raster
//    
//
///////////////////////////////////////////////////////////////////////////
//
// S.D.Sidher:
// 2011/05/10 V0.1: Initial version adapted from the interlaced cross-raster section of
//                  SpireProc_CalcParam_RasterCross (2009/09/17 V0.4)
//
///////////////////////////////////////////////////////////////////////////
//
{double[],double[]} procedure SpireProc_CalcParam_CrossRasterPositions {
    int m = 9; // Number of points in raster along Y [odd number!]
    int n = 9; // Number of points in raster along Z [odd number!]
    double d1 = 4.0; // Angular stepsize along Y axis [arcsec] 
    double d2 = 4.0; // Angular stepsize along Z axis [arcsec]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Declare some variables:
    //
    // //
    // //
    double[] yarray = [0.0];
    double[] zarray = [0.0];
    double z = 0.0;
    double y = 0.0;
    int m2 = iround(double(m - 1) / 2.0);
    int n2 = iround(double(n - 1) / 2.0);
    int index = 0;
    // 
    // //
    // //
    // Calculate cross raster positions
    //
    for(int yc = 1 .. m) {
        z = 0.0;
        y = (double(m2) - double(yc - 1)) * d1;
        if(debug) {
            debug_print("yc/y: " + yc + "," + y);
        }
        zarray[index] = z;
        yarray[index] = y;
        index = index + 1;
    }
    //
    for(int zc = 1 .. n) {
        y = 0.0;
        z = (double(n2) - double(zc - 1)) * d2;
        if(debug) {
            debug_print("zc/z: " + zc + "," + z);
        }
        zarray[index] = z;
        yarray[index] = y;
        index = index + 1;
    }
    //
    if(debug) {
        debug_print("zarray = " + zarray);
        debug_print("yarray = " + yarray);
    }
    // 

    return {zarray,yarray};
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndScannedSmecBeamProfile.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of 
// Spectro_CalGCO_ScannedSmecBeamProfile.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/09/15 V0.1: Initial version adapted from
//                  SpireBb_EndFovMapCrossRaster (2009/07/12 V1.1) and
//                  SpireSpectro_CalGCO_ScannedSmecBeamProfile (2009/03/31 V0.4)
// 2009/10/28 V1.0: (SPR-SPIRE-2062) Add open SMEC loop.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndScannedSmecBeamProfile SPIRE 14076 {
    string resolution = "M" in ["L","M","H","C"]; // Resolution (low, medium, high,calibration)
    int hold_chop = 37632; // Chop hold position [Dec(Hex)]
    int hold_jigg = 39520; // Jiggle hod position [Dec(Hex)]
    int smecHomePosn = 3500; // SMEC home position
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    string version05 = "v00"; // Version in cal table SpireTable_Spectrometer
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndScannedSmecBeamProfile reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set obsstep back to 0:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP(0)");
    Spire_SET_OBS_STEP(0);
    // //
    // //
    // Move SMEC back to home position:
    //
    // Hardcoded calibration tables:
    string tabName = "SpireTable_Spectrometer.txt";
    // Retrieve required SMEC end from calibration tables: 
    int scanEnd = SpireProc_GetTableEntryInt(tabName,"ResChar",resolution,"ScanEnd",version05,debug);
    //
    SpireProc_SmecMove(smecHomePosn,scanEnd,debug);
    // //
    // //
    // Set instrument back to Spec-STBY:
    //
    SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    // //
    // //
    // Set number of DCU frames to continuous:
    //
    int dcuFrameNumber = 0;
    dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuFrameNumber","v00",debug);
    //
    SpireSendDrcuCmd(0x843d0000 + dcuFrameNumber,0);
    // //
    // //
    // Set number of MCU frames to continuous:
    //
    int mcuFrameNumber = 0;
    mcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","mcuFrameNumber","v00",debug);
    SpireSendDrcuCmd(0x91c30000 + mcuFrameNumber,0);
    delay(1);
    // //
    // //
    // Set SMEC framerate (== SMEC sampling rate) back to SPEC_STBY:
    // (Note, hardcoded version to go back to STBY)
    //
    int smecFrameRate = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","smecFrameRate","v00",debug);
    SpireProc_Set_SmecFramerate(smecFrameRate,debug);
    // //
    // //
    // Stop any remaining SMEC movement:
    //
    SpireProc_SmecHold(debug);
    // //
    // //
    //  Open SMEC control loop:
    //
    SpireSendDrcuCmd(0x90440006,0);
    delay(4);
    // //
    // //
    // Set scientific datarate back to zero:
    //
    data_rate(0.0);
    // //
    // //
    // End observation:
    //
    bool phot = false;
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndScannedSmecBeamProfile reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_Cal_MultiLevelNoise.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  CUS script for: 'Spec Multi-Level Noise'  
//
//  in *basic_fine_pointing* or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/06/09 V0.1: Initial version adapted from 
//                  SpirePhoto_Cal_MultiLevelNoise (2008/08/04 V0.3)
// 2008/11/11 V0.2: Allow 'no pointing' as input option; Adapt debug printing
// 2008/11/12 V0.3: Implement mode setting; Add isBright 
//                  Change 'no pointing' implementation
// 2009/02/19 V0.4: Add debug_print as input and pass it to low level scripts. 
//                  Use new SpireBb_EndObsAll and SpireBb_StartObsAll. 
//                  Read nominal bias frequency and bias divider from new
//                  SpireTable_SpecModeParams. Implemented message 
//                  if activating isBright setting. Implemented setting 
//                  of datarates. Remove cal table name from input and 
//                  hardcode. Use SpireBb_SpecSetMode to set to SPECSTBY 
//                  during SLEW and FINAL_HOLD. Unset isBright if set. 
//                  Read boresight from SpireTable_OpsParms. Fixed bug in 
//                  low level script SpireProc_Exec_SpecMultiLevelNoise,
//                  biasfreq and samplerate were set each time in loop. 
// 2009/03/04 V0.5: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Change isBright behaviour.
//                  Subtract isBright phase shift read from one calibration 
//                  file from the nominal phase value in the other calibration 
//                  file.
// 2009/05/06 V0.6: Add in move BSM/SMEC to hold/home at start. Add new 
//                  SpireBb_SmecHold to account for the fact that
//                  SpireBb_SmecMove2Home does not stop SMEC.
//                  Gather procedures at start and end in separate BB. 
// 
// Sunil Sidher 
// 2009/07/21 V0.7: Implemented isPcal flag to perform standard AOT style PCAL flashes after each bias setting
//
///////////////////////////////////////////////////////////////////////////
//
//  Script assumes that:
//
//  1)  Instrument is in SPECSTBY at beginning 
//  (i.e. bias amplitude, phase, frequency [mclkdiv,biasdiv] are nominal)
//
//  2) Phase is adjusted with changing bias amplitude and frequency.
//     
//  3) Levels/phases are read from CalTable: 
//     SpireTable_SpecMultiLevelNoiseLevels.txt 
//
//  4) Phase shift for isBright setting can be read from following
//     cal table: SpireTable_IsBrightPhaseShift.txt 
//
//  5) Bias frequency  and sampling rate  are user inputs
//
//  6) Boresight of array can be read from following cal table:
//     Spire_TableOpsParms.txt  
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_Cal_MultiLevelNoise {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    bool isBright = false; // Use settings for bright source (==tick) (Note: Only phases values will be changed!)
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    double biasfreq = 160.09 in [80.0,240.0]; // Bias frequency [Hz]
    double samplerate = 80.05 in [1.0,80.5]; // Sampling rate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    int ftime = 300; // Readout time at each bias level [s]
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_SpecMultiLevelNoiseLevels
    string version05 = "v00"; // Version in cal table SpireTable_OpsParms.txt
    string version06 = "v00"; // Version in cal table SpireTable_IsBrightPhaseShift
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
    /* */
}{
    // //
    // //
    // Check for is bright setting: 
    //
    if(isBright) {
        message("IsBright selected! SxW bias amplitude is unchanged but isBright phase-shift is subtracted.");
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = false;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_SpecMultiLevelNoiseLevels.txt";
    string tabName04 = "SpireTable_BsmNominalSettings.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    string tabName06 = "SpireTable_IsBrightPhaseShift.txt";
    string tabName09 = "SpireTable_SmecNominalSettings.txt";
    //
    // Currently hardcoded version and model parameter:
    //
    string version09 = "v00";
    // Version in cal table SpireTable_SmecNominalSettings
    string version04 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    // //
    // //
    // Setup mode: 
    //
    string obsModeQla = "ENG_CAL_OBS37";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "SEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version04;
    tabName = tabName04;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Read SMEC home position from calibration file:
    //
    tarCol = "Home";
    tabName = tabName09;
    selVal = version09;
    int smecHomePosn = ilookup(tabName,selVal,tarCol);
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // // 
    // // 
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartMultiLevelNoise(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug));
    // 
    // BBs carried out when the pointing is reached:
    if(pointing) {
        int tinithold = 0;
    } else {
        tinithold = tslewmin;
    }
    //
    // BB carried out during pointing:
    int tp = duration(SpireProc_Exec_SpecMultiLevelNoise(biasfreq,samplerate,tabName03,version03,isBright,isPcal,tabName06,version06,ftime,debug));
    //
    // BB carried out at the end:
    int tfinalhold = duration(SpireBb_EndMultiLevelNoise(phot,isBright,version01,version02,debug));
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,0,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartMultiLevelNoise(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug);
            // 
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            //
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation:
                //
                SpireBb_StartMultiLevelNoise(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug);
                //
            }
            //
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            // //
            // //
            // Execute Multi-Level Noise task:
            //
            SpireProc_Exec_SpecMultiLevelNoise(biasfreq,samplerate,tabName03,version03,isBright,isPcal,tabName06,version06,ftime,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            SpireBb_EndMultiLevelNoise(phot,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

// Missionphase  : EQM IMT
//
// Purpose	: Setup SPU for photometry data flow
//
// Author	: Bart Vandenbussche
//
// Arguments	: 
//
// Description	: Configures photometry compression /reduction mode and (optionally) starts 
//                     reduction/compression
//                  
// Dependencies : 
//
// Comments	:
//
// Version	: 1.4.4
//               
// History	: 1.0 18-Apr-2005 BV - first version after Thomas' tcl script\
//                                and Diego's SPEC_spu_setup
//                     1.1 19-apr-2005 DAC Use Array2grp_1 to generate TC operands
//                     1.2 09-aug-2006 TM update of WRT_DET_CST_PHOT parameters
//                     1.3 23-aug-2006 TM update for SPU HLSW UM, issue 12.8
//                     1.4 28-mar-2007 DAC Update for SPUv13.x
//                     1.4.1 29-mar-2007 Set scm = 1 (new compression scheme)
//                     1.4.2  4-apr-2007 SCM back to zero
//                     1.4.3 10-apr-2007 SCM back to 1
//                     1.4.4 11-apr-2007 SCM back to 0
//                     1.4.5 16-jun-2007 SCM back to 1
//                     1.4.6 23-feb-2008 TM: update for new SPU OBSW (shift 1, option to do bit rounding)
//                     1.4.7 24-mar-2009 DAC Rename spr1&spr2 per SPU UM 13.95a
//
int procedure PHOT_spu_setup {
    int comp_mode_blu = 0; //  Compression blue: default=0, double=1, half=2, lossless=4, transp=7, buffer=9
    int comp_mode_red = 0; //  Compression blue: default=0, double=1, half=2, lossless=4, transp=7, buffer=9
    int nraw_blu = 3; // Number of raw channels transmitted in the blue SPU
    int nraw_red = 3; // Number of raw channels transmitted in the red SPU
    bool startSPU = true; // Start SPU or not [true,false]
}{
    // Duration accumulator (accumulated time expressed in milliseconds)
    // (no longer used)
    int duration_msec = 0;
    // Stop the Long and Short SPUs
    Pacs_SPUS_STOP_REDUCT_COMPR();
    Pacs_SPUL_STOP_REDUCT_COMPR();
    // Set the SPU compression modes
    int[] aux = [comp_mode_blu,comp_mode_red];
    int check_sum = checksum("int",aux);
    // Issue the TC
    {int}[] comp_par = Array2grp_1(aux);
    Pacs_DMC_WRT_SPU_TRAN_MODE(comp_par,check_sum);
    // Setting of start index of raw channels for SPUS and SPUL
    string spus_obs_mode = "PHOT";
    string spul_obs_mode = "PHOT";
    int spus_startraw = 1;
    int spul_startraw = 1;
    Pacs_SPUS_RAW_CHAN_TRAN_MODE(spus_obs_mode,nraw_blu,spus_startraw);
    Pacs_SPUL_RAW_CHAN_TRAN_MODE(spul_obs_mode,nraw_red,spul_startraw);
    // Photo "Ottensamer" block ("S" SPU)
    // PPF: Pre-Processing Flag (0: no PP, 1: addition, 2: subtraction, 
    //                           3: multiplication, 4: division)
    int ppf = 0;
    // PPP: Pre-Processing Parameter
    int ppp = 0;
    // Threshold for glitch detection in photometry
    int tfp = 1000;
    // Threshold for chopper position deviation in photometry
    int tcp = 100;
    // Glitch detection for photometry (1: no glitch detection)
    int gdfp = 1;
    // Override samples to average
    int navg = 0;
    // resolution reduction parameter 2 (rnd: number of bits for optional rounding:
    // low gain: 0, high gain: 1-2, RO's recommendation: 2 in high gain)
    int rnd = 0;
    // resolution reduction parameter 3 (rnds: rounding strategy: best option 0)
    int rnds = 0;
    // Lossless scheme
    int scm = 1;
    // lossless compression algorithm (0,1,2,3,4)
    int lcal = 4;
    // PACS Codec Order (3,4)
    int pcod = 3;
    // dpre: delete pre (number of readouts to be discarded in group at beginning)
    int dpre = 0;
    // dpost: delete post (number of readouts to be discarded at the end of a group)
    int dpost = 0;
    // syncd: synchronisation delay: number of readouts delayed to start averaging 
    int syncd = 1;
    // Spare elements: 10 spare element; hardcoded as 0,0,... in operand
    // Create operand
    aux = [ppf,ppp,tfp,tcp,gdfp,navg,rnd,rnds,scm,lcal,pcod,dpre,dpost,syncd,0,0,0,0,0,0,0,0,0,0];
    check_sum = checksum("int",aux);
    // Convert to grp_1 syntax
    {int}[] spu_par = Array2grp_1(aux);
    // Issue TC
    Pacs_SPUS_WRT_DET_CST_PHOT(spu_par,check_sum);
    delay(1);
    // Photo "Ottensamer" block ("L" SPU)
    // PPF: Pre-Processing Flag (0: no PP, 1: addition, 2: subtraction, 
    //                           3: multiplication, 4: division)
    ppf = 0;
    // PPP: Pre-Processing Parameter
    ppp = 0;
    // Threshold for glitch detection in photometry
    tfp = 1000;
    // Threshold for chopper position deviation in photometry
    tcp = 100;
    // Glitch detection for photometry (1: no glitch detection)
    gdfp = 1;
    // Override samples to average
    navg = 0;
    // resolution reduction parameter 2 (rnd: number of bits for optional rounding:
    // low gain: 0, high gain: 1-2, RO's recommendation: 2 in high gain)
    rnd = 0;
    // resolution reduction parameter 3 (rnds: rounding strategy: best option 0)
    rnds = 0;
    // Lossless compression scheme
    scm = 1;
    // lossless compression algoithm (0,1,2,3,4)
    lcal = 4;
    // PACS Codec Order (3,4)
    pcod = 3;
    // dpre: delete pre (number of readouts to be discarded in group at beginning)
    dpre = 0;
    // dpost: delete post (number of readouts to be discarded at the end of a group)
    dpost = 0;
    // syncd: synchronisation delay: number of readouts delayed to start averaging 
    syncd = 1;
    // Spare elements: 10 spare element; hardcoded as 0,0,... in operand
    // Create operand
    aux = [ppf,ppp,tfp,tcp,gdfp,navg,rnd,rnds,scm,lcal,pcod,dpre,dpost,syncd,0,0,0,0,0,0,0,0,0,0];
    check_sum = checksum("int",aux);
    // Convert to grp_1 syntax
    spu_par = Array2grp_1(aux);
    // Issue TC
    Pacs_SPUL_WRT_DET_CST_PHOT(spu_par,check_sum);
    delay(1);
    // Send time stamps
    // DMC_WRT_TIME: Write the time sent by the DPU into the DMC buffer
    // (No action on this one?)
    // DPU sends the time to DEC/MEC
    Pacs_DPU_SEND_TIME();
    // DMC_SET_TIME: Set the time previously written by the write time command
    Pacs_DMC_SET_TIME();
    // Start reduction/compression if commanded to do so
    if(startSPU) {
        Pacs_SPUS_START_REDUCT_COMPR();
        Pacs_SPUL_START_REDUCT_COMPR();
    }
    // sync the bus
    sync();

    return duration_msec;
}

// SpireBbSdetOff
//
// $id$
//
// This building block switches off the photometer detectors
//
//  07/05/2009 KJK:
//          First Version
// 
block SpireBbSdetOff SPIRE 1551 {
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SdetOff started");
    SpireMsg(2,"          $Id:$");
    //
    int cmd = 0x0;
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // Set STEP to 0
    SpireSetObsStep(0x0);
    delay(1);
    //
    // Set MODE to SDET_OFF
    SpireSetObsMode("SDET_OFF");
    delay(1);
    //
    // Switch off  SSW VDD and VSS
    SpireSendDrcuCmd(0x84370001,0);
    for(int i = 0 .. 1) {
        SpireSendDrcuCmd(0x84350000 + 0x10000 * i,0);
        delay(1);
    }
    //
    // Switch off  SLW VDD and VSS
    SpireSendDrcuCmd(0x84370000,0);
    SpireSendDrcuCmd(0x84340000,0);
    delay(1);
    // 
    // Set DEMOD PHASE TO ZERO
    SpireSendDrcuCmd(0x843a0000,0);
    SpireSendDrcuCmd(0x843b0000,0);
    delay(1);
    //
    // Set BIAS TO ZERO
    SpireSendDrcuCmd(0x84310000,0);
    SpireSendDrcuCmd(0x84320000,0);
    delay(1);
    //
    // Switch OFF SLIAs 
    SpireSendDrcuCmd(0xa0870004,0);
    delay(4);
    //
    // completion
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB SdetOff   ended");
    SpireMsg(1,"  ..SDET Switch Off (" + (time() - t0) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_SmecScan.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to scan SMEC 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/25 V0.1: Initial version adapted from
//                  SpireBb_SmecScan (2008/11/03 V0.1)
//                  SpireBbFtsScan (KJK, 2009/01/01)
//
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1) SMEC scan parameters can be read from calibration table:
//     SpireTable_Spectrometer.txt 
//
//  2) SMEC is at scanStart at the start of the procedure.  
//
//  3) To have the SMEC also at the scanStart at the end of a scan
//     the input number of scans will be doubled, regardless of
//     using SAWTOOTH or TRIANGUAR scan mode. Note, this could means 
//     that depending on the mode one could get a different S/N (up
//     to a factor of ~2).  
//
//  4) Script assumes that DCU and MCU data collection is already  
//     switched on, it will be switched off outside where also 
//     the FIFOs will be flushed.   
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_SmecScan {
    string resolution = "L" in ["L","M","H","C"]; // Resolution (low, medium, high,calibration)
    int nscans = 1; // Number of SMEC scans (back+forth == 1)
    string version = "v00"; // Version in cal table SpireTable_Spectrometer
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Define some variables:
    //
    string tstr = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    //
    // Hardcoded calibration tables:
    //
    string tabName = "SpireTable_Spectrometer.txt";
    //
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"     " + tstr + ": SpireProc_Setup_SmecScan started");
    SpireMsg(4,"          $Id:$");
    // //
    // //
    // Retrieve required SMEC parameters from calibration tables: 
    // 
    int scanStart = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanStart",version,debug);
    int scanEnd = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanEnd",version,debug);
    int scanFSpeed = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanFSpeed",version,debug);
    int scanRSpeed = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanRSpeed",version,debug);
    // string waveform = SpireProc_GetTableEntryString("SpireTable_Spectrometer.txt","ResChar",resolution,"Waveform",version,debug);
    //
    if(debug) {
        debug_print("scanStart: " + scanStart);
        debug_print("scanEnd: " + scanEnd);
        debug_print("scanFSpeed: " + scanFSpeed);
        debug_print("scanRSpeed: " + scanRSpeed);
        // debug_print("waveform: " + waveform);
    }
    // //
    // //
    // Adjust nscans to obtain correct number of scans: 
    // (to always start and end at scanStart)
    // 
    nscans = nscans * 2;
    // //
    // //
    // Calculate the scan 'forward','reverse' travel times:
    //
    int scanFTime = iceil(double(scanEnd - scanStart) * (double(nscans) / 2.0) / double(scanFSpeed));
    int scanRTime = iceil(double(scanEnd - scanStart) * (double(nscans) / 2.0) / double(scanRSpeed));
    //
    if(debug) {
        debug_print("scanFTime: " + scanFTime);
        debug_print("scanRTime: " + scanRTime);
    }
    // //
    // //
    // Specify number of scans 
    //
    SpireSendDrcuCmd(0x90480000 + nscans,0);
    // //
    // //
    // Start scanning:
    //
    SpireSendDrcuCmd(0x90490002,0);
    delay(scanFTime + scanRTime + nscans * 1 + 2);
    // Note, allow 1 sec for turnaraound at end of each scan.
    // Note, add 2 sec at the very end as a saftey margin. 
    // Note, nscans is already included in scanFTime and scanRTime.
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    if(debug) {
        debug_print("tstr: " + tstr);
    }
    SpireMsg(4,"      " + tstr + ": SpireProc_Setup_SmecScan ended");
    //
}

// $Id: WriteEndBB.txt,v 1.2 2007/08/22 10:21:52 dcesarsk Exp $ 
// Purpose       : Set BBID to its default value to indicate the end
//                 of current BB execution (see FIRST-FSC-DOC-0200) 
//
// CUS script    : Diego A. Cesarsky (diego.cesarsky@mpe.mpg.de)
//
// Input arguments N/A
//
// Description   : BBID will be set to its LEG value
//
// Comments      : Needed for SCR-3507
//
// Version       : 0.1 21-aug-2007 First creation
// 		 : 1.0 derived from ...made it a block
//
block PacsBbWriteEndBB PACS 1101 {
}{
    int iBBID = 0x40000000;
    // Write BBID to DEC/MEC
    Pacs_DMC_SET_BBID(iBBID);
    // bus sync
    sync();
}

//CLName: JM64
//VMVersion: 2.8
//CLVersion: 1.3
//CLCVSId: $ID$
//TableId: 0x33
//TableLength: 0x80
//Date: 090722103224
//
// Created by Sunil Sidher on 22/07/2009  in response to SPIRE SCR-1670
// Normally the JM64 table is created as a BB (Number 3045) but here it is created as a procedure to prevent nesting of BBs
//
procedure SpireProc_Load_JmTable {
}{
    int t_min = 1;
    //set table command call for table id 0x33
    Spire_SET_TABLE(0x33,0x80);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x33,0x0,38,[{0xa192d122},{0xa1924608},{0xa922d27e},{0xa922486a},{0xb0b2d122},{0xb0b24608},{0xbfd2d122},{0xbfd24608},{0xb842d27e},{0xb842486a},{0xb0b2d3ce},{0xb0b24acf},{0xb842d513},{0xb8424d37},{0xb0b2d64d},{0xb0b24fa1},{0xb0b2d89c},{0xb0b2547c},{0xa922d9b1},{0xa92256ec},{0xa192d89c},{0xa192547c},{0xa922d77a},{0xa922520d},{0xa192d64d},{0xa1924fa1},{0xa922d513},{0xa9224d37},{0xa192d3ce},{0xa1924acf},{0x9a02d27e},{0x9a02486a},{0x9271d122},{0x92714608},{0x8ae1d27e},{0x8ae1486a},{0x9271d3ce},{0x92714acf}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x33,0x26,38,[{0x9a02d513},{0x9a024d37},{0x9271d64d},{0x92714fa1},{0x9a02d77a},{0x9a02520d},{0x9a02d9b1},{0x9a0256ec},{0x9271d89c},{0x9271547c},{0x8ae1d9b1},{0x8ae156ec},{0x8ae1d77a},{0x8ae1520d},{0x8351d64d},{0x83514fa1},{0x8ae1d513},{0x8ae14d37},{0x8351d3ce},{0x83514acf},{0x7bc1d27e},{0x7bc1486a},{0x8351d122},{0x83514608},{0x8ae1cfbb},{0x8ae143a9},{0xa922cfbb},{0xa92243a9},{0xb0b2ce49},{0xb0b2414d},{0xb842cfbb},{0xb84243a9},{0xbfd2ce49},{0xbfd2414d},{0xb842cccd},{0xb8423ef5},{0xb0b2cb46},{0xb0b23ca1}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x33,0x4c,38,[{0xb842c9b5},{0xb8423a50},{0xb0b2c81a},{0xb0b23804},{0xb0b2c4c7},{0xb0b23378},{0xa922c675},{0xa92235bc},{0xa192c4c7},{0xa1923378},{0xa192c81a},{0xa1923804},{0xa922c9b5},{0xa9223a50},{0xa192cb46},{0xa1923ca1},{0xa922cccd},{0xa9223ef5},{0xa192ce49},{0xa192414d},{0x9271ce49},{0x9271414d},{0x8ae1cccd},{0x8ae13ef5},{0x8351ce49},{0x8351414d},{0x7bc1cfbb},{0x7bc143a9},{0x7bc1cccd},{0x7bc13ef5},{0x8351cb46},{0x83513ca1},{0x8ae1c9b5},{0x8ae13a50},{0x8351c81a},{0x83513804},{0x8ae1c675},{0x8ae135bc}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x33,0x72,14,[{0x9271c4c7},{0x92713378},{0x9a02c675},{0x9a0235bc},{0x9271c81a},{0x92713804},{0x9a02c9b5},{0x9a023a50},{0x9271cb46},{0x92713ca1},{0x9a02cccd},{0x9a023ef5},{0x9a02cfbb},{0x9a0243a9}]);
    delay(t_min);
}

// SpireBbSOF1Config
//
// $Id:$
//
// Building Block to configure the instrument for SOF1 operations
//
// The complete instrument setup operation is divided into two parts:
//   Configuration: actions that can be executed during the slew to the start
//          position of the S/C pointing mode.
//   Initialisation: actions that must be carried out at the S/C intial pointing
//          position before any observational operations are executed.   
//
// This building Block implements the first part of the setup:
//   It assumes the instrument is in the SPECSTBY mode (with SMEC at Home position) 
//   It resete the  SMEC encoder , in case it has lost steps
//   It moves the  SMEC to scan start position in preparation for scanning
//   It sets the detectors to the required configuration for scanning
//
// 28 January 2009 V1.1 KJK
//   Remove Mode setting - now carried out in SpireBb_StartObsAll
//   Remove DRCU Counter resetting - now carried out in SpireBb_StartObsAll
//   Use SpireProc_SmecMove to move into position - assuming SMEC is at Home position
// 22/09/2009 V1.2 KJK:
//   SPR Spire-1978: Use bright source settings if necessary
// 21/10/2009 V1.3 KJK:
//   SPR Spire-2062: remove resetting of SMEC encoder and moving to scan start
//
block SpireBbSOF1Config SPIRE 8368 {
    string obsMode = "Scan";
    string res = "H";
    bool isBright = false in [true,false];
    string comVersion = "v00";
    string smodeVersion = "v00";
    string smecVersion = "v00";
    string specVersion = "v00";
    bool debug = false;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SOF1 Configuration started");
    SpireMsg(2,"          $Id:$");
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // ..... configuration .....
    //
    // set biases and phases - if needed
    //
    if(isBright) {
        SpireProc_Set_SpecBright("Scan",smodeVersion,debug);
    } else {
        if(smodeVersion != "v00") {
            SpireProc_Set_SpecMode("Scan",isBright,smodeVersion,comVersion,debug);
        } else {
            if(comVersion != "v00") {
                SpireProc_Set_SpecMode("Scan",isBright,smodeVersion,comVersion,debug);
            }
        }
    }
    //
    // ..... completion .....
    //
    sync();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SOF1 Configuration ended");
    SpireMsg(1,"  ..SOF1 Configuration (" + (time() - t) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartPtcPwr.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of SpirePhoto_Cal_PtcPwr.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/06 V0.1: Initial version adapted from
//                  SpireBb_StartBsmAngleCal (2009/05/05 V0.1) and
//                  SpirePhoto_Cal_PtcPwr (2009/03/30 V0.1).
//                  BB includes now to move BSM to hold.  
//  
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartPtcPwr SPIRE 14058 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    string obsModeQla = "ENG_CAL_OBS13";
    string obsMode = "PEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_Phot/SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartPtcPwr configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    if(phot) {
        SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    }
    //delay(timeSlewCal);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartPtcPwr configuration ended");
    SpireMsg(1,"  ..StartPtcPwr took " + (time() - t) + " seconds)");
    //
}

// SpireBbPOF2Config
//
// $Id:$
//
// Building Block to configure the instrument for POF2 (7-point jiggle) operation
//
// The complete instrument setup operation is divided into two parts:
//   Configuration: actions that can be executed during the slew to the start
//          position of the S/C pointing mode.
//   Initialisation: actions that must be carried out at the S/C intial pointing
//          position before any observational operations are executed.   
//
// This building Block implements the first part of the setup
//
//  09/02/09: KJK
//      -  Removed setting of Mode and resetting DRCU counters -
//          These are now implemented in SpireBb_StartObsAll
//      - Add possible bright-source setting  
//  14/02/09: MP
//      -  Replace calls to SpireProc_Set_PhotPhase/Bias with 
//          call to SpireProc_Set_PhotBright
//  04/03/09: MP
//      - Fixed bug in call to SpireProc_Set_PhotBright
//  02/07/09: KJK
//      - renamed version to photVersion
//
//  04/08/2009 SDS:
//         SPR-1752 - Updated to allow the loading of a new JM07 table (uses the boolean pBool1)
//  10/08/2009 KJK:
//         SPR-1709:  Added new input parameter, comVersion
//                           updated to execute SpireProc_Set_PhotMode if photversion is not "V00"
//  14/08/2009 KJK:
//         Spire_1759: Removed loading of new jiggle table as it is now loaded in a new BB
//
block SpireBbPOF2Config SPIRE 8224 {
    string obsMode = "POF2";
    bool isBright = false in [true,false];
    string photVersion = "v00";
    string comVersion = "v00";
    bool debug = false in [true,false];
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF2 Configuration started");
    SpireMsg(2,"          $Id:$");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set biases and phases - if needed
    //
    if(isBright) {
        SpireProc_Set_PhotBright(obsMode,photVersion,debug);
    } else {
        if(photVersion != "v00") {
            SpireProc_Set_PhotMode(obsMode,isBright,photVersion,comVersion,debug);
        }
    }
    //
    // ..... completion .....
    //
    delay(2);
    // to allow hsk to stabilise
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF2 Configuration ended");
    SpireMsg(1,"  ..POF2 Configuration (" + (time() - t) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_CalGCO_TransRespoAndDynBeamProf.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Phot Transient Response and Dynamic Beam Profile'   
//
//              in * line_scan_with_off_pointing * mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/03 V1.0: Initial version renamed from (2008/11/12 V0.2)
//                  SpirePhoto_CalGCO_PhotTransRespoAndDynBeamProf.
//                  Add debug_print as input and pass it to some low 
//                  level scripts. Replace call to SpireProc_Set_ObsStep 
//                  with call to SpireBb_SetObsStep. Introduce 
//                  SpireBb_WaitAtGcp at GCP and use SpireBbScanLine during 
//                  the line scanning to collect data within defined BBIDs. 
//                  Use new SpireBb_EndObsAll and SpireBb_StartObsAll. 
//                  Read nominal bias frequency and bias divider from new
//                  SpireTable_DetectorSettings.txt. Implemented setting 
//                  of datarates. Implemented isBright setting.
// 2009/02/18 V1.1: Update to new calibration table structure for Mode setting. 
//                  New setting of datarates. Use SpireBb_PhotSetMode to set 
//                  to PHOTSTBY during SLEW and FINAL_HOLD. Change call to 
//                  SpireBb_StartDcuData.
// 2009/03/04 V1.2: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Set gcp_time to 
//                  20 (desired value for SOVT2).
// 2009/05/07 V1.3: Add in move BSM to hold at start. Gather procedures at 
//                  start and end in separate BB. 
// 2009/06/05 V1.4: Change default gcp_time to 20 (SPR-1478). SPR-1477: 
//                  Hardcode STBY 'v00' in EndBB.
// 2009/10/28 V1.5: (SCR-SPIRE-2118) Allow SSO. Hardcode gcp_peride for SSOs. 
// 
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in PHOTSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for all three arrays and could be taken from following cal table: 
//    SpireTable_PhotModeParams.txt
//
//  3) That currently the gyro reconstruction is only available for 
//     non-SSO targets.  
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhoto_CalGCO_TransRespoAndDynBeamProf {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target [deg]
    double dec = 0.0 in [-90.0,90.0]; // DEC of target [deg]
    int naifid = 0; // Put '0' to use RA and DEC, otherwise put correct 'NAFID'
    /* */
    bool isBright = false; // Use settings for bright source (==tick)
    bool refSelected = true; // ExpHSpot (refSelected) parameter
    bool refByOffset = true; // ExpHSpot (refByOffset) parameter   
    double raoff = 0.0 in [0.0,360.0]; // RA of GCP position, or relative offset [deg]
    double decoff = 0.0 in [-90.0,90.0]; // DEC of GCP position, or relative offset [deg]
    string ib = "S14_0"; // Central aperture (defined in SIAM) of raster
    double d1 = 500.0 in [20.0,7200.0]; // Length of the scan line along scan axis [arcsec] 
    double rate = 30.0 in [0.1,60.0]; // Scan rate of a line scan [arcsec/s]
    string scan_dir = "Y" in ["Y","Z"]; // Scan direction 
    int nrepeat = 1 in [1,1200]; // Number of forth+back scans (repetitions)
    int gcp_time = 20; // Time spend at GCP (gyro calibration position) [s]
    int gcp_period = 600; // Maximum time between successiv GCP visits (Note, set to 64800 for SSOs!)[s]
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // //
    // //
    // Current restrictions:
    //
    if(naifid != 0) {
        message("Note, currently no SSO objects are allowed if gyro reconstruction is needed. Using SSO tracking the visists to the OFF position are minimised by setting gcp_period to 18h.");
        gcp_period = 64800;
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = true;
    bool fts = !phot;
    //
    // Start timing of script:
    int start = time();
    int linestart = time();
    //
    // Line counter (start at 1): 
    int linecount = 1;
    //
    // GCP counter (start at 1):
    int gcpcounter = 1;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    //
    // Currently hardcoded version and model parameter:
    //
    string version03 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS06";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "PEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Increase scan length to allow time to mark start/end of the scan:
    //
    int tStart = 2;
    int tEnd = 2;
    // Note: the two 2 seconds are justified in SpireBbScanLine.txt
    d1 = d1 + double(tStart + tEnd) * rate;
    //
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version03;
    tabName = tabName03;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartTransRespoAndDynBeamProf(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,debug));
    // 
    // BBs carried out when the pointing is reached:
    int tinithold = duration(SpireBb_PhotOffsetAuto(debug)) + duration(SpireBb_StartDcuData());
    //
    // BB carried out during pointing:
    //int tp = 0;
    //
    // BB carried at off position:
    int top = duration(SpireBb_WaitAtGcp(gcp_time,debug));
    // == Time spent at the OFF position.
    //
    // BB carried out at the end:
    int tfinalhold = duration(SpireBb_EndTransRespoAndDynBeamProf(phot,isBright,version01,version02,debug)) + duration(SpireBb_StopDcuData());
    // 
    // Debug_printing:
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        //debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // Fixed parameters for pointing mode:
    //  
    bool fixed = false;
    // Pattern orientation (true==sky; false==array)
    double yoff = 0.0;
    // Offset of pattern in the direction of the +Y
    double zoff = 0.0;
    // Offset of pattern in the direction of the +Z
    double d2 = 0.0;
    // Spacing of adjacent scan lines [arcsec]
    int n = 2;
    // Number of raster lines or scan lines.
    int k = 2;
    // Number of scan lines before before going to the OFF position
    int thold = 0;
    // The duration of the hold when nhold>0.
    int nhold = 0;
    // Number of nods or raster points or scan lines before
    //              // performing a hold.
    int nload = 0;
    // The number of slews (e.g. nods) before performing 
    //             // a load operation
    int tloadmin = 0;
    // The minimum duration of a load operation.
    // //
    // //
    // Select scan direction: 
    //
    double patt = 90.0;
    // Rotation angle of the pattern
    //
    if(scan_dir == "Y") {
        patt = 90.0;
    }
    if(scan_dir == "Z") {
        patt = 0.0;
    }
    // //
    // //
    // Set pointing mode:
    //
    //int[] ts = line_scan_with_off_pointing(true,tslewmin,tih,tfh,ib,naifid,
    // ra,dec,fixed,patt,yoff,zoff,n,d1,d2,rate,k,top,raoff,decoff,nrepeat,
    // thold,nhold,tloadmin,nload);
    //
    int[] ts = line_scan_with_off_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,fixed,patt,yoff,zoff,n,d1,d2,rate,k,top,raoff,decoff,nrepeat,thold,nhold,tloadmin,nload);
    //
    // //
    // //
    // Fill in timings of actual pointing mode:
    int tacc = ts[2];
    // acceleration time
    int tdec = ts[3];
    // deceleration time
    int tl = ts[4];
    // time for actual scan of single line in map area 
    int tll = ts[5];
    // turnaround time bewteen 2 lines 
    int tsop = ts[6];
    // slew time from/to OFF position 
    // Note: 'tsop' includes acceleration/deceleration time
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
        debug_print("Time for actual scan of single line in requested area: " + tl);
    }
    // //
    // //
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //     
            SpireBb_StartTransRespoAndDynBeamProf(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD (spacecraft is idling at source)
            //
            //delay(tinithold);
            // //
            // //
            // Set offsets:
            //
            SpireBb_PhotOffsetAuto(debug);
            // //
            // //
            // Start data generation before scan: 
            //
            SpireBb_StartDcuData();
            //
        }
        if(state[0] == 4) {
            // STATE = OFF position
            // //
            // //
            // Show time elapsed between visits to GCP:
            //
            int t = time() - start;
            if(gcpcounter > 1) {
                message("Time elapsed since last visit to GCP: " + t);
                if(t > gcp_period) {
                    error("Time between visits to GCP > gcp_period! Pray to the Lord or modify the script!");
                }
                if(debug) {
                    debug_print("Time elapsed since last visit to GCP: " + t);
                }
            }
            gcpcounter = gcpcounter + 1;
            //
            // Reset timer:           
            start = time();
            // //
            // //
            // Wait at GCP:
            //
            SpireBb_WaitAtGcp(gcp_time,debug);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activities )
            // //
            // //
            // Stop data generation after scan: 
            //
            SpireBb_StopDcuData();
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            //
            SpireBb_EndTransRespoAndDynBeamProf(phot,isBright,version01,version02,debug);
            //
        }
        if(state[0] == 6) {
            //delay(thold);
        }
        if(state[0] == 8) {
            // STATE =  ( line )
            //
            // //
            // //
            // Start timing:
            //
            int tscan = time();
            // //
            // //
            // Debug printing
            //
            if(debug) {
                debug_print("state[0]: " + state[0]);
                debug_print("state[1]: " + state[1]);
                debug_print("state[2]: " + state[2]);
                debug_print("linecount: " + linecount);
            }
            // 
            if(linecount == 1) {
                linestart = time();
            } else {
                int tline = time() - linestart;
                if(debug) {
                    debug_print("Time elapsed since first line: " + tline);
                }
            }
            // //
            // //
            // Wait while scan is performed:
            //
            SpireBbScanLine(tl,linecount);
            linecount = linecount + 1;
            //
        }
        if(state[0] == 9) {
            //delay(tloadmin);
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

// SpireEngPatchTables
//
// $id$
//
// This observations patches the on-board tables 
// 
// The instrument should normally be in REDY mode before execution
// of this observation.
//
// 
// 03/08/2010 SDS: First Version 1.0
//                 See SPIRE-SCRs 2572, 2750, 2764 and 2766
//
obs SpireEngPatchTables {
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use)
    int pInt2 = 0; // Spare parameter (currently not in use)
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int t = duration(SpireBbStartObs()) + duration(SpireBbEndObs());
    t = t + duration(SpireBb_StopMonitoring()) + duration(SpireBb_PatchTables()) + duration(SpireBb_StartMonitoring());
    // ***********************************************
    int[] ts = no_pointing(true,0,0,t);
}{
    SpireMsg(0,"Observation Start");
    SpireMsg(3,"       $Id:$");
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            mois_comment("Procedure SpireEngPatchTables: to patch the SPIRE on-board tables");
            mois_comment("Procedure starts and ends in SPIRE REDY mode");
            mois_comment("Procedure requires Real Time Science");
            mois_comment("The OBSID needs to be set manually in the first TC");
            mois_tmcheck("Verify that the OBSID has been set correctly");
            mois_comment("No other manual TM checks or intervention is necessary");
            mois_comment("Procedure will be monitored remotely by the SPIRE ICC");
            SpireBbStartObs();
            mois_comment("Stop the on-board monitoring");
            SpireBb_StopMonitoring();
            mois_comment("Patch the necessary tables");
            SpireBb_PatchTables();
            mois_comment("Restart the on-board monitoring");
            SpireBb_StartMonitoring();
            SpireBbEndObs();
        }
    }
    SpireMsg(0,"Observation Completed  (" + time() + " seconds)");
    SpireMsg(0,"Note: Total time (s) = Observation Completed time - slew time + Observatory Overheads");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndFovMapCrossRaster.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of 
// SpirePhoto/Spectro_CalGCO_FovMapCrossRaster.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V0.1: Initial version adapted from
//                  SpireBb_EndBsmPcalFlash (2009/05/05 V0.1),
//                  SpirePhoto_CalGCO_FovMapCrossRaster (2009/03/17 V1.0), and
//                  SpireSpectro_CalGCO_FovMapCrossRaster (2008/09/17 V0.1).
// 2009/05/07 V0.2: Set dcuFrameNumber and mcuFrameNumber back to continuous
//                  to unset setting passed to VM. 
// 2009/06/05 V1.0: Replace Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd 
//                  as requested in SPR-1482.
// 2009/07/12 V1.1: Set SMEC framerate back to nominal (SPR-SPIRE-1551).
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndFovMapCrossRaster SPIRE 14045 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    int hold_chop = 37632; // Chop hold position [Dec(Hex)]
    int hold_jigg = 39520; // Jiggle hod position [Dec(Hex)]
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndFovMapCrossRaster reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set obsstep back to 0:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP(0)");
    Spire_SET_OBS_STEP(0);
    // //
    // //
    // Set instrument back to Phot/Spec-STBY:
    //
    if(phot) {
        SpireProc_Set_PhotMode("PHTSTBY",isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Set number of DCU frames to continuous:
    //
    int dcuFrameNumber = 0;
    if(phot) {
        dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","PHTSTBY","dcuFrameNumber","v00",debug);
    } else {
        dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuFrameNumber","v00",debug);
    }
    //
    SpireSendDrcuCmd(0x843d0000 + dcuFrameNumber,0);
    // //
    // //
    // Set number of MCU frames to continuous:
    //
    int mcuFrameNumber = 0;
    if(phot) {
        mcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","PHTSTBY","mcuFrameNumber","v00",debug);
    } else {
        mcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","mcuFrameNumber","v00",debug);
    }
    SpireSendDrcuCmd(0x91c30000 + mcuFrameNumber,0);
    delay(1);
    // //
    // //
    // Set SMEC framerate (== SMEC sampling rate) back to SPEC_STBY:
    // (Note, hardcoded version to go back to STBY)
    //
    if(!phot) {
        int smecFrameRate = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","smecFrameRate","v00",debug);
        SpireProc_Set_SmecFramerate(smecFrameRate,debug);
    }
    // //
    // //
    // End observation:
    //
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndFovMapCrossRaster reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

// CVS file      : CONF_phot_fltw.txt
// Missionphase  : FMILT_3 & Later
//
// Purpose       : CONFigure the PHOT filter wheel servo loop
//                  
// Description   : 
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      :
//
// Version       : 1.0
// History       : 0.1  4-jul-2006 DAC
//                    1.0 11-Jun-2007 PR New scheme due to new format of configuration command
//                                               (DMC UM v.4.3)
//               :
procedure CONF_phot_fltw {
}{
    string calUname = "CONFFWPHOT";
    // FWPHOT CALIBRATION TABLE
    string calUrow = "FMILT";
    // INSTRUMENT VERSION
    int rate = ilookup(calUname,calUrow,"Rate");
    int current = ilookup(calUname,calUrow,"Drive_current");
    int threshold_A = ilookup(calUname,calUrow,"Threshold_A");
    int threshold_B = ilookup(calUname,calUrow,"Threshold_B");
    int status_A = ilookup(calUname,calUrow,"Status_A");
    int status_B = ilookup(calUname,calUrow,"Status_B");
    {int}[] parlist = [{rate},{current},{threshold_A},{threshold_B},{status_A},{status_B}];
    int[] aux = [rate,current,threshold_A,threshold_B,status_A,status_B];
    int check_sum = checksum("int",aux);
    Pacs_DMC_WRT_FWPHOT_CONF_PAR(parlist,check_sum);
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
//
// SpireProc_Set_PhotBright.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to configure instrument for bright source observation
//  while being in any of the photometer modes. 
//
///////////////////////////////////////////////////////////////////////////
//
// KJK:
// 2009/02/07 V0.1: Initial version renamed from 
//                  SpireProc_Set_BrightSettings (MP, 2009/01/27 V0.1)
//                  Added "_b" to obs mode to select bright settings.
// 2009/02/14 V0.2: (MP) Replaced calls to bias and phase BB with
//                  call to bias and phase procedure. Added some cosmetics 
//                  to script. Replace call to SpireTable_DetectorSettings
//                  with call to new SpireTable_PhotModeParams.
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_PhotBright {
    string obsMode = "POF2"; // Mode in cal file with detector settings
    string version = "v00"; // Version in cal file with detector settings
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Declare some variable:
    //
    string tarCol = "";
    string tstr = "";
    //
    // Hardcoded name of calibration table: 
    string tabName = "SpireTable_PhotModeParams.txt";
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"     " + tstr + ":  SpireProc_Set_PhotBright started");
    SpireMsg(4,"          $Id:$");
    // //
    // //
    // Read settings (currently phase and bias) from calibration table:
    //
    // Name of column for selecting:
    string selCol = "mode";
    //
    // Value of 'string' selector:
    string selVal = obsMode + "_b";
    //
    tarCol = "pswBias";
    int psw_bias = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "pmwBias";
    int pmw_bias = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "plwBias";
    int plw_bias = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "ptcBias";
    int ptc_bias = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "pswPhase";
    int psw_phase = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "pmwPhase";
    int pmw_phase = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "plwPhase";
    int plw_phase = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "ptcPhase";
    int ptc_phase = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Set the selected bias values:
    //
    SpireProc_Set_PhotBias(psw_bias,pmw_bias,plw_bias,ptc_bias,debug);
    // //
    // //
    // Set the selected phase values:
    //
    SpireProc_Set_PhotPhase(psw_phase,pmw_phase,plw_phase,ptc_phase,debug);
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"      " + tstr + ": SpireProc_Set_PhotBright ended");
}

// Missionphase  : 
//
// Purpose       : Perform Setup Photometry according to TM's input:
//                 Scripts:
//      a) tm_phot_dpu_dmc_setup.tcl  <phot_hk 1, syn_source 4>
//      b) tm_phot_mec_setup.tcl      <phot_filter_wheel_id 1,
//                                     chop_def_pos 0, temp_bb1 800000
//                                     temp_bb2 920000 >
//      c) tm_phot_sequencer_setup.tcl
//      d) tm_phot_polar_bestM7_setup.tcl
//         (Setting of optimal polarisations in the cold 0.3K)
//      e) tm_phot_change_datamode.tcl  <"Bolo & HK">
//      f) tm_phot_change_seq_mode.tcl  <"Sbolo-Sref">
//      g) PACS_Phot_Gain_high.tcl
//         (gain setting  <"high">)
//      h) tm_phot_spu_setup.tcl   <comp_mode_blue 0, comp_mode_red 0
//                                  spus_nraw 3, spul_nraw 3>
//
//
// CUS author    : DAC
// Script file   : PHOT_setup.txt 
//
// Input arguments
// type    name         description
//
// Return values
// Type    Name      Default      Description
//
// Description   : 
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : 
// 
// Version       : 3.0
// History:
// 0.1 DAC 22-apr-2005
// 0.2 DAC 25-apr-2005 New default: Do not start SPU
// 1.0 TM  12-apr-2006, update for FM with new settings
// 1.1 TM  08-aug-2006, new procedure to read bias tables in [V]
// 1.2 TM  10-oct-2006, autonomy function added
// 2.0 DAC 17-oct-2006 Use BIAS tables in volts, eliminate useless
//                     timing calculation, call with BIAS table name and
//                     initial filter position, initial CS temperatures
// 2.1 TM 08-Nov-2006 add the switch on of the groups
// 2.2 TM 08-Nov-2006 autonomy function 17 added
// 2.3 TM 08-Nov-2006 autonomy functions modified again (moved to PHOT_switchon_groups)
// 2.4 TM 10-Nov-2006 default bias table changed, low gain
// 2.5 13-nov-2006 Use RAW bias tables
// 2.6 15-nov-2006 Using volts again
// 2.7  8-dec-2006 Add temperature autonomy function
// 2.8  5-mar-2007 update for chopper, CSs
// 2.9  4-apr-2007 TM: number of raw channels set to zero
// 3.0  9-apr-2007 TM & KO: update of AFs
// 3.1  9-apr-2007 TM & KO: AF 15 taken out again
// 3.2 21-aug-2007 SRC-3507 Indicate end of BB
//                 Sync bus at end of script
// 3.3 06-oct-2008 TM & VDP: PHOT_change_seq_mode set to Sref_only 
// 3.4 12-nov-2008 KO: gotoDirect option added
// 4.0 28-jul-2009 VD & TM: SCR PACS-1805
//
int[] block PHOT_setup PACS 200 {
    string calUfile = "BOLObias_preILT_standard_low"; //BIAS table name
    string fltPOS = "POS A" in ["POS A","POS B"]; // Filter wheel position
    double set_CS1 = 48.0; // CS1 settings (ohms)
    double set_CS2 = 58.0; // CS2 settings (ohms)
    bool gotoDirect = true in [true,false]; // DDCS setting to Direct setting
}{
    // Register BBID with environment
    WriteBBID($BBID);
    // Define variables to communicate various durations to HSPOT.
    int time_start = time();
    PHOT_dpu_dmc_setup("BOTH Array",4);
    // Place filter wheel
    PHOT_dmc_setup(fltPOS,0,set_CS1,set_CS2);
    // switch on groups and enable AF 17
    PHOT_switchon_groups();
    // Set polarisations
    PHOT_set_bias_volt(calUfile,1);
    PHOT_set_bias_volt(calUfile,2);
    PHOT_set_bias_volt(calUfile,3);
    PHOT_set_bias_volt(calUfile,4);
    PHOT_set_bias_volt(calUfile,5);
    PHOT_set_bias_volt(calUfile,6);
    // Set sequencer
    PHOT_seq_setup();
    // Set data mode
    PHOT_change_data_mode("Bolo_HK");
    //  PHOT_change_seq_mode("Sb_Sref"); New setup post-SOVT1
    // Now we set the direct mode post-SOVT1
    int operand = 0;
    if(gotoDirect) {
        //*********************************************************
        // Sequence mode : blocking on VDEC_X for the direct mode
        //*********************************************************
        //
        // Set all groups bol bias 09 (CKRLH) to 0.0 volt (0)
        Pacs_DMC_SEND_COMMAND_BOLC(0x90000);
        // Set all groups bol bias 12 (VDECX-L) to 2.0 volt (2298)
        Pacs_DMC_SEND_COMMAND_BOLC(0xc08fa);
        // Set seq mode Sref_only (hexadecimal value to avoid the commanding confusion)
        //Pacs_BOLC_SET_SEQ_MODE("Sref_only");
        //# P 09 01 00 01
        operand = 0x9010001;
        Pacs_DMC_SEND_COMMAND_BOLC(operand);
        delay(1);
    } else {
        // Set seq mode Sb_Sref (hexadecimal value to avoid the commanding confusion)
        //Pacs_BOLC_SET_SEQ_MODE("Sb_Sref");
        //# P 09 01 00 00
        operand = 0x9010000;
        Pacs_DMC_SEND_COMMAND_BOLC(operand);
        delay(1);
    }
    // Set gain LOW
    PHOT_set_gain("LOW");
    // Set SPU but do not start it yet
    PHOT_spu_setup(0,0,0,0,false);
    // Time spent
    int duree_TCs = time() - time_start;
    int duree_num = duree_TCs;
    // Return the array of times
    int[] time_array = [duree_num,0,0,0,0];
    //
    // enable AF 12 (to check for the protection biases)
    Pacs_DPU_SET_FUNCT("EVENT_BOL_BIAS","ENABLE");
    // enable AF 14 to check for TEMP_EV < 0.3 K
    Pacs_DPU_SET_FUNCT("EVENT_BOL_T_FPU","ENABLE");
    // enable AF 15 (to check for the VSS currents of groups and BUs)
    Pacs_DPU_SET_FUNCT("EVENT_BOL_I_RO","ENABLE");
    // Mark end of BB
    WriteEndBB();
    // Sync bus
    sync();

    return time_array;
}

// SpireBb_CalSdetOn
//
// $id$
//
// This building block switches on the spectrometer detectors for calibration observations
// 
// The instrument should be in the REDY mode before execution of this building block
//
//
// 07/01/2010 S.D.Sidher V0.1:
//         Adapted from SpireBbSdetOn (does not set the mode)
block SpireBb_CalSdetOn SPIRE 3415 {
    int jfet_heater_V = 0; // By default don't switch on jfet heater 
    string detVersion = "v00";
    string vssVersion = "v00";
    bool debug = false;
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB CalSdetOn started");
    SpireMsg(2,"          $Id$");
    //
    int cmd = 0x0;
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP to 0
    SpireSetObsStep(0x0);
    //
    // Retrieve detector settings
    //
    int dcuDataMode = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuDataMode",detVersion,debug);
    int biasmode = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","biasMode",detVersion,debug);
    int mclkdiv = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","mclkDiv",detVersion,debug);
    int biasdiv = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","biasDiv",detVersion,debug);
    //
    // Retrive array nominal settings for PHTSTBY mode
    //
    int ssw_bias = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","sswBias",detVersion,debug);
    int ssw_phase = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","sswPhase",detVersion,debug);
    int slw_bias = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","slwBias",detVersion,debug);
    int slw_phase = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","slwPhase",detVersion,debug);
    //
    // ---
    // Building block starts
    // ---
    SpireSetObsStep(0x1);
    delay(1);
    //
    // Switch ON PLIAs
    //
    SpireSendDrcuCmd(0xa0870006,0);
    delay(1);
    //
    // Set bias mode ,bias frequency and sampling frequency
    //
    SpireSendDrcuCmd(0x84300000 + biasmode,0);
    SpireSendDrcuCmd(0x84390000 + mclkdiv,0);
    SpireSendDrcuCmd(0x84380000 + biasdiv,0);
    delay(1);
    //
    // Switch on with small bias (~ 1 mVrms) across the arrays
    //
    SpireSendDrcuCmd(0x84310002,0);
    SpireSendDrcuCmd(0x84320002,0);
    delay(1);
    //
    // Set demodulation phase shift
    //
    SpireSendDrcuCmd(0x843a0000 + ssw_phase,0);
    SpireSendDrcuCmd(0x843b0000 + slw_phase,0);
    delay(1);
    //
    // Automatic offset setting + get offsets
    //
    SpireSendDrcuCmd(0x843c0014,0);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(2);
    SpireSendDrcuCmd(0x843e0000,0);
    SpireSendDrcuCmd(0x843c001c,0);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(3);
    SpireSendDrcuCmd(0x843e0000,0);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(1);
    //
    // Start SF data generation
    //
    SpireSendDrcuCmd(0x843c0000 + dcuDataMode,0);
    SpireSendDrcuCmd(0x843d0000,0);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(1);
    //
    // If necessary switch ON jfet heater
    if(jfet_heater_V != 0) {
        SpireSendDrcuCmd(0x84330000 + jfet_heater_V,0);
        delay(60);
        SpireSendDrcuCmd(0x84330000,0);
    } else {
        delay(3);
    }
    //
    // Apply Startup Vss voltages
    //
    // Read the startup Vss settings 
    // 
    int ssw_jfet_Vss1 = SpireProc_GetTableEntryInt("SpireTable_SpecVssSettings.txt","model","startup","ssw_vss1",vssVersion,debug);
    int ssw_jfet_Vss2 = SpireProc_GetTableEntryInt("SpireTable_SpecVssSettings.txt","model","startup","ssw_vss2",vssVersion,debug);
    int slw_jfet_Vss1 = SpireProc_GetTableEntryInt("SpireTable_SpecVssSettings.txt","model","startup","slw_vss",vssVersion,debug);
    //
    //  Apply Vss voltages followed by PVdd
    //
    // SSW JFET1 
    SpireSendDrcuCmd(0x84350000 + ssw_jfet_Vss1,0);
    SpireSendDrcuCmd(0x84370002,0);
    delay(1);
    // SSW JFET2	
    SpireSendDrcuCmd(0x84360000 + ssw_jfet_Vss2,0);
    SpireSendDrcuCmd(0x84370006,0);
    delay(1);
    // SLW JFET	
    SpireSendDrcuCmd(0x84340000 + slw_jfet_Vss1,0);
    SpireSendDrcuCmd(0x84370007,0);
    delay(1);
    //
    // Wait 30 seconds before setting nominal biases 
    //
    delay(30);
    SpireSendDrcuCmd(0x84310000 + ssw_bias,0);
    delay(1);
    SpireSendDrcuCmd(0x84320000 + slw_bias,0);
    delay(1);
    //
    // Stop DCU data, apply automatic offset setting + get offsets
    // 
    SpireSendDrcuCmd(0x843e0000,0);
    delay(1);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO(0x1000);
    delay(3);
    SpireSendDrcuCmd(0x843c0014,0);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(2);
    SpireSendDrcuCmd(0x843e0000,0);
    SpireSendDrcuCmd(0x843c001c,0);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(3);
    SpireSendDrcuCmd(0x843e0000,0);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO(0x1000);
    delay(1);
    //
    // Start SF data generation
    //
    SpireSendDrcuCmd(0x843c0000 + dcuDataMode,0);
    SpireSendDrcuCmd(0x843d0000,0);
    SpireSendDrcuCmd(0x843e0001,0);
    //
    // Wait 30 seconds before setting the optimum Vss values
    //
    delay(30);
    //
    // Read the optimum Vss settings (lowest noise)
    // 
    int ssw_jfet_OVss1 = SpireProc_GetTableEntryInt("SpireTable_SpecVssSettings.txt","model","optimum","ssw_vss1",vssVersion,debug);
    int ssw_jfet_OVss2 = SpireProc_GetTableEntryInt("SpireTable_SpecVssSettings.txt","model","optimum","ssw_vss2",vssVersion,debug);
    int slw_jfet_OVss1 = SpireProc_GetTableEntryInt("SpireTable_SpecVssSettings.txt","model","optimum","slw_vss",vssVersion,debug);
    // 
    // Now set the optimum Vss values for all the JFETs
    //
    // SSW JFET1 
    SpireSendDrcuCmd(0x84350000 + ssw_jfet_OVss1,0);
    // PSW JFET2
    SpireSendDrcuCmd(0x84360000 + ssw_jfet_OVss2,0);
    delay(1);
    // SLW JFET	
    SpireSendDrcuCmd(0x84340000 + slw_jfet_OVss1,0);
    //
    //
    delay(10);
    // setup DCU data sampling
    SpireSendDrcuCmd(0x843c0000 + dcuDataMode,0);
    int dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuFrameNumber",detVersion,debug);
    SpireSendDrcuCmd(0x843d0000 + dcuFrameNumber,0);
    int dcuDataGen = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuDataGen",detVersion,debug);
    SpireSendDrcuCmd(0x843e0000 + dcuDataGen,0);
    //
    // flush data from FIFOs
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(3);
    //
    SpireSetObsStep(0x0);
    sync();
    //
    // completion
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB CalSdetOn   ended");
    SpireMsg(1,"  ..BB CalSdetOn (" + (time() - t0) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProcSetBsmSampling.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to set the BSM sampling  for any operating mode
//
///////////////////////////////////////////////////////////////////////////
//
// 04/09/2009 MP: First version adapted from 
//                SpireBbSetBsmSampling (03/09/2009 KJK)
// 
///////////////////////////////////////////////////////////////////////////
//
double procedure SpireProcSetBsmSampling {
    string opsMode = "PHTSTBY";
    string bsmVersion = "v00";
    bool debug = false; // Allow debug_print statements 
}{
    // 
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    //
    // Start procedure:
    //
    message("4    " + time() + ": SpireProcSetBsmSampling started");
    message("4          $Id: $");
    // //
    // //
    //  Set default values
    //
    // set default datarate
    double bsmDataRate = 0.0;
    // set default TM Packet 12 sampling rate
    int bsmFrameRate = 0;
    // set default bsmFrameNumber:
    int bsmFrameNumber = 0;
    //
    // deal with Observing Mode transitions
    //
    if(opsMode == "REDY" || opsMode == "PHTSTBY" || opsMode == "SPECSTBY") {
        //  if generating data, setup sampling first
        int bsmDataGen = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",opsMode,"mcuDataGen","v00",debug);
        if(bsmDataGen == 1) {
            // if starting data generation
            // Set number of samples
            bsmFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",opsMode,"mcuFrameNumber","v00",debug);
            SpireSendDrcuCmd(0x91c30000 + bsmFrameNumber,0);
            // read datarate
            bsmDataRate = SpireProc_GetTableEntryDouble("SpireTable_CommonModeParams.txt","mode",opsMode,"bsmDataRate",bsmVersion,debug);
            // read TM Packet 12 sampling rate
            bsmFrameRate = SpireProc_GetTableEntryInt("SpireTable_CommonModeParams.txt","mode",opsMode,"bsmFrameRate",bsmVersion,debug);
        } else {
            if(opsMode == "REDY") {
                bsmFrameRate = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",opsMode,"bsmFrameRate",bsmVersion,debug);
            } else {
                bsmFrameRate = SpireProc_GetTableEntryInt("SpireTable_CommonModeParams.txt","mode",opsMode,"bsmFrameRate",bsmVersion,debug);
            }
            // Set number of samples
            bsmFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",opsMode,"mcuFrameNumber","v00",debug);
            SpireSendDrcuCmd(0x91c30000 + bsmFrameNumber,0);
        }
        // Start/Stop Data Generation
        SpireSendDrcuCmd(0x91c20000 + bsmFrameRate,0);
        SpireSendDrcuCmd(0x91c10000 + bsmDataGen,0);
    } else {
        // operating mode transitions
        bsmFrameRate = SpireProc_GetTableEntryInt("SpireTable_CommonModeParams.txt","mode",opsMode,"bsmFrameRate",bsmVersion,debug);
        SpireSendDrcuCmd(0x91c20000 + bsmFrameRate,0);
        bsmDataRate = SpireProc_GetTableEntryDouble("SpireTable_CommonModeParams.txt","mode",opsMode,"bsmDataRate",bsmVersion,debug);
    }
    //
    // End procedure:
    //
    sync();
    SpireMsg(4,"    " + time() + ": Proc SpireBbSetBsmSampling ended");

    return bsmDataRate;
}

// SpireBbChop
//
// execute chopping operations
//
// returns the actual time on-source
//
//  K.J. King
//
// 2009/09/11 V1.1: MP Use versionized SpireTable_ChopParams instead of
//                     Chopping.txt; Added chopVersion, debug to input. 
//
/////////////////////////////////////////////////////////////////////
double block SpireBbChop SPIRE 8449 {
    string opsMode = "" in ["POF1","SOF3","SOF4"];
    int onChop = 0; // on-source Chop position
    int onJigg = 0; // on-source Jiggle position
    int offChop = 0; // off-source Chop position
    int offJigg = 0; // off-source Jiggle position
    int step = 0; // step number
    string chopVersion = "v00"; // Version in cal table SpireTable_ChopParams
    bool debug = false;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Chop started");
    SpireMsg(2,"          $Id: SpireBbChop.txt,v 1.1 2006/08/10 09:38:57 kking Exp $");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP 
    hstr = SpireHexStr(step,4);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(" + hstr + ")");
    Spire_SET_OBS_STEP_RAW(step);
    //
    // execute chop
    //
    int id = ilookup("CommandLists.txt","Chop","Id");
    //  number of table containing the jiggle command list
    int index = ilookup("CommandLists.txt","Chop","Index");
    //  istart point in table containing the jiggle command list
    int nParms = ilookup("CommandLists.txt","Chop","Nparms");
    //  number of parameters to the jiggle command list
    int nChops = ilookup("OpsParms.txt",opsMode,"NChops");
    //  number of chop cycles per jiggle position
    int tChop = SpireProc_GetTableEntryInt("SpireTable_ChopParams.txt","mode",opsMode,"Period",chopVersion,debug);
    //  period of chop cycle
    int dcuFrame = SpireProc_GetTableEntryInt("SpireTable_ChopParams.txt","mode",opsMode,"DcuFrame",chopVersion,debug);
    //  DCU Sample Mode
    int nDcu = SpireProc_GetTableEntryInt("SpireTable_ChopParams.txt","mode",opsMode,"DcuSamples",chopVersion,debug);
    //  number of DCU Samples per chop position 
    int tDelay = SpireProc_GetTableEntryInt("SpireTable_ChopParams.txt","mode",opsMode,"DcuDelay",chopVersion,debug);
    //  delay to start of DCU sampling
    int nBsm = SpireProc_GetTableEntryInt("SpireTable_ChopParams.txt","mode",opsMode,"BsmSamples",chopVersion,debug);
    //  number of BSM samples per chop position
    //
    {int}[] parms = [{onChop},{onJigg},{offChop},{offJigg},{nChops},{tChop},{dcuFrame},{nDcu},{tDelay},{nBsm}];
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM_RAW(" + id + "," + index + "," + nParms + "," + parms + ")");
    Spire_RUN_VM_RAW(id,index,nParms,parms);
    //
    int nOps = nChops;
    double opsTime = double(nOps) * double(tChop) / 1000000.0;
    // time to perform a chopping operation
    delay(iceil(opsTime));
    //
    double srcTime = double(nOps) * double(tChop - tDelay * 2) / 1000000.0;
    // effective integration time per chopoperation
    //
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Chop ended");
    SpireMsg(1,"  ..Jiggle (" + (time() - t) + " seconds)");
    //

    return srcTime;
}

// SpireSpectroPcalFlash
//
// $id$
//
// This observation executes a PCAL Flash
// 
// The instrument should be in  the SPECSTBY mode before execution of this procedure
// and the parameter passed to the observation should correspond to the initial state.
//
// 17/03/2009 KJK: 
//         SCR 0946 created from SpireEngPcalFlash and SpirePhotoPcalFlash
// 05/07/2009 KJK:
//         SPR-1593 - Updated input parameters in call to SpirePcalFlash
// 27/10/2009 KJK:
//        SPR Spire-2049 - calls SpirePcalFlash with flashMode="SFlash_b" if bright source is set.
//
obs SpireSpectroPcalFlash {
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; // NAIF identifier
    string boresight = ""; // instrument boresight to use
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    bool isBright = false;
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    string flashVersion = "v00"; // Version in cal table SpireTable_FlashParms
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    string obsMode = "SOF8";
    string flashMode = "SFlash";
    if(isBright) {
        flashMode = "SFlash_b";
    }
    bool isPhot = false;
    string version01 = "v00";
    // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00";
    // Version in cal table SpireTable_CommonModeParams
    string version06 = "v00";
    // Version in cal table SpireTable_IsBrightPhaseShift
    //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    //
    int tslewmin = duration(SpireBb_StartObsAll(obsMode)) + duration(SpireBb_SpecSetMode("SFlash",isBright,version01,version02,debug));
    //   
    // BBs carried out when the pointing is reached:
    //
    if(pointing) {
        int tinithold = duration(SpireBb_SpecOffsetAuto(false,debug));
    } else {
        tinithold = duration(SpireBb_SpecOffsetAuto(false,debug)) + duration(SpireBb_StartObsAll(obsMode)) + duration(SpireBb_SpecSetMode("SFlash",isBright,version01,version02,debug));
    }
    //
    // BB carried out during pointing:
    //
    int tp = duration(SpirePcalFlash(flashMode,flashVersion,debug));
    //
    // BB carried out at the end:
    //
    int tfinalhold = duration(SpireBb_EndObsAll(isPhot)) + duration(SpireBb_SpecSetMode("SPECSTBY",isBright,version01,version02,debug)) + duration(SpireBb_SetObsStep(0,debug));
    //
    // Debug printing:
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // Lookup boresight, if not provided
    //
    string ib = boresight;
    if(boresight == "") {
        ib = SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode",obsMode,"Boresight",opsVersion,debug);
    }
    //
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    // 
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // ***********************  SLEW
            // Start observation: 
            SpireBb_StartObsAll(obsMode);
            // configure instrument 
            SpireBb_SpecSetMode("SFlash",isBright,version01,version02,debug);
        }
        if(state[0] == 2) {
            // ***********************  INITHOLD
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            if(!pointing) {
                // Start observation: 
                SpireBb_StartObsAll(obsMode);
                // configure instrument 
                SpireBb_SpecSetMode("SFlash",isBright,version01,version02,debug);
            }
            // Set offsets: 
            //
            SpireBb_SpecOffsetAuto(false,debug);
        }
        if(state[0] == 3) {
            // ***********************  POINTING
            SpirePcalFlash(flashMode,flashVersion,debug);
        }
        if(state[0] == 5) {
            // ***********************  FINALHOLD
            // reset STEP
            SpireBb_SetObsStep(0,debug);
            //
            // Set detectors back to SPECSTBY:  
            SpireBb_SpecSetMode("SPECSTBY",isBright,version01,version02,debug);
            //
            // End Observation
            SpireBb_EndObsAll(isPhot);
            //
        }
    }
}

//CLName: SpireBb_LoadTableMCUSAFE
//VMVersion: 2.8
//CLVersion: 1.0
//CLCVSId: $ID$
//TableId: 0xd5
//TableLength: 0x19
//Date: 090326172619
block SpireBb_LoadTableMCUSAFE SPIRE 3806 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableMCUSAFE started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0xd5
    Spire_SET_TABLE(0xd5,0x19);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0xd5,0x0,25,[{0x60660000},{0x80007d0},{0x1000001},{0x80007d0},{0x120000ff},{0x0},{0x12000000},{0x18},{0x61060001},{0x12000000},{0x7},{0x6066000c},{0x60660006},{0xb002710},{0x1000000},{0x80007d0},{0x1000001},{0x80007d0},{0x60660002},{0x60660007},{0x80007d0},{0x1000000},{0x80007d0},{0x7f000000},{0x900}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0xd5,0x0,0x0);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableMCUSAFE ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

// SpirePointSpectrum
//
// $id$
//
// Execute the FTS scans required at a single jiggle position, inserting flashes where required
// The script assumes that the SMEC is already at the ScanStart when it is called 
// and retutns the SMEC to that position on completion
//
// 04 November 2008: 
//       added data_rate commands
//       added commands to setup detector sampling, in case it is set differently (e.g. for flash mode)
// 27 January 2009: KJK
//       updated calls to SpireBbFtsScan to provide version and debug parameters
//       changed inputs to take in 2 sets of scans (usually higher and lower resolution)
//       If only 1 set of scans is used, they should be defined in set1
//       Now uses new SpireProc_SFlash Procedure, which moves SMEC to the Home position for the flash
// 03/09/2009 KJK: SPR-1763 (Problem1)
//            Added bsmVersion and smecVersion to input parameters
// 29/09/2009 MP: SPR-SPIRE-2048
//            Fix bug with hardcoded SFlash for isBright. Change call to 
//            SpireBbSetSmecSampling.
// 
//////////////////////////////////////////////////////////////////////////
double procedure SpirePointSpectrum {
    string res1 = "H" in ["H","M","C","L"]; // resolution for set 1
    int nCycles1 = 0; // number of cycles to execute in set 1
    double tCycle1 = 0.0; // time for a cycle in set 1
    int scansPerCycle1 = 0; // number of scans in a cycle for set 1
    string res2 = "L" in ["H","M","C","L"]; // resolution for set 2
    int nCycles2 = 0; // number of cycles to execute in set 2
    double tCycle2 = 0.0; // time for a cycle in set 2
    int scansPerCycle2 = 0; // number of scans in a cycle for set 2
    double tFlash = 0.0; // time between flashes
    int step = 0; // current step value - indicates the jiggle position
    string bsmVersion = "v00";
    string smecVersion = "v00";
    string specVersion = "v00";
    string flashVersion = "v00";
    bool isBright = false;
    bool debug = false;
}{
    // //
    // //
    // Set flash to isBright:  
    //
    string flashMode = "";
    if(isBright) {
        flashMode = "SFlash_b";
    } else {
        flashMode = "SFlash";
    }
    //
    // variables
    //
    // adjust tFlash to ensure that total time is not a multiple of tFlash leading to extra flash at end
    tFlash = tFlash + tCycle1;
    double srcTime = 0.0;
    // total on-source time
    int nFlash = 0;
    // number of cycles to next flash
    double tNext = tFlash;
    // time to next flash
    double s = 0.0;
    // on-source time per set of scans 
    //
    // Set up detector sampling
    //
    SpireConfigDcuData("Scan");
    //
    // set up MCU
    //
    SpireBbSetBsmSampling("Scan",bsmVersion,debug);
    if(isBright) {
        SpireBbSetSmecSampling("Scan_b",smecVersion,debug);
    } else {
        SpireBbSetSmecSampling("Scan",smecVersion,debug);
    }
    //
    // execute scans for set 1
    int scanStart1 = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",res1,"ScanStart",specVersion,debug);
    while(nCycles1 > 0) {
        nFlash = iround(tNext / tCycle1);
        if(nCycles1 < nFlash) {
            // execute remaining set 1 scans
            s = SpireBbFtsScan(res1,nCycles1 * scansPerCycle1,step,specVersion,debug);
            nCycles1 = 0;
            tNext = tNext - tCycle1 * double(nCycles1);
        } else {
            // execute scans to next flash
            s = SpireBbFtsScan(res1,nFlash * scansPerCycle1,step,specVersion,debug);
            // execute flash
            SpireProc_SFlash(flashMode,scanStart1,scanStart1,step,bsmVersion,smecVersion,flashVersion,debug);
            SpireBbSetBsmSampling("Scan",bsmVersion,debug);
            SpireBbSetSmecSampling("Scan",smecVersion,debug);
            nCycles1 = nCycles1 - nFlash;
            tNext = tFlash;
        }
        srcTime = srcTime + s;
        // increment on-source time
    }
    //
    // execute scans for set 2
    int scanStart2 = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",res2,"ScanStart",specVersion,debug);
    while(nCycles2 > 0) {
        nFlash = iround(tNext / tCycle2);
        if(nCycles2 < nFlash) {
            // execute remaining set 2 scans
            s = SpireBbFtsScan(res2,nCycles2 * scansPerCycle2,step,specVersion,debug);
            nCycles2 = 0;
            tNext = tNext - tCycle2 * double(nCycles2);
        } else {
            // execute scans to next flash
            s = SpireBbFtsScan(res2,nFlash * scansPerCycle2,step,specVersion,debug);
            // execute flash
            SpireProc_SFlash(flashMode,scanStart2,scanStart2,step,bsmVersion,smecVersion,flashVersion,debug);
            SpireBbSetBsmSampling("Scan",bsmVersion,debug);
            SpireBbSetSmecSampling("Scan",smecVersion,debug);
            nCycles2 = nCycles2 - nFlash;
            tNext = tFlash;
        }
        srcTime = srcTime + s;
        // increment on-source time
    }

    return srcTime;
}

// Missionphase  : CQM
//
// Purpose       : CONFigure the CSs servo loops
//                  
// Author TCL    : Helmut Feuchtgruber
// CUS script    : Diego A. Cesarsky
// CVS file      : CONF_cs.txt
//
// Arguments     : This version uses the hardcoded parameters found in the
//                 DEC/MEC User Manual V3.3
//
// type    name     default      Description
// string  whichCS  "CS1"        Which CS is configured 
// Description   : 
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : Current version (0.2) uses hardcoded values from DEC/MEC
//                 SUM V3.3
//
// Version       : 0.3
// History       : 0.1 13-Oct-2004 Creation by DAC
//               : 0.2 27-apr-2005 DAC Added missing 7th argument
//               : 0.3 30-sep-2005 CS1 and CS2 were called with same variable
//               :
int procedure CONF_cs {
    string whichCS = "CS1" in ["CS1","CS2","Both"]; // CS to configure
}{
    // Tally total duration [milliseconds]
    int duration_msec = 0;
    // Use HF's version where everything is hardcoded
    // Parameters for CS1
    int[] aux1 = [1000000,5000,3277,1857,327,0x7fff,0];
    int check_sum1 = checksum("int",aux1);
    {int}[] parlist1 = Array2grp_1(aux1);
    // Parameters for CS2
    int[] aux2 = [1000000,5000,3277,1857,327,0x7fff,0];
    int check_sum2 = checksum("int",aux2);
    {int}[] parlist2 = Array2grp_1(aux2);
    if(whichCS == "CS1") {
        Pacs_DMC_WRT_CS1_CONF_PAR(parlist1,check_sum1);
    }
    if(whichCS == "CS2") {
        Pacs_DMC_WRT_CS2_CONF_PAR(parlist2,check_sum2);
    }
    if(whichCS == "Both") {
        Pacs_DMC_WRT_CS1_CONF_PAR(parlist1,check_sum1);
        Pacs_DMC_WRT_CS2_CONF_PAR(parlist2,check_sum2);
    }
    // Set delay
    int duration_sec = Msec2sec(duration_msec);
    delay(duration_sec);

    return duration_msec;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Set_SpecPhase
//
///////////////////////////////////////////////////////////
//
// Procedure to configure the spectrometer detector phases
//
///////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/15 V0.1: Initial version adapted from
//                  SpireProc_Set_PhotPhase (KJK, 2009/02/14 V0.2) and 
//                  SpireBb_SpecFSetPhase (2008/08/11 V0.1)
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_SpecPhase {
    int ssw_phase = 0x0 in [0,255]; //Default phase is 0 [Hex]
    int slw_phase = 0x0 in [0,255]; //Default phase is 0 [Hex]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string tstr = "";
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"     " + tstr + ":  SpireProc_Set_SpecPhase started");
    SpireMsg(4,"          $Id:$");
    // //
    // //
    // Set the selected phases:
    //
    // Set the phases for the two arrays:
    SpireSendDrcuCmd(0x843a0000 + ssw_phase,0);
    SpireSendDrcuCmd(0x843b0000 + slw_phase,0);
    sync();
    // //
    // //
    // Debug Printing:
    //
    double ssw_phase_deg = 360.0 * double(ssw_phase) / 255.0;
    double slw_phase_deg = 360.0 * double(slw_phase) / 255.0;
    if(debug) {
        debug_print("ssw phase is set to " + ssw_phase + " [Dec(Hex)] " + ssw_phase_deg + " [deg]");
        debug_print("slw phase is set to " + slw_phase + " [Dec(Hex)] " + slw_phase_deg + " [deg]");
    }
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"      " + tstr + ": SpireProc_Set_SpecPhase ended");
}

// SpirePOF5Pointing
//
// $id$
//
// This procedure calculates and returns the pointing parameters for the POF5 observing mode  
//
//  13/04/07: SCR3010 - changed default obsMode
//  14/02/08:         - added duration of StartDcuData Building Block to tInitHold 
//  02/07/2009  KJK:
//         - Added bsmModel, isBright, bsmVersion, photVersion, comVersion and debug input parameters
//            for use in calls to other scripts
//  05/07/2009 KJK:
//         SPR-1593 - added flashVersion to input parameters
//                         - changed call to SpireBbPcalFlash
//  10/08/2009 KJK (SPR-1709):  Added new input parameter, comVersion 
//                 to call to SpreBbPOF5Config
//  15/08/2009 MP (SCR-SPIRE-1818): New input opsVersion to allow changes 
//                 to rate/d2 from the top level script.  
//  10/09/2009 KJK:
//                 SPR  Spire-01897-1: updated to use initFlash to determin initHold duration  
//                 Updated to fetch data from new calibration table (SpireTable_SpireParams.txt)
//                 Required additional input parameter (spireVersion)
//  15/09/2009 KJK: updated to call SpireBbPOF5Init with obsMode parameter
//  25/01/2010 KJK: Now calls  SpireBbStartObsAll instead of SpireObsConfig during intitalisation
//
///////////////////////////////////////////////////////////////////////////
{int,int,int,int,int,double,double} procedure SpirePOF5Pointing {
    string obsMode = "POF5_S_N";
    int nMaps = 1; // total number of number of maps to perform
    int nLines = 1; // number of lines per map
    int nCal = 99999; // number of lines per Gyro calibration
    int nFlash = 99999; // number of lines per PCAL flash
    bool isBright = false;
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string spireVersion = "v00";
    string flashVersion = "v00";
    string photVersion = "v00";
    string comVersion = "v00";
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    bool debug = false;
}{
    // //
    // //
    // Declare some variables:
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double patt = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName05 = "SpireTable_OpsParms.txt";
    //
    // ***** fetch fixed operating mode parameters *****
    //
    bool initFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"InitFlash",spireVersion,debug);
    // initial flash flag
    bool endFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"EndFlash",spireVersion,debug);
    // final flash flag
    //
    // scan rate:  
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "ScanRate";
    version = opsVersion;
    double rate = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
    // 
    // scan line separation:   
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "D2";
    version = opsVersion;
    double d2 = SpireProc_GetTableEntryDouble(tabName,selCol,selVal,tarCol,version,debug);
    //
    //
    // ****** calculate parameters for pointing mode ******
    //
    int tSlewMin = duration(SpireBb_StartObsAll("POF5")) + duration(SpireBbPOF5Config(obsMode,isBright,bsmModel,bsmVersion,photVersion,comVersion,debug)) + 2;
    //
    // time for Initial Hold
    int tInitHold = duration(SpireBbPOF5Init(obsMode)) + duration(SpireBbStartDcuData(obsMode)) + 2;
    int tFlash = duration(SpireBbPcalFlash("PFlash",flashVersion,0,debug));
    if(initFlash || nFlash < nLines) {
        tInitHold = tInitHold + tFlash;
    }
    //
    int tHold = tFlash + duration(SpireBbStopDcuData()) + duration(SpireBbStartDcuData(obsMode)) + 2;
    //
    int nHold = 0;
    // default if no flashes required during scanning
    if(nFlash < nMaps * nLines) {
        nHold = nLines;
        // flash required every map
    }
    if(nFlash < nLines) {
        nHold = nFlash;
        // flash required within map
    }
    //
    // time for Final Hold
    int tFinalHold = duration(SpireBbPOF5End("PHTSTBY",isBright,bsmModel,bsmVersion,photVersion,comVersion,debug)) + duration(SpireBbStopDcuData()) + 2;
    if(endFlash && nHold != nLines) {
        tFinalHold = tFinalHold + tFlash;
    }

    return {tSlewMin,tInitHold,tFinalHold,tHold,nHold,d2,rate};
}

// $Id: PacsEng_orbit_epilogue.E2E,v 1.1 2007/08/24 08:28:44 dcesarsk Exp $
//
// Missionphase  : FM RMS
//
// Purpose       : Leave PACS in switched off mode
//
// Author        : Diego A. Cesarsky
//
// Arguments     : None
//
// Description   : Calls OBCP_safe
//
// Dependencies  : OBCP_SAFE
//
// Comments      : Use new "no_pointing" request
//
// Version       : 0.1
// History       : 0.1 14-feb-2008 Based on AOT's PacsEng_orbit_epilogue
// 		 : 1.0 17-sep-2009 VD OD113 problem... 
//
obs SpirePacsEng_Parallel_PacsEpilogue {
}{
    bool execute = true;
    int tih = 0;
    int tfh = 0;
    int tp = duration(OBCP_SAFE());
    // Add needed time to set/unset OBSID
    int tset = duration(WriteOBSID($OBSID));
    int tunset = duration(WriteEndID());
    tp = tp + tset + tunset;
    // Issue PointReq
    int[] ts = no_pointing(execute,0,0,tp);
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            //     Obtain and set OBSID
            WriteOBSID($OBSID);
            data_rate(120.0);
            //     Call OBCP_SAFE
            OBCP_SAFE();
            //     Reset OBSID and BBID
            data_rate(0.0);
            WriteEndID();
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_PhotMultiLevelNoiseLevels.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to translate user input in Hz for bias frequency and 
//  sampling rate into nearest Hex values for mclkdiv and biasdiv
//  and then select list of bias amplitudes and phases for the nearest 
//  match to mclkdiv from the input calibration table. 
// 
//  Adapted from: Lookup.txt (2008-06-13 13:56)
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/06/14 V0.1: Initial version 
// 2008/08/04 V0.2: Allow separate phase for each array (including PTC)
// 2008/08/15 V0.3: Adapt to change in call to low level script 
//                  SpireProc_CalcParam_BiasFreqSampFreq.txt 
// 2008/09/22 V0.4: Adapt to change in cal table setup
// 2008/11/14 V0.5: Include check for non-existing version; Add debug parameter
// 2009/01/31 V1.0: Add debug_print option (also to low level script).
// 2009/02/17 V1.1: Extend error message. 
//
///////////////////////////////////////////////////////////////////////////
//
{string,int,int,int,double,double,double,double}[] procedure SpireProc_CalcParam_PhotMultiLevelNoiseLevels {
    double biasfreq = 130.2; // Bias frequency (Hz)
    double samplerate = 18.6; // Sampling frequency (Hz)
    string tabName = "SpireTable_PhotMultiLevelNoiseLevels.txt"; // Calibration table name 
    string version = "v00"; // Version parameter defined in calibration table
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Calculate mclkdiv and biasdiv based on user input in Hz:
    //
    bool fts = false;
    // FTS or photometer limits? 
    int[] hexvalues = SpireProc_CalcParam_BiasFreqSampFreq(biasfreq,samplerate,fts,debug);
    int mclkdiv = hexvalues[0];
    int biasdiv = hexvalues[1];
    // //
    // //
    // Debug printout:
    //
    if(debug) {
        debug_print("Converted values mclkdiv/biasdiv [raw]: " + mclkdiv + " " + biasdiv);
    }
    // //
    // //
    // Setup variables:
    //
    string colName = "mclkdiv";
    int[] searchCol = icolumn(tabName,colName);
    int size = table_size(tabName);
    // //
    // //
    // Determine closest match: 
    //
    // Start with the first value as the closest:
    int closest = searchCol[0];
    int diff = iround(abs(double(mclkdiv - closest)));
    if(debug) {
        debug_print("diff = " + diff);
    }
    // Run through the values in the column:
    for(int i = 0 .. size - 1) {
        int next = searchCol[i];
        int nextDiff = iround(abs(double(mclkdiv - next)));
        if(debug) {
            debug_print("next = " + next);
            debug_print("nextdiff = " + nextDiff);
        }
        if(nextDiff < diff) {
            closest = next;
            // Change diff to allow for non-monotonous mclkdiv in cal. tab. :
            diff = nextDiff;
            if(debug) {
                debug_print("closest = " + closest);
                debug_print("diff = " + diff);
            }
        }
    }
    // //
    // //
    // Get all other column information:
    //
    string[] versionCol = scolumn(tabName,"version");
    int[] settingCol = icolumn(tabName,"setting");
    double[] pswphaseCol = dcolumn(tabName,"pswphase");
    double[] pmwphaseCol = dcolumn(tabName,"pmwphase");
    double[] plwphaseCol = dcolumn(tabName,"plwphase");
    double[] ptcphaseCol = dcolumn(tabName,"ptcphase");
    //
    {string,int,int,int,double,double,double,double}[] rows = [{"",0,0,0,0.0,0.0,0.0,0.0}];
    int index = 0;
    //
    // //
    // //
    // Cycle through values again to get all rows with closest match:
    //
    for(int j = 0 .. size - 1) {
        // If the key matches the closest and has the correct version tag 
        // then we want it:
        if(closest == searchCol[j]) {
            if(versionCol[j] == version) {
                rows[index] = {versionCol[j],searchCol[j],biasdiv,settingCol[j],pswphaseCol[j],pmwphaseCol[j],plwphaseCol[j],ptcphaseCol[j]};
                index = index + 1;
            }
        }
    }
    // //
    // //
    // Safety check: Make sure input version parameter is defined in cal. table:
    if(debug) {
        debug_print("rows[0]{0}: " + rows[0]{0});
    }
    if(rows[0]{0} == "") {
        error("Input version parameter is not defined for selected bias frequency. Either select another version or change bias frequency!");
    }
    // //
    // //
    // Return values:
    //

    return rows;
}

// SpireBbPOF5End
//
// $Id:$
//
// Building Block to reconfigure the instrument from POF5 (scan map) mode
//
//  02/07/2009 KJK: 
//         - Added bsmModel, isBright, bsmVersion, photVersion, comVersion and debug input parameters
//         - Added reset from possible bright-source operations
// 13/07/2009 MP: 
//         - Moved 'reset bright-source biases and phases' before unsetting
//           the OBSID (SPR-SPIRE-1639)
//  10/08/2009 KJK:
//         SPR-1709:  Updated to execute SpireProc_Set_PhotMode if photversion is not "V00"
//                           Updated to always use photVersion and comVersion = "v00" for all calls - to reset the detectors
//  25-Aug-2009 KJK:
//        SPR Spire-1641: Now read BSM HOLD positions from SpireTable_BsmNominalSettings.txt rather than BSM.txt
// 15/09/2009 KJK: added  reconfiguration of  DCU 
//
block SpireBbPOF5End SPIRE 8274 {
    string obsMode = "PHTSTBY";
    bool isBright = false in [true,false];
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string photVersion = "v00";
    string comVersion = "v00";
    bool debug = false in [true,false];
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF5 Reconfiguration started");
    SpireMsg(2,"          $Id:$");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP to zero
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x0000)");
    Spire_SET_OBS_STEP_RAW(0x0);
    //
    // Move BSM to HOLD
    int bsmHoldChopPosn = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",bsmModel,"chop_0_I",bsmVersion,debug);
    int bsmHoldJiggPosn = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",bsmModel,"jigg_0_I",bsmVersion,debug);
    SpireBsmMove(bsmHoldChopPosn,bsmHoldJiggPosn);
    //
    // reset bright-source biases and phases - if needed
    //
    if(isBright) {
        SpireProc_Set_PhotMode(obsMode,isBright,"v00","v00",debug);
    } else {
        if(photVersion != "v00") {
            SpireProc_Set_PhotMode(obsMode,isBright,"v00","v00",debug);
        }
    }
    SpireConfigDcuData("PHTSTBY");
    //
    // Set Mode to PHT_STBY
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_MODE_RAW(0x0300)");
    Spire_SET_OBS_MODE_RAW(0x300);
    // 
    // Clear OBSID/BBID to null values
    tstr = SpireTimeStr(time());
    message("5          " + tstr + "Cmd: Spire_SET_BBID_RAW(0x80000000)");
    Spire_SET_BBID_RAW(0x80000000);
    int obsId = SpireNullObsid();
    tstr = SpireTimeStr(time());
    hstr = SpireHexStr(obsId,8);
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBSID_RAW(" + hstr + ")");
    Spire_SET_OBSID_RAW(obsId);
    // 
    // ..... completion .....
    //
    sync();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF5 Reconfiguration ended");
    SpireMsg(1,"  ..POF5 Reconfiguration to PHT_STBY mode (" + (time() - t) + " seconds)");
}

// Missionphase  : FM
//
// Purpose       :  Time DMC syncing
//                  
//                 
//
// Input arguments none
// type    name         description
//
// Return values
// Type    Name      Default      Description
//
// Description   :  DMC time syncing
//                            
//                           
//                            
//                  
// Dependencies  : 
//
// Preconditions : PACS must be on 
//                             
//                 
// Comments      : 
// 
// History       : 1.0 28-may-2009 creation VD
//
int block OBCP_TimeSynch3 PACS 1024 {
}{
    // Register start of BB
    // special Hexa
    int iBBID = 0xcd2a4a5;
    // Obtain duration of an "internal" command [msec]      
    int t_cmd = iceil(dlookup("PACSparams","int_cmd","freq_time"));
    // Obtain duration of OBCP "communication jitter" [msec]
    int obcp_margin = iceil(dlookup("PACSparams","obcp_margin","freq_time"));
    // Tally duration (NOTE: we use [msec] for the return value)
    int duration_msec = 0;
    // DMC_WRT_TIME()
    duration_msec = duration_msec + t_cmd;
    // DMC_SET_TIME
    duration_msec = duration_msec + t_cmd;
    string obcp_ID = "TIME_SYNC_III";
    int obcp_par = 0;
    //   int seq_DMC=0;
    //    int seq_time = duration_msec;
    {int,int}[] grp = [];
    Pacs_DPU_START_OBCP(obcp_ID,obcp_par,grp);
    // Add the "communication jitter"
    duration_msec = duration_msec + obcp_margin;
    // write BB ID to DMC
    Pacs_DMC_SET_BBID(iBBID);
    duration_msec = duration_msec + t_cmd;
    // Return time

    return duration_msec;
}

// SpireSpectroRaster
//
// $Id: SpireSpectroRaster.txt,v 1.7 2008/05/23 08:48:39 kking Exp $
//
// The high level script for the Spire Spectrometer Raster  observing mode 
//
// 15/02/08        Added np to step value when pointing or hold
//
// 04 November 2008: added data_rate commands
// 04/03/09: MP Fixed bug in call to 
//                  SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode"....)
// 10/03/2009 KJK: 
//         SCR 1274, add additional dummy parameters 
//         Update input API to include versions for all cal tables
// 17/03/2009 KJK:
//         Update API to read NCycles1 from NHCycles and NCycles2 from NLCycles
// 05/07/2009 KJK:
//         SPR-1593 - Updated calls to SpireBbPcalFlash to use flashVersion 
// 25/08/2009 KJK:
//        SPR Spire-1641: Needed new input parameters bsmModel and bsmVersion
// 03/09/2009 KJK: 
//       Added smecVersion to input parameters
// 04/09/2009 MP:
//       Pass smecVersion to SpireBbSOF1End and SpireBbSOF2End
// 05/09/2009 MP:
//       Add in move of BSM to home before PCAL flash       
// 14/09/2009 KJK:
//       SCR Spire-1953: updated calls to pass smodeVersion to 
//       SpireBbSOF1Init, SpireBbSOF2Init, SpireSOF12Pointing
// 15/09/2009 KJK:
//      SPR Spire-1763: changed calls to Proc_Sflash to assume SMEC is 
//      at scanstart position and to leave it at scanstart position
// 24/09/2009 KJK:
//       Updated calls to SpireSOF12Pointing, SpireBbSOF1Config, 
//       SpireBbSOF2Config, SpireBbSOF1End, SpireBbSOF2End//
// 29/09/2009 MP: SPR-SPIRE-2048
//       Fix bug with hardcoded SFlash for isBright. Needed to changed
//       call to SOF1/2Init and SpirePointSpectrum. 
// 20/10/2009 KJK SPR Spire-2062:
//       Add call to SpireBbSmecInit in INIT_HOLD
// 16/02/2010 KJK: SCR Spire-2341:
//       Updated to get Flash info from SpireTable_SpireParams rather than SpireParams
//       Updated to call SpireSOF12Pointing with additional parameter
// 02/03/2010 SDS: Still SPIRE-SCR-2341: set nFlashes to 0, just as for SpireSpectroPoint
// 31/03/2010 KJK: SCR Spire-2459:
//       Added calls to SpireBb_SetSpecDetOffsets when necessary
//  20/07/2011 SDS:  SCR Spire-2563:
//                              opsVersion added in call to SpireSOF12Pointing
//
/////////////////////////////////////////////////////////////////////////
{int,int,double,int,double,int,int,int} obs SpireSpectroRaster {
    double ra = 0.0 in [0.0,360.0]; // RA of Target
    double dec = 0.0 in [-90.0,90.0]; // DEC of Target
    int naifid = 0; // NAIF identifier
    string pointing = "raster" in ["single","raster"]; // pointing type
    string sampling = "sparse" in ["sparse","intermediate","full"]; // spatial sampling
    string resolution = "H" in ["H","M","L","C","H+L"]; // spectral resolution
    double mapSize1 = 0.0 in [0.0,30.0]; // arc minutes
    double mapSize2 = 0.0 in [0.0,30.0]; // arc minutes
    double mapOffsetY = 0.0 in [-300.0,300.0]; // arc minutes
    double mapOffsetZ = 0.0 in [-300.0,300.0]; // arc minutes
    bool mapOrientationArray = true; // is the map orientation an array (rather than array with constraints)
    double mapOrientationConFrom = 0.0 in [0.0,360.0];
    double mapOrientationConTo = 360.0 in [0.0,360.0];
    int nRepetitions1 = 2 in [2,1200]; // number of times to repeat spectral scan pairs for single resolution scan modes and high resolution in H+L mode
    int nRepetitions2 = 2 in [2,1200]; // number of times to repeat spectral scan pairs for low resolution scans for 'H+L" mode
    double wavelength1 = -1.0; // wavelength
    double wavelength2 = -1.0; // wavelength
    double wavelength3 = -1.0; // wavelength
    double wavelength4 = -1.0; // wavelength
    double wavelength5 = -1.0; // wavelength
    double wavelength6 = -1.0; // wavelength
    double wavelength7 = -1.0; // wavelength
    double wavelength8 = -1.0; // wavelength
    double lineFlux1 = -1.0; // line flux estimate
    double lineFlux2 = -1.0; // line flux estimate
    double lineFlux3 = -1.0; // line flux estimate
    double lineFlux4 = -1.0; // line flux estimate
    double lineFlux5 = -1.0; // line flux estimate
    double lineFlux6 = -1.0; // line flux estimate
    double lineFlux7 = -1.0; // line flux estimate
    double lineFlux8 = -1.0; // line flux estimate
    bool isJyContinuum = true; // is Jy units rather than Wm-2um-1
    double contFlux1 = -1.0; // continuum flux estimate
    double contFlux2 = -1.0; // continuum flux estimate
    double contFlux3 = -1.0; // continuum flux estimate
    double contFlux4 = -1.0; // continuum flux estimate
    double contFlux5 = -1.0; // continuum flux estimate
    double contFlux6 = -1.0; // continuum flux estimate
    double contFlux7 = -1.0; // continuum flux estimate
    double contFlux8 = -1.0; // continuum flux estimate
    bool isBright = false; // Use settings for bright source (==tick)
    bool isChopped = false;
    int nRasters = 1;
    int nPoints = 1;
    int nMaps = 1;
    int nHCycles = 0; // total number of High resolution scans at each pointing and jiggle position(it is a multiple of 
    int nMCycles = 0; // total number of Medium resolution scans at each pointing and jiggle position(it is a multiple of 
    int nLCycles = 0; // total number of Low resolution scans at each pointing and jiggle position
    int nCals = 999999;
    double tCal = 999999.0; // time between Gyro calibrations within a jiggle point operation
    int nFlashes = 0;
    double tFlash = 999999.0; // time between PCAL flashes within a jiggle point operation
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParms
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    string flashVersion = "v00"; // Version in cal table SpireTable_FlashParms
    string smodeVersion = "v00"; // Version in cal table SpireTable_SpecModeParams
    string specVersion = "v00"; // Version in cal table SpireTable_Spectrometer
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // unused parameters
    string comVersion = "v00";
    string smecVersion = "v00";
    //
    // check inputs
    if(pointing != "raster") {
        error("SpireSpectroRaster: Pointing is not set to raster");
    }
    SpireMsg(0,"Spectrometer Raster Observation");
    //
    //
    // *****************************************
    //      select instrument ops mode    
    // *****************************************
    //       
    string opsMode = "";
    // opsMode
    int md = 0;
    // value of MODE parameter
    if(sampling == "sparse") {
        opsMode = "SOF1";
        md = 0x410;
    } else {
        if(sampling == "intermediate") {
            opsMode = "SOF2_int";
        } else {
            if(sampling == "full") {
                opsMode = "SOF2";
            } else {
                error("SpireSpectroPoint: Unknown sampling");
            }
        }
        md = 0x420;
    }
    string flashMode = "";
    if(isBright) {
        flashMode = "SFlash_b";
    } else {
        flashMode = "SFlash";
    }
    //
    // *****************************************
    //      set up scan sets  
    // *****************************************
    // 
    string res1 = resolution;
    string res2 = "L";
    int nCycles1 = nHCycles;
    int nCycles2 = nLCycles;
    if(resolution == "H+L") {
        res1 = "H";
    }
    // *****************************************
    // get observing parameters
    // *****************************************
    //
    double tScan1 = SpireProc_GetTableEntryDouble("SpireTable_Spectrometer.txt","ResChar",res1,"ScanTime",specVersion,debug);
    double tScan2 = SpireProc_GetTableEntryDouble("SpireTable_Spectrometer.txt","ResChar",res2,"ScanTime",specVersion,debug);
    int scansPerCycle1 = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"N" + res1 + "Scans",opsVersion,debug);
    int scansPerCycle2 = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"N" + res2 + "Scans",opsVersion,debug);
    double tCycle1 = tScan1 * double(scansPerCycle1);
    double tCycle2 = tScan2 * double(scansPerCycle2);
    //
    //
    int jiggleTable = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"TableId",opsVersion,debug);
    // Jiggle Table ID
    int jiggleSize = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"TableSize",opsVersion,debug);
    // Jiggle Table length 
    int tSerendipity = duration(SpireBbSpecSerendipity(opsMode,0));
    // minimum time for a serendipity observation
    // initial flash flag
    bool initFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",opsMode,"InitFlash",spireVersion,debug);
    // final flash flag
    bool endFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",opsMode,"EndFlash",spireVersion,debug);
    double perScanOsit1 = SpireProc_GetTableEntryDouble("SpireTable_Spectrometer.txt","ResChar",res1,"Osit",specVersion,debug);
    // effective on source integration time per scan
    double perScanOsit2 = SpireProc_GetTableEntryDouble("SpireTable_Spectrometer.txt","ResChar",res2,"Osit",specVersion,debug);
    // effective on source integration time per scan
    //
    int nScans1 = nCycles1 * scansPerCycle1;
    int nScans2 = nCycles2 * scansPerCycle2;
    //
    int scanStart1 = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",res1,"ScanStart",specVersion,debug);
    int smecHome = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"Home");
    // //
    // //
    // Read BSM hold position from calibration table:  
    //
    string tabName05 = "SpireTable_BsmNominalSettings.txt";
    string version = bsmVersion;
    string tabName = tabName05;
    string selCol = "model";
    string selVal = bsmModel;
    string tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    //
    // *****************************************
    // set telescope pointing mode
    // *****************************************
    //
    string ib = SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode",opsMode,"Boresight",opsVersion,debug);
    double deltaY = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",opsMode,"DeltaY",opsVersion,debug);
    // offset to pixel centre from boresight in Y direction (arcsecs)
    double deltaZ = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",opsMode,"DeltaZ",opsVersion,debug);
    // offset to pixel centre from boresight in Z direction (arcsecs)
    bool fixed = SpireProc_GetTableEntryBool("SpireTable_OpsParms.txt","mode",opsMode,"Fixed",opsVersion,debug);
    // pattern angle definition
    double pattNod = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",opsMode,"Patt",opsVersion,debug);
    // direction of nod 
    double chopThrow = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",opsMode,"D1",opsVersion,debug);
    double yOffset = mapOffsetY * 60.0 + deltaY;
    // offset to observation position from target in Y direction (arcsecs)
    double zOffset = mapOffsetZ * 60.0 + deltaZ;
    // offset to observation position from target in Z direction (arcsecs)
    {int,int,int,int,int,int} sofPoint = SpireSOF12Pointing(opsMode,res1,nCycles1,tCycle1,scansPerCycle1,res2,nCycles2,tCycle2,scansPerCycle2,nMaps,nFlashes,tFlash,isBright,bsmModel,bsmVersion,comVersion,spireVersion,smodeVersion,smecVersion,specVersion,flashVersion,opsVersion,debug);
    int tSlewMin = sofPoint{0};
    int tInitHold = sofPoint{1};
    int tFinalHold = sofPoint{2};
    int tpp = sofPoint{3};
    int tHold = sofPoint{4};
    int nHold = sofPoint{5};
    // calculate raster positions
    {double[],double[]} sofRaster = SpireSpecRasterPositions(opsMode,0.0,0.0,mapSize1 * 60.0,mapSize2 * 60.0);
    double[] yArray = sofRaster{0};
    double[] zArray = sofRaster{1};
    int[] tp = [];
    int nRasterPoints = length(yArray);
    if(nPoints != nRasterPoints) {
        error("SpireSpectroRaster: Number of raster points has changed");
    }
    for(int n = 0 .. nRasterPoints - 1) {
        tp[n] = sofPoint{3};
    }
    if(nHold > nRasterPoints) {
        nHold = 0;
    }
    //
    int[] ts = custom_map_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,fixed,pattNod,yOffset,zOffset,yArray,zArray,tp,pattNod,chopThrow,1,0,0,0,tHold,nHold);
    //
    int tobs = ts[0];
    int tslew = ts[1];
    int tnod = ts[2];
    int tss = ts[3];
    int tload = ts[4];
    int tend = ts[5];
    //
}{
    SpireMsg(0,"Observation Start");
    SpireMsg(0,"  Uses observing mode " + opsMode);
    SpireMsg(3,"       $Id: $");
    //
    // *****************************************
    //   Display input parameters
    // *****************************************
    SpireMsg(3,"     Input values:");
    SpireMsg(3,"     ..RA: " + ra);
    SpireMsg(3,"     ..Dec: " + dec);
    SpireMsg(3,"     ..NAIF ID: " + naifid);
    SpireMsg(3,"     ..Pointing: " + pointing);
    SpireMsg(3,"     ..Sampling: " + sampling);
    SpireMsg(3,"     ..Resolution: " + resolution);
    SpireMsg(3,"     ..mapSize1: " + mapSize1);
    SpireMsg(3,"     ..mapSize2: " + mapSize2);
    SpireMsg(3,"     ..Y Offset: " + yOffset);
    SpireMsg(3,"     ..Z Offset: " + zOffset);
    SpireMsg(3,"     ..nRasters: " + nRasters);
    SpireMsg(3,"     ..nPoints: " + nPoints);
    SpireMsg(3,"     ..nMaps: " + nMaps);
    SpireMsg(3,"     ..nHCycles: " + nHCycles);
    SpireMsg(3,"     ..nMCycles: " + nMCycles);
    SpireMsg(3,"     ..nLCycles: " + nLCycles);
    SpireMsg(3,"     ..tCal: " + tCal);
    SpireMsg(3,"     ..tFlash: " + tFlash);
    SpireMsg(3,"     Fixed values:");
    SpireMsg(3,"     ..ib: " + ib);
    SpireMsg(3,"     ..initFlash: " + initFlash);
    SpireMsg(3,"     ..endFlash: " + endFlash);
    SpireMsg(3,"     Pointing Mode Input values:");
    SpireMsg(3,"     ..tSlewMin: " + tSlewMin);
    SpireMsg(3,"     ..tInitHold: " + tInitHold);
    SpireMsg(3,"     ..tFInalHold: " + tFinalHold);
    SpireMsg(3,"     ..tpp: " + tpp);
    SpireMsg(3,"     ..Y raster positions:" + yArray);
    SpireMsg(3,"     ..Z raster positions:" + zArray);
    SpireMsg(3,"     Pointing Mode Output values:");
    SpireMsg(3,"     ..tobs: " + tobs);
    SpireMsg(3,"     ..slew: " + tslew);
    SpireMsg(3,"     ..tnod: " + tnod);
    SpireMsg(3,"     ..tss: " + tss);
    SpireMsg(3,"     ..tload: " + tload);
    SpireMsg(3,"     ..tend: " + tend);
    // *****************************************
    //   execute observation
    // *****************************************
    //
    data_rate(0.0);
    double chkrate = dlookup("Datarates.txt","Scan","CHK");
    ess_hk_data_rate(chkrate);
    double nhkrate = dlookup("Datarates.txt","Scan","NHK");
    non_ess_hk_data_rate(nhkrate);
    string tstr = "";
    // time string
    int otf = 0x8000;
    // On Target Flag
    double srcTime = 0.0;
    // total on source integration time
    int np = 0;
    // raster point number
    int t = 0;
    //
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // *********************   SLEWING
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Slewing to start position");
            t = time();
            // set up observation parameters
            SpireBb_StartObsAll(opsMode);
            // perform serendipity operation if possible
            if(tslew > tSerendipity + tSlewMin) {
                SpireBbSpecSerendipity(opsMode,tslew - tSlewMin - 2);
            }
            // configure instrument for operations
            if(opsMode == "SOF1") {
                SpireBbSOF1Config(opsMode,res1,isBright,comVersion,smodeVersion,smecVersion,specVersion,debug);
            } else {
                SpireBbSOF2Config(opsMode,res1,isBright,comVersion,smodeVersion,smecVersion,specVersion,debug);
            }
        }
        if(state[0] == 2) {
            // ********************* INITIAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Telescope at start position");
            SpireMsg(0,"  Slew (" + (time() - t) + " secs)");
            SpireMsg(2,"    " + tstr + " Initialising Instrument");
            t = time();
            // initialise instrument
            SpireBbSmecInit(res1,bsmVersion,smecVersion,specVersion,debug);
            if(opsMode == "SOF1") {
                SpireBbSOF1Init(smodeVersion,isBright,debug);
            } else {
                SpireBbSOF2Init(smodeVersion,isBright,debug);
            }
            // calibrate if necessary
            if(initFlash || double(tpp) > tFlash) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                if(opsMode != "SOF1" && isBright) {
                    SpireBb_SetSpecDetOffsets(debug);
                }
                SpireProc_SFlash(flashMode,scanStart1,scanStart1,otf,bsmVersion,smodeVersion,flashVersion,debug);
            }
        }
        if(state[0] == 3) {
            // ********************* POINTING
            //??p pointing file generation ------------------------------
            //??p PtOutput(rdp0);
            //??p pointing file generation ------------------------------
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " New Pointing");
            int nFlash = 0;
            int step = 0;
            t = time();
            double s = 0.0;
            //
            for(int j = 0 .. jiggleSize - 1) {
                step = np | j;
                if(j > 0) {
                    if(nFlashes > 0 || j % nFlash == 0) {
                        SpireBb_BsmMove(hold_chop,hold_jigg,debug);
                        SpireBbPcalFlash(flashMode,flashVersion,otf | step,debug);
                    }
                }
                SpireBbBsmMove(jiggleTable,j,step);
                if(opsMode != "SOF1" && isBright) {
                    SpireBb_SetSpecDetOffsets(debug);
                }
                s = SpirePointSpectrum(res1,nCycles1,tCycle1,scansPerCycle1,res2,nCycles2,tCycle2,scansPerCycle2,tFlash,otf | step,bsmVersion,smodeVersion,specVersion,flashVersion,isBright,debug);
                srcTime = srcTime + s;
                if(j == 0) {
                    nFlash = ifloor(tFlash / double(time() - t));
                    if(nFlash == 0) {
                        nFlash = jiggleSize;
                    }
                }
            }
            np = np + 0x80;
            // increment bit 7
        }
        if(state[0] == 5) {
            // ******************** FINAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Reconfiguring Instrument");
            t = time();
            // calibrate if necessary
            if(endFlash || double(tpp) > tFlash) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                if(debug) {
                    debug_print("Move BSM to hold and do PCAL");
                }
                SpireBb_BsmMove(hold_chop,hold_jigg,debug);
                SpireProc_SFlash(flashMode,scanStart1,scanStart1,otf | step,bsmVersion,smodeVersion,flashVersion,debug);
            }
            // reconfigure back to SPEC_STBY configuration
            if(opsMode == "SOF1") {
                SpireBbSOF1End(res1,isBright,bsmModel,bsmVersion,comVersion,smodeVersion,smecVersion,specVersion,debug);
            } else {
                SpireBbSOF2End(res1,isBright,bsmModel,bsmVersion,comVersion,smodeVersion,smecVersion,specVersion,debug);
            }
            // 
        }
        if(state[0] == 6) {
            // ***********************  HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
            if(debug) {
                debug_print("Move BSM to hold and do PCAL");
            }
            SpireBb_BsmMove(hold_chop,hold_jigg,debug);
            SpireBbPcalFlash(flashMode,flashVersion,otf | np,debug);
        }
    }
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + " Instrument Reconfigured");
    SpireMsg(0,"  Instrument Reset (" + (time() - t) + " secs)");
    //
    SpireMsg(0,"Observation Completed  (" + time() + " seconds)");
    SpireMsg(0,"Note: Total time (s) = Observation Completed time - slew time + Observatory Overheads");
    assert (time() == ts[0] + ts[1]);
    //

    return {nRasters * nRasterPoints,jiggleSize,perScanOsit1,nScans1,perScanOsit2,nScans2,iround(srcTime),time() - iround(srcTime) - tslew};
}

// SpireBbSOF1End
//
// $Id$
//
// Building Block to reconfigure the instrument to SPEC_STBY mode from SOF1 mode
//
// 07/02/2009: KJK 
//        Now assumes SMEC is at scan start position (SPR-591) 
// 25/08/2009 KJK:
//        SPR Spire-1641: Now read BSM HOLD positions from 
//        SpireTable_BsmNominalSettings.txt rather than BSM.txt
//        Needed new input parameters bsmModel and bsmVersion
// 04/09/2009: MP 
//        SPR-SPIRE-1763 (problem1) Set MCU sampling rates back to STBY values;
//        Accept smecVersion as input. 
// 14/09/2009 KJK:
//       SCR Spire-1953: updated to reset detector phases
// 19/09/2009 KJK:  
//       SPR Spire-1979: Added call to SpireConfigDcuData to reset detector frequencies
//  24/09/2009 KJK:
//       SPR Spire-1978: reset biases if bright source settings used
// 29/09/2009 MP: SPR-SPIRE-2048
//       Fix bug with hardcoded SFlash for isBright. Hardcode smodeVersion=v00 
//       in call to SpireProcSetBsmSampling and SpireProcSetSmecSampling.
// 20/10/2009 KJK: SPR Spire-2062
//       Open SMEC loop 
//
/////////////////////////////////////////////////////////////////////////////
block SpireBbSOF1End SPIRE 8370 {
    string res = "H";
    bool isBright = false in [true,false];
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string comVersion = "v00";
    string smodeVersion = "v00";
    string smecVersion = "v00";
    string specVersion = "v00";
    bool debug = false;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SOF1 Reconfiguration started");
    SpireMsg(2,"          $Id$");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP to zero
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x0000)");
    Spire_SET_OBS_STEP_RAW(0x0);
    //
    // Move SMEC to HOME position
    int scanStart1 = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",res,"ScanStart",specVersion,debug);
    int smecHome = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"Home");
    SpireProc_SmecMove(smecHome,scanStart1,debug);
    //
    //  Open SMEC control loop
    SpireSendDrcuCmd(0x90440006,0);
    delay(4);
    //  
    // Move BSM to HOLD
    int bsmHoldChopPosn = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",bsmModel,"chop_0_I",bsmVersion,debug);
    int bsmHoldJiggPosn = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",bsmModel,"jigg_0_I",bsmVersion,debug);
    SpireBsmMove(bsmHoldChopPosn,bsmHoldJiggPosn);
    //
    // Set MCU sampling back to STBY
    //
    SpireProcSetBsmSampling("SPECSTBY","v00",debug);
    SpireProcSetSmecSampling("SPECSTBY","v00",debug);
    //
    //  reset detectors 
    //
    // reset bright-source biases and phases - if needed
    if(isBright) {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,"v00","v00",debug);
    } else {
        if(smodeVersion != "v00") {
            SpireProc_Set_SpecMode("SPECSTBY",isBright,"v00","v00",debug);
        } else {
            if(comVersion != "v00") {
                SpireProc_Set_SpecMode("SPECSTBY",isBright,"v00","v00",debug);
            }
        }
    }
    //
    //
    // Set Mode to SPEC_STBY
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_MODE_RAW(0x0400)");
    Spire_SET_OBS_MODE_RAW(0x400);
    // 
    // Clear OBSID/BBID to null values
    tstr = SpireTimeStr(time());
    message("5          " + tstr + "Cmd: Spire_SET_BBID_RAW(0x80000000)");
    Spire_SET_BBID_RAW(0x80000000);
    int obsId = SpireNullObsid();
    tstr = SpireTimeStr(time());
    hstr = SpireHexStr(obsId,8);
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBSID_RAW(" + hstr + ")");
    Spire_SET_OBSID_RAW(obsId);
    sync();
    //
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SOF1 Reconfiguration ended");
    SpireMsg(1,"  ..SOF1 Reconfiguration to SPEC_STBY mode (" + (time() - t) + " seconds)");
}

string procedure SpireHexStr {
    int n = 0; // input value
    int field = 4; // number of digits in hexadecimal number in output string
}{
    string s = "";
    int signbit = 0;
    int x = 0;
    string h = "";
    //
    // extract sign bit
    if(n < 0) {
        signbit = 1;
        n = n & 0x7fffffffffffffff;
    }
    //
    // convert nibble by nibble
    for(int i = 1 .. 16) {
        x = n % 0x10;
        // get next character
        if(x < 10) {
            h = "" + x;
        } else {
            if(x == 10) {
                h = "a";
            }
            if(x == 11) {
                h = "b";
            }
            if(x == 12) {
                h = "c";
            }
            if(x == 13) {
                h = "d";
            }
            if(x == 14) {
                h = "e";
            }
            if(x == 15) {
                h = "f";
            }
        }
        // perepare next nibble
        n = n / 0x10;
        if(i == 15) {
            n = n + signbit * 8;
        }
        if(i == field && n != 0) {
            field = field + 1;
        }
        // add character  to output if necessary 
        if(i <= field) {
            s = h + s;
        }
    }
    //

    return "0x" + s;
}

//
// Procedure to move the BSM to four corners of the SM16 jiggle positions table
// 25-Mar-2010 SDS: First Version
// 20-Apr-2010 SDS: V1.1
//                              Now using direct DRCU commands to move the BSM in place of the BSMMove VM
//                              Hardcoded the chop and jiggle positions of the 4 corners of the SM16 table
//                              Removed redundant jiggleTable and jiggleSize inputs
//
procedure SpireProc_SOF2Jiggle {
    int hold_chop = 2048 in [0,65535];
    int hold_jigg = 2048 in [0,65535];
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    //
    // Start MCU BSM data generation
    //
    SpireBb_StartMcuData();
    //
    // Move the BSM back to hold position 
    //
    SpireBb_BsmMove(hold_chop,hold_jigg,debug);
    //
    // Now move the BSM to each corner of the full SOF2 spectral map positions 
    //
    SpireBb_BsmMove(0x9789,0xa987,debug);
    //
    SpireBb_BsmMove(0x7dbd,0xac69,debug);
    //
    SpireBb_BsmMove(0x89aa,0x7b6e,debug);
    //
    SpireBb_BsmMove(0xa286,0x788d,debug);
    //
    // Stop MCU BSM data generation
    //
    SpireBb_StopMcuData();
}

// SpireSPEC_STBYtoREDY
//
// $id$
//
// This procedure configures the instrument into the REDY mode
// 
// The instrument should be in  the SPEC_STBY mode before execution of this observation
//
//
// 07/05/2009 KJK: First Version
// 08/06/2009  KJK: added commands for starting/stopping the SCAL Command List
// 02/07/2009 MP: Added report of tables and memory checksums (SPIRE-SCR-1527)  
//
//
procedure SpireSPEC_STBYtoREDY {
    string bsmVersion = "v00";
    string smecVersion = "v00";
    string detVersion = "v00";
    string scalVersion = "v00";
    bool debug = false;
}{
    // ----------------
    // Configure SCAL
    // ----------------
    //
    string scal = SpireProc_GetTableEntryString("SpireTable_DefaultParams.txt","mode","REDY","scalVm",scalVersion,debug);
    SpireBbSetScal(scal,-1,scalVersion,debug);
    // ----------------
    // switch off detectors
    // ----------------
    mois_comment("Procedure SPIRE SDET_OFF: to switch off the SPIRE Spectrometer");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    SpireBbSdetOff();
    //
    // setup detector sampling
    SpireBbSetDetSampling("REDY",true,detVersion,false,debug);
    mois_comment("SPIRE SPIRE_SDET_OFF Procedure Completed");
    mois_tmcheck("Ensure that parameter MODE is set to SDET_OFF");
    mois_tmcheck("Ensure SLIABITSTAT is set to 0");
    mois_tmcheck("Ensure SPECJFETSTAT is set to 0");
    mois_tmcheck("Ensure parameters SSWJFET1V to SSWJFET2V are all set to 0");
    mois_tmcheck("Ensure parameter SLWJFET1V is set to 0");
    mois_spacon("Select the TM Display for SFT PARAMETERS");
    mois_tmcheck("SLIAP5V, SLIAP9V and SLIAM9V should all be 0");
    //
    // -------------
    // switch off SMEC
    // -------------
    mois_comment("Procedure SPIRE_SMEC_OFF: to switch off the SPIRE SMEC");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    SpireBbSmecOff(smecVersion,debug);
    // Setup  SMEC sampling
    SpireBbSetSmecSampling("REDY",smecVersion,debug);
    mois_comment("SPIRE SPIRE_SMEC_OFF Procedure Completed");
    mois_tmcheck("Check that parameter SMECENCPWR is set to 0");
    mois_tmcheck("Check that parameter SMECLVDTPWR is set to 0");
    mois_tmcheck("Check that parameter MODE is set to SMEC_OFF");
    //
    // -------------
    // switch off BSM
    // -------------
    mois_comment("Procedure SPIRE_BSM_OFF: to switch off the SPIRE BSM");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    SpireBbBsmOff();
    //
    // Setup  BSM sampling
    SpireBbSetBsmSampling("REDY",bsmVersion,debug);
    mois_comment("SPIRE SPIRE_BSM_OFF Procedure Completed");
    mois_tmcheck("Check that parameter CHOPSENSPWR is set to 0");
    mois_tmcheck("Check that parameter JIGGSENSPWR is set to 0");
    mois_tmcheck("Check that parameter MODE is set to REDY");
    //
    //
    SpireBbSetScuSampling("REDY","v00",debug);
    // // 
    // //
    // Report tables and do memory checksums:
    //
    SpireBb_RepTabAndMemChecksum();
    //
    //
    // set nominal housekeeping rate
    SpireBbSetNhkSampling("REDY","v00",debug);
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndTransRespoAndDynBeamProf.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of 
// SpirePhoto_CalGCO_TransRespoAndDynBeamProf.txt
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/07 V1.0: Initial version adapted from
//                  SpireBb_EndBsmAngleCal (2009/05/05 V1.2) and
//                  SpirePhoto_CalGCO_TransRespoAndDynBeamProf (2009/03/04 V1.2)
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndTransRespoAndDynBeamProf SPIRE 14063 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndTransRespoAndDynBeamProf reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set obsstep back to 0:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP(0)");
    Spire_SET_OBS_STEP(0);
    // //
    // //
    // Set instrument back to Phot/Spec-STBY:
    //
    if(phot) {
        SpireProc_Set_PhotMode("PHTSTBY",isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    }
    // //
    // //
    // End observation:
    //
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndTransRespoAndDynBeamProf reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

//CLName: SpireBb_LoadTableSmec
//VMVersion: 2.8
//CLVersion: 1.1
//CLCVSId: $ID$
//TableId: 0x4b
//TableLength: 0xf9
//Date: 090820151445
// 23/07/2010: SDS
//                      Now only reporting static sections of table, excluding the locations for storing 
//                      the computed encoder signal offsets 1 & 2.  
//                      See SPIRE-SCR-2761
block SpireBb_LoadTableSmec SPIRE 3349 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableSmec started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0x4b
    Spire_SET_TABLE(0x4b,0xf9);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x4b,0x0,2,[{0x3000000a},{0x30000083}]);
    delay(t_min);
    //update table command call for table index 0x000a
    Spire_UPDATE_TABLE(0x4b,0xa,38,[{0x12000014},{0x501},{0x12000015},{0x4b01},{0x53020014},{0x2000000},{0x20050001},{0x200a0000},{0x1200000b},{0x0},{0x120000ff},{0x21},{0x12000016},{0x0},{0x12000017},{0x0},{0x80007d0},{0x1000001},{0x8000bb8},{0x12000000},{0x1},{0x12000001},{0x49},{0x12000002},{0x2},{0x12000003},{0xbb8},{0x60640001},{0xb000014},{0x1000000},{0x9000005},{0x12000014},{0x501},{0x12000015},{0x4b02},{0x53020014},{0x2000000},{0x12000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x4b,0x30,38,[{0x80},{0x61060002},{0x2000000},{0x12000000},{0x82},{0x62060002},{0x49010082},{0x49020083},{0x20000001},{0x18000000},{0x80000000},{0x32000002},{0x3000000d},{0x20000002},{0x18000000},{0x80000000},{0x32000002},{0x30000008},{0x1000000b},{0x18000001},{0xffff},{0x21160116},{0x18000002},{0xffff},{0x21170217},{0x1100000a},{0x320affe5},{0x8000bb8},{0x12000014},{0x501},{0x12000015},{0x4b03},{0x53020014},{0x2000000},{0x320b0008},{0x12000000},{0x5000},{0x12000001}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x4b,0x56,38,[{0x4b00},{0x53020000},{0x2000000},{0x30000020},{0x2416160b},{0x2417170b},{0x80007d0},{0x1000001},{0x8000bb8},{0x12000000},{0x1},{0x12000001},{0x58},{0x20020016},{0x12000003},{0xbb8},{0x60640001},{0x12000000},{0x1},{0x12000001},{0x5a},{0x20020017},{0x12000003},{0xbb8},{0x60640001},{0x80007d0},{0x1000000},{0x80007d0},{0x4b160082},{0x4b170083},{0x120000ff},{0x7},{0x12000000},{0x82},{0x61070002},{0x12000014},{0x501},{0x12000015}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x4b,0x7c,38,[{0x4b04},{0x53020014},{0x2000000},{0x7f000000},{0x28050000},{0x28060000},{0x0},{0x0},{0x12000014},{0x501},{0x12000015},{0x4b11},{0x53020014},{0x2000000},{0x200a0002},{0x12000003},{0xbb8},{0x21160001},{0x22170001},{0x80007d0},{0x1000001},{0x12000000},{0x1},{0x12000001},{0x844},{0x12000002},{0x0},{0x60640001},{0x80007d0},{0x1000000},{0x9000003},{0x3200002c},{0x20020001},{0x14000001},{0x1},{0x3200002f},{0x12000014},{0x501}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x4b,0xa2,38,[{0x12000015},{0x4b12},{0x53020014},{0x2000000},{0x80007d0},{0x1000001},{0x12000000},{0x1},{0x12000001},{0x861},{0x12000002},{0x0},{0x60640001},{0x80007d0},{0x1000000},{0x32000024},{0x35010016},{0x30000029},{0x34010017},{0x30000027},{0x12000014},{0x501},{0x12000015},{0x4b13},{0x53020014},{0x2000000},{0x80007d0},{0x1000001},{0x12000000},{0x1},{0x12000001},{0x4d},{0x2002000a},{0x60640001},{0x80007d0},{0x1000000},{0x3000002c},{0x12000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x4b,0xc8,38,[{0x5000},{0x12000001},{0x4b10},{0x53020000},{0x2000000},{0x30000025},{0x12000000},{0x5000},{0x12000001},{0x4b11},{0x53030000},{0x2000000},{0x3000001e},{0x12000000},{0x5000},{0x12000001},{0x4b12},{0x53020000},{0x2000000},{0x30000017},{0x20020001},{0x12000000},{0x5000},{0x12000001},{0x4b13},{0x20030016},{0x20040017},{0x53050000},{0x2000000},{0x80007d0},{0x1000001},{0x12000000},{0x1},{0x12000001},{0x44},{0x12000002},{0x6},{0x12000003}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x4b,0xee,11,[{0xbb8},{0x60640001},{0x80007d0},{0x1000000},{0x12000014},{0x501},{0x12000015},{0x4b14},{0x53020014},{0x2000000},{0x7f000000}]);
    delay(t_min);
    //
    // Dump table contents in two stages 
    // Report the first 130 words  (0x82 words from index 0)
    //  
    //
    Spire_REPORT_TABLE(0x4b,0x0,0x82);
    delay(4);
    // 
    // Skip indices 130 and 131 (i.e. 0x82 and 0x83) and report remainder of table
    //
    Spire_REPORT_TABLE(0x4b,0x84,0x75);
    delay(4);
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableSmec ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

// CVS comments  : $Id: DMC_phot_2_3_chop.txt,v 1.5 2007/04/25 15:14:03 dcesarsk Exp $ 
// Missionphase  : 
//
// Purpose       : Two or three position chopping followed
//             by calibration readouts chopping between CS1 and CS2 
//             
//
// Author        : Helmut Feuchtgruber
// CUS script    : Diego A. Cesarsky
// CVS file      : DMC_phot_2_3_chop.txt from AOT code
//
// Arguments     : 
//             nb_SRC_REF        Number of SRC->CHOPP1->SRC->CHOPP2 cycles
//             chop_pos_SRC      Position of chopper to see SRC
//             nb_rdouts_plateau Number of readouts per chopper plateau
//             chop_pos_REF1     Position of chopper for REF1
//             chop_pos_REF2     Position of chopper for REF2
//             nb_cycles_obs_cal Number of times (OBS = CAL)
//             nb_CS1_CS2        Number of CS1->CS2 cycles
//             chop_pos_CS1      Chopper position for CS1
//             chop_pos_CS2      Chopper position for CS2
//
// Description : Chopped observations of SRC in the manner:
//                     SRC->REF1->SRC->REF2 
//             followed by a calibration sequence using the internal 
//             blackbodies 
//                     CS1 -> CS2
//             User can specify the number of source observing cycles 
//            (nb_SRC_REF), the number of calibration cycles (nb_CS1_CS2) 
//             and how many times the whole sequence shall be repeated
//             (nb_cycles_obs_cal). 
//             The number of readouts per quiescent chopper position is 
//             the same (nb_rdouts_plateau) within each cycle  
//             
//
// Dependencies  : Stand alone DEC/MEC sequence  
//             
// Comments      : Follows line by line 4.1.1 in PACS-ME-LI-005
//
// Version       : 0.1 21-Jan-2004 Creation by DAC
// History       : 0.2 12-Oct-2004 Use only time related arguments
//             0.3 18-Oct-2004 Normalized variable names
//             0.4  9-Nov-2004 Return array containing 4 times.
//                             time[0] = total SRC time
//                             time[1] = total CAL time
//                             time[2] = total overhead time
//                             time[3] = total DMC time (by Version 0.1)
//             0.5 22-nov-2006 Removed debug_print
//             0.6 14-mar-2007 WAIT=1 for chopper are useful
//           :
int[] procedure DMC_phot_2_3_chop {
    int nb_SRC_REF = 1; // p01 Nb of cycles SRC->REF1->SRC->REF2
    int nb_rdouts_plateau = 16; // p03 Nb of readouts per chopper plateau
    int nb_cycles_obs_cal = 1; // p06 Nb of repetions of OBS-CAL cycle
    int nb_CS1_CS2 = 0; // p07 Nb of cycles CS1->CS2
}{
    int duree_SRC = 0;
    int duree_REF = 0;
    int duree_CAL = 0;
    int duree_OVR = 0;
    // Start tallying the duration (measured in number of readouts)
    int duration_rdouts = 0;
    // WAIT 1 ; have a defined start 
    duration_rdouts = duration_rdouts + 1;
    duree_OVR = duree_OVR + 1;
    // LABEL 0 ; set Label to 0 
    // WAIT 1 ; have a defined start 
    duration_rdouts = duration_rdouts + 1;
    duree_OVR = duree_OVR + 1;
    // Outermost LOOP on nb_cycles_obs_cal
    for(int obs_cal_loop = 1 .. nb_cycles_obs_cal) {
        //  Inner LOOP on nb_SRC_REF 
        for(int obs_loop = 1 .. nb_SRC_REF) {
            // WAIT 1 ; sync. for chopper 
            duration_rdouts = duration_rdouts + 1;
            duree_SRC = duree_SRC + 1;
            // MOVE_CHOPPER_ABSOLUTE chop_pos_SRC; chopper to chop_pos_SRC 
            // LABEL 1 ; start quadruple 
            // WAIT nb_rdouts_plateau ; take nb_rdouts_plateau images 
            duration_rdouts = duration_rdouts + nb_rdouts_plateau;
            duree_SRC = duree_SRC + nb_rdouts_plateau;
            // WAIT 1 ; sync. for chopper 
            duration_rdouts = duration_rdouts + 1;
            duree_SRC = duree_SRC + 1;
            // MOVE_CHOPPER_ABSOLUTE chop_pos_REF1; chopper to chop_pos_REF1 
            // LABEL 3 ; next chopper position 
            // WAIT nb_rdouts_plateau ; take nb_rdouts_plateau images 
            duration_rdouts = duration_rdouts + nb_rdouts_plateau;
            duree_REF = duree_REF + nb_rdouts_plateau;
            // WAIT 1 ; sync. for chopper 
            duration_rdouts = duration_rdouts + 1;
            duree_SRC = duree_SRC + 1;
            // MOVE_CHOPPER_ABSOLUTE chop_pos_SRC; chopper to chop_pos_SRC 
            // LABEL 1 ; first chopper position 
            // WAIT nb_rdouts_plateau ; take nb_rdouts_plateau images 
            duration_rdouts = duration_rdouts + nb_rdouts_plateau;
            duree_SRC = duree_SRC + nb_rdouts_plateau;
            // WAIT 1 ; sync. for chopper 
            duration_rdouts = duration_rdouts + 1;
            duree_SRC = duree_SRC + 1;
            // MOVE_CHOPPER_ABSOLUTE chop_pos_REF2 ; move chopper to chop_pos_REF2 
            // LABEL 5 ; chopper position 3 
            // WAIT nb_rdouts_plateau ; take nb_rdouts_plateau images 
            duration_rdouts = duration_rdouts + nb_rdouts_plateau;
            duree_REF = duree_REF + nb_rdouts_plateau;
            // End inner loop on nb_SRC_REF
            // END_LOOP ; end loop measurement 
        }
        //  Inner LOOP on nb_CS1_CS2 
        for(int cal_loop = 1 .. nb_CS1_CS2) {
            // WAIT 1 ; sync. for chopper 
            duration_rdouts = duration_rdouts + 1;
            duree_CAL = duree_CAL + 1;
            // MOVE_CHOPPER_ABSOLUTE chop_pos_CS1 ; move chopper to CS1 
            // LABEL 65 ; chopper to CS1 
            // WAIT nb_rdouts_plateau ; take nb_rdouts_plateau images 
            duration_rdouts = duration_rdouts + nb_rdouts_plateau;
            duree_CAL = duree_CAL + nb_rdouts_plateau;
            // WAIT 1 ; sync. for chopper 
            duration_rdouts = duration_rdouts + 1;
            duree_CAL = duree_CAL + 1;
            // MOVE_CHOPPER_ABSOLUTE chop_pos_CS2 ; move chopper to CS2 
            // LABEL 129 ; chopper to CS2 
            // WAIT nb_rdouts_plateau ; take nb_rdouts_plateau images 
            duration_rdouts = duration_rdouts + nb_rdouts_plateau;
            duree_CAL = duree_CAL + nb_rdouts_plateau;
            // End inner loop on nb_CS1_CS2
            // END_LOOP ; end loop calibration
        }
        // End outermost loop on nb_cycles_obs_cal
        // END_LOOP ; end main loop
    }
    // WAIT 1 ; complete last plateau 
    duration_rdouts = duration_rdouts + 1;
    duree_OVR = duree_OVR + 1;
    // LABEL 0 ; no sequence anymore 
    // END_SEQUENCE
    // Define return array
    int[] time_array = [duration_rdouts,duree_SRC,duree_REF,duree_CAL,duree_OVR];
    //    debug_print("DMC_phot_2_3_chop: " + time_array);
    // Return the array of times

    return time_array;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_StopMcuEngData.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to stop generation of MCU engineering dataTM packets
//
///////////////////////////////////////////////////////////////////////////
//
// K. King:
// 2009/10/21: First Version 
//                  Created for SPR Spire-2062
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_StopMcuEngData {
}{
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    // Start procedure:
    //
    message("4    " + time() + ": SpireProc_Set_StopMcuEngData started");
    message("4          $Id: $");
    //
    //
    // Stop MCU Eng data
    SpireSendDrcuCmd(0x91c10000,0);
    delay(2);
    //
    // Flush fifo
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x2000)");
    Spire_FLUSH_FIFO_RAW(0x2000);
    delay(2);
    //
    // clear MCU Eng sampling
    SpireSendDrcuCmd(0x91c40000,0);
    //
    //
    // End procedure:
    //
    sync();
    message("4    " + time() + ": SpireProc_Set_StopMcuEngData ended");
    //
}

// SpirePHOT_STBYtoREDY
//
// $id$
//
// This procedure configures the instrument into the REDY mode
// 
// The instrument should be in  the PHOT_STBY mode before execution of this observation
//
//
// 08/11/2007 KJK: removed StartObs and EndObs building blocks from the engineering procedure
// 07/05/2009 KJK: 
//           now switch off detectors before switching off the BSM
//           added debug as input parameter
//  09/06/2009  KJK:
//           added ptcVersion input parameter
//           now sets PTC status
// 02/07/2009 MP: Added report of tables and memory checksums (SPIRE-SCR-1527)  
//
//
procedure SpirePHOT_STBYtoREDY {
    string bsmVersion = "v00";
    string detVersion = "v00";
    string ptcVersion = "v00";
    bool debug = false;
}{
    // ----------------
    // Configure PTC
    // ----------------
    //
    string ptc = SpireProc_GetTableEntryString("SpireTable_DefaultParams.txt","mode","REDY","ptcVm",ptcVersion,debug);
    SpireBbSetPtc(ptc,ptcVersion,debug);
    //
    // ----------------
    // switch off detectors
    // ----------------
    mois_comment("Procedure SPIRE PDET_OFF: to switch off the SPIRE Photometer");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    SpireBbPdetOff();
    //
    // setup detector sampling
    SpireBbSetDetSampling("REDY",true,detVersion,false,debug);
    mois_comment("SPIRE SPIRE_PDET_OFF Procedure Completed");
    mois_tmcheck("Ensure that parameter MODE is set to PDET_OFF");
    mois_tmcheck("Ensure PLIABITSTAT is set to 0");
    mois_tmcheck("Ensure PSWJFETSTAT is set to 0");
    mois_tmcheck("Ensure PMLWJFETSTAT is set to 0");
    mois_tmcheck("Ensure parameters PSWJFET1V to PSWJFET6V are all set to 0");
    mois_tmcheck("Ensure parameters PMWJFET1V to PSWJFET4V are all set to 0");
    mois_tmcheck("Ensure parameters PLWJFET1V & PSWJFET2V are set to 0");
    mois_spacon("Select the TM Display for SFT PARAMETERS");
    mois_tmcheck("PLIAP5V, PLIAP9V and PLIAM9V should all be 0");
    //
    // ----------------
    // switch off BSM
    // ----------------
    mois_comment("Procedure SPIRE_BSM_OFF: to switch off the SPIRE BSM");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    SpireBbBsmOff();
    //
    // Setup  BSM sampling
    SpireBbSetBsmSampling("REDY",bsmVersion,debug);
    mois_comment("SPIRE SPIRE_BSM_OFF Procedure Completed");
    mois_tmcheck("Check that parameter CHOPSENSPWR is set to 0");
    mois_tmcheck("Check that parameter JIGGSENSPWR is set to 0");
    mois_tmcheck("Check that parameter MODE is set to REDY");
    //
    //
    SpireBbSetScuSampling("REDY","v00",debug);
    //
    // // 
    // //
    // Report tables and do memory checksums:
    //
    SpireBb_RepTabAndMemChecksum();
    //
    // set nominal housekeeping rate
    SpireBbSetNhkSampling("REDY","v00",debug);
}

// SpireBbJiggle
//
// $id$
//
// execute jiggle operations
//
// returns the actual time on-source
//
//  K.J. King
//
// 04 November 2008: added data_rate commands
//
// Sunil Sidher
// 07 Aug 2009: v1.4 - Increased delay by 2 seconds before flushing the FIFOs (SPIRE SPR-1772)
// 12 Aug 2009 KJK:
//        SPIRE-1804: updated to get chop parameters from SpireTable_ChopParams.txt
//        Updated to use SpireTable_CommandListst.txt
//
double block SpireBbJiggle SPIRE 8993 {
    string opsMode = "" in ["POF2","POF3","POF4"];
    int jiggleTable = 0; // number of jiggle table
    int startPosn = 0; // starting position in jiggle map
    int nPosns = 1; // number of jiggle positions to execute
    int nRepeats = 1; // number of times to repeat this jiggle operation
    int step = 0; // step number
    string opsVersion = "v00";
    string chopVersion = "v00";
    bool debug = false;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Jiggle started");
    SpireMsg(2,"          $Id:$");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP 
    hstr = SpireHexStr(step,4);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(" + hstr + ")");
    Spire_SET_OBS_STEP_RAW(step);
    //
    //  set up detectors for operations
    //
    //SpireConfigDcuData(opsMode);
    //
    // execute jiggle
    //
    int id = ilookup("SpireTable_CommandLists.txt","JiggleMap","Id");
    //  number of table containing the jiggle command list
    int index = ilookup("SpireTable_CommandLists.txt","JiggleMap","Index");
    //  istart point in table containing the jiggle command list
    int nParms = ilookup("SpireTable_CommandLists.txt","JiggleMap","Nparms");
    //  number of parameters to the jiggle command list
    int nChops = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"NChops",opsVersion,debug);
    //  number of chop cycles per jiggle position
    int tChop = SpireProc_GetTableEntryInt("SpireTable_ChopParams.txt","mode",opsMode,"Period",chopVersion,debug);
    //  period of chop cycle
    int dcuFrame = SpireProc_GetTableEntryInt("SpireTable_ChopParams.txt","mode",opsMode,"DcuFrame",chopVersion,debug);
    //  DCU Sample Mode
    int nDcu = SpireProc_GetTableEntryInt("SpireTable_ChopParams.txt","mode",opsMode,"DcuSamples",chopVersion,debug);
    //  number of DCU Samples per chop position 
    int tDelay = SpireProc_GetTableEntryInt("SpireTable_ChopParams.txt","mode",opsMode,"DcuDelay",chopVersion,debug);
    //  delay to start of DCU sampling
    int nBsm = SpireProc_GetTableEntryInt("SpireTable_ChopParams.txt","mode",opsMode,"BsmSamples",chopVersion,debug);
    //  number of BSM samples per chop position
    //
    //  issue VM command 
    //
    {int}[] parms = [{jiggleTable},{startPosn * 2},{nPosns * 2},{nChops},{tChop},{dcuFrame},{nDcu},{tDelay},{nBsm},{nRepeats}];
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM_RAW(" + id + "," + index + "," + nParms + "," + parms + ")");
    Spire_RUN_VM_RAW(id,index,nParms,parms);
    //  set datarate
    double rate = 0.0;
    rate = dlookup("Datarates.txt",opsMode,"DCU");
    rate = rate + dlookup("Datarates.txt",opsMode,"BSM");
    data_rate(rate);
    // calc time to perform a jiggle operation
    int nOps = nPosns * nChops * nRepeats;
    // Add 2 seconds to the estimated time before flushing the FIFOs 
    double opsTime = double(nOps) * double(tChop) / 1000000.0 + 2.0;
    // wait to end of jiggle operation
    delay(iceil(opsTime));
    data_rate(0.0);
    //
    // flush data
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x3000)");
    Spire_FLUSH_FIFO_RAW(0x3000);
    delay(2);
    double srcTime = double(nOps) * double(tChop) / 1000000.0;
    //
    // effective integration time per jiggle operation
    //
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Jiggle ended");
    SpireMsg(1,"  ..Jiggle (" + (time() - t) + " seconds)");
    //

    return srcTime;
}

// SpireBbPdetOn
//
// $id$
//
// This building block switches on the photometer detectors
// 
// The instrument should be in  the REDY mode before execution of this building block
//
//  21.08.2008: KK Updated to new switch on sequence using nominal and optimum JFet voltages
//
// 11/11/2008: KJK Updated to set offsets after switchon
//
// 02/12/2008 MP: now DCU data generation is stopped before setting the 
//                detector offsets and FIFOs are flushed before resetting 
//                the detector offset (problem raised after TB/TV as 
//                SPIRE-SCR 1052)
//
// 27/04/2009 KJK: 
//         Updated to use new NominalSettings Cal Tables
//         version and debug passed as parameters
//
//
block SpireBbPdetOn SPIRE 1280 {
    int jfet_heater_V = 0; // By default don't switch on jfet heater 
    string detVersion = "v00";
    string vssVersion = "v00";
    bool debug = false;
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB PdetOn started");
    SpireMsg(2,"          $Id$");
    //
    int cmd = 0x0;
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP to 0
    SpireSetObsStep(0x0);
    //
    // Retrieve bias settings
    //
    int biasmode = ilookup("SpireTable_DefaultParams.txt","v00","biasMode");
    int mclkdiv = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","mclkDiv",detVersion,debug);
    int biasdiv = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","biasDiv",detVersion,debug);
    //
    // Retrive array nominal settings for PHTSTBY mode
    //
    int psw_bias = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","pswBias",detVersion,debug);
    int psw_phase = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","pswPhase",detVersion,debug);
    int pmw_bias = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","pmwBias",detVersion,debug);
    int pmw_phase = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","pmwPhase",detVersion,debug);
    int plw_bias = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","plwBias",detVersion,debug);
    int plw_phase = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","plwPhase",detVersion,debug);
    int ptc_bias = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","ptcBias",detVersion,debug);
    int ptc_phase = SpireProc_GetTableEntryInt("SpireTable_PhotModeParams.txt","mode","PHTSTBY","ptcPhase",detVersion,debug);
    //
    // ---
    // Building block starts
    // ---
    // Set MODE to PDET_ON
    SpireSetObsMode("PDET_ON");
    delay(1);
    SpireSetObsStep(0x1);
    delay(1);
    //
    // Switch ON PLIAs
    //
    SpireSendDrcuCmd(0xa0870005,0);
    delay(1);
    //
    // Set bias mode ,bias frequency and sampling frequency
    //
    SpireSendDrcuCmd(0x84000000 + biasmode,0);
    SpireSendDrcuCmd(0x84190000 + mclkdiv,0);
    delay(1);
    SpireSendDrcuCmd(0x84180000 + biasdiv,0);
    //
    // Switch on with small bias (~ 1 mVrms) across the arrays
    //
    SpireSendDrcuCmd(0x84010002,0);
    delay(1);
    SpireSendDrcuCmd(0x84020002,0);
    SpireSendDrcuCmd(0x84030002,0);
    delay(1);
    SpireSendDrcuCmd(0x84040002,0);
    //
    // Set demodulation phase shift
    //
    SpireSendDrcuCmd(0x841a0000 + psw_phase,0);
    delay(1);
    SpireSendDrcuCmd(0x841b0000 + pmw_phase,0);
    SpireSendDrcuCmd(0x841c0000 + plw_phase,0);
    delay(1);
    SpireSendDrcuCmd(0x841d0000 + ptc_phase,0);
    delay(1);
    //
    // Automatic offset setting + get offsets
    //
    SpireSendDrcuCmd(0x843c0010,0);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(2);
    SpireSendDrcuCmd(0x843e0000,0);
    SpireSendDrcuCmd(0x843c0018,0);
    delay(1);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(3);
    SpireSendDrcuCmd(0x843e0000,0);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(1);
    //
    // Start PF data generation
    //
    SpireSendDrcuCmd(0x843c0000,0);
    SpireSendDrcuCmd(0x843d0000,0);
    delay(1);
    SpireSendDrcuCmd(0x843e0001,0);
    //
    // If necessary switch ON jfet heater
    if(jfet_heater_V != 0) {
        SpireSendDrcuCmd(0x84110000 + jfet_heater_V,0);
        delay(60);
        SpireSendDrcuCmd(0x84110000,0);
    } else {
        delay(3);
    }
    //
    // Apply Startup Vss voltages
    //
    // Read the startup Vss settings 
    // 
    //PSW
    int psw_jfet_Vss1 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","psw_vss1",vssVersion,debug);
    int psw_jfet_Vss2 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","psw_vss2",vssVersion,debug);
    int psw_jfet_Vss3 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","psw_vss3",vssVersion,debug);
    int psw_jfet_Vss4 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","psw_vss4",vssVersion,debug);
    int psw_jfet_Vss5 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","psw_vss5",vssVersion,debug);
    int psw_jfet_Vss6 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","psw_vss6",vssVersion,debug);
    // PMW
    int pmw_jfet_Vss1 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","pmw_vss1",vssVersion,debug);
    int pmw_jfet_Vss2 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","pmw_vss2",vssVersion,debug);
    int pmw_jfet_Vss3 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","pmw_vss3",vssVersion,debug);
    int pmw_jfet_Vss4 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","pmw_vss4",vssVersion,debug);
    //PLW
    int plw_jfet_Vss1 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","plw_vss1",vssVersion,debug);
    int plw_jfet_Vss2 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","plw_vss2",vssVersion,debug);
    // PTC
    int ptc_jfet_Vss = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","startup","ptc_vss1",vssVersion,debug);
    //
    //  Apply PSW Vss voltages followed by PSW Vdd
    //
    // PSW JFET1 
    SpireSendDrcuCmd(0x84050000 + psw_jfet_Vss1,0);
    SpireSendDrcuCmd(0x84120001,0);
    delay(1);
    // PSW JFET2	
    SpireSendDrcuCmd(0x84060000 + psw_jfet_Vss2,0);
    SpireSendDrcuCmd(0x84120003,0);
    delay(1);
    // PSW JFET3	
    SpireSendDrcuCmd(0x84070000 + psw_jfet_Vss3,0);
    SpireSendDrcuCmd(0x84120007,0);
    delay(1);
    // PSW JFET4	
    SpireSendDrcuCmd(0x84080000 + psw_jfet_Vss4,0);
    SpireSendDrcuCmd(0x8412000f,0);
    delay(1);
    // PSW JFET5	
    SpireSendDrcuCmd(0x84090000 + psw_jfet_Vss5,0);
    SpireSendDrcuCmd(0x8412001f,0);
    delay(1);
    // PSW JFET6	
    SpireSendDrcuCmd(0x840a0000 + psw_jfet_Vss6,0);
    SpireSendDrcuCmd(0x8412003f,0);
    delay(1);
    //
    // Apply PMW Vss voltages followed by PMW Vdd
    //
    // PMW JFET1
    SpireSendDrcuCmd(0x840b0000 + pmw_jfet_Vss1,0);
    SpireSendDrcuCmd(0x84130001,0);
    delay(1);
    // PMW JFET2
    SpireSendDrcuCmd(0x840c0000 + pmw_jfet_Vss2,0);
    SpireSendDrcuCmd(0x84130003,0);
    delay(1);
    // PMW JFET3
    SpireSendDrcuCmd(0x840d0000 + pmw_jfet_Vss3,0);
    SpireSendDrcuCmd(0x84130007,0);
    delay(1);
    // PMW JFET4	
    SpireSendDrcuCmd(0x840e0000 + pmw_jfet_Vss4,0);
    SpireSendDrcuCmd(0x8413000f,0);
    delay(1);
    //
    // Apply PLW Vss voltages followed by PLW Vdd
    //
    // PLW JFET1
    SpireSendDrcuCmd(0x840f0000 + plw_jfet_Vss1,0);
    SpireSendDrcuCmd(0x8413001f,0);
    // PLW JFET2
    SpireSendDrcuCmd(0x84100000 + plw_jfet_Vss2,0);
    SpireSendDrcuCmd(0x8413003f,0);
    delay(1);
    //
    // Apply TC Vss voltage followed by Vdd
    //
    SpireSendDrcuCmd(0x84140000 + ptc_jfet_Vss,0);
    SpireSendDrcuCmd(0x8413007f,0);
    //
    // Wait 30 seconds before setting nominal biases 
    //
    delay(30);
    SpireSendDrcuCmd(0x84010000 + psw_bias,0);
    delay(1);
    SpireSendDrcuCmd(0x84020000 + pmw_bias,0);
    delay(1);
    SpireSendDrcuCmd(0x84030000 + plw_bias,0);
    delay(1);
    SpireSendDrcuCmd(0x84040000 + ptc_bias,0);
    delay(1);
    //
    // Stop DCU data, apply automatic offset setting + get offsets
    // 
    SpireSendDrcuCmd(0x843e0000,0);
    delay(1);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(3);
    SpireSendDrcuCmd(0x843c0010,0);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(2);
    SpireSendDrcuCmd(0x843e0000,0);
    SpireSendDrcuCmd(0x843c0018,0);
    delay(1);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(3);
    SpireSendDrcuCmd(0x843e0000,0);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(1);
    //
    // Start PF data generation
    //
    SpireSendDrcuCmd(0x843c0000,0);
    SpireSendDrcuCmd(0x843d0000,0);
    delay(1);
    SpireSendDrcuCmd(0x843e0001,0);
    //
    // Wait 30 seconds before setting the optimum Vss values
    //
    delay(30);
    //
    // Read the optimum Vss settings (lowest noise)
    // 
    //PSW
    int psw_jfet_OVss1 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","psw_vss1",vssVersion,debug);
    int psw_jfet_OVss2 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","psw_vss2",vssVersion,debug);
    int psw_jfet_OVss3 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","psw_vss3",vssVersion,debug);
    int psw_jfet_OVss4 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","psw_vss4",vssVersion,debug);
    int psw_jfet_OVss5 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","psw_vss5",vssVersion,debug);
    int psw_jfet_OVss6 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","psw_vss6",vssVersion,debug);
    //
    // PMW
    int pmw_jfet_OVss1 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","pmw_vss1",vssVersion,debug);
    int pmw_jfet_OVss2 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","pmw_vss2",vssVersion,debug);
    int pmw_jfet_OVss3 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","pmw_vss3",vssVersion,debug);
    int pmw_jfet_OVss4 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","pmw_vss4",vssVersion,debug);
    //
    // PLW
    int plw_jfet_OVss1 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","plw_vss1",vssVersion,debug);
    int plw_jfet_OVss2 = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","plw_vss2",vssVersion,debug);
    //
    // PTC
    int ptc_jfet_OVss = SpireProc_GetTableEntryInt("SpireTable_PhotVssSettings.txt","model","optimum","ptc_vss1",vssVersion,debug);
    // 
    // Now set the optimum Vss values for all the JFETs
    //
    // PSW JFET1 
    SpireSendDrcuCmd(0x84050000 + psw_jfet_OVss1,0);
    // PSW JFET2
    SpireSendDrcuCmd(0x84060000 + psw_jfet_OVss2,0);
    delay(1);
    // PSW JFET3	
    SpireSendDrcuCmd(0x84070000 + psw_jfet_OVss3,0);
    // PSW JFET4	
    SpireSendDrcuCmd(0x84080000 + psw_jfet_OVss4,0);
    delay(1);
    // PSW JFET5	
    SpireSendDrcuCmd(0x84090000 + psw_jfet_OVss5,0);
    // PSW JFET6	
    SpireSendDrcuCmd(0x840a0000 + psw_jfet_OVss6,0);
    delay(1);
    // PMW JFET1
    SpireSendDrcuCmd(0x840b0000 + pmw_jfet_OVss1,0);
    // PMW JFET2
    SpireSendDrcuCmd(0x840c0000 + pmw_jfet_OVss2,0);
    delay(1);
    // PMW JFET3
    SpireSendDrcuCmd(0x840d0000 + pmw_jfet_OVss3,0);
    // PMW JFET4	
    SpireSendDrcuCmd(0x840e0000 + pmw_jfet_OVss4,0);
    delay(1);
    // PLW JFET1
    SpireSendDrcuCmd(0x840f0000 + plw_jfet_OVss1,0);
    // PLW JFET2
    SpireSendDrcuCmd(0x84100000 + plw_jfet_OVss2,0);
    delay(1);
    // PTC JFET Vss
    SpireSendDrcuCmd(0x84140000 + ptc_jfet_OVss,0);
    //
    //
    delay(10);
    // stop data collection
    SpireSendDrcuCmd(0x843e0000,0);
    //
    // flush data from FIFOs
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(1);
    delay(3);
    //
    SpireSetObsMode("PHOTSTBY");
    SpireSetObsStep(0x0);
    sync();
    //
    // completion
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB PdetOn   ended");
    SpireMsg(1,"  ..PDET Switch On (" + (time() - t0) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Exec_SpecPhaseUp.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to loop through a list of phase values for
//  the 'Spec Phase Up' task
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/11 V0.1: Initial version adapted from
//                  SpireProc_Exec_PhotPhaseUp.txt (2008/07/03 V0.2)
//                  Mode_ILT_PERF_DPH_S.txt (v1.4 2008/01/31 20:24:33)
// 2009/02/19 V0.2: Add debug_print as input and pass to low level scripts.
//                  Do not set first phase, now done during SLEW. Add
//                  dcuData to input. 
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Exec_SpecPhaseUp {
    int[] raw_phase_list = [127,128,129,130,131,132,133]; // Raw phase list (0-255) [dec(HEX)]
    int ftime = 10; // Time at each bias level [sec]
    bool dcuData = false; // Is (==tick) the DCU currently sampled? 
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Setup bias amplitude and frequency:
    // --> during slew!!
    //
    // //
    // //
    // Start the phase loop:
    //
    for(int l = 0 .. length(raw_phase_list) - 1) {
        // //
        // //
        // Set phases for arrays:
        //
        if(l > 0) {
            SpireBb_SpecFSetPhase(raw_phase_list[l],raw_phase_list[l],debug);
        }
        // //
        // //
        // Stop DCU data before resetting offsets:
        //
        SpireBb_StopDcuData();
        // //
        // //
        // Set offsets:
        //
        SpireBb_SpecOffsetAuto(dcuData,debug);
        // //
        // //
        // Take data:
        //
        SpireBb_SpecFTakeData(ftime,debug);
        //
        //
        if(debug) {
            debug_print("Phase finished is: " + raw_phase_list[l]);
        }
    }
    //
    //
}

// SpireSpecRasterPositions
//
// $Id: SpireSpecRasterPositions.txt,v 1.3 2007/01/15 15:05:05 kking Exp $ 
// 
// A procedure to calculate the positions of spectrometer raster points to cover a given area
//
{double[],double[]} procedure SpireSpecRasterPositions {
    string opsMode = "SOF1" in ["SOF1","SOF2","SOF2_int"]; // operations mode
    double offsetY = 0.0;
    double offsetZ = 0.0;
    double width = 0.0;
    double height = 0.0;
}{
    double pi = asin(1.0) * 2.0;
    // read in raster positioning parameters
    double yShiftUnit = dlookup("OpsParms.txt",opsMode,"YShiftUnit");
    // units for shift in Y direction
    double zShiftUnit = dlookup("OpsParms.txt",opsMode,"ZShiftUnit");
    // units for shift in Z direction
    double yStep = dlookup("OpsParms.txt",opsMode,"YStep") * yShiftUnit;
    // step in Y direction
    double zStep = dlookup("OpsParms.txt",opsMode,"ZStep") * zShiftUnit;
    // step in Z direction
    double yRowSep = dlookup("OpsParms.txt",opsMode,"YRowSep") * yShiftUnit;
    // row separation in Y direction
    double zRowSep = dlookup("OpsParms.txt",opsMode,"ZRowSep") * zShiftUnit;
    // row separation in Z direction
    //
    // angle of rows with respect to YZ
    double yz_angle = atan(yStep / zStep);
    //
    // calculate the separation between points along and between rows
    double separation_along_row = sqrt(yStep * yStep + zStep * zStep);
    double separation_between_row = sqrt(yRowSep * yRowSep + zRowSep * zRowSep) * sin(yz_angle + atan(yRowSep / zRowSep));
    // calculate number of raster positions corresponding to length and height
    //   accounting for extra coverage at the ends on rows and columns
    int number_length = iceil((width - separation_along_row / 2.0) / separation_along_row);
    int number_height = iceil((height - separation_between_row / 2.0) / separation_between_row);
    // Check if just doing a single row. If so include the 1/2 separation on the left hand side
    if(number_height == 0) {
        number_length = iceil((width - separation_along_row) / separation_along_row);
    }
    // Check the supplied width and height are not less than 1/2 separation of raster points
    if(width < separation_along_row / 2.0) {
        number_length = 0;
    }
    if(height < separation_between_row / 2.0) {
        number_height = 0;
    }
    // now adjust the width, height to be the actual one covered (using
    // distance between rows and along rows
    width = double(number_length) * separation_along_row + separation_along_row / 2.0;
    // in the case of a single row, add an extra half separation for the left hand side.
    if(number_height == 0) {
        width = width + separation_along_row / 2.0;
    }
    // do not add "separation_between_row/2.0" here because this does not affect the starting position for height
    height = double(number_height) * separation_between_row;
    //
    // calculate the actual parallelogram covered
    // get the parallelogram angle using cosine rule
    double a = sqrt(pow(2.0 * zRowSep,2.0) + pow(2.0 * yRowSep,2.0));
    double b = sqrt(yStep * yStep + zStep * zStep);
    double c = sqrt(pow(yStep + 2.0 * yRowSep,2.0) + pow(2.0 * zRowSep - zStep,2.0));
    double parallelogram_angle = acos((pow(b,2.0) + pow(c,2.0) - pow(a,2.0)) / (2.0 * b * c)) - pi / 2.0;
    //
    // Calculate starting position (depends on number of points in each direction)
    // top left corner of parallelogram
    double start_y = 0.0;
    double start_z = 0.0;
    if(number_height > 0) {
        start_y = (-width / 2.0 + height * tan(parallelogram_angle) / 2.0) * cos(yz_angle) - height / 2.0 * sin(yz_angle);
        start_z = height / 2.0 * cos(yz_angle) + (-width / 2.0 + height * tan(parallelogram_angle) / 2.0) * sin(yz_angle);
    }
    // This is for a single row, or a single point. 
    // 1st row starts in centre of left side of parallelogram - but shifted by 1/2 sep_along_row
    if(number_height == 0) {
        start_y = -(width / 2.0 - separation_along_row / 2.0) * cos(yz_angle);
        start_z = -(width / 2.0 - separation_along_row / 2.0) * sin(yz_angle);
    }
    //
    // create raster offsets arrays
    double[] yRasterOffsets = [];
    double[] zRasterOffsets = [];
    int direction = 0;
    int w = 0;
    for(int h = 0 .. number_height) {
        for(int i = 0 .. number_length) {
            // alternate rows go in opposite directions
            direction = (h + 1) / 2 - h / 2;
            w = direction * (number_length - i) - (direction - 1) * i;
            yRasterOffsets[i + h * (number_length + 1)] = start_y + double(w) * yStep + double(h) * yRowSep + double((h + 1) / 2) * yStep;
            zRasterOffsets[i + h * (number_length + 1)] = start_z + double(w) * zStep - double(h) * zRowSep + double((h + 1) / 2) * zStep;
        }
    }

    return {yRasterOffsets,zRasterOffsets};
}

// SpirePhotoPcalFlash
//
// $id$
//
// This observation executes a PCAL Flash
// 
// The instrument should be in  the PHOTSTBY mode before execution of this procedure
// and the parameter passed to the observation should correspond to the initial state.
//
// 17/03/2009 KJK: 
//         SCR 0946 created from SpireEngPcalFlash
// 05/07/2009 KJK:
//         SPR-1593 - Updated input parameters in call to SpirePcalFlash
// 27/10/2009 KJK:
//        SPR Spire-2049 - calls SpirePcalFlash with obsmode="PFlash_b" if bright source is set.
//
obs SpirePhotoPcalFlash {
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; // NAIF identifier
    string boresight = ""; // instrument boresight to use
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    bool isBright = false; // Use settings for bright source (==tick)
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    string flashVersion = "v00"; // Version in cal table SpireTable_FlashParms
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    string obsMode = "POF8";
    string flashMode = "PFlash";
    if(isBright) {
        flashMode = "PFlash_b";
    }
    bool isPhot = true;
    string version01 = "v00";
    // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00";
    // Version in cal table SpireTable_CommonModeParams
    string version06 = "v00";
    // Version in cal table SpireTable_IsBrightPhaseShift
    //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    //
    int tslewmin = duration(SpireBb_StartObsAll(obsMode)) + duration(SpireBb_PhotSetMode("PFlash",isBright,version01,version02,debug));
    //   
    // BBs carried out when the pointing is reached:
    //
    if(pointing) {
        int tinithold = duration(SpireBb_PhotOffsetAuto(debug));
    } else {
        tinithold = duration(SpireBb_PhotOffsetAuto(debug)) + duration(SpireBb_StartObsAll(obsMode)) + duration(SpireBb_PhotSetMode("PFlash",isBright,version01,version02,debug));
    }
    //
    // BB carried out during pointing:
    //
    int tp = duration(SpirePcalFlash(flashMode,flashVersion,debug));
    //
    // BB carried out at the end:
    //
    int tfinalhold = duration(SpireBb_EndObsAll(isPhot)) + duration(SpireBb_PhotSetMode("PHTSTBY",isBright,version01,version02,debug)) + duration(SpireBb_SetObsStep(0,debug));
    //
    // Debug printing:
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // Lookup boresight, if not provided
    //
    string ib = boresight;
    if(boresight == "") {
        ib = SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode",obsMode,"Boresight",opsVersion,debug);
    }
    //
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    // 
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // ***********************  SLEW
            // Start observation: 
            SpireBb_StartObsAll(obsMode);
            // configure instrument 
            SpireBb_PhotSetMode("PFlash",isBright,version01,version02,debug);
        }
        if(state[0] == 2) {
            // ***********************  INITHOLD
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            if(!pointing) {
                // Start observation: 
                SpireBb_StartObsAll(obsMode);
                // configure instrument 
                SpireBb_PhotSetMode("PFlash",isBright,version01,version02,debug);
            }
            // Set offsets: 
            //
            SpireBb_PhotOffsetAuto(debug);
        }
        if(state[0] == 3) {
            // ***********************  POINTING
            SpirePcalFlash(flashMode,flashVersion,debug);
        }
        if(state[0] == 5) {
            // ***********************  FINALHOLD
            // reset STEP
            SpireBb_SetObsStep(0,debug);
            //
            // Set detectors back to PHOTSTBY:  
            SpireBb_PhotSetMode("PHTSTBY",isBright,version01,version02,debug);
            //
            // End Observation
            SpireBb_EndObsAll(isPhot);
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartFovMapCrossRaster.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpirePhoto/Spectro_CalGCO_FovMapCrossRaster.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V0.1: Initial version adapted from
//                  SpireBb_StartBsmPcalFlash (2009/05/05 V0.1),
//                  SpirePhoto_CalGCO_FovMapCrossRaster (2009/03/17 V1.0), and
//                  SpireSpectro_CalGCO_FovMapCrossRaster (2008/09/17 V0.1).
//                  BB includes now to move BSM/SMEC to hold/home.  
// 2009/07/12 V1.0: Fix bug in passing of SMEC home position (SPR-SPIRE-1612)
//                  Set SMEC framerate to zero to get all BSM samples 
//                  (SPR-SPIRE-1551).
// 
// Notes:
//    1) Scripts assumes that SpireBb_SpecOffsetAuto is run 
//       during INITHOLD or at first POINTING.
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartFovMapCrossRaster SPIRE 14044 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    string obsModeQla = "ENG_CAL_OBS03";
    string obsMode = "PEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_Phot/SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    bool setFramerate = true; // Set BSM framerate (==tick)?
    int frate = 0; // BSM framerate 
    int smecHomePosn = 3500; // SMEC home position
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartFovMapCrossRaster configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // In case move SMEC to home:
    // 
    if(!phot) {
        //
        // Calculate available time for possible movement:
        //
        int tmove = duration(SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug)) + duration(SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug)) + duration(SpireBb_SpecOffsetAuto(false,debug));
        if(setFramerate) {
            tmove = tmove + duration(SpireProc_Set_BsmFramerate(frate,debug));
        }
        //
        // Calculate max offset for which time is available:
        //
        int smecMaxOff = tmove * 500;
        // Note, 500 is maximum possible SMEC speed.
        int smecStart = smecHomePosn + smecMaxOff;
        // Note, formula above only reasonable 
        // when smecHomePosn small compared to 39500  
        // Safety check: 
        if(smecStart > 39500) {
            smecStart = 39500;
        }
        if(debug) {
            debug_print("smecStart: " + smecStart);
            debug_print("smecHomePosn: " + smecHomePosn);
            debug_print("tmove: " + tmove);
        }
        // 
        // Move from maximal offset to home:
        //
        SpireProc_SmecMove2Home(smecHomePosn,smecHomePosn + smecMaxOff,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    if(phot) {
        SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    }
    //delay(timeSlewCal);
    // //
    // //
    // Set user requested framerate:
    //
    if(setFramerate) {
        SpireProc_Set_BsmFramerate(frate,debug);
    }
    // //
    // //
    // Set SMEC framerate (== SMEC sampling rate) to zero:
    //
    if(!phot) {
        SpireProc_Set_SmecFramerate(0,debug);
    }
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartFovMapCrossRaster configuration ended");
    SpireMsg(1,"  ..StartFovMapCrossRaster took " + (time() - t) + " seconds)");
    //
}

// SpireBbSdetOn
//
// $id$
//
// This building block switches on the spectrometer detectors
// 
// The instrument should be in  the REDY mode before execution of this building block
//
// 29/04/2009 KJK:  First Version
// 08/06/2009 KJK:  Updated to set MODE to SDET_ON
//                             Read DcuDataMode from SpireTable_DefaultParams and use it
//                             Read biasMode correctly from SpireTable_DefaultParams
//                             Now finally sets up detectors according to SpireTable_DefaultParams 
//
block SpireBbSdetOn SPIRE 1550 {
    int jfet_heater_V = 0; // By default don't switch on jfet heater 
    string detVersion = "v00";
    string vssVersion = "v00";
    bool debug = false;
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SdetOn started");
    SpireMsg(2,"          $Id$");
    //
    int cmd = 0x0;
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP to 0
    SpireSetObsStep(0x0);
    //
    // Retrieve detector settings
    //
    int dcuDataMode = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuDataMode",detVersion,debug);
    int biasmode = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","biasMode",detVersion,debug);
    int mclkdiv = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","mclkDiv",detVersion,debug);
    int biasdiv = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","biasDiv",detVersion,debug);
    //
    // Retrive array nominal settings for PHTSTBY mode
    //
    int ssw_bias = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","sswBias",detVersion,debug);
    int ssw_phase = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","sswPhase",detVersion,debug);
    int slw_bias = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","slwBias",detVersion,debug);
    int slw_phase = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","SPECSTBY","slwPhase",detVersion,debug);
    //
    // ---
    // Building block starts
    // ---
    // Set MODE to SDET_ON
    SpireSetObsMode("SDET_ON");
    delay(1);
    SpireSetObsStep(0x1);
    delay(1);
    //
    // Switch ON PLIAs
    //
    SpireSendDrcuCmd(0xa0870006,0);
    delay(1);
    //
    // Set bias mode ,bias frequency and sampling frequency
    //
    SpireSendDrcuCmd(0x84300000 + biasmode,0);
    SpireSendDrcuCmd(0x84390000 + mclkdiv,0);
    SpireSendDrcuCmd(0x84380000 + biasdiv,0);
    delay(1);
    //
    // Switch on with small bias (~ 1 mVrms) across the arrays
    //
    SpireSendDrcuCmd(0x84310002,0);
    SpireSendDrcuCmd(0x84320002,0);
    delay(1);
    //
    // Set demodulation phase shift
    //
    SpireSendDrcuCmd(0x843a0000 + ssw_phase,0);
    SpireSendDrcuCmd(0x843b0000 + slw_phase,0);
    delay(1);
    //
    // Automatic offset setting + get offsets
    //
    SpireSendDrcuCmd(0x843c0014,0);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(2);
    SpireSendDrcuCmd(0x843e0000,0);
    SpireSendDrcuCmd(0x843c001c,0);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(3);
    SpireSendDrcuCmd(0x843e0000,0);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(1);
    //
    // Start SF data generation
    //
    SpireSendDrcuCmd(0x843c0000 + dcuDataMode,0);
    SpireSendDrcuCmd(0x843d0000,0);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(1);
    //
    // If necessary switch ON jfet heater
    if(jfet_heater_V != 0) {
        SpireSendDrcuCmd(0x84330000 + jfet_heater_V,0);
        delay(60);
        SpireSendDrcuCmd(0x84330000,0);
    } else {
        delay(3);
    }
    //
    // Apply Startup Vss voltages
    //
    // Read the startup Vss settings 
    // 
    int ssw_jfet_Vss1 = SpireProc_GetTableEntryInt("SpireTable_SpecVssSettings.txt","model","startup","ssw_vss1",vssVersion,debug);
    int ssw_jfet_Vss2 = SpireProc_GetTableEntryInt("SpireTable_SpecVssSettings.txt","model","startup","ssw_vss2",vssVersion,debug);
    int slw_jfet_Vss1 = SpireProc_GetTableEntryInt("SpireTable_SpecVssSettings.txt","model","startup","slw_vss",vssVersion,debug);
    //
    //  Apply Vss voltages followed by PVdd
    //
    // SSW JFET1 
    SpireSendDrcuCmd(0x84350000 + ssw_jfet_Vss1,0);
    SpireSendDrcuCmd(0x84370002,0);
    delay(1);
    // SSW JFET2	
    SpireSendDrcuCmd(0x84360000 + ssw_jfet_Vss2,0);
    SpireSendDrcuCmd(0x84370006,0);
    delay(1);
    // SLW JFET	
    SpireSendDrcuCmd(0x84340000 + slw_jfet_Vss1,0);
    SpireSendDrcuCmd(0x84370007,0);
    delay(1);
    //
    // Wait 30 seconds before setting nominal biases 
    //
    delay(30);
    SpireSendDrcuCmd(0x84310000 + ssw_bias,0);
    delay(1);
    SpireSendDrcuCmd(0x84320000 + slw_bias,0);
    delay(1);
    //
    // Stop DCU data, apply automatic offset setting + get offsets
    // 
    SpireSendDrcuCmd(0x843e0000,0);
    delay(1);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO(0x1000);
    delay(3);
    SpireSendDrcuCmd(0x843c0014,0);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(2);
    SpireSendDrcuCmd(0x843e0000,0);
    SpireSendDrcuCmd(0x843c001c,0);
    SpireSendDrcuCmd(0x843e0001,0);
    delay(3);
    SpireSendDrcuCmd(0x843e0000,0);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO(0x1000);
    delay(1);
    //
    // Start SF data generation
    //
    SpireSendDrcuCmd(0x843c0000 + dcuDataMode,0);
    SpireSendDrcuCmd(0x843d0000,0);
    SpireSendDrcuCmd(0x843e0001,0);
    //
    // Wait 30 seconds before setting the optimum Vss values
    //
    delay(30);
    //
    // Read the optimum Vss settings (lowest noise)
    // 
    int ssw_jfet_OVss1 = SpireProc_GetTableEntryInt("SpireTable_SpecVssSettings.txt","model","optimum","ssw_vss1",vssVersion,debug);
    int ssw_jfet_OVss2 = SpireProc_GetTableEntryInt("SpireTable_SpecVssSettings.txt","model","optimum","ssw_vss2",vssVersion,debug);
    int slw_jfet_OVss1 = SpireProc_GetTableEntryInt("SpireTable_SpecVssSettings.txt","model","optimum","slw_vss",vssVersion,debug);
    // 
    // Now set the optimum Vss values for all the JFETs
    //
    // SSW JFET1 
    SpireSendDrcuCmd(0x84350000 + ssw_jfet_OVss1,0);
    // PSW JFET2
    SpireSendDrcuCmd(0x84360000 + ssw_jfet_OVss2,0);
    delay(1);
    // SLW JFET	
    SpireSendDrcuCmd(0x84340000 + slw_jfet_OVss1,0);
    //
    //
    delay(10);
    // setup DCU data sampling
    SpireSendDrcuCmd(0x843c0000 + dcuDataMode,0);
    int dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuFrameNumber",detVersion,debug);
    SpireSendDrcuCmd(0x843d0000 + dcuFrameNumber,0);
    int dcuDataGen = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuDataGen",detVersion,debug);
    SpireSendDrcuCmd(0x843e0000 + dcuDataGen,0);
    //
    // flush data from FIFOs
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(3);
    //
    SpireSetObsMode("SPECSTBY");
    SpireSetObsStep(0x0);
    sync();
    //
    // completion
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB SdetOn   ended");
    SpireMsg(1,"  ..SDET Switch On (" + (time() - t0) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Exec_BsmAngleCal.txt
//
///////////////////////////////////////////////////////////
//
//  Procedure to loop through a list of BSM positions for
//  the 'Phot/Spec BSM Angle Calibration' tests 
//
///////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/11/07 V0.1: Initial version adapted from
//                  SpireProc_Exec_PhotBsmAngleCal (2008/10/13 V0.2)
//                  Adapt to change in name of low level script. Allow
//                  selecting FTS or photometer. 
// 2008/11/13 V0.2: Implement proper setting of MCU/BSM framerate
// 2009/01/27 V1.0: Add debug_print as input (to this and low level scripts)
// 2009/01/30 V1.1: Replaced cal to procedure SpireProc_Set_BsmFramerate
//                  with call to BB (see SPR-5890). Remove unsetting of
//                  MCU/BSM framerate. This will be now done during FINAL_HOLD.
// 2009/02/15 V1.2: Remove setting of BSM framerate. This will be now done 
//                  during SLEW. 
// 2009/02/16 V1.3: Adapt call to updated SpireBb_Chop. Add some VM parameters
//                  as new inputs.  
// 2009/09/05 V1.4: Allow reverse loop through values (SCR-SPIRE-1894)
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Exec_BsmAngleCal {
    int increment = 384; // Chop/Jiggle increment along scan axis [Dec(Hex)]
    int ref_chop = 0; // Chop position of BSM reference position [Dec(Hex)]
    int ref_jigg = 0; // Jiggle position of BSM reference position [Dec(Hex)]
    int home_chop = 37632; // Hold chop position of BSM  
    int home_jigg = 39520; // Hold jiggle position of BSM 
    int max_chop = 60000; // Maximum chop position of BSM 
    int max_jigg = 60000; // Minimum jiggle position of BSM 
    int min_chop = 1000; // Maximum chop position of BSM 
    int min_jigg = 1000; // Minimum jiggle position of BSM
    int vmId = 71; // Raw VM table number [Dec(Hex)]
    int vmIndex = 0; // Raw VM index [Dec(Hex)]
    int nParms = 10; // Number of parameters passed to VM
    double chopf = 2.0; // Chop frequency [Hz] 
    int ftime = 15; // Read-out time [s]
    double framerate = 125.0; // Specifies the MCU framerate [Hz] (photometer)
    double biasdivHz = 18.6; // Sampling rate [Hz] (photometer)
    bool fts = true; // FTS or photometer (for dcumode)
    bool chop = true; // Scan chop or jiggle axis
    bool reverse = false; // Scan axis either increasing or decreasing (==tick)
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Declare some variable:
    //
    if(fts) {
        // DCU data mode (4 == Full spectrometer):
        int dcumode = 4;
    } else {
        // DCU data mode (0 == Full photometer):
        dcumode = 0;
    }
    // //
    // //
    // Calculate BSM positions:
    //
    {int,int,int,int}[] pos = SpireProc_CalcParam_BsmAngleCal(increment,ref_chop,ref_jigg,home_chop,home_jigg,max_chop,max_jigg,min_chop,min_jigg,chop,reverse,debug);
    int n = length(pos);
    if(debug) {
        debug_print("length: " + n);
    }
    // //
    // //    
    // Calculate BSM chop parameters:
    //
    int[] chopparam1 = SpireProc_CalcParam_BsmSetup(ftime,chopf,biasdivHz,framerate,debug);
    int ncycles = chopparam1[0];
    int chop_period = chopparam1[1];
    int dcusample = chopparam1[2];
    int dcudelay = chopparam1[3];
    int bsmsample = chopparam1[4];
    // //
    // //    
    // Execute loop of chopping operations:
    //
    int obsstep = 0x0;
    // First obsstep [HEX]    
    for(int i = 0 .. n - 1) {
        {int,int,int,int} nextpos = pos[i];
        SpireBb_Chop(vmId,vmIndex,nParms,nextpos{0},nextpos{1},nextpos{2},nextpos{3},ncycles,chop_period,dcumode,dcusample,dcudelay,bsmsample,obsstep,debug);
        obsstep = obsstep + 1;
    }
}

// Missionphase  : 
//
// Purpose       : Read a BOLObias calibration table and command bias
//                 voltages for the given group, viz.
//                 VDL-BU for Group 3. Will also establish VDD_PROT_BLU
//                 and VDD_PROT_CL before setting bias voltages
//
// Author        : Diego A. Cesarsky
// CUS script    : Diego A. Cesarsky
// CVS file      : PHOT_set_bias_volt.txt
//
// Arguments     : 
// string  calTableName    The Cal table name, f.i. BOLObias or BOLOsafe
// string  BiasGR          The group number, BiasGRn (n:1, 2, ..6)
//
// Description   : Read Bias U-CAL tables in volts.
//                 Since BIAS are to be set in a predetermined order, the
//                 array biasOrder lists the preconised ordering.
//                 Prior to commanding the voltage generators, two voltages
//                 have to be switched ON with the operand
// 
//                 0x0001 + 0x10000*BiasNum + 0x1000000*GroupNum
//
//                 and this for BiasNum 23, 22 and 21
//                  
// Dependencies  : 
//
// Preconditions :
//
// Comments      :
//
// Version       : 0.3
// History       : 0.1   07-aug-2006; 1st version DAC
//                 0.1.1 22-aug-2006, KO, waitFor set to 1s everywhere
//                 0.2 17-oct-2006 DAC Had forgotten GND-BU
//                 0.3 13-nov-2006 DAC&TM Wait 3 sec after GND-BU
//
procedure PHOT_set_bias_volt {
    string calTableName = "PHOT_bias_low_direct"; // The U-Cal table [volts]
    int groupNb = 1 in [1,6]; // Requested group
}{
    // Construct BiasGR entry
    string biasGR = "BiasGR" + groupNb;
    // Switch ON the requested group (bias numbers 22 and 21)
    int biasHexa = 0x1;
    int biasNb = 22;
    int operand = groupNb * 0x1000000 + biasNb * 0x10000 + biasHexa;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    int waitFor = 1;
    delay(waitFor);
    biasNb = 21;
    operand = groupNb * 0x1000000 + biasNb * 0x10000 + biasHexa;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    waitFor = 1;
    delay(waitFor);
    biasNb = 23;
    operand = groupNb * 0x1000000 + biasNb * 0x10000 + biasHexa;
    Pacs_DMC_SEND_COMMAND_BOLC(operand);
    waitFor = 3;
    delay(waitFor);
    // Bias setting order
    string[] biasOrder = ["VDD-PROT-BU","VDD-PROT-CL","GND-BU","VGL-BU","VDL-BU","VSS-BU","VGG","VDD","VGL","VDL","VH-BLIND","VSS","VDECX-L","VDECX-H","CKRLL","CKRLH","VSMS-L","VSMS-H","VINJ","VH","VL","VRL","VCH"];
    // Introduce 1 sec delay after commanding each bias
    waitFor = 1;
    // Use lookup function; get BIAS voltage for given group and Bias number
    // For each BIAS defined in table and for demanded group
    for(int index = 3 .. 22) {
        biasNb = ilookup(calTableName,biasOrder[index],"Bias");
        double biasVolt = dlookup(calTableName,biasOrder[index],biasGR);
        //   Branch according to group number	
        if(groupNb == 1) {
            PHOT_bias_group_1(groupNb,biasNb,biasOrder[index],biasVolt);
        }
        if(groupNb == 2) {
            PHOT_bias_group_2(groupNb,biasNb,biasOrder[index],biasVolt);
        }
        if(groupNb == 3) {
            PHOT_bias_group_3(groupNb,biasNb,biasOrder[index],biasVolt);
        }
        if(groupNb == 4) {
            PHOT_bias_group_4(groupNb,biasNb,biasOrder[index],biasVolt);
        }
        if(groupNb == 5) {
            PHOT_bias_group_5(groupNb,biasNb,biasOrder[index],biasVolt);
        }
        if(groupNb == 6) {
            PHOT_bias_group_6(groupNb,biasNb,biasOrder[index],biasVolt);
        }
    }
    // to sync the bus
    sync();
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_LoadCurve.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to read list of bias levels from calibration table 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/02 V1.0: Initial version renamed from 
//                  SpireProc_CalcParam_StdLoadCurve 2009/02/01 V1.0
//
///////////////////////////////////////////////////////////////////////////
//
int[] procedure SpireProc_CalcParam_LoadCurve {
    string tabName = "SpireTable_StdLoadCurveLevels.txt"; // Calibration table name 
    string version = "v00"; // Version parameter defined in calibration table
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Setup variables:
    //
    string colName = "version";
    string tarName = "setting";
    string[] searchCol = scolumn(tabName,colName);
    int[] tarCol = icolumn(tabName,tarName);
    int size = table_size(tabName);
    int[] nbiaslist = [];
    int index = 0;
    // //
    // //
    // Cycle through values to get all rows which match:
    //
    for(int j = 0 .. size - 1) {
        if(searchCol[j] == version) {
            nbiaslist[index] = tarCol[j];
            index = index + 1;
        }
    }
    // //
    // //
    // Safety check: Make sure input version parameter is defined in cal. table:
    if(debug) {
        debug_print("nbiaslist: " + nbiaslist);
    }
    if(length(nbiaslist) == 0) {
        error("Input version parameter not defined. Select another one!");
    }
    // //
    // //
    // Return values:
    //

    return nbiaslist;
}

// SpireBbSmecRedy
//
// $id$
//
// This building block retuirns the SMEC to its REDY state (control open-loop)
// 
// The SMECshould be switched on (SpireBbSmecOn) before execution of this building block
//
// 17/02/2010 KJK: First Version (SPR Spire-2391)
//
block SpireBbSmecRedy SPIRE 3417 {
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SMEC Redy started");
    SpireMsg(2,"          $Id$");
    //
    // 
    // intialise variables
    // 
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set Step to zero
    SpireSetObsStep(0);
    delay(1);
    //
    //
    //  Open SMEC control loop
    SpireSendDrcuCmd(0x90440006,0);
    delay(4);
    //  
    //
    // completion
    sync();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB SMEC Redy  ended");
    SpireMsg(1,"  ..SMEC Redy (" + (time() - t0) + " seconds)");
}

// SpireSpectro_Cal_LvdtScans
//
// $id$
//
// This observation closes the loop on the LVDT and performs scans
// 
// The instrument should be in the SPECSTBY mode before execution of this procedure
// and the parameter passed to the observation should correspond to the initial state.
// 
// 2009/07/17 v0.1: SDS
//
// 2009/07/27 v0.2: SDS
//    Use pString1 parameter to select version of SpireTable_SmecNominalSettings.txt
//
obs SpireSpectro_Cal_LvdtScans {
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; // NAIF identifier
    string boresight = ""; // instrument boresight to use
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    bool isBright = false;
    int nScans = 32; // Number of Up/Down LVDT scans (must be even number)
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = "v00"; // Version of SpireTable_SmecNominalSettings.txt
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    string obsMode = "SEngCalObs";
    bool isPhot = false;
    string version01 = "v00";
    // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00";
    // Version in cal table SpireTable_CommonModeParams
    string version06 = "v00";
    // Version in cal table SpireTable_IsBrightPhaseShift
    //
    // Currently hardcoded parameter:
    // Is (==tick) the DCU currently sampled?
    bool dcuData = false;
    // //
    // //
    // Setup mode:
    //
    // Set obsMode for QLA:
    string obsModeQla = "ENG_CAL_OBS45";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    //
    int tslewmin = duration(SpireBb_StartObsAll(obsModeQla)) + duration(SpireBb_SpecSetMode(obsMode,isBright,version01,version02,debug));
    //   
    // BBs carried out when the pointing is reached:
    //
    if(pointing) {
        int tinithold = duration(SpireBb_SpecOffsetAuto(dcuData,debug));
    } else {
        tinithold = duration(SpireBb_SpecOffsetAuto(dcuData,debug)) + duration(SpireBb_StartObsAll(obsMode)) + duration(SpireBb_SpecSetMode("SFlash",isBright,version01,version02,debug));
    }
    //
    // BB carried out during pointing:
    //
    int tp = duration(SpireBb_LvdtScans(nScans,pString1,version02,debug));
    //
    // BB carried out at the end:
    //
    int tfinalhold = duration(SpireBb_EndObsAll(isPhot)) + duration(SpireBb_SpecSetMode("SPECSTBY",isBright,version01,version02,debug)) + duration(SpireBb_SetObsStep(0,debug));
    //
    // Debug printing:
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // Lookup boresight, if not provided
    //
    string ib = boresight;
    if(boresight == "") {
        ib = SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode",obsMode,"Boresight",opsVersion,debug);
    }
    //
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    // 
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // ***********************  SLEW
            // Start observation: 
            SpireBb_StartObsAll(obsModeQla);
            // configure instrument 
            SpireBb_SpecSetMode(obsMode,isBright,version01,version02,debug);
        }
        if(state[0] == 2) {
            // ***********************  INITHOLD
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            if(!pointing) {
                // Start observation: 
                SpireBb_StartObsAll(obsModeQla);
                // configure instrument 
                SpireBb_SpecSetMode(obsMode,isBright,version01,version02,debug);
            }
            // Set offsets: 
            //
            SpireBb_SpecOffsetAuto(dcuData,debug);
        }
        if(state[0] == 3) {
            // ***********************  POINTING
            SpireBb_LvdtScans(nScans,pString1,version02,debug);
        }
        if(state[0] == 5) {
            // ***********************  FINALHOLD
            // reset STEP
            SpireBb_SetObsStep(0,debug);
            //
            // Set detectors back to SPECSTBY:  
            SpireBb_SpecSetMode("SPECSTBY",isBright,version01,version02,debug);
            //
            // End Observation
            SpireBb_EndObsAll(isPhot);
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id:$
///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_Cal_BsmPidTuning.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'CoP: Phot BSM Tuning' 
//
//  in *basic_fine_pointing* mode or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/30 V0.1: Initial version adapted from
//                  SPIRE_IST_BSM_CHOP_POS1.txt (SDS, email 30.03.2009)
// 2009/04/01 V0.2: Increased allowed range of BSM inputs. 
// 2009/05/06 V0.3: Add in move BSM to hold at start. Gather procedures at 
//                  start and end in separate BB. Set input BSM framerate
//                  only if different from PHOTSTBY one. 
// 2009/06/05 V1.0: Adapt call to SpireBb_EndBsmPidTuning to account for
//                  SPR-1476. SPR-1477: Hardcode STBY 'v00' in EndBB. 
// 2009/08/22 V1.1: Change default input parameters (
// 
// 
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in PHOTSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for all three arrays and could be taken from following cal table: 
//  SpireTable_PhotModeParams.txt 
//
//  3) Further mode dependent parameters can be read from:
//  SpireTable_CommonModeParams.txt           
//
//  4) BSM parameters can be read from SpireTable_BsmNominalSettings.txt
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhoto_Cal_BsmPidTuning {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; //NAIF identifier: put '0' to use RA/DEC, or correct 'NAIFID'
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    bool isBright = false; // Use settings for bright source (==tick)
    string ib = "S14_0"; // Central aperture (defined in SIAM) of raster
    int on_source_chop = 46113 in [4096,61440]; // On source chop position (==POF2; POF3=53179)
    int on_source_jiggle = 39426 in [4096,61440]; // On source jiggle position (==POF2; POF3=39426)
    int off_source_chop = 27280 in [4096,61440]; // Off source chop position (==POF2; POF3=17321)
    int off_source_jiggle = 39426 in [4096,61440]; // Off source jiggle position (==POF2; POF3=39426)
    double chopkp_range = 1.0; // Percentage half-range for tuning Chop Kp around ILT nominal values (+/1%)
    double chopki_range = 10.0; // Percentage half-range for tuning Chop Ki around ILT nominal values (+/1%)
    double chopkd_range = 10.0; // Percentage half-range for tuning Chop Kd around ILT nominal values (+/1%)
    int nkp = 2; // Number of steps for Chop Kp for half-range
    int nki = 3; // Number of steps for Chop Ki for half-range
    int nkd = 3; // Number of steps for Chop Kd for half-range
    double chopf = 2.0 in [0.1,4.0]; // Chop frequency [Hz] 
    double framerate = 125.0; // Specifies the MCU framerate [Hz]
    int ftime = 20; // Read-out time [s]
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial"; // Model in cal table SpireTable_BsmNominalSettings
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Declare some variable:
    //
    // FTS or photometer (for dcumode in VM set in SpireProc_Exec_BsmPidTuning):
    bool fts = false;
    // Photometer or FTS 
    bool phot = !fts;
    //
    string version = "";
    string tabName = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    int frate = 0;
    int tinithold = 0;
    bool setFramerate = true;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    string tabName04 = "SpireTable_CommandLists.txt";
    //
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS14";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for setup and datarates:  
    string obsMode = "PEngCalObs";
    // Note: datarates are currently only maximum values
    // //
    // //
    // Setup parameters for BSM chopping movement: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version03;
    tabName = tabName03;
    string selCol = "model";
    // Name of column for selecting 
    string selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table (to reconfigure at end):  
    //
    string tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Read VM parameters from calibration table:
    //
    tabName = tabName04;
    selVal = "Chop";
    int vmId = ilookup(tabName,selVal,"Id");
    int vmIndex = ilookup(tabName,selVal,"Index");
    int nParms = ilookup(tabName,selVal,"Nparms");
    // //
    // //
    // Read nominal bias frequency and bias divider:
    // (to determine the sampling rate)
    //    
    // Select version flag and set GetTableEntry parameters:
    version = version01;
    tabName = tabName01;
    selCol = "mode";
    // Name of column for selecting 
    selVal = obsMode;
    // Value of 'string' selector
    //
    tarCol = "mclkDiv";
    int mclkdiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "biasDiv";
    int biasdiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Calculate nominal sampling rate from mclkdiv and biasdiv:
    //
    double mclkdivHz = 1.0E7 / (512.0 * double(mclkdiv + 1));
    double biasdivHz = 1.0 / (double(biasdiv) + 1.0) * mclkdivHz;
    if(debug) {
        debug_print("Nominal sampling rate is: " + biasdivHz + " [Hz]");
    }
    // //
    // //
    // Read PHOTSTBY BSM framerate:
    // 
    selCol = "mode";
    selVal = "PHTSTBY";
    version = version02;
    tabName = tabName02;
    tarCol = "bsmFrameRate";
    int bsmFrameRate = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    double bsmFrameRateHz = 1000000.0 / (double(bsmFrameRate) * 420.0);
    if(debug) {
        debug_print("Nominal BSM sampling rate is: " + bsmFrameRateHz + " [Hz]");
    }
    //
    // Compare PHOTSTBY with input BSM framerate:
    // 
    frate = SpireProc_CalcParam_BsmFramerate(framerate,debug);
    if(frate == bsmFrameRate) {
        setFramerate = false;
    }
    //
    // // // // // // // // // // // // // // // // 
    // // // // // // // // // // // // // // // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    //
    int tslewmin = duration(SpireBb_StartBsmPidTuning(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,setFramerate,frate,debug));
    // 
    // BBs carried out when the pointing is reached:
    //
    if(pointing) {
        tinithold = duration(SpireBb_PhotOffsetAuto(debug));
    } else {
        tinithold = duration(SpireBb_PhotOffsetAuto(debug)) + tslewmin;
    }
    //
    // BB carried out during pointing:
    //
    int tp = duration(SpireProc_Exec_BsmPidTuning(vmId,vmIndex,nParms,chopf,ftime,framerate,biasdivHz,fts,on_source_chop,on_source_jiggle,off_source_chop,off_source_jiggle,chopkp_range,chopki_range,chopkd_range,nkp,nki,nkd,version03,model,debug));
    //
    // BB carried out at the end:
    //
    int tfinalhold = duration(SpireBb_EndBsmPidTuning(phot,isBright,version01,version02,version03,model,debug));
    //
    // Debug printing?:
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // 
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ******************************************************* */
    // POINTING STATES WITH OBSERVING MODE LOGIC AND DATARATES */
    // ******************************************************* */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartBsmPidTuning(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,setFramerate,frate,debug);
            //
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation: 
                //
                SpireBb_StartBsmPidTuning(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,setFramerate,frate,debug);
                //
            }
            // //
            // //
            // Set offsets:
            //
            SpireBb_PhotOffsetAuto(debug);
            //
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            // //
            // //
            // Execute BSM PID tuning:
            //
            SpireProc_Exec_BsmPidTuning(vmId,vmIndex,nParms,chopf,ftime,framerate,biasdivHz,fts,on_source_chop,on_source_jiggle,off_source_chop,off_source_jiggle,chopkp_range,chopki_range,chopkd_range,nkp,nki,nkd,version03,model,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            version03 = "v00";
            model = "initial";
            //
            SpireBb_EndBsmPidTuning(phot,isBright,version01,version02,version03,model,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_StdLoadCurve.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to read list of bias levels from calibration table 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/01 V1.0: Initial version adapted from top level script
//                  SpirePhoto_Cal_StdLoadCurve (2008/11/12 V0.7)
//
///////////////////////////////////////////////////////////////////////////
//
int[] procedure SpireProc_CalcParam_StdLoadCurve {
    string tabName = "SpireTable_StdLoadCurveLevels.txt"; // Calibration table name 
    string version = "v00"; // Version parameter defined in calibration table
    bool debug = false; // Allow (==tick) or suppress cus debug_print statement
}{
    // //
    // //
    // Setup variables:
    //
    string colName = "version";
    string tarName = "setting";
    string[] searchCol = scolumn(tabName,colName);
    int[] tarCol = icolumn(tabName,tarName);
    int size = table_size(tabName);
    int[] nbiaslist = [];
    int index = 0;
    // //
    // //
    // Cycle through values to get all rows which match:
    //
    for(int j = 0 .. size - 1) {
        if(searchCol[j] == version) {
            nbiaslist[index] = tarCol[j];
            index = index + 1;
        }
    }
    // //
    // //
    // Safety check: Make sure input version parameter is defined in cal. table:
    if(debug) {
        debug_print("nbiaslist: " + nbiaslist);
    }
    if(length(nbiaslist) == 0) {
        error("Input version parameter not defined. Select another one!");
    }
    // //
    // //
    // Return values:
    //

    return nbiaslist;
}

// SpireSMEC_INITtoREDY
//
// $id$
//
// This procedure configures the instrument into the REDY mode
// 
// The instrument should be in the SMEC_INIT mode before execution of this observation
//
// This procedure is for testing of SMEC initialisation during PV Phase
//
//
// 28/08/2009 TWG: First Version
//
//
procedure SpireSMEC_INITtoREDY {
    string smecVersion = "v00";
    bool debug = false;
}{
    //
    // -------------
    // switch off SMEC
    // -------------
    mois_comment("Procedure SPIRE_SMEC_OFF: to switch off the SPIRE SMEC");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    SpireBbSmecOff(smecVersion,debug);
    // Setup  SMEC sampling
    SpireBbSetSmecSampling("REDY",smecVersion,debug);
    mois_comment("SPIRE SPIRE_SMEC_OFF Procedure Completed");
    mois_tmcheck("Check that parameter SMECENCPWR is set to 0");
    mois_tmcheck("Check that parameter SMECLVDTPWR is set to 0");
    mois_tmcheck("Check that parameter MODE is set to SMEC_OFF");
    //
    // set mode to REDY
    SpireSetObsMode("REDY");
    //    
    // set nominal housekeeping rate
    SpireBbSetNhkSampling("REDY","v00",debug);
    //
}

// Missionphase  : EQM IMT 
//
// Purpose       :  SAFE mode OBCP
//                  
//                 
//
// TCL author    : HF
// TCL file      : 
// CUS author    : HF 
// Script file   : OBCP_SAFE.txt 
//
// Input arguments none
// type    name         description
//
// Return values
// Type    Name      Default      Description
//
// Description   :  Transit to SAFE mode
//                            
//                           
//                            
//                  
// Dependencies  : 
//
// Preconditions : PACS must be on and configured for spectroscopy
//                             
//                 
// Comments      : 
// 
// History       : 1.0 29-Mar-2005 creation by HF
//
int block OBCP_SAFE PACS 24 {
}{
    // Register start of BB
    WriteBBID($BBID);
    // Tally duration (NOTE: we use [msec] for the return value)
    int duration_msec = 0;
    Pacs_DPU_START_OBCP("GO_SAFE_MODE",0,[]);
    delay(10);
    duration_msec = duration_msec + 10000;
    // Mark End of Block
    WriteEndBB();
    // Return time

    return duration_msec;
}

// Missionphase  : 
//
// Purpose       : Prepare MEC for photometry, including filterwheel,
//                 chopper and calibration sources 
//                  
// TCL author    : TM
// TCL file      : tm_phot_mec_setup.tcl
// CUS author    : DAC
// Script file   : PHOT_dmc_setup.txt
//
// Input arguments
// type    name         description
//
// Return values
// Type    Name      Default      Description
//
// Description   : This script will switch on and set all required
//                 parameters for the chopper, the photometry filter
//                 wheel and the calibration sources.
//                 This script should be executed just after the
//                 switch-on procedure and the bolometer setup
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : 
// 
// Version      0.8
// History      
// 0.1 12-apr-2005 DAC (based on TM's version 1.2)
// 0.2 13-apr-2005 DAC Redefined as procedure
// 0.3 20-apr-2005 DAC Use new CONF_cs
// 0.4 08-aug-2006 TM, integration of diagnostic HK for fw and chopper
// 0.5 10-nov-2006 DAC Use "current" chopper controller parameters          
// 0.6 13-nov-2006 DAC Use "Heidelberg 4deg" chopper controller parameters          
// 0.7 05-mar-2007 TM update for chopper and CSs
// 0.8 15-Jun-2007 PR modify PHOT_fltw_conf -> CONF_phot_fltw
//
int[] procedure PHOT_dmc_setup {
    string phot_fltw_id = "POS B" in ["POS A","POS B"]; // Photometer filter ID
    int chop_def_pos = 0; // Chopper default position
    double temp_CS1 = 48.0; //  Temperature for the PACS calibration source 1 
    double temp_CS2 = 58.0; //  Temperature for the PACS calibration source 2
}{
    // Define variables to communicate various durations to HSPOT.
    // NOTE: all time variables in units of number of ramps (SPEC) or
    //       number of readouts (BOLO). The calling program must convert this
    //       count into actual duration in true time units [seconds].
    //       SRC, REF, CAL, OVR stand for time spent on SRC, REF (on sky),
    //       CAL source, and overheads (wait for something). Total
    //       duration is given by duree_num. If no error, this duration
    //       must be equal to the sum of all others
    int duree_num = 0;
    int duree_SRC = 0;
    int duree_REF = 0;
    int duree_CAL = 0;
    int duree_OVR = 0;
    int time_start = time();
    //-------------------
    // FILTERWHEEL
    //-------------------
    //
    // Configure diagnostik HK for filterwheel
    // Read out every 5 ms
    // DMC_WRT_DIAG_HK_LIST
    // DMC_FW_PHOT_CTRL  211
    // DMC_FWGRAT_HALLA  256
    // DMC_FWGRAT_HALLB  257
    // DMC_FWPH_CUR_POS  260                    
    // DMC_FPU_T_SEN_ST  404
    // DMC_FW_PHOT_TEMP  406                    
    // DMC_FW_GR_VMOTA   556
    // DMC_FW_GR_IMOTA   560
    // DMC_FWPHOT_POS_A  563
    // DMC_FW_GR_VMOTB   564
    // DMC_FW_GR_IMOTB   567
    // DMC_FWPHOT_POS_B  569
    {int}[] parlist_fw = [{211},{256},{257},{260},{404},{406},{556},{560},{563},{564},{567},{569},{0xffff}];
    int[] aux_fw = [211,256,257,260,404,406,556,560,563,564,567,569,0xffff];
    int check_sum_fw = checksum("int",aux_fw);
    int diag_hk_length_fw = 13;
    int diag_hk_period_fw = 5;
    Pacs_DMC_WRT_DIAG_HK_LIST(diag_hk_length_fw,parlist_fw,check_sum_fw);
    Pacs_DMC_START_DIAG_HK(diag_hk_period_fw);
    //
    CONF_phot_fltw();
    //PHOT_fltw_conf();
    // PC129420 "DMC_SWON_FW_PHOTO" SWITCH ON POWER SUPPLY OF FILTER WHEEL PHOTO
    // PC136420 "DMC_MOVE_PHOT_FW_LOC" MOVE PHOTOMETER FILTER WHEEL TO LOCATION
    //         PP075420 "FW_ID"
    // PC109420 "DMC_SWOF_GRAT_CONT" SWITCH OFF GRATING CONTROLLER
    PHOT_fltw_move(phot_fltw_id);
    delay(1);
    //
    Pacs_DMC_STOP_DIAG_HK();
    delay(1);
    //
    //-------------------
    // CHOPPER
    //-------------------
    //
    // Configure diagnostik HK for chopper
    // Read out every 5 ms
    // DMC_CHOP_CTRL_ST  209
    // DMC_CHOP_CUR_POS  244
    // DMC_CHOP_SETPOIN  245
    // DMC_CHOP_TARGET   246
    // DMC_CHOP_PID_ERR  247
    // DMC_CHOP_PID_ACC  248
    // DMC_CHOP_MAX_DIT  249
    // DMC_CHOP_OUTPUT   258
    // DMC_CHOPPER_TEMP  407
    // DMC_CHOP_VA       557
    // DMC_CHOP_IA       561
    // DMC_CHOP_VB       565
    {int}[] parlist_cho = [{209},{244},{245},{246},{247},{248},{249},{258},{407},{557},{561},{565},{0xffff}];
    int[] aux_cho = [209,244,245,246,247,248,249,258,407,557,561,565,0xffff];
    int check_sum_cho = checksum("int",aux_cho);
    int diag_hk_length_cho = 13;
    int diag_hk_period_cho = 5;
    Pacs_DMC_WRT_DIAG_HK_LIST(diag_hk_length_cho,parlist_cho,check_sum_cho);
    Pacs_DMC_START_DIAG_HK(diag_hk_period_cho);
    //
    // DMC_WRT_CHOP_CONF_PAR (now modified for 20 parameters)
    CONF_chopper("CONFChopper","nom_sky");
    // PC119420 "DMC_SWON_CHOP_CONT" SWITCH ON CHOPPER CONTROLLER
    // PC121420 "DMC_ENABLE_CHOP_CONT" ENABLE CHOPPER CONTROLLER
    CHOP_on_off("ON");
    // PC123420 "DMC_MOVE_CHOP_ABS" MOVE CHOPPER TO AN ABSOLUTE POSITION
    //         PP079420 "SET_POINT"
    Pacs_DMC_MOVE_CHOP_ABS(chop_def_pos);
    delay(1);
    //
    Pacs_DMC_STOP_DIAG_HK();
    delay(1);
    //
    //-------------------------
    // PACS CALIBRATION SOURCES
    //-------------------------
    // DMC_WRT_CS1_CONF_PAR
    // DMC_WRT_CS2_CONF_PAR
    CONF_cs("Both");
    // PC138420 "DMC_SWON_BB_1_CONT" SWITCH ON BLACK BODY 1 CONTROLLER
    // PC206420 "DMC_ENABLE_BB_1_CONT" ENABLE BB1 CONTROLLER
    CS_on_off("CS1","ON");
    // PC140420 "DMC_SET_TEMP_BB_1" SET THE TEMPERATURE OF THE BLACK BODY 1
    //         PP079420 "SET_POINT"
    CS_temp("CS1",temp_CS1);
    // PC142420 "DMC_SWON_BB_2_CONT" SWITCH ON BLACK BODY 2 CONTROLLER
    // PC208420 "DMC_ENABLE_BB_2_CONT" ENABLE BB2 CONTROLLER
    CS_on_off("CS2","ON");
    // PC144420 "DMC_SET_TEMP_BB_2" SET THE TEMPERATURE OF THE BLACK BODY 2
    //         PP079420 "SET_POINT"
    CS_temp("CS2",temp_CS2);
    //-------------------------
    // End of Procedure
    //-------------------------
    // Return empty array for time being...
    // Time spent
    int duree_TCs = time() - time_start;
    duree_OVR = duree_TCs;
    duree_num = duree_OVR;
    // Return the array of times
    int[] time_array = [duree_num,duree_SRC,duree_REF,duree_CAL,duree_OVR];

    return time_array;
}

block SpireBb_StartMonitoring SPIRE 3410 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_StartMonitoring started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    // //
    // Start on-board monitoring:
    //
    Spire_START_MONITORING_RAW(5);
    delay(10);
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_StartMonitoring ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectro_Cal_PhaseUp.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Spec Phase Up' 
//
//  in *basic_fine_pointing* or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/15 V0.1: Initial version adapted from 
//                  SpireSpeco_Cal_PhaseUp.txt (2008/07/03 V0.5)
//                  Mode_ILT_PERF_DPH_S.txt (v1.4 2008/01/31 20:24:33)
// 2008/11/11 V0.2: Allow 'no pointing' as input option; Adapt debug printing
// 2008/11/12 V0.3: Implement mode setting; Add isBright 
//                  Change 'no pointing' implementation
// 2009/02/19 V0.4: Add debug_print as input and pass it to some low level 
//                  scripts. Use new SpireBb_EndObsAll and SpireBb_StartObsAll. 
//                  Read nominal bias frequency and bias divider from new
//                  SpireTable_SpecModeParams.txt. Implemented message 
//                  if activating isBright setting. Implemented setting 
//                  of datarates. Change Hspot description of ftime.
//                  Use SpireBb_SpecSetMode to set to SPECSTBY during 
//                  SLEW and FINAL_HOLD. Read boresight from 
//                  SpireTable_OpsParms. Replace call to SpireBb_SpecFSetupData
//                  by call to SpireBb_DcuSetFreqSamp, SpireBb_SpecFSetPhase, 
//                  and SpireBb_SpecFSetBiasAmpl. Correct first phase is now 
//                  set during SLEW instead of target phase. Adapt to changes
//                  in cal of SpireProc_Exec_SpecPhaseUp.
// 2009/03/04 V0.5: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Replace 'message' with
//                  'error' when isBright is used.
// 2009/05/06 V0.6: Add in move BSM/SMEC to hold/home at start. Add new 
//                  SpireBb_SmecHold to account for the fact that
//                  SpireBb_SmecMove2Home does not stop SMEC.
//                  Gather procedures at start and end in separate BB. 
// 2010/01/06 V1.7: Edit default parameters for input bias ampl. and number 
//                  of steps to one size = 16, raw step size=4
//                  (SCR-SPIRE-2300)
// 
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in SPECSTBY at beginning 
//  (i.e. bias amplitude, phase, frequency [mclkdiv,biasdiv] are nominal)
//
//  2) Phases are user input  
//
//  3) Bias frequency and sampling rate are user inputs both in Hz. They
//     are translated in the script to the Hex values of mclkdiv and biasdiv.
//
//  4) Boresight of array can be read from following cal table:
//     SpireTable_OpsParms.txt  
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectro_Cal_PhaseUp {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    bool isBright = false; // Use settings for bright source (==tick)
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    double biasfreq = 160.09 in [80.0,240.0]; // Bias frequency [Hz]
    double samplerate = 80.05 in [1.0,80.5]; // Sampling rate [Hz] (Careful, don't exceed number of data packages to be transferred from spacecraft!)
    double biasmV_ssw = 35.969 in [0.0,176.385]; // SSW Bias amplitude (peak2peak) [mV]
    double biasmV_slw = 31.132 in [0.0,176.417]; // SLW Bias amplitude (peak2peak) [mV]
    double target_phase = 187.5 in [0.0,360.0]; // Central phase shift (target phase) [degree]
    int number_steps = 16 in [1,127]; // Number of steps to one side [int]
    int step_size = 4 in [1,20]; // Raw step size (1 step==1.411 degrees) [dec(HEX)]
    int ftime = 10; // Time at each bias level [s]
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version05 = "v00"; // Version in cal table SpireTable_OpsParms.txt
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // //
    // //
    // Check for is bright setting: 
    //
    if(isBright) {
        isBright = false;
        error("IsBright does not make sense while doing phase ups. Try again!");
    }
    // //
    // //
    // Declare some variable:
    //
    //
    // Photometer or FTS:
    bool phot = false;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_SpecModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    string tabName06 = "SpireTable_SmecNominalSettings.txt";
    //
    // Currently hardcoded version and model parameter:
    //
    string version06 = "v00";
    // Version in cal table SpireTable_SmecNominalSettings
    string version03 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    //
    // Dummy value for Phot script:
    // (needed but not used in spec script!)
    //
    int psw_bias = 62;
    //
    int pmw_bias = 62;
    //
    int plw_bias = 62;
    //
    int ptc_bias = 62;
    //
    //
    // Currently hardcoded parameter:
    // Is (==tick) the DCU currently sampled? 
    bool dcuData = false;
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS40";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "SEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Calculate a raw phase value used for the initial setup:
    // 
    int target_phase_raw = iround(target_phase * 255.0 / 360.0);
    // //
    // //
    // Calculate list of phases:
    //
    int[] raw_phase_list = SpireProc_CalcParam_PhaseUp(target_phase,number_steps,step_size,debug);
    if(debug) {
        debug_print("Phase list [dec(HEX)]: " + raw_phase_list);
    }
    // //
    // //
    // Convert user input to Hex values:
    //
    // for bias frequency and sample rate: 
    //  
    int[] hexvalues = SpireProc_CalcParam_BiasFreqSampFreq(biasfreq,samplerate,fts,debug);
    int mclkdiv = hexvalues[0];
    int biasdiv = hexvalues[1];
    if(debug) {
        debug_print("Hex values of mclkdiv/biasdiv are: " + mclkdiv + " " + biasdiv);
    }
    //
    // for bias amplitude:
    //
    int[] biashex = SpireProc_CalcParam_SpecBiasConvert(biasmV_ssw,biasmV_slw,debug);
    int ssw_bias = biashex[0];
    int slw_bias = biashex[1];
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version03;
    tabName = tabName03;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // //
    // Read SMEC home position from calibration file:
    //
    tarCol = "Home";
    tabName = tabName06;
    selVal = version06;
    int smecHomePosn = ilookup(tabName,selVal,tarCol);
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // // 
    // // 
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartPhaseUp(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,ssw_bias,slw_bias,raw_phase_list,debug));
    // 
    // BBs carried out when the pointing is reached:
    if(pointing) {
        int tinithold = 0;
    } else {
        tinithold = tslewmin;
    }
    //
    // BB carried out during pointing:
    int tp = duration(SpireProc_Exec_SpecPhaseUp(raw_phase_list,ftime,dcuData,debug));
    //
    // BB carried out at the end:
    int tfinalhold = duration(SpireBb_EndPhaseUp(phot,isBright,version01,version02,debug));
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // // 
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,0,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_SpecDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartPhaseUp(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,ssw_bias,slw_bias,raw_phase_list,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            //
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation: 
                //
                SpireBb_StartPhaseUp(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,mclkdiv,biasdiv,psw_bias,pmw_bias,plw_bias,ptc_bias,ssw_bias,slw_bias,raw_phase_list,debug);
                //
            }
            //
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            // //
            // //
            // Execute stepping through phase list:
            //
            SpireProc_Exec_SpecPhaseUp(raw_phase_list,ftime,dcuData,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            SpireBb_EndPhaseUp(phot,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_SmecMove.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to move SMEC to a given position from a known input position
// allowing for the necessary delay in time to reach position. SMEC is set
// to hold its position at end of script.   
//
///////////////////////////////////////////////////////////////////////////
//
// KJK:
// 2009/02/02 V0.1: Initial version 
// 2009/03/02 V0.2: (MP) Add header lines and some cosmetics.
// 2009/03/31 V0.3: (MP) Remove final stop SMEC, i.e allow SMEC to
//                       continue running to its position beyond the 
//                       procedure. Add stop of SMEC at start of script
//                       to make sure there is no move command while 
//                       the SMEC is still moving. 
// 2009/05/05 V0.4: (MP) Add final stop SMEC back in, use 
//                       SpireProc_SmecMove2Home to startup scripts instead. 
// 2009/09/15 V 0.4: KJK moved  sync() to end, so that is it always done
//
// Notes:
// 
//  1) When SpireProc_Setup_SmecScan is used, SpireProc_SmecMove needs 
//     to be run before. 
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_SmecMove {
    int smecPosn = 1000; // SMEC final position (encoder value) 
    int smecCurrPosn = 1000; // SMEC current position (encoder value)
    bool debug = false;
}{
    // //
    // //
    // Define some variables:
    //
    int t = time();
    //
    // hex string:
    string hstr = "";
    //
    // time string:
    string tstr = "";
    //
    // Hardcoded name and version of calibration tables:
    string tabName = "SpireTable_SmecNominalSettings.txt";
    string version = "v00";
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(3,"      " + tstr + ": Proc SmecMove started");
    SpireMsg(3,"            $Id: $");
    // //
    // //
    // Move to  position (only if we have to):
    //
    if(smecCurrPosn != smecPosn) {
        //
        // fetch SMEC movement parameters
        //    
        int moveCmd = ilookup(tabName,version,"MoveCmd");
        int moveSpeed = ilookup(tabName,version,"MoveSpeed");
        int moveTime = (smecCurrPosn - smecPosn) / moveSpeed;
        if(moveTime < 0) {
            moveTime = moveTime * -1;
        }
        moveTime = moveTime + 2;
        // allow 2 sec to stabilise
        if(debug) {
            debug_print("Movement Time: " + moveTime);
        }
        // //
        // //
        // Set SMEC mode to hold its position:
        //
        SpireSendDrcuCmd(0x90490000,0);
        // //
        // //
        // Move to  position:
        //
        // Set scan speeds:
        SpireSendDrcuCmd(0x90470000 + moveCmd,0);
        delay(1);
        SpireSendDrcuCmd(0x90560000 + moveCmd,0);
        //
        // Set SMEC position:
        SpireSendDrcuCmd(0x90450000 + smecPosn,0);
        delay(1);
        //
        // Move SMEC to position:
        SpireSendDrcuCmd(0x90490001,0);
        delay(moveTime);
        //
        // Set SMEC mode to hold its position:
        SpireSendDrcuCmd(0x90490000,0);
    }
    sync();
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(3,"      " + tstr + ": Proc SmecMove ended");
    SpireMsg(2,"    Proc SmecMove (" + (time() - t) + " seconds)");
}

//
// BB for standalone SMEC scans from REDY mode
// 
// 05-Jul-2010: Version 1.0 SDS
// 
//
block SpireBb_EngSmecScan SPIRE 3423 {
    string smecVersion = "v00";
    string specVersion = "v00";
    string resolution = "H";
    int nscans = 2;
    bool debug = false;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_EngSmecScan started");
    SpireMsg(2,"          $Id$");
    //
    // intialise variables
    int encPwr = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"encPwr");
    int lvdtScale = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"lvdtScale");
    int lvdtOff = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"lvdtOff");
    int ffGain = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"ffGain");
    int ffOff = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"ffOff");
    int drvFlt = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"drvFlt");
    int rteLim = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"rteLim");
    int intLim = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"intLim");
    // 
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    delay(1);
    //
    // set Step to zero
    SpireSetObsStep(0);
    //
    delay(1);
    //
    //   **** SWITCH ON SMEC ****
    //
    // switch on optical encoder
    SpireSendDrcuCmd(0x90400000 + encPwr,0);
    delay(1);
    //
    // Switch on LVDT		
    SpireSendDrcuCmd(0x90410001,0);
    SpireSendDrcuCmd(0x905f0000 + lvdtScale,0);
    delay(1);
    SpireSendDrcuCmd(0x905e0000 + lvdtOff,0);
    // 
    // Set Feed Forward Gain
    SpireSendDrcuCmd(0x90540000 + ffGain,0);
    delay(1);
    //
    // Set the FF offset to put the SMEC at mechanical stop
    SpireSendDrcuCmd(0x90550000 + ffOff,0);
    delay(15);
    // Set slew rate limiter
    SpireSendDrcuCmd(0x90510000 + rteLim,0);
    // Set integration limit
    SpireSendDrcuCmd(0x904e0000 + intLim,0);
    delay(1);
    // Set derivative filter
    SpireSendDrcuCmd(0x904c0000 + drvFlt,0);
    delay(1);
    //
    // Change contents of MCU engineering frames to contain only SMEC parameters
    // MCU Eng Par #4: SMEC encoder fine position
    SpireSendDrcuCmd(0x91d4006b,0);
    // MCU Eng Par #9: SMEC encoder sig2 amplitude
    SpireSendDrcuCmd(0x91d90059,0);
    delay(1);
    // MCU Eng Par #10: SMEC mean position error
    SpireSendDrcuCmd(0x91da006f,0);
    // MCU Eng Par #11: SMEC encoder sig1 amplitude
    SpireSendDrcuCmd(0x91db0057,0);
    delay(1);
    // MCU Eng Par #12: SMEC mean speed
    SpireSendDrcuCmd(0x91dc006e,0);
    // MCU Eng Par #13: SMEC DAC value
    SpireSendDrcuCmd(0x91dd0069,0);
    delay(1);
    // MCU Eng Par #14: SMEC LVDT position
    SpireSendDrcuCmd(0x91de0065,0);
    //
    SpireSendDrcuCmd(0x91c20000,0);
    // clear BSM sampling
    SpireSendDrcuCmd(0x91c00000,0);
    // clear SMEC sampling
    // Set MCU Eng sampling to 125Hz and start data generation
    SpireSendDrcuCmd(0x91c40013,0);
    delay(1);
    SpireSendDrcuCmd(0x91c3ffff,0);
    delay(1);
    SpireSendDrcuCmd(0x91c10001,0);
    delay(10);
    //
    // 
    // initialise variables
    int kp = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"kp");
    int ki = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"ki");
    int kd = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"kd");
    int smecHome = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"Home");
    int moveCmd = ilookup("SpireTable_SmecNominalSettings.txt",smecVersion,"MoveCmd");
    //
    // 
    //
    // Set scan speeds:
    SpireSendDrcuCmd(0x90470000 + moveCmd,0);
    SpireSendDrcuCmd(0x90560000 + moveCmd,0);
    delay(1);
    //
    //   **** INITIALISE  SMEC ****
    //
    // Set the Signal 1 & Signal 2 offsets to be outside the valid range
    SpireSendDrcuCmd(0x90588000,0);
    SpireSendDrcuCmd(0x905a8000,0);
    delay(1);
    //
    // Stop trajectory generation
    SpireSendDrcuCmd(0x90490000,0);
    delay(1);
    // Move the SMEC to 3mm
    SpireSendDrcuCmd(0x90450bb8,0);
    SpireSendDrcuCmd(0x90490001,0);
    // Allow enough time for SMEC to move from MR scan end
    delay(24);
    // 
    //
    // Stop trajectory generation
    SpireSendDrcuCmd(0x90490000,0);
    delay(1);
    //
    // Set the scan start and end positions to 3mm and 4mm
    SpireSendDrcuCmd(0x90460bb8,0);
    SpireSendDrcuCmd(0x90450fa0,0);
    delay(1);
    //
    // Set the number of scans to 4  - (TWG, 21-Aug-09 - increased from 2 scans)
    SpireSendDrcuCmd(0x90480004,0);
    delay(1);
    //
    // Run the SMEC offset VM to start scanning, determine and set the Signal 1 & Signal 2 offsets
    // Changed to run on VM1, with updated sample parameters (TWG, 21-Aug-09)
    //
    tstr = SpireTimeStr(time());
    {int}[] params = [{80},{100000}];
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM1(75,0,2," + params + ")");
    Spire_RUN_VM1(75,0,2,params);
    delay(10);
    //
    // Set Ki to 0
    SpireSendDrcuCmd(0x904d0000,0);
    delay(2);
    //
    // Stop trajectory generation
    SpireSendDrcuCmd(0x90490000,0);
    delay(1);
    //
    // Go to Mechanical Stop
    //
    SpireSendDrcuCmd(0x90450000,0);
    delay(1);
    SpireSendDrcuCmd(0x90490001,0);
    delay(10);
    //
    // Reset Encoder
    SpireSendDrcuCmd(0x90490004,0);
    delay(1);
    //
    // Start trajectory generation
    SpireSendDrcuCmd(0x90490001,0);
    // 
    // Set Kd
    SpireSendDrcuCmd(0x904b0000 + kd,0);
    delay(1);
    //
    // Set Kp
    SpireSendDrcuCmd(0x904a0000 + kp,0);
    delay(1);
    //
    // Close loop on encoder signals 
    SpireSendDrcuCmd(0x90440001,0);
    delay(2);
    //
    // Move the SMEC to 0.1mm
    SpireSendDrcuCmd(0x90450064,0);
    delay(4);
    //
    // Run the SMEC VM to set Ki if the encoder position is 0.1mm +/- 0.02mm
    // Changed to run on VM1 (TWG, 21-Aug-09)
    //
    tstr = SpireTimeStr(time());
    params = [{100},{20},{ki}];
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM1(75,1,3," + params + ")");
    Spire_RUN_VM1(75,1,3,params);
    delay(10);
    //
    // Move mechanism to scan start position ready to scan
    int scanStart1 = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanStart",specVersion,debug);
    SpireProc_SmecMove(scanStart1,100,debug);
    delay(3);
    //
    // Stop MCU Eng data, flush MCU FIFO and set MCU Eng sampling to off 
    //
    SpireSendDrcuCmd(0x91c10000,0);
    delay(2);
    Spire_FLUSH_FIFO(0x2000);
    delay(1);
    SpireSendDrcuCmd(0x91c40000,0);
    //
    //
    //   **** SCAN IN CLOSED LOOP WITH THE SMEC ****
    //
    //
    // Retrieve required SMEC params
    // 
    int resId = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ResId",specVersion,debug);
    int scanStart = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanStart",specVersion,debug);
    int scanEnd = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanEnd",specVersion,debug);
    int scanFSpeed = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanFSpeed",specVersion,debug);
    int scanRSpeed = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanRSpeed",specVersion,debug);
    int scanFCmd = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanFCmd",specVersion,debug);
    int scanRCmd = SpireProc_GetTableEntryInt("SpireTable_Spectrometer.txt","ResChar",resolution,"ScanRCmd",specVersion,debug);
    string waveform = SpireProc_GetTableEntryString("SpireTable_Spectrometer.txt","ResChar",resolution,"Waveform",specVersion,debug);
    //
    //  adjust nscans to obtain correct number of scans at observing speed 
    if(waveform == "SAWTOOTH") {
        nscans = nscans * 2;
    }
    //
    // Calculate the scan 'forward','reverse' travel times 
    int scanFTime = (scanEnd - scanStart) * (nscans / 2) / scanFSpeed;
    int scanRTime = (scanEnd - scanStart) * (nscans / 2) / scanRSpeed;
    //
    //
    // Set SCANRES parameter
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_UPDATE_TABLE_RAW(7, 6, 1, " + resId + ")");
    Spire_UPDATE_TABLE_RAW(7,6,1,[{resId}]);
    // Set SMEC to hold its position
    SpireSendDrcuCmd(0x90490000,0);
    // 
    // execute scans
    //
    // Set scan start and ending position
    //
    SpireSendDrcuCmd(0x90460000 + scanStart,0);
    SpireSendDrcuCmd(0x90450000 + scanEnd,0);
    delay(1);
    //
    // Set scan forward and reverse speed (only different if we are performing a saw tooth scan) 
    SpireSendDrcuCmd(0x90470000 + scanFCmd,0);
    SpireSendDrcuCmd(0x90560000 + scanRCmd,0);
    delay(1);
    //
    // Specify number of scans 
    SpireSendDrcuCmd(0x90480000 + nscans,0);
    //
    // Set number of frames to continuous
    //
    SpireSendDrcuCmd(0x91c3ffff,0);
    // Start SMEC data collection
    int smecFrameRate = SpireProc_GetTableEntryInt("SpireTable_SpecModeParams.txt","mode","Scan","smecFrameRate",smecVersion,debug);
    SpireSendDrcuCmd(0x91c00000 + smecFrameRate,0);
    // 
    delay(1);
    SpireSendDrcuCmd(0x91c10001,0);
    //  set datarate
    double rate = 0.0;
    rate = rate + dlookup("Datarates.txt","Scan","BSM");
    rate = rate + dlookup("Datarates.txt","Scan","SMEC");
    data_rate(rate);
    //
    // Start scanning
    SpireSendDrcuCmd(0x90490002,0);
    delay(scanFTime + scanRTime + nscans + 2);
    // allow 1 sec for turnaround at end of each scan
    //
    // When scan is finished stop data generation
    //
    SpireSendDrcuCmd(0x91c10000,0);
    data_rate(0.0);
    delay(1);
    Spire_FLUSH_FIFO(0x2000);
    delay(1);
    // hold position
    SpireSendDrcuCmd(0x90490000,0);
    //
    // reset SCANRES parameter
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_UPDATE_TABLE_RAW(7, 6, 1, " + 0 + ")");
    Spire_UPDATE_TABLE_RAW(7,6,1,[{0}]);
    //
    // **** MOVE SMEC TO HOME ****
    // 
    // Set SMEC to Home position
    SpireSendDrcuCmd(0x90490000,0);
    // set Home position
    SpireSendDrcuCmd(0x90450000 + smecHome,0);
    SpireSendDrcuCmd(0x90460000,0);
    delay(1);
    //
    SpireSendDrcuCmd(0x90470000 + moveCmd,0);
    SpireSendDrcuCmd(0x90560000 + moveCmd,0);
    delay(1);
    //
    // **** OPEN THE SMEC LOOP ****
    // 
    // Open the control loop
    SpireSendDrcuCmd(0x90440006,0);
    delay(4);
    // move it
    SpireSendDrcuCmd(0x90490001,0);
    delay(20);
    // hold current position
    SpireSendDrcuCmd(0x90490000,0);
    delay(1);
    //
    // **** SWITCH OFF SMEC SENSORS ****
    // 
    //
    // switch off position sensors
    SpireSendDrcuCmd(0x90400000,0);
    SpireSendDrcuCmd(0x90410000,0);
    delay(1);
    //
    // Set SMEC Kp and Ki to 0 (SPIRE SCR-1719)
    SpireSendDrcuCmd(0x904a0000,0);
    SpireSendDrcuCmd(0x904d0000,0);
    delay(1);
    //
    // Set SMEC sampling rate back to REDY mode
    //
    smecFrameRate = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","REDY","smecFrameRate",smecVersion,debug);
    SpireSendDrcuCmd(0x91c00000 + smecFrameRate,0);
    // 
    delay(1);
    //
    //
    // ..... completion .....
    //
    sync();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_EngSmecScan ended");
    SpireMsg(1,"  ..Scanning (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// 
// SpireSpectroPeakup.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// This observation executes a Peakup observation
// 
// The instrument should be in  the SPECSTBY mode before execution 
// of this procedure.
//
// The peakup offset generated takes effect with the next observation 
// so this observation should be concatenated with a following observation 
// that requires peaking up
//
// 17/03/2009  KJK first version
//  Adapted from 17/03/2009 version of SpirePhotoPeakup
//25/09/2009 kjk: SCR Spire-1932
//        modified call to SpirePeakup to pass on versions etc
//        added default values for versions
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpireSpectroPeakup {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; // NAIF identifier
    string boresight = ""; // Instrument Boresight
    bool isBright = false; // Use settings for bright source (==tick)
    string opsVersion = "v00"; // Version in Table_OpsParms cal table 
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int step = 0;
    string comVersion = "v00";
    string pmodeVersion = "v00";
    string smodeVersion = "v00";
    string smecVersion = "v00";
    string peakVersion = "v00";
    string siamVersion = "v00";
    //
    // Lookup boresight, if not provided
    string ib = boresight;
    if(boresight == "") {
        ib = SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode","SOF1","Boresight",opsVersion,debug);
    }
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    int tslewmin = duration(SpireBbStartObs());
    //
    // BBs carried out when the pointing is reached:
    int tinithold = duration(SpireBb_SpecOffsetAuto(false,debug)) + duration(SpireBbSetSmecSampling("SPeakup",smecVersion,debug));
    //
    // BB carried out during pointing:
    int tp = duration(SpirePeakup("SPeakup",ib,0,comVersion,pmodeVersion,smodeVersion,peakVersion,siamVersion,debug));
    //
    // BB carried out at the end:
    int tfinalhold = duration(SpireBbEndObs()) + duration(SpireBbSetSmecSampling("SPECSTBY","v00",debug));
    //
    // Debug_printing?
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                              */
    // ****************************************************** */
    //
    // Set pointing mode:
    //
    int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    // 
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
        debug_print("Boresight: " + ib);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBbStartObs();
            // 
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // Set offsets: 
            //
            SpireBb_SpecOffsetAuto(false,debug);
            SpireBbSetSmecSampling("SPeakup",smecVersion,debug);
            //
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            // //
            // //
            // Execute  Peakup
            //
            SpirePeakup("SPeakup",ib,0,comVersion,pmodeVersion,smodeVersion,peakVersion,siamVersion,debug);
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activities )
            // //
            // // 
            // Reset OBSID and BBID:
            //
            SpireBbSetSmecSampling("SPECSTBY","v00",debug);
            SpireBbEndObs();
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

//
// Script to perform standalone SMEC scans from REDY mode 
// 05-Jul-2010: Version 1.0 SDS
//                      Created in response to SCR SPIRE-2564
//
//
// 06-Jul-2010: Version 1.1 SDS
//                      Added basic MOIS statements
//                      Changed resolution from Low to High
//
//
obs SpireEngSmecScan {
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string res = "H" in ["H","L"]; // Spectral resolution;
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use)
    int pInt2 = 0; // Spare parameter (currently not in use)
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    string smecVersion = "v00";
    string specVersion = "v00";
    int nscans = 2;
    int t = duration(SpireBbStartObs()) + duration(SpireBbEndObs());
    t = t + duration(SpireBbSetNhkSampling("SPECSTBY","v00",debug));
    t = t + duration(SpireBb_EngSmecScan(smecVersion,specVersion,res,nscans,debug));
    t = t + duration(SpireBbSetNhkSampling("REDY","v00",debug));
    // // 
    // //
    // ***********************************************
    int[] ts = no_pointing(true,0,0,t);
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            mois_comment("Procedure SpireEngSmecScan: to scan the SMEC standalone in REDY mode");
            mois_comment("Procedure starts and ends in SPIRE REDY mode");
            mois_comment("The OBSID needs to be set manually in the first TC");
            mois_tmcheck("Verify that the OBSID has been set correctly");
            mois_comment("No other manual TM checks or intervention is necessary");
            mois_comment("Rest of commands in procedure can be executed automatically");
            SpireBbStartObs();
            // set SPECSTBY housekeeping rate (1Hz)
            SpireBbSetNhkSampling("SPECSTBY","v00",debug);
            SpireBb_EngSmecScan(smecVersion,specVersion,res,nscans,debug);
            // set REDY mode housekeeping rate (0.25Hz)
            SpireBbSetNhkSampling("REDY","v00",debug);
            SpireBbEndObs();
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartPcalLevelCheck.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpirePhoto/Spectro_Cal_PcalLevelCheck.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/07 V0.1: Initial version adapted from
//                  SpireBb_StartBsmAngleCal (2009/05/05 V0.1),
//                  SpirePhoto_Cal_PcalLevelCheck (2009/03/04 V1.4), and
//                  SpireSpectro_Cal_PcalLevelCheck (2009/03/04 V0.5)
//                  BB includes now to move BSM/SMEC to hold/home.  
// 2009/07/10 V1.0: Fix bug SPR-SPIRE-1612
// 
// Notes:
//    1) Scripts assumes that SpireBb_SpecOffsetAuto is run 
//       during INITHOLD or at first POINTING.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartPcalLevelCheck SPIRE 14064 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    string obsModeQla = "ENG_CAL_OBS09";
    string obsMode = "PEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_Phot/SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    int smecHomePosn = 3500; // SMEC home position
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartPcalLevelCheck configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // In case move SMEC to home:
    // 
    if(!phot) {
        //
        // Calculate available time for possible movement:
        //
        int tmove = duration(SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug)) + duration(SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug)) + duration(SpireProc_Set_ObsStep(999,debug)) + duration(SpireBb_SpecOffsetAuto(false,debug));
        //
        // Calculate max offset for which time is available:
        //
        int smecMaxOff = tmove * 500;
        // Note, 500 is maximum possible SMEC speed.
        int smecStart = smecHomePosn + smecMaxOff;
        // Note, formula above only reasonable 
        // when smecHomePosn small compared to 39500  
        // Safety check: 
        if(smecStart > 39500) {
            smecStart = 39500;
        }
        if(debug) {
            debug_print("smecStart: " + smecStart);
            debug_print("smecHomePosn: " + smecHomePosn);
            debug_print("tmove: " + tmove);
        }
        // 
        // Move from maximal offset to home:
        //
        SpireProc_SmecMove2Home(smecHomePosn,smecHomePosn + smecMaxOff,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    if(phot) {
        SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    }
    //delay(timeSlewCal);
    // //
    // //
    // Set NHK STEP parameter to count PCAL levels:
    //
    int obsStep = 1;
    SpireProc_Set_ObsStep(obsStep,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartPcalLevelCheck configuration ended");
    SpireMsg(1,"  ..StartPcalLevelCheck took " + (time() - t) + " seconds)");
    //
}

// Missionphase  : EQM IMT
//
// Purpose	: Switch on/off and enable/disable a controller for a PACS
//                internal Calibration Source
//
// Author	: DAC
// CUS script	: DAC
// CVS file	: CS_on_off.txt
//
// Arguments	:
// type  name               Description
// string   cal_source      Either CS1 or CS2
// string   on_off          Either ON or OFF  
//
// Description	: Switch on/off and enable/disable controller for selected
//                PACS internal CS (calibration source)
//                  
// Dependencies : 
//
// Preconditions : Configuration parameters have been uploaded for CS1 and CS2
//                 
// Comments	: Several ways exist to fill in the preconditions, 
//                e.g. CONF_csx, or SetupSpectroscopyEQMIMT.
//
// Version	: 1.0
//               
// History	: 1.0 12-Apr-2005 Creation by DAC
//
procedure CS_on_off {
    string cal_source = "CS1" in ["CS1","CS2"];
    string on_off = "ON" in ["ON","OFF"];
}{
    // Start with internal source CS1
    if(cal_source == "CS1") {
        if(on_off == "ON") {
            Pacs_DMC_SWON_BB_1_CONT();
            Pacs_DMC_ENABLE_BB_1_CONT();
        }
        if(on_off == "OFF") {
            Pacs_DMC_DISABLE_BB_1_CONT();
            Pacs_DMC_SWOF_BB_1_CONT();
        }
    }
    // Continue with CS2
    if(cal_source == "CS2") {
        if(on_off == "ON") {
            Pacs_DMC_SWON_BB_2_CONT();
            Pacs_DMC_ENABLE_BB_2_CONT();
        }
        if(on_off == "OFF") {
            Pacs_DMC_DISABLE_BB_2_CONT();
            Pacs_DMC_SWOF_BB_2_CONT();
        }
    }
    // end of procedure
}

// SpireSOF12Observing
//
// $Id:$
//
// This is the  procedure to calculate instrument parameters for 
// the spectrometer single pointing observing mode
//
//  03/02/2009: KJK
//          changed input interface to accept 2 sets of scan info in order to call SpirePointSpectrum correctly
//          now calls SpireProc_SFlash to get PCAL flash duration (including SMEC movement times)
// 04/03/2009: MP Fixed bug in call to 
//           SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode"...)
// 03/09/2009: KJK
//           Added bsmVersion and smecVersion as input parameters
// 29/09/2009 MP: SPR-SPIRE-2048
//       Fix bug with hardcoded SFlash for isBright. Here change call to
//       SpirePointSpectrum.  
// 16/02/2010 KJK: SCR Spire-2341:
//       Updated to get Flash/Cal info from SpireTable_SpireParams rather than SpireParams
//       This required a additional input parameter - spireVersion
// 
//////////////////////////////////////////////////////////////////////////
{int,double,int,double,int,double,int,double,int,int,double,int,double} procedure SpireSOF12Observing {
    string opsMode = "SOF1" in ["SOF1","SOF2","SOF2_int"]; // operations mode
    string res1 = "H" in ["H","M","C","L"]; // resolution for set 1
    string res2 = "L" in ["H","M","C","L"]; // resolution for set 2
    int nRepetitions1 = 2; // number of times to repeat spectral scan pairs for 1st set of scans
    int nRepetitions2 = 0; // number of times to repeat spectral scan pairs for 2nd set of scans
    string bsmVersion = "v00";
    string smecVersion = "v00";
    string specVersion = "v00";
    string opsVersion = "v00";
    string spireVersion = "v00";
    string flashVersion = "v00";
    bool isBright = false;
    bool debug = false;
}{
    string version = "v00";
    SpireMsg(2,"    " + opsMode + " Observing Parameters");
    SpireMsg(2,"    $Id:$");
    //
    // fetch operating parameters 
    int t = 0;
    t = SpireProc_GetTableEntryInt("SpireTable_SpireParams.txt","mode",opsMode,"FlashTime",spireVersion,debug);
    double flashTime = double(t);
    // Optimum time between flashes
    t = SpireProc_GetTableEntryInt("SpireTable_SpireParams.txt","mode",opsMode,"CalTime",spireVersion,debug);
    double calTime = double(t);
    string ib = SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode",opsMode,"Boresight",opsVersion,debug);
    // instrument boresight
    // initial flash flag
    bool initFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",opsMode,"InitFlash",spireVersion,debug);
    // final flash flag
    bool endFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",opsMode,"EndFlash",spireVersion,debug);
    double srcTime1 = SpireProc_GetTableEntryDouble("SpireTable_Spectrometer.txt","ResChar",res1,"Osit",specVersion,debug);
    // effective on source integration time per scan
    double srcTime2 = SpireProc_GetTableEntryDouble("SpireTable_Spectrometer.txt","ResChar",res2,"Osit",specVersion,debug);
    // effective on source integration time per scan
    double scanTime1 = SpireProc_GetTableEntryDouble("SpireTable_Spectrometer.txt","ResChar",res1,"ScanTime",specVersion,debug);
    // time per  scan
    double scanTime2 = SpireProc_GetTableEntryDouble("SpireTable_Spectrometer.txt","ResChar",res2,"ScanTime",specVersion,debug);
    // time per  scan
    int jiggleTable = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"TableId",opsVersion,debug);
    // Jiggle Table ID
    int jiggleSize = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"TableSize",opsVersion,debug);
    // Jiggle Table length 
    //     
    // *****************************************
    //   Display input parameters
    // *****************************************
    SpireMsg(3,"     " + opsMode + " Logic Input values:");
    SpireMsg(3,"     ..Resolution1: " + res1);
    SpireMsg(3,"     ..Resolution2: " + res2);
    SpireMsg(3,"     ..nRepetitions1: " + nRepetitions1);
    SpireMsg(3,"     ..nRepetitions2: " + nRepetitions2);
    SpireMsg(3,"     ..specVersion: " + specVersion);
    SpireMsg(3,"     ..opsVersion: " + opsVersion);
    SpireMsg(3,"     ..flashVersion: " + flashVersion);
    SpireMsg(3,"     " + opsMode + "  Fixed values:");
    SpireMsg(3,"     ..ib: " + ib);
    SpireMsg(3,"     ..initFlash: " + initFlash);
    SpireMsg(3,"     ..endFlash: " + endFlash);
    SpireMsg(3,"     ..srcTime1: " + srcTime1);
    SpireMsg(3,"     ..srcTime2: " + srcTime2);
    SpireMsg(3,"     ..scanTime1: " + scanTime1);
    SpireMsg(3,"     ..scanTime2: " + scanTime2);
    SpireMsg(3,"     ..jiggleTable: " + jiggleTable);
    SpireMsg(3,"     ..jiggleSize: " + jiggleSize);
    //
    // *****************************************
    // calculate observing parameters
    // *****************************************
    SpireMsg(2,"    Calculated Parameters:");
    //
    int nMaps = 1;
    // always is 1 for SOF1/2
    //
    int nCycles1 = 0;
    int nCycles2 = 0;
    double tCycle1 = 0.0;
    double tCycle2 = 0.0;
    double osit1 = 0.0;
    double osit2 = 0.0;
    //
    //  number of scans to perform
    int ms = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"MinScans",opsVersion,debug);
    double minScans = double(ms);
    int scansPerCycle1 = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"N" + res1 + "Scans",opsVersion,debug);
    int scansPerCycle2 = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",opsMode,"N" + res2 + "Scans",opsVersion,debug);
    double ns = 0.0;
    // number of scans
    //
    // find number of cycles to perform and the time they take
    //
    int nScans1 = 0;
    ns = double(nRepetitions1 * 2);
    if(ns < minScans) {
        ns = minScans;
        SpireMsg(1,"      Number of requested Set 1 scans below minimum: " + ns + " - value has been set to " + minScans);
    }
    // round number of scans to integral number of cycles 
    nScans1 = scansPerCycle1 * ifloor(ns / double(scansPerCycle1));
    if(nScans1 < scansPerCycle1) {
        nScans1 = scansPerCycle1;
    }
    SpireMsg(3,"      Required number of Set 1 scans : " + nScans1);
    osit1 = double(nScans1) * srcTime1;
    SpireMsg(3,"      Set 1 on source time : " + osit1);
    nCycles1 = nScans1 / scansPerCycle1;
    SpireMsg(3,"      Number of Set 1 cycles: " + nCycles1);
    tCycle1 = double(scansPerCycle1) * scanTime1;
    int nScans2 = 0;
    ns = double(nRepetitions2 * 2);
    if(ns < minScans) {
        ns = minScans;
        SpireMsg(1,"      Number of requested Set 2 scans below minimum: " + ns + " - value has been set to " + minScans);
    }
    // round number of scans to integral number of cycles 
    nScans2 = scansPerCycle2 * ifloor(ns / double(scansPerCycle2));
    if(nScans2 < scansPerCycle2) {
        nScans2 = scansPerCycle2;
    }
    if(nRepetitions2 == 0) {
        nScans2 = 0;
    }
    SpireMsg(3,"      Required number of Set 2 scans : " + nScans2);
    osit2 = double(nScans2) * srcTime2;
    SpireMsg(3,"      Set 2 on source time : " + osit2);
    nCycles2 = nScans2 / scansPerCycle2;
    SpireMsg(3,"      Number of Set 2 cycles: " + nCycles2);
    tCycle2 = double(scansPerCycle2) * scanTime2;
    //
    // estimate time on source with no flashes
    //
    double pointTime = 0.0;
    double totalTime = 2.0;
    for(int i = 0 .. jiggleSize - 1) {
        totalTime = totalTime + double(duration(SpireBbBsmMove(jiggleTable,i,0)));
        totalTime = totalTime + double(duration(SpirePointSpectrum(res1,nCycles1,tCycle1,scansPerCycle1,res2,nCycles2,tCycle2,scansPerCycle2,99999.0,0,bsmVersion,smecVersion,specVersion,flashVersion,isBright,debug)));
        if(i == 0) {
            pointTime = totalTime;
        }
    }
    SpireMsg(3,"      Observing time per point: " + pointTime);
    SpireMsg(3,"      Total observing time: " + totalTime);
    //
    // calculate when Gyro calibrations and PCAL flashes are needed
    // during the scanning at one point
    //
    //
    // Gyro calibration information
    double tCal = calTime;
    int nCals = ifloor(pointTime / calTime);
    if(nCals > 0) {
        tCal = pointTime / double(nCals + 1);
    }
    // SpireMsg(3,"      Number of Gyro Calibrations per point: " + nCals);
    // SpireMsg(3,"      Time between Gyro calibrations: " + tCal);
    //
    // PCAL calibration information
    double tFlash = flashTime;
    int nFlashes = ifloor(pointTime / flashTime);
    if(nFlashes > 0) {
        tFlash = pointTime / double(nFlashes + 1);
    }
    SpireMsg(3,"      Number of Flashes per point: " + nFlashes);
    SpireMsg(3,"      Time between Flashes: " + tFlash);

    return {nCycles1,tCycle1,scansPerCycle1,osit1,nCycles2,tCycle2,scansPerCycle2,osit2,nMaps,nFlashes,tFlash,nCals,tCal};
}

// SpireSetMode
//
// $id$
//
// This building block sets the Observing Mode parameter
// 
// 27/10/2009 KJK:
//           SPR Spire_2049: now calls SpireTableInstConfigs
//
procedure SpireSetObsMode {
    string obsmode = "REDY"; // name of the  mode
}{
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    // find mode number
    int modeid = ilookup("SpireTableInstConfigs.txt",obsmode,"value");
    //
    // set it 
    hstr = SpireHexStr(modeid,4);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_MODE_RAW(" + hstr + ")");
    Spire_SET_OBS_MODE_RAW(modeid);
}

//
// Author	: DAC
// CUS script	: DAC
// CVS file	: 
//
// Arguments	:
// type     name         Description
// string   cal_source   Internal CAL source CS1 or CS2
// double   resist_temp  Desired resistance [ohm]
//
// Description	: Set the temperature of a PACS internal Calibration source  
//                  
// Dependencies : 
//
// Preconditions : Configuration parameters have been uploaded  and the 
//                 controller has been SWON & enabled
//                 
// Comments	: 
//
// Version	: 1.0
//               
// History	: 1.0 13-Apr-2005 Creation by DAC
//
procedure CS_temp {
    string cal_source = "CS1" in ["CS1","CS2"]; // Chosen calibration source
    double resist_temp = 80.0; // The desired resistance of CS2, in Ohms
}{
    // Start with CS1
    if(cal_source == "CS1") {
        Pacs_DMC_SET_TEMP_BB_1(resist_temp);
    }
    // Continue with CS2
    if(cal_source == "CS2") {
        Pacs_DMC_SET_TEMP_BB_2(resist_temp);
    }
}

// $Id
// Purpose        : Bring PACS from switched off condition to standby
//                  for PHOT observations
//
// CUS author     : Composed from various ILT modules
//
// Input arguments: see after module identification
//
// Return values
// N/A
//
// Comments      :
//
// History: 
// 0.1  25-jun-2007  Created from ILT modules
// 0.2   9-aug-2007  Conformed to JonBr's mail (07/26/07)
// 1.0  21-aug-2007  Renamed from PACS_PHOT_orbit_prologue
//                                Use new "no_pointing" pointing request and
//                                StateMachine logic
// 1.1 20-may-2008  KO, Debugged for the pointing timing logic
// 1.2 24-jun-2008 KO, calUfile, temp_CS1 and temp_CS2 put in the argument
// 1.3 25-jun-2008 KO, CSs stabilisation time tSET put in the argument and the default calUfile changed to ILT
// 1.4 11-nov-2008 VD&KO&TM tSet chnaged to 2100s to allow for stabilisation
// 1.5 12-nov-2008 KO gotoDirect option added
// 2.0 26-feb-2009 VD SpirePacsParallel pacs Prologue specific
//
obs SpirePacsEng_Parallel_PacsPrologue {
    string calUfile = "BOLObias_ILT_standard_low"; // Bias table
    double set_CS1 = 48.0; // CS1 settings (ohms)
    double set_CS2 = 58.0; // CS2 settings (ohms)
    int tSET = 2100; // CSs stabilisation time in seconds
    bool gotoDirect = true in [true,false]; // DDCS setting to Direct setting
}{
    // Settling time for CS
    string fltPOS = "POS A";
    bool execute = true;
    // Initial hold
    int tih = imax(1,duration(WriteOBSID($OBSID)));
    // Final hold
    int tfh = imax(1,duration(WriteEndID())) + tSET;
    // Duration of "stable" pointing
    int tp = duration(PHOT_setup(calUfile,fltPOS,set_CS1,set_CS2,gotoDirect));
    // Issue PointReq
    int[] ts = no_pointing(execute,tih,tfh,tp);
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            //     Obtain and set OBSID
            WriteOBSID($OBSID);
            data_rate(120.0);
        }
        if(state[0] == 3) {
            //     Call the PHOT setup script
            PHOT_setup(calUfile,fltPOS,set_CS1,set_CS2,gotoDirect);
        }
        if(state[0] == 5) {
            //     Wait for CS to stabilize
            delay(tSET);
            //     Reset OBSID and BBID
            data_rate(0.0);
            WriteEndID();
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_SmecHold.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to stop SMEC trajectory generation.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/31 V0.1: Initial version 
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_SmecHold {
    bool debug = false;
}{
    // //
    // //
    // Define some variables:
    //
    int t = time();
    //
    // hex string:
    string hstr = "";
    //
    // time string:
    string tstr = "";
    //
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(3,"      " + tstr + ": Proc SmecHold started");
    SpireMsg(3,"            $Id: $");
    // //
    // //
    // Set SMEC mode to hold its position:
    //
    SpireSendDrcuCmd(0x90490000,0);
    sync();
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(3,"      " + tstr + ": Proc SmecHold ended");
    SpireMsg(2,"    Proc SmecHold (" + (time() - t) + " seconds)");
}

// SpirePOF2Pointing
//
// $id$
//
// This procedure calculates and returns the pointing parameters for the POF2 observing mode  
//
//  11/02/09: KJK Updated to reflect changed configuration and reconfiguration stages
//  02/07/2009  KJK:
//         Added configuration input parameters to pass to SpirePOF2Config and SpirePOF2End
//  05/07/2009 KJK:
//         SPR-1593 - added flashVersion to input parameters
//                         - changed call to SpireBbPcalFlash
//  04/08/2009 SDS:
//         SPR-1752 - Updated to allow the loading of a new JM07 table (uses the boolean pBool1)
//                    Now references SpireTable_OpsParms.txt (previously OpsParms.txt)
//                    Booleans InitFlash and EndFlash now read from SpireTable_SpireParams.txt (previously OpsParms.txt)
//                    New input parameter opsVersion added
//  10/08/2009 KJK:
//         SPR-1709:  Added new input parameter, comVersion to call to SpreBbPOF2Config
//  12/08/2009 KJK:
//         SPIRE-1804:Added chopVersion as new input parameter 
//                           Changed calls to SpirebBJiggle to provide versions and debug parameters
//  14/08/2009 KJK:
//         Spire-1759: Added duration of SpireBb_LoadTableJM07b() to tSlewMin, if necessary - it is no longer calculated
//                            in SpirePOF2Config()
//  25-Aug-2009 KJK:
//        SPR Spire-1641: Needed new input parameters bsmModel and bsmVersion
//  10-Sep-2009 KJK:
//        SCR Spire-1943: Needed new input parameter detVersion
//  16-Feb-2010 KJK:
//        SCR Spire-648: added time for movement of BSM to Home for  HOLD and FINAL_HOLD times
//
{int,int,int,int,int,int} procedure SpirePOF2Pointing {
    int nCycles = 1; // total number of number of nod cycles to perform
    int nNodInts = 1; // number of nod integrations per nod position    
    int nCal = 99999; // number of nod cycles per pointing calibration
    int nFlash = 99999; // number of nod cycles per PCAL flash
    bool isBright = false;
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string detVersion = "v00";
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParms
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    string flashVersion = "v00";
    string chopVersion = "v00"; // Version in cal table SpireTable_ChopParams
    string photVersion = "v00";
    string comVersion = "v00";
    bool debug = false;
    bool pBool1 = false; // Load new JM07 table? 
}{
    string obsMode = "POF2";
    // Jiggle Table ID
    int jiggleTable = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"TableId",opsVersion,debug);
    // Jiggle Table length
    int jiggleSize = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"TableSize",opsVersion,debug);
    // number of jiggle positions per nod position
    int nJiggs = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NJiggs",opsVersion,debug);
    // number of nod positions in a nod cycle
    int nNodPosns = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NNodPosns",opsVersion,debug);
    // initial flash flag
    bool initFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"InitFlash",spireVersion,debug);
    // final flash flag
    bool endFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"EndFlash",spireVersion,debug);
    //
    // ***** check inputs *****
    int nMoves = nCycles * nNodPosns / 2;
    if(nMoves > 1200) {
        error("POFS2Pointing: number of nod switches is greater  than maximum allowed (1200): " + nMoves);
    }
    //
    // ****** calculate parameters for pointing mode ******
    //
    // minimum slew time
    int tSlewMin = duration(SpireBb_StartObsAll("POF2")) + duration(SpireBbPOF2Config("POF2",isBright,photVersion,comVersion,debug)) + 2;
    if(pBool1) {
        tSlewMin = tSlewMin + duration(SpireBb_LoadTableJM07b());
    }
    //
    // time for Initial Hold
    int tInitHold = duration(SpireBbPOF2Init()) + 2;
    int tFlash = duration(SpireBbPcalFlash("PFlash",flashVersion,0,debug));
    if(initFlash || nFlash < nCycles) {
        tInitHold = tInitHold + tFlash;
    }
    //
    // time for Final Hold 
    int tBsmMove = duration(SpireBb_BsmMove2Hold(bsmModel,bsmVersion,debug));
    int tFinalHold = duration(SpireBbPOF2End("PHTSTBY",isBright,bsmModel,bsmVersion,detVersion,photVersion,comVersion,debug)) + duration(SpireBb_EndObsAll(true)) + 2;
    if(endFlash || nFlash < nCycles) {
        tFinalHold = tFinalHold + tFlash + tBsmMove;
    }
    //
    // time at hold position
    int tHold = tFlash + tBsmMove + 2;
    //
    // number of nods per hold
    int nHold = 0;
    if(nFlash < nCycles) {
        nHold = nFlash * nNodPosns / 2;
    }
    //
    // time per point
    int tp = duration(SpireBbJiggle("POF2",jiggleTable,0,nJiggs,nNodInts,0,opsVersion,chopVersion,debug)) + duration(SpireBbMove(0)) + 2;
    //

    return {tSlewMin,tInitHold,tFinalHold,tp,tHold,nHold};
}

// SpireBbBsmOn
//
// $id$
//
// This building block switches on the BSM
// 
// The instrument should be in  the REDY mode before execution of this building block
//
// 27/04/2009 KJK: 
//         Updated to use new NominalSettings Cal Tables
//         model, version and debug passed as parameters
// 07/05/2009 KJK:
//         Added opsMode as input parameter to allow setting of mode dependant parameters
//
block SpireBbBsmOn SPIRE 256 {
    string opsMode = "PHTSTBY";
    string model = "initial";
    string version = "v00";
    bool debug = false;
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB BSM On started");
    SpireMsg(2,"          $Id$");
    //
    // intialise variables
    int chop_ff_gain = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",model,"chop_ff_gain",version,debug);
    int jigg_ff_gain = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",model,"jigg_ff_gain",version,debug);
    //
    // 
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    delay(1);
    //
    // set Step to zero
    SpireSetObsStep(0);
    //
    // Flag the current operation
    SpireSetObsMode("BSM_ON");
    delay(1);
    // 
    // Switch ON chop and jiggle sensors  
    SpireSendDrcuCmd(0x90c00001,0);
    SpireSendDrcuCmd(0x91400001,0);
    delay(1);
    // 
    // Force open loop in both axis 
    SpireSendDrcuCmd(0x90c20003,0);
    SpireSendDrcuCmd(0x91420003,0);
    //
    // Set Chop and jiggle ff gain 		
    SpireSendDrcuCmd(0x90cd0000 + chop_ff_gain,0);
    SpireSendDrcuCmd(0x914d0000 + jigg_ff_gain,0);
    //
    // Set Movement Mode
    SpireSendDrcuCmd(0x90c60000,0);
    //   
    // Set Chop and Jiggle Target Positions to centre POSITIONS  
    SpireSendDrcuCmd(0x90c38000,0);
    SpireSendDrcuCmd(0x91438000,0);
    sync();
    //
    // completion
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB BSM On   ended");
    SpireMsg(1,"  ..BSM ON (" + (time() - t0) + " seconds)");
}

// SpirePhotoSmallScan
//
// $Id: $
//
// Implementation of a small scan map observation without chopping
//
// Assumptions:
//    1. the instrument is in the PHOT_STBY configuration on entry
//
//  20/01/10:  v1.0: First version - copied from SpirePhotoLargeScan and updated for POF10
//  15/02/2010 KJK: SCR Spire-1887:
//                             Added spireVersion to input parameters for call to SpirePOF5Observing
//
///////////////////////////////////////////////////////////////////////////////
{int,int,int,int} obs SpirePhotoSmallScan {
    double ra = 0.0 in [0.0,360.0]; // RA of Target
    double dec = 0.0 in [-90.0,90.0]; // DEC of Target
    int naifid = 0; // NAIF identifier
    string source = "small" in ["point","small","large"]; // source type
    string scanDirection = "scanab" in ["scana","scanb","scanab"];
    double mapOffsetY = 0.0 in [-300.0,300.0]; // mapOffsetY [arc minutes]
    double mapOffsetZ = 0.0 in [-300.0,300.0]; // mapOffsetZ [arc minutes]
    string mapScanRate = "nominal" in ["nominal","fast"]; // selected scan rate
    bool mapOrientationArray = true; // is the map orientation an array (rather than array with constraints)
    double mapOrientationConFrom = 0.0 in [0.0,360.0];
    double mapOrientationConTo = 360.0 in [0.0,360.0];
    int nRepetitions = 1 in [1,100]; // number of  map repeats
    double sourceFluxPSW = -1.0;
    double sourceFluxPMW = -1.0;
    double sourceFluxPLW = -1.0;
    double sourceBrightPSW = -1.0;
    double sourceBrightPMW = -1.0;
    double sourceBrightPLW = -1.0;
    bool isBright = false; // Use settings for bright source (==tick)
    bool isRasterMap = false;
    int nRasters = 1; // number of times to repeat map
    int nPoints = 1; // not used
    int nMaps = 1; // not used
    int nCycles = 1; // not used
    int nNodInts = 1; // not used
    int nLines = 1; // number of scan lines in map
    int nCal = 999999; // number of lines between Gyro calibrations
    int nFlash = 999999; // number of lines between PCAL flashes
    int nLinesx = 1; // number of scan lines in cross scan map
    int nCalx = 999999; // number of lines between Gyro calibrations in cross scan map
    int nFlashx = 999999; // number of lines between PCAL flashes in cross scan map
    string bsmModel = "initial";
    string bsmVersion = "v00"; // Version in cal table SpireTable_BsmNominalSettings.txt
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParms
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    string flashVersion = "v00"; // Version in cal table SpireTable_FlashParms
    string photVersion = "v00"; // Version in cal table SpireTable_PhotModeParams.txt
    string comVersion = "v00"; // Version in cal table SpireTable_CommonModeParams.txt
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // check inputs
    if(source != "small") {
        error("SpirePhotoSmallScan: Source is not a small map");
    }
    if(isRasterMap) {
        error("SpirePhotoLargeScan: Raster Map Selected");
    }
    // //
    // //
    // Declare some variables:
    //
    double mapSize1 = 0.0;
    double mapSize2 = 0.0;
    int tSlewMin = 0;
    int tInitHold = 0;
    int tFinalHold = 0;
    int tHold = 0;
    int nHold = 0;
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string selValN = "";
    string selValO = "";
    string tarCol = "";
    string version = "";
    double patt = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName05 = "SpireTable_OpsParms.txt";
    //
    // *****************************************
    //      set up telescope pointing mode    
    // *****************************************
    //
    string obsMode = "POF10";
    if(mapScanRate == "fast") {
        obsMode = obsMode + "_F";
    } else {
        obsMode = obsMode + "_S";
    }
    string obsModeN = obsMode + "_N";
    string obsModeO = obsMode + "_O";
    if(debug) {
        debug_print("Selected obsMode: " + obsModeN + "/" + obsModeO);
    }
    // //
    // //
    // Select scan angle from calibration table:
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "Patt";
    version = opsVersion;
    //
    // Selection depending on direction of scan:
    // 
    if(scanDirection == "scana") {
        patt = SpireProc_GetTableEntryDouble(tabName,selCol,selValN,tarCol,version,debug);
    }
    if(scanDirection == "scanb") {
        patt = SpireProc_GetTableEntryDouble(tabName,selCol,selValO,tarCol,version,debug);
    }
    if(scanDirection == "scanab") {
        patt = SpireProc_GetTableEntryDouble(tabName,selCol,selValN,tarCol,version,debug);
    }
    // //
    // //
    // Select number of map repetitions (nMaps) from calibration table:
    // (incl. calculation of pof10Obs parameters)
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "NMaps";
    version = opsVersion;
    //
    // Selection depending on direction of scan:
    //  
    {double,double,int,int,int,int} pof10Obs = {0.0,0.0,0,0,0,0};
    if(scanDirection == "scana") {
        nMaps = SpireProc_GetTableEntryInt(tabName,selCol,selValN,tarCol,version,debug);
        pof10Obs = SpirePOF5Observing(obsModeN,nRepetitions * nMaps,mapSize1,mapSize2,opsVersion,spireVersion,debug);
    }
    if(scanDirection == "scanb") {
        nMaps = SpireProc_GetTableEntryInt(tabName,selCol,selValO,tarCol,version,debug);
        pof10Obs = SpirePOF5Observing(obsModeO,nRepetitions * nMaps,mapSize1,mapSize2,opsVersion,spireVersion,debug);
    }
    if(scanDirection == "scanab") {
        if(debug) {
            debug_print("nMaps/scanab path:");
            debug_print("tabName: " + tabName);
            debug_print("selCols: " + selCol);
            debug_print("selValN: " + selValN);
            debug_print("selValN: " + selValN);
            debug_print("tarCol: " + tarCol);
            debug_print("version: " + version);
        }
        nMaps = SpireProc_GetTableEntryInt(tabName,selCol,selValN,tarCol,version,debug);
        pof10Obs = SpirePOF5Observing(obsModeN,nMaps,mapSize1,mapSize2,opsVersion,spireVersion,debug);
    }
    double mapOsit = pof10Obs{0};
    double d1 = pof10Obs{1};
    int nRepeats = pof10Obs{2};
    //
    // //
    // //
    // Calculate further pointing mode input parameters:
    //
    {int,int,int,int,int,double,double} pof10Point = {0,0,0,0,0,0.0,0.0};
    if(scanDirection == "scanb") {
        pof10Point = SpirePOF5Pointing(obsModeO,nRepeats,nLines,nCal,nFlash,isBright,bsmModel,bsmVersion,spireVersion,flashVersion,photVersion,comVersion,opsVersion,debug);
    } else {
        pof10Point = SpirePOF5Pointing(obsModeN,nRepeats,nLines,nCal,nFlash,isBright,bsmModel,bsmVersion,spireVersion,flashVersion,photVersion,comVersion,opsVersion,debug);
    }
    tSlewMin = pof10Point{0};
    tInitHold = pof10Point{1};
    tFinalHold = pof10Point{2};
    tHold = pof10Point{3};
    nHold = pof10Point{4};
    double d2 = pof10Point{5};
    double rate = pof10Point{6};
    // //
    // //
    // Calculate further cross scan parameters:
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "NMaps";
    version = opsVersion;
    //
    if(scanDirection == "scanab") {
        if(debug) {
            debug_print("x calculation");
        }
        nMaps = SpireProc_GetTableEntryInt(tabName,selCol,selValO,tarCol,version,debug);
        double mapOsitx = 0.0;
        // observing mode parameters
        {double,double,int,int,int,int} pof10Obsx = {0.0,0.0,0,0,0,0};
        pof10Obsx = SpirePOF5Observing(obsModeO,nMaps,mapSize2,mapSize1,opsVersion,spireVersion,debug);
        mapOsitx = pof10Obsx{0};
        double d1x = pof10Obsx{1};
        int nRepeatsx = pof10Obsx{2};
        //
        // pointing mode input parameters:
        {int,int,int,int,int,double,double} pof10Pointx = {0,0,0,0,0,0.0,0.0};
        pof10Pointx = SpirePOF5Pointing(obsModeO,nRepeatsx,nLinesx,nCalx,nFlashx,isBright,bsmModel,bsmVersion,spireVersion,flashVersion,photVersion,comVersion,opsVersion,debug);
        int nHoldx = pof10Pointx{4};
        double d2x = pof10Pointx{5};
        //
        // Lookup direction of cross scan:
        //
        tabName = tabName05;
        selCol = "mode";
        selValN = obsModeN;
        selValO = obsModeO;
        tarCol = "Patt";
        version = opsVersion;
        double pattx = SpireProc_GetTableEntryDouble(tabName,selCol,selValO,tarCol,version,debug);
    }
    // //
    // //
    // Calculate further pointing mode pointing parameters:
    //
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "Boresight";
    version = opsVersion;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selValN,tarCol,version,debug);
    //
    // Lookup offset to pixel centre from boresight in Y direction (arcsecs):
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "DeltaY";
    version = opsVersion;
    double deltaY = SpireProc_GetTableEntryDouble(tabName,selCol,selValN,tarCol,version,debug);
    //
    // Lookup offset to pixel centre from boresight in Z direction (arcsecs)
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "DeltaZ";
    version = opsVersion;
    double deltaZ = SpireProc_GetTableEntryDouble(tabName,selCol,selValN,tarCol,version,debug);
    //
    // Lookup pattern angle definition:
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "Fixed";
    version = opsVersion;
    bool fixed = SpireProc_GetTableEntryBool(tabName,selCol,selValN,tarCol,version,debug);
    // //
    // //
    // Calculate further offsets:
    //
    // offset to observation position from target in Y direction (arcsecs):
    //
    double yOffset = mapOffsetY * 60.0 + deltaY;
    //
    // offset to observation position from target in Z direction (arcsecs):
    //
    double zOffset = mapOffsetZ * 60.0 + deltaZ;
    //
    // fetch timing information
    //
    if(debug) {
        debug_print("fetch timing information");
    }
    bool initFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsModeN,"InitFlash",spireVersion,debug);
    // initial flash flag
    bool endFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsModeN,"EndFlash",spireVersion,debug);
    // final flash flag
    int tFlash = duration(SpireBbPcalFlash("PFlash",flashVersion,0,debug));
    // time for a PCAL flash
    if(debug) {
        debug_print("Calculate tSerendipity");
    }
    int tSerendipity = duration(SpireBbPhotSerendipity(obsModeN,0));
    // minimum time for a serendipity observation
    //
    //
    // ****** execute telescope pointing mode ******
    //
    int[] ts = [];
    if(scanDirection == "scanab") {
        ts = cross_scan_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,fixed,patt,yOffset,zOffset,nLines,d1,d2,rate,tHold,nHold,nRepetitions,nMaps,pattx,nLinesx,d1x,d2x,nHoldx);
    } else {
        ts = line_scan_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,fixed,patt,yOffset,zOffset,nLines,d1,d2,rate,tHold,nHold,nRepeats);
    }
    //
}{
    // *****************************************
    //   Display input parameters
    // *****************************************
    SpireMsg(3,"     POF10 Input values:");
    SpireMsg(3,"     ..RA: " + ra);
    SpireMsg(3,"     ..Dec: " + dec);
    SpireMsg(3,"     ..NAIF ID: " + naifid);
    SpireMsg(3,"     ..Y Offset: " + yOffset);
    SpireMsg(3,"     ..Z Offset: " + zOffset);
    SpireMsg(3,"     ..No of Map Repeats: " + nRepeats);
    SpireMsg(3,"     ..No of Lines: " + nLines);
    // SpireMsg(3,"     ..No of lines between Gyro Calibrations: " + nCal);
    SpireMsg(3,"     ..No of lines between Flashes: " + nFlash);
    SpireMsg(3,"     ..No of Map Repeats: " + nRepeats);
    SpireMsg(3,"     ..No of Lines in cross-scan map: " + nLines);
    // SpireMsg(3,"     ..No of lines between Gyro Calibrations in cross-scan map: " + nCal);
    SpireMsg(3,"     ..No of lines between Flashes in cross-scan map: " + nFlash);
    SpireMsg(3,"     POF10 Fixed values:");
    SpireMsg(3,"     ..ib: " + ib);
    SpireMsg(3,"     ..patt: " + patt);
    SpireMsg(3,"     ..d2: " + d2);
    SpireMsg(3,"     ..rate: " + rate);
    SpireMsg(3,"     ..initFlash: " + initFlash);
    SpireMsg(3,"     ..endFlash: " + endFlash);
    if(scanDirection == "scanab") {
        SpireMsg(3,"     Cross Scan Pointing Mode Input values:");
        SpireMsg(3,"     ..tSlewMin: " + tSlewMin);
        SpireMsg(3,"     ..tInitHold: " + tInitHold);
        SpireMsg(3,"     ..tFInalHold: " + tFinalHold);
        SpireMsg(3,"     ..nLines: " + nLines);
        SpireMsg(3,"     ..d1: " + d1);
        SpireMsg(3,"     ..tHold: " + tHold);
        SpireMsg(3,"     ..nHold: " + nHold);
        SpireMsg(3,"     ..nLinesx: " + nLinesx);
        SpireMsg(3,"     ..d1x: " + d1x);
        SpireMsg(3,"     ..nHoldx: " + nHoldx);
        SpireMsg(3,"     Cross Scan Pointing Mode Output values:");
        SpireMsg(3,"     ..tobs: " + ts[0]);
        SpireMsg(3,"     ..tslew: " + ts[1]);
        SpireMsg(3,"     ..tacc: " + ts[2]);
        SpireMsg(3,"     ..tdec: " + ts[3]);
        SpireMsg(3,"     ..tl: " + ts[4]);
        SpireMsg(3,"     ..tll: " + ts[5]);
        SpireMsg(3,"     ..trep: " + ts[6]);
        SpireMsg(3,"     ..tlx: " + ts[7]);
        SpireMsg(3,"     ..tllx: " + ts[8]);
        SpireMsg(3,"     ..tcross: " + ts[9]);
        SpireMsg(3,"     ..trev: " + ts[10]);
        SpireMsg(3,"     ..tend: " + ts[11]);
    } else {
        SpireMsg(3,"     Line Scan with Hold Pointing Mode Input values:");
        SpireMsg(3,"     ..tSlewMin: " + tSlewMin);
        SpireMsg(3,"     ..tInitHold: " + tInitHold);
        SpireMsg(3,"     ..tFInalHold: " + tFinalHold);
        SpireMsg(3,"     ..nLines: " + nLines);
        SpireMsg(3,"     ..d1: " + d1);
        SpireMsg(3,"     ..tHold: " + tHold);
        SpireMsg(3,"     ..nHold: " + nHold);
        SpireMsg(3,"     Line Scan Pointing Mode Output values:");
        SpireMsg(3,"     ..tobs: " + ts[0]);
        SpireMsg(3,"     ..tslew: " + ts[1]);
        SpireMsg(3,"     ..tacc: " + ts[2]);
        SpireMsg(3,"     ..tdec: " + ts[3]);
        SpireMsg(3,"     ..tl: " + ts[4]);
        SpireMsg(3,"     ..tll: " + ts[5]);
        SpireMsg(3,"     ..trep: " + ts[6]);
        SpireMsg(3,"     ..tend: " + ts[7]);
    }
    // *****************************************
    //   execute observation
    // *****************************************
    SpireMsg(0,"Observation Start");
    SpireMsg(0,"  Uses observing mode POF10 (Scan Map)");
    SpireMsg(3,"       $Id: $");
    data_rate(0.0);
    double chkrate = SpireProc_GetTableEntryDouble("SpireTable_Datarates.txt","mode",obsModeN,"CHK","v00",debug);
    ess_hk_data_rate(chkrate);
    double nhkrate = SpireProc_GetTableEntryDouble("SpireTable_Datarates.txt","mode",obsModeN,"NHK","v00",debug);
    non_ess_hk_data_rate(nhkrate);
    //
    //??p pointing file generation ------------------------------
    //??double pos = 90.0;
    //??double[] rdp0 = PtOffset([ra,dec,pos],zOffset,yOffset,0.0,false);
    //??p pointing file generation ------------------------------
    //
    bool relative = true;
    int tslew = ts[1];
    // slew time
    int tl = ts[4];
    // time for line scan
    int tlx = ts[7];
    // time for cross-scan line scan
    string tstr = "";
    // time string
    int otf = 0x8000;
    // On Target Flag
    double srcTime = 0.0;
    //  total on source integration time
    int nl = 0;
    // line counter
    double s = 0.0;
    int x = 0;
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // ***********************  SLEWING
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Slewing to start position");
            // set up observation parameters
            SpireBb_StartObsAll("POF10");
            // perform serendipity operation if possible
            if(tslew > tSerendipity + tSlewMin) {
                SpireBbPhotSerendipity(obsModeN,tslew - tSlewMin - 2);
            }
            // configure instrument for operations
            SpireBbPOF5Config(obsModeN,isBright,bsmModel,bsmVersion,photVersion,comVersion,debug);
        }
        if(state[0] == 2) {
            // ***********************  INITIAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Initialising Instrument");
            // initialise instrument
            SpireBbPOF5Init(obsModeN);
            // calibrate if necessary
            if(initFlash || nFlash < nLines) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireBbPcalFlash("PFlash",flashVersion,otf,debug);
            }
            SpireBbStartDcuData(obsModeN);
        }
        if(state[0] == 5) {
            // ***********************  FINAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Reconfiguring Instrument");
            SpireBbStopDcuData();
            // calibrate if necessary
            if(endFlash && nHold != nLines) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireBbPcalFlash("PFlash",flashVersion,otf | nl,debug);
            }
            // reconfigure back to PHOT_STBY configuration
            SpireBbPOF5End("PHTSTBY",isBright,bsmModel,bsmVersion,photVersion,comVersion,debug);
        }
        if(state[0] == 6) {
            // ***********************  HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
            SpireBbStopDcuData();
            SpireBbPcalFlash("PFlash",flashVersion,otf | nl,debug);
            SpireBbStartDcuData(obsModeN);
        }
        if(state[0] == 8) {
            // ***********************  SCAN
            //??p pointing file generation ------------------------------
            int line = state[2];
            int r = state[3];
            if(scanDirection == "scanab") {
                x = state[4];
            } else {
                x = 0;
            }
            int t = time();
            //??p pointing file generation ------------------------------
            //??p PtScanStart(rdp0,line,nCycles,d1,d2,patt,relative);
            tstr = SpireTimeStr(time());
            if(x == 0) {
                SpireMsg(2,"    " + tstr + " Instrument scanning");
                SpireMsg(2,"    " + tstr + " Map " + r + ", Line " + line);
                s = SpireBbScanLine(tl,otf | nl);
                wait_until(t + tl);
            } else {
                SpireMsg(2,"    " + tstr + " Instrument cross-scanning");
                SpireMsg(2,"    " + tstr + " Map " + r + ", xLine " + line + ", xRepeat " + x);
                s = SpireBbScanLine(tlx,otf | nl);
                wait_until(t + tlx);
            }
            //??p pointing file generation ------------------------------
            //??p PtScanStop(rdp0,line,nCycles,d1,d2,patt,relative);
            srcTime = srcTime + s;
            nl = nl + 1;
            SpireBbMove(0);
        }
    }
    assert (time() == ts[0] + ts[1]);
    //
    // finish observation
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + " Instrument Reconfigured");
    //
    //
    SpireMsg(0,"Observation Completed  (" + time() + " seconds)");
    SpireMsg(0,"Note: Total time (s) = Observation Completed time - slew time + Observatory Overheads");
    if(scanDirection == "scanab") {
        mapOsit = mapOsit + mapOsitx;
    }
    int mOsit = iround(mapOsit);

    return {nRepetitions,mOsit,mOsit * nRepetitions,time() - mOsit * nRepetitions - tslew};
}

// SpireREDYtoSPEC_STBY
//
// $id$
//
// This procedure configures the instrument into the SPEC_STBY mode
// 
// The instrument should be in  the REDY mode before execution of this observation
//
// 28/04/2009 KJK:  first version
// 08/06/2009 KJK: added commands for starting/stopping the SCAL Command List
// 02/07/2009 MP: Added report of tables and memory checksums (SPIRE-SCR-1527)  
// 12/07/2009 MP: Changed default stabilisationTime (SCR-SPIRE-1632)
// 13/07/2009 MP: Introduce wait time after SMEC on as input (SCR-SPIRE-1638)
// 21/08/2009 TWG: Moved SetBSMSampling to after SMEC Init
// 06/09/2009 KJK: Changed scalTemp to accept values in Kelvin (SCR SPire-1870)
// 20/10/2009 KJK: Removed call to SpireBbSmecInit (SPR Spire-2062)
//                            Moved set BSM and SMEC sampling to after the detectors are switched on so that some SMEC engineering data is taken
//                            Set default SMECwait to 0
// 17/02/1020 KJK: Spire-2391:
//                            Updated to initialise the SMEC, perform a PCAL flash and open the SMEC control loop at the end of the script
// 02/03/2010 SDS: Corrections for SPIRE-SCR-2391: replaced call to SpireBbPcalFlash with SpireProc_SFlash
//
procedure SpireREDYtoSPEC_STBY {
    int jfet_heater_V = 0; // Default jfet heater voltage at switch on
    string scal = "Default" in ["Default","SCAL2","SCAL4","None"]; // SCAL status
    double scalTemp = 5.0 in [5.0,80.0]; // SCAL temperature, if SCAL2 or SCAL4 selected (Kelvin)
    int stabilisationTime = 120; // time (secs) to allow SCAL/Detectors to stabilise before starting observations
    int smecWait = 0; // Wait time after switch-on of SMEC [s]
    bool sampleDetectors = false; // sample detectors during the stabilisation period
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string smecVersion = "v00";
    string detVersion = "v00";
    string vssVersion = "v00";
    string scalVersion = "v00";
    bool debug = false;
}{
    // set nominal housekeeping rate
    SpireBbSetNhkSampling("SPECSTBY","v00",debug);
    // // 
    // //
    // Report tables and do memory checksums:
    //
    SpireBb_RepTabAndMemChecksum();
    //
    //
    // -----------
    // configure BSM
    // -----------
    //
    // switch on BSM
    mois_comment("Procedure SPIRE_BSM_ON: to switch on the SPIRE BSM");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    mois_tmcheck("Check that parameter CHOPSENSPWR is set to 0");
    mois_tmcheck("Check that parameter JIGGSENSPWR is set to 0");
    SpireBbBsmOn("SPECSTBY",bsmModel,bsmVersion,debug);
    mois_comment("SPIRE SPIRE_BSM_ON Procedure Completed");
    mois_tmcheck("Check that parameter CHOPSENSPWR is set to 1");
    mois_tmcheck("Check that parameter JIGGSENSPWR is set to 1");
    mois_tmcheck("Check that parameter MODE is set to BSM_ON");
    //
    // initialise BSM
    mois_comment("Procedure SPIRE_BSM_INIT: to initialise the SPIRE BSM");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    mois_spacon("Ensure that SPIRE_BSM_ON procedure has been run before continuing");
    mois_tmcheck("Ensure that parameter MODE is set to BSM_ON");
    SpireBbBsmChopInit("SPECSTBY",bsmModel,bsmVersion,debug);
    SpireBbBsmJiggInit("SPECSTBY",bsmModel,bsmVersion,debug);
    //
    // Setup  BSM sampling - now done after SMEC Initialisation (TWG, 21-Aug-09)
    //
    mois_comment("SPIRE SPIRE_BSM_INIT Procedure Completed");
    mois_tmcheck("Check that parameter MODE is set to BSM_INIT");
    //
    // -------------
    // configure SMEC
    // -------------
    //
    // switch on SMEC
    mois_comment("Procedure SPIRE_SMEC_ON: to switch on the SPIRE SMEC");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    mois_tmcheck("Check that parameter SMECENCPWR is set to 0");
    mois_tmcheck("Check that parameter SMECLVDTPWR is set to 0");
    SpireBbSmecOn(smecVersion,debug);
    mois_tmcheck("Check that parameter SMECENCPWR is set to 1");
    mois_tmcheck("Check that parameter SMECLVDTPWR is set to 1");
    mois_tmcheck("Check that parameter MODE is set to SMEC_ON");
    // //
    // //
    // Wait time after SMEC on before SMEC initialisation:
    //
    delay(smecWait);
    //
    // ----------------
    // configure Detectors
    // ----------------
    //
    mois_comment("Procedure SPIRE_SDET_ON: to switch on the SPIRE Spectrometer");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    mois_tmcheck("Ensure that parameter MODE is set to SMEC_INIT");
    mois_tmcheck("Ensure SLIABITSTAT is set to 0");
    mois_tmcheck("Ensure SPECJFETSTAT is set to 0");
    mois_tmcheck("Ensure parameters SSWJFET1V to SSWJFET2V are all set to 0");
    mois_tmcheck("Ensure parameter SLWJFET1V is set to 0");
    mois_spacon("Select the TM Display for SFT PARAMETERS");
    mois_tmcheck("SLIAP5V, SLIAP9V and SLIAM9V should all be set to 0");
    SpireBbSdetOn(jfet_heater_V,detVersion,vssVersion,debug);
    mois_tmcheck("Ensure SLIABITSTAT is set to 1");
    mois_tmcheck("SLIAP5V should be ~5V");
    mois_tmcheck("SLIAP9V should be ~11.5V");
    mois_tmcheck("SLIAM9V should be ~-11.5V");
    mois_spacon("Select the TM Display for FUNCTIONAL TEST PARAMETERS");
    mois_tmcheck("Ensure SPECJFETSTAT is set to 7");
    mois_tmcheck("Ensure parameters SSWJFET1V & SSWJFET2V are all < 0 - nominally within ~ -1V and -3V");
    mois_tmcheck("Ensure parameter SLWJFET1V is < 0 - nominally within ~ -1V and -3V");
    mois_tmcheck("Ensure that parameter MODE is set to SPECSTBY");
    //
    // Stop MCU Eng Data
    SpireBb_StopMcuEngData();
    //
    // Setup BSM Sampling
    SpireBbSetBsmSampling("SPECSTBY",bsmVersion,debug);
    //
    // Setup SMEC sampling
    SpireBbSetSmecSampling("SPECSTBY",smecVersion,debug);
    //
    // ----------------
    // configure SCU
    // ----------------
    //
    SpireBbSetScuSampling("SPECSTBY","v00",debug);
    //
    // ----------------
    // Configure SCAL
    // ----------------
    //
    int scalTempRaw = -1;
    if(scal == "Default") {
        // read default status
        scal = SpireProc_GetTableEntryString("SpireTable_DefaultParams.txt","mode","SPECSTBY","scalVm",scalVersion,debug);
    } else {
        if(scal != "None") {
            scalTempRaw = iround(interpolate("SpireTable_SCALTemp.txt",scal,scalTemp));
        }
    }
    SpireBbSetScal(scal,scalTempRaw,scalVersion,debug);
    // 
    // ----------------
    // Stabilisation
    // ----------------
    if(sampleDetectors) {
        SpireBbSetDetSampling("SPECSTBY",false,detVersion,sampleDetectors,debug);
    }
    delay(stabilisationTime);
    //
    // -----------------------
    // Setup final detector sampling
    // -----------------------
    SpireBbSetDetSampling("SPECSTBY",false,detVersion,false,debug);
    //
    // ----------------
    // start of OD PCAL Flash
    // ---------------- 
    SpireBbSmecInit("H",bsmVersion,smecVersion,"v00",debug);
    SpireBb_SpecSetMode("SFlash",false,"v00","v00",debug);
    // Perform PCAL flash after moving SMEC to HOME
    // Assumes SMEC is currently at 0.1mm 
    // Assumes HOME is at 3.5mm
    // PCAL Flash table flashVersion hardcoded to "v00"
    SpireProc_SFlash("SFlash",100,3500,0,bsmVersion,smecVersion,"v00",debug);
    SpireBb_SpecSetMode("SPECSTBY",false,"v00","v00",debug);
    SpireBbSmecRedy();
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBbSetScuSampling.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// The Building Block sets the SCU sampling  
//
//
///////////////////////////////////////////////////////////////////////////
//
// 28/04/2009  KJK: First Version
// 07/05/2009 KJK:
//      Now only set sampling parameters if the data is to be generated (these values are not available for REDY mode)
//
///////////////////////////////////////////////////////////////////////////
//
double block SpireBbSetScuSampling SPIRE 1604 {
    string opsMode = "PHTSTBY";
    string version = "v00";
    bool debug = false; // Allow debug_print statements 
}{
    // 
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    //
    // Start BB:
    //
    message("4    " + time() + ": SpireBbSetScuSampling started");
    message("4          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    delay(1);
    //
    // set default datarate
    double scuDataRate = 0.0;
    // set default TM Packet 12 sampling rate
    int scuDataModeRate = 0;
    //
    //
    //  if generating data, setup sampling first
    int scuDataGen = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",opsMode,"scuDataGen","v00",debug);
    if(scuDataGen == 1) {
        // if starting data generation
        // Set number of samples
        int scuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",opsMode,"scuFrameNumber","v00",debug);
        SpireSendDrcuCmd(0xa0840000 + scuFrameNumber,0);
        // read datarate
        scuDataRate = SpireProc_GetTableEntryDouble("SpireTable_CommonModeParams.txt","mode",opsMode,"bsmDataRate",version,debug);
        // read sampling type rate
        scuDataModeRate = SpireProc_GetTableEntryInt("SpireTable_CommonModeParams.txt","mode",opsMode,"scuFrameRate",version,debug);
    }
    // Start/Stop Data Generation
    SpireSendDrcuCmd(0xa0830000 + scuDataModeRate,0);
    SpireSendDrcuCmd(0xa0820000 + scuDataGen,0);
    //
    // End BB:
    //
    sync();
    SpireMsg(4,"    " + time() + ": BB SpireBbSetScuSampling ended");

    return scuDataRate;
}

// SpireBb_SetSpecDetOffsets
//
// $Id:$
//
// Building Block to  to set the spectrometer detector offsets 
//
// K.King:  
// 2010/03/31 V1.0: Initial version created for SCR Spire-2459
//
// 
/////////////////////////////////////////////////////////////////////////////
block SpireBb_SetSpecDetOffsets SPIRE 3421 {
    bool debug = false;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SetSpecDetOffsets started");
    SpireMsg(2,"          $Id:$");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set Offsets
    //
    SpireProc_Set_SpecDetOffsets(debug);
    sync();
    //
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SetSpecDetOffsets ended");
    SpireMsg(1,"  ..SetSpecOffsets (" + (time() - t) + " seconds)");
}

// SpireBb_SmecLedLvdt
//
// $id$
//
// This building block switches on the SMEC LED and LVDT
// 
// The instrument should be in REDY mode before execution of this building block
//
// 05-Jul-2010 SDS: First Version
//
// 06-Jul-2010 SDS: 1.1
//                             Added MOIS statements
block SpireBb_SmecLedLvdt SPIRE 3425 {
    string version = "v00";
    bool debug = false;
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SmecLedLvdt started");
    SpireMsg(2,"          $Id: $");
    //
    // Read the LED level from calibration table
    int encPwr = ilookup("SpireTable_SmecNominalSettings.txt",version,"encPwr");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    //
    // Switch on the SMEC LED
    mois_comment("Switch on the SMEC LED");
    SpireSendDrcuCmd(0x90400000 + encPwr,0);
    delay(4);
    //
    // Switch on LVDT	
    mois_comment("Switch on the SMEC LVDT sensor");	
    SpireSendDrcuCmd(0x90410001,0);
    delay(4);
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SmecLedLvdt ended");
    SpireMsg(1,"  ..SmecLedLvdt (" + (time() - t) + " seconds)");
    //
}

// SpireBbPOF3Config
//
// $Id:$
//
// Building Block to configure the instrument for POF3 ( jiggle map) operation
//
// The complete instrument setup operation is divided into two parts:
//   Configuration: actions that can be executed during the slew to the start
//          position of the S/C pointing mode.
//   Initialisation: actions that must be carried out at the S/C intial pointing
//          position before any observational operations are executed.   
//
// This building Block implements the first part of the setup 
//
//  11/02/09: KJK
//      -  Removed setting of Mode and resetting DRCU counters -
//          These are now implemented in SpireBb_StartObsAll
//      - Add possible bright-source setting  
//  14/02/09: MP
//      -  Replace calls to SpireProc_Set_PhotPhase/Bias with 
//          call to SpireProc_Set_PhotBright
//  04/03/09: MP
//      - Fixed bug in call to SpireProc_Set_PhotBright
//  22/07/2009 SDS:
//         SCR-1670 - Added option to load new JM64 table which has +/- 126 arcseconds chop throw
//  28/07/2009 SDS:
//         SCR-1728 - Reads and sets the Chop PID parameters from model jm64 in the SpireTable_BsmNominalSettings.txt table  
//  10/08/2009 KJK:
//         SPR-1709:  Added new input parameter, comVersion
//                           updated to execute SpireProc_Set_PhotMode if photversion is not "V00"
//  12/08/2009 KJK:
//         Changed chopVersion to bsmVersion - in line with other scripts
//  14/08/2009 KJK:
//         Spire_1759: Removed loading of new jiggle table as it is now loaded in a new BB
//
block SpireBbPOF3Config SPIRE 8240 {
    string obsMode = "POF3";
    bool isBright = false in [true,false];
    string bsmVersion = "v00"; //Version of the SpireTable_BsmNominalSettings.txt table
    string photVersion = "v00";
    string comVersion = "v00";
    bool debug = false in [true,false];
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF3 Configuration started");
    SpireMsg(2,"          $Id: $");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    //
    // set biases and phases - if needed
    //
    if(isBright) {
        SpireProc_Set_PhotBright(obsMode,photVersion,debug);
    } else {
        if(photVersion != "v00") {
            SpireProc_Set_PhotMode(obsMode,isBright,photVersion,comVersion,debug);
        }
    }
    //
    // ..... completion .....
    //
    delay(2);
    //
    // Read the Chop PID parameters 
    int chopkp = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model","jm64","chop_kp",bsmVersion,debug);
    int chopki = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model","jm64","chop_ki",bsmVersion,debug);
    int chopkd = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model","jm64","chop_kd",bsmVersion,debug);
    //
    // //
    // Set PID parameters to nominal JM64 values:
    //
    SpireProc_Set_BsmChopPid(chopkp,chopki,chopkd,debug);
    // //
    //
    // to allow hsk to stabilise
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF3 Configuration ended");
    SpireMsg(1,"  ..POF3 Configuration (" + (time() - t) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBbSetNhkSampling.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// The Building Block sets the NHK sampling  
//
//
///////////////////////////////////////////////////////////////////////////
//
// 28/04/2009  KJK: First Version
//
///////////////////////////////////////////////////////////////////////////
//
double block SpireBbSetNhkSampling SPIRE 1600 {
    string opsMode = "PHTSTBY";
    string version = "v00";
    bool debug = false; // Allow debug_print statements 
}{
    // 
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    //
    // Start BB:
    //
    message("4    " + time() + ": SpireBbSetNhkSampling started");
    message("4          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    delay(1);
    //
    // Set sampling
    //
    int nhkSampling = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",opsMode,"nhkSampling",version,debug);
    SpireNhkSampling(nhkSampling);
    //
    // End BB:
    //
    sync();
    SpireMsg(4,"    " + time() + ": BB SpireBbSetNhkSampling ended");
    double nhkDataRate = SpireProc_GetTableEntryDouble("SpireTable_DefaultParams.txt","mode",opsMode,"nhkDataRate",version,debug);

    return nhkDataRate;
}

// SpireBbStartObs
//
// $Id: SpireBbStartObs.txt,v 1.2 2007/10/26 10:19:51 kking Exp $
//
// Building Block to configure an engineering observation
//
// 22 Oct 2007: 
//      Correct parameter used for setting of STEP to 1
//      Add delay of 1 sec before setting OBSID to allow time for busconfig to be performed
//
//  17/11/2008 KJK: added sync() statement to round up total duration
//
block SpireBbStartObs SPIRE 2 {
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Start Obs started");
    SpireMsg(2,"          $Id: SpireBbStartObs.txt,v 1.2 2007/10/26 10:19:51 kking Exp $");
    hstr = SpireHexStr($BBID,8);
    SpireMsg(3,"          BBID = " + hstr);
    //
    // Wait for busconfig to be performed
    delay(1);
    //
    // set OBSID
    hstr = SpireHexStr($OBSID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + " Cmd: Spire_SET_OBSID_RAW(" + hstr + ")");
    Spire_SET_OBSID_RAW($OBSID);
    // 
    // set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    delay(1);
    //
    // set STEP to one
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x0001)");
    Spire_SET_OBS_STEP_RAW(0x1);
    delay(1);
    // 
    // reset DRCU counters
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RESET_DRCU_COUNTERS()");
    Spire_RESET_DRCU_COUNTERS();
    delay(1);
    // 
    // set STEP to zero
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x0000)");
    Spire_SET_OBS_STEP_RAW(0x0);
    //
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Start Obs ended");
    SpireMsg(1,"  ..Observation Configuration (" + (time() - t) + " secs)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_BsmChopPid.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to set BSM PID parameters
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/06/05 V1.0: First version re-configured from 
//                  SpireBb_SetBsmChopPid (2009/03/30 V0.1) which was
//                  originally adapted from 
//                  Proc_SetChopPID.txt (SDS, email 30.03.2009)
// 
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_BsmChopPid {
    int kp = 1000; // Chop Kp
    int ki = 536; // Chop Ki
    int kd = 3504; // Chop Kd
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string hstr = "";
    // a hex string
    string tstr = "";
    // a time string
    // //
    // //
    // Start procedure:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(3,"    " + tstr + ": SpireProc_Set_BsmChopPid started");
    SpireMsg(3,"          $Id: $");
    // //
    // //
    // Set PID parameters:
    //
    // Set Chop Kp parameter:
    SpireSendDrcuCmd(0x90c80000 + kp,0);
    //
    // Set Chop Ki parameter:
    SpireSendDrcuCmd(0x90ca0000 + ki,0);
    delay(1);
    //
    // Set Chop Kd parameter:
    SpireSendDrcuCmd(0x90c90000 + kd,0);
    sync();
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(3,"    " + tstr + ": SpireProc_Set_BsmChopPid ended");
    //
}

//CLName: SpireBb_LoadTablePTC
//VMVersion: 2.8
//CLVersion: 2.2
//CLCVSId: $ID$
//TableId: 0x51
//TableLength: 0x1dd
//Date: 100106164808
// 23/07/2010: SDS
//                      Now reporting 41 words less than the length of table (static part of table) 
//                      See SPIRE-SCR-2761
block SpireBb_LoadTablePTC SPIRE 3339 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTablePTC started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0x51
    Spire_SET_TABLE(0x51,0x1dd);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x51,0x0,38,[{0x120000fd},{0x100},{0x20140000},{0x20150001},{0x14000001},{0xa8f00000},{0x32010010},{0x80007d0},{0x1000001},{0x12000000},{0xa8860000},{0x12000001},{0xbb8},{0x60640000},{0x18000001},{0xffff},{0x80007d0},{0x1000000},{0x32010004},{0x12000001},{0x5100},{0x30000171},{0x20000014},{0x20010015},{0x4b0101b9},{0x4b0201c6},{0x120000ff},{0xa},{0x120000fc},{0x1b9},{0x6107fc01},{0x120000ff},{0x1},{0x120000fc},{0x1b3},{0x12000014},{0x1},{0x4b1401b3}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x51,0x26,38,[{0x6107fc01},{0x4b0301c0},{0x4b0401c1},{0x4b0501c2},{0x4b0601c3},{0x19000006},{0x80000000},{0x4b0601c4},{0x4b0701c8},{0x4b0801c9},{0x4b0901ca},{0x4b0a01d8},{0x4b0b01d7},{0x4b0c01d9},{0x4b0d01da},{0x1000000e},{0x4b0f01db},{0x20140000},{0x490001b9},{0x12000001},{0xbb8},{0x13000001},{0x7d0},{0x13000001},{0x7d0},{0x490201b6},{0x22020201},{0x4000018b},{0x9000002},{0x2000000},{0x32000140},{0x22000114},{0x63fd001d},{0x4b0001b7},{0x490001c6},{0x63fd001d},{0x4b0001c6},{0x12000001}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x51,0x4c,38,[{0x40000000},{0x63fd0013},{0x4b0001c7},{0x12000000},{0x49742400},{0x490101c6},{0x63fd0013},{0x4b0001c5},{0x12000000},{0x0},{0x4b0001ba},{0x4b0001bb},{0x4b0001bc},{0x4b0001bd},{0x4b0001be},{0x4b0001bf},{0x120000ff},{0x1},{0x12000014},{0x2},{0x4b1401b3},{0x6107fc01},{0x490001bb},{0x4b0001bc},{0x490001ba},{0x4b0001bb},{0x490001b9},{0x12000001},{0xbb8},{0x13000001},{0x7d0},{0x13000001},{0x7d0},{0x490201b6},{0x22020201},{0x4000018b},{0x9000002},{0x2000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x51,0x72,38,[{0x3200fff4},{0x20000001},{0x63fd001d},{0x20140000},{0x490001cb},{0x490101cb},{0x63fd0012},{0x490101db},{0x63fd0012},{0x20010014},{0x63fd0010},{0x4b0001ba},{0x490001be},{0x4b0001bf},{0x490001bd},{0x4b0001be},{0x12000000},{0x40000000},{0x490101bb},{0x63fd0012},{0x490101ba},{0x63fd0010},{0x490101bc},{0x63fd0010},{0x4b0001bd},{0x490001be},{0x490101c9},{0x63fd0012},{0x490101bd},{0x63fd0010},{0x4b0001bd},{0x490001bf},{0x490101ca},{0x63fd0012},{0x490101bd},{0x63fd0010},{0x4b0001bd},{0x1100000e}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x51,0x98,38,[{0x320effca},{0x1200000e},{0x1},{0x120000ff},{0x1},{0x12000014},{0x3},{0x4b1401b3},{0x6107fc01},{0x490001d1},{0x12000001},{0xbf800000},{0x63fd0012},{0x4b0001d2},{0x490001bd},{0x490101c8},{0x63fd0013},{0x20010000},{0x490001b7},{0x63fd0011},{0x4b0001d1},{0x490101c0},{0x63fd0012},{0x4b0001d4},{0x490001d1},{0x490101c5},{0x63fd0013},{0x490101d3},{0x63fd0010},{0x4b0001d3},{0x490101c3},{0x63fd0011},{0x18000000},{0x80000000},{0x32000003},{0x490001c3},{0x4b0001d3},{0x490101d3}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x51,0xbe,38,[{0x490001c4},{0x63fd0011},{0x18000000},{0x80000000},{0x32000003},{0x490001c4},{0x4b0001d3},{0x490001d3},{0x490101c1},{0x63fd0012},{0x4b0001d5},{0x490001d1},{0x490101d2},{0x63fd0010},{0x490101c5},{0x63fd0012},{0x490101c2},{0x63fd0012},{0x4b0001d6},{0x490001d4},{0x490101d5},{0x63fd0010},{0x490101d6},{0x63fd0010},{0x490101d8},{0x63fd0010},{0x4b0001cb},{0x63fd001c},{0x4b0001ce},{0x63fd001d},{0x20010000},{0x490001cb},{0x63fd0011},{0x4b0001cc},{0x490001d9},{0x32000010},{0x490001cc},{0x12000001}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x51,0xe4,38,[{0x3f000000},{0x63fd0011},{0x18000000},{0x80000000},{0x490101ce},{0x32000002},{0x10000001},{0x4b0101ce},{0x4b0101cd},{0x490001c7},{0x4b0001d0},{0x4b0001cf},{0x3000003a},{0x490001cc},{0x12000001},{0x3e800000},{0x63fd0011},{0x18000000},{0x80000000},{0x32000014},{0x490101cc},{0x12000000},{0x3f400000},{0x63fd0011},{0x18000000},{0x80000000},{0x32000020},{0x490001ce},{0x10000000},{0x4b0001cd},{0x490001cc},{0x490101c6},{0x63fd0012},{0x4b0001cf},{0x20010000},{0x490001c6},{0x63fd0011},{0x4b0001d0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x51,0x10a,38,[{0x30000020},{0x490001ce},{0x10000000},{0x4b0001cd},{0x11000000},{0x11000000},{0x4b0001ce},{0x490001cc},{0x12000001},{0x3f800000},{0x63fd0010},{0x4b0001cc},{0x490101c7},{0x63fd0012},{0x4b0001cf},{0x20010000},{0x490001c6},{0x63fd0011},{0x4b0001d0},{0x3000000d},{0x490001ce},{0x10000000},{0x10000000},{0x4b0001cd},{0x490001cc},{0x490101c7},{0x63fd0012},{0x4b0001cf},{0x20010000},{0x490001c6},{0x63fd0011},{0x4b0001d0},{0x490001ce},{0x12000001},{0x0},{0x35000001},{0x30000008},{0x4b0101ce}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x51,0x130,38,[{0x4b0101cd},{0x490101c7},{0x4b0101d0},{0x4b0101cf},{0x4b0101cb},{0x3000000d},{0x490001cd},{0x490101d7},{0x34000001},{0x30000009},{0x4b0101ce},{0x4b0101cd},{0x490101c7},{0x4b0101d0},{0x4b0101cf},{0x490001d7},{0x63fd001d},{0x4b0001cb},{0x80007d0},{0x1000001},{0x12000000},{0x2},{0x12000001},{0xc6},{0x490201ce},{0x12000003},{0xbb8},{0x60640001},{0x490001d0},{0x63fd001c},{0x12000002},{0x7d0},{0x22000002},{0x12000002},{0x7d0},{0x22000002},{0x9000000},{0x1000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x51,0x156,38,[{0x80007d0},{0x1000001},{0x12000000},{0x2},{0x12000001},{0xc6},{0x490201cd},{0x12000003},{0xbb8},{0x60640001},{0x490001cf},{0x63fd001c},{0x490101b6},{0x22000001},{0x12000001},{0x7d0},{0x22000001},{0x12000001},{0x7d0},{0x22000001},{0x9000000},{0x1000000},{0x490001da},{0x32000002},{0x30000015},{0x49ff01b4},{0x12000000},{0x1b4},{0x61520029},{0x490001b4},{0x13000000},{0x29},{0x4b0001b4},{0x1100000d},{0x320d000b},{0x120000ff},{0x0},{0x12000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x51,0x17c,38,[{0x1b4},{0x61520001},{0x54000052},{0x490d01da},{0x12000000},{0x0},{0x4b0001b4},{0x30fffedf},{0x12000001},{0x5101},{0x12000000},{0x5000},{0x53020000},{0x2000000},{0x7f000000},{0x1200005a},{0x7d0},{0x2201015a},{0x1200005a},{0x7d0},{0x2201015a},{0x80007d0},{0x1000001},{0x205a0000},{0x1800005a},{0x80000000},{0x325a0016},{0x120000ff},{0x20},{0x12000000},{0x1b9},{0x61060001},{0x9000001},{0x2000000},{0x12000000},{0x1b8},{0x62060001},{0x490101b8}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x51,0x1a2,38,[{0x20000001},{0x18000000},{0x80000000},{0x32000004},{0x12000000},{0xffff},{0x30000005},{0x12000000},{0x0},{0x30000002},{0x60640000},{0x18000001},{0xffff},{0x80007d0},{0x1000000},{0x41000000},{0x7f000000},{0x0},{0x0},{0xface},{0x3a98},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x51,0x1c8,21,[{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x7fff},{0x0},{0x0},{0x0},{0x0},{0xcafe}]);
    delay(t_min);
    //
    //  Dump table contents - report 41 words less than the length of table. 
    //  These 41 words in table are dynamic (used for calculations) 
    //
    Spire_REPORT_TABLE(0x51,0x0,0x1b3);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTablePTC ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

command PacsCcuMonitorPeriodDefault HFKACQP1 {
} {
    bus_schedule(SC, 6);
}

// SpireEngBsmTuner
//
// $id$
//
// This observation allows tuning of the BSM CHOPFFGAIN, CHOPKD, JIGFFGAIN, JIGGKP and CHOPJIGGCOUPLE for 7 and 64 ppint jiggle maps
// 
// The instrument should be in REDY mode before execution of this observation
// Final Configuration: Instrument is still in REDY mode after execution of this observation
//
//
// 03/11/2009 KJK: First Version 1.0 
//
// 12/11/2009 SDS: Added BBs to set NHK sampling to 1Hz at the start and 0.25Hz at the end 
//                            Added BB to set BSM sampling appropriate for REDY mode
// 13/11/2009 SDS: Added new BB SpireBb_TReset after each tuning block to prevent the DRCU counters from wrapping
//
// 15/11/2009 SDS: Added BB SpireBbSetDetSampling to set the detector settings for REDY mode (isPhot boolean is set to true)
//                             Also added new BB SpireBb_ResetBsm to set BSM frame parameters back to default values
//
// 04/03/2010 SDS: Inserted default CHOPINTLIMIT and CHOPINTREF values in calls to SpireBb_SetBsm
// 25/03/2010 SDS: Removed the setting of CHOPINTLIMIT and CHOPINTREF
//                            
//
obs SpireEngBsmTuner {
    bool tuneChop7 = true; // Tune CHOPFFGAIN and CHOPKD for 7 point jiggle Map
    bool tuneChop64 = true; // Tune CHOPFFGAIN and CHOPKD for 64 point jiggle Map   
    bool tuneCouple7 = true; // Tune CHOPJIGGCOUPLE for 7 point jiggle Map 
    bool tuneCouple64 = true; // Tune CHOPJIGGCOUPLE for 64 point jiggle Map
    bool tuneJigg = true; // Tune JIGGFFGAIN and JIGGKD
    int chopFfOffsetNom = 0x929f;
    int chopFfGainNom = 0xbeb; // nominal value of CHOPFFGAIN
    double chopFfGainLow = 0.6; // starting value of CHOPFFGAIN as a fraction of the nominal value
    double chopFfGainHigh = 1.4; // end value of CHOPFFGAIN as a fraction of the nominal value
    double chopFfGainStep = 0.05; // increment in value of CHOPFFGAIN as a fraction of the nominal value
    int chopKpNom = 1000;
    int chopKiNom = 620;
    int chopKdNom = 0xca8; // nominal value of CHOPKD
    double chopKdLow = 0.2; // starting value of CHOPKD as a fraction of the nominal value
    double chopKdHigh = 1.8; // end value of CHOPKD as a fraction of the nominal value
    double chopKdStep = 0.2; // increment in value of CHOPKD as a fraction of the nominal value
    int jiggFfOffsetNom = 0x9946;
    int jiggFfGainNom = 0x17d8; // nominal value of JIGGFFGAIN
    double jiggFfGainLow = 0.6; // starting value of JIGGFFGAIN as a fraction of the nominal value
    double jiggFfGainHigh = 1.4; // end value of JIGGFFGAIN as a fraction of the nominal value
    double jiggFfGainStep = 0.05; // increment in value of JIGGFFGAIN as a fraction of the nominal value
    int jiggKpNom = 1500;
    int jiggKiNom = 500;
    int jiggKdNom = 0x1b58; // nominal value of JIGGKD
    double jiggKdLow = 0.2; // starting value of JIGGKD as a fraction of the nominal value
    double jiggKdHigh = 1.8; // end value of JIGGKD as a fraction of the nominal value
    double jiggKdStep = 0.2; // increment in value of JIGGKD as a fraction of the nominal value
    int cjCoupleNom = 0x8161; // nominal value of CHOPJIGGCOUPLE
    double coupleLow = 0.989342109; // starting value of CHOPJIGGCOUPLE as a fraction of the nominal value
    double coupleHigh = 1.1010657891; // end value of CHOPJIGGCOUPLE as a fraction of the nominal value
    double coupleStep = 0.001776315; // increment in value of CHOPJIGGCOUPLE as a fraction of the nominal value
    int cjdCoupleNom = 0x8000;
    int jcCoupleNom = 0x8000;
    int chopOn7 = 0xb5ac;
    int chopOff7 = 0x6b90;
    int jigglePosn7 = 0x9a19;
    int chopOn64 = 0xcb31;
    int chopOff64 = 0x41db;
    int jigglePosn64 = 0x9a19;
    int jiggTop = 0xa1ca;
    int jiggBottom = 0x9267;
    int chopPosn = 0x909e;
    int nChopCycles = 20;
    int chopPeriod = 500000;
    int dcuMode = 0;
    int dcuSample = 1;
    int dcuDelay = 34959;
    int bsmSample = 0xffff;
    int sampFreq = 10;
    string bsmModel = "initial";
    string bsmVersion = "v00";
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // variables
    double g = 0.0;
    double d = 0.0;
    double c = 0.0;
    int s = 0;
    int chopFfGain = 0;
    int chopFfOffset = 0;
    int chopKp = 0x0;
    int chopKi = 0x0;
    int chopKd = 0;
    int couple = 0;
    int jiggFfGain = 0;
    int jiggFfOffset = 0;
    int jiggKp = 0x0;
    int jiggKi = 0x0;
    int jiggKd = 0;
    int t = duration(SpireBbStartObs()) + duration(SpireBbSetNhkSampling("PHTSTBY","v00",debug)) + duration(SpireBbBsmOn("PHTSTBY",bsmModel,bsmVersion,debug)) + duration(SpireBbBsmChopInit("PHTSTBY",bsmModel,bsmVersion,debug)) + duration(SpireBbBsmJiggInit("PHTSTBY",bsmModel,bsmVersion,debug)) + duration(SpireBbBsmOff()) + duration(SpireBbSetDetSampling("REDY",true,"v00",false,debug)) + duration(SpireBbSetBsmSampling("REDY","v00",debug)) + duration(SpireBb_ResetBsm(debug)) + duration(SpireBbSetNhkSampling("REDY","v00",debug)) + duration(SpireBbEndObs());
    if(tuneChop7) {
        g = chopFfGainLow;
        d = chopKdLow;
        while(g <= chopFfGainHigh) {
            d = chopKdLow;
            while(d <= chopKdHigh) {
                t = t + duration(SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKp,chopKi,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKp,jiggKi,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug));
                t = t + duration(SpireBb_Chop(71,0,10,chopOn7,jigglePosn7,chopOff7,jigglePosn7,nChopCycles,chopPeriod,dcuMode,dcuSample,dcuDelay,bsmSample,0,debug));
                t = t + duration(SpireBb_StopDcuMcuData());
                d = d + chopKdStep;
            }
            g = g + chopFfGainStep;
        }
        t = t + duration(SpireBb_TReset());
    }
    if(tuneChop64) {
        g = chopFfGainLow;
        d = chopKdLow;
        while(g <= chopFfGainHigh) {
            d = chopKdLow;
            while(d <= chopKdHigh) {
                t = t + duration(SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKp,chopKi,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKp,jiggKi,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug));
                t = t + duration(SpireBb_Chop(71,0,10,chopOn64,jigglePosn64,chopOff64,jigglePosn64,nChopCycles,chopPeriod,dcuMode,dcuSample,dcuDelay,bsmSample,0,debug));
                t = t + duration(SpireBb_StopDcuMcuData());
                d = d + chopKdStep;
            }
            g = g + chopFfGainStep;
        }
        t = t + duration(SpireBb_TReset());
    }
    if(tuneCouple7) {
        c = coupleLow;
        while(c <= coupleHigh) {
            t = t + duration(SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKp,chopKi,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKp,jiggKi,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug));
            t = t + duration(SpireBb_Chop(71,0,10,chopOn7,jigglePosn7,chopOff7,jigglePosn7,nChopCycles,chopPeriod,dcuMode,dcuSample,dcuDelay,bsmSample,0,debug));
            t = t + duration(SpireBb_StopDcuMcuData());
            c = c + coupleStep;
        }
        t = t + duration(SpireBb_TReset());
    }
    if(tuneCouple64) {
        c = coupleLow;
        while(c <= coupleHigh) {
            t = t + duration(SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKp,chopKi,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKp,jiggKi,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug));
            t = t + duration(SpireBb_Chop(71,0,10,chopOn64,jigglePosn64,chopOff64,jigglePosn64,nChopCycles,chopPeriod,dcuMode,dcuSample,dcuDelay,bsmSample,0,debug));
            t = t + duration(SpireBb_StopDcuMcuData());
            c = c + coupleStep;
        }
        t = t + duration(SpireBb_TReset());
    }
    if(tuneJigg) {
        g = jiggFfGainLow;
        d = jiggKdLow;
        while(g <= jiggFfGainHigh) {
            d = jiggKdLow;
            while(d <= jiggKdHigh) {
                t = t + duration(SpireBb_SetBsm(chopFfOffsetNom,chopFfGainNom,chopKp,chopKi,chopKdNom,jiggFfOffsetNom,jiggFfGainNom,jiggKp,jiggKi,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug));
                t = t + duration(SpireBb_Chop(71,0,10,chopPosn,jiggTop,chopPosn,jiggBottom,nChopCycles,chopPeriod,dcuMode,dcuSample,dcuDelay,bsmSample,0,debug));
                t = t + duration(SpireBb_StopDcuMcuData());
                d = d + jiggKdStep;
            }
            g = g + jiggFfGainStep;
        }
        t = t + duration(SpireBb_TReset());
    }
    int[] ts = no_pointing(true,0,0,t);
}{
    int step = 0x0;
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            SpireBbStartObs();
            // set nominal housekeeping rate to PHTSTBY
            SpireBbSetNhkSampling("PHTSTBY","v00",debug);
            // // 
            // switch on BMS in nominal configuration
            SpireBbBsmOn("PHTSTBY",bsmModel,bsmVersion,debug);
            SpireBbBsmChopInit("PHTSTBY",bsmModel,bsmVersion,debug);
            SpireBbBsmJiggInit("PHTSTBY",bsmModel,bsmVersion,debug);
            if(tuneChop7) {
                chopFfOffset = chopFfOffsetNom;
                chopFfGain = chopFfGainNom;
                chopKp = 0;
                chopKi = 0;
                chopKd = chopKdNom;
                jiggFfOffset = jiggFfOffsetNom;
                jiggFfGain = jiggFfGainNom;
                jiggKp = jiggKpNom;
                jiggKi = jiggKiNom;
                jiggKd = jiggKdNom;
                step = 0x0;
                g = chopFfGainLow;
                d = chopKdLow;
                s = 0;
                while(g <= chopFfGainHigh) {
                    chopFfGain = ifloor(g * double(chopFfGainNom));
                    step = step + 0x40;
                    s = step;
                    d = chopKdLow;
                    while(d <= chopKdHigh) {
                        chopKd = ifloor(d * double(chopKdNom));
                        s = s + 0x1;
                        SpireBb_SetBsm(chopFfOffset,chopFfGain,chopKp,chopKi,chopKd,jiggFfOffset,jiggFfGainNom,jiggKpNom,jiggKiNom,jiggKdNom,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
                        SpireBb_Chop(71,0,10,chopOn7,jigglePosn7,chopOff7,jigglePosn7,nChopCycles,chopPeriod,dcuMode,dcuSample,dcuDelay,bsmSample,s,debug);
                        SpireBb_StopDcuMcuData();
                        d = d + chopKdStep;
                    }
                    g = g + chopFfGainStep;
                }
                SpireBb_TReset();
            }
            if(tuneCouple7) {
                chopFfOffset = chopFfOffsetNom;
                chopFfGain = chopFfGainNom;
                chopKp = chopKpNom;
                chopKi = chopKiNom;
                chopKd = chopKdNom;
                jiggFfOffset = jiggFfOffsetNom;
                jiggFfGain = jiggFfGainNom;
                jiggKp = jiggKpNom;
                jiggKi = jiggKiNom;
                jiggKd = jiggKdNom;
                step = 0x1000;
                c = coupleLow;
                couple = 0;
                s = 0;
                while(c <= coupleHigh) {
                    couple = ifloor(c * double(cjCoupleNom));
                    step = step + 0x40;
                    s = step;
                    SpireBb_SetBsm(chopFfOffset,chopFfGain,chopKp,chopKi,chopKd,jiggFfOffset,jiggFfGain,jiggKp,jiggKi,jiggKd,couple,cjdCoupleNom,sampFreq,debug);
                    SpireBb_Chop(71,0,10,chopOn7,jigglePosn7,chopOff7,jigglePosn7,nChopCycles,chopPeriod,dcuMode,dcuSample,dcuDelay,bsmSample,s,debug);
                    SpireBb_StopDcuMcuData();
                    c = c + coupleStep;
                }
                SpireBb_TReset();
            }
            if(tuneChop64) {
                chopFfOffset = chopFfOffsetNom;
                chopFfGain = chopFfGainNom;
                chopKp = 0;
                chopKi = 0;
                chopKd = chopKdNom;
                jiggFfOffset = jiggFfOffsetNom;
                jiggFfGain = jiggFfGainNom;
                jiggKp = jiggKpNom;
                jiggKi = jiggKiNom;
                jiggKd = jiggKdNom;
                step = 0x2000;
                g = chopFfGainLow;
                d = chopKdLow;
                chopFfGain = 0;
                chopKd = 0;
                s = 0;
                while(g <= chopFfGainHigh) {
                    chopFfGain = ifloor(g * double(chopFfGainNom));
                    step = step + 0x40;
                    s = step;
                    d = chopKdLow;
                    while(d <= chopKdHigh) {
                        chopKd = ifloor(d * double(chopKdNom));
                        s = s + 0x1;
                        SpireBb_SetBsm(chopFfOffset,chopFfGain,chopKp,chopKi,chopKd,jiggFfOffset,jiggFfGain,jiggKp,jiggKi,jiggKd,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
                        SpireBb_Chop(71,0,10,chopOn64,jigglePosn64,chopOff64,jigglePosn64,nChopCycles,chopPeriod,dcuMode,dcuSample,dcuDelay,bsmSample,s,debug);
                        SpireBb_StopDcuMcuData();
                        d = d + chopKdStep;
                    }
                    g = g + chopFfGainStep;
                }
                SpireBb_TReset();
            }
            if(tuneCouple64) {
                chopFfOffset = chopFfOffsetNom;
                chopFfGain = chopFfGainNom;
                chopKp = chopKpNom;
                chopKi = chopKiNom;
                chopKd = chopKdNom;
                jiggFfOffset = jiggFfOffsetNom;
                jiggFfGain = jiggFfGainNom;
                jiggKp = jiggKpNom;
                jiggKi = jiggKiNom;
                jiggKd = jiggKdNom;
                step = 0x3000;
                c = coupleLow;
                couple = 0;
                s = 0;
                while(c <= coupleHigh) {
                    couple = ifloor(c * double(cjCoupleNom));
                    step = step + 0x40;
                    s = step;
                    SpireBb_SetBsm(chopFfOffset,chopFfGain,chopKp,chopKi,chopKd,jiggFfOffset,jiggFfGain,jiggKp,jiggKi,jiggKd,couple,cjdCoupleNom,sampFreq,debug);
                    SpireBb_Chop(71,0,10,chopOn64,jigglePosn64,chopOff64,jigglePosn64,nChopCycles,chopPeriod,dcuMode,dcuSample,dcuDelay,bsmSample,s,debug);
                    SpireBb_StopDcuMcuData();
                    c = c + coupleStep;
                }
                SpireBb_TReset();
            }
            if(tuneJigg) {
                chopFfOffset = chopFfOffsetNom;
                chopFfGain = chopFfGainNom;
                chopKp = chopKpNom;
                chopKi = chopKiNom;
                chopKd = chopKdNom;
                jiggFfOffset = jiggFfOffsetNom;
                jiggFfGain = jiggFfGainNom;
                jiggKp = 0;
                jiggKi = 0;
                jiggKd = jiggKdNom;
                step = 0x4000;
                g = jiggFfGainLow;
                d = jiggKdLow;
                jiggFfGain = 0;
                jiggKd = 0;
                s = 0;
                while(g <= jiggFfGainHigh) {
                    jiggFfGain = ifloor(g * double(jiggFfGainNom));
                    step = step + 0x40;
                    s = step;
                    d = jiggKdLow;
                    while(d <= jiggKdHigh) {
                        jiggKd = ifloor(d * double(jiggKdNom));
                        s = s + 0x1;
                        SpireBb_SetBsm(chopFfOffset,chopFfGain,chopKp,chopKi,chopKd,jiggFfOffset,jiggFfGain,jiggKp,jiggKi,jiggKd,cjCoupleNom,cjdCoupleNom,sampFreq,debug);
                        SpireBb_Chop(71,0,10,chopPosn,jiggTop,chopPosn,jiggBottom,nChopCycles,chopPeriod,dcuMode,dcuSample,dcuDelay,bsmSample,s,debug);
                        SpireBb_StopDcuMcuData();
                        d = d + chopKdStep;
                    }
                    g = g + jiggFfGainStep;
                }
                SpireBb_TReset();
            }
            // switch off BSM
            SpireBbBsmOff();
            // Set the DCU detector sampling for REDY mode
            SpireBbSetDetSampling("REDY",true,"v00",false,debug);
            // Set the BSM sampling for REDY mode (i.e. Off)
            SpireBbSetBsmSampling("REDY","v00",debug);
            // Reset BSM frame parameters back to their default values
            SpireBb_ResetBsm(debug);
            // set nominal housekeeping rate to REDY mode
            SpireBbSetNhkSampling("REDY","v00",debug);
            // // 
            SpireBbEndObs();
        }
    }
}

//
// 10-Nov-2009 SDS - First Version
// Purpose: To set the size of storage table for VMTM (SPIRE-SCR-2144)
// Default size of Table 82 in OBS 4.0.0 is 0x64 - needs to be set to 0x200
//
block SpireBb_SetVMStorage SPIRE 3361 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SetVMStorage started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //
    //set table command call for table id 0x52
    Spire_SET_TABLE(0x52,0x200);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x52,0x0,0x0);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SetVMStorage ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SetObsStep.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set NHK STEP parameter
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/02 V1.0: Initial version to give BB surrounding for
//                  SpireProc_Set_ObsStep procedure. 
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SetObsStep SPIRE 14027 {
    int obsStep = 0; // Obs step parameter [dec]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    message("4    " + time() + ": SpireBb_SetObsStep started");
    message("4          $Id: $");
    // //
    // //
    // Set ObsStep:
    //
    SpireProc_Set_ObsStep(obsStep,debug);
    // //
    // //
    // End BB:
    //
    SpireMsg(4,"    " + time() + ": BB SpireBb_SetObsStep ended");
    //
}

// Missionphase  : 
//
// Purpose       : Loading the sequencer to build up the signal (OBMO)
//                 for normal DDCS mode                  
//                 
//
// TCL author    : TM
// TCL file      : tm_phot_sequencer_setup.tcl
// CUS author    : DAC
// Script file   : PHOT_seq_setup.txt 
//
// Input arguments
// type    name         description
//
// Return values
// Type    Name      Default      Description
//
// Description  : This script will set the sequencer, which is building
//                up the final signal and it sets the data mode
//                to "Bolo & HK".
//                This script should be executed just after the
//                switch-on procedure, the BOLC initialisation
//                and the bias SETTING (polarizer)
//                The purpose of this scenario is to configure the BOLC 
//                sequencer.
//                The sequencer will provide clock signals for detector
//                readout and for BOLC analog synchronous operation 
//                (switching between S and Sref, triggering A to D conversion)
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : 
// 
// Version       : 0.2 
// History       : 0.1 13-apr-2005 DAC. Based on TM's V1.0 from 20-apr-2004
//               : 0.2 13-apr-2006 TM, updated for new sequencer, cleaning
//                                 of commands in the end (2_Load_of_new_sequencer.txt)
int[] procedure PHOT_seq_setup {
}{
    // Define variables to communicate various durations to HSPOT.
    // NOTE: all time variables in units of number of ramps (SPEC) or
    //       number of readouts (BOLO). The calling program must convert this
    //       count into actual duration in true time units [seconds].
    //       SRC, REF, CAL, OVR stand for time spent on SRC, REF (on sky),
    //       CAL source, and overheads (wait for something). Total
    //       duration is given by duree_num. If no error, this duration
    //       must be equal to the sum of all others
    int duree_num = 0;
    int duree_SRC = 0;
    int duree_REF = 0;
    int duree_CAL = 0;
    int duree_OVR = 0;
    int time_start = time();
    //--------------------------------------
    //  BOLC sequencer initialisation (OBMO)
    //--------------------------------------
    //   
    // PC103420 "DMC_SEND_COMMAND_BOLC" SEND COMMAND TO BOL CONTROLLER
    //         PP071420 "BOLOMETER_COMMAND"
    //
    // Sequence of command to load the BOLC programmable sequencer:
    // The timing is defined according to timing diagram given by P.Agnese
    //    Set_clock_mux stop
    //    P 09 00 00 00
    Pacs_BOLC_SET_CLOCK_MUX("STOP");
    // Set seq param table 0 time 0 clk 20
    // P 0C 00 0014
    Pacs_BOLC_FINE_TIME_SETTING(0x14);
    // Set seq param table 1 time 35 clk 52
    // P 0C 01 11B4
    Pacs_BOLC_FINE_TIME_SETTING(0x111b4);
    // Set seq param table 2 time 144 clk 116
    // P 0C 02 4874
    Pacs_BOLC_FINE_TIME_SETTING(0x24874);
    // Set seq param table 3 time 153 clk 100
    // P 0C 03 4CE4
    Pacs_BOLC_FINE_TIME_SETTING(0x34ce4);
    // Set seq param table 4 time 159 clk 108
    // P 0C 04 4FEC
    Pacs_BOLC_FINE_TIME_SETTING(0x44fec);
    // Set seq param table 5 time 280 clk 44
    // P 0C 05 8C2C
    Pacs_BOLC_FINE_TIME_SETTING(0x58c2c);
    // Set seq param table 6 time 290 clk 36
    // P 0C 06 9124
    Pacs_BOLC_FINE_TIME_SETTING(0x69124);
    // Set seq param table 7 time 294 clk 52
    // P 0C 07 9334
    Pacs_BOLC_FINE_TIME_SETTING(0x79334);
    // Set seq param table 8 time 314 clk 20
    // P 0C 08 9B14
    Pacs_BOLC_FINE_TIME_SETTING(0x89b14);
    // Set seq param table 9 time 322 clk 0
    // P 0C 09 A100
    Pacs_BOLC_FINE_TIME_SETTING(0x9a100);
    // Set clock mux sequencer
    // P 09 00 00 01
    Pacs_BOLC_SET_CLOCK_MUX("Sequencer");
    //-----------------
    // End of Procedure
    //-----------------
    // Time spent
    int duree_TCs = time() - time_start;
    duree_OVR = duree_TCs;
    duree_num = duree_OVR;
    // Return the array of times
    int[] time_array = [duree_num,duree_SRC,duree_REF,duree_CAL,duree_OVR];

    return time_array;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Set_SpecBias
//
///////////////////////////////////////////////////////////
//
//  Procedure to configure the spectrometer detector biases
//
///////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/15 V0.1: Initial version adapted from
//                  SpireProc_Set_PhotBias (KJK, 2009/02/15 V0.2) and
//                  SpireBb_SpecFSetBiasAmpl (MP, 2008/08/12 V0.1)
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_SpecBias {
    int ssw_bias = 0; // SSW bias amplitud
    int slw_bias = 0; // SLW bias amplitud
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string tstr = "";
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"     " + tstr + ":  SpireProc_Set_SpecBias started");
    SpireMsg(4,"          $Id:$");
    // //
    // //
    // Set the selected bias values:
    //
    // Set the bias levels for the three arrays:
    SpireSendDrcuCmd(0x84310000 + ssw_bias,0);
    SpireSendDrcuCmd(0x84320000 + slw_bias,0);
    sync();
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"      " + tstr + ": SpireProc_Set_SpecBias ended");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_WaitAtGcp.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to wait input time setting NHK parameter SSTEP at start and end
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/03 V1.0: Initial version adapted from 
//                  SpireBb_StopDcuData (2009/01/30 V1.1)
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_WaitAtGcp SPIRE 14029 {
    int gcp_time = 15; // Time spend at GCP (gyro calibration position) [s]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // 
    // Determine time to set ObsStep:
    int osTime = duration(SpireProc_Set_ObsStep(9999,debug));
    // //
    // //
    // Start BB:
    //
    message("4    " + time() + ": SpireBb_WaitAtGcp started");
    message("4          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    delay(1);
    // //
    // //
    // Set Step parameter at start:
    //
    SpireProc_Set_ObsStep(65535,debug);
    // //
    // //
    // Wait:
    //
    delay(gcp_time - 2 * osTime - 1);
    // //
    // //
    // Set Step parameter at end:
    //
    SpireProc_Set_ObsStep(0,debug);
    // //
    // //
    // End BB:
    //
    SpireMsg(4,"    " + time() + ": BB SpireBb_WaitAtGcp ended");
    //
}

// SpireEngPatchPM
//
// $id$
//
// This observation patches the DPU PM (RAM) 
//
// The instrument should normally be in REDY mode before execution
// of this observation.
//
//
// 26/04/2010 SDS: First Version 1.0 - SPIRE-SCR-2534  
//
///////////////////////////////////////////////////////////////////////////
obs SpireEngPatchPM {
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use)
    int pInt2 = 0; // Spare parameter (currently not in use)
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int t = duration(SpireBbStartObs()) + duration(SpireBbEndObs());
    t = t + duration(SpireBb_StopMonitoring()) + duration(SpireBb_PatchPM()) + duration(SpireBb_StartMonitoring());
    // ***********************************************
    int[] ts = no_pointing(true,0,0,t);
}{
    SpireMsg(0,"Observation Start");
    SpireMsg(3,"       $Id:$");
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            SpireBbStartObs();
            SpireBb_StopMonitoring();
            SpireBb_PatchPM();
            SpireBb_StartMonitoring();
            SpireBbEndObs();
        }
    }
    SpireMsg(0,"Observation Completed  (" + time() + " seconds)");
    SpireMsg(0,"Note: Total time (s) = Observation Completed time - slew time + Observatory Overheads");
}

// SpireSpectroScalOn
//
// $id$
//
// This observation switches on the SCAL
// 
// The instrument should be in SPECSTBY mode before execution of this observation
// Final Configuration: Instrument is still in SPECSTBY mode after execution of this observation
//
//
// 26/08/2009 KJK: First Version
// 06/09/2009 KJK: Changed scalTemp to accept values in Kelvin (SCR SPire-1870)
//
obs SpireSpectroScalOn {
    string scal = "Default" in ["Default","SCAL2","SCAL4"]; // SCAL status
    double scalTemp = 5.0 in [5.0,80.0]; // SCAL temperature, if SCAL2 or SCAL4 selected (Kelvin)
    int stabilisationTime = 120; // time (secs) to allow SCAL/Detectors to stabilise before starting observations
    bool sampleDetectors = true; // sample detectors during the stabilisation period (assumes detector sampling rate/mode is already configured)
    string scalVersion = "v00";
    string detVersion = "v00";
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int scalTempRaw = -1;
    if(scal != "Default") {
        scalTempRaw = iround(interpolate("SpireTable_SCALTemp.txt",scal,scalTemp));
    }
    int tih = duration(SpireBbStartObs());
    int tfh = duration(SpireBbEndObs()) + duration(SpireBbSetDetSampling("SPECSTBY",false,detVersion,false,debug));
    int tp = duration(SpireProc_Set_Scal(scal,scalTempRaw,stabilisationTime,sampleDetectors,scalVersion,detVersion,debug));
    int[] ts = no_pointing(true,tih,tfh,tp);
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // ***********************  INITIAL HOLD          
            // set OBSID
            SpireBbStartObs();
        }
        if(state[0] == 3) {
            // ***********************  EXECUTE
            SpireProc_Set_Scal(scal,scalTempRaw,stabilisationTime,sampleDetectors,scalVersion,detVersion,debug);
        }
        if(state[0] == 5) {
            // ***********************  FINAL HOLD
            // Return detector sampling to default configuration
            SpireBbSetDetSampling("SPECSTBY",false,detVersion,false,debug);
            SpireBbEndObs();
        }
    }
}

// Missionphase  : 
//
// Purpose       : Enable/disable the chopper electronics
//
// Author CUS    : Diego A. Cesarsky (diego.cesarsky@mpe.mpg.de)
//
// Author TCL    : N/A
//
// Original TCL  : N/A
//
// Input arguments
// Type    Name          DefVal   Description
// string  on_off        "ON"     ON: Enable chopper, OFF: Disable
//
// Description   : 
//
// Dependencies  : 
//                 
// Comments      : 
//
// Version       : 0.3
// History       : 0.1 23-Aug-2004 First creation
//                 0.2 13-apr-2005 DAC Renamed and modified
//                                 Enable_disable_chopper procedure
//                 0.3  8-mar-2007 Added 10sec delay between SWON and ENABLE
//                                 (HD's e-mail)
//               :
//
procedure CHOP_on_off {
    string on_off = "ON" in ["ON","OFF"]; //Enable/Disable chopper
}{
    if(on_off == "ON") {
        Pacs_DMC_SWON_CHOP_CONT();
        delay(10);
        Pacs_DMC_ENABLE_CHOP_CONT();
    }
    // Disable
    if(on_off == "OFF") {
        Pacs_DMC_DISABLE_CHOP_CONT();
        Pacs_DMC_SWOF_CHOP_CONT();
    }
}

// SpireBb_CalPdetOff
//
// $id$
//
// This building block switches off the photometer detectors for calibration observations
//
// 07/01/2010 S.D.Sidher V0.1:
//         Adapted from SpireBbPdetOff (does not set the mode)
// 
block SpireBb_CalPdetOff SPIRE 3414 {
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB CalPdetOff started");
    //
    int cmd = 0x0;
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // Set STEP to 0
    SpireSetObsStep(0x0);
    delay(1);
    //
    //
    // Switch off TC Vdd and Vss
    //
    SpireSendDrcuCmd(0x8413003f,0);
    SpireSendDrcuCmd(0x84140000,0);
    delay(1);
    // 
    // Switch off  PSW VDD and VSS
    SpireSendDrcuCmd(0x84120000,0);
    for(int i = 0 .. 5) {
        SpireSendDrcuCmd(0x84050000 + 0x10000 * i,0);
        delay(1);
    }
    //
    // Switch off  PMW VDD and VSS
    SpireSendDrcuCmd(0x84130030,0);
    for(int j = 0 .. 3) {
        SpireSendDrcuCmd(0x840b0000 + 0x10000 * j,0);
        delay(1);
    }
    //
    // Switch off  PLW VDD and VSS
    SpireSendDrcuCmd(0x84130000,0);
    for(int k = 0 .. 1) {
        SpireSendDrcuCmd(0x840f0000 + 0x10000 * k,0);
    }
    delay(1);
    // 
    // Set DEMOD PHASE TO ZERO
    SpireSendDrcuCmd(0x841a0000,0);
    SpireSendDrcuCmd(0x841b0000,0);
    delay(1);
    SpireSendDrcuCmd(0x841c0000,0);
    SpireSendDrcuCmd(0x841d0000,0);
    delay(1);
    //
    // Set BIAS TO ZERO
    SpireSendDrcuCmd(0x84010000,0);
    SpireSendDrcuCmd(0x84020000,0);
    delay(1);
    SpireSendDrcuCmd(0x84030000,0);
    SpireSendDrcuCmd(0x84040000,0);
    delay(1);
    //
    // Switch OFF PLIAs 
    SpireSendDrcuCmd(0xa0870004,0);
    delay(1);
    //
    // completion
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB CalPdetOff   ended");
    SpireMsg(1,"  ..BB CalPdetOff Switch Off (" + (time() - t0) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SetBsmFramerate.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set MCU framerate (==BSM ampling rate) 
//
// Note: Script calls the procedure SpireProc_Set_BsmFramerate.txt
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/01/30 V1.0: Initial version 
// 2009/02/15 V1.1: Replaced input in Hz by input in Dec(Hex), conversion done
//                  in SpireProc_CalcParam_BsmFramerate. 
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SetBsmFramerate SPIRE 14025 {
    int frate = 37; // Specifies the frame rate [Dec(Hex)]
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    message("4    " + time() + ": SpireBb_SetBsmFramerate started");
    message("4          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    delay(1);
    // //
    // //
    // Set framerate:
    //
    SpireProc_Set_BsmFramerate(frate,debug);
    // //
    // //
    // End BB:
    //
    SpireMsg(4,"    " + time() + ": BB SpireBb_SetBsmFramerate ended");
    //
}

//CLName: SpireBb_LoadTableFlash
//VMVersion: 2.8
//CLVersion: 1.4
//CLCVSId: $ID$
//TableId: 0x46
//TableLength: 0xe0
//Date: 090811172019
block SpireBb_LoadTableFlash SPIRE 3344 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableFlash started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0x46
    Spire_SET_TABLE(0x46,0xe0);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x46,0x0,38,[{0x201e0000},{0x201f0001},{0x20200002},{0x12000016},{0x7d0},{0x12000017},{0x7d0},{0x14000017},{0x5dc},{0x20140006},{0x14000014},{0x7d0},{0x14000014},{0x7d0},{0x32080002},{0x30000005},{0x14000014},{0x7d0},{0x14000014},{0x7d0},{0x35140016},{0x30000005},{0x12000014},{0x7700},{0x53010014},{0x7f000000},{0x20150003},{0x16000015},{0x2},{0x22151506},{0x14000015},{0x7d0},{0x32050002},{0x30000005},{0x14000015},{0x7d0},{0x14000015},{0x7d0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x46,0x26,38,[{0x35150016},{0x30000005},{0x12000015},{0x7701},{0x53010015},{0x7f000000},{0x80007d0},{0x1000001},{0x12000003},{0x7d0},{0x9000003},{0x12000000},{0x0},{0x12000001},{0x43e},{0x12000002},{0x0},{0x60640001},{0x12000000},{0x0},{0x12000001},{0x43c},{0x20020004},{0x60640001},{0x12000000},{0x0},{0x12000001},{0x43d},{0x20020005},{0x60640001},{0x32050008},{0x12000000},{0x0},{0x12000001},{0x43e},{0x12000002},{0x1},{0x60640001}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x46,0x4c,38,[{0x12000000},{0x2},{0x12000001},{0x82},{0x12000002},{0x0},{0x60640001},{0x12000000},{0x2},{0x12000001},{0x83},{0x20020007},{0x60640001},{0x12000000},{0x2},{0x12000001},{0x84},{0x20020008},{0x60640001},{0x32080008},{0x12000000},{0x2},{0x12000001},{0x82},{0x12000002},{0x1},{0x60640001},{0x12000000},{0x2},{0x12000001},{0xc8},{0x2002001e},{0x60640001},{0x32080002},{0x3000000f},{0x12000000},{0x2},{0x12000001}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x46,0x72,38,[{0x82},{0x12000002},{0x0},{0x60640001},{0x12000000},{0x2},{0x12000001},{0x82},{0x12000002},{0x1},{0x60640001},{0x9000014},{0x1000000},{0x80007d0},{0x1000001},{0x80007d0},{0x32050002},{0x3000000f},{0x12000000},{0x0},{0x12000001},{0x43e},{0x12000002},{0x0},{0x60640001},{0x12000000},{0x0},{0x12000001},{0x43e},{0x12000002},{0x1},{0x60640001},{0x9000015},{0x1000000},{0x80007d0},{0x1000001},{0x80007d0},{0x12000000}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x46,0x98,38,[{0x2},{0x12000001},{0xc8},{0x2002001f},{0x60640001},{0x32080002},{0x3000000f},{0x12000000},{0x2},{0x12000001},{0x82},{0x12000002},{0x0},{0x60640001},{0x12000000},{0x2},{0x12000001},{0x82},{0x12000002},{0x1},{0x60640001},{0x9000014},{0x1000000},{0x80007d0},{0x1000001},{0x80007d0},{0x32050002},{0x3000000f},{0x12000000},{0x0},{0x12000001},{0x43e},{0x12000002},{0x0},{0x60640001},{0x12000000},{0x0},{0x12000001}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x46,0xbe,34,[{0x43e},{0x12000002},{0x1},{0x60640001},{0x9000015},{0x1000000},{0x80007d0},{0x1000001},{0x80007d0},{0x11000020},{0x3220ff9f},{0x12000000},{0x0},{0x12000001},{0x43e},{0x12000002},{0x0},{0x60640001},{0x12000000},{0x2},{0x12000001},{0x82},{0x12000002},{0x0},{0x60640001},{0x12000000},{0x2},{0x12000001},{0xc8},{0x2002001e},{0x60640001},{0x1000000},{0x80007d0},{0x7f000000}]);
    delay(t_min);
    //
    //  dump table contents
    //
    Spire_REPORT_TABLE(0x46,0x0,0x0);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableFlash ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

// $Id: WriteEndBB.txt,v 1.2 2007/08/22 10:21:52 dcesarsk Exp $ 
// Purpose       : Set BBID to its default value to indicate the end
//                 of current BB execution (see FIRST-FSC-DOC-0200) 
//
// CUS script    : Diego A. Cesarsky (diego.cesarsky@mpe.mpg.de)
//
// Input arguments N/A
//
// Description   : BBID will be set to its LEG value
//
// Comments      : Needed for SCR-3507
//
// Version       : 0.1 21-aug-2007 First creation
// 		 : 1.0 derived from ...made it a block
// 		 : 2.0 to accomodate with Spire logic PHS-1325
//
block PacsSpireBbWriteEndBB PACS 1106 {
    int tDelay = 0;
}{
    int iBBID = 0x40000000;
    // Write BBID to DEC/MEC
    wait_until(tDelay);
    Pacs_DMC_SET_BBID(iBBID);
    // bus sync
    //    sync();
}

// SpirePcalFlash
//
// $id$
//
// This procedure executes a PCAL Flash
// 
// The instrument should be in  the PHOTSTBY or SPECSTBY modes before execution of this procedure
// and the parameter passed to the procedure should correspond to the initial state
//
// 09/11/2007 KJK  Updated to return MODE to correct value at end of observation
// 05/07/2009 KJK:
//         SPR-1593 - Added flashVersion and debug to input parameters
//                         - Updated call to SpireBbPcalFlash to provide flashVersion and debug
// 27/10/2009 KJK: added new possible flash modes to input list
// 17/02/2010 KJK: SPR Spire-2391:
//        Change calls to SpireSetObsMode to use SpireBb_SetObsMode
//
// 04/03/2010 SDS: The changes Ken made on 17/02/2010 are for SPR Spire-2390, not SPR Spire-2391.
//
procedure SpirePcalFlash {
    string flashMode = "PFlash" in ["PFlash","SFlash","POF8","SOF8","PFlash_b","SFlash_b","POF8_b","SOF8_b"]; // Flash mode
    string flashVersion = "v00";
    bool debug = false;
}{
    // Set Mode to PCAL Flash
    SpireBb_SetObsMode(flashMode,debug);
    delay(1);
    //
    // execute PCAL Flash
    SpireBbPcalFlash(flashMode,flashVersion,0,debug);
    //
    // reset Mode
    if(flashMode == "PFlash") {
        SpireBb_SetObsMode("PHOTSTBY",debug);
    } else {
        SpireBb_SetObsMode("SPECSTBY",debug);
    }
    delay(1);
}

// CVS comments  : $Id: PHOT_aot_prologue.txt,v 1.8 2008/05/06 13:34:53 vanessa Exp $ 
// Purpose       : SetUp of BOLO preceding AOT (but after orbit_prologue)
//
// CUS author    : DAC
// Script file   : PHOT_aot_prologue.txt 
//
// Input arguments
// type    name         description
//
// Return values
// Type          Description
//
// Description   : Conditions and starts SPU
//                  
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : 
// 
// History       : 0.1 18-jan-2006 DAC
//                 0.2 21-aug-2007 SRC-3507 Indicate end of BB
//                 1.0 10-oct-2007 Added input variables after SCR-3628
//		   2.0 06-may-2008 Added Gain setup: LOW/HIGH gain obs.
//		   2.1 23-spe-2008 SCR 4431 data_rate		   
int[] block PHOT_aot_prologue PACS 211 {
    string set_gain = "LOW";
    int comp_mode_blu = 0;
    int comp_mode_red = 0;
    int nraw_blu = 3;
    int nraw_red = 3;
    bool verbose = true;
}{
    int timeStart = time();
    // Register start of BB
    WriteBBID($BBID);
    // Define the elements of time_array
    int duree_sec = 0;
    int duree_SRC = 0;
    int duree_REF = 0;
    int duree_CAL = 0;
    int duree_OVR = 0;
    // Setup SPU
    bool startSPU = true;
    PHOT_spu_gain_setup(set_gain,comp_mode_blu,comp_mode_red,nraw_blu,nraw_red,startSPU);
    data_rate(120.0);
    // Mark end of BB
    WriteEndBB();
    // Synch bus
    sync();
    // Accumulated duree [milliseconds]
    int duree_msec = 0;
    duree_sec = time() - timeStart;
    // Do nothing for time being
    if(verbose) {
        debug_print("PHOT_aot_prologue: " + duree_sec + " [sec]");
    }

    return [duree_sec,duree_SRC,duree_REF,duree_CAL,duree_OVR];
}

// SpireEngSmecLedLvdt
//
// $id$
//
// This observation just switches on the SMEC LED and LVDT sensor
//
// The instrument should normally be in REDY mode before execution
// of this observation.
//
//
// 05-Jul-2010: Version 1.0 SDS
//                      Created in response to SCR SPIRE-2669
//
// 06-Jul-2010: Version 1.1 SDS
//                             Added MOIS statements
///////////////////////////////////////////////////////////////////////////
obs SpireEngSmecLedLvdt {
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string smecVersion = "v00"; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use)
    int pInt2 = 0; // Spare parameter (currently not in use)
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int t = duration(SpireBbStartObs()) + duration(SpireBbEndObs());
    t = t + duration(SpireBb_SmecLedLvdt(smecVersion,debug));
    //
    // ***********************************************
    int[] ts = no_pointing(true,0,0,t);
}{
    SpireMsg(0,"Observation Start");
    SpireMsg(3,"       $Id:$");
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            mois_comment("Procedure SpireEngSmecLedLvdt: to switch on the SMEC LED and LVDT sensor");
            mois_comment("Procedure starts and ends in SPIRE REDY mode");
            mois_comment("The OBSID needs to be set manually in the first TC");
            mois_tmcheck("Verify that the OBSID has been set correctly");
            mois_comment("No other manual TM checks or intervention is necessary");
            mois_comment("Rest of commands in procedure can be executed automatically");
            SpireBbStartObs();
            // Call the BB to switch on the SMEC LED and LVDT
            SpireBb_SmecLedLvdt(smecVersion,debug);
            // 
            SpireBbEndObs();
        }
    }
    SpireMsg(0,"Observation Completed  (" + time() + " seconds)");
    SpireMsg(0,"Note: Total time (s) = Observation Completed time - slew time + Observatory Overheads");
}

// CVS comments  : $Id: OBCP_chopped_photometry.txt,v 1.6 2007/08/22 10:18:28 dcesarsk Exp $ 
// Missionphase  : PACS AVM ILT Orbit-Operations
//
// Purpose       : OnBoardControlProcedure to perform
//                 chopped photometry
//                 Chopped observations of SRC in the manner:
//                     SRC->REF1->SRC->REF2
//                 followed by a calibration sequence using the internal
//                 blackbodies
//                     CS1 -> CS2
//                 User can specify the number of source observing cycles
//                (nb_SRC_REF), the number of calibration cycles (nb_CS1_CS2)
//                 and how many times the whole sequence shall be repeated
//                (nb_cycles_obs_cal).
//                 The number of readouts per quiescent chopper position is
//                 the same (nb_rdouts_plateau) within each cycle
//
// OBCP author   : Helmut Feuchtgruber
// CUS script    : Diego A. Cesarsky
// CVS file      : OBCP_chopped_photometry.txt from AOT code  
//
// Arguments: 
// Type  Name                 Description
// int   nb_SRC_REF           p01 Number of observations in OBS loop
// int   chop_pos_SRC         p02 Chopper position for SRC
// int   nb_rdouts_plateau    p03 Number of readouts per chopper position 
// int   chop_pos_REF1        p04 Chopper position for BKG1
// int   chop_pos_REF2        p05 Chopper position for BKG2 (may be equal to BKG1) 
// int   nb_cycles_obs_cal    p06 Number of obs/cal cycles
// int   nb_CS1_CS2           p07 Number of observations in CAL loop
// int   chop_pos_CS1         p08 Chopper position for CS1
// int   chop_pos_CS2         p09 Ditto for CS2 
// int   comp_mode_blu         Compression mode BLUE
// int   comp_mode_red         Ditto RED 
// int   chop_def              Chopper default position 
//
//
// Description   : This script mimics the OBCP_CHOPPED_PHOTOMETRY
//                 pseudo script, section 3.1.1 in PACS-ME-LI-005
//                 This CUS version computes the duration of the
//                 observation, as specified by the input parameters.
//                 It will also send the trigger TC to start the OBCP
//
// Dependencies  : DMC_phot_2_3_chop
//                 WriteBBID   
// Comments      : 
//
// Version       : 1.2 21-Jan-2004 Creation by DAC
// History       : 0.2 23-Jan-2004 Set value for seq_time, removed seq
//                                 and seq_time as arguments  
//               : 0.3 08-Aug-2004 Changed variable name as "duration" 
//                                 is now a reserved name
//               : 0.4  08-Aug-2004 Rename to block OBCP_etc PACS 4
//                 0.5  20-Aug-2004 Use redefined DMC script
//                 0.6  25-Aug-2004 The BBID is generated and TCed here
//                 0.7  17-Sep-2004 Use renamed DEC_phot_2_3_chop
//                 0.8  27-Sep-2004 Use "double" for BOL frequency and associated data
//                 0.9   7-Oct-2004 Use renamed WriteBBID
//                 0.91 18-Oct 2004 Normalized variable names
//                 0.92  9-Nov-2004 DMC now returns [] of times
//                                  [duration_rdouts,
//                                   duree_SRC,
//                                   duree_REF,
//                                   duree_CAL,
//                                   duree_OVR]
//                                   (expressed in nb_of_readouts)
//                 0.93 10-Dec-2004 True duration must include the fact that
//                                  TCs are sent 2 per second, i.e. each TC
//                                  takes 1/2 second. Use "time" function to
//                                  get actual duration.
//                                  obcp_ID is now a string
//                 1.0  30-Nov-2005 Use computed duration; remove debug_print
//                 1.1  21-aug-2007 SRC-3507 Indicate end of BB
//                 1.2  18-feb-2008 DAC Added sync at end
//                 1.3 09-sep-2009 VD SPR PACS-2039 add 5sec delay for Bolometer stabilisation
//                 1.4 15-sep-2009 VD: SPR PACS-2039. delay removed from OBCP (too many dependences)
//
int[] block OBCP_chopped_photometry PACS 4 {
    int nb_SRC_REF = 1; // p01 Number of observations in OBS loop
    int chop_pos_SRC = 0; // p02 Chopper position for SRCE
    int nb_rdouts_plateau = 8; // p03 Number of readouts per chopper position 
    int chop_pos_REF1 = -2000; // p04 Chopper position for BKG1
    int chop_pos_REF2 = 2000; // p05 Chopper position for BB2
    int nb_cycles_obs_cal = 1; // p06 Number of obs/cal cycles
    int nb_CS1_CS2 = 0; // p07 Number of observations in CAL loop
    int chop_pos_CS1 = -22680; // p08 Chopper position for CS1
    int chop_pos_CS2 = 22680; // p09 Chopper position for CS2
    int comp_mode_blu = 0; // Compression mode BLUE channel
    int comp_mode_red = 0; // Compression mode RED channel
    int chop_def = 0; // Chopper default position
}{
    // Starting time
    int time_start = time();
    // Register start of BB
    WriteBBID($BBID);
    // Variables that may be used to define various times
    int duree_SRC = 0;
    int duree_REF = 0;
    int duree_CAL = 0;
    int duree_OVR = 0;
    // Obtain system parameter from PACSparams
    // BOL readout frequency [Hz] and readout period [msec]
    double bol_freq = dlookup("PACSparams","bolo_sample","freq_time");
    //  string bol_unit = slookup("PACSparams","bolo_sample","unit");
    double bol_period = 1000.0 / bol_freq;
    //  debug_print("Bolo sample: " + bol_freq + " " + bol_unit);
    //  debug_print("Bolo period: " + bol_period + "[msec]");
    // Obtain duration of an "internal" command [msec]
    int t_cmd = iceil(dlookup("PACSparams","int_cmd","freq_time"));
    // Obtain duration of DEC/MEC "communication jitter" [msec]
    int dmc_margin = iceil(dlookup("PACSparams","dmc_margin","freq_time"));
    // Obtain duration of OBCP "communication jitter" [msec]
    int obcp_margin = iceil(dlookup("PACSparams","obcp_margin","freq_time"));
    // Start tallying the duration of this script [msec]
    int duration_msec = 0;
    // OBCP Pseudo Code starts here (accumulate duration_msec [msec] as it goes)
    // Begin 
    // DEC_WRITE_TIME (DPU_TIME in standard 48 bit format according to PS-ICD)
    // Here and elsewhere it is assumed that OBCP "internal" TCs take t_cmd
    // [msec] to be executed
    duration_msec = duration_msec + t_cmd;
    duree_OVR = duree_OVR + t_cmd;
    // SET_TIME 
    duration_msec = duration_msec + t_cmd;
    duree_OVR = duree_OVR + t_cmd;
    // DEC_WRITE_SEQ_BUF(ID, LENGTH, DATA, CHECKSUM)
    duration_msec = duration_msec + t_cmd;
    duree_OVR = duree_OVR + t_cmd;
    // Invoke CUS version of DECMEC sequence above (DMC_PHOT_2_3_CHOP)
    // (only to compute duration!! Hence use only duration related parameters
    // in the call)
    // The DMC is number seq_DMC=1 and lasts seq_time [msec]
    // Duration "duree1" is an array with five elements
    int[] duree1 = DMC_phot_2_3_chop(nb_SRC_REF,nb_rdouts_plateau,nb_cycles_obs_cal,nb_CS1_CS2);
    // Convert duration [readouts] into [msec]; add dmc_margin
    int seq_time = ifloor(double(duree1[0]) * bol_period) + dmc_margin;
    // Convert other times as well into msec
    duree_SRC = ifloor(double(duree1[1]) * bol_period);
    duree_REF = ifloor(double(duree1[2]) * bol_period);
    duree_CAL = ifloor(double(duree1[3]) * bol_period);
    duree_OVR = duree_OVR + ifloor(double(duree1[4]) * bol_period) + dmc_margin;
    // Tally into accumulated duration of OBCP   			 
    duration_msec = duration_msec + seq_time;
    // SYNCHRONIZE_ON_DETECTOR(3) 
    duration_msec = duration_msec + t_cmd;
    duree_OVR = duree_OVR + t_cmd;
    // DEC_WRITE_TRM_CMP(ID, 1, cmp_par, CHHKSUM) 
    duration_msec = duration_msec + t_cmd;
    duree_OVR = duree_OVR + t_cmd;
    // START_SEQUENCE duration_msec(seq_time)
    duration_msec = duration_msec + t_cmd;
    duree_OVR = duree_OVR + t_cmd;
    // WAIT(seq_time)
    // Check execution status of the sequence and in case of failure stop OBCP
    // and issue TM(1,8) + event 
    // MOVE_CHOPPER_ABSOLUTE(chop_def) 
    duration_msec = duration_msec + t_cmd;
    duree_OVR = duree_OVR + t_cmd;
    // Issue TM(1,7) 
    // Now trigger execution of OBCP
    // This OBCP is number 4, requires 14 parameters and lasts seq_time [msec]
    string obcp_ID = "CHOPPED_PHOT";
    int obcp_par_nber = 14;
    int seq_DMC = 1;
    {int,int}[] grp = [{1,seq_DMC},{2,seq_time},{3,nb_SRC_REF},{4,chop_pos_SRC},{5,nb_rdouts_plateau},{6,chop_pos_REF1},{7,chop_pos_REF2},{8,nb_cycles_obs_cal},{9,nb_CS1_CS2},{10,chop_pos_CS1},{11,chop_pos_CS2},{12,comp_mode_blu},{13,comp_mode_red},{14,chop_def}];
    Pacs_DPU_START_OBCP(obcp_ID,obcp_par_nber,grp);
    // Add the "communication jitter"
    duration_msec = duration_msec + obcp_margin;
    duree_OVR = duree_OVR + obcp_margin;
    // Return total duration [sec] to calling program
    // Create return time array; convert into [sec]
    int[] time_array = [duration_msec,duree_SRC,duree_REF,duree_CAL,duree_OVR];
    for(int aux = 0 .. 4) {
        time_array[aux] = Msec2sec(time_array[aux]);
    }
    // Set delay()
    // removed: add delay 5sec for Bolo stabilisation: SPR PACS-2039
    delay(time_array[0]);
    // Mark end of BB
    WriteEndBB();
    // Sync the bus
    sync();
    // Return OBCP time estimates

    return time_array;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_PhotPhaseConvert.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to translate user input in deg for bias phase 
//  into nearest Hex values for psw_phase, pmw_phase, plw_phase, and ptc_phase  
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/06/09 V0.1: Initial version adapted from
//                  SpireProc_CalcParam_PhotBiasConvert.txt (2008/06/09 V1.3)
// 2008/07/03 V0.2: Renumber version; include PTC conversion
// 2009/02/01 V1.0: Add debug_print as input
//
///////////////////////////////////////////////////////////////////////////
int[] procedure SpireProc_CalcParam_PhotPhaseConvert {
    double input_phase_psw = 0.0 in [0.0,360.0]; // Input PSW Bias Phase [0.0 - 360.0] [deg]
    double input_phase_pmw = 0.0 in [0.0,360.0]; // Input PMW Bias Phase [0.0 - 360.0] [deg]
    double input_phase_plw = 0.0 in [0.0,360.0]; // Input PLW Bias Phase [0.0 - 360.0] [deg]
    double input_phase_ptc = 0.0 in [0.0,360.0]; // Input PTC Bias Phase [0.0 - 360.0] [deg]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Convert from deg to nearest RAW values:
    //
    double conversion_factor = 255.0 / 360.0;
    //
    int raw_phase_psw = iround(conversion_factor * input_phase_psw);
    int raw_phase_pmw = iround(conversion_factor * input_phase_pmw);
    int raw_phase_plw = iround(conversion_factor * input_phase_plw);
    int raw_phase_ptc = iround(conversion_factor * input_phase_ptc);
    //
    // //
    // //
    // Convert nearest RAW values back to deg:
    //
    double phase_psw = double(raw_phase_psw) / conversion_factor;
    double phase_pmw = double(raw_phase_pmw) / conversion_factor;
    double phase_plw = double(raw_phase_plw) / conversion_factor;
    double phase_ptc = double(raw_phase_ptc) / conversion_factor;
    // //
    // //
    // Debug printout:
    //
    if(debug) {
        debug_print("Input deg value for PSW/PMW/PLW/PTC phase amplitude: " + input_phase_psw + "/" + input_phase_pmw + "/" + input_phase_plw + "/" + input_phase_ptc);
        debug_print("Output Hex values for PSW/PMW/PLW/PTC: " + raw_phase_psw + "/" + raw_phase_pmw + "/" + raw_phase_plw + "/" + raw_phase_ptc);
        debug_print("Commanded deg values for PSW/PMW/PLW/PTC: " + phase_psw + "/" + phase_pmw + "/" + phase_plw + "/" + phase_ptc);
    }
    // //
    // //
    // Return required values:
    //

    return [raw_phase_psw,raw_phase_pmw,raw_phase_plw,raw_phase_ptc];
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartPhaseUp.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpirePhoto/Spectro_Cal_PhaseUp.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V0.1: Initial version adapted from
//                  SpireBb_StartBsmAngleCal (2009/05/05 V0.1),
//                  SpirePhoto_Cal_PhaseUp (2009/03/30 V1.4), and
//                  SpireSpectro_Cal_PhaseUp (2009/03/04 V0.5)
//                  BB includes now to move BSM/SMEC to hold/home.  
// 2009/07/03 V1.0: Fix bug to allow spectrometer to use script.   
// 2009/07/10 V1.1: Fix bug SPR-SPIRE-1612
//
// Notes:
//    1) Scripts assumes that SpireBb_SpecOffsetAuto is run 
//       during INITHOLD or at first POINTING.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartPhaseUp SPIRE 14048 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    string obsModeQla = "ENG_CAL_OBS11";
    string obsMode = "PEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_Phot/SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    int smecHomePosn = 3500; // SMEC home position
    int mclkdiv = 149; // mclkdiv (spec ==~ 121)
    int biasdiv = 6; // biasdiv (spec ==~ 1)
    int psw_bias = 62; //
    int pmw_bias = 62; //
    int plw_bias = 62; //
    int ptc_bias = 62; //
    int ssw_bias = 45; //
    int slw_bias = 45; //
    int[] raw_phase_list = [0,0,0,0]; // 
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartPhaseUp configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // In case move SMEC to home:
    // 
    if(!phot) {
        //
        // Calculate available time for possible movement:
        //
        int tmove = duration(SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug)) + duration(SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug)) + duration(SpireProc_Set_DcuFreqSamp(mclkdiv,biasdiv,phot,debug)) + duration(SpireProc_Set_PhotBias(psw_bias,pmw_bias,plw_bias,ptc_bias,debug)) + duration(SpireProc_Set_PhotPhase(raw_phase_list[0],raw_phase_list[0],raw_phase_list[0],raw_phase_list[0],debug)) + duration(SpireBb_SpecOffsetAuto(false,debug));
        //
        // Calculate max offset for which time is available:
        //
        int smecMaxOff = tmove * 500;
        // Note, 500 is maximum possible SMEC speed.
        int smecStart = smecHomePosn + smecMaxOff;
        // Note, formula above only reasonable 
        // when smecHomePosn small compared to 39500  
        // Safety check: 
        if(smecStart > 39500) {
            smecStart = 39500;
        }
        if(debug) {
            debug_print("smecStart: " + smecStart);
            debug_print("smecHomePosn: " + smecHomePosn);
            debug_print("tmove: " + tmove);
        }
        // 
        // Move from maximal offset to home:
        //
        SpireProc_SmecMove2Home(smecHomePosn,smecHomePosn + smecMaxOff,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    if(phot) {
        SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    }
    //delay(timeSlewCal);
    // //
    // //
    // Set requested frequency and bias ampl. plus first phase:
    //
    SpireProc_Set_DcuFreqSamp(mclkdiv,biasdiv,phot,debug);
    if(phot) {
        SpireProc_Set_PhotBias(psw_bias,pmw_bias,plw_bias,ptc_bias,debug);
        SpireProc_Set_PhotPhase(raw_phase_list[0],raw_phase_list[0],raw_phase_list[0],raw_phase_list[0],debug);
    } else {
        SpireProc_Set_SpecBias(ssw_bias,slw_bias,debug);
        SpireProc_Set_SpecPhase(raw_phase_list[0],raw_phase_list[0],debug);
    }
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartPhaseUp configuration ended");
    SpireMsg(1,"  ..StartPhaseUp took " + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Set_PhotBias
//
///////////////////////////////////////////////////////////
//
//  Procedure to configure the photometer detector biases
//
///////////////////////////////////////////////////////////
//
// KJK:
// 2009/02/11 V0.1: Initial version
// 2009/02/15 V0.2: (MP) Use actual amplitudes as input instead of mode. 
//                  Added delay(1). Add some cosmetics to script.  
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_PhotBias {
    int psw_bias = 0; // PSW bias amplitud
    int pmw_bias = 0; // PMW bias amplitud
    int plw_bias = 0; // PLW bias amplitud
    int ptc_bias = 0; // PTC bias amplitud
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string tstr = "";
    // //
    // //
    // Start procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"     " + tstr + ":  SpireProc_Set_PhotBias started");
    SpireMsg(4,"          $Id:$");
    // //
    // //
    // Set the selected bias values:
    //
    // Set the bias levels for the three arrays:
    SpireSendDrcuCmd(0x84010000 + psw_bias,0);
    SpireSendDrcuCmd(0x84020000 + pmw_bias,0);
    delay(1);
    SpireSendDrcuCmd(0x84030000 + plw_bias,0);
    //
    // Set the bias for the PTC:
    SpireSendDrcuCmd(0x84040000 + ptc_bias,0);
    sync();
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(4,"      " + tstr + ": SpireProc_Set_PhotBias ended");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndPcalLoadCurve.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of 
// SpirePhoto/Spectro_Cal_PcalLoadCurve.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/07 V1.0: Initial version adapted from
//                  SpireBb_EndBsmAngleCal (2009/05/05 V1.2),
//                  SpirePhoto_Cal_PcalLoadCurve (2009/03/04 V1.4), and
//                  SpireSpectro_Cal_PcalLoadCurve (2009/03/04 V0.5)
//                  Incl. setting dcuFrameNumber and scuFrameNumber back 
//                  to continuous to unset setting passed to VM. 
// 2009/06/05 V1.1: Replace Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd 
//                  as requested in SPR-1482.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndPcalLoadCurve SPIRE 14069 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndPcalLoadCurve reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set obsstep back to 0:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP(0)");
    Spire_SET_OBS_STEP(0);
    // //
    // //
    // Set instrument back to Phot/Spec-STBY:
    //
    if(phot) {
        SpireProc_Set_PhotMode("PHTSTBY",isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    }
    // //
    // //
    // Set number of DCU frames to continuous:
    //
    int dcuFrameNumber = 0;
    if(phot) {
        dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","PHTSTBY","dcuFrameNumber","v00",debug);
    } else {
        dcuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","dcuFrameNumber","v00",debug);
    }
    //
    SpireSendDrcuCmd(0x843d0000 + dcuFrameNumber,0);
    // //
    // //
    // Set number of SCU frames to continuous:
    //
    int scuFrameNumber = 0;
    if(phot) {
        scuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","PHTSTBY","scuFrameNumber","v00",debug);
    } else {
        scuFrameNumber = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode","SPECSTBY","scuFrameNumber","v00",debug);
    }
    SpireSendDrcuCmd(0xa0840000 + scuFrameNumber,0);
    delay(1);
    // //
    // //
    // End observation:
    //
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndPcalLoadCurve reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartIltPcalFlash.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpirePhoto/Spectro_Cal_IltPcalFlash.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/06 V0.1: Initial version adapted from
//                  SpireBb_StartBsmAngleCal (2009/05/05 V0.1),
//                  SpirePhoto_Cal_IltPcalFlash (2009/03/04 V1.4), and
//                  SpireSpectro_Cal_IltPcalFlash (2009/03/04 V0.5)
//                  BB includes now to move BSM/SMEC to hold/home.  
// 2009/05/26 V0.2: Fixed a bug in call to SpireProc_Set_Phot/SpecPhase
//                  and SpireProc_Set_Phot/SpecBias (phase and bias mixed up).
// 2009/07/10 V1.0: Fix bug SPR-SPIRE-1612
// 
// Notes:
//    1) Scripts assumes that SpireBb_SpecOffsetAuto is run 
//       during INITHOLD or at first POINTING.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartIltPcalFlash SPIRE 14046 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    string obsModeQla = "ENG_CAL_OBS01";
    string obsMode = "PEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_Phot/SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    int smecHomePosn = 3500; // SMEC home position
    int mclkdiv = 149; // mclkdiv (spec ==~ 121)
    int biasdiv = 6; // biasdiv (spec ==~ 1)
    int bias_psw = 62; //
    int bias_pmw = 62; //
    int bias_plw = 62; //
    int bias_ptc = 62; //
    int phase_psw = 127; //
    int phase_pmw = 127; //
    int phase_plw = 127; //
    int phase_ptc = 127; //
    int bias_ssw = 45; //
    int bias_slw = 45; //
    int phase_ssw = 128; //
    int phase_slw = 128; // 
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartIltPcalFlash configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // In case move SMEC to home:
    // 
    if(!phot) {
        //
        // Calculate available time for possible movement:
        //
        int tmove = duration(SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug)) + duration(SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug)) + duration(SpireBb_SpecOffsetAuto(false,debug)) + duration(SpireProc_Set_DcuFreqSamp(mclkdiv,biasdiv,phot,debug)) + duration(SpireProc_Set_SpecPhase(bias_ssw,bias_slw,debug)) + duration(SpireProc_Set_SpecBias(phase_ssw,phase_slw,debug));
        //
        // Calculate max offset for which time is available:
        //
        int smecMaxOff = tmove * 500;
        // Note, 500 is maximum possible SMEC speed.
        int smecStart = smecHomePosn + smecMaxOff;
        // Note, formula above only reasonable 
        // when smecHomePosn small compared to 39500  
        // Safety check: 
        if(smecStart > 39500) {
            smecStart = 39500;
        }
        if(debug) {
            debug_print("smecStart: " + smecStart);
            debug_print("smecHomePosn: " + smecHomePosn);
            debug_print("tmove: " + tmove);
        }
        // 
        // Move from maximal offset to home:
        //
        SpireProc_SmecMove2Home(smecHomePosn,smecHomePosn + smecMaxOff,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    if(phot) {
        SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    }
    //delay(timeSlewCal);
    // //
    // //
    // Set requested frequency, phase, and bias level:
    //
    if(phot) {
        SpireProc_Set_DcuFreqSamp(mclkdiv,biasdiv,phot,debug);
        SpireProc_Set_PhotPhase(phase_psw,phase_pmw,phase_plw,phase_ptc,debug);
        SpireProc_Set_PhotBias(bias_psw,bias_pmw,bias_plw,bias_ptc,debug);
    } else {
        SpireProc_Set_DcuFreqSamp(mclkdiv,biasdiv,phot,debug);
        SpireProc_Set_SpecPhase(phase_ssw,phase_slw,debug);
        SpireProc_Set_SpecBias(bias_ssw,bias_slw,debug);
    }
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartIltPcalFlash configuration ended");
    SpireMsg(1,"  ..StartIltPcalFlash took " + (time() - t) + " seconds)");
    //
}

//CLName: JM07
//VMVersion: 2.8
//CLVersion: 2.0
//CLCVSId: $ID$
//TableId: 0x32
//TableLength: 0x10
//Date: 090805151653
//
// Created by Sunil Sidher on 05 Aug 2009 in response to SPIRE SPR-1752
// Normally the JM07 table is created as a BB (Number 3341) but here it is created as a procedure to prevent nesting of BBs
// 
// 2009/08/16: MP (SPR-SPIRE-1752) Fixed a bug in table entries. 
//             Note, I commented but left the old version for reference. 
//
/////////////////////////////////////////////////////////////////////////
procedure SpireProc_Load_Jm7Table {
}{
    int t_min = 1;
    //set table command call for table id 0x32
    Spire_SET_TABLE(0x32,0x10);
    delay(t_min);
    // // 
    // //
    // Update table command call for table index 0x0000:
    //
    // Command before OD98/99 delivery:
    //Spire_UPDATE_TABLE(0x32,0x0,16,[{0x9a026a90},{0x9a02b421},{0x92ce6a90},{0x92ceb421},{0x96686750},{0x9668b17a},{0x9d9b6750},{0x9d9bb17a},{0xa1356a90},{0xa135b421},{0x9d9b6dcf},{0x9d9bb6bb},{0x96686dcf},{0x9668b6bb},{0x92ce6a90},{0x9a02b421}]);
    Spire_UPDATE_TABLE(0x32,0x0,16,[{0x9a026a90},{0x9a02b421},{0x92ce6a90},{0x92ceb421},{0x96686750},{0x9668b17a},{0x9d9b6750},{0x9d9bb17a},{0xa1356a90},{0xa135b421},{0x9d9b6dcf},{0x9d9bb6bb},{0x96686dcf},{0x9668b6bb},{0x9a026a90},{0x9a02b421}]);
    delay(t_min);
}

// $Id:$
//
// Missionphase    : PV
//
// Purpose           : Execute Pacs/Spire coolers recycling in parallel
//                 
// Author             : Diego A. Cesarsky, Ken King
//
// Arguments       : None
//
// Description      : Merge of Spire's and PACS cooler recycling scripts into  a single procedure
//
// Dependencies  : 
//
// Comments       : Spire should be in  the REDY mode before execution of this
//                         observation
// Version       : 1.0
// History        : 0.1  22-oct-2007 DAC
//                   : 0.2    6-feb-2008 DAC Start PACS recycling 30 min after SPIRE 
//                                      Renamed SpireParallelCoolerRecycle.txt
//                   : 1.0 24-Aug-2009 KJK
//                           - Removed calls to SpireBbStartObs() and SpireBbEndObs() as they
//                             are called in SpireEngCoolerRecycle
//                           - tidied up comments
procedure SpireParallelCoolerRecycle {
}{
    int t0 = time();
    // remember start time
    //
    mois_comment("Procedure to recycle SPIRE/PACS Sorption Coolers");
    //
    //  start execution of Spire's recycle
    int howLongSpire = SpirePacsBbCoolerRecycle();
    mois_comment("SPIRE Cooler Recycle Procedure Started");
    //
    // Wait 30 minutes before starting PACS
    delay(1800);
    //
    // Now start PACS cooler procedure
    mois_comment("PACS Cooler Recycle Procedure Started");
    //DAC 27/06/08  PACS_BOLO_cool_recycle();    
    BOLO_cool_recycle(0,0);
    //
    // Assume Spire recycle has finished by the time the PACS recycle has finished
    // End Spire's procedure
    // Set MODE to REDY
    mois_comment("Set the SPIRE mode to REDY");
    SpireSetObsMode("REDY");
    //
    // completion
    string tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB Cooler Recycle   ended");
    SpireMsg(1,"  ..Cooler Recycle (" + (time() - t0) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndFovMapFpgScan.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of 
// SpirePhoto/Spectro_Cal_FovMapFpgScan
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V1.0: Initial version adapted from
//                  SpireBb_EndBsmAngleCal (2009/05/05 V1.2),
//                  SpirePhoto_Cal_FovMapFpgScan (2009/03/04 V1.3), and
//                  SpireSpectro_Cal_FovMapFpgScan (2009/03/04 V0.1)
//                  Incl. setting dcuFrameNumber and mcuFrameNumber back 
//                  to continuous to unset setting passed to VM. 
// 2009/06/05 V1.1: Replace Spire_SEND_DRCU_COMMAND with SpireSendDrcuCmd 
//                  as requested in SPR-1482.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndFovMapFpgScan SPIRE 14067 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    int hold_chop = 37632; // Chop hold position [Dec(Hex)]
    int hold_jigg = 39520; // Jiggle hod position [Dec(Hex)]
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndFovMapFpgScan reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set obsstep back to 0:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP(0)");
    Spire_SET_OBS_STEP(0);
    // //
    // //
    // Set instrument back to Phot/Spec-STBY:
    //
    if(phot) {
        SpireProc_Set_PhotMode("PHTSTBY",isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Set number of DCU frames to continuous:
    //
    SpireSendDrcuCmd(0x843d0000,0);
    // //
    // //
    // Set number of MCU frames to continuous:
    //
    SpireSendDrcuCmd(0x91c3ffff,0);
    delay(1);
    // //
    // //
    // End observation:
    //
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndFovMapFpgScan reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_PhotSetMode.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to configure some important instrument parameters
// for the photometer depending on the mode. 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/02/15 V0.1: Initial version 
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_PhotSetMode SPIRE 14030 {
    string obsMode = "POF2"; // Obs mode as defined in calibration files
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string hstr = "";
    // a hex string
    string tstr = "";
    // a time string
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": SpireBb_PhotSetMode started");
    SpireMsg(2,"          $Id: $");
    hstr = SpireHexStr($BBID,8);
    SpireMsg(3,"          BBID = " + hstr);
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    sync();
    // //
    // //
    // Call procedure to set parameters:
    //
    SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_PhotSetMode ended");
    SpireMsg(1,"  ..Set Phot phases (" + (time() - t) + " secs)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SmecMove.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to move SMEC to input position and hold
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/11/06 V0.1: Initial version adapted from SpireBb_MoveSmec2Home
//                  (2008/11/02 V0.1)
// 2009/02/02 V0.2: (KJK) Updated to be used in all scripts
//                  - added smecCurrposn input parameter to allow 
//                     calculation of time to move to end position from 
//                     current SMEC position
//                  - replaced call to individual commands by call to new 
//                     procedure SpireProc_SmecMove
// 2009/02/15 V0.3: (MP) Made some cosmetic changes and extended the 
//                  header entry above.
// 2009/03/30 V0.4: (MP) Remove unnecessary calibration table name.
// 2009/09/15 V 0.4: KJK added sync() at end, just to be sure
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SmecMove SPIRE 14019 {
    int smecEndPosn = 1000; // final SMEC position in encoder values 
    int smecCurrPosn = 1000; // current SMEC position in encoder values 
    bool debug = false;
}{
    // //
    // //
    // Define some variables:
    //
    int t = time();
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SmecMove started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBID:
    // 
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    // //
    // //
    // Move SMEC to position:
    //    
    SpireProc_SmecMove(smecEndPosn,smecCurrPosn,debug);
    // //
    // //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SmecMove ended");
    SpireMsg(1,"  ..BB SmecMove (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////
//
// SpireProc_Exec_PhotStdLoadCurve.txt
//
///////////////////////////////////////////////////////////
//
//  Procedure to loop through a list of bias amplitudes 
//  for the 'Phot Standard Load Curve' task 
//
///////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/06/09 V0.1: Initial version adapted from
//                 Mode_ILT_PERF_DAB_P_CPS.txt (v1.3 2008/01/31 23:35:17)
// 2008/07/04 V0.2: Renumber version; Include PTC boloms in loop; skip 
//                  first setup in SpireBb_PhotFSetupData, as it is already 
//                  done during slew
// 2008/11/07 V0.3: Remove test number from script
// 2009/02/01 V1.0: Add debug_print as input
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Exec_PhotStdLoadCurve {
    int[] nbiaslist = [0,50,100,255]; // List of raw bias levels in range (0-255)
    int ftime = 10; // Readout time at each bias level [s]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    //
    //
    // Start the LC bias loop:
    //
    for(int l = 0 .. length(nbiaslist) - 1) {
        // //
        // //
        // Safety check:
        //
        if(nbiaslist[l] > 255) {
            nbiaslist[l] = 255;
            if(debug) {
                debug_print("Input bias list is corrupt! Raw value > 255 requested!");
            }
        }
        // //
        // //
        // Set bias amplitude:
        //
        if(l == 0) {
            if(debug) {
                debug_print("Bias already set during slew");
            }
        } else {
            SpireBb_PhotFSetBiasAmpl(nbiaslist[l],nbiaslist[l],nbiaslist[l],nbiaslist[l],debug);
        }
        // //
        // //
        // Stop DCU data before resetting offsets:
        //
        SpireBb_StopDcuData();
        //
        // //
        // //
        // Set offsets:
        //
        SpireBb_PhotOffsetAuto(debug);
        // //
        // //
        // Take data:
        //
        SpireBb_PhotFTakeData(ftime,debug);
        //
        // //
        // //
        // Debug printing: 
        //
        if(debug) {
            debug_print("Bias level " + nbiaslist[l] + " done.");
        }
    }
    //
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartFixedSmecBeamProfile.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpireSpectro_CalGCO_FixedSmecBeamProfile
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/09/15 V0.1: Initial version adapted from
//                  SpireBb_StartScannedSmecBeamProfile (2009/09/15 V0.1) and 
//                  SpireSpectro_CalGCO_FixedSmecBeamProfile (2008/11/06 V0.3)
// 2009/09/16 V0.2: Replaced last SpireProc_SmecMove2Home with 
//                  SpireProc_SmecMove to allow to end SMEC movement
// 
// Notes:
//    1) Scripts assumes that SpireBb_SpecOffsetAuto is run 
//       during INITHOLD or at first POINTING.
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartFixedSmecBeamProfile SPIRE 14077 {
    string obsModeQla = "ENG_CAL_OBS32";
    string obsMode = "SEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int smec_pos = 1000; // SMEC position in encoder values 
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    bool setFramerate = true; // Set BSM framerate (==tick)?
    int frate = 0; // BSM framerate 
    int smecHomePosn = 3500; // SMEC home position
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartFixedSmecBeamProfile configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // Move SMEC to home:
    // 
    //
    // Calculate available time for possible movement:
    //
    int tmove = duration(SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug)) + duration(SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug));
    if(setFramerate) {
        tmove = tmove + duration(SpireProc_Set_BsmFramerate(frate,debug));
    }
    //
    // Calculate max offset for which time is available:
    //
    int smecMaxOff = tmove * 500;
    // Note, 500 is maximum possible SMEC speed.
    int smecStart = smecHomePosn + smecMaxOff;
    // Note, formula above only reasonable 
    // when smecHomePosn small compared to 39500  
    // Safety check: 
    if(smecStart > 39500) {
        smecStart = 39500;
    }
    if(debug) {
        debug_print("smecStart: " + smecStart);
        debug_print("smecHomePosn: " + smecHomePosn);
        debug_print("tmove: " + tmove);
    }
    // 
    // Move from maximal offset to home (allowing movement beyond proc!):
    //
    SpireProc_SmecMove2Home(smecHomePosn,smecHomePosn + smecMaxOff,debug);
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    //delay(timeSlewCal);
    // //
    // //
    // Set user requested framerate:
    //
    if(setFramerate) {
        SpireProc_Set_BsmFramerate(frate,debug);
    }
    // //
    // //
    // Move SMEC from home to input position:
    //
    SpireProc_SmecMove(smec_pos,smecHomePosn,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartFixedSmecBeamProfile configuration ended");
    SpireMsg(1,"  ..StartFixedSmecBeamProfile took " + (time() - t) + " seconds)");
    //
}

// SpireBbCcuMonitorPeriodRecycle
//
// $Id:$
//
// Building Block to set CCU monitoring period for cooler recycling
//
block SpireBbCcuMonitorPeriodRecycle SPIRE 11776 {
}{
    SpireCcuMonitorPeriodRecycle();
    sync();
}

// SpirePacsBbParallelConfig
//
// $Id: SpirePacsBbParallelConfig.txt,v 1.1 2006/10/11 10:23:39 kking Exp $
//
// Building Block to configure the instrument for Parallel mode operation
//
// The complete instrument setup operation is divided into two parts:
//   Configuration: actions that can be executed during the slew to the start
//          position of the S/C pointing mode.
//   Initialisation: actions that must be carried out at the S/C intial pointing
//          position before any observational operations are executed.   
//
// This building Block implements the first part of the setup 
//
//  25-Aug-2009 KJK:
//                     - Added input parameters to enable selection of versions in Cal Tables
//                     - BSM HOLD position is read from new Cal Table (SpireTable_BsmNominalSettings.txt)
//                     - added code to deal with bright source settings
//
block SpirePacsBbParallelConfig SPIRE 8336 {
    string obsMode = "Parallel";
    bool isBright = false in [true,false];
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string photVersion = "v00";
    string comVersion = "v00";
    bool debug = false in [true,false];
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Parallel Configuration started");
    SpireMsg(2,"          $Id$");
    //
    // ..... configuration .....
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // Set Mode to Parallel
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_MODE_RAW(0x0500)");
    Spire_SET_OBS_MODE_RAW(0x500);
    //
    // Move BSM to HOLD
    int bsmHoldChopPosn = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",bsmModel,"chop_0_I",bsmVersion,debug);
    int bsmHoldJiggPosn = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",bsmModel,"jigg_0_I",bsmVersion,debug);
    SpireBsmMove(bsmHoldChopPosn,bsmHoldJiggPosn);
    //
    // set biases and phases - if needed
    if(isBright) {
        SpireProc_Set_PhotBright(obsMode,photVersion,debug);
    } else {
        if(photVersion != "v00") {
            SpireProc_Set_PhotMode(obsMode,isBright,photVersion,comVersion,debug);
        }
    }
    //
    // Time synchronisation
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_RESET_DRCU_COUNTERS_RAW()");
    Spire_RESET_DRCU_COUNTERS_RAW();
    //
    // ..... completion .....
    //
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Parallel Configuration ended");
    SpireMsg(1,"  ..Parallel Configuration (" + (time() - t) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_Cal_BsmPcalFlash.txt
//
///////////////////////////////////////////////////////////////////////////
//  
//  CUS script for: 'Phot BSM PCAL Flash' 
//
//  in *basic_fine_pointing* or *no_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/12/12 V0.1: Initial version adapted from 
//                  SPIRE_IST_BSM_PCALFLASH.txt (Sunil email 09/12/08 19:10)
//                  using as template
//                  SpirePhoto_Cal_BsmAngleCal.txt (2008/12/10 V0.5)          
// 2009/02/02 V1.0: Pass debug_print to some low level scripts. 
//                  Add setting of NHK STEP parameter in 
//                  SpireProc_Exec_BsmPcalFlash. Set first STEP
//                  already during SLEW and unset at end during FINAL_HOLD.   
//                  Use new SpireBb_EndObsAll and SpireBb_StartObsAll. 
//                  Read nominal bias frequency and bias divider from new
//                  SpireTable_DetectorSettings.txt. Implemented setting 
//                  of datarates. Replace SpireProc_Set_PhotNominal by
//                  SpireProc_Set_FreqSampAmpPhasNominal. Implemented 
//                  isBright (+!pointing) setting. Move BSM back to home
//                  at end. Introduce limits for VSM input positions. 
//                  Add check to make sure c2>c1. 
// 2009/02/16 V1.1: Replace call to SpireTable_DetectorSettings by call to
//                  SpireTable_PhotModeParams. Update call to 
//                  SpireProc_Exec_BsmPcalFlash with VM table parameters, 
//                  which are now read from a calibration file. 
//                  Use SpireProc_Set_PhotMode to set instrument to PHTSTBY
//                  during SLEW and FINAL_HOLD. Use new setting of 
//                  datarates. 
// 2009/02/18 V1.2: Adapt to change in call to  SpireProc_Exec_BsmPcalFlash
// 2009/03/04 V1.3: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Allow isBright in 
//                  combination with no pointing.
// 2009/05/05 V1.4: Add in move BSM to hold at start. Gather procedures at 
//                  start and end in separate BB. 
// 2009/06/05 V1.5: Hardcode STBY 'v00' in EndBB (SPR-1477)
//
///////////////////////////////////////////////////////////////////////////
//  Script assumes that:
//
//  1)  Instrument is in PHOTSTBY 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Bias frequency (mclkdiv) and sampling rate (biasdiv) are the same 
//  for all three arrays and could be taken from following cal table: 
//  SpireTable_PhotModeParams.txt
//
//  3) Home position of BSM can be read from SpireTable_BsmNominalSettings.txt
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhoto_Cal_BsmPcalFlash {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; //NAIF identifier: put '0' to use RA/DEC, or correct 'NAIFID'
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    bool isBright = false; // Use settings for bright source (==tick)
    string ib = "S14_0"; // Central aperture (defined in SIAM) of raster
    int c_start = 0x1000 in [0x1000,0xf000]; // RAW chop target start position
    int c_end = 0xf000 in [0x1000,0xf000]; // RAW chop target end position
    int c_step = 0x2000; // RAW chop target step in position
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial"; // Model in cal table SpireTable_BsmNominalSettings
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Check user input for chop/jiggle parameters :
    //
    if(c_end < c_start + c_step) {
        error("End chop is smaller than start chop plus 1*step. Try again!");
    }
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = true;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_BsmNominalSettings.txt";
    string tabName04 = "SpireTable_CommandLists.txt";
    //
    // Dummy value for smecHomePosn (needed but not used in phot script!)
    int smecHomePosn = 3500;
    // SMEC home position
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS02";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "PEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Read nominal bias frequency and bias divider:
    //    
    // Select version flag and set GetTableEntry parameters:
    version = version01;
    tabName = tabName01;
    selCol = "mode";
    // Name of column for selecting 
    selVal = obsMode;
    // Value of 'string' selector
    //
    tarCol = "mclkDiv";
    int mclkDiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "biasDiv";
    int biasDiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Calculate nominal sampling rate from mclkdiv and biasdiv:
    //
    double mclkdivHz = 1.0E7 / (512.0 * double(mclkDiv + 1));
    double biasdivHz = 1.0 / (double(biasDiv) + 1.0) * mclkdivHz;
    if(debug) {
        debug_print("Nominal sampling rate is: " + biasdivHz + " [Hz]");
    }
    // //
    // //
    // Read BSM home position: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version03;
    tabName = tabName03;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Set jigg position during test to hold_jigg:
    int jiggPosn = hold_jigg;
    // //
    // //
    // Read VM parameters from calibration table:
    //
    tabName = tabName04;
    selVal = "Flash";
    int vmId = ilookup(tabName,selVal,"Id");
    int vmIndex = ilookup(tabName,selVal,"Index");
    int nParms = ilookup(tabName,selVal,"Nparms");
    //
    // // // // // // // // // // // // // // // // 
    // // // // // // // // // // // // // // // //
    // Calculate timing for the pointing request:
    // 
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartBsmPcalFlash(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug));
    // 
    // BBs carried out when the pointing is reached:
    if(pointing) {
        int tinithold = duration(SpireBb_PhotOffsetAuto(debug));
    } else {
        tinithold = duration(SpireBb_PhotOffsetAuto(debug)) + tslewmin;
    }
    //
    // BB carried out during pointing:
    int tp = duration(SpireProc_Exec_BsmPcalFlash(c_start,c_end,c_step,jiggPosn,mclkDiv,biasDiv,vmId,vmIndex,nParms,fts,debug));
    //
    // BB carried out at the end:
    int tfinalhold = duration(SpireBb_EndBsmPcalFlash(phot,hold_chop,hold_jigg,isBright,version01,version02,debug));
    //
    // Debug_printing?
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                                    */
    // ****************************************************** */
    // //
    // //
    // 
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,naifid,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW (Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartBsmPcalFlash(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation:
                //
                SpireBb_StartBsmPcalFlash(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug);
            }
            // //
            // //
            // Set offsets:
            //
            SpireBb_PhotOffsetAuto(debug);
            //
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            //
            // //
            // //
            // Execute loop of BSM Pcal flashes:
            //
            SpireProc_Exec_BsmPcalFlash(c_start,c_end,c_step,jiggPosn,mclkDiv,biasDiv,vmId,vmIndex,nParms,fts,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            version03 = "v00";
            model = "initial";
            //
            SpireBb_EndBsmPcalFlash(phot,hold_chop,hold_jigg,isBright,version01,version02,debug);
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpirePhoto_Cal_PcalLevelCheck.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  CUS script for: 'Phot PCAL Level Ceck' 
//
//    in *basic_fine_pointing* mode 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/06/10 V0.1: Initial version adapted from 
//                  Mode_ILT_PERF_CPT_P.tcl (v 1.12 2006/03/23 17:14:58)
// 2008/07/04 V0.2: Renumber version
// 2008/08/01 V0.3: Change number of PCAL flash cycles and change flash levels 
// 2008/08/12 V0.4: Remove test number; add additional PCAL level and
//                  check levels with ComP plan; take into account renaming 
//                  of low level script SpireProc_CalcParam_PhotPcalFlash
//                  and calibration table SpireTable_PhotPcalCurrentConvCoef  
// 2008/11/11 V0.5: Allow 'no pointing' as input option; Adapt debug printing
// 2008/11/12 V0.6: Implement mode setting; Add isBright 
// 2009/02/02 V1.0: Add debug_print as input and pass it to some low 
//                  level scripts. Add setting of NHK STEP parameter
//                  in SpireProc_Exec_PcalLevelCheck. Set first STEP
//                  already during SLEW and unset at end during INIT_HOLD.   
//                  Use new SpireBb_EndObsAll and SpireBb_StartObsAll. 
//                  Read nominal bias frequency and bias divider from new
//                  SpireTable_DetectorSettings.txt. Implemented setting 
//                  of datarates. Replace SpireProc_Set_PhotNominal by
//                  SpireProc_Set_FreqSampAmpPhasNominal. Fix bug with
//                  implementation of 'no pointing' option. Implemented 
//                  isBright (+!pointing) setting.
// 2009/02/17 V1.1: Replace call to SpireTable_DetectorSettings by call to
//                  SpireTable_PhotModeParams. New setting of datarates. 
//                  Use SpireBb_PhotSetMode to set to PHOTSTBY during 
//                  SLEW and FINAL_HOLD. Read boresight from 
//                  SpireTable_OpsParms. Read Pcal levels from new calibration 
//                  table. Read VM table parameters now from a cal. table.
// 2009/02/18 V1.2: Adapt to change in call to SpireProc_Exec_PcalLevelCheck.
// 2009/02/19 V1.3: Elevate version05 to input. Fixed bug of not doing 
//                  an Offset during INIT_HOLD.
// 2009/03/04 V1.4: Add isSerendipity, isPcal, and 8 more dummy parameters
//                  to the script for future use. Allow isBright for no
//                  pointing observation. 
// 2009/05/07 V1.5: Add in move BSM to hold at start. Gather procedures at 
//                  start and end in separate BB. 
// 2009/05/11 V1.6: Elevate Pcal flash period and number of cycles to input. 
// 2009/06/05 V1.7: Hardcode STBY 'v00' in EndBB (SPR-1477)
//
///////////////////////////////////////////////////////////////////////////
//
//  Script assumes that:
//
//  1)  Instrument is in PHOTSTBY at beginning 
//  (i.e. bias amplitude, phase, frequency  [mclkdiv,biasdiv] are nominal)
//
//  2) Nominal bias frequency and sampling rate are read from
//     following calibration table: SpireTable_PhotModeParams.txt
//
//  3) PCAL bias calibration coefficients are read from following cal table:
//     SpireTable_PcalCurrentConvCoef.txt
//
//  4) PCAL bias levels are read from following cal table:
//     SpireTable_PcalLevelCheckLevels.txt
//
//  5) Boresight of array are read from following cal table:
//     SpireTable_OpsParms.txt   
//
///////////////////////////////////////////////////////////////////////////
// 
obs SpirePhoto_Cal_PcalLevelCheck {
    /* ****************************************************** */
    /* USER PARAMETER DEFINITION, CUS SIGNATURE for EX-HSpot  */
    /* ****************************************************** */
    /* */
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    bool isBright = false; // Use settings for bright source (==tick)
    bool pointing = true; // Should telescope 'point' (==tick) or do a 'no pointing' (==untick)? 
    /* */
    int period = 4000; // PCAL Flash *FULL* period (high+low bias) [millisec]
    int ncycles = 15; // PCAL Flash Number of cycles
    string version01 = "v00"; // Version in cal table SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    string version03 = "v00"; // Version in cal table SpireTable_PcalLevelCheckLevels
    string version05 = "v00"; // Version in cal table SpireTable_OpsParms.txt
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
    bool isSerendipity = true; // Allow (==tick) serendipity mode to be activated or prohibit (==untick) it (currently not in use)? 
    bool isPcal = true; // Allow (==tick) regular PcalFlash in script or prohibit (==untick) it (currently not in use)?.  
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // //
    // //
    // Declare some variable:
    //
    // Photometer or FTS:
    bool phot = true;
    bool fts = !phot;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string tarCol = "";
    string version = "";
    double scirate = 0.0;
    double chkrate = 0.0;
    double nhkrate = 0.0;
    //
    int obsStep = 0;
    //
    // Hardcoded calibration tables:
    //
    string tabName01 = "SpireTable_PhotModeParams.txt";
    string tabName02 = "SpireTable_CommonModeParams.txt";
    string tabName03 = "SpireTable_PcalLevelCheckLevels.txt";
    string tabName04 = "SpireTable_CommandLists.txt";
    string tabName05 = "SpireTable_OpsParms.txt";
    string tabName06 = "SpireTable_BsmNominalSettings.txt";
    //
    // Currently hardcoded version and model parameter:
    //
    string version06 = "v00";
    // Version in cal table SpireTable_BsmNominalSettings
    string model = "initial";
    // Model in cal table SpireTable_BsmNominalSettings
    //
    // Dummy value for Spec script:
    // (needed but not used in phot script!)
    //
    int smecHomePosn = 3500;
    // SMEC home position
    // //
    // //
    // Setup mode: 
    //
    // Set obsMode for QLA: 
    string obsModeQla = "ENG_CAL_OBS09";
    // Note: this needs entry in MIB table and in SpireTableInstConfigs.txt
    //
    // Set obsMode for datarates:  
    string obsMode = "PEngCalObs";
    // Note: this is currently only a maximum value
    // //
    // //
    // Read BSM home parameters: 
    //
    // Select version flag and set GetTableEntry parameters:
    //
    version = version06;
    tabName = tabName06;
    selCol = "model";
    // Name of column for selecting 
    selVal = model;
    // Value of 'string' selector
    //
    // Read hold position from calibration table:  
    //
    tarCol = "chop_0_I";
    int hold_chop = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "jigg_0_I";
    int hold_jigg = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // ****************************************************** */
    // CALCULATE DURATIONS for POINTING STATES                */
    // ****************************************************** */
    // //
    // //
    // Read nominal bias frequency and bias divider:
    //    
    // Select version flag and set GetTableEntry parameters:
    version = version01;
    tabName = tabName01;
    selCol = "mode";
    // Name of column for selecting 
    selVal = obsMode;
    // Value of 'string' selector
    //
    tarCol = "mclkDiv";
    int mclkdiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    tarCol = "biasDiv";
    int biasdiv = SpireProc_GetTableEntryInt(tabName,selCol,selVal,tarCol,version,debug);
    //
    // Calculate nominal sampling rate from mclkdiv and biasdiv:
    //
    double mclkdivHz = 1.0E7 / (512.0 * double(mclkdiv + 1));
    double biasdivHz = 1.0 / (double(biasdiv) + 1.0) * mclkdivHz;
    if(debug) {
        debug_print("Nominal sampling rate is: " + biasdivHz + " [Hz]");
    }
    //
    // //
    // //
    // Read VM parameters from calibration table:
    //
    tabName = tabName04;
    selVal = "Flash";
    int vmId = ilookup(tabName,selVal,"Id");
    int vmIndex = ilookup(tabName,selVal,"Index");
    int nParms = ilookup(tabName,selVal,"Nparms");
    // //
    // //
    // Initialize PCAL variables with their default values:
    // 
    // PCAL Flash FULL period (high and low bias) in millisec:
    // int period = 4000;
    //
    // Number of cycles: 
    // V0.2: int ncycles = 7;
    // from V0.3 on:
    // int ncycles = 15;
    //
    // --> PCAL setup parameters now in calibration file or input parameters.   
    //
    // DCU data mode (default = PF == 0; SF == 4)
    int ndcumode = 0;
    //
    // SCU sampling rate (f =80Hz/(1+scumode))  
    int scumode = 0;
    // //
    // //
    // Define/retrieve the list of PCAL biases for each of the flashes in mA:
    // 
    double[] low_bias = [0.0];
    // V0.2:
    //double[] high_bias = [1.0,2.0,3.0,4.0,5.0,6.0,7.0];
    // V0.3:
    //double[] high_bias = [0.35,0.7,1.05,1.4,1.75,2.1,2.45,2.8,3.15,3.5,3.85,4.2,4.55,4.9,5.25,5.6,5.95,6.3,6.65,7.0];
    //
    double[] high_bias = [];
    int index = 0;
    tabName = tabName03;
    selCol = "version";
    selVal = version03;
    tarCol = "level";
    string[] searchCol = scolumn(tabName,selCol);
    double[] targetCol = dcolumn(tabName,tarCol);
    int size = table_size(tabName);
    // 
    // Loop through table to find matching entries:
    //
    for(int j = 0 .. size - 1) {
        if(searchCol[j] == selVal) {
            high_bias[index] = targetCol[j];
            index = index + 1;
        }
    }
    //
    // Safety check:
    //
    if(length(high_bias) == 0) {
        error("No PCAL bias level selected! Check version with entries in calibration table SpireTable_PcalLevelCheckLevels.txt");
    }
    // //
    // //
    // Predefine version in SpireTable_PcalCurrentConvCoef.txt:
    //
    string ver_b = "v01";
    if(debug) {
        debug_print("The nominal version in SpireTable_PcalCurrentConvCoef.txt is v01");
    }
    // //
    // //
    // Retrieve PCAL bias calibration coefficients:
    //
    double[] coeff = [0.0];
    coeff[0] = dlookup("SpireTable_PcalCurrentConvCoef.txt",ver_b,"c_0");
    coeff[1] = dlookup("SpireTable_PcalCurrentConvCoef.txt",ver_b,"c_1");
    // //
    // //
    // Calculate RAW PCAL bias values for each of the flashes from mA list:
    //  
    int[] raw_low_bias = [0];
    int[] raw_high_bias = [0];
    for(int i = 0 .. length(high_bias) - 1) {
        raw_low_bias[i] = 0;
        raw_high_bias[i] = iround((high_bias[i] * 0.0010 - coeff[0]) / coeff[1]);
    }
    if(debug) {
        debug_print("High bias levels in mA are: " + high_bias);
        debug_print("Raw high bias levels to check are: " + raw_high_bias);
        debug_print("Raw low bias level to check is: " + raw_low_bias);
    }
    // //
    // //
    // Deduce number of DCU samples, SCU samples and DCU sample delay based on mclkdiv and biasdiv:
    //
    int[] flash_params = SpireProc_CalcParam_PcalFlash(period,mclkdiv,biasdiv,debug);
    int dcusamples = flash_params[0];
    int scusamples = flash_params[1];
    int dcudelay = flash_params[2];
    if(debug) {
        debug_print("//////////////////////////////////////////////////////////////");
        debug_print("");
        debug_print("CALCULATED DCU SAMPLES : " + dcusamples);
        debug_print("CALCULATED SCU SAMPLES : " + scusamples);
        debug_print("CALCULATED  SAMP DELAY : " + dcudelay + "microsec");
        debug_print("");
        debug_print("//////////////////////////////////////////////////////////");
    }
    //
    // // // // // // // // // // // // // // // // 
    // // // // // // // // // // // // // // // //
    //
    // Calculate timing for the pointing request:
    //
    // BBs called during slew:
    int tslewmin = duration(SpireBb_StartPcalLevelCheck(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug));
    // 
    // BBs carried out when the pointing is reached:
    if(pointing) {
        int tinithold = duration(SpireBb_PhotOffsetAuto(debug));
    } else {
        tinithold = duration(SpireBb_PhotOffsetAuto(debug)) + tslewmin;
    }
    //
    // BB carried out during pointing:
    int tp = duration(SpireProc_Exec_PcalLevelCheck(vmId,vmIndex,nParms,raw_low_bias,raw_high_bias,ncycles,period,ndcumode,dcusamples,dcudelay,scumode,scusamples,debug));
    //
    // BB carried out at the end:
    int tfinalhold = duration(SpireBb_EndPcalLevelCheck(phot,isBright,version01,version02,debug));
    // // 
    // // 
    // Debug printing:
    //
    if(debug) {
        debug_print("tslewmin = " + tslewmin);
        debug_print("tinithold = " + tinithold);
        debug_print("tpointing = " + tp);
        debug_print("tfinalhold = " + tfinalhold);
    }
    //
    // ****************************************************** */
    // POINTING MODE DECLARATION                              */
    // ****************************************************** */
    // //
    // // 
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selVal = obsMode;
    tarCol = "Boresight";
    version = version05;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selVal,tarCol,version,debug);
    // //
    // // 
    // Set pointing mode:
    //
    if(pointing) {
        int[] ts = basic_fine_pointing(true,tslewmin,tinithold,tfinalhold,ib,0,ra,dec,0.0,0.0,tp);
    } else {
        ts = no_pointing(true,tinithold,tfinalhold,tp);
    }
    //
    if(debug) {
        debug_print("Output timing vector from the pointing request: " + ts);
    }
    //
}{
    // ****************************************************** */
    // POINTING STATES WITH OBSERVING MODE LOGIC           */
    // ****************************************************** */
    // //
    // //
    // Set datarates: 
    //
    string rateType = "chk";
    chkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    ess_hk_data_rate(chkrate);
    //
    rateType = "nhk";
    //
    nhkrate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    non_ess_hk_data_rate(nhkrate);
    //
    rateType = "sci";
    scirate = SpireProc_CalcParam_PhotDataRates(rateType,obsMode,version01,version02,debug);
    data_rate(scirate);
    //
    if(debug) {
        debug_print("Set CHK datarate to: " + chkrate);
        debug_print("Set NHK datarate to: " + nhkrate);
        debug_print("Set SCI datarate to: " + scirate);
    }
    //
    // Start the state_machine:
    //
    int[] state = [0];
    //
    while(state[0] >= 0) {
        if(debug) {
            debug_print("Current state: " + state);
        }
        state = next_state();
        if(debug) {
            debug_print("Next state: " + state);
        }
        //
        if(state[0] == 1) {
            // STATE = SLEW ( Spacecraft is slewing )
            // //
            // //
            // Startup observation: 
            //
            SpireBb_StartPcalLevelCheck(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug);
            //
            //delay(timeSlewCal);
        }
        if(state[0] == 2) {
            // STATE = INIT_HOLD ( spacecraft is idling at source )
            //
            // //
            // //
            // If no pointing observation do stuff here which is 
            // done nominally during SLEW:  
            //
            if(!pointing) {
                // //
                // //
                // Startup observation:
                //
                SpireBb_StartPcalLevelCheck(phot,obsModeQla,obsMode,isBright,version01,version02,hold_chop,hold_jigg,smecHomePosn,debug);
                //
            }
            // //
            // //
            // Set offsets:
            //
            SpireBb_PhotOffsetAuto(debug);
            // 
            //delay(tinithold);
            //
        }
        if(state[0] == 3) {
            // STATE = POINT ( spacecraft is at nominal RA,DEC (staring, raster) )
            // //
            // //
            // Execute sequence of PCAL flashes:
            //
            SpireProc_Exec_PcalLevelCheck(vmId,vmIndex,nParms,raw_low_bias,raw_high_bias,ncycles,period,ndcumode,dcusamples,dcudelay,scumode,scusamples,debug);
            //
            //delay(tp);
            //
        }
        if(state[0] == 5) {
            // STATE = FINAL_HOLD ( "sky" observation ends, performing final activ.)
            // //
            // //
            // Set scientific datarate back to zero:
            //
            data_rate(0.0);
            // //
            // //
            // Reconfigure at the end (incl. resetting of OBSID and BBIB):
            //
            // Hardcode STBY values for resetting (SPR-1477):
            //
            version01 = "v00";
            version02 = "v00";
            //
            SpireBb_EndPcalLevelCheck(phot,isBright,version01,version02,debug);
            //
        }
        if(state[0] == -1) {
            // STATE = END ( end of the pointing/commanding part of the code )
            //
        }
    }
}

// SpireEngREDYtoSPEC_STBY
//
// $id$
//
// This observation puts the instrument into the SPEC_STBY mode
// 
// The instrument should be in  the REDY mode before execution of this observation
//
//
// 28/04/2009 KJK: first version
// 08/06/2009 KJK: modified to allow input of SCAL status and a version
// 12/07/2009 MP: Changed default stabilisationTime (SCR-SPIRE-1632)
// 13/07/2009 MP: Introduce wait time after SMEC on as input (SCR-SPIRE-1638)
// 20/10/2009 KJK: Set default SMECwait to 0 as we no longer have to initialise the SMEC in this observation
// 06/01/2010 MP: Set default SMECwait to 10 (SCR-SPIRE-2227)
// 09/04/2010 SDS: Changed input for bsmModel from "initial" to "spec" (SCR-SPIRE-2490)
obs SpireEngREDYtoSPEC_STBY {
    int jfet_heater_V = 0; // Default jfet heater voltage at switch on
    string scal = "Default" in ["Default","SCAL2","SCAL4","None"]; // SCAL
    double scalTemp = 5.0 in [5.0,80.0]; // SCAL temperature, if SCAL2 or SCAL4 selected (Kelvin)
    int stabilisationTime = 120; // time (secs) to allow Detectors to stabilise before starting observations
    int smecWait = 10; // Wait time after switch-on of SMEC [s]
    bool sampleDetectors = false; // sample detectors during the stabilisation period
    string bsmModel = "spec";
    string bsmVersion = "v00";
    string smecVersion = "v00";
    string detVersion = "v00";
    string vssVersion = "v00";
    string scalVersion = "v00";
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    int t = duration(SpireBbStartObs()) + duration(SpireREDYtoSPEC_STBY(jfet_heater_V,scal,scalTemp,stabilisationTime,smecWait,sampleDetectors,bsmModel,bsmVersion,smecVersion,detVersion,vssVersion,scalVersion,debug)) + duration(SpireBbEndObs());
    int[] ts = no_pointing(true,0,0,t);
}{
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 3) {
            SpireBbStartObs();
            SpireREDYtoSPEC_STBY(jfet_heater_V,scal,scalTemp,stabilisationTime,smecWait,sampleDetectors,bsmModel,bsmVersion,smecVersion,detVersion,vssVersion,scalVersion,debug);
            SpireBbEndObs();
        }
    }
}

// SpirePhotoSmall  
//
// $Id:$
//
// Implementation of a n-point Jiggle map observation with nodding
//
// Assumptions:
//    1. the instrument is in the PHOT_STBY configuration on entry
//    2. nodding is used
//
// This mode is based on a partial jiggle map operation (nominally 16 point out of 64 for the complete map), 
// which is executed at each nod position.
// A set of two nod positions constitutes a nod cycle, which may be repeated.
// The minimum observation consists of executing this set for each partial jiggle map
// This may be repeated more than once to build up the required signal to noise ratio 
//
// 04 November 2008: added data_rate commands
// 10/02/2009 KJK: added new parameters to SpirePOF3Pointing, SpirePOF3Config, SpirePOF3End
// 10/03/2009 KJK: 
//         SCR 1274, add additional dummy parameters 
//         Update input API to include versions for all cal tables
// 11/05/2009 KJK:
//         Updated to use new calibration Tables: SpireTable_OpsParms.txt  and SpireTable_SpireParams.txt
//  03/07/2009  KJK:
//         Added configuration input parameters to pass to SpirePOF3Config, SpirePOF3Pointing and SpirePOF3End
//  05/07/2009 KJK:
//         SPR-1593 - Updated calls to SpirePOF3Pointing and SpireBbPcalFlash to use flashVersion 
//  22/07/2009 SDS:
//         SCR-1670 - Added option to load new JM64 table which has +/- 126 arcseconds chop throw
//
//  27/07/2009 SDS:
//         Change the default value of the boolean pBool1 from true to false (Load 64-Point Jiggle Map Table?)
//  28/07/2009 SDS:
//         Added chopVersion parameter to SpireBbPOF3end to be able to set the Chop PID parameters back to their 
//         nominal values  
//  10/08/2009 KJK:
//         SPR-1709:  Added new input parameter, comVersion to call to SpreBbPOF3Config
//  12/08/2009 KJK:
//         Spire-1804: Changed calls to SpireBbJiggle to use versions
//                            Changed call to SpirePOF3Pointing to use versions
//                            Changed name of version used to select parameters from BSMNominalSetting table  from 
//                            chopVersion to bsmVersion, in line with other scripts
//   14/08/2009 KJK:
//         Spire-1759: Now load new jigglemap in separate BB
//  25-Aug-2009 KJK:
//        SPR Spire-1641: Needed new input parameter bsmModel
//  10-Sep-2009 KJK:
//        SCR Spire-1943: Needed new input parameter detVersion
//  16-Feb-2010 KJK:
//       SCR Spire-648: added call to SpireBb_BsmMove2Hold before each PCAL flash, except the initial
//
{int,int,int,int} obs SpirePhotoSmall {
    double ra = 0.0 in [0.0,360.0]; // RA of target
    double dec = 0.0 in [-90.0,90.0]; // DEC of target
    int naifid = 0; // NAIF identifier
    string source = "small" in ["point","small","large"]; // source type
    bool choppingAvoidOn = false; // is chopping avoidance selected 
    int choppingAvoidNumber = 0 in [0,3]; // the number of chopping avoid angles selected 
    double choppingAvoidFrom1 = 0.0 in [0.0,360.0];
    double choppingAvoidTo1 = 0.0 in [0.0,360.0];
    double choppingAvoidFrom2 = 0.0 in [0.0,360.0];
    double choppingAvoidTo2 = 0.0 in [0.0,360.0];
    double choppingAvoidFrom3 = 0.0 in [0.0,360.0];
    double choppingAvoidTo3 = 0.0 in [0.0,360.0];
    int nRepetitions = 1 in [1,300]; // number of map repeats
    double sourceFluxPSW = -1.0;
    double sourceFluxPMW = -1.0;
    double sourceFluxPLW = -1.0;
    double sourceBrightPSW = -1.0;
    double sourceBrightPMW = -1.0;
    double sourceBrightPLW = -1.0;
    bool isBright = false; // Use settings for bright source (==tick)
    int nMaps = 1; // total number of number of jiggle maps to perform
    int nCycles = 1; // number of nod cycles per map
    int nNodInts = 1; // number of times to repeat NJigg jiggles at each nod position  
    int nCal = 99999; // number of nod cycles per Gyro calibration 
    int nFlash = 999999; // number of nod cycles per PCAL flash
    string bsmModel = "initial";
    string bsmVersion = "v00"; // Version in cal table SpireTable_BsmNominalSettings.txt
    string detVersion = "v00"; // Version in cal table SpireTable_DefaultParams.txt
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParms
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    string flashVersion = "v00"; // Version in cal table SpireTable_FlashParms
    string chopVersion = "v00"; // Version in cal table SpireTable_ChopParams
    string photVersion = "v00"; // Version in cal table SpireTable_PhotModeParams.txt
    string comVersion = "v00"; // Version in cal table SpireTable_CommonModeParams.txt
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Load 64-Point Jiggle Map Table?
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // *****************
    // check user inputs
    // *****************
    if(source != "small") {
        error("SpirePhotoSmall: Source is not small");
    }
    // *****************
    // set constants
    // *****************
    string obsMode = "POF3";
    bool isPhot = true;
    // is a photometer observation
    double yOffset = 0.0;
    //  offset to observation position from target in Y direction (arcsecs)
    double zOffset = 0.0;
    // offset to observation position from target in Z direction (arcsecs)
    //
    // *****************************************
    //      set up telescope pointing mode    
    // *****************************************
    //
    // ***** operating mode parameters *****
    string ib = SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode",obsMode,"Boresight",opsVersion,debug);
    // instrument boresight
    double deltaY = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"DeltaY",opsVersion,debug);
    // offset to pixel centre from boresight in Y direction (arcsecs)
    double deltaZ = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"DeltaZ",opsVersion,debug);
    // offset to pixel centre from boresight in Z direction (arcsecs)
    bool fixed = SpireProc_GetTableEntryBool("SpireTable_OpsParms.txt","mode",obsMode,"Fixed",opsVersion,debug);
    // pattern angle definition
    double pattNod = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"Patt",opsVersion,debug);
    // direction of nod 
    double chopThrow = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"D1",opsVersion,debug);
    // nod separation   
    int jiggleTable = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"TableId",opsVersion,debug);
    // Jiggle Table ID  
    int jiggleSize = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"TableSize",opsVersion,debug);
    // Jiggle Table length 
    int nChops = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NChops",opsVersion,debug);
    // number of chop cycles per jiggle position  
    int nJiggs = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NJiggs",opsVersion,debug);
    // number of jiggle positions per nod position  
    int nNodPosns = SpireProc_GetTableEntryInt("SpireTable_OpsParms.txt","mode",obsMode,"NNodPosns",opsVersion,debug);
    // number of nod positions in a nod cycle      
    bool initFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"InitFlash",spireVersion,debug);
    // initial flash flag
    bool endFlash = SpireProc_GetTableEntryBool("SpireTable_SpireParams.txt","mode",obsMode,"EndFlash",spireVersion,debug);
    // final flash flag
    double cycTime = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"SrcTime",opsVersion,debug);
    // effective on source integration time per complete map
    //
    // ***** pointing mode timing parameters *****
    //
    {int,int,int,int,int,int,int} pof3Point = SpirePOF3Pointing(nMaps,nCycles,nNodInts,nCal,nFlash,isBright,bsmModel,bsmVersion,detVersion,spireVersion,opsVersion,flashVersion,chopVersion,photVersion,comVersion,debug,pBool1);
    int tSlewMin = pof3Point{0};
    int tInitHold = pof3Point{1};
    int tFinalHold = pof3Point{2};
    int nMoves = pof3Point{3};
    int tp = pof3Point{4};
    int tHold = pof3Point{5};
    int nHold = pof3Point{6};
    //
    // ***** fetch timing information *****
    //
    int tFlash = duration(SpireBbPcalFlash("PFlash",flashVersion,0,debug));
    // time for a PCAL flash
    int tSerendipity = duration(SpireBbPhotSerendipity("POF3",0));
    // minimum time for a serendipity observation
    //
    // ****** execute telescope pointing mode ******
    //
    int[] ts = nodding_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,fixed,pattNod,yOffset + deltaY,zOffset + deltaZ,nMaps * nCycles * nNodPosns / 2,chopThrow,tp,tp,0,0,tHold,nHold,false);
    //
}{
    // *****************************************
    //   Display input parameters
    // *****************************************
    SpireMsg(3,"     POF3 Input values:");
    SpireMsg(3,"     ..RA: " + ra);
    SpireMsg(3,"     ..Dec: " + dec);
    SpireMsg(3,"     ..NAIF ID: " + naifid);
    SpireMsg(3,"     ..Y Offset: " + yOffset);
    SpireMsg(3,"     ..Z Offset: " + zOffset);
    SpireMsg(3,"     ..No of Map Repeats: " + nMaps);
    SpireMsg(3,"     ..No of Nod Cycles per Map: " + nCycles);
    SpireMsg(3,"     ..No of Ints per Nod Posn: " + nNodInts);
    // SpireMsg(3,"     ..No of  Nod Cycles between Gyro Calibrations: " + nCal);
    SpireMsg(3,"     ..No of  Nod Cycles between Flashes: " + nFlash);
    SpireMsg(3,"     POF3 Fixed values:");
    SpireMsg(3,"     ..ib: " + ib);
    SpireMsg(3,"     ..deltaY: " + deltaY);
    SpireMsg(3,"     ..deltaZ: " + deltaZ);
    SpireMsg(3,"     ..fixed: " + fixed);
    SpireMsg(3,"     ..pattNod: " + pattNod);
    SpireMsg(3,"     ..chopThrow: " + chopThrow);
    SpireMsg(3,"     ..jiggleTable: " + jiggleTable);
    SpireMsg(3,"     ..jiggleSize: " + jiggleSize);
    SpireMsg(3,"     ..nChops: " + nChops);
    SpireMsg(3,"     ..nJiggs: " + nJiggs);
    SpireMsg(3,"     ..nNodInts: " + nNodInts);
    SpireMsg(3,"     ..nNodPosns: " + nNodPosns);
    SpireMsg(3,"     ..initFlash: " + initFlash);
    SpireMsg(3,"     ..endFlash: " + endFlash);
    SpireMsg(3,"    Composite Nodding Pointing Mode Input values:");
    SpireMsg(3,"    ..tSlewMin: " + tSlewMin);
    SpireMsg(3,"    ..tInitHold: " + tInitHold);
    SpireMsg(3,"    ..tFInalHold: " + tFinalHold);
    SpireMsg(3,"    ..tp: " + tp);
    SpireMsg(3,"    ..tHold: " + tHold);
    SpireMsg(3,"    ..nHold: " + nHold);
    SpireMsg(3,"    Composite Nodding Pointing Mode Output values:");
    SpireMsg(3,"    ..tobs: " + ts[0]);
    SpireMsg(3,"    ..tslew: " + ts[1]);
    SpireMsg(3,"    ..tnod: " + ts[2]);
    SpireMsg(3,"    ..tss: " + ts[3]);
    SpireMsg(3,"    ..tload: " + ts[4]);
    SpireMsg(3,"    ..tend: " + ts[5]);
    // *****************************************
    //   execute observation
    // *****************************************
    SpireMsg(0,"Observation Start");
    SpireMsg(0,"  Uses observing mode POF3 (n-point Jiggle Map)");
    SpireMsg(3,"       $Id:$");
    data_rate(0.0);
    double chkrate = dlookup("Datarates.txt","POF3","CHK");
    ess_hk_data_rate(chkrate);
    double nhkrate = dlookup("Datarates.txt","POF3","NHK");
    non_ess_hk_data_rate(nhkrate);
    //
    //??p pointing file generation ------------------------------
    double pos = 90.0;
    //??p double[] rdp0 = PtOffset([ra,dec,pos],zOffset,yOffset,0.0,false);
    //??p pointing file generation ------------------------------
    //
    int tslew = ts[1];
    // slew time
    string tstr = "";
    // time string
    bool holdFlag = false;
    // true when holding at nod position
    int otf = 0x8000;
    // On Target Flag
    int nf = 0x4000;
    // Nod Flag
    int step = 0x0;
    // value of STEP parameter
    double srcTime = 0.0;
    //  total on source integration time
    int np = 0;
    // pointing counter
    int npart = 0;
    double s = 0.0;
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // ***********************  SLEWING
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Slewing to start position");
            // set up observation parameters
            SpireBb_StartObsAll(obsMode);
            // perform serendipity operation if possible
            if(tslew > tSerendipity + tSlewMin) {
                SpireBbPhotSerendipity(obsMode,tslew - tSlewMin - 2);
            }
            // configure instrument for operations
            if(pBool1) {
                SpireBb_LoadTableJM64b();
            }
            SpireBbPOF3Config(obsMode,isBright,bsmVersion,photVersion,comVersion,debug);
        }
        if(state[0] == 2) {
            // ***********************  INITIAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Initialising Instrument");
            // initialise instrument
            SpireBbPOF3Init();
            // calibrate if necessary
            if(initFlash || nFlash < nCycles) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireBbPcalFlash("PFlash",flashVersion,otf,debug);
            }
        }
        if(state[0] == 5) {
            // ***********************  FINAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Reconfiguring Instrument");
            // calibrate if necessary
            if(endFlash || nFlash < nCycles) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireBb_BsmMove2Hold(bsmModel,bsmVersion,debug);
                SpireBbPcalFlash("PFlash",flashVersion,otf | np,debug);
            }
            // reconfigure back to PHOT_STBY configuration
            SpireBbPOF3End("PHTSTBY",isBright,bsmModel,bsmVersion,detVersion,photVersion,comVersion,debug);
            SpireBb_EndObsAll(isPhot);
        }
        if(state[0] == 6) {
            // ***********************  HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
            SpireBb_BsmMove2Hold(bsmModel,bsmVersion,debug);
            SpireBbPcalFlash("PFlash",flashVersion,otf | np,debug);
        }
        if(state[0] == 3) {
            // ***********************  POINTING
            //??p pointing file generation ------------------------------
            //??p PtOutput(rdp0);
            //??p pointing file generation ------------------------------
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Instrument at Pointing Position");
            SpireMsg(2,"    " + tstr + " Start Jiggles " + np);
            step = otf;
            npart = np / nNodPosns % (jiggleSize / nJiggs);
            s = SpireBbJiggle("POF3",jiggleTable,npart * nJiggs,nJiggs,nNodInts,step,opsVersion,chopVersion,debug);
            srcTime = srcTime + s;
            np = np + 1;
            step = 0;
            SpireBbMove(step);
        }
        if(state[0] == 7) {
            // ***********************  NOD
            //??p pointing file generation ------------------------------
            //??p PtNod(rdp0,patt,d1,patt,false,false);
            //??p pointing file generation ------------------------------
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Instrument at Nod Position");
            SpireMsg(2,"    " + tstr + " Start Jiggles " + np);
            step = nf | otf;
            npart = np / nNodPosns % (jiggleSize / nJiggs);
            s = SpireBbJiggle("POF3",jiggleTable,npart * nJiggs,nJiggs,nNodInts,step,opsVersion,chopVersion,debug);
            srcTime = srcTime + s;
            np = np + 1;
            step = 0;
            SpireBbMove(step);
        }
        if(state[0] == 9) {
            // ***********************  LOAD
        }
    }
    assert (time() == ts[0] + ts[1]);
    //
    // finish observation
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + " Instrument Reconfigured");
    //
    //
    SpireMsg(0,"Observation Completed  (" + time() + " seconds)");
    SpireMsg(0,"Note: Total time (s) = Observation Completed time - slew time + Observatory Overheads");

    return {nMaps,iround(cycTime),iround(srcTime),time() - iround(srcTime) - tslew};
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SetVmTable.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to update POF2-like VM positions tables
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/05/01 V0.1: Initial version, adapted from tem,plate 
//                  SpireBb_StartDcuData (2009/06/05 V1.1) 
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SetVmTable SPIRE 14079 {
    int itableID = 0x37; // Table ID to be uploaded 
    string version = "v01"; // Version in calibration file
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SetVmTable started");
    SpireMsg(2,"          $Id:$");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Start DCU data:
    //
    SpireProc_Set_VmTable(itableID,version);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SetVmTable ended");
    SpireMsg(1,"  ..StartDcuData End (" + (time() - t) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_CalcParam_PhotPhaseUp.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to calculate the parameters needed for a Phot Phase Up.  
//  It creates and returns a list of raw phases to be stepped through,
// 
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/05/02 V0.1: Initial version adapted from
//                  Mode_ILT_PERF_DPH_P.txt (v1.4 2008/01/31 20:24:33)
// 2008/07/03 V0.2: Renumber version; add new limits for step_size
//
///////////////////////////////////////////////////////////////////////////
//
int[] procedure SpireProc_CalcParam_PhotPhaseUp {
    double target_phase = 0.0 in [0.0,360.0]; // Central phase shift (target phase) [degree]
    int number_steps = 1 in [1,127]; // Number of steps to one side [int]
    int step_size = 1 in [1,20]; // Raw step size (1 step==1.411 degrees) [dec(HEX)]
}{
    // //
    // //
    // Calculate total number of steps:
    //
    int n_steps = 2 * number_steps + 1;
    debug_print("Numbers of steps requested: " + n_steps);
    //
    // //
    // //
    // Get the central point of the list in raw units:
    //
    int raw_target_phase = iround(target_phase * 255.0 / 360.0);
    debug_print("The requested phase is: " + target_phase);
    debug_print("The associated raw value is: " + raw_target_phase);
    //
    // //
    // //
    // Get the starting point of the list in raw units:
    //
    int raw_start_phase = raw_target_phase - number_steps * step_size;
    debug_print("the raw phase @start is :" + raw_start_phase);
    //
    // //
    // //
    // Create list of phases:
    //
    int[] raw_phase_list = [0];
    double[] phase_list = [0.0];
    double low_limit = 0.0;
    double high_limit = 360.0;
    double resol = 360.0 / 255.0;
    double k = 0.0;
    //
    for(int i = 0 .. n_steps - 1) {
        raw_phase_list[i] = raw_start_phase + step_size * i;
        phase_list[i] = double(raw_phase_list[i]) * resol;
        debug_print("the phase for step " + i + " is: " + phase_list[i]);
        // //
        // //
        // Check if phase is 0 <= phase <= 2*pi:
        //
        if(phase_list[i] < low_limit) {
            k = 1.0;
        } else {
            if(phase_list[i] > high_limit) {
                k = -1.0;
            } else {
                k = 0.0;
            }
        }
        debug_print("The value of k for step" + " " + i + " " + "  is :" + k);
        //
        // Adapt raw phase list if outside 0 <= phase <= 2*pi:
        //
        raw_phase_list[i] = iround((phase_list[i] + k * 360.0) * (255.0 / 360.0));
    }
    //
    debug_print("Final raw phase list: " + raw_phase_list);
    debug_print("Imput phase list in [deg]: " + phase_list);

    return raw_phase_list;
}

// SpirePhotoSmallLogic
//
// $id$
//
// This procedure selects the SPIRE observing mode and calculates its instrument parameters  
//  for small map observations
//
// This type of observation is executed using  the POF10  observing mode
//
//  25/01/10:  v2.0:  Mdification to use scan map for small maps
//                             see SCR Spire-2173
//  15/02/2010 KJK: SCR Spire-1887:
//                             Added spireVersion to input parameters for call to SpirePOF5Observing
//
////////////////////////////////////////////////////////////////////////////
{{string,double,double,double,double,bool,double,double,double}[],bool,int,int,int,int,int,int,int,int,int,int,int} obs SpirePhotoSmallLogic {
    double ra = 0.0 in [0.0,360.0]; // RA of Target
    double dec = 0.0 in [-90.0,90.0]; // DEC of Target
    int naifid = 0; // NAIF identifier
    string source = "small" in ["point","small","large"]; // source type
    string scanDirection = "scanab" in ["scana","scanb","scanab"];
    double mapOffsetY = 0.0 in [-300.0,300.0]; // offset to observation position from target in Y direction (arcmins)
    double mapOffsetZ = 0.0 in [-300.0,300.0]; // offset to observation position from target in Z direction (arcmins)
    string mapScanRate = "nominal" in ["nominal","fast"]; // selected scan rate
    bool mapOrientationArray = true; // is the map orientation an array (rather than array with constraints)
    double mapOrientationConFrom = 0.0 in [0.0,360.0];
    double mapOrientationConTo = 360.0 in [0.0,360.0];
    int nRepetitions = 1 in [1,100]; // number of repeats of a map sequence (nominal + orthoganal scans)
    double sourceFluxPSW = -1.0;
    double sourceFluxPMW = -1.0;
    double sourceFluxPLW = -1.0;
    double sourceBrightPSW = -1.0;
    double sourceBrightPMW = -1.0;
    double sourceBrightPLW = -1.0;
    bool isBright = false;
    string bsmModel = "initial";
    string bsmVersion = "v00"; // Version in cal table SpireTable_BsmNominalSettings.txt
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParams
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    string flashVersion = "v00"; // Version in cal table SpireTable_FlashParms
    string photVersion = "v00"; // Version in cal table SpireTable_PhotModeParams.txt
    string comVersion = "v00"; // Version in cal table SpireTable_CommonModeParams.txt
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    // check inputs
    if(source != "small") {
        error("SpirePhotoSmallLogic: Source is not a small map");
    }
    SpireMsg(0,"Photometric Small Map Observation");
    // //
    // //
    // Declare some variables:
    //
    double mapSize1 = 0.0;
    double mapSize2 = 0.0;
    int nRasters = nRepetitions;
    int nPoints = 1;
    int nMaps = 1;
    int nCycles = 1;
    int nNodInts = 1;
    int nLines = 1;
    int nCal = 99999;
    int nFlash = 99999;
    int nLinesx = 1;
    int nCalx = 99999;
    int nFlashx = 99999;
    //
    string tabName = "";
    string selCol = "";
    string selVal = "";
    string selValN = "";
    string selValO = "";
    string tarCol = "";
    string version = "";
    double patt = 0.0;
    //
    // Hardcoded calibration tables:
    //
    string tabName05 = "SpireTable_OpsParms.txt";
    //
    //
    // *************************************************************
    //  calculate parameters for POF10 observation
    // *************************************************************
    SpireMsg(1,"  POF10 (Non-chopped Scan Map) mode parameters");
    //
    string obsMode = "POF10";
    if(mapScanRate == "fast") {
        obsMode = obsMode + "_F";
    } else {
        obsMode = obsMode + "_S";
    }
    string obsModeN = obsMode + "_N";
    string obsModeO = obsMode + "_O";
    if(debug) {
        debug_print("Selected obsMode: " + obsModeN + "/" + obsModeO);
    }
    // //
    // //
    // Select scan angle from calibration table:
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "Patt";
    version = opsVersion;
    //
    // Selection depending on direction of scan:
    // 
    if(scanDirection == "scana") {
        patt = SpireProc_GetTableEntryDouble(tabName,selCol,selValN,tarCol,version,debug);
    }
    if(scanDirection == "scanb") {
        patt = SpireProc_GetTableEntryDouble(tabName,selCol,selValO,tarCol,version,debug);
    }
    if(scanDirection == "scanab") {
        patt = SpireProc_GetTableEntryDouble(tabName,selCol,selValN,tarCol,version,debug);
    }
    // //
    // //
    // Select number of map repetitions (nMaps) from calibration table:
    // (incl. calculation of pof10Obs parameters)
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "NMaps";
    version = opsVersion;
    //
    // Selection depending on direction of scan:
    //  
    {double,double,int,int,int,int} pof10Obs = {0.0,0.0,0,0,0,0};
    if(scanDirection == "scana") {
        nMaps = SpireProc_GetTableEntryInt(tabName,selCol,selValN,tarCol,version,debug);
        pof10Obs = SpirePOF5Observing(obsModeN,nRepetitions * nMaps,mapSize1,mapSize2,opsVersion,spireVersion,debug);
    }
    if(scanDirection == "scanb") {
        nMaps = SpireProc_GetTableEntryInt(tabName,selCol,selValO,tarCol,version,debug);
        pof10Obs = SpirePOF5Observing(obsModeO,nRepetitions * nMaps,mapSize1,mapSize2,opsVersion,spireVersion,debug);
    }
    if(scanDirection == "scanab") {
        if(debug) {
            debug_print("nMaps/scanab path:");
            debug_print("tabName: " + tabName);
            debug_print("selCols: " + selCol);
            debug_print("selValN: " + selValN);
            debug_print("selValN: " + selValN);
            debug_print("tarCol: " + tarCol);
            debug_print("version: " + version);
        }
        nMaps = SpireProc_GetTableEntryInt(tabName,selCol,selValN,tarCol,version,debug);
        pof10Obs = SpirePOF5Observing(obsModeN,nMaps,mapSize1,mapSize2,opsVersion,spireVersion,debug);
    }
    double mapOsit = pof10Obs{0};
    double d1 = pof10Obs{1};
    int nRepeats = pof10Obs{2};
    nLines = pof10Obs{3};
    nCal = pof10Obs{4};
    nFlash = pof10Obs{5};
    //
    // //
    // //
    // Calculate further pointing mode input parameters:
    //
    {int,int,int,int,int,double,double} pof10Point = {0,0,0,0,0,0.0,0.0};
    if(scanDirection == "scanb") {
        pof10Point = SpirePOF5Pointing(obsModeO,nRepeats,nLines,nCal,nFlash,isBright,bsmModel,bsmVersion,spireVersion,flashVersion,photVersion,comVersion,opsVersion,debug);
    } else {
        pof10Point = SpirePOF5Pointing(obsModeN,nRepeats,nLines,nCal,nFlash,isBright,bsmModel,bsmVersion,spireVersion,flashVersion,photVersion,comVersion,opsVersion,debug);
    }
    int tSlewMin = pof10Point{0};
    int tInitHold = pof10Point{1};
    int tFinalHold = pof10Point{2};
    int tHold = pof10Point{3};
    int nHold = pof10Point{4};
    double d2 = pof10Point{5};
    double rate = pof10Point{6};
    // //
    // //
    // Calculate further cross scan parameters:
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "NMaps";
    version = opsVersion;
    //
    if(scanDirection == "scanab") {
        if(debug) {
            debug_print("x calculation");
        }
        nMaps = SpireProc_GetTableEntryInt(tabName,selCol,selValO,tarCol,version,debug);
        double mapOsitx = 0.0;
        // observing mode parameters
        {double,double,int,int,int,int} pof10Obsx = {0.0,0.0,0,0,0,0};
        pof10Obsx = SpirePOF5Observing(obsModeO,nMaps,mapSize2,mapSize1,opsVersion,spireVersion,debug);
        mapOsitx = pof10Obsx{0};
        double d1x = pof10Obsx{1};
        int nRepeatsx = pof10Obsx{2};
        nLinesx = pof10Obsx{3};
        nCalx = pof10Obsx{4};
        nFlashx = pof10Obsx{5};
        //
        // pointing mode input parameters:
        {int,int,int,int,int,double,double} pof10Pointx = {0,0,0,0,0,0.0,0.0};
        pof10Pointx = SpirePOF5Pointing(obsModeO,nRepeatsx,nLinesx,nCalx,nFlashx,isBright,bsmModel,bsmVersion,spireVersion,flashVersion,photVersion,comVersion,opsVersion,debug);
        int nHoldx = pof10Pointx{4};
        double d2x = pof10Pointx{5};
        //
        // Lookup direction of cross scan:
        //
        tabName = tabName05;
        selCol = "mode";
        selValN = obsModeN;
        selValO = obsModeO;
        tarCol = "Patt";
        version = opsVersion;
        double pattx = SpireProc_GetTableEntryDouble(tabName,selCol,selValO,tarCol,version,debug);
    }
    // //
    // //
    // Calculate further pointing mode pointing parameters:
    //
    // Lookup boresight:
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "Boresight";
    version = opsVersion;
    string ib = SpireProc_GetTableEntryString(tabName,selCol,selValN,tarCol,version,debug);
    //
    // Lookup offset to pixel centre from boresight in Y direction (arcsecs):
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "DeltaY";
    version = opsVersion;
    double deltaY = SpireProc_GetTableEntryDouble(tabName,selCol,selValN,tarCol,version,debug);
    //
    // Lookup offset to pixel centre from boresight in Z direction (arcsecs)
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "DeltaZ";
    version = opsVersion;
    double deltaZ = SpireProc_GetTableEntryDouble(tabName,selCol,selValN,tarCol,version,debug);
    //
    // Lookup pattern angle definition:
    //
    tabName = tabName05;
    selCol = "mode";
    selValN = obsModeN;
    selValO = obsModeO;
    tarCol = "Fixed";
    version = opsVersion;
    bool fixed = SpireProc_GetTableEntryBool(tabName,selCol,selValN,tarCol,version,debug);
    // //
    // //
    // Calculate further offsets:
    //
    // offset to observation position from target in Y direction (arcsecs):
    //
    double yOffset = mapOffsetY * 60.0 + deltaY;
    //
    // offset to observation position from target in Z direction (arcsecs):
    //
    double zOffset = mapOffsetZ * 60.0 + deltaZ;
    //
    //
    int[] ts = [];
    if(scanDirection == "scanab") {
        // correct nHold and nFlash
        if(nFlash < nLines) {
            int nFlashes = nLines / nFlash;
            nHold = nLines / (nFlashes + 1);
            nFlash = nHold;
        }
        ts = cross_scan_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,fixed,patt,yOffset,zOffset,nLines,d1,d2,rate,tHold,nHold,nRepetitions,nMaps,pattx,nLinesx,d1x,d2x,nHoldx);
    } else {
        ts = line_scan_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,fixed,patt,yOffset,zOffset,nLines,d1,d2,rate,tHold,nHold,nRepeats);
    }
    //
    // ***** choose observing mode *****
    //
    bool isRasterMap = false;
    SpireMsg(1,"  Using POF10 (Scan Map) Observing Mode");
}{
    // *******************************
    // return instrument parameters
    // *******************************
    //
    {string,double,double,double,double,bool,double,double,double}[] estimates = [];
    //
    if(isRasterMap) {
    } else {
        double tau = double(nRepetitions);
        estimates = SpirePOF5Estimate(obsMode + "_" + scanDirection,tau,rate,sourceFluxPSW,sourceFluxPMW,sourceFluxPLW,sourceBrightPSW,sourceBrightPMW,sourceBrightPLW,isBright);
    }
    //
    SpireMsg(3,"     Spire Photometry Large Map Mode parameters:");
    SpireMsg(3,"     ..estimates: " + estimates);
    SpireMsg(3,"     ..isRasterMap: " + isRasterMap);
    SpireMsg(3,"     ..nRasters: " + nRasters + "(# map repeats)");
    SpireMsg(3,"     ..nPoints: " + nPoints);
    SpireMsg(3,"     ..nMaps: " + nMaps);
    SpireMsg(3,"     ..nCycles: " + nCycles);
    SpireMsg(3,"     ..nNodInts: " + nNodInts);
    SpireMsg(3,"     ..nLines: " + nLines);
    SpireMsg(3,"     ..nCal: " + nCal);
    SpireMsg(3,"     ..nFlash: " + nFlash);
    SpireMsg(3,"     ..nLinesx: " + nLinesx);
    SpireMsg(3,"     ..nCalx: " + nCalx);
    SpireMsg(3,"     ..nFlashx: " + nFlashx);
    //

    return {estimates,isRasterMap,nRasters,nPoints,nMaps,nCycles,nNodInts,nLines,nCal,nFlash,nLinesx,nCalx,nFlashx};
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartObsAll.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure observation at the start of all AOTs
// (i.e. astronomer, engineering, and calibration ones). 
//
// It sets the OBSIDs for the current observation, sets the BB, 
// resets the DRCU counter, and sets the MODE. This script includes 
// HSPOT messages. 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/01/26 V1.0: Merged BB using SpireBb_StartupObs (2008/11/12 V0.2) and
//                  SpireBbObsConfig(22 Oct 2007). This will also replace 
//                  part of the ObsConfig stuff done currently in 
//                  SpireBbPOF2Config (v 1.3 2007/08/02)
//                  SpireBbPOF3Config (v 1.3 2007/08/02)
//                  SpireBbPOF5Config (v 1.3 2007/08/02)
//                  Script includes a delay to allow busconfig setting 
//                  befor ethe first command (SCR-1167).
// 2009/01/30 V1.1: Changed entries in messages related to 'RAW' and added
//                  SCR number to header. Replaced final delay(1) with sync().
// 2009/05/05 V1.2: Move commands into low level procedure 
//                  SpireProc_Set_StartObsAll which will be called here. 
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartObsAll SPIRE 14024 {
    string obsmode = "ENG_CAL_OBS"; // Parameter to specify the configuration mode
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string: 
    string hstr = "";
    // 
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartObsAll started");
    SpireMsg(2,"          $Id: $");
    hstr = SpireHexStr($BBID,8);
    SpireMsg(3,"          BBID = " + hstr);
    SpireMsg(3,"          MODE = " + obsmode);
    //
    // Wait for busconfig to be performed:
    delay(1);
    // //
    // //
    // Start observation:
    //
    SpireProc_Set_StartObsAll(obsmode);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartObsAll ended");
    SpireMsg(1,"  ..Observation Configuration (" + (time() - t) + " secs)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBbSetBsmSampling.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// The Building Block sets the BSM sampling  for any operating mode
//
//
///////////////////////////////////////////////////////////////////////////
//
// 28/04/2009 KJK: First Version
// 07/05/2009 KJK: Now only set sampling parameters if the data is to be 
//                 generated (these values are not available for REDY mode)
// 03/07/2009 MP: Set bsmFrameRate and mcuFrameNumber to fix SPR-SPIRE-1588
// 03/09/2009 KJK: Setup to work for any operating mode to fix SPR-1763 
//                 (Problem1)
// 04/09/2009 MP: Move commands to procedure SpireProcSetBsmSampling 
//                and call this here. 
// 
///////////////////////////////////////////////////////////////////////////
//
double block SpireBbSetBsmSampling SPIRE 1601 {
    string opsMode = "PHTSTBY";
    string bsmVersion = "v00";
    bool debug = false; // Allow debug_print statements 
}{
    // 
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    double bsmDataRate = 0.0;
    //
    // Start BB:
    //
    message("4    " + time() + ": SpireBbSetBsmSampling started");
    message("4          $Id: $");
    // //
    // //
    // Set the  BBID
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    delay(1);
    // //
    // //
    // Call procedure:
    //
    bsmDataRate = SpireProcSetBsmSampling(opsMode,bsmVersion,false);
    //
    // End BB:
    //
    SpireMsg(4,"    " + time() + ": BB SpireBbSetBsmSampling ended");

    return bsmDataRate;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartBsmPcalFlash.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpirePhoto/Spectro_Cal_BsmPcalFlash.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V0.1: Initial version adapted from
//                  SpireBb_StartBsmAngleCal (2009/05/05 V0.1),
//                  SpirePhoto_Cal_BsmPcalFlash (2009/03/04 V1.3), and
//                  SpireSpectro_Cal_BsmPcalFlash (2009/03/04 V0.1)
//                  BB includes now to move BSM/SMEC to hold/home.  
// 2009/07/12 V1.0: Fix bug in passing of SMEC home position (SPR-SPIRE-1612)
//                  Set SMEC framerate to zero to get all BSM samples 
//                  (SPR-SPIRE-1551).
// 
// Notes:
//    1) Scripts assumes that SpireBb_SpecOffsetAuto is run 
//       during INITHOLD or at first POINTING.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartBsmPcalFlash SPIRE 14042 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    string obsModeQla = "ENG_CAL_OBS01";
    string obsMode = "PEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_Phot/SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    int smecHomePosn = 3500; // SMEC home position
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartBsmPcalFlash configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // In case move SMEC to home:
    // 
    if(!phot) {
        //
        // Calculate available time for possible movement:
        //
        int tmove = duration(SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug)) + duration(SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug)) + duration(SpireProc_Set_ObsStep(999,debug)) + duration(SpireBb_SpecOffsetAuto(false,debug));
        //
        // Calculate max offset for which time is available:
        //
        int smecMaxOff = tmove * 500;
        // Note, 500 is maximum possible SMEC speed.
        int smecStart = smecHomePosn + smecMaxOff;
        // Note, formula above only reasonable 
        // when smecHomePosn small compared to 39500  
        // Safety check: 
        if(smecStart > 39500) {
            smecStart = 39500;
        }
        if(debug) {
            debug_print("smecStart: " + smecStart);
            debug_print("smecHomePosn: " + smecHomePosn);
            debug_print("tmove: " + tmove);
        }
        // 
        // Move from maximal offset to home:
        //
        SpireProc_SmecMove2Home(smecHomePosn,smecHomePosn + smecMaxOff,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    if(phot) {
        SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    }
    //delay(timeSlewCal);
    // //
    // //
    // Set NHK STEP parameter to count PCAL levels:
    //
    int obsStep = 1;
    SpireProc_Set_ObsStep(obsStep,debug);
    // //
    // //
    // Set SMEC framerate (== SMEC sampling rate) to zero:
    //
    if(!phot) {
        SpireProc_Set_SmecFramerate(0,debug);
    }
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartBsmPcalFlash configuration ended");
    SpireMsg(1,"  ..StartBsmPcalFlash took " + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartMultiLevelNoise.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpirePhoto/Spectro_Cal_MultiLevelNoise.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V0.1: Initial version adapted from
//                  SpireBb_StartBsmAngleCal (2009/05/05 V0.1),
//                  SpirePhoto_Cal_MultiLevelNoise (2009/03/03 V1.3), and
//                  SpireSpectro_Cal_MultiLevelNoise (2009/03/04 V0.5)
//                  BB includes now to move BSM/SMEC to hold/home.  
// 2009/07/10 V1.0: Fix bug SPR-SPIRE-1612
//
// Notes:
//    1) Scripts assumes that SpireBb_SpecOffsetAuto is run 
//       during INITHOLD or at first POINTING.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartMultiLevelNoise SPIRE 14052 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    string obsModeQla = "ENG_CAL_OBS08";
    string obsMode = "PEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_Phot/SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    int smecHomePosn = 3500; // SMEC home position
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartMultiLevelNoise configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // In case move SMEC to home:
    // 
    if(!phot) {
        //
        // Calculate available time for possible movement:
        //
        int tmove = duration(SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug)) + duration(SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug)) + duration(SpireBb_SpecOffsetAuto(false,debug));
        //
        // Calculate max offset for which time is available:
        //
        int smecMaxOff = tmove * 500;
        // Note, 500 is maximum possible SMEC speed.
        int smecStart = smecHomePosn + smecMaxOff;
        // Note, formula above only reasonable 
        // when smecHomePosn small compared to 39500  
        // Safety check: 
        if(smecStart > 39500) {
            smecStart = 39500;
        }
        if(debug) {
            debug_print("smecStart: " + smecStart);
            debug_print("smecHomePosn: " + smecHomePosn);
            debug_print("tmove: " + tmove);
        }
        // 
        // Move from maximal offset to home:
        //
        SpireProc_SmecMove2Home(smecHomePosn,smecHomePosn + smecMaxOff,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    if(phot) {
        SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    }
    //delay(timeSlewCal);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartMultiLevelNoise configuration ended");
    SpireMsg(1,"  ..StartMultiLevelNoise took " + (time() - t) + " seconds)");
    //
}

// SpireBbBsmChopInit
//
// $id$
//
// This building block initialises the BSM chop axis
// 
// The BSM should be switched on (SpireBbBsmOn) before execution of this building block
//
// 27/04/2009 KJK: 
//         Updated to use new NominalSettings Cal Tables
//         model, version and debug passed as parameters
// 07/05/2009 KJK:
//         Added opsMode as input parameter to allow setting of bsmMoveMode from DefaultParams.txt calibration table
// 09/04/2010 SDS:
//         Added the setting of Chop FF offset and Chop-Jiggle coupling term (SPIRE-SCR-2490)
block SpireBbBsmChopInit SPIRE 266 {
    string opsMode = "PHTSTBY";
    string model = "initial";
    string version = "v00";
    bool debug = false;
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB BSM Chop Init started");
    SpireMsg(2,"          $Id$");
    //
    // 
    // intialise variables
    int chopkd = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",model,"chop_kd",version,debug);
    int chopkp = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",model,"chop_kp",version,debug);
    int chopki = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",model,"chop_ki",version,debug);
    int chop_t1 = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",model,"chop_filt1",version,debug);
    int chop_hold = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",model,"chop_0_I",version,debug);
    // Additional parameters
    int chopffoffset = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",model,"chop_ff_offset",version,debug);
    int chopjiggcouple = SpireProc_GetTableEntryInt("SpireTable_BsmNominalSettings.txt","model",model,"chop_jigg_couple",version,debug);
    //
    // 
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    delay(1);
    //
    // set Step to zero
    SpireSetObsStep(0);
    //
    // flag the current operation
    SpireSetObsMode("BSM_INIT");
    delay(1);
    //
    // Set Movement Mode for initialisation
    SpireSendDrcuCmd(0x90c60000,0);
    delay(1);
    //
    // Set the Chop FF offset and Chop Jiggle coupling term
    //
    SpireSendDrcuCmd(0x90c70000 + chopffoffset,0);
    delay(1);
    SpireSendDrcuCmd(0x90d90000 + chopjiggcouple,0);
    delay(1);
    //
    //
    //   
    // Set Chop Kd parameter
    SpireSendDrcuCmd(0x90c90000 + chopkd,0);
    delay(1);
    //
    // Set Chop Kp parameter
    SpireSendDrcuCmd(0x90c80000 + chopkp,0);
    delay(1);
    //
    // Set Chop Ki parameter
    SpireSendDrcuCmd(0x90ca0000 + chopki,0);
    delay(1);
    //
    // Set Chop derivative filtering parameter 1
    SpireSendDrcuCmd(0x90cf0000 + chop_t1,0);
    delay(1);
    //
    // Remove slew rate limiter
    SpireSendDrcuCmd(0x90d1ffff,0);
    delay(1);
    //
    // Set target position to HOLD
    SpireSendDrcuCmd(0x90c30000 + chop_hold,0);
    delay(1);
    //
    // Close loop on chop axis
    SpireSendDrcuCmd(0x90c20001,0);
    delay(1);
    //
    // Set Default Movement Mode
    int bsmMoveMode = SpireProc_GetTableEntryInt("SpireTable_DefaultParams.txt","mode",opsMode,"bsmMoveMode",version,debug);
    SpireSendDrcuCmd(0x90c60000 + bsmMoveMode,0);
    //
    // completion
    sync();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB BSM Chop Init   ended");
    SpireMsg(1,"  ..BSM Chop Axis Initialisation (" + (time() - t0) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StopDcuMcuData.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to stop generation of detector data (TM packets) plus MCU 
// (here only BSM and SMEC) data.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/03/31 V0.1: Initial version adapted from 
//                  SpireBb_StartDcuMcuData (2009/03/31 V0.1)
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StopDcuMcuData SPIRE 14038 {
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_StopDcuMcuData started");
    SpireMsg(2,"          $Id:$");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Start DCU data:
    //
    SpireProc_Set_StopDcuData();
    SpireProc_Set_StopMcuData();
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_StopDcuMcuData ended");
    SpireMsg(1,"  ..StopDcuMcuData (" + (time() - t) + " seconds)");
}

// SpirePhoto_Cal_Sample.txt
//
// $id$
//
// This observation samples detector data while staring at a point on the sky. 
// It is based on the POF5 observing mode and configires the detectors as for obsMode=POF5_S_N
// 
// The instrument should normally be in PHOTSTBY mode before execution of this observation
// Final Configuration: Instrument is still in PHOTSTBY mode after execution of this observation
//
//
// 03/10/2009 MP: First Version  (SCR-SPIRE-2101)
//                renamed from SpirePhotoSample (15/09/2009 KJK)
//
obs SpirePhoto_Cal_Sample {
    double ra = 0.0 in [0.0,360.0]; // RA of Target
    double dec = 0.0 in [-90.0,90.0]; // DEC of Target
    int naifid = 0; // NAIF identifier
    int observingTime = 120; // Time (secs) to produce detector data
    bool initFlash = false; // Flash at start of observation?
    bool endFlash = false; // Flash at end of observation?
    bool isBright = false;
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string opsVersion = "v00";
    string flashVersion = "v00";
    string photVersion = "v00";
    string comVersion = "v00";
    bool debug = false;
    bool pBool1 = false; // Spare parameter (currently not in use)
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    string obsMode = "POF5_S_N";
    string ib = SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode",obsMode,"Boresight",opsVersion,debug);
    int tFlash = duration(SpireBbPcalFlash("PFlash",flashVersion,0,debug));
    int tSlewMin = duration(SpireBbObsConfig(0)) + duration(SpireBbPOF5Config(obsMode,isBright,bsmModel,bsmVersion,photVersion,comVersion,debug)) + 2;
    int tInitHold = duration(SpireBbPOF5Init(obsMode)) + duration(SpireBbStartDcuData(obsMode)) + 2;
    if(initFlash) {
        tInitHold = tInitHold + tFlash;
    }
    int tFinalHold = duration(SpireBbPOF5End("PHTSTBY",isBright,bsmModel,bsmVersion,photVersion,comVersion,debug)) + duration(SpireBbStopDcuData()) + 2;
    if(endFlash) {
        tFinalHold = tFinalHold + tFlash;
    }
    int tp = observingTime;
    int tSerendipity = duration(SpireBbPhotSerendipity(obsMode,0));
    // minimum time for a serendipity observation
    //
    // Set pointing mode:
    //
    int[] ts = basic_fine_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,0.0,0.0,tp);
}{
    int tslew = ts[1];
    // slew time
    string tstr = "";
    // time string
    int otf = 0x8000;
    // On Target Flag
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // ***********************  SLEWING
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Slewing to start position");
            // set up observation parameters
            SpireBbObsConfig(0x350);
            // perform serendipity operation if possible
            if(tslew > tSerendipity + tSlewMin) {
                SpireBbPhotSerendipity(obsMode,tslew - tSlewMin - 2);
            }
            // configure instrument for operations
            SpireBbPOF5Config(obsMode,isBright,bsmModel,bsmVersion,photVersion,comVersion,debug);
        }
        if(state[0] == 2) {
            // ***********************  INITIAL HOLD          
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Initialising Instrument");
            // initialise instrument
            SpireBbPOF5Init(obsMode);
            // calibrate if necessary
            if(initFlash) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireBbPcalFlash("PFlash",flashVersion,otf,debug);
            }
            SpireMsg(2,"    " + tstr + " Sampling Started");
            SpireBbStartDcuData(obsMode);
        }
        if(state[0] == 3) {
            // ***********************  POINTING
        }
        if(state[0] == 5) {
            // ***********************  FINAL HOLD
            tstr = SpireTimeStr(time());
            SpireMsg(2,"    " + tstr + " Reconfiguring Instrument");
            SpireMsg(2,"    " + tstr + " Sampling Stopped");
            SpireBbStopDcuData();
            // calibrate if necessary
            if(endFlash) {
                tstr = SpireTimeStr(time());
                SpireMsg(2,"    " + tstr + " PCAL Calibration inserted");
                SpireBbPcalFlash("PFlash",flashVersion,otf,debug);
            }
            // reconfigure back to PHOT_STBY configuration
            SpireBbPOF5End("PHTSTBY",isBright,bsmModel,bsmVersion,photVersion,comVersion,debug);
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_GetTableEntryString.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to select a double entry in a calibration table
//  giving a string input as selector using the versioning approach. 
//
//  Note: Currently script is restricted to a 'string' selector!
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/01/26 V0.1: Initial version adapted from 
//                  SpireProc_CalcParam_FpgInitialPointing.txt (2008/11/06 V0.3)
// 2009/07/12 V1.0: Fix SPR-SPIRE-1636 (reduce number of debug printouts)
//                  Change default values for testing. 
// 2009/08/15 V1.1: Fix SPR-SPIRE-1819 (add proper error message and report 
//                  table name)
//
///////////////////////////////////////////////////////////////////////////
//
string procedure SpireProc_GetTableEntryString {
    string tabName = "SpireTable_DefaultParams.txt"; // Name of the table to be selected from
    string selCol = "mode"; // Name of column for selecting 
    string selVal = "PHTSTBY"; // Value of 'string' selector 
    string tarCol = "ptcVm"; // Target column name     
    string version = "v00"; // Version parameter defined in calibration table
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variable:
    //
    string stringVar = "";
    //
    // Define columns:
    string[] versionCol = scolumn(tabName,"version");
    string[] targetCol = scolumn(tabName,tarCol);
    string[] selectorCol = scolumn(tabName,selCol);
    //
    // Read table size: 
    int nrows = table_size(tabName);
    // //
    // //
    // Cycle through values to get all rows with correct version tag:
    //
    //Setup:
    {string,string}[] rows = [{"",""}];
    int nindex = 0;
    bool match = false;
    //
    for(int j = 0 .. nrows - 1) {
        //if(debug) {
        //    debug_print("versionCol[j]: " + versionCol[j]);
        //}
        if(versionCol[j] == version) {
            rows[nindex] = {targetCol[j],selectorCol[j]};
            nindex = nindex + 1;
            match = true;
        }
    }
    //if(debug) {
    //    debug_print("selected rows: " + rows);
    //}
    // Safety check: 
    if(!match) {
        error("Calibration table empty or wrong version selected!");
    }
    // //
    // //
    // Make final selection from all rows (selected by version):
    //
    int nentries = length(rows);
    int counter = 0;
    match = false;
    for(int i = 0 .. nentries - 1) {
        //if(debug) {
        //    debug_print("rows sliced:" + rows[i]{0} + "/" + rows[i]{1});
        //}
        if(rows[i]{1} == selVal) {
            stringVar = rows[i]{0};
            match = true;
            counter = counter + 1;
        }
    }
    // Safety checks: 
    if(!match) {
        error("Entry " + selVal + " not found in calibration table (" + tabName + "). Call for help and wait to be rescued!");
    }
    //
    if(counter > 1) {
        error("Selector string " + selVal + " is present at least twice in the versioned calibration table(" + tabName + "). Please report this bug to the relevant authorities!");
    }
    // //
    // //
    // Return required value:
    //
    if(debug) {
        debug_print(" If you believe it of not, I found " + tarCol + "=" + stringVar + " as version " + version + " when selecting for " + selCol + "=" + selVal + " in table " + tabName);
    }

    return stringVar;
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Set_EndObsAll.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Procedure to reconfigure at the end of all AOTs
// (i.e. astronomer, engineering, and calibration ones) 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2009/05/05 V1.0: First version adapted from
//                  SpireBb_EndObsAll (2009/01/30 V1.1)
// 
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Set_EndObsAll {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start procedure:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(3,"      " + tstr + ": Proc EndObsAll started");
    SpireMsg(3,"            $Id: $");
    // //
    // //
    // Reset ObsMODE to PHOT/SPEC-STBY:
    //
    if(phot) {
        // Set mode back to PHOTSTBY:
        obsmode = "PHOTSTBY";
        mode_id = ilookup("SpireTableInstConfigs.txt",obsmode,"value");
    } else {
        // Set mode back to SPECSTBY
        obsmode = "SPECSTBY";
        mode_id = ilookup("SpireTableInstConfigs.txt",obsmode,"value");
    }
    tstr = SpireTimeStr(time());
    hstr = SpireHexStr(mode_id,8);
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_MODE(" + hstr + ")");
    Spire_SET_OBS_MODE(mode_id);
    delay(1);
    // //
    // //
    // Set the BBID(s) back to null:
    //
    tstr = SpireTimeStr(time());
    message("5          " + tstr + "Cmd: Spire_SET_BBID_RAW(0x80000000)");
    Spire_SET_BBID_RAW(0x80000000);
    // //
    // //
    // Set the OBSIDs to null:
    //
    int null_obsid = SpireNullObsid();
    tstr = SpireTimeStr(time());
    hstr = SpireHexStr(null_obsid,8);
    Spire_SET_OBSID(null_obsid);
    //delay(1);
    // //
    // //
    // Round up total duration:
    //
    sync();
    // //
    // //
    // End procedure:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(3,"      " + tstr + ": Proc EndObsAll ended");
    SpireMsg(2,"    Proc StartObsAll (" + (time() - t) + " seconds)");
}

// SpireBbSpecSerendipity
//
// $Id:$
//
// Building Block to take serendipity data for a specified period of time
//
// If the time specified is less than the minimum then this BB takes the minimum time anyway
//
// Note: this BB assumes that the detector bias and sampling frequency and 
//       the BSM sampling frequency have been set appropriately  
//
// 04 November 2008: 
//            changed to accept observing mode
//            changed to provide operations mode rather than data mode as a parameter to StartDcuData
// 21/09/2009 KJK:
//            SPR Spire-1993: updated to read SpireTable_SpireParams.txt instead of SpireParms.txt
//
block SpireBbSpecSerendipity SPIRE 8453 {
    string opsMode = "" in ["SOF1","SOF2","SOF2_int","SOF3","SOF4"];
    int len = 0 in [0,10000]; // scan length in seconds - maximum determined by max time between Tsync
}{
    string spireVersion = "v00";
    bool debug = false;

    message("2    " + time() + ": BB Spec Serendipity started");
    message("2          $Id:$");
    message("3          length = " + len);
    int t = time();
    //
    // find actual length of BB
    int tSerendipity = SpireProc_GetTableEntryInt("SpireTable_SpireParams.txt","mode",opsMode,"TSerendipity",spireVersion,debug);
    // minimum time for Serendipity observation
    if(len < tSerendipity) {
        len = tSerendipity;
    }
    //
    // ..... configuration .....
    //
    // set BBID
    message("5          " + time() + "Cmd: Spire_SET_BBID_RAW(" + $BBID + ")");
    Spire_SET_BBID_RAW($BBID);
    // set value
    delay(2);
    // allow HSK to reflect new value
    //
    // ..... initialisation .....
    //
    //
    // ..... execution ..... 
    //
    // start sampling detectors
    SpireStartDcuData("SSer");
    //
    // wait to end of time
    int tStop = duration(SpireStopDcuData());
    wait_until(t + len - tStop - 2);
    //
    // stop detector sampling
    SpireStopDcuData();
    //
    // ..... completion .....
    //
    //
    wait_until(t + len);
    message("2    " + time() + ": BB Spec Serendipity ended");
    message("0  Serendipity Mode (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SpecFSetBiasAmpl.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set bias amplitude of spectrometer arrays
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/12 V0.1: Initial version adapted from
//                  SpireBb_PhotFSetBiasAmpl (2008/07/03 V0.3)
//                  based on
//                  SFBias_Ampl (v1.4 2008/01/31 20:24:37)
// 2009/02/19 V0.2: Instead of using commands call SpireProc_Set_SpecBias
//                  and add sync() after setBbId. Add HSpot messages. 
//                  Add debug_print. Remove unsetting of BBID at end.
// 2009/07/04 V0.3: Fixed copy/paste bug to set bias instead of phase
//                  detected during FS testing plus messages.  
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SpecFSetBiasAmpl SPIRE 14016 {
    int ssw_bias = 0x2d; //Default (IST) bias amplitud  (==31.1 mV)
    int slw_bias = 0x2d; //Default (IST) bias amplitud  (==31.1 mV)
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string hstr = "";
    // a hex string
    string tstr = "";
    // a time string
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": SpireBb_SpecFSetBiasAmpl started");
    SpireMsg(2,"          $Id: $");
    hstr = SpireHexStr($BBID,8);
    SpireMsg(3,"          BBID = " + hstr);
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    sync();
    // //
    // //
    // Set the bias levels for the two arrays:
    //
    SpireProc_Set_SpecBias(ssw_bias,slw_bias,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SpecFSetBiasAmpl ended");
    SpireMsg(1,"  ..Set Spec bias (" + (time() - t) + " secs)");
    //
}

// SpireBb_CalSdetOff
//
// $id$
//
// This building block switches off the spectrometer detectors for calibration observations 
//
//
// 07/01/2010 S.D.Sidher V0.1:
//         Adapted from SpireBbPdetOn (does not set the mode)
// 
block SpireBb_CalSdetOff SPIRE 3416 {
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB CalSdetOff started");
    SpireMsg(2,"          $Id:$");
    //
    int cmd = 0x0;
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // Set STEP to 0
    SpireSetObsStep(0x0);
    delay(1);
    //
    //
    // Switch off  SSW VDD and VSS
    SpireSendDrcuCmd(0x84370001,0);
    for(int i = 0 .. 1) {
        SpireSendDrcuCmd(0x84350000 + 0x10000 * i,0);
        delay(1);
    }
    //
    // Switch off  SLW VDD and VSS
    SpireSendDrcuCmd(0x84370000,0);
    SpireSendDrcuCmd(0x84340000,0);
    delay(1);
    // 
    // Set DEMOD PHASE TO ZERO
    SpireSendDrcuCmd(0x843a0000,0);
    SpireSendDrcuCmd(0x843b0000,0);
    delay(1);
    //
    // Set BIAS TO ZERO
    SpireSendDrcuCmd(0x84310000,0);
    SpireSendDrcuCmd(0x84320000,0);
    delay(1);
    //
    // Switch OFF SLIAs 
    SpireSendDrcuCmd(0xa0870004,0);
    delay(4);
    //
    // completion
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB CalSdetOff   ended");
    SpireMsg(1,"  ..BB CalSdetOff (" + (time() - t0) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireProc_Exec_IltPcalFlash.txt
//
///////////////////////////////////////////////////////////////////////////
//
//  Procedure to execute two PCAL flashes with the standard values 
//  from ILT as fixed parameters inside the script. 
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/12 V0.1: Initial version adapted from
//                  SpireProc_Exec_PhotIltPcalFlash (2008/05/02 V0.1)
//                  based on
//                  Mode_ILT_PERF_DAB_P_CPS.txt (v1.3 2008/01/31 23:35:17)
//                  Rename script, remove 'Phot'; Move input parameters
//                  to fixed parameters inside the script
// 2008/11/07 V0.2: Adapt to change in name of low level script
// 2009/02/02 V1.0: Add debug_print as input and pass to low level scripts.
//                  Adapt input to updated SpireBb_PcalFlash with rate and step.
// 2009/02/17 V1.1: Read VM parameters from calibration file. 
// 2009/02/18 V1.2: Adapt to change in call to SpireBb_PcalFlash.
// 2009/02/19 V1.3: Add phot as new input and set the correct 
//                  high bias levels for phot and fts accordingly. 
//
///////////////////////////////////////////////////////////////////////////
//
procedure SpireProc_Exec_IltPcalFlash {
    int period = 4000000; //PCAL Flash FULL period (high and low bias) [microsec]
    int mclkdiv = 149; // Fetched master clock divisor [Hex]
    int biasdiv = 6; // Fetched bias divisor [Hex]
    int ndcumode = 0; // DCU data mode (0 == PF; 4 == SF) 
    bool phot = true; // Photometer (==tick) or FTS IltPcalFlash values?
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Declare some variables:
    int pcal_low_bias_0 = 0;
    int pcal_high_bias_0 = 0;
    int pcal_low_bias_1 = 0;
    int pcal_high_bias_1 = 0;
    // //
    // //
    // Set PCAL Flash values to the once fixed used during ILT: 
    // 
    // Read VM parameters from calibration table:
    //
    string tabName = "SpireTable_CommandLists.txt";
    string selVal = "Flash";
    // Raw VM table number: 
    int vmId = ilookup(tabName,selVal,"Id");
    // Raw VM index:
    int vmIndex = ilookup(tabName,selVal,"Index");
    // Number of parameters passed to VM:
    int nParms = ilookup(tabName,selVal,"Nparms");
    //
    // Raw value of low level for 1. flash phot/spec:
    pcal_low_bias_0 = 4;
    //
    // Raw value of high level for 1. flash:
    if(phot) {
        pcal_high_bias_0 = 2176;
    } else {
        pcal_high_bias_0 = 2748;
    }
    //
    // Raw value of low level for 2. flash phot/spec:
    pcal_low_bias_1 = 4;
    //
    // Raw value of high level for 2. flash
    if(phot) {
        pcal_high_bias_1 = 2748;
    } else {
        pcal_high_bias_1 = 3433;
    }
    //
    // Number of cycles:
    int ncycles = 15;
    //
    // SCU sampling rate (f =80Hz/(1+scumode)):
    int scumode = 0;
    // //
    // //
    // Calculate variable (erroneous) ILT PCAL Flash values
    //
    int periodinmillisec = ifloor(double(period) / 1000.0);
    int[] iltvalues = SpireProc_CalcParam_IltPcalFlash(periodinmillisec,mclkdiv,biasdiv,debug);
    // Number of DCU and SCU samples, and DCU sample delay  mclkdiv/biasdivi (149/6):
    int dcusamples = iltvalues[0];
    //
    // Number of DCU and SCU samples, and DCU sample delay  mclkdiv/biasdiv (149/6):
    int dcudelay = iltvalues[2];
    //
    // Number of DCU and SCU samples, and DCU sample delay mclkdiv/biasdiv (149/6)
    int scusamples = iltvalues[1];
    // Note: (0==continuous sampling) 
    // //
    // //
    // First PCAL Flash: 
    // 
    // Set STEP:
    int obsStep = 1;
    // NHK Step parameter 
    SpireBb_SetObsStep(obsStep,debug);
    //
    // Execute FLASH:
    SpireBb_PcalFlash(vmId,vmIndex,nParms,pcal_low_bias_0,pcal_high_bias_0,ncycles,period,ndcumode,dcusamples,dcudelay,scumode,scusamples,obsStep,debug);
    // Note: DCU start and stop is taken care of in the PCAL_Flash proceedure
    // // 
    // //
    // Second  PCAL Flash:         
    // 
    // Set STEP:
    obsStep = 2;
    // NHK Step parameter 
    SpireBb_SetObsStep(obsStep,debug);
    //
    // Execute FLASH:
    SpireBb_PcalFlash(vmId,vmIndex,nParms,pcal_low_bias_1,pcal_high_bias_1,ncycles,period,ndcumode,dcusamples,dcudelay,scumode,scusamples,obsStep,debug);
    //
}

// SpireBbSetScal
//
// $id$
//
// This building block starts or stops the  SCAL PID Command List
//
// 08/06/2009 KJK:  First Version
//
block SpireBbSetScal SPIRE 1610 {
    string scal = "None" in ["SCAL2","SCAL4","None"];
    int reqTemp = -1;
    string version = "v00";
    bool debug = false;
}{
    int t0 = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Set SCAL started");
    SpireMsg(2,"          $Id: $");
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    //
    // stop SCAL VM
    // this stops VM2 from another command list - this stops the possibility of a TC execution error if the 
    // VM is not running
    int vm = ilookup("SpireTable_CommandLists.txt","SCAL","Vm");
    tstr = SpireTimeStr(time());
    {int}[] cl = [{0x58000000 + vm},{0x7f000000}];
    SpireMsg(5,"          " + tstr + "Cmd: Spire_EXECUTE_COMMAND_LIST_RAW(" + 2 + "," + cl + ")");
    Spire_EXECUTE_COMMAND_LIST_RAW(2,cl);
    delay(2);
    //
    // ensure SCAL bias is zero
    SpireSendDrcuCmd(0xa0ca0000,0);
    // set SCAL2 bias to zero
    SpireSendDrcuCmd(0xa0cc0000,0);
    // set SCAL4 bias to zero
    delay(2);
    //
    if(scal != "None") {
        // start SCAL VM, if required
        //
        // Get Command List info 
        int tableId = ilookup("SpireTable_CommandLists.txt","SCAL","TableId");
        int startIndex = ilookup("SpireTable_CommandLists.txt","SCAL","Index");
        int nParams = ilookup("SpireTable_CommandLists.txt","SCAL","NParms");
        //
        // Retrieve the input parameters 
        if(reqTemp == -1) {
            reqTemp = SpireProc_GetTableEntryInt("SpireTable_CL_SCAL.txt","ScalId",scal,"ReqTemp",version,debug);
        }
        int getTempCmd = SpireProc_GetTableEntryInt("SpireTable_CL_SCAL.txt","ScalId",scal,"GetTempCmd",version,debug);
        int setHtrCurrCmd = SpireProc_GetTableEntryInt("SpireTable_CL_SCAL.txt","ScalId",scal,"SetHtrCurrCmd",version,debug);
        int loopPeriod = SpireProc_GetTableEntryInt("SpireTable_CL_SCAL.txt","ScalId",scal,"LoopPeriod",version,debug);
        int kp = SpireProc_GetTableEntryInt("SpireTable_CL_SCAL.txt","ScalId",scal,"Kp",version,debug);
        int ki = SpireProc_GetTableEntryInt("SpireTable_CL_SCAL.txt","ScalId",scal,"Ki",version,debug);
        int kd = SpireProc_GetTableEntryInt("SpireTable_CL_SCAL.txt","ScalId",scal,"Kd",version,debug);
        int kiLimit = SpireProc_GetTableEntryInt("SpireTable_CL_SCAL.txt","ScalId",scal,"KiLimit",version,debug);
        int lpFiltGain = SpireProc_GetTableEntryInt("SpireTable_CL_SCAL.txt","ScalId",scal,"LpFiltGain",version,debug);
        int lpFiltB1 = SpireProc_GetTableEntryInt("SpireTable_CL_SCAL.txt","ScalId",scal,"LpFiltB1",version,debug);
        int lpFiltB2 = SpireProc_GetTableEntryInt("SpireTable_CL_SCAL.txt","ScalId",scal,"LpFiltB2",version,debug);
        int maxDac = SpireProc_GetTableEntryInt("SpireTable_CL_SCAL.txt","ScalId",scal,"MaxDac",version,debug);
        int pwmFlag = SpireProc_GetTableEntryInt("SpireTable_CL_SCAL.txt","ScalId",scal,"PwmFlag",version,debug);
        int frameCount = SpireProc_GetTableEntryInt("SpireTable_CL_SCAL.txt","ScalId",scal,"FrameCount",version,debug);
        int initCount = SpireProc_GetTableEntryInt("SpireTable_CL_SCAL.txt","ScalId",scal,"InitCount",version,debug);
        //
        // start executing Command List
        {int}[] params = [{reqTemp},{getTempCmd},{setHtrCurrCmd},{loopPeriod},{kp},{ki},{kd},{kiLimit},{lpFiltGain},{lpFiltB1},{lpFiltB2},{maxDac},{pwmFlag},{frameCount},{initCount}];
        tstr = SpireTimeStr(time());
        if(vm == 1) {
            SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM1_RAW(" + tableId + "," + startIndex + "," + nParams + "," + params + ")");
            Spire_RUN_VM1_RAW(tableId,startIndex,nParams,params);
        }
        if(vm == 2) {
            SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM2_RAW(" + tableId + "," + startIndex + "," + nParams + "," + params + ")");
            Spire_RUN_VM2_RAW(tableId,startIndex,nParams,params);
        }
        if(vm == 3) {
            SpireMsg(5,"          " + tstr + "Cmd: Spire_RUN_VM3_RAW(" + tableId + "," + startIndex + "," + nParams + "," + params + ")");
            Spire_RUN_VM3_RAW(tableId,startIndex,nParams,params);
        }
        //
        delay(2);
    }
    //
    sync();
    //
    // completion
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ":  BB Set SCAL   ended");
}

// SpirePeakup
//
// $id$
//
// This procedure executes a Peakup observation
// 
// The instrument should be in  the PHOTSTBY mode before execution of this procedure.
// Th epeakup offset generated takes effect with the next observation so this observation
// should be concatenated with a following observation that requires peaking up
//
// 11/11/2008  KJK: first version
// 25/09/2009 KJK: SCR Spire-1932
//        modified call to SpireBbPeakup to pass on versions etc
// 17/02/2010 KJK: SPR Spire-2391:
//        Change calls to SpireSetObsMode to use SpireBb_SetObsMode
//
procedure SpirePeakup {
    string peakupMode = "PPeakup" in ["PPeakup","SPeakup"]; // Peakup Mode
    string ib = "";
    int step = 0;
    string comVersion = "v00";
    string pmodeVersion = "v00";
    string smodeVersion = "v00";
    string peakVersion = "v00";
    string siamVersion = "v00";
    bool debug = false;
}{
    // Set Mode to Peakup
    SpireBb_SetObsMode(peakupMode,debug);
    delay(1);
    //
    // execute Peakup
    SpireBbPeakup(peakupMode,ib,step,comVersion,pmodeVersion,smodeVersion,peakVersion,siamVersion,debug);
    //
    // reset Mode
    if(peakupMode == "PPeakup") {
        SpireBb_SetObsMode("PHOTSTBY",debug);
    } else {
        SpireBb_SetObsMode("SPECSTBY",debug);
    }
    delay(1);
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBbSetSmecSampling.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// The Building Block sets the SMECsampling  
//
///////////////////////////////////////////////////////////////////////////
//
// 28/04/2009 v1.0 KJK: First Version
// 08/06/2009 v1.1 KJK: Use smecTelemetryType in SpireTable_DefaultParams to 
//                 determine if selected packets are generated rearranged to 
//                 set default values for smec sampling whether or not 
//                 generating data corrceted to get REDY mode parameters from 
//                 DefaultParams table.
// 22/08/2009 v1.2 MP: Improved header; changed behaviour of script when 
//                 input opsMode="REDY", in this case add 
//                 Spire_DISABLE_SELECTION. Added a sync() at the end. 
// 03/09/2009 v1.3 KJK: Setup to work for any operating mode to fix SPR-1763 
//                 (Problem1)
// 04/09/2009 v1.4 MP: Move commands to procedure SpireProcSetBsmSampling 
//                 and call this here. 
//
///////////////////////////////////////////////////////////////////////////
//
double block SpireBbSetSmecSampling SPIRE 1602 {
    string opsMode = "SPECSTBY";
    string smecVersion = "v00";
    bool debug = false; // Allow debug_print statements 
}{
    // 
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    double smecDataRate = 0.0;
    //
    // Start BB:
    //
    message("4    " + time() + ": SpireBbSetSmecSampling started");
    message("4          $Id: $");
    // //
    // //
    // Set the BBID
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    delay(1);
    // //
    // //
    // Call procedure:
    //
    smecDataRate = SpireProcSetSmecSampling(opsMode,smecVersion,debug);
    //
    // End BB:
    //
    SpireMsg(4,"    " + time() + ": BB SpireBbSetSmecSampling ended");

    return smecDataRate;
}

//CLName: SpireBb_LoadTableSCAL
//VMVersion: 2.8
//CLVersion: 2.5
//CLCVSId: $ID$
//TableId: 0x50
//TableLength: 0x1ac
//Date: 100120110534
// 23/07/2010: SDS
//                      Now reporting 40 words less than the length of table (static part of table) 
//                      See SPIRE-SCR-2761
block SpireBb_LoadTableSCAL SPIRE 3332 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableSCAL started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // 
    //set table command call for table id 0x50
    Spire_SET_TABLE(0x50,0x1ac);
    delay(t_min);
    //update table command call for table index 0x0000
    Spire_UPDATE_TABLE(0x50,0x0,38,[{0x120000fd},{0x100},{0x20140000},{0x20150001},{0x20160002},{0x14000001},{0xa8ea0000},{0x32010015},{0x12000001},{0x5000},{0x14000002},{0xca},{0x32020172},{0x80007d0},{0x1000001},{0x12000000},{0xa8850000},{0x12000001},{0xbb8},{0x60640000},{0x18000001},{0x400},{0x80007d0},{0x1000000},{0x32010018},{0x12000001},{0x5001},{0x30000163},{0x12000001},{0x5002},{0x14000002},{0xcc},{0x3202015e},{0x80007d0},{0x1000001},{0x12000000},{0xa8850000},{0x12000001}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x50,0x26,38,[{0xbb8},{0x60640000},{0x18000001},{0x800},{0x80007d0},{0x1000000},{0x32010004},{0x12000001},{0x5003},{0x3000014f},{0x20000014},{0x20010015},{0x20020016},{0x4b010189},{0x4b02018a},{0x120000ff},{0xb},{0x120000fc},{0x189},{0x6107fc01},{0x120000ff},{0x2},{0x120000fc},{0x183},{0x12000014},{0x1},{0x4b140183},{0x6107fc01},{0x4b010189},{0x4b02018a},{0x4b030197},{0x4b040191},{0x4b050192},{0x4b060193},{0x4b070194},{0x19000007},{0x80000000},{0x4b070195}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x50,0x4c,38,[{0x4b080199},{0x4b09019a},{0x4b0a019b},{0x4b0b01a8},{0x4b0c01a9},{0x4b0d01aa},{0x1000000e},{0x63fd001d},{0x4b000187},{0x49000197},{0x63fd001d},{0x4b000197},{0x12000001},{0x40000000},{0x63fd0013},{0x4b000198},{0x12000000},{0x49742400},{0x49010197},{0x63fd0013},{0x4b000196},{0x120000ff},{0x2},{0x12000014},{0x2},{0x4b140183},{0x6107fc01},{0x4900018c},{0x4b00018d},{0x4900018b},{0x4b00018c},{0x80007d0},{0x1000001},{0x49000189},{0x12000001},{0xbb8},{0x60640000},{0x49020186}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x50,0x72,38,[{0x12000003},{0x7d0},{0x22020203},{0x12000003},{0x7d0},{0x22020203},{0x9000002},{0x1000000},{0x3200fff1},{0x20000001},{0x63fd001d},{0x4b00018b},{0x4900018f},{0x4b000190},{0x4900018e},{0x4b00018f},{0x12000000},{0x40000000},{0x4901018c},{0x63fd0012},{0x4901018b},{0x63fd0010},{0x4901018d},{0x63fd0010},{0x4b00018e},{0x4900018f},{0x4901019a},{0x63fd0012},{0x4901018e},{0x63fd0010},{0x4b00018e},{0x49000190},{0x4901019b},{0x63fd0012},{0x4901018e},{0x63fd0010},{0x4b00018e},{0x1100000e}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x50,0x98,38,[{0x320effcf},{0x1200000e},{0x1},{0x120000ff},{0x2},{0x12000014},{0x3},{0x4b140183},{0x6107fc01},{0x490001a2},{0x12000001},{0xbf800000},{0x63fd0012},{0x4b0001a3},{0x4900018e},{0x49010199},{0x63fd0013},{0x20010000},{0x49000187},{0x63fd0011},{0x4b0001a2},{0x49010191},{0x63fd0012},{0x4b0001a5},{0x490001a2},{0x49010196},{0x63fd0013},{0x490101a4},{0x63fd0010},{0x4b0001a4},{0x49010194},{0x63fd0011},{0x18000000},{0x80000000},{0x32000003},{0x49000194},{0x4b0001a4},{0x490101a4}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x50,0xbe,38,[{0x49000195},{0x63fd0011},{0x18000000},{0x80000000},{0x32000003},{0x49000195},{0x4b0001a4},{0x490001a4},{0x49010192},{0x63fd0012},{0x4b0001a6},{0x490001a2},{0x490101a3},{0x63fd0010},{0x49010196},{0x63fd0012},{0x49010193},{0x63fd0012},{0x4b0001a7},{0x490001a5},{0x490101a6},{0x63fd0010},{0x490101a7},{0x63fd0010},{0x4b00019c},{0x63fd001c},{0x4b00019f},{0x63fd001d},{0x20010000},{0x4900019c},{0x63fd0011},{0x4b00019d},{0x490001a9},{0x32000010},{0x4900019d},{0x12000001},{0x3f000000},{0x63fd0011}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x50,0xe4,38,[{0x18000000},{0x80000000},{0x4901019f},{0x32000002},{0x10000001},{0x4b01019f},{0x4b01019e},{0x49000198},{0x4b0001a1},{0x4b0001a0},{0x3000003a},{0x4900019d},{0x12000001},{0x0},{0x63fd0011},{0x18000000},{0x80000000},{0x32000014},{0x4901019d},{0x12000000},{0x3f400000},{0x63fd0011},{0x18000000},{0x80000000},{0x32000020},{0x4900019f},{0x10000000},{0x4b00019e},{0x4900019d},{0x49010197},{0x63fd0012},{0x4b0001a0},{0x20010000},{0x49000197},{0x63fd0011},{0x4b0001a1},{0x30000020},{0x4900019f}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x50,0x10a,38,[{0x10000000},{0x4b00019e},{0x11000000},{0x11000000},{0x4b00019f},{0x4900019d},{0x12000001},{0x3f800000},{0x63fd0010},{0x4b00019d},{0x49010198},{0x63fd0012},{0x4b0001a0},{0x20010000},{0x49000197},{0x63fd0011},{0x4b0001a1},{0x3000000d},{0x4900019f},{0x10000000},{0x10000000},{0x4b00019e},{0x4900019d},{0x49010198},{0x63fd0012},{0x4b0001a0},{0x20010000},{0x49000197},{0x63fd0011},{0x4b0001a1},{0x4900019f},{0x12000001},{0x0},{0x35000001},{0x30000007},{0x4b01019f},{0x4b01019e},{0x49010198}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x50,0x130,38,[{0x4b0101a1},{0x4b0101a0},{0x3000000a},{0x4900019e},{0x490101a8},{0x34000001},{0x30000006},{0x4b01019f},{0x4b01019e},{0x49010198},{0x4b0101a1},{0x4b0101a0},{0x80007d0},{0x1000001},{0x12000000},{0x2},{0x4901018a},{0x4902019f},{0x12000003},{0xbb8},{0x60640001},{0x490001a1},{0x63fd001c},{0x12000002},{0x7d0},{0x22000002},{0x12000002},{0x7d0},{0x22000002},{0x9000000},{0x1000000},{0x80007d0},{0x1000001},{0x12000000},{0x2},{0x4901018a},{0x4902019e},{0x12000003}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x50,0x156,38,[{0xbb8},{0x60640001},{0x490001a0},{0x63fd001c},{0x49010186},{0x22000001},{0x12000001},{0x7d0},{0x22000001},{0x12000001},{0x7d0},{0x22000001},{0x9000000},{0x1000000},{0x490001aa},{0x32000002},{0x30000015},{0x49ff0184},{0x12000000},{0x184},{0x61520028},{0x49000184},{0x13000000},{0x28},{0x4b000184},{0x1100000d},{0x320d000b},{0x120000ff},{0x0},{0x12000000},{0x184},{0x61520001},{0x54000052},{0x490d01aa},{0x12000000},{0x0},{0x4b000184},{0x30fffeec}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x50,0x17c,38,[{0x12000001},{0x5010},{0x12000000},{0x5000},{0x53020000},{0x2000000},{0x7f000000},{0x0},{0x0},{0xface},{0x3a98},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x0}]);
    delay(t_min);
    Spire_UPDATE_TABLE(0x50,0x1a2,10,[{0x0},{0x0},{0x0},{0x0},{0x0},{0x0},{0x7fff},{0x0},{0x0},{0xcafe}]);
    delay(t_min);
    //
    //  Dump table contents - report 40 words less than the length of table. 
    //  These 40 words in table are dynamic (used for calculations) 
    //
    Spire_REPORT_TABLE(0x50,0x0,0x183);
    delay(4);
    //
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_LoadTableSCAL ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_EndPtcPwr.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to reconfigure at the end of SpirePhoto_Cal_PtcPwr.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/05 V1.0: Initial version adapted from
//                  SpireBb_EndBsmAngleCal (2009/05/05 V1.2) and
//                  SpirePhoto_Cal_PtcPwr (2009/03/30 V0.1).
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_EndPtcPwr SPIRE 14059 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    bool isBright = false in [true,false]; // IsBright (==tick) flag
    string version01 = "v00"; // Version in cal.tab. SpireTable_PhotModeParams
    string version02 = "v00"; // Version in cal.tab. SpireTable_CommonModeParams
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndPtcPwr reconfiguration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Set instrument back to Phot/Spec-STBY:
    //
    if(phot) {
        SpireProc_Set_PhotMode("PHTSTBY",isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode("SPECSTBY",isBright,version01,version02,debug);
    }
    // //
    // //
    // End observation:
    //
    SpireProc_Set_EndObsAll(phot);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB EndPtcPwr reconfiguration ended");
    SpireMsg(1,"  ..Reconfiguration to " + obsmode + "mode (" + (time() - t) + " seconds)");
    //
}

//
// Patch on-board tables
// 03/08/2010: SDS First Version 
//             See SPIRE-SCRs 2572, 2750, 2764 and 2766
//    
block SpireBb_PatchTables SPIRE 3426 {
}{
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    // a time string:
    string tstr = "";
    int t_min = 1;
    //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_PatchTables started");
    SpireMsg(2,"          $Id: $");
    //
    // Set the BBid 
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    //
    // Report the current contents of table location to be patched
    //
    mois_comment("The next three TCs are for patching and checking the FIRST SPIRE on-board Table");
    Spire_REPORT_TABLE(0x50,2,1);
    delay(2);
    Spire_UPDATE_TABLE(0x50,2,1,[{0x20140000}]);
    delay(2);
    // Report the new contents of table location which has just been patched
    Spire_REPORT_TABLE(0x50,2,1);
    delay(2);
    //
    // Report the current contents of table location to be patched
    //
    mois_comment("The next three TCs are for patching and checking the SECOND SPIRE on-board Table");
    Spire_REPORT_TABLE(0x67,121,1);
    delay(2);
    Spire_UPDATE_TABLE(0x67,121,1,[{0x60660003}]);
    delay(2);
    // Report the new contents of table location which has just been patched
    Spire_REPORT_TABLE(0x67,121,1);
    delay(2);
    //
    // Report the current contents of table location to be patched
    //
    mois_comment("The next three TCs are for patching and checking the THIRD SPIRE on-board Table");
    Spire_REPORT_TABLE(0x5,1427,1);
    delay(2);
    Spire_UPDATE_TABLE(0x5,1427,1,[{0xfffff054}]);
    delay(2);
    // Report the new contents of table location which has just been patched
    Spire_REPORT_TABLE(0x5,1427,1);
    delay(2);
    //
    // End BB:
    sync();
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_PatchTables ended");
    SpireMsg(1,"  ..Table Load (" + (time() - t) + " seconds)");
    //
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_StartPcalLoadCurve.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// Building Block to configure at the start of 
// SpirePhoto/Spectro_Cal_PcalLoadCurve.
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
//
// 2009/05/07 V0.1: Initial version adapted from
//                  SpireBb_StartBsmAngleCal (2009/05/05 V0.1),
//                  SpirePhoto_Cal_PcalLoadCurve (2009/03/04 V1.4), and
//                  SpireSpectro_Cal_PcalLoadCurve (2009/03/04 V0.5)
//                  BB includes now to move BSM/SMEC to hold/home.  
// 2009/07/05 V1.0: Fix bug to allow spectrometer to use script.   
// 2009/07/10 V1.1: Fix bug SPR-SPIRE-1612
// 
// Notes:
//    1) Scripts assumes that SpireBb_SpecOffsetAuto is run 
//       during INITHOLD or at first POINTING.
// 
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_StartPcalLoadCurve SPIRE 14068 {
    bool phot = true; // Photometer (==tick) or FTS (==untick)? 
    string obsModeQla = "ENG_CAL_OBS01";
    string obsMode = "PEngCalObs";
    bool isBright = false; // Use settings for bright source (==tick)
    string version01 = "v00"; // Version in cal table SpireTable_Phot/SpecModeParams
    string version02 = "v00"; // Version in cal table SpireTable_CommonModeParams
    int hold_chop = 37632; // Chop hold position
    int hold_jigg = 39520; // Jiggle hold position
    int smecHomePosn = 3500; // SMEC home position
    int mclkdiv = 149; // mclkdiv (spec ==~ 121)
    int biasdiv = 6; // biasdiv (spec ==~ 1)
    int psw_bias = 62; //
    int pmw_bias = 62; //
    int plw_bias = 62; //
    int ptc_bias = 62; //
    int psw_phase = 127; //
    int pmw_phase = 127; //
    int plw_phase = 127; //
    int ptc_phase = 127; //
    int ssw_bias = 45; //
    int slw_bias = 45; //
    int ssw_phase = 128; //
    int slw_phase = 128; // 
    bool debug = false; // Allow debug_print statements 
}{
    // //
    // //
    // Define some variables:
    //
    // a hex string:
    string hstr = "";
    //
    // a time string:
    string tstr = "";
    //
    int mode_id = 0;
    string obsmode = "";
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartPcalLoadCurve configuration started");
    SpireMsg(2,"          $Id: $");
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    // //
    // //
    // Startup observation: 
    //
    SpireProc_Set_StartObsAll(obsModeQla);
    // //
    // //
    // In case move SMEC to home:
    // 
    if(!phot) {
        //
        // Calculate available time for possible movement:
        //
        int tmove = duration(SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug)) + duration(SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug)) + duration(SpireProc_Set_DcuFreqSamp(mclkdiv,biasdiv,phot,debug)) + duration(SpireProc_Set_PhotPhase(psw_phase,pmw_phase,plw_phase,ptc_phase,debug)) + duration(SpireProc_Set_PhotBias(psw_bias,pmw_bias,plw_bias,ptc_bias,debug)) + duration(SpireBb_SpecOffsetAuto(false,debug)) + duration(SpireProc_Set_ObsStep(9999,debug));
        //
        // Calculate max offset for which time is available:
        //
        int smecMaxOff = tmove * 500;
        // Note, 500 is maximum possible SMEC speed.
        int smecStart = smecHomePosn + smecMaxOff;
        // Note, formula above only reasonable 
        // when smecHomePosn small compared to 39500  
        // Safety check: 
        if(smecStart > 39500) {
            smecStart = 39500;
        }
        if(debug) {
            debug_print("smecStart: " + smecStart);
            debug_print("smecHomePosn: " + smecHomePosn);
            debug_print("tmove: " + tmove);
        }
        // 
        // Move from maximal offset to home:
        //
        SpireProc_SmecMove2Home(smecHomePosn,smecHomePosn + smecMaxOff,debug);
    }
    // //
    // //
    // Move BSM back to hold:
    //
    SpireProc_Set_BsmMove(hold_chop,hold_jigg,debug);
    // //
    // //
    // Initialise instrument (in case to isBright): 
    //
    if(phot) {
        SpireProc_Set_PhotMode(obsMode,isBright,version01,version02,debug);
    } else {
        SpireProc_Set_SpecMode(obsMode,isBright,version01,version02,debug);
    }
    //delay(timeSlewCal);
    // //
    // //
    // Set requested frequency and phase plus first bias level:
    //
    SpireProc_Set_DcuFreqSamp(mclkdiv,biasdiv,phot,debug);
    if(phot) {
        SpireProc_Set_PhotPhase(psw_phase,pmw_phase,plw_phase,ptc_phase,debug);
        SpireProc_Set_PhotBias(psw_bias,pmw_bias,plw_bias,ptc_bias,debug);
    } else {
        SpireProc_Set_SpecBias(ssw_bias,slw_bias,debug);
        SpireProc_Set_SpecPhase(ssw_phase,slw_phase,debug);
    }
    // //
    // //
    // Set NHK STEP parameter to count PCAL levels:
    //
    int obsStep = 1;
    SpireProc_Set_ObsStep(obsStep,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB StartPcalLoadCurve configuration ended");
    SpireMsg(1,"  ..StartPcalLoadCurve took " + (time() - t) + " seconds)");
    //
}

// SpireBbSOF2Config
//
// $Id:$
//
// Building Block to configure the instrument for SOF2 operations
//
// The complete instrument setup operation is divided into two parts:
//   Configuration: actions that can be executed during the slew to the start
//          position of the S/C pointing mode.
//   Initialisation: actions that must be carried out at the S/C intial pointing
//          position before any observational operations are executed.   
//
// This building Block implements the first part of the setup: 
//   It assumes the instrument is in the SPECSTBY mode (with SMEC at Home position) 
//   It resete the  SMEC encoder , in case it has lost steps
//   It moves the  SMEC to scan start position in preparation for scanning
//   It sets the detectors to the required configuration for scanning
//
// 28 January 2009 V1.1 KJK
//   Remove Mode setting - now carried out in SpireBb_StartObsAll
//   Remove DRCU Counter resetting - now carried out in SpireBb_StartObsAll
//   Use SpireProc_SmecMove to move into position - assuming SMEC is at Home position
// 22/09/2009 V1.2 KJK:
//   SPR Spire-1978: Use bright source settings if necessary
// 21/10/2009 V1.3 KJK:
//   SPR Spire-2062: remove resetting of SMEC encoder and moving to scan start
//
block SpireBbSOF2Config SPIRE 8384 {
    string obsMode = "Scan";
    string res = "H";
    bool isBright = false in [true,false];
    string comVersion = "v00";
    string smodeVersion = "v00";
    string smecVersion = "v00";
    string specVersion = "v00";
    bool debug = false;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SOF2 Configuration started");
    SpireMsg(2,"          $Id:$");
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // ..... configuration .....
    //
    // set biases and phases - if needed
    //
    if(isBright) {
        SpireProc_Set_SpecBright("Scan",smodeVersion,debug);
    } else {
        if(smodeVersion != "v00") {
            SpireProc_Set_SpecMode("Scan",isBright,smodeVersion,comVersion,debug);
        } else {
            if(comVersion != "v00") {
                SpireProc_Set_SpecMode("Scan",isBright,smodeVersion,comVersion,debug);
            }
        }
    }
    //
    // ..... completion .....
    //
    sync();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SOF2 Configuration ended");
    SpireMsg(1,"  ..SOF2 Configuration (" + (time() - t) + " seconds)");
}

// CVS comments  : $Id:
// Purpose       : Invoke  PACS aot prologue to start the science data flow  
//                 
//
// CUS author    : DAC
// Script file   : Pacs_PHOT_aot_Prologue
//
// Input arguments
// Type                      Description
//
// Return values
// Type    Name      Default      Description
//
// Description   : Perform AOT prologue
//
// Dependencies  : 
//
// Preconditions :
//                 
// Comments      : 
// 
// History       : 0.1 SCR 7005
int[] procedure Pacs_PHOT_aot_Prologue {
    bool verbose = true; // Debug_print or not 
    {int,int,int,int,int,int,int,int,int}[] confPHOTblu = [{0,64,0,0,0,0,0,0,0}]; // BLUE SPU parameters
    {int,int,int,int,int,int,int,int,int}[] confPHOTred = [{0,64,0,0,0,0,0,0,0}]; // RED  SPU parameters
    {int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int}[] confOBCP = [{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}]; // OBCP parameters
    string filter = "blue2"; // PHOT filter
}{
    // Array to collect OBCP times per line
    int duree_num = 0;
    int duree_SRC = 0;
    int duree_REF = 0;
    int duree_CAL = 0;
    int duree_OVR = 0;
    int time_start = time();
    int[] totalDUREE = [0,0,0,0,0];
    // Table of filter wheel positions as per MIB
    // Actually originally not blue1 = SW = POS B, and blue2 = LW = POS A for
    // the photmeter
    if(filter == "blue1") {
        string filterID = "POS B";
    }
    if(filter == "blue2") {
        filterID = "POS A";
    }
    // Long sequence to "unpack" default values from tuples
    int gain_blu = confPHOTblu[0]{0};
    int comp_mode_blu = confPHOTblu[0]{3};
    int nb_raw_blu = confPHOTblu[0]{6};
    int gain_red = confPHOTred[0]{0};
    int comp_mode_red = confPHOTred[0]{3};
    int nb_raw_red = confPHOTred[0]{6};
    int filterPOS = confOBCP[0]{19};
    if(gain_blu == 1 && gain_red == 1) {
        string set_gain = "LOW";
    } else {
        if(gain_blu == 0 || gain_red == 0) {
            set_gain = "HIGH";
        }
    }
    totalDUREE = PHOT_aot_prologue(set_gain,comp_mode_blu,comp_mode_red,nb_raw_blu,nb_raw_red,verbose);
    // Turn the filter wheel
    int timeFLTW = PHOT_fltw_move(filterID);
    //  increment total duration and overheads
    totalDUREE[0] = totalDUREE[0] + timeFLTW;
    totalDUREE[4] = totalDUREE[4] + timeFLTW;
    // Tally total durations
    for(int loop0 = 0 .. 4) {
        totalDUREE[loop0] = totalDUREE[loop0];
    }
    if(verbose) {
        debug_print("***** PHOT AOT prologue (switch on science data) requires " + totalDUREE[0] + " [sec]");
    }
    // Leave bus scheduler in a known state (SP1707)
    sync();

    return totalDUREE;
}

// SpirePhotoPointLogic
//
// $id$
//
// This procedure selectes the SPIRE observing mode and calculates its instrument parameters  
//  for point source observations
//
// This type of observation may be executed using either the POF1 or POF2 observing modes
//
// 10/03/2009 KJK: 
//         SCR 1274, add additional dummy parameters 
//         Update input API to include versions for all cal tables
//  02/07/2009  KJK:
//         Added configuration input parameters to pass to SpirePOF2Config, SpirePOF2Pointing and SpirePOF2End
//  05/07/2009 KJK:
//         SPR-1593 - Updated call to SpirePOF2Pointing
//  04/08/2009 SDS:
//         SPR-1752 - Updated to allow the loading of a new JM07 table (uses the boolean pBool1)
//                    Now references SpireTable_OpsParms.txt (previously OpsParms.txt)
//  12/08/2009 KJK:
//            SPIRE-1804: Added versions and debug as input parameters to enable calling SpirePOF2Pointing and SpirePOF2Observing correctly
//            Changed calls to calibration Tables to use versions
//  25-Aug-2009 KJK:
//        SPR Spire-1641: Needed new input parameters bsmModel and bsmVersion
//  10-Sep-2009 KJK:
//        SCR Spire-1943: Needed new input parameter detVersion
//
{{string,double,double,double,double,bool}[],bool,int,int,int,int} obs SpirePhotoPointLogic {
    double ra = 0.0 in [0.0,360.0]; // RA of Target
    double dec = 0.0 in [-90.0,90.0]; // DEC of Target
    int naifid = 0; // NAIF identifier
    string source = "point" in ["point","small","large"]; // source type
    bool choppingAvoidOn = false; // is chopping avoidance selected
    int choppingAvoidNumber = 0 in [0,3]; // the number of chopping avoid angles selected
    double choppingAvoidFrom1 = 0.0 in [0.0,360.0];
    double choppingAvoidTo1 = 0.0 in [0.0,360.0];
    double choppingAvoidFrom2 = 0.0 in [0.0,360.0];
    double choppingAvoidTo2 = 0.0 in [0.0,360.0];
    double choppingAvoidFrom3 = 0.0 in [0.0,360.0];
    double choppingAvoidTo3 = 0.0 in [0.0,360.0];
    int nRepetitions = 1 in [1,600]; // number of repeats of basic observing cycle
    double sourceFluxPSW = -1.0;
    double sourceFluxPMW = -1.0;
    double sourceFluxPLW = -1.0;
    bool isBright = false;
    string bsmModel = "initial";
    string bsmVersion = "v00";
    string detVersion = "v00"; // Version in cal table SpireTable_DefaultParams.txt
    string spireVersion = "v00"; // Version in cal table SpireTable_SpireParms
    string opsVersion = "v00"; // Version in cal table SpireTable_OpsParms
    string flashVersion = "v00"; // Version in cal table SpireTable_FlashParms
    string chopVersion = "v00"; // Version in cal table SpireTable_ChopParms
    string photVersion = "v00"; // Version in cal table SpireTable_PhotModeParams.txt
    string comVersion = "v00"; // Version in cal table SpireTable_CommonModeParams.txt
    bool debug = false; // debug messages flag
    bool pBool1 = false; // Load 7-Point Jiggle Map Table? 
    bool pBool2 = false; // Spare parameter (currently not in use)
    string pString1 = ""; // Spare parameter (currently not in use)
    string pString2 = ""; // Spare parameter (currently not in use)
    int pInt1 = 0; // Spare parameter (currently not in use) 
    int pInt2 = 0; // Spare parameter (currently not in use) 
    double pDouble1 = 0.0; // Spare parameter (currently not in use)
    double pDouble2 = 0.0; // Spare parameter (currently not in use)
}{
    SpireMsg(0,"Photometric Point Source Observation");
    // *****************
    // check user inputs
    // *****************
    if(source != "point") {
        error("SpirePhotoPointLogic: Source is not a point");
    }
    //
    // *****************
    // set constants
    // *****************
    double yOffset = 0.0;
    // offset to observation position from target in Y direction (arcsecs)
    double zOffset = 0.0;
    // offset to observation position from target in Z direction (arcsecs)
    //
    // declare variables
    //
    int nCycles = 1;
    int nNodPosns = 1;
    int nNodInts = 1;
    int nCal = 99999;
    int nFlash = 99999;
    int tSlewMin = 0;
    int tInitHold = 0;
    int tFinalHold = 0;
    int nMoves = 0;
    int tp = 0;
    int tHold = 0;
    int nHold = 0;
    //
    // *************************************************************
    //  calculate parameters for POF1 observation 
    // *************************************************************
    SpireMsg(1,"  POF1 (Chop without Jiggle) mode parameters");
    //
    //    !!! THIS IS NOT IMPLEMENTED YET !!!
    //
    // *************************************************************
    //  calculate parameters for POF2 observation
    // *************************************************************
    SpireMsg(1,"  POF2 (7-pnt Jiggle Map) mode parameters");
    //
    //
    // *****************
    // constants
    // *****************
    string obsMode = "POF2";
    bool photstby = true;
    //
    // ***** observing mode parameters *****
    {double,int,int,int,int,int} pof2Obs = SpirePOF2Observing(nRepetitions,spireVersion,opsVersion,chopVersion,debug);
    double cycOsit = pof2Obs{0};
    // osit for each nod cycle
    nCycles = pof2Obs{1};
    // number of nod cycles to perform
    nNodPosns = pof2Obs{2};
    nNodInts = pof2Obs{3};
    nCal = pof2Obs{4};
    nFlash = pof2Obs{5};
    //
    // ***** pointing mode timing parameters *****
    {int,int,int,int,int,int} pof2Point = SpirePOF2Pointing(nCycles,nNodInts,nCal,nFlash,isBright,bsmModel,bsmVersion,detVersion,spireVersion,opsVersion,flashVersion,chopVersion,photVersion,comVersion,debug,pBool1);
    tSlewMin = pof2Point{0};
    tInitHold = pof2Point{1};
    tFinalHold = pof2Point{2};
    tp = pof2Point{3};
    tHold = pof2Point{4};
    nHold = pof2Point{5};
    //
    // ***** pointing mode pointing parameters ***** 
    // instrument boresight
    string ib = SpireProc_GetTableEntryString("SpireTable_OpsParms.txt","mode",obsMode,"Boresight",opsVersion,debug);
    // offset to pixel centre from boresight in Y direction (arcsecs)
    double deltaY = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"DeltaY",opsVersion,debug);
    // offset to pixel centre from boresight in Z direction (arcsecs)
    double deltaZ = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"DeltaZ",opsVersion,debug);
    // pattern angle definition
    bool fixed = SpireProc_GetTableEntryBool("SpireTable_OpsParms.txt","mode",obsMode,"Fixed",opsVersion,debug);
    // direction of nod
    double pattNod = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"Patt",opsVersion,debug);
    //
    double chopThrow = SpireProc_GetTableEntryDouble("SpireTable_OpsParms.txt","mode",obsMode,"D1",opsVersion,debug);
    //
    int[] ts = nodding_pointing(true,tSlewMin,tInitHold,tFinalHold,ib,naifid,ra,dec,fixed,pattNod,yOffset + deltaY,zOffset + deltaZ,nCycles * nNodPosns / 2,chopThrow,tp,tp,0,0,tHold,nHold,false);
    //
    // ***** choose observing mode *****
    //
    bool isJiggleMap = true;
    SpireMsg(1,"  Using POF2 (7-pnt Jiggle Map) Observing Mode");
}{
    // *******************************
    // return instrument parameters
    // *******************************
    //
    {string,double,double,double,double,bool}[] estimates = [];
    //
    if(isJiggleMap) {
        double osit = cycOsit * double(nCycles);
        estimates = SpirePOF2Estimate(osit,sourceFluxPSW,sourceFluxPMW,sourceFluxPLW,isBright);
        nCycles = pof2Obs{1};
        // number of nod cycles to perform
        nNodInts = pof2Obs{3};
        nCal = pof2Obs{4};
        nFlash = pof2Obs{5};
    } else {
    }
    //
    SpireMsg(3,"     Spire Photometry Pointing Mode parameters:");
    SpireMsg(3,"     ..estimates: " + estimates);
    SpireMsg(3,"     ..isJiggleMap: " + isJiggleMap);
    SpireMsg(3,"     ..nCycles: " + nCycles);
    SpireMsg(3,"     ..nNodInts: " + nNodInts);
    SpireMsg(3,"     ..nCal: " + nCal);
    SpireMsg(3,"     ..nFlash: " + nFlash);

    return {estimates,isJiggleMap,nCycles,nNodInts,nCal,nFlash};
}

// Missionphase  : AOT validation
//
// Purpose	: Setup SPU for photometry data flow
//
// Author	: VDP / Bart Vandenbussche
//
// Arguments	: 
//
// Description	: Configures photometry compression /reduction mode and (optionally) starts 
//                     reduction/compression and GAIN
//                  
// Dependencies : 
//
// Comments	:
//
// Version	: 2.0
//               
// History	: 1.0 created from PHOT_spu_setup
// 		      needed to set Gain for LowGain obs 
//		      implementation: SCR4196 i.e. gain and bit rounding
//		      compression mode etc..
//		  2.0 25-feb-2009 VD implement decimation new SPU function
//                2.1 24-mar-2009 DAC Renamed spr1 & spr2 to rnd & rnds;
//                                syncd to syncdel as per SPU UM 13.95a 
//
int procedure PHOT_spu_gain_setup {
    string set_gain = "LOW" in ["HIGH","LOW"]; // Gain Blue settings: default = LOW
    int comp_mode_blu = 0; //  Compression blue: default=0, double=1, half=2, lossless=4, transp=7, buffer=9
    int comp_mode_red = 0; //  Compression blue: default=0, double=1, half=2, lossless=4, transp=7, buffer=9
    int nraw_blu = 3; // Number of raw channels transmitted in the blue SPU
    int nraw_red = 3; // Number of raw channels transmitted in the red SPU
    bool startSPU = true; // Start SPU or not [true,false]
}{
    string calU = "CONF_PHOT_params";
    if(set_gain == "LOW") {
        string col_calU = "BrightPacs";
    } else {
        if(set_gain == "HIGH") {
            col_calU = "Prime";
        }
    }
    int duration_msec = 0;
    // Stop the Long and Short SPUs
    Pacs_SPUS_STOP_REDUCT_COMPR();
    Pacs_SPUL_STOP_REDUCT_COMPR();
    // Set gain
    Pacs_BOLC_SET_GAIN(set_gain);
    // Set the SPU compression modes
    int[] aux = [comp_mode_blu,comp_mode_red];
    int check_sum = checksum("int",aux);
    // Issue the TC
    {int}[] comp_par = Array2grp_1(aux);
    Pacs_DMC_WRT_SPU_TRAN_MODE(comp_par,check_sum);
    // Setting of start index of raw channels for SPUS and SPUL
    string spus_obs_mode = "PHOT";
    string spul_obs_mode = "PHOT";
    int spus_startraw = ilookup(calU,"startraw_blu",col_calU);
    int spul_startraw = ilookup(calU,"startraw_red",col_calU);
    Pacs_SPUS_RAW_CHAN_TRAN_MODE(spus_obs_mode,nraw_blu,spus_startraw);
    Pacs_SPUL_RAW_CHAN_TRAN_MODE(spul_obs_mode,nraw_red,spul_startraw);
    // Photo "Ottensamer" block ("S" SPU)
    // PPF: Pre-Processing Flag (0: no PP, 1: addition, 2: subtraction, 
    //                           3: multiplication, 4: division)
    int ppf = ilookup(calU,"pre_proc_f_blu",col_calU);
    // PPP: Pre-Processing Parameter
    int ppp = ilookup(calU,"pre_proc_p_blu",col_calU);
    // Threshold for glitch detection in photometry
    int tfp = ilookup(calU,"glitch_thres_blu",col_calU);
    // Threshold for chopper position deviation in photometry
    int tcp = ilookup(calU,"chop_dev_thres_blu",col_calU);
    // Glitch detection for photometry (1: no glitch detection)
    int gdfp = ilookup(calU,"glitch_det_blu",col_calU);
    // Override samples to average
    int navg = ilookup(calU,"navg_blu",col_calU);
    int rnd = ilookup(calU,"rnd_blu",col_calU);
    // resolution reduction parameter 2 RND!!!
    //    int spr1 = 0; defined as function of the set_gain value
    // resolution reduction parameter 3
    int rnds = ilookup(calU,"rnds_blu",col_calU);
    // Lossless scheme
    int scm = ilookup(calU,"scm_blu",col_calU);
    // lossless compression algoithm (0,1,2,3,4)
    int lcal = ilookup(calU,"lcal_blu",col_calU);
    // PACS Codec Order (3,4)
    int pcod = ilookup(calU,"pcod_blu",col_calU);
    // PACS Decimation
    // discard samples at the beginning of each averaged groups
    int dpre = ilookup(calU,"dpre_blu",col_calU);
    // discard samples at the nd of each averaged groups
    int dpost = ilookup(calU,"dpost_blu",col_calU);
    int syncdel = ilookup(calU,"syncdel_blu",col_calU);
    // Spare elements: 10 spare element; hardcoded as 0,0,... in operand
    // Create operand
    aux = [ppf,ppp,tfp,tcp,gdfp,navg,rnd,rnds,scm,lcal,pcod,dpre,dpost,syncdel,0,0,0,0,0,0,0,0,0,0];
    check_sum = checksum("int",aux);
    // Convert to grp_1 syntax
    {int}[] spu_par = Array2grp_1(aux);
    // Issue TC
    Pacs_SPUS_WRT_DET_CST_PHOT(spu_par,check_sum);
    delay(1);
    // Photo "Ottensamer" block ("L" SPU)
    // PPF: Pre-Processing Flag (0: no PP, 1: addition, 2: subtraction, 
    //                           3: multiplication, 4: division)
    ppf = ilookup(calU,"pre_proc_f_red",col_calU);
    // PPP: Pre-Processing Parameter
    ppp = ilookup(calU,"pre_proc_p_red",col_calU);
    // Threshold for glitch detection in photometry
    tfp = ilookup(calU,"glitch_thres_red",col_calU);
    // Threshold for chopper position deviation in photometry
    tcp = ilookup(calU,"chop_dev_thres_red",col_calU);
    // Glitch detection for photometry (1: no glitch detection)
    gdfp = ilookup(calU,"glitch_det_red",col_calU);
    // Override samples to average
    navg = ilookup(calU,"navg_red",col_calU);
    rnd = ilookup(calU,"rnd_red",col_calU);
    // resolution reduction parameter 2 RND!!!
    //    int spr1 = 0; defined as function of the set_gain value
    // resolution reduction parameter 3
    rnds = ilookup(calU,"rnds_red",col_calU);
    // Lossless scheme
    scm = ilookup(calU,"scm_red",col_calU);
    // lossless compression algoithm (0,1,2,3,4)
    lcal = ilookup(calU,"lcal_red",col_calU);
    // PACS Codec Order (3,4)
    pcod = ilookup(calU,"pcod_red",col_calU);
    // PACS Decimation
    // discard samples at the beginning of each averaged groups
    dpre = ilookup(calU,"dpre_red",col_calU);
    // discard samples at the nd of each averaged groups
    dpost = ilookup(calU,"dpost_red",col_calU);
    syncdel = ilookup(calU,"syncdel_red",col_calU);
    // Spare elements: 10 spare element; hardcoded as 0,0,... in operand
    // Create operand
    aux = [ppf,ppp,tfp,tcp,gdfp,navg,rnd,rnds,scm,lcal,pcod,dpre,dpost,syncdel,0,0,0,0,0,0,0,0,0,0];
    check_sum = checksum("int",aux);
    // Convert to grp_1 syntax
    spu_par = Array2grp_1(aux);
    // Issue TC
    Pacs_SPUL_WRT_DET_CST_PHOT(spu_par,check_sum);
    delay(1);
    // Send time stamps
    // DMC_WRT_TIME: Write the time sent by the DPU into the DMC buffer
    // (No action on this one?)
    // DPU sends the time to DEC/MEC
    Pacs_DPU_SEND_TIME();
    // DMC_SET_TIME: Set the time previously written by the write time command
    Pacs_DMC_SET_TIME();
    // Start reduction/compression if commanded to do so
    if(startSPU) {
        Pacs_SPUS_START_REDUCT_COMPR();
        Pacs_SPUL_START_REDUCT_COMPR();
    }

    return duration_msec;
}

// SpirePacsBbParallelInit
//
// $Id:$
//
// Building Block to initialise the instrument for Parallel operation
//
// The complete instrument setup operation is divided into two parts:
//   Configuration: actions that can be executed during the slew to the start
//          position of the S/C pointing mode.
//   Initialisation: actions that must be carried out at the S/C intial pointing
//          position before any observational operations are executed.   
//
// This building Block implements the second part of the setup 
// 
// 04 November 2008: first version
// 25-Aug-2009 KJK:
//               - Added sync() command
//               - Added debug input parameter
//               - read datarates from new Cal Table (SpireTable_Datarates.txt)
// 15/09/2009 KJK: added obsMode as input parameter
//
block SpirePacsBbParallelInit SPIRE 8337 {
    string obsMode = "Par_F_N";
    bool debug = false;
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Parallel Initialisation started");
    SpireMsg(2,"          $Id:$");
    //
    // ..... configuration .....
    //
    int cmd = 0x0;
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP  to On Target
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x8000)");
    Spire_SET_OBS_STEP_RAW(0x8000);
    //
    // set detector offsets
    //
    // set DCU data mode  to Auto Offset 
    cmd = 0x843c0010;
    SpireSendDrcuCmd(cmd,0);
    // start auto offset generation
    cmd = 0x843e0001;
    SpireSendDrcuCmd(cmd,0);
    delay(15);
    //
    // dump detector offsets
    // stop auto offset generation
    cmd = 0x843e0000;
    SpireSendDrcuCmd(cmd,0);
    // set DCU data mode to get offset data
    cmd = 0x843c0018;
    SpireSendDrcuCmd(cmd,0);
    // start offset data dump
    cmd = 0x843e0001;
    SpireSendDrcuCmd(cmd,0);
    //  set datarate
    double rate = 0.0;
    rate = SpireProc_GetTableEntryDouble("SpireTable_Datarates.txt","mode","POffsets","DCU","v00",debug);
    data_rate(rate);
    delay(5);
    // stop offset data dump 
    cmd = 0x843e0000;
    SpireSendDrcuCmd(cmd,0);
    data_rate(0.0);
    //
    // flush data
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(2);
    //
    //  set up detectors for operations
    //
    SpireConfigDcuData(obsMode);
    //
    sync();
    //
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB Parallel Initialisation ended");
    SpireMsg(1,"  ..Parallel Initialisation (" + (time() - t) + " seconds)");
}

///////////////////////////////////////////////////////////////////////////
// $Id: $
///////////////////////////////////////////////////////////////////////////
// 
// SpireBb_SpecFSetPhase.txt
//
///////////////////////////////////////////////////////////////////////////
//  
// BB to set phase of spectrometer arrays
//
///////////////////////////////////////////////////////////////////////////
//
// M.Pohlen:
// 2008/08/11 V0.1: Initial version adapted from 
//                  SpireBb_PhotFSetPhase (V0.3 2008/07/04) using 
//                  SF_Phase.txt (v 1.4 2008/01/31 20:24:37) 
// 2009/02/19 V0.2: Instead of using commands call SpireProc_Set_SpecPhase
//                  and add sync() after setBbId. Add HSpot messages. 
//                  Add debug_print. Remove unsetting of BBID at end.
//
///////////////////////////////////////////////////////////////////////////
//
block SpireBb_SpecFSetPhase SPIRE 14012 {
    int ssw_phase = 0x0 in [0,255]; //Default phase is 0 [Hex]
    int slw_phase = 0x0 in [0,255]; //Default phase is 0 [Hex]
    bool debug = false; // Allow (==tick) or suppress cus debug_print statements
}{
    // //
    // //
    // Define some variables:
    //
    string hstr = "";
    // a hex string
    string tstr = "";
    // a time string
    // //
    // //
    // Start BB:
    //
    int t = time();
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": SpireBb_SpecFSetPhase started");
    SpireMsg(2,"          $Id: $");
    hstr = SpireHexStr($BBID,8);
    SpireMsg(3,"          BBID = " + hstr);
    // //
    // //
    // Set the BBs to SPIRE bbid:
    //
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID(" + hstr + ")");
    Spire_SET_BBID($BBID);
    sync();
    // //
    // //
    // Set the phase for the two arrays:
    //
    SpireProc_Set_SpecPhase(ssw_phase,slw_phase,debug);
    // //
    // //
    // End BB:
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB SpireBb_SpecFSetPhase ended");
    SpireMsg(1,"  ..Set Phot phases (" + (time() - t) + " secs)");
    //
}

// SpireBbPOF5Init
//
// $Id:$
//
// Building Block to initialise the instrument for POF5 (scan map) operation
//
// The complete instrument setup operation is divided into two parts:
//   Configuration: actions that can be executed during the slew to the start
//          position of the S/C pointing mode.
//   Initialisation: actions that must be carried out at the S/C intial pointing
//          position before any observational operations are executed.   
//
// This building Block implements the second part of the setup 
// 
// 04 November 2008: 
//         added data_rate commands
//         added commands to setup the detector sampling
//
block SpireBbPOF5Init SPIRE 8273 {
    string obsMode = "POF5_F_N";
}{
    int t = time();
    string hstr = "";
    // hex string
    string tstr = "";
    // time string
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF5 Initialisation started");
    SpireMsg(2,"          $Id:$");
    //
    // ..... configuration .....
    //
    int cmd = 0x0;
    //
    // Set BBID
    hstr = SpireHexStr($BBID,8);
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_BBID_RAW(" + hstr + ")");
    Spire_SET_BBID_RAW($BBID);
    //
    // set STEP  to On Target
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_SET_OBS_STEP_RAW(0x8000)");
    Spire_SET_OBS_STEP_RAW(0x8000);
    //
    // set detector offsets
    // set DCU data mode  to Auto Offset 
    cmd = 0x843c0010;
    SpireSendDrcuCmd(cmd,0);
    // start auto offset generation
    cmd = 0x843e0001;
    SpireSendDrcuCmd(cmd,0);
    delay(15);
    //
    // dump detector offsets
    // stop auto offset generation
    cmd = 0x843e0000;
    SpireSendDrcuCmd(cmd,0);
    // set DCU data mode to get offset data
    cmd = 0x843c0018;
    SpireSendDrcuCmd(cmd,0);
    // start offset data dump
    cmd = 0x843e0001;
    SpireSendDrcuCmd(cmd,0);
    //  set datarate
    double rate = 0.0;
    rate = dlookup("Datarates.txt","POffsets","DCU");
    data_rate(rate);
    delay(5);
    // stop offset data dump 
    cmd = 0x843e0000;
    SpireSendDrcuCmd(cmd,0);
    data_rate(0.0);
    //
    // flush data
    tstr = SpireTimeStr(time());
    SpireMsg(5,"          " + tstr + "Cmd: Spire_FLUSH_FIFO_RAW(0x1000)");
    Spire_FLUSH_FIFO_RAW(0x1000);
    delay(2);
    //
    //  set up detectors for operations
    //
    SpireConfigDcuData(obsMode);
    sync();
    //
    // ..... completion .....
    //
    tstr = SpireTimeStr(time());
    SpireMsg(2,"    " + tstr + ": BB POF5 Initialisation ended");
    SpireMsg(1,"  ..POF5 Initialisation (" + (time() - t) + " seconds)");
}

