X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Fdcttech-usbrelay%2Fprotocol.c;h=9038432054812ba342230528f845e61f4bb24639;hb=HEAD;hp=111e4ef1206c2df87cc648b2279e4c19abbcd7e3;hpb=64d54a719aed9204091b8d88c1b881f1341f0592;p=libsigrok.git diff --git a/src/hardware/dcttech-usbrelay/protocol.c b/src/hardware/dcttech-usbrelay/protocol.c index 111e4ef1..90384320 100644 --- a/src/hardware/dcttech-usbrelay/protocol.c +++ b/src/hardware/dcttech-usbrelay/protocol.c @@ -18,24 +18,120 @@ */ #include + +#include + #include "protocol.h" -SR_PRIV int dcttech_usbrelay_receive_data(int fd, int revents, void *cb_data) +SR_PRIV int dcttech_usbrelay_update_state(const struct sr_dev_inst *sdi) { - const struct sr_dev_inst *sdi; struct dev_context *devc; + uint8_t report[1 + REPORT_BYTECOUNT]; + int ret; + GString *txt; + + devc = sdi->priv; + + /* Get another HID report. */ + memset(report, 0, sizeof(report)); + report[0] = REPORT_NUMBER; + ret = hid_get_feature_report(devc->hid_dev, report, sizeof(report)); + if (ret != sizeof(report)) + return SR_ERR_IO; + if (sr_log_loglevel_get() >= SR_LOG_SPEW) { + txt = sr_hexdump_new(report, sizeof(report)); + sr_spew("Got report bytes: %s.", txt->str); + sr_hexdump_free(txt); + } - (void)fd; + /* Update relay state cache from HID report content. */ + devc->relay_state = report[1 + STATE_INDEX]; + devc->relay_state &= devc->relay_mask; + + return SR_OK; +} + +SR_PRIV int dcttech_usbrelay_switch_cg(const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg, gboolean on) +{ + struct dev_context *devc; + struct channel_group_context *cgc; + gboolean is_all; + size_t relay_idx; + uint8_t report[1 + REPORT_BYTECOUNT]; + int ret; + GString *txt; - if (!(sdi = cb_data)) - return TRUE; + devc = sdi->priv; - if (!(devc = sdi->priv)) - return TRUE; + /* Determine if all or a single relay should be turned off or on. */ + is_all = !cg ? TRUE : FALSE; + if (is_all) { + relay_idx = 0; + } else { + cgc = cg->priv; + relay_idx = cgc->number; + } - if (revents == G_IO_IN) { - /* TODO */ + /* + * Construct and send the HID report. Notice the weird(?) bit + * pattern. Bit 1 is low when all relays are affected at once, + * and high to control an individual relay? Bit 0 communicates + * whether the relay(s) should be on or off? And all other bits + * are always set? It's assumed that the explicit assignment of + * full byte values simplifies future maintenance. + */ + memset(report, 0, sizeof(report)); + report[0] = REPORT_NUMBER; + if (is_all) { + if (on) { + report[1] = 0xfe; + } else { + report[1] = 0xfc; + } + } else { + if (on) { + report[1] = 0xff; + report[2] = relay_idx; + } else { + report[1] = 0xfd; + report[2] = relay_idx; + } + } + if (sr_log_loglevel_get() >= SR_LOG_SPEW) { + txt = sr_hexdump_new(report, sizeof(report)); + sr_spew("Sending report bytes: %s", txt->str); + sr_hexdump_free(txt); } + ret = hid_send_feature_report(devc->hid_dev, report, sizeof(report)); + if (ret != sizeof(report)) + return SR_ERR_IO; + + /* Update relay state cache (non-fatal). */ + (void)dcttech_usbrelay_update_state(sdi); + + return SR_OK; +} + +/* Answers the query from cached relay state. Beware of 1-based indexing. */ +SR_PRIV int dcttech_usbrelay_query_cg(const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg, gboolean *on) +{ + struct dev_context *devc; + struct channel_group_context *cgc; + size_t relay_idx; + uint32_t relay_mask; + + devc = sdi->priv; + if (!cg) + return SR_ERR_ARG; + cgc = cg->priv; + relay_idx = cgc->number; + if (relay_idx < 1 || relay_idx > devc->relay_count) + return SR_ERR_ARG; + relay_mask = 1U << (relay_idx - 1); + + *on = devc->relay_state & relay_mask; - return TRUE; + return SR_OK; }