X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=hardware%2Fkecheng-kc-330b%2Fprotocol.c;h=caf896ac051204e62dfab51e8eeba6137efd536c;hb=43cd4637285833706f8a404ca027bcf0ee75b9ae;hp=040652959dcf19489aa19ce68e555f51587086d6;hpb=bc7be4a9f4940dd9708208bddab87bd190ef816f;p=libsigrok.git diff --git a/hardware/kecheng-kc-330b/protocol.c b/hardware/kecheng-kc-330b/protocol.c index 04065295..caf896ac 100644 --- a/hardware/kecheng-kc-330b/protocol.c +++ b/hardware/kecheng-kc-330b/protocol.c @@ -17,24 +17,181 @@ * along with this program. If not, see . */ +#include #include "protocol.h" +extern struct sr_dev_driver kecheng_kc_330b_driver_info; +static struct sr_dev_driver *di = &kecheng_kc_330b_driver_info; +extern const uint64_t kecheng_kc_330b_sample_intervals[][2]; + SR_PRIV int kecheng_kc_330b_handle_events(int fd, int revents, void *cb_data) { - const struct sr_dev_inst *sdi; + struct drv_context *drvc; struct dev_context *devc; + struct sr_datafeed_packet packet; + struct sr_dev_inst *sdi; + struct sr_usb_dev_inst *usb; struct timeval tv; + const uint64_t *intv_entry; + gint64 now, interval; + int offset, len, ret; + unsigned char buf[4]; (void)fd; (void)revents; + drvc = di->priv; sdi = cb_data; devc = sdi->priv; + usb = sdi->conn; + + memset(&tv, 0, sizeof(struct timeval)); + libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv, + NULL); + if (sdi->status == SR_ST_STOPPING) { + libusb_free_transfer(devc->xfer); + usb_source_remove(sdi->session, drvc->sr_ctx); + packet.type = SR_DF_END; + sr_session_send(cb_data, &packet); + sdi->status = SR_ST_ACTIVE; + return TRUE; + } + + if (devc->state == LIVE_SPL_IDLE) { + /* Request samples at the interval rate. */ + now = g_get_monotonic_time() / 1000; + intv_entry = kecheng_kc_330b_sample_intervals[devc->sample_interval]; + interval = intv_entry[0] * 1000 / intv_entry[1]; + if (now - devc->last_live_request > interval) { + buf[0] = CMD_GET_LIVE_SPL; + ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 1, &len, 5); + if (ret != 0 || len != 1) { + sr_dbg("Failed to request new acquisition: %s", + libusb_error_name(ret)); + sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi, + devc->cb_data); + return TRUE; + } + libusb_submit_transfer(devc->xfer); + devc->last_live_request = now; + devc->state = LIVE_SPL_WAIT; + } + } else if (devc->state == LIVE_SPL_IDLE) { + buf[0] = CMD_GET_LOG_DATA; + offset = devc->num_samples / 63; + buf[1] = (offset >> 8) & 0xff; + buf[2] = offset & 0xff; + if (devc->stored_samples - devc->num_samples > 63) + buf[3] = 63; + else + /* Last chunk. */ + buf[3] = devc->stored_samples - devc->num_samples; + ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 4, &len, 5); + if (ret != 0 || len != 4) { + sr_dbg("Failed to request next chunk: %s", + libusb_error_name(ret)); + sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi, + devc->cb_data); + return TRUE; + } + libusb_submit_transfer(devc->xfer); + devc->state = LIVE_SPL_WAIT; + } return TRUE; } +static void send_data(const struct sr_dev_inst *sdi, void *buf, unsigned int buf_len) +{ + struct dev_context *devc; + struct sr_datafeed_packet packet; + struct sr_datafeed_analog analog; + + devc = sdi->priv; + + memset(&analog, 0, sizeof(struct sr_datafeed_analog)); + analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL; + analog.mqflags = devc->mqflags; + analog.unit = SR_UNIT_DECIBEL_SPL; + analog.channels = sdi->channels; + analog.num_samples = buf_len; + analog.data = buf; + packet.type = SR_DF_ANALOG; + packet.payload = &analog; + sr_session_send(devc->cb_data, &packet); + +} + +SR_PRIV void kecheng_kc_330b_receive_transfer(struct libusb_transfer *transfer) +{ + struct dev_context *devc; + struct sr_dev_inst *sdi; + float fvalue[64]; + int packet_has_error, num_samples, i; + + sdi = transfer->user_data; + devc = sdi->priv; + + packet_has_error = FALSE; + switch (transfer->status) { + case LIBUSB_TRANSFER_NO_DEVICE: + /* USB device was unplugged. */ + sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi, + devc->cb_data); + return; + case LIBUSB_TRANSFER_COMPLETED: + case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though */ + break; + default: + packet_has_error = TRUE; + break; + } + + if (packet_has_error) + return; + + if (devc->state == LIVE_SPL_WAIT) { + if (transfer->actual_length != 3 || transfer->buffer[0] != 0x88) { + sr_dbg("Received invalid SPL packet."); + } else { + fvalue[0] = ((transfer->buffer[1] << 8) + transfer->buffer[2]) / 10.0; + send_data(sdi, fvalue, 1); + devc->num_samples++; + if (devc->limit_samples && devc->num_samples >= devc->limit_samples) { + sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi, + devc->cb_data); + } else { + /* let USB event handler fire off another + * request when the time is right. */ + devc->state = LIVE_SPL_IDLE; + } + } + } else if (devc->state == LOG_DATA_WAIT) { + if (transfer->actual_length < 1 || !(transfer->actual_length & 0x01)) { + sr_dbg("Received invalid stored SPL packet."); + } else { + num_samples = (transfer->actual_length - 1) / 2; + for (i = 0; i < num_samples; i++) { + fvalue[i] = transfer->buffer[1 + i * 2] << 8; + fvalue[i] += transfer->buffer[1 + i * 2 + 1]; + fvalue[i] /= 10.0; + } + send_data(sdi, fvalue, 1); + devc->num_samples += num_samples; + if (devc->num_samples >= devc->stored_samples) { + sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi, + devc->cb_data); + } else { + /* let USB event handler fire off another + * request when the time is right. */ + devc->state = LOG_DATA_IDLE; + } + } + } + +} + SR_PRIV int kecheng_kc_330b_configure(const struct sr_dev_inst *sdi) { struct dev_context *devc; @@ -71,6 +228,8 @@ SR_PRIV int kecheng_kc_330b_configure(const struct sr_dev_inst *sdi) return SR_ERR; } + devc->config_dirty = FALSE; + return SR_OK; } @@ -110,14 +269,70 @@ SR_PRIV int kecheng_kc_330b_set_date_time(struct sr_dev_inst *sdi) return SR_ERR; } + return SR_OK; +} +SR_PRIV int kecheng_kc_330b_status_get(const struct sr_dev_inst *sdi, + int *status) +{ + struct sr_usb_dev_inst *usb; + int len, ret; + unsigned char buf; + + sr_dbg("Getting device status."); + + usb = sdi->conn; + buf = CMD_GET_STATUS; + ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, &buf, 1, &len, 5); + if (ret != 0 || len != 1) { + sr_dbg("Failed to get status: %s", libusb_error_name(ret)); + return SR_ERR; + } + + ret = libusb_bulk_transfer(usb->devhdl, EP_IN, &buf, 1, &len, 10); + if (ret != 0 || len != 1) { + sr_dbg("Failed to get status (no ack): %s", libusb_error_name(ret)); + return SR_ERR; + } + /* Need either 0x84 or 0xa4. */ + if (buf != (CMD_GET_STATUS | 0x80) && buf != (CMD_GET_STATUS | 0xa0)) { + sr_dbg("Failed to get status: invalid response 0x%2.x", buf); + return SR_ERR; + } + + if (buf & 0x20) + *status = DEVICE_INACTIVE; + else + *status = DEVICE_ACTIVE; return SR_OK; } -SR_PRIV int kecheng_kc_330b_recording_get(const struct sr_dev_inst *sdi, - gboolean *tmp) +SR_PRIV int kecheng_kc_330b_log_info_get(const struct sr_dev_inst *sdi, + unsigned char *buf) { + struct sr_usb_dev_inst *usb; + int len, ret; + + sr_dbg("Getting logging info."); + + usb = sdi->conn; + buf[0] = CMD_GET_LOG_INFO; + ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 1, &len, 5); + if (ret != 0 || len != 1) { + sr_dbg("Failed to get status: %s", libusb_error_name(ret)); + return SR_ERR; + } + + ret = libusb_bulk_transfer(usb->devhdl, EP_IN, buf, 9, &len, 10); + if (ret != 0 || len != 9) { + sr_dbg("Failed to get status (no ack): %s", libusb_error_name(ret)); + return SR_ERR; + } + if (buf[0] != (CMD_GET_LOG_INFO | 0x80) || buf[1] > 6) { + sr_dbg("Failed to get log info: invalid response 0x%2.x", buf[0]); + return SR_ERR; + } return SR_OK; }