X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fhardware%2Fdevantech-eth008%2Fapi.c;h=9bace4eaa4dc938eb55fdcbf0f910f1ed57852ce;hb=204dd31fa1074a78fbe3bf04208776a4a3615a1c;hp=8411d9adc1f0e9e874b78ef61499b97ede6b40ba;hpb=c12ca361e724ed1e04c659420d74dd68efe345a9;p=libsigrok.git
diff --git a/src/hardware/devantech-eth008/api.c b/src/hardware/devantech-eth008/api.c
index 8411d9ad..9bace4ea 100644
--- a/src/hardware/devantech-eth008/api.c
+++ b/src/hardware/devantech-eth008/api.c
@@ -17,120 +17,355 @@
* along with this program. If not, see .
*/
-#include
+#include "config.h"
+
+#include
+
#include "protocol.h"
-static struct sr_dev_driver devantech_eth008_driver_info;
+#define VENDOR_TEXT "Devantech"
-static GSList *scan(struct sr_dev_driver *di, GSList *options)
-{
- struct drv_context *drvc;
- GSList *devices;
+static const uint32_t scanopts[] = {
+ SR_CONF_CONN,
+};
+
+static const uint32_t drvopts[] = {
+ SR_CONF_MULTIPLEXER,
+};
- (void)options;
+static const uint32_t devopts[] = {
+ SR_CONF_CONN | SR_CONF_GET,
+ SR_CONF_ENABLED | SR_CONF_SET, /* Enable/disable all relays at once. */
+};
- devices = NULL;
- drvc = di->context;
- drvc->instances = NULL;
+static const uint32_t devopts_cg_do[] = {
+ SR_CONF_ENABLED | SR_CONF_GET | SR_CONF_SET,
+};
+
+static const uint32_t devopts_cg_di[] = {
+ SR_CONF_ENABLED | SR_CONF_GET,
+};
+
+static const uint32_t devopts_cg_ai[] = {
+ SR_CONF_VOLTAGE | SR_CONF_GET,
+};
+
+/* List of supported devices. Sorted by model ID. */
+static const struct devantech_eth008_model models[] = {
+ { 18, "ETH002", 2, 0, 0, 0, 1, 0, 0, },
+ { 19, "ETH008", 8, 0, 0, 0, 1, 0, 0, },
+ { 20, "ETH484", 16, 8, 4, 0, 2, 2, 0x00f0, },
+ { 21, "ETH8020", 20, 8, 8, 0, 3, 4, 0, },
+ { 22, "WIFI484", 16, 8, 4, 0, 2, 2, 0x00f0, },
+ { 24, "WIFI8020", 20, 8, 8, 0, 3, 4, 0, },
+ { 26, "WIFI002", 2, 0, 0, 0, 1, 0, 0, },
+ { 28, "WIFI008", 8, 0, 0, 0, 1, 0, 0, },
+ { 52, "ETH1610", 10, 16, 16, 0, 2, 2, 0, },
+};
- /* TODO: scan for devices, either based on a SR_CONF_CONN option
- * or on a USB scan. */
+static const struct devantech_eth008_model *find_model(uint8_t code)
+{
+ size_t idx;
+ const struct devantech_eth008_model *check;
+
+ for (idx = 0; idx < ARRAY_SIZE(models); idx++) {
+ check = &models[idx];
+ if (check->code != code)
+ continue;
+ return check;
+ }
- return devices;
+ return NULL;
}
-static int dev_open(struct sr_dev_inst *sdi)
+static struct sr_dev_driver devantech_eth008_driver_info;
+
+static struct sr_dev_inst *probe_device_conn(const char *conn)
{
- (void)sdi;
+ struct sr_dev_inst *sdi;
+ struct dev_context *devc;
+ struct sr_serial_dev_inst *ser;
+ uint8_t code, hwver, fwver;
+ const struct devantech_eth008_model *model;
+ gboolean has_serno_cmd;
+ char snr_txt[16];
+ struct channel_group_context *cgc;
+ size_t ch_idx, nr, do_idx, di_idx, ai_idx;
+ struct sr_channel_group *cg;
+ char cg_name[24];
+ int ret;
+
+ sdi = g_malloc0(sizeof(*sdi));
+ devc = g_malloc0(sizeof(*devc));
+ sdi->priv = devc;
+ ser = sr_serial_dev_inst_new(conn, NULL);
+ sdi->conn = ser;
+ if (!ser)
+ goto probe_fail;
+ ret = serial_open(ser, 0);
+ if (ret != SR_OK)
+ goto probe_fail;
+
+ ret = devantech_eth008_get_model(ser, &code, &hwver, &fwver);
+ if (ret != SR_OK)
+ goto probe_fail;
+ model = find_model(code);
+ if (!model) {
+ sr_err("Unknown model ID 0x%02x (HW %u, FW %u).",
+ code, hwver, fwver);
+ goto probe_fail;
+ }
+ devc->model_code = code;
+ devc->hardware_version = hwver;
+ devc->firmware_version = fwver;
+ devc->model = model;
+ sdi->vendor = g_strdup(VENDOR_TEXT);
+ sdi->model = g_strdup(model->name);
+ sdi->version = g_strdup_printf("HW%u FW%u", hwver, fwver);
+ sdi->connection_id = g_strdup(conn);
+ sdi->driver = &devantech_eth008_driver_info;
+ sdi->inst_type = SR_INST_SERIAL;
+
+ has_serno_cmd = TRUE;
+ if (model->min_serno_fw && fwver < model->min_serno_fw)
+ has_serno_cmd = FALSE;
+ if (has_serno_cmd) {
+ snr_txt[0] = '\0';
+ ret = devantech_eth008_get_serno(ser,
+ snr_txt, sizeof(snr_txt));
+ if (ret != SR_OK)
+ goto probe_fail;
+ sdi->serial_num = g_strdup(snr_txt);
+ }
- /* TODO: get handle from sdi->conn and open it. */
+ ch_idx = 0;
+ devc->mask_do = (1UL << devc->model->ch_count_do) - 1;
+ devc->mask_do &= ~devc->model->mask_do_missing;
+ for (do_idx = 0; do_idx < devc->model->ch_count_do; do_idx++) {
+ nr = do_idx + 1;
+ if (devc->model->mask_do_missing & (1UL << do_idx))
+ continue;
+ snprintf(cg_name, sizeof(cg_name), "DO%zu", nr);
+ cgc = g_malloc0(sizeof(*cgc));
+ cg = sr_channel_group_new(sdi, cg_name, cgc);
+ cgc->index = do_idx;
+ cgc->number = nr;
+ cgc->ch_type = DV_CH_DIGITAL_OUTPUT;
+ (void)cg;
+ ch_idx++;
+ }
+ for (di_idx = 0; di_idx < devc->model->ch_count_di; di_idx++) {
+ nr = di_idx + 1;
+ snprintf(cg_name, sizeof(cg_name), "DI%zu", nr);
+ cgc = g_malloc0(sizeof(*cgc));
+ cg = sr_channel_group_new(sdi, cg_name, cgc);
+ cgc->index = di_idx;
+ cgc->number = nr;
+ cgc->ch_type = DV_CH_DIGITAL_INPUT;
+ (void)cg;
+ ch_idx++;
+ }
+ for (ai_idx = 0; ai_idx < devc->model->ch_count_ai; ai_idx++) {
+ nr = ai_idx + 1;
+ snprintf(cg_name, sizeof(cg_name), "AI%zu", nr);
+ cgc = g_malloc0(sizeof(*cgc));
+ cg = sr_channel_group_new(sdi, cg_name, cgc);
+ cgc->index = ai_idx;
+ cgc->number = nr;
+ cgc->ch_type = DV_CH_ANALOG_INPUT;
+ (void)cg;
+ ch_idx++;
+ }
+ if (1) {
+ /* Create an analog channel for the supply voltage. */
+ snprintf(cg_name, sizeof(cg_name), "Vsupply");
+ cgc = g_malloc0(sizeof(*cgc));
+ cg = sr_channel_group_new(sdi, cg_name, cgc);
+ cgc->index = 0;
+ cgc->number = 0;
+ cgc->ch_type = DV_CH_SUPPLY_VOLTAGE;
+ (void)cg;
+ ch_idx++;
+ }
+
+ return sdi;
- return SR_OK;
+probe_fail:
+ if (ser) {
+ serial_close(ser);
+ sr_serial_dev_inst_free(ser);
+ }
+ if (devc) {
+ g_free(devc);
+ }
+ if (sdi) {
+ sdi->priv = NULL;
+ sr_dev_inst_free(sdi);
+ sdi = NULL;
+ }
+ return sdi;
}
-static int dev_close(struct sr_dev_inst *sdi)
+static GSList *scan(struct sr_dev_driver *di, GSList *options)
{
- (void)sdi;
+ struct drv_context *drvc;
+ const char *conn;
+ GSList *devices;
+ struct sr_dev_inst *sdi;
- /* TODO: get handle from sdi->conn and close it. */
+ drvc = di->context;
+ drvc->instances = NULL;
+
+ /* A conn= spec is required for the TCP attached device. */
+ conn = NULL;
+ (void)sr_serial_extract_options(options, &conn, NULL);
+ if (!conn || !*conn)
+ return NULL;
+
+ devices = NULL;
+ sdi = probe_device_conn(conn);
+ if (sdi)
+ devices = g_slist_append(devices, sdi);
- return SR_OK;
+ return std_scan_complete(di, devices);
}
static int config_get(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
+ struct channel_group_context *cgc;
+ gboolean on;
+ uint16_t vin;
+ double vsupply;
int ret;
- (void)sdi;
- (void)data;
- (void)cg;
+ if (!cg) {
+ switch (key) {
+ case SR_CONF_CONN:
+ if (!sdi->connection_id)
+ return SR_ERR_NA;
+ *data = g_variant_new_string(sdi->connection_id);
+ return SR_OK;
+ default:
+ return SR_ERR_NA;
+ }
+ }
- ret = SR_OK;
+ cgc = cg->priv;
+ if (!cgc)
+ return SR_ERR_NA;
switch (key) {
- /* TODO */
+ case SR_CONF_ENABLED:
+ if (cgc->ch_type == DV_CH_DIGITAL_OUTPUT) {
+ ret = devantech_eth008_query_do(sdi, cg, &on);
+ if (ret != SR_OK)
+ return ret;
+ *data = g_variant_new_boolean(on);
+ return SR_OK;
+ }
+ if (cgc->ch_type == DV_CH_DIGITAL_INPUT) {
+ ret = devantech_eth008_query_di(sdi, cg, &on);
+ if (ret != SR_OK)
+ return ret;
+ *data = g_variant_new_boolean(on);
+ return SR_OK;
+ }
+ return SR_ERR_NA;
+ case SR_CONF_VOLTAGE:
+ if (cgc->ch_type == DV_CH_ANALOG_INPUT) {
+ ret = devantech_eth008_query_ai(sdi, cg, &vin);
+ if (ret != SR_OK)
+ return ret;
+ *data = g_variant_new_uint32(vin);
+ return SR_OK;
+ }
+ if (cgc->ch_type == DV_CH_SUPPLY_VOLTAGE) {
+ ret = devantech_eth008_query_supply(sdi, cg, &vin);
+ if (ret != SR_OK)
+ return ret;
+ vsupply = vin;
+ vsupply /= 1000.;
+ *data = g_variant_new_double(vsupply);
+ return SR_OK;
+ }
+ return SR_ERR_NA;
default:
return SR_ERR_NA;
}
-
- return ret;
}
static int config_set(uint32_t key, GVariant *data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
- int ret;
-
- (void)sdi;
- (void)data;
- (void)cg;
+ struct channel_group_context *cgc;
+ gboolean on;
+
+ if (!cg) {
+ switch (key) {
+ case SR_CONF_ENABLED:
+ /* Enable/disable all channels at the same time. */
+ on = g_variant_get_boolean(data);
+ return devantech_eth008_setup_do(sdi, cg, on);
+ default:
+ return SR_ERR_NA;
+ }
+ }
- ret = SR_OK;
+ cgc = cg->priv;
+ if (!cgc)
+ return SR_ERR_NA;
switch (key) {
- /* TODO */
+ case SR_CONF_ENABLED:
+ if (cgc->ch_type != DV_CH_DIGITAL_OUTPUT)
+ return SR_ERR_NA;
+ on = g_variant_get_boolean(data);
+ return devantech_eth008_setup_do(sdi, cg, on);
default:
- ret = SR_ERR_NA;
+ return SR_ERR_NA;
}
-
- return ret;
}
static int config_list(uint32_t key, GVariant **data,
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
- int ret;
-
- (void)sdi;
- (void)data;
- (void)cg;
+ struct channel_group_context *cgc;
+
+ if (!cg) {
+ switch (key) {
+ case SR_CONF_SCAN_OPTIONS:
+ case SR_CONF_DEVICE_OPTIONS:
+ return STD_CONFIG_LIST(key, data, sdi, cg,
+ scanopts, drvopts, devopts);
+ default:
+ return SR_ERR_NA;
+ }
+ }
- ret = SR_OK;
+ cgc = cg->priv;
+ if (!cgc)
+ return SR_ERR_NA;
switch (key) {
- /* TODO */
+ case SR_CONF_DEVICE_OPTIONS:
+ if (cgc->ch_type == DV_CH_DIGITAL_OUTPUT) {
+ *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_do));
+ return SR_OK;
+ }
+ if (cgc->ch_type == DV_CH_DIGITAL_INPUT) {
+ *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_di));
+ return SR_OK;
+ }
+ if (cgc->ch_type == DV_CH_ANALOG_INPUT) {
+ *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_ai));
+ return SR_OK;
+ }
+ if (cgc->ch_type == DV_CH_SUPPLY_VOLTAGE) {
+ *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_ai));
+ return SR_OK;
+ }
+ return SR_ERR_NA;
default:
return SR_ERR_NA;
}
-
- return ret;
-}
-
-static int dev_acquisition_start(const struct sr_dev_inst *sdi)
-{
- /* TODO: configure hardware, reset acquisition state, set up
- * callbacks and send header packet. */
-
- (void)sdi;
-
- return SR_OK;
-}
-
-static int dev_acquisition_stop(struct sr_dev_inst *sdi)
-{
- /* TODO: stop acquisition. */
-
- (void)sdi;
-
- return SR_OK;
}
static struct sr_dev_driver devantech_eth008_driver_info = {
@@ -145,10 +380,10 @@ static struct sr_dev_driver devantech_eth008_driver_info = {
.config_get = config_get,
.config_set = config_set,
.config_list = config_list,
- .dev_open = dev_open,
- .dev_close = dev_close,
- .dev_acquisition_start = dev_acquisition_start,
- .dev_acquisition_stop = dev_acquisition_stop,
+ .dev_open = std_serial_dev_open,
+ .dev_close = std_serial_dev_close,
+ .dev_acquisition_start = std_dummy_dev_acquisition_start,
+ .dev_acquisition_stop = std_dummy_dev_acquisition_stop,
.context = NULL,
};
SR_REGISTER_DEV_DRIVER(devantech_eth008_driver_info);