///
/// @file sequence.c
/// @authors k. Headley
/// @date 05 dec 2019

/// Carbon Waveglider IO sequencing API

/// @sa doxygen-examples.c for more examples of Doxygen markup


/////////////////////////
// Terms of use
/////////////////////////
/*
 Copyright Information

 Copyright 2002-2019 MBARI
 Monterey Bay Aquarium Research Institute, all rights reserved.

 Terms of Use

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version. You can access the GPLv3 license at
 http://www.gnu.org/licenses/gpl-3.0.html

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details
 (http://www.gnu.org/licenses/gpl-3.0.html)

 MBARI provides the documentation and software code "as is", with no warranty,
 express or implied, as to the software, title, non-infringement of third party
 rights, merchantability, or fitness for any particular purpose, the accuracy of
 the code, or the performance or results which you may obtain from its use. You
 assume the entire risk associated with use of the code, and you agree to be
 responsible for the entire cost of repair or servicing of the program with
 which you are using the code.

 In no event shall MBARI be liable for any damages, whether general, special,
 incidental or consequential damages, arising out of your use of the software,
 including, but not limited to, the loss or corruption of your data or damages
 of any kind resulting from use of the software, any prohibited use, or your
 inability to use the software. You agree to defend, indemnify and hold harmless
 MBARI and its officers, directors, and employees against any claim, loss,
 liability or expense, including attorneys' fees, resulting from loss of or
 damage to property or the injury to or death of any person arising out of the
 use of the software.

 The MBARI software is provided without obligation on the part of the
 Monterey Bay Aquarium Research Institute to assist in its use, correction,
 modification, or enhancement.

 MBARI assumes no responsibility or liability for any third party and/or
 commercial software required for the database or applications. Licensee agrees
 to obtain and maintain valid licenses for any additional third party software
 required.
 */

/////////////////////////
// Headers
/////////////////////////
#include <string.h>
#include "cwg-shared.h"
#include "cwgsys.h"
#include "ioserial.h"
#include "iodigital.h"
#include "timers.h"
#include "sequence.h"
/////////////////////////
// Macros
/////////////////////////

// These macros should only be defined for
// application main files rather than general C files
/*
/// @def PRODUCT
/// @brief header software product name
#define PRODUCT "carbonwg"

/// @def COPYRIGHT
/// @brief header software copyright info
#define COPYRIGHT "Copyright 2002-2019 MBARI Monterey Bay Aquarium Research Institute, all rights reserved."
/// @def NOWARRANTY
/// @brief header software terms of use
#define NOWARRANTY  \
"This program is distributed in the hope that it will be useful,\n"\
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"\
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"\
"GNU General Public License for more details (http://www.gnu.org/licenses/gpl-3.0.html)\n"
*/

/////////////////////////
// Declarations
/////////////////////////

/////////////////////////
// Imports
/////////////////////////

/////////////////////////
// Module Global Variables
/////////////////////////
#ifdef MANIFOLD_V0

const seq_actuation_t seq_actuation_table[] ={
    {"+AIR",MXB_AIPUMP,ACT_ON},
    {"-AIR",MXB_AIPUMP,ACT_OFF},
    {"+SEA",MXB_SWPUMP,ACT_ON},
    {"-SEA",MXB_SWPUMP,ACT_OFF},
    {"+LI",MXB_LICOR,ACT_ON},
    {"-LI",MXB_LICOR,ACT_OFF},
    {"+IOPURGE",MPURGE_VSET,ACT_VALVE_HL},
    {"-IOPURGE",MPURGE_VCLR,ACT_VALVE_HL},
    {"+IOFILL",MFILL_VSET,ACT_VALVE_HL},
    {"-IOFILL",MFILL_VCLR,ACT_VALVE_HL},
    {"SAPUMP",(MXB_SAPUMP),ACT_PUMP_HL},
    {"ACPUMP",(MXB_ACPUMP),ACT_PUMP_HL},
    {"+IOZERO",MZERO_VSET,ACT_VALVE_HL},
    {"-IOZERO",MZERO_VCLR,ACT_VALVE_HL},
    {"+IOZVENT",MZERO_VENT_VSET,ACT_VALVE_HL},
    {"-IOZVENT",MZERO_VENT_VCLR,ACT_VALVE_HL},
    {"+IOZCAL",MZCAL_VSET,ACT_VALVE_HL},
    {"-IOZCAL",MZCAL_VCLR,ACT_VALVE_HL},
    {"+IOSZERO",MSZERO_VENT_VSET,ACT_VALVE_HL},
    {"-IOSZERO",MSZERO_VCLR,ACT_VALVE_HL},
    {"+IOSZVENT",MSZERO_VENT_VSET,ACT_VALVE_HL},
    {"-IOSZVENT",MSZERO_VENT_VCLR,ACT_VALVE_HL},
    {"+IOSAMPLE",MSAMPLE_VSET,ACT_VALVE_HL},
    {"-IOSAMPLE",MSAMPLE_VCLR,ACT_VALVE_HL},
    {"+IOAIR",MAIR_VSET,ACT_VALVE_HL},
    {"-IOAIR",MAIR_VCLR,ACT_VALVE_HL},
    {"+IOSTD",MSTD_VSET,ACT_VALVE_HL},
    {"-IOSTD",MSTD_VCLR,ACT_VALVE_HL},
    {"+IOSTDFILL",MSTD_FILL_VSET,ACT_VALVE_HL},
    {"-IOSTDFILL",MSTD_FILL_VCLR,ACT_VALVE_HL},
    {"+IOREST",MREST_VSET,ACT_VALVE_HL},
    {"-IOREST",MREST_VCLR,ACT_VALVE_HL},
    {NULL,0,0}
};

const seq_param_t seq_param_table[] ={
    // FILL
    {{0,0,MFILL_SWPUMP_DON_MSEC},1},
    {{MFILL_SAPUMP_TON_MSEC,MFILL_SAPUMP_TOFF_MSEC,0},MFILL_SAPUMP_CYC},
    // PURGE
    {{0,0,MPURGE_AIPUMP_DON_MSEC},1},
    // ACID
    {{MACID_ACPUMP_TON_MSEC,MACID_ACPUMP_TOFF_MSEC,0},MACID_ACPUMP_CYC},
    // ZERO
    {{0,0,MZERO_AIPUMP_DON_MSEC},1},
    // ZCAL
    {{0,0,MZCAL_AIPUMP_DON_MSEC},1},
     // SZERO
    {{0,0,MSZERO_AIPUMP_DON_MSEC},1},
    // SAMPLE
    // AIR
    {{0,0,MAIR_AIPUMP_DON_MSEC},1},
    // STD
    {{0,0,MSTD_AIPUMP_DON_MSEC},1},
    // Power default
    {{0,0,0},1},
    // valve default
    {{MX_VALVE_TON_MSEC,0,0},1},
    // Licor default
    {{0,0,MX_LI_BLANK_MSEC},1}
};

const sequence_step_t seq_def_table[] ={
    // FILL
    {&seq_actuation_table[AIO_FILL_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_SWPUMP_ON],&seq_param_table[APAR_FILL_SWPUMP]},
    {&seq_actuation_table[AIO_SAPUMP],&seq_param_table[APAR_FILL_SAPUMP]},
    {&seq_actuation_table[AIO_SWPUMP_OFF],&seq_param_table[APAR_POWER_DFL]},
    // PURGE
    {&seq_actuation_table[AIO_PURGE_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_ON],&seq_param_table[APAR_PURGE_AIPUMP]},
    {&seq_actuation_table[AIO_AIPUMP_OFF],&seq_param_table[APAR_POWER_DFL]},
    // ACID
    {&seq_actuation_table[AIO_ACPUMP],&seq_param_table[APAR_ACPUMP]},
    // ZERO
    {&seq_actuation_table[AIO_ZERO_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_ON],&seq_param_table[APAR_ZERO_AIPUMP]},
    {&seq_actuation_table[AIO_ZERO_VENT_VCLR],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_OFF],&seq_param_table[APAR_POWER_DFL]},
    // ZCAL
    {&seq_actuation_table[AIO_ZCAL_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_ON],&seq_param_table[APAR_ZCAL_AIPUMP]},
    // SZERO
    {&seq_actuation_table[AIO_SZERO_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_ON],&seq_param_table[APAR_SZERO_AIPUMP]},
    {&seq_actuation_table[AIO_SZERO_VENT_VCLR],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_OFF],&seq_param_table[APAR_POWER_DFL]},
    // SAMPLE
    {&seq_actuation_table[AIO_SAMPLE_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_ON],&seq_param_table[APAR_POWER_DFL]},
    {&seq_actuation_table[AIO_LICOR_ON],&seq_param_table[APAR_LICOR_DFL]},
    // AIR
    {&seq_actuation_table[AIO_AIR_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_ON],&seq_param_table[APAR_POWER_DFL]},
    {&seq_actuation_table[AIO_LICOR_ON],&seq_param_table[APAR_LICOR_DFL]},
     // STD
    {&seq_actuation_table[AIO_STD_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_FILL_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_ON],&seq_param_table[APAR_POWER_DFL]},
    {&seq_actuation_table[AIO_LICOR_ON],&seq_param_table[APAR_STD_LICOR]},
    // MTERM
    {&seq_actuation_table[AIO_AIPUMP_OFF],&seq_param_table[APAR_POWER_DFL]},
    {&seq_actuation_table[AIO_LICOR_OFF],&seq_param_table[APAR_POWER_DFL]},
     // REST
    {&seq_actuation_table[AIO_REST_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_OFF],&seq_param_table[APAR_POWER_DFL]},
    {&seq_actuation_table[AIO_LICOR_OFF],&seq_param_table[APAR_POWER_DFL]}
};

const sequence_t seq_table[] ={
    // PURGE sequence definition
    {"FILL",4,&seq_def_table[0]},
    {"PURGE",3,&seq_def_table[4]},
    {"ACID",1,&seq_def_table[7]},
    {"ZERO",4,&seq_def_table[8]},
    {"ZCAL",2,&seq_def_table[12]},
    {"SZERO",4,&seq_def_table[14]},
    {"SAMPLE",3,&seq_def_table[18]},
    {"AIR",3,&seq_def_table[21]},
    {"STD",4,&seq_def_table[24]},
    {"MTERM",2,&seq_def_table[28]},
    {"REST",3,&seq_def_table[30]},
    {NULL,0,NULL}
};
#endif

#ifdef MANIFOLD_V1
/// @var const seq_actuation_t seq_actuation_table[]
/// @brief actuation IO lookup table
/// lookup by key (name string) using
/// or index (ACT_IO_IDX_t)
const seq_actuation_t seq_actuation_table[] ={
    {"+AIPUMP",MXB_AIPUMP,ACT_ON},
    {"-AIPUMP",MXB_AIPUMP,ACT_OFF},
    {"+SWPUMP",MXB_SWPUMP,ACT_ON},
    {"-SWPUMP",MXB_SWPUMP,ACT_OFF},
    {"+LI",MXB_LICOR,ACT_ON},
    {"-LI",MXB_LICOR,ACT_OFF},
    {"+UL",MXB_XCVR_LICOR,ACT_ON},
    {"-UL",MXB_XCVR_LICOR,ACT_OFF},
    {"+IOPURGE",MPURGE_VSET,ACT_VALVE_HL},
    {"-IOPURGE",MPURGE_VCLR,ACT_VALVE_HL},
    {"+IOFILL",MFILL_VSET,ACT_VALVE_HL},
    {"-IOFILL",MFILL_VCLR,ACT_VALVE_HL},
    {"SAPUMP",(MXB_SAPUMP),ACT_PUMP_HL},
    {"ACPUMP",(MXB_ACPUMP),ACT_PUMP_HL},
    {"+IOZERO",MZERO_VSET,ACT_VALVE_HL},
    {"-IOZERO",MZERO_VCLR,ACT_VALVE_HL},
    {"+IOZVENT",MZERO_VENT_VSET,ACT_VALVE_HL},
    {"-IOZVENT",MZERO_VENT_VCLR,ACT_VALVE_HL},
    {"+IOZCAL",MZCAL_VSET,ACT_VALVE_HL},
    {"-IOZCAL",MZCAL_VCLR,ACT_VALVE_HL},
    {"+IOSZERO",MSZERO_VENT_VSET,ACT_VALVE_HL},
    {"-IOSZERO",MSZERO_VCLR,ACT_VALVE_HL},
    {"+IOSZVENT",MSZERO_VENT_VSET,ACT_VALVE_HL},
    {"-IOSZVENT",MSZERO_VENT_VCLR,ACT_VALVE_HL},
    {"+IOSAMPLE",MSAMPLE_VSET,ACT_VALVE_HL},
    {"-IOSAMPLE",MSAMPLE_VCLR,ACT_VALVE_HL},
    {"+IOAIR",MAIR_VSET,ACT_VALVE_HL},
    {"-IOAIR",MAIR_VCLR,ACT_VALVE_HL},
    {"+IOSTD",MSTD_VSET,ACT_VALVE_HL},
    {"-IOSTD",MSTD_VCLR,ACT_VALVE_HL},
    {"+IOSTDFILL",MSTD_FILL_VSET,ACT_VALVE_HL},
    {"-IOSTDFILL",MSTD_FILL_VCLR,ACT_VALVE_HL},
    {"+IOREST",MREST_VSET,ACT_VALVE_HL},
    {"-IOREST",MREST_VCLR,ACT_VALVE_HL},
    {"+IOVEX1",MVEX_S1_VSET,ACT_VALVE_HL},
    {"+IOVEX2",MVEX_S2_VSET,ACT_VALVE_HL},
    {"+IOVEX3",MVEX_S3_VSET,ACT_VALVE_HL},
    {"+IOVEX4",MVEX_S4_VSET,ACT_VALVE_HL},
    {"+IOVEX5",MVEX_S5_VSET,ACT_VALVE_HL},
    {"+IOVEX6",MVEX_S6_VSET,ACT_VALVE_HL},
    {"+IOVEX7",MVEX_S7_VSET,ACT_VALVE_HL},
    {"+IOVEX8",MVEX_S8_VSET,ACT_VALVE_HL},
    {"+IOSCAL",MSCAL_VSET,ACT_VALVE_HL},
    {"-IOSCAL",MSCAL_VCLR,ACT_VALVE_HL},
    {"+IOSCALGAS",MSCAL_GAS_VSET,ACT_VALVE_HL},
    {"-IOSCALGAS",MSCAL_GAS_VCLR,ACT_VALVE_HL},
    {NULL,0,0}
};

const seq_param_t seq_param_table[] ={
    // FILL
    {{0,0,MFILL_SWPUMP_DON_MSEC},1},
    {{MFILL_SAPUMP_TON_MSEC,MFILL_SAPUMP_TOFF_MSEC,0},MFILL_SAPUMP_CYC},
    // PURGE
    {{0,0,MPURGE_AIPUMP_DON_MSEC},1},
    // ACID
    {{MACID_ACPUMP_TON_MSEC,MACID_ACPUMP_TOFF_MSEC,0},MACID_ACPUMP_CYC},
    // ZERO
    {{0,0,MZERO_AIPUMP_DON_MSEC},1},
    // ZCAL
    {{0,0,MZCAL_AIPUMP_DON_MSEC},1},
    {{0,0,MZCAL_AIPUMP_DOFF_MSEC},1},
     // SZERO
    {{0,0,MSZERO_AIPUMP_DON_MSEC},1},
    // SAMPLE
     {{0,0,MSAMPLE_AIPUMP_DON_MSEC},1},
    // AIR
    {{0,0,MAIR_AIPUMP_DON_MSEC},1},
    {{0,0,MAIR_AIPUMP_DOFF_MSEC},1},
    // STD
    {{0,0,MSTD_AIPUMP_DON_MSEC},1},
    // VEX
    {{MVEX_PUL_MSEC,0,0},1},
    // SCAL
    {{MSCAL_VALVE_TON_MSEC,0,MSCAL_GAS_PUMP_DON_MSEC},1},
    {{MSCAL_VALVE_TON_MSEC,0,MSCAL_WAIT_DON_MSEC},1},
    // Power default
    {{0,0,0},1},
    // valve default
    {{MX_VALVE_TON_MSEC,0,0},1},
    // Licor default
    {{0,0,MX_BLANK_MSEC},1},
    // Licor cal
    {{0,0,MX_CAL_TON_MSEC},1}
};

const sequence_step_t seq_def_table[] ={
    // FILL
    {&seq_actuation_table[AIO_FILL_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_SWPUMP_ON],&seq_param_table[APAR_FILL_SWPUMP]},
    {&seq_actuation_table[AIO_SAPUMP],&seq_param_table[APAR_FILL_SAPUMP]},
    {&seq_actuation_table[AIO_SWPUMP_OFF],&seq_param_table[APAR_POWER_DFL]},
    // PURGE
    {&seq_actuation_table[AIO_PURGE_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_ON],&seq_param_table[APAR_PURGE_AIPUMP]},
    {&seq_actuation_table[AIO_AIPUMP_OFF],&seq_param_table[APAR_POWER_DFL]},
    // ACID
    {&seq_actuation_table[AIO_ACPUMP],&seq_param_table[APAR_ACPUMP]},
    // ZERO
    {&seq_actuation_table[AIO_ZERO_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_ON],&seq_param_table[APAR_ZERO_AIPUMP]},
//    {&seq_actuation_table[AIO_ZERO_VENT_VCLR],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_OFF],&seq_param_table[APAR_POWER_DFL]},
    // ZCAL
    {&seq_actuation_table[AIO_ZCAL_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_ON],&seq_param_table[APAR_ZCAL_AIPUMP_ON]},
    {&seq_actuation_table[AIO_AIPUMP_OFF],&seq_param_table[APAR_ZCAL_AIPUMP_OFF]},
    {&seq_actuation_table[AIO_LICOR_ON],&seq_param_table[APAR_LICOR_CAL]},
    // SZERO
    {&seq_actuation_table[AIO_SZERO_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_ON],&seq_param_table[APAR_SZERO_AIPUMP]},
    {&seq_actuation_table[AIO_SZERO_VENT_VCLR],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_OFF],&seq_param_table[APAR_POWER_DFL]},
    // SAMPLE
    {&seq_actuation_table[AIO_SAMPLE_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_ON],&seq_param_table[APAR_SAMPLE_AIPUMP_ON]},
    {&seq_actuation_table[AIO_LICOR_ON],&seq_param_table[APAR_LICOR_DFL]},
    // AIR
    {&seq_actuation_table[AIO_AIR_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_ON],&seq_param_table[APAR_AIR_AIPUMP_ON]},
    {&seq_actuation_table[AIO_AIPUMP_OFF],&seq_param_table[APAR_AIR_AIPUMP_OFF]},
    {&seq_actuation_table[AIO_LICOR_ON],&seq_param_table[APAR_LICOR_DFL]},
     // STD
    {&seq_actuation_table[AIO_STD_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_FILL_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_ON],&seq_param_table[APAR_STD_AIPUMP_ON]},
    {&seq_actuation_table[AIO_LICOR_ON],&seq_param_table[APAR_LICOR_DFL]},
    // MTERM
    {&seq_actuation_table[AIO_AIPUMP_OFF],&seq_param_table[APAR_POWER_DFL]},
    {&seq_actuation_table[AIO_LICOR_OFF],&seq_param_table[APAR_POWER_DFL]},
     // REST
    {&seq_actuation_table[AIO_REST_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_AIPUMP_OFF],&seq_param_table[APAR_POWER_DFL]},
    {&seq_actuation_table[AIO_LICOR_OFF],&seq_param_table[APAR_POWER_DFL]},
     // VEX
    {&seq_actuation_table[AIO_VEX_S1_VSET],&seq_param_table[APAR_VEX_VALVE_DFL]},
    {&seq_actuation_table[AIO_VEX_S2_VSET],&seq_param_table[APAR_VEX_VALVE_DFL]},
    {&seq_actuation_table[AIO_VEX_S3_VSET],&seq_param_table[APAR_VEX_VALVE_DFL]},
    {&seq_actuation_table[AIO_VEX_S4_VSET],&seq_param_table[APAR_VEX_VALVE_DFL]},
    {&seq_actuation_table[AIO_VEX_S5_VSET],&seq_param_table[APAR_VEX_VALVE_DFL]},
    {&seq_actuation_table[AIO_VEX_S6_VSET],&seq_param_table[APAR_VEX_VALVE_DFL]},
    {&seq_actuation_table[AIO_VEX_S7_VSET],&seq_param_table[APAR_VEX_VALVE_DFL]},
    {&seq_actuation_table[AIO_VEX_S8_VSET],&seq_param_table[APAR_VEX_VALVE_DFL]},
    // SCAL
    {&seq_actuation_table[AIO_SCAL_VSET],&seq_param_table[APAR_VALVE_DFL]},
    {&seq_actuation_table[AIO_SCAL_GAS_VSET],&seq_param_table[APAR_SCAL_GAS]},
    {&seq_actuation_table[AIO_SCAL_GAS_VCLR],&seq_param_table[APAR_SCAL_WAIT]},
    {&seq_actuation_table[AIO_LICOR_ON],&seq_param_table[APAR_LICOR_CAL]},
};

#define FILL_STEPS   4
#define PURGE_STEPS  3
#define ACID_STEPS   1
#define ZERO_STEPS   3
#define ZCAL_STEPS   4
#define SZERO_STEPS  4
#define SAMPLE_STEPS 3
#define AIR_STEPS    4
#define STD_STEPS    4
#define MTERM_STEPS  2
#define REST_STEPS   3
#define VEX_STEPS    8
#define SCAL_STEPS   4

typedef enum {
    FILL_OFS=0,
    PURGE_OFS=(FILL_OFS+FILL_STEPS),
    ACID_OFS=(PURGE_OFS+PURGE_STEPS),
    ZERO_OFS=(ACID_OFS+ACID_STEPS),
    ZCAL_OFS=(ZERO_OFS+ZERO_STEPS),
    SZERO_OFS=(ZCAL_OFS+ZCAL_STEPS),
    SAMPLE_OFS=(SZERO_OFS+SZERO_STEPS),
    AIR_OFS=(SAMPLE_OFS+SAMPLE_STEPS),
    STD_OFS=(AIR_OFS+AIR_STEPS),
    MTERM_OFS=(STD_OFS+STD_STEPS),
    REST_OFS=(MTERM_OFS+MTERM_STEPS),
    VEX_OFS=(REST_OFS+REST_STEPS),
    SCAL_OFS=(VEX_OFS+VEX_STEPS)
}seq_table_ofs_t;

const sequence_t seq_table[] ={
    // PURGE sequence definition
    {"FILL",  FILL_STEPS,&seq_def_table[FILL_OFS]},
    {"PURGE", PURGE_STEPS,&seq_def_table[PURGE_OFS]},
    {"ACID",  ACID_STEPS,&seq_def_table[ACID_OFS]},
    {"ZERO",  ZERO_STEPS,&seq_def_table[ZERO_OFS]},
    {"ZCAL",  ZCAL_STEPS,&seq_def_table[ZCAL_OFS]},
    {"SZERO", SZERO_STEPS,&seq_def_table[SZERO_OFS]},
    {"SAMPLE",SAMPLE_STEPS,&seq_def_table[SAMPLE_OFS]},
    {"AIR",   AIR_STEPS,&seq_def_table[AIR_OFS]},
    {"STD",   STD_STEPS,&seq_def_table[STD_OFS]},
    {"MTERM", MTERM_STEPS,&seq_def_table[MTERM_OFS]},
    {"REST",  REST_STEPS,&seq_def_table[REST_OFS]},
    {"VEX",   VEX_STEPS,&seq_def_table[VEX_OFS]},
    {"SCAL",  SCAL_STEPS,&seq_def_table[SCAL_OFS]},
    {NULL,0,NULL}
};
#endif

#define SEQ_SCOUNT(sidx) ( sidx >=0 && sidx<SEQ_COUNT ? seq_table[sidx].s_count : -1)
#define SEQ_PSEQ(sidx)) ( sidx >=0 && sidx<SEQ_COUNT ? &seq_table[sidx] : NULL)

/////////////////////////
// Function Definitions
/////////////////////////

static void seq_sub_logic(seq_param_t *dest, const seq_param_t *src, ATIM_SUB_FLAGS_t flags)
{
    if(NULL!=src && NULL!=dest){
        if( (flags&ATSF_P0) && src->timing[ATIM_P0]>=0)
            dest->timing[ATIM_P0] = src->timing[ATIM_P0];
        if( (flags&ATSF_P1) && src->timing[ATIM_P1]>=0)
            dest->timing[ATIM_P1] = src->timing[ATIM_P1];
        if( (flags&ATSF_D) && src->timing[ATIM_DELAY]>=0)
             dest->timing[ATIM_DELAY] = src->timing[ATIM_DELAY];
        if( (flags&ATSF_C) && src->cycles>=0)
            dest->cycles = src->cycles;
    }
}

void seq_param_show(const seq_param_t *self, uint16_t indent)
{
    if(NULL!=self){
        int wkey=12;
        int wval=20;
        OUT_CTTY("%*s%*s  %*s%03d/%03d/%03d\r\n",indent,"",wkey,"p0/p1/delay",wval-11,"",self->timing[0],self->timing[1],self->timing[2]);
        OUT_CTTY("%*s%*s  %*s%04d\r\n",indent,"",wkey,"cycles",wval-4,"",self->cycles);
    }
}

void seq_actuation_show(const seq_actuation_t *self, uint16_t indent)
{
    if(NULL!=self){
        int wkey=12;
        int wval=20;
        OUT_CTTY("%*s%*s  %*s\r\n",indent,"",wkey,"name",wval,self->name);
        OUT_CTTY("%*s%*s  %*s%08lX\r\n",indent,"",wkey,"iomask",wval-8,"",self->iomask);
        OUT_CTTY("%*s%*s  %*d\r\n",indent,"",wkey,"act",wval,self->act);
    }
}

void sequence_show(const sequence_t *self, uint16_t indent)
{
    if(NULL!=self){
        int wkey=12;
        int wval=20;
        OUT_CTTY("%*s%*s  %*s\r\n",indent,"",wkey,"name",wval,self->name);
        OUT_CTTY("%*s%*s  %*u\r\n",indent,"",wkey,"s_count",wval,self->s_count);
        if(NULL!=self->steps){
            int i=0;
            for(i=0;i<self->s_count;i++){
                seq_actuation_show(self->steps[i].act_io,indent+2);
                seq_param_show(self->steps[i].act_param,indent+2);
                if(i<(self->s_count-1))OUT_CTTY("\r\n");
            }
        }
    }
}

void meas_profile_show(const meas_profile_t *self, uint16_t indent)
{
    if(NULL!=self){
        int wkey=12;
        int wval=20;
        OUT_CTTY("%*s%*s %*"FMT_U16"\r\n",indent,"",wkey,"rtid",wval,self->rtid);
        OUT_CTTY("%*s%*s %*"FMT_U16"\r\n",indent,"",wkey,"rmid",wval,self->rmid);
        OUT_CTTY("%*s%*s %*"FMT_U16"\r\n",indent,"",wkey,"mmid",wval,self->mmid);
        OUT_CTTY("%*s%*s %*"FMT_U32"\r\n",indent,"",wkey,"blank_ms",wval,self->blank_ms);
        OUT_CTTY("%*s%*s %*"FMT_U32"\r\n",indent,"",wkey,"meas_n",wval,self->meas_n);
        OUT_CTTY("%*s%*s %*"FMT_U32"\r\n",indent,"",wkey,"meas_ms",wval,self->meas_ms);
        OUT_CTTY("%*s%*s %*.3f\r\n",indent,"",wkey,"period_s",wval,self->period_s);
        OUT_CTTY("%*s%*s %*"FMT_U32"\r\n",indent,"",wkey,"to_msec",wval,self->to_msec);
        OUT_CTTY("%*s%*s %*"FMT_U16"\r\n",indent,"",wkey,"cal_wr",wval,self->cal_wr);
        OUT_CTTY("%*s%*s %*"FMT_U16"\r\n",indent,"",wkey,"op_id",wval,self->op_id);
    }
}

const seq_actuation_t *seq_actuation_slookup(const char *key)
{
    const seq_actuation_t *retval=NULL;
    const seq_actuation_t *next=seq_actuation_table;
    while(NULL!=next && NULL!=next->name){
        if(strcmp(next->name,key)==0){
            retval=next;
            break;
        }
        next++;
    }
    return retval;
}

const seq_actuation_t *seq_actuation_ilookup(ACT_IO_IDX_t key)
{
    const seq_actuation_t *retval=NULL;
    if(key>=0 && key<AIO_IDX_COUNT)
        retval=&seq_actuation_table[key];

    return retval;
}

const sequence_t *seq_slookup(const char *key)
{
    const sequence_t *retval = NULL;
    const sequence_t *next = seq_table;
    while(NULL!=next && NULL!=next->name){
        if(strcmp(key,next->name)==0){
            retval=next;
            break;
        }
        next++;
    }
    return retval;
}

const sequence_t *seq_ilookup(SEQ_IDX_t key)
{
    const sequence_t *retval=NULL;
    if(key>=0 && key<SEQ_IDX_COUNT)
        retval=&seq_table[key];

    return retval;
}

//int seq_io_assert(ACT_IO_IDX_t id, IODIR_t dir)
//{
//  int retval=-1;
//  if(id>=0 && id<AIO_IDX_COUNT){
//      MX_ASSERT(seq_actuation_table[id].iomask,dir);
//      retval=0;
//  }
//  return retval;
//}

uint32_t seq_actuation_sbits(const char *key)
{
  uint32_t retval=0;

  const seq_actuation_t *next=seq_actuation_table;
  while(NULL!=next){
      if(NULL!=next->name && strcmp(next->name,key)==0){
        retval=next->iomask;
        break;
      }
      next++;
  }
  return retval;
}

uint32_t seq_actuation_ibits(ACT_IO_IDX_t key)
{
  uint32_t retval=0;
  if(key>=0 && key<AIO_IDX_COUNT){
      retval=seq_actuation_table[key].iomask;
  }
  return retval;
}

int seq_actuation_run(const seq_actuation_t *self, const seq_param_t *params)
{
    int retval=-1;

    if(NULL!=self && NULL!=params){
        int i=0;
        retval=0;
        switch(self->act){
            case ACT_VALVE_HL:
                MX_PULSE_HILO(self->iomask,params->timing[ATIM_P0],params->timing[ATIM_P1]);
                break;
            case ACT_VALVE_LH:
                MX_PULSE_LOHI(self->iomask,params->timing[ATIM_P0],params->timing[ATIM_P1]);
                break;
            case ACT_PUMP_HL:
                for(i=0;i<params->cycles;i++)
                MX_PULSE_HILO(self->iomask,params->timing[ATIM_P0],params->timing[ATIM_P1]);
                 break;
            case ACT_PUMP_LH:
                for(i=0;i<params->cycles;i++)
                MX_PULSE_LOHI(self->iomask,params->timing[ATIM_P0],params->timing[ATIM_P1]);
                break;
            case ACT_ON:
                MX_ON(self->iomask);
                break;
            case ACT_OFF:
                 MX_OFF(self->iomask);
               break;
            default:
                retval=-1;
                break;
        }
        // does nothing if delay <=0
        MX_DELAY(params->timing[ATIM_DELAY]);
    }
    return retval;
}

int seq_run(const sequence_t *self, seq_param_t *alt_pump, seq_param_t *alt_valve)
{
    int retval=-1;
    if(NULL!=self && self->s_count>0){
        int i=0;
        for(i=0;i<self->s_count;i++){
            const seq_actuation_t *action = self->steps[i].act_io;

            seq_param_t pump_logic = {{0},0};
            seq_param_t valve_logic = {{0},0};
            const seq_param_t *step_logic=self->steps[i].act_param;
            const seq_param_t *xlogic=NULL;

            if(NULL!=action && NULL!=step_logic){

                switch(action->act){
                   case ACT_VALVE_HL:
                      MPRINT(MOD_SEQ,"ACT_VALVE_LH\r\n");
                      memcpy( &valve_logic, step_logic, sizeof(seq_param_t));
                       seq_sub_logic(&valve_logic, alt_valve, (ATSF_P0|ATSF_P1));
                       xlogic=&valve_logic;
                       break;
                   case ACT_VALVE_LH:
                      MPRINT(MOD_SEQ,"ACT_VALVE_LH\r\n");
                      memcpy( &valve_logic, step_logic, sizeof(seq_param_t));
                       seq_sub_logic(&valve_logic, alt_valve, (ATSF_P0|ATSF_P1));
                       xlogic=&valve_logic;
                       break;
                   case ACT_PUMP_HL:
                         MPRINT(MOD_SEQ,"ACT_PUMP_HL\r\n");
                      memcpy( &pump_logic, step_logic, sizeof(seq_param_t));
                       seq_sub_logic(&pump_logic, alt_pump, (ATSF_P0|ATSF_P1|ATSF_C));
                       xlogic=&pump_logic;
                       break;
                   case ACT_PUMP_LH:
                        MPRINT(MOD_SEQ,"ACT_PUMP_LH\r\n");
                      memcpy( &pump_logic, step_logic, sizeof(seq_param_t));
                       seq_sub_logic(&pump_logic, alt_pump, (ATSF_P0|ATSF_P1|ATSF_C));
                       xlogic=&pump_logic;
                       break;
                   case ACT_ON:
                       MPRINT(MOD_SEQ,"ACT_ON\r\n");
                       xlogic=step_logic;
                       break;
                   case ACT_OFF:
                       MPRINT(MOD_SEQ,"ACT_OFF\r\n");
                      xlogic=step_logic;
                      break;
                   case ACT_NONE:
                   default:
                       MPRINT(MOD_SEQ,"ACT_NONE/default\r\n");
                      break;
                }
                if(NULL!=xlogic){
                    if(MOD_SEQ&g_mdebug_flags){
                        OUT_CTTY("iobits %07lX\r\n",action->iomask);
                        seq_param_show(xlogic,5);
                    }
                    int test=seq_actuation_run(action,xlogic);
                    retval+=(test==0 ? 0 : -1);
                }else{ OUT_CTTY("NULL xlogic\r\n"); }
            }else{ OUT_CTTY("NULL sequence/step_logic\r\n"); }
        }
    }
    return retval;
}

//int seq_logic_copy(seq_param_t *dest, const sequence_t *src, uint16_t len)
//{
//    int retval=-1;
//    if(NULL!=dest && NULL!=src && len<=src->s_count){
//        memset(dest,0,len*sizeof(seq_param_t));
//        int j=0;
//        for(j=0;j<len;j++){
//            memcpy(&dest[j],src->steps[j].act_param,sizeof(seq_param_t));
//        }
//        retval=0;
//    }
//    return retval;
//}
