]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/scpi-pps/profiles.c
scpi-pps: Add configurable sr_mqflags.
[libsigrok.git] / src / hardware / scpi-pps / profiles.c
index c9ddd61ecb24448a1ba752543d0ef0b9322965ca..a83e0396d2619b58bd15cf4915155e835a02316c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
  * Copyright (C) 2015 Google, Inc.
  * (Written by Alexandru Gagniuc <mrnuke@google.com> for Google, Inc.)
- * Copyright (C) 2017 Frank Stettner <frank-stettner@gmx.net>
+ * Copyright (C) 2017,2019 Frank Stettner <frank-stettner@gmx.net>
  *
  * 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
@@ -48,7 +48,7 @@ static const uint32_t agilent_n5700a_devopts_cg[] = {
 };
 
 static const struct channel_group_spec agilent_n5700a_cg[] = {
-       { "1", CH_IDX(0), PPS_OVP | PPS_OCP },
+       { "1", CH_IDX(0), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
 };
 
 static const struct channel_spec agilent_n5767a_ch[] = {
@@ -109,9 +109,9 @@ static const struct channel_spec bk_9130_ch[] = {
 };
 
 static const struct channel_group_spec bk_9130_cg[] = {
-       { "1", CH_IDX(0), PPS_OVP },
-       { "2", CH_IDX(1), PPS_OVP },
-       { "3", CH_IDX(2), PPS_OVP },
+       { "1", CH_IDX(0), PPS_OVP, SR_MQFLAG_DC },
+       { "2", CH_IDX(1), PPS_OVP, SR_MQFLAG_DC },
+       { "3", CH_IDX(2), PPS_OVP, SR_MQFLAG_DC },
 };
 
 static const struct scpi_command bk_9130_cmd[] = {
@@ -156,7 +156,7 @@ static const struct channel_spec chroma_61604_ch[] = {
 };
 
 static const struct channel_group_spec chroma_61604_cg[] = {
-       { "1", CH_IDX(0), PPS_OVP | PPS_OCP },
+       { "1", CH_IDX(0), PPS_OVP | PPS_OCP, SR_MQFLAG_AC },
 };
 
 static const struct scpi_command chroma_61604_cmd[] = {
@@ -199,7 +199,7 @@ static const uint32_t chroma_62000_devopts_cg[] = {
 };
 
 static const struct channel_group_spec chroma_62000_cg[] = {
-       { "1", CH_IDX(0), PPS_OVP | PPS_OCP },
+       { "1", CH_IDX(0), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
 };
 
 static const struct scpi_command chroma_62000_cmd[] = {
@@ -305,7 +305,7 @@ static const struct channel_spec rigol_dp712_ch[] = {
 };
 
 static const struct channel_group_spec rigol_dp700_cg[] = {
-       { "1", CH_IDX(0), PPS_OVP | PPS_OCP },
+       { "1", CH_IDX(0), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
 };
 
 /* Same as the DP800 series, except for the missing :SYST:OTP* commands. */
@@ -383,14 +383,14 @@ static const struct channel_spec rigol_dp832_ch[] = {
 };
 
 static const struct channel_group_spec rigol_dp820_cg[] = {
-       { "1", CH_IDX(0), PPS_OVP | PPS_OCP },
-       { "2", CH_IDX(1), PPS_OVP | PPS_OCP },
+       { "1", CH_IDX(0), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
+       { "2", CH_IDX(1), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
 };
 
 static const struct channel_group_spec rigol_dp830_cg[] = {
-       { "1", CH_IDX(0), PPS_OVP | PPS_OCP },
-       { "2", CH_IDX(1), PPS_OVP | PPS_OCP },
-       { "3", CH_IDX(2), PPS_OVP | PPS_OCP },
+       { "1", CH_IDX(0), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
+       { "2", CH_IDX(1), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
+       { "3", CH_IDX(2), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
 };
 
 static const struct scpi_command rigol_dp800_cmd[] = {
@@ -458,8 +458,12 @@ static const uint32_t hp_6630b_devopts_cg[] = {
        SR_CONF_CURRENT | SR_CONF_GET,
        SR_CONF_VOLTAGE_TARGET | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
        SR_CONF_CURRENT_LIMIT | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+       SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE | SR_CONF_GET,
        SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
        SR_CONF_OVER_CURRENT_PROTECTION_ENABLED | SR_CONF_GET | SR_CONF_SET,
+       SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE | SR_CONF_GET,
+       SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE | SR_CONF_GET,
+       SR_CONF_REGULATION | SR_CONF_GET,
 };
 
 static const struct channel_spec hp_6633a_ch[] = {
@@ -487,7 +491,7 @@ static const struct channel_spec hp_6634b_ch[] = {
 };
 
 static const struct channel_group_spec hp_663xx_cg[] = {
-       { "1", CH_IDX(0), 0 },
+       { "1", CH_IDX(0), 0, SR_MQFLAG_DC },
 };
 
 static const struct scpi_command hp_6630a_cmd[] = {
@@ -518,11 +522,187 @@ static const struct scpi_command hp_6630b_cmd[] = {
        { SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ENABLED, ":CURR:PROT:STAT?" },
        { SCPI_CMD_SET_OVER_CURRENT_PROTECTION_ENABLE, ":CURR:PROT:STAT 1" },
        { SCPI_CMD_SET_OVER_CURRENT_PROTECTION_DISABLE, ":CURR:PROT:STAT 0" },
+       { SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ACTIVE, "STAT:QUES:COND?" },
+       { SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ACTIVE, "STAT:QUES:COND?" },
        { SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_THRESHOLD, ":VOLT:PROT?" },
        { SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_THRESHOLD, ":VOLT:PROT %.6f" },
+       { SCPI_CMD_GET_OVER_TEMPERATURE_PROTECTION_ACTIVE, "STAT:QUES:COND?" },
+       { SCPI_CMD_GET_OUTPUT_REGULATION, "STAT:OPER:COND?" },
        ALL_ZERO
 };
 
+static int hp_6630b_init_aquisition(const struct sr_dev_inst *sdi)
+{
+       struct sr_scpi_dev_inst *scpi;
+       int ret;
+
+       scpi = sdi->conn;
+
+       /*
+        * Monitor CV (256), CC+ (1024) and CC- (2048) bits of the
+        * Operational Status Register.
+        * Use both positive and negative transitions of the status bits.
+        */
+       ret = sr_scpi_send(scpi, "STAT:OPER:PTR 3328;NTR 3328;ENAB 3328");
+       if (ret != SR_OK)
+               return ret;
+
+       /*
+        * Monitor OVP (1), OCP (2), OTP (16) and Unreg (1024) bits of the
+        * Questionable Status Register.
+        * Use both positive and negative transitions of the status bits.
+        */
+       ret = sr_scpi_send(scpi, "STAT:QUES:PTR 1043;NTR 1043;ENAB 1043");
+       if (ret != SR_OK)
+               return ret;
+
+       /*
+        * Service Request Enable Register set for Operational Status Register
+        * bits (128) and Questionable Status Register bits (8).
+        * This masks the Status Register generating a SRQ/RQS. Not implemented yet!
+        */
+       /*
+       ret = sr_scpi_send(scpi, "*SRE 136");
+       if (ret != SR_OK)
+               return ret;
+       */
+
+       return SR_OK;
+}
+
+static int hp_6630b_update_status(const struct sr_dev_inst *sdi)
+{
+       struct sr_scpi_dev_inst *scpi;
+       int ret;
+       int stb;
+       int ques_even, ques_cond;
+       int oper_even, oper_cond;
+       gboolean output_enabled;
+       gboolean unreg, cv, cc_pos, cc_neg;
+       gboolean regulation_changed;
+       char *regulation;
+
+       scpi = sdi->conn;
+
+       unreg = FALSE;
+       cv = FALSE;
+       cc_pos = FALSE;
+       cc_neg = FALSE;
+       regulation_changed = FALSE;
+
+       /*
+        * Use SPoll when SCPI uses GPIB as transport layer.
+        * SPoll is approx. twice as fast as a normal GPIB write + read would be!
+        */
+#ifdef HAVE_LIBGPIB
+       char spoll_buf;
+
+       if (scpi->transport == SCPI_TRANSPORT_LIBGPIB) {
+               ret = sr_scpi_gpib_spoll(scpi, &spoll_buf);
+               if (ret != SR_OK)
+                       return ret;
+               stb = (uint8_t)spoll_buf;
+       }
+       else {
+#endif
+               ret = sr_scpi_get_int(scpi, "*STB?", &stb);
+               if (ret != SR_OK)
+                       return ret;
+#ifdef HAVE_LIBGPIB
+       }
+#endif
+
+       /* Questionable status summary bit */
+       if (stb & (1 << 3)) {
+               /* Read the event register to clear it! */
+               ret = sr_scpi_get_int(scpi, "STAT:QUES:EVEN?", &ques_even);
+               if (ret != SR_OK)
+                       return ret;
+               /* Now get the values. */
+               ret = sr_scpi_get_int(scpi, "STAT:QUES:COND?", &ques_cond);
+               if (ret != SR_OK)
+                       return ret;
+
+               /* OVP */
+               if (ques_even & (1 << 0))
+                       sr_session_send_meta(sdi, SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE,
+                               g_variant_new_boolean(ques_cond & (1 << 0)));
+
+               /* OCP */
+               if (ques_even & (1 << 1))
+                       sr_session_send_meta(sdi, SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE,
+                               g_variant_new_boolean(ques_cond & (1 << 1)));
+
+               /* OTP */
+               if (ques_even & (1 << 4))
+                       sr_session_send_meta(sdi, SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE,
+                               g_variant_new_boolean(ques_cond & (1 << 4)));
+
+               /* UNREG */
+               unreg = (ques_cond & (1 << 10));
+               regulation_changed = (ques_even & (1 << 10)) | regulation_changed;
+
+               /*
+                * Check if output state has changed, due to one of the
+                * questionable states changed.
+                * NOTE: The output state is send even if it hasn't changed, but that
+                * only happends rarely.
+                */
+               ret = sr_scpi_get_bool(scpi, "OUTP:STAT?", &output_enabled);
+               if (ret != SR_OK)
+                       return ret;
+               sr_session_send_meta(sdi, SR_CONF_ENABLED,
+                       g_variant_new_boolean(output_enabled));
+       }
+
+       /* Operation status summary bit */
+       if (stb & (1 << 7)) {
+               /* Read the event register to clear it! */
+               ret = sr_scpi_get_int(scpi, "STAT:OPER:EVEN?", &oper_even);
+               if (ret != SR_OK)
+                       return ret;
+               /* Now get the values. */
+               ret = sr_scpi_get_int(scpi, "STAT:OPER:COND?", &oper_cond);
+               if (ret != SR_OK)
+                       return ret;
+
+               /* CV */
+               cv = (oper_cond & (1 << 8));
+               regulation_changed = (oper_even & (1 << 8)) | regulation_changed;
+               /* CC+ */
+               cc_pos = (oper_cond & (1 << 10));
+               regulation_changed = (oper_even & (1 << 10)) | regulation_changed;
+               /* CC- */
+               cc_neg = (oper_cond & (1 << 11));
+               regulation_changed = (oper_even & (1 << 11)) | regulation_changed;
+       }
+
+       if (regulation_changed) {
+               if (cv && !cc_pos && !cc_neg &&!unreg)
+                       regulation = "CV";
+               else if (cc_pos && !cv && !cc_neg && !unreg)
+                       regulation = "CC";
+               else if (cc_neg && !cv && !cc_pos && !unreg)
+                       regulation = "CC-";
+               else if (unreg && !cv && !cc_pos && !cc_neg)
+                       regulation = "UR";
+               else if (!cv && !cc_pos && !cc_neg &&!unreg)
+                       /* This happends in case of OCP active */
+                       regulation = "";
+               else {
+                       /* This happends from time to time (CV and CC+ active). */
+                       sr_dbg("Undefined regulation for HP 66xxB "
+                               "(CV=%i, CC+=%i, CC-=%i, UR=%i).",
+                               cv, cc_pos, cc_neg, unreg);
+                       return FALSE;
+               }
+               sr_session_send_meta(sdi, SR_CONF_REGULATION,
+                       g_variant_new_string(regulation));
+       }
+
+       return SR_OK;
+}
+
 /* Philips/Fluke PM2800 series */
 static const uint32_t philips_pm2800_devopts[] = {
        SR_CONF_CONTINUOUS,
@@ -646,6 +826,7 @@ static int philips_pm2800_probe_channels(struct sr_dev_inst *sdi,
                (*channel_groups)[i].name = (char *)philips_pm2800_names[i];
                (*channel_groups)[i].channel_index_mask = 1 << i;
                (*channel_groups)[i].features = PPS_OTP | PPS_OVP | PPS_OCP;
+               (*channel_groups)[i].mqflags = SR_MQFLAG_DC;
        }
        *num_channels = *num_channel_groups = num_modules;
 
@@ -698,9 +879,9 @@ static const struct channel_spec rs_hmc8043_ch[] = {
 };
 
 static const struct channel_group_spec rs_hmc8043_cg[] = {
-       { "1", CH_IDX(0), PPS_OVP },
-       { "2", CH_IDX(1), PPS_OVP },
-       { "3", CH_IDX(2), PPS_OVP },
+       { "1", CH_IDX(0), PPS_OVP, SR_MQFLAG_DC },
+       { "2", CH_IDX(1), PPS_OVP, SR_MQFLAG_DC },
+       { "3", CH_IDX(2), PPS_OVP, SR_MQFLAG_DC },
 };
 
 static const struct scpi_command rs_hmc8043_cmd[] = {
@@ -732,6 +913,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                ARRAY_AND_SIZE(agilent_n5700a_cg),
                agilent_n5700a_cmd,
                .probe_channels = NULL,
+               .init_aquisition = NULL,
+               .update_status = NULL,
        },
 
        /* Agilent N5767A */
@@ -742,6 +925,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                ARRAY_AND_SIZE(agilent_n5700a_cg),
                agilent_n5700a_cmd,
                .probe_channels = NULL,
+               .init_aquisition = NULL,
+               .update_status = NULL,
        },
 
        /* BK Precision 9310 */
@@ -752,6 +937,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                ARRAY_AND_SIZE(bk_9130_cg),
                bk_9130_cmd,
                .probe_channels = NULL,
+               .init_aquisition = NULL,
+               .update_status = NULL,
        },
 
        /* Chroma 61604 */
@@ -762,6 +949,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                ARRAY_AND_SIZE(chroma_61604_cg),
                chroma_61604_cmd,
                .probe_channels = NULL,
+               .init_aquisition = NULL,
+               .update_status = NULL,
        },
 
        /* Chroma 62000 series */
@@ -772,6 +961,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                NULL, 0,
                chroma_62000_cmd,
                .probe_channels = chroma_62000p_probe_channels,
+               .init_aquisition = NULL,
+               .update_status = NULL,
        },
 
        /* HP 6633A */
@@ -782,6 +973,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                ARRAY_AND_SIZE(hp_663xx_cg),
                hp_6630a_cmd,
                .probe_channels = NULL,
+               .init_aquisition = NULL,
+               .update_status = NULL,
        },
 
        /* HP 6631B */
@@ -792,6 +985,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                ARRAY_AND_SIZE(hp_663xx_cg),
                hp_6630b_cmd,
                .probe_channels = NULL,
+               hp_6630b_init_aquisition,
+               hp_6630b_update_status,
        },
 
        /* HP 6632B */
@@ -802,6 +997,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                ARRAY_AND_SIZE(hp_663xx_cg),
                hp_6630b_cmd,
                .probe_channels = NULL,
+               hp_6630b_init_aquisition,
+               hp_6630b_update_status,
        },
 
        /* HP 66332A */
@@ -812,6 +1009,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                ARRAY_AND_SIZE(hp_663xx_cg),
                hp_6630b_cmd,
                .probe_channels = NULL,
+               hp_6630b_init_aquisition,
+               hp_6630b_update_status,
        },
 
        /* HP 6633B */
@@ -822,6 +1021,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                ARRAY_AND_SIZE(hp_663xx_cg),
                hp_6630b_cmd,
                .probe_channels = NULL,
+               hp_6630b_init_aquisition,
+               hp_6630b_update_status,
        },
 
        /* HP 6634B */
@@ -832,6 +1033,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                ARRAY_AND_SIZE(hp_663xx_cg),
                hp_6630b_cmd,
                .probe_channels = NULL,
+               hp_6630b_init_aquisition,
+               hp_6630b_update_status,
        },
 
        /* Rigol DP700 series */
@@ -842,6 +1045,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                ARRAY_AND_SIZE(rigol_dp700_cg),
                rigol_dp700_cmd,
                .probe_channels = NULL,
+               .init_aquisition = NULL,
+               .update_status = NULL,
        },
        { "Rigol", "^DP712$", SCPI_DIALECT_UNKNOWN, 0,
                ARRAY_AND_SIZE(rigol_dp700_devopts),
@@ -850,6 +1055,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                ARRAY_AND_SIZE(rigol_dp700_cg),
                rigol_dp700_cmd,
                .probe_channels = NULL,
+               .init_aquisition = NULL,
+               .update_status = NULL,
        },
 
        /* Rigol DP800 series */
@@ -860,6 +1067,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                ARRAY_AND_SIZE(rigol_dp820_cg),
                rigol_dp800_cmd,
                .probe_channels = NULL,
+               .init_aquisition = NULL,
+               .update_status = NULL,
        },
        { "Rigol", "^DP831A$", SCPI_DIALECT_UNKNOWN, PPS_OTP,
                ARRAY_AND_SIZE(rigol_dp800_devopts),
@@ -868,6 +1077,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                ARRAY_AND_SIZE(rigol_dp830_cg),
                rigol_dp800_cmd,
                .probe_channels = NULL,
+               .init_aquisition = NULL,
+               .update_status = NULL,
        },
        { "Rigol", "^(DP832|DP832A)$", SCPI_DIALECT_UNKNOWN, PPS_OTP,
                ARRAY_AND_SIZE(rigol_dp800_devopts),
@@ -876,6 +1087,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                ARRAY_AND_SIZE(rigol_dp830_cg),
                rigol_dp800_cmd,
                .probe_channels = NULL,
+               .init_aquisition = NULL,
+               .update_status = NULL,
        },
 
        /* Philips/Fluke PM2800 series */
@@ -886,6 +1099,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                NULL, 0,
                philips_pm2800_cmd,
                philips_pm2800_probe_channels,
+               .init_aquisition = NULL,
+               .update_status = NULL,
        },
 
        /* Rohde & Schwarz HMC8043 */
@@ -896,6 +1111,8 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
                ARRAY_AND_SIZE(rs_hmc8043_cg),
                rs_hmc8043_cmd,
                .probe_channels = NULL,
+               .init_aquisition = NULL,
+               .update_status = NULL,
        },
 };