static gboolean _write_memory (ArvUvDevice *uv_device, guint64 address, guint32 size, void *buffer, GError **error) { ArvUvcpPacket *packet; void *read_packet; size_t packet_size; size_t read_packet_size; gboolean success = FALSE; unsigned n_tries = 0; guint32 timeout_ms = 0; read_packet_size = arv_uvcp_packet_get_write_memory_ack_size (); if (read_packet_size > uv_device->priv->ack_packet_size_max) { arv_debug_device ("Invalid acknowledge packet size (%d / max: %d)", read_packet_size, uv_device->priv->ack_packet_size_max); return FALSE; } packet = arv_uvcp_packet_new_write_memory_cmd (address, size, 0, &packet_size); if (packet_size > uv_device->priv->cmd_packet_size_max) { arv_debug_device ("Invalid command packet size (%d / max: %d)", packet_size, uv_device->priv->cmd_packet_size_max); arv_uvcp_packet_free (packet); return FALSE; } memcpy (arv_uvcp_packet_get_write_memory_cmd_data (packet), buffer, size); read_packet = g_malloc (read_packet_size); do { GError *error = NULL; size_t transferred; uv_device->priv->packet_id = arv_uvcp_next_packet_id (uv_device->priv->packet_id); arv_uvcp_packet_set_packet_id (packet, uv_device->priv->packet_id); arv_uvcp_packet_debug (packet, ARV_DEBUG_LEVEL_LOG); success = TRUE; success = success && arv_uv_device_bulk_transfer (uv_device, ARV_UV_ENDPOINT_CONTROL, LIBUSB_ENDPOINT_OUT, packet, packet_size, NULL, 0, &error); if (success ) { gboolean expected_answer; do { success = TRUE; success = success && arv_uv_device_bulk_transfer (uv_device, ARV_UV_ENDPOINT_CONTROL, LIBUSB_ENDPOINT_IN, read_packet, read_packet_size, &transferred, timeout_ms, &error); if (success) { ArvUvcpPacketType packet_type; ArvUvcpCommand command; guint16 packet_id; packet_type = arv_uvcp_packet_get_packet_type (read_packet); command = arv_uvcp_packet_get_command (read_packet); packet_id = arv_uvcp_packet_get_packet_id (read_packet); if (command == ARV_UVCP_COMMAND_PENDING_ACK) { expected_answer = FALSE; timeout_ms = arv_uvcp_packet_get_pending_ack_timeout (read_packet); arv_log_device ("[UvDevice::write_memory] Pending ack timeout = %d", timeout_ms); } else expected_answer = packet_type == ARV_UVCP_PACKET_TYPE_ACK && command == ARV_UVCP_COMMAND_WRITE_MEMORY_ACK && packet_id == uv_device->priv->packet_id; } else { expected_answer = FALSE; if (error != NULL) g_warning ("[UvDevice::write_memory] Ack reception error: %s", error->message); g_clear_error (&error); } } while (success && !expected_answer); success = success && expected_answer; if (success) arv_uvcp_packet_debug (read_packet, ARV_DEBUG_LEVEL_LOG); } else { if (error != NULL) g_warning ("[UvDevice::write_memory] Command sending error: %s", error->message); g_clear_error (&error); } n_tries++; } while (!success && n_tries < ARV_UV_DEVICE_N_TRIES_MAX); g_free (read_packet); arv_uvcp_packet_free (packet); if (!success) { if (error != NULL && *error == NULL) *error = g_error_new (ARV_DEVICE_ERROR, ARV_DEVICE_STATUS_TIMEOUT, "[ArvDevice::write_memory] Timeout"); } return success; }
static void * arv_uv_stream_thread (void *data) { ArvUvStreamThreadData *thread_data = data; ArvUvspPacket *packet; ArvBuffer *buffer = NULL; void *incoming_buffer; guint64 offset; size_t transferred; arv_log_stream_thread ("Start USB3Vision stream thread"); incoming_buffer = g_malloc (MAXIMUM_TRANSFER_SIZE); if (thread_data->callback != NULL) thread_data->callback (thread_data->user_data, ARV_STREAM_CALLBACK_TYPE_INIT, NULL); offset = 0; while (!thread_data->cancel) { size_t size; transferred = 0; if (buffer == NULL) size = thread_data->leader_size; else { if (offset < buffer->priv->size) size = MIN (thread_data->payload_size, buffer->priv->size - offset); else size = thread_data->trailer_size; } /* Avoid unnecessary memory copy by transferring data directly to the image buffer */ if (buffer != NULL && buffer->priv->status == ARV_BUFFER_STATUS_FILLING && offset + size <= buffer->priv->size) packet = buffer->priv->data + offset; else packet = incoming_buffer; arv_uv_device_bulk_transfer (thread_data->uv_device, 0x81 | LIBUSB_ENDPOINT_IN, packet, size, &transferred, 0, NULL); if (transferred > 0) { ArvUvspPacketType packet_type; arv_log_sp ("Received %d bytes", transferred); arv_uvsp_packet_debug (packet, ARV_DEBUG_LEVEL_LOG); packet_type = arv_uvsp_packet_get_packet_type (packet); switch (packet_type) { case ARV_UVSP_PACKET_TYPE_LEADER: if (buffer != NULL) { arv_debug_stream_thread ("New leader received while a buffer is still open"); buffer->priv->status = ARV_BUFFER_STATUS_MISSING_PACKETS; arv_stream_push_output_buffer (thread_data->stream, buffer); thread_data->n_failures++; buffer = NULL; } buffer = arv_stream_pop_input_buffer (thread_data->stream); if (buffer != NULL) { buffer->priv->status = ARV_BUFFER_STATUS_FILLING; buffer->priv->gvsp_payload_type = ARV_GVSP_PAYLOAD_TYPE_IMAGE; arv_uvsp_packet_get_region (packet, &buffer->priv->width, &buffer->priv->height, &buffer->priv->x_offset, &buffer->priv->y_offset); buffer->priv->frame_id = arv_uvsp_packet_get_frame_id (packet); buffer->priv->timestamp_ns = arv_uvsp_packet_get_timestamp (packet); offset = 0; } else thread_data->n_underruns++; break; case ARV_UVSP_PACKET_TYPE_TRAILER: if (buffer != NULL) { arv_log_stream_thread ("Received %" G_GUINT64_FORMAT " bytes - expected %" G_GUINT64_FORMAT, offset, buffer->priv->size); buffer->priv->status = ARV_BUFFER_STATUS_SUCCESS; arv_stream_push_output_buffer (thread_data->stream, buffer); thread_data->n_completed_buffers++; buffer = NULL; } break; case ARV_UVSP_PACKET_TYPE_DATA: if (buffer != NULL && buffer->priv->status == ARV_BUFFER_STATUS_FILLING) { if (offset + transferred <= buffer->priv->size) { if (packet == incoming_buffer) memcpy (((char *) buffer->priv->data) + offset, packet, transferred); offset += transferred; } else buffer->priv->status = ARV_BUFFER_STATUS_SIZE_MISMATCH; } break; default: arv_debug_stream_thread ("Unkown packet type"); break; } } } if (thread_data->callback != NULL) thread_data->callback (thread_data->user_data, ARV_STREAM_CALLBACK_TYPE_EXIT, NULL); g_free (incoming_buffer); arv_log_stream_thread ("Stop USB3Vision stream thread"); return NULL; }