[aravis/wip/emmanuel/usb3vision] wip: initialize u3v stream interface parameters
- From: Emmanuel Pacaud <emmanuel src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [aravis/wip/emmanuel/usb3vision] wip: initialize u3v stream interface parameters
- Date: Wed, 3 Aug 2016 09:08:56 +0000 (UTC)
commit 0e8a21d0fa584347ceebb232d53d30280cff5c6d
Author: Emmanuel Pacaud <emmanuel gnome org>
Date: Wed Aug 3 11:08:47 2016 +0200
wip: initialize u3v stream interface parameters
src/arvuvcp.h | 4 +-
src/arvuvdevice.c | 115 +++++++++++++++++++++++++++++++---------------
src/arvuvdeviceprivate.h | 9 ++++
src/arvuvinterface.c | 36 +++++++++++++--
src/arvuvstream.c | 72 +++++++++++++++++++++++++----
src/arvuvstream.h | 3 +-
6 files changed, 185 insertions(+), 54 deletions(-)
---
diff --git a/src/arvuvcp.h b/src/arvuvcp.h
index 86ccc0f..3411a53 100644
--- a/src/arvuvcp.h
+++ b/src/arvuvcp.h
@@ -30,6 +30,8 @@ G_BEGIN_DECLS
#define ARV_UVCP_MAGIC 0x43563355
+#define ARV_UV_DEFAULT_RESPONSE_TIME_MS 5
+
#define ARV_ABRM_GENCP_VERSION 0x0000
#define ARV_ABRM_MANUFACTURER_NAME 0x0004
#define ARV_ABRM_MODEL_NAME 0x0044
@@ -39,7 +41,7 @@ G_BEGIN_DECLS
#define ARV_ABRM_SERIAL_NUMBER 0x0144
#define ARV_ABRM_USER_DEFINED_NAME 0x0184
#define ARV_ABRM_DEVICE_CAPABILITY 0x01c4
-#define ARV_ABRM_MAX_DEVICE_RESPONSE_TIME 0x01cc
+#define ARV_ABRM_MAX_DEVICE_RESPONSE_TIME 0x01cc /* in ms */
#define ARV_ABRM_MANIFEST_TABLE_ADDRESS 0x01d0
#define ARV_ABRM_SBRM_ADDRESS 0x01d8
#define ARV_ABRM_DEVICE_CONFIGURATION 0x01e0
diff --git a/src/arvuvdevice.c b/src/arvuvdevice.c
index 5fbebca..a5034af 100644
--- a/src/arvuvdevice.c
+++ b/src/arvuvdevice.c
@@ -53,12 +53,34 @@ struct _ArvUvDevicePrivate {
guint16 packet_id;
- guint data_size_max;
+ guint timeout_ms;
+ guint cmd_packet_size_max;
+ guint ack_packet_size_max;
};
+/* ArvDevice implemenation */
+
/* ArvUvDevice implemenation */
-/* ArvDevice implemenation */
+gboolean
+arv_uv_device_bulk_transfer (ArvUvDevice *uv_device, unsigned char endpoint, void *data,
+ size_t size, size_t *transferred_size)
+{
+ gboolean success;
+ int transferred = 0;
+
+ g_return_val_if_fail (ARV_IS_UV_DEVICE (uv_device), FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (size > 0, FALSE);
+
+ success = libusb_bulk_transfer (uv_device->priv->usb_device, endpoint, data, size, &transferred,
+ uv_device->priv->timeout_ms) >= 0;
+
+ if (transferred_size != NULL)
+ *transferred_size = transferred;
+
+ return success;
+}
static ArvStream *
arv_uv_device_create_stream (ArvDevice *device, ArvStreamCallback callback, void *user_data)
@@ -66,7 +88,7 @@ arv_uv_device_create_stream (ArvDevice *device, ArvStreamCallback callback, void
ArvUvDevice *uv_device = ARV_UV_DEVICE (device);
ArvStream *stream;
- stream = arv_uv_stream_new (uv_device->priv->usb, uv_device->priv->usb_device, callback, user_data);
+ stream = arv_uv_stream_new (uv_device, callback, user_data);
return stream;
}
@@ -75,43 +97,48 @@ static gboolean
_read_memory (ArvUvDevice *uv_device, guint32 address, guint32 size, void *buffer, GError **error)
{
ArvUvcpPacket *packet;
+ void *read_packet;
+ size_t read_packet_size;
size_t packet_size;
- size_t answer_size;
gboolean success = FALSE;
- answer_size = arv_uvcp_packet_get_read_memory_ack_size (size);
-
- g_return_val_if_fail (answer_size <= 1024, FALSE);
+ read_packet_size = arv_uvcp_packet_get_read_memory_ack_size (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_read_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;
+ }
- do {
- int transferred;
- void *read_packet;
- size_t read_packet_size;
+ read_packet = g_malloc (read_packet_size);
- read_packet_size = arv_uvcp_packet_get_read_memory_ack_size (size);
- read_packet = g_malloc0 (read_packet_size);
+ do {
+ 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);
- g_assert (libusb_bulk_transfer (uv_device->priv->usb_device, (0x04 | LIBUSB_ENDPOINT_OUT),
- (guchar *) packet, packet_size, &transferred, 0) >= 0);
- g_assert (libusb_bulk_transfer (uv_device->priv->usb_device, (0x84 | LIBUSB_ENDPOINT_IN),
- (guchar *) read_packet, read_packet_size, &transferred, 0) >=
0);
success = TRUE;
+ success = success && arv_uv_device_bulk_transfer (uv_device, (0x04 | LIBUSB_ENDPOINT_OUT),
+ packet, packet_size, NULL);
+ success = success && arv_uv_device_bulk_transfer (uv_device, (0x84 | LIBUSB_ENDPOINT_IN),
+ read_packet, read_packet_size,
&transferred);
memcpy (buffer, arv_uvcp_packet_get_read_memory_ack_data (read_packet), size);
arv_uvcp_packet_debug (read_packet, ARV_DEBUG_LEVEL_LOG);
- g_free (read_packet);
-
} while (!success);
+ g_free (read_packet);
arv_uvcp_packet_free (packet);
if (!success) {
@@ -131,7 +158,7 @@ arv_uv_device_read_memory (ArvDevice *device, guint32 address, guint32 size, voi
gint32 block_size;
guint data_size_max;
- data_size_max = uv_device->priv->data_size_max;
+ data_size_max = uv_device->priv->ack_packet_size_max - sizeof (ArvUvcpHeader);
for (i = 0; i < (size + data_size_max - 1) / data_size_max; i++) {
block_size = MIN (data_size_max, size - i * data_size_max);
@@ -148,42 +175,47 @@ static gboolean
_write_memory (ArvUvDevice *uv_device, guint32 address, guint32 size, void *buffer, GError **error)
{
ArvUvcpPacket *packet;
+ void *read_packet;
size_t packet_size;
- size_t answer_size;
+ size_t read_packet_size;
gboolean success = FALSE;
- answer_size = arv_uvcp_packet_get_write_memory_ack_size ();
-
- g_return_val_if_fail (answer_size <= 1024, FALSE);
+ 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 {
- int transferred;
- void *read_packet;
- size_t read_packet_size;
-
- read_packet_size = arv_uvcp_packet_get_read_memory_ack_size (size);
- read_packet = g_malloc0 (read_packet_size);
+ 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);
- g_assert (libusb_bulk_transfer (uv_device->priv->usb_device, (0x04 | LIBUSB_ENDPOINT_OUT),
- (guchar *) packet, packet_size, &transferred, 0) >= 0);
- g_assert (libusb_bulk_transfer (uv_device->priv->usb_device, (0x84 | LIBUSB_ENDPOINT_IN),
- (guchar *) read_packet, read_packet_size, &transferred, 0) >=
0);
success = TRUE;
+ success = success && arv_uv_device_bulk_transfer (uv_device, (0x04 | LIBUSB_ENDPOINT_OUT),
+ packet, packet_size, NULL);
+ success = success && arv_uv_device_bulk_transfer (uv_device, (0x84 | LIBUSB_ENDPOINT_IN),
+ read_packet, read_packet_size,
&transferred);
arv_uvcp_packet_debug (read_packet, ARV_DEBUG_LEVEL_LOG);
- g_free (read_packet);
-
} while (!success);
+ g_free (read_packet);
arv_uvcp_packet_free (packet);
if (!success) {
@@ -203,7 +235,7 @@ arv_uv_device_write_memory (ArvDevice *device, guint32 address, guint32 size, vo
gint32 block_size;
guint data_size_max;
- data_size_max = uv_device->priv->data_size_max;
+ data_size_max = uv_device->priv->ack_packet_size_max - sizeof (ArvUvcpHeader);
for (i = 0; i < (size + data_size_max - 1) / data_size_max; i++) {
block_size = MIN (data_size_max, size - i * data_size_max);
@@ -269,6 +301,8 @@ _bootstrap (ArvUvDevice *uv_device)
g_message ("SRBM_ADDRESS = 0x%016lx", offset);
g_message ("MANIFEST_TABLE_ADDRESS = 0x%016lx", manifest_table_address);
+ uv_device->priv->timeout_ms = MAX (ARV_UV_DEFAULT_RESPONSE_TIME_MS, response_time);
+
arv_device_read_memory (device, offset + ARV_SBRM_U3VCP_CAPABILITY, sizeof (guint32),
&u3vcp_capability, NULL);
arv_device_read_memory (device, offset + ARV_SBRM_MAX_CMD_TRANSFER, sizeof (guint32),
&max_cmd_transfer, NULL);
arv_device_read_memory (device, offset + ARV_SBRM_MAX_ACK_TRANSFER, sizeof (guint32),
&max_ack_transfer, NULL);
@@ -279,6 +313,9 @@ _bootstrap (ArvUvDevice *uv_device)
g_message ("MAX_ACK_TRANSFER = 0x%08x", max_ack_transfer);
g_message ("SIRM_OFFSET = 0x%016lx", sirm_offset);
+ uv_device->priv->cmd_packet_size_max = MIN (uv_device->priv->cmd_packet_size_max, max_cmd_transfer);
+ uv_device->priv->ack_packet_size_max = MIN (uv_device->priv->ack_packet_size_max, max_ack_transfer);
+
arv_device_read_memory (device, sirm_offset + ARV_SI_INFO, sizeof (si_info), &si_info, NULL);
arv_device_read_memory (device, sirm_offset + ARV_SI_CONTROL, sizeof (si_control), &si_control, NULL);
arv_device_read_memory (device, sirm_offset + ARV_SI_REQ_PAYLOAD_SIZE, sizeof (si_req_payload_size),
&si_req_payload_size, NULL);
@@ -448,6 +485,7 @@ arv_uv_device_new (const char *vendor, const char *product, const char *serial_n
uv_device->priv->product = g_strdup (product);
uv_device->priv->serial_nbr = g_strdup (serial_nbr);
uv_device->priv->packet_id = 65300; /* Start near the end of the circular counter */
+ uv_device->priv->timeout_ms = 32;
_open_usb_device (uv_device);
@@ -470,7 +508,8 @@ static void
arv_uv_device_init (ArvUvDevice *uv_device)
{
uv_device->priv = G_TYPE_INSTANCE_GET_PRIVATE (uv_device, ARV_TYPE_UV_DEVICE, ArvUvDevicePrivate);
- uv_device->priv->data_size_max = 256;
+ uv_device->priv->cmd_packet_size_max = 65536 + sizeof (ArvUvcpHeader);
+ uv_device->priv->ack_packet_size_max = 65536 + sizeof (ArvUvcpHeader);
}
static void
diff --git a/src/arvuvdeviceprivate.h b/src/arvuvdeviceprivate.h
new file mode 100644
index 0000000..3454b38
--- /dev/null
+++ b/src/arvuvdeviceprivate.h
@@ -0,0 +1,9 @@
+#ifndef ARV_UV_DEVICE_PRIVATE
+#define ARV_UV_DEVICE_PRIVATE
+
+#include <arvuvdevice.h>
+
+gboolean arv_uv_device_bulk_transfer (ArvUvDevice *uv_device, unsigned char endpoint, void
*data,
+ size_t size, size_t *transferred_size);
+
+#endif
diff --git a/src/arvuvinterface.c b/src/arvuvinterface.c
index 5b843a3..6fdc2e4 100644
--- a/src/arvuvinterface.c
+++ b/src/arvuvinterface.c
@@ -226,9 +226,8 @@ _usb_device_to_device_ids (ArvUvInterface *uv_interface, libusb_device *device)
}
static void
-arv_uv_interface_update_device_list (ArvInterface *interface, GArray *device_ids)
+_discover (ArvUvInterface *uv_interface, GArray *device_ids)
{
- ArvUvInterface *uv_interface = ARV_UV_INTERFACE (interface);
libusb_device **devices;
unsigned uv_count = 0;
unsigned count;
@@ -244,7 +243,14 @@ arv_uv_interface_update_device_list (ArvInterface *interface, GArray *device_ids
ids = _usb_device_to_device_ids (uv_interface, devices[i]);
if (ids != NULL) {
uv_count++;
- g_array_append_val (device_ids, ids);
+ if (device_ids != NULL)
+ g_array_append_val (device_ids, ids);
+ else {
+ g_free (ids->device);
+ g_free (ids->physical);
+ g_free (ids->address);
+ g_free (ids);
+ }
}
}
@@ -255,8 +261,16 @@ arv_uv_interface_update_device_list (ArvInterface *interface, GArray *device_ids
libusb_free_device_list (devices, 1);
}
+static void
+arv_uv_interface_update_device_list (ArvInterface *interface, GArray *device_ids)
+{
+ ArvUvInterface *uv_interface = ARV_UV_INTERFACE (interface);
+
+ _discover (uv_interface, device_ids);
+}
+
static ArvDevice *
-arv_uv_interface_open_device (ArvInterface *interface, const char *device_id)
+_open_device (ArvInterface *interface, const char *device_id)
{
ArvUvInterface *uv_interface;
ArvDevice *device = NULL;
@@ -281,6 +295,20 @@ arv_uv_interface_open_device (ArvInterface *interface, const char *device_id)
return device;
}
+static ArvDevice *
+arv_uv_interface_open_device (ArvInterface *interface, const char *device_id)
+{
+ ArvDevice *device;
+
+ device = _open_device (interface, device_id);
+ if (ARV_IS_DEVICE (device))
+ return device;
+
+ _discover (ARV_UV_INTERFACE (interface), NULL);
+
+ return _open_device (interface, device_id);
+}
+
static ArvInterface *uv_interface = NULL;
ARV_DEFINE_STATIC_MUTEX (uv_interface_mutex);
diff --git a/src/arvuvstream.c b/src/arvuvstream.c
index 515da19..8d0a870 100644
--- a/src/arvuvstream.c
+++ b/src/arvuvstream.c
@@ -26,7 +26,9 @@
*/
#include <arvuvstream.h>
+#include <arvuvdeviceprivate.h>
#include <arvuvsp.h>
+#include <arvuvcp.h>
#include <arvstreamprivate.h>
#include <arvbufferprivate.h>
#include <arvdebug.h>
@@ -44,14 +46,12 @@ struct _ArvUvStreamPrivate {
/* Acquisition thread */
typedef struct {
+ ArvUvDevice *uv_device;
ArvStream *stream;
ArvStreamCallback callback;
void *user_data;
- libusb_context *usb;
- libusb_device_handle *usb_device;
-
gboolean cancel;
/* Statistics */
@@ -68,7 +68,7 @@ arv_uv_stream_thread (void *data)
ArvUvspPacket *packet;
ArvBuffer *buffer = NULL;
guint64 offset;
- int transferred;
+ size_t transferred;
arv_log_stream_thread ("[UvStream::thread] Start");
@@ -80,8 +80,12 @@ arv_uv_stream_thread (void *data)
offset = 0;
while (!thread_data->cancel) {
- g_assert (libusb_bulk_transfer (thread_data->usb_device, (0x81 | LIBUSB_ENDPOINT_IN),
- (guchar *) packet, 65536, &transferred, 1000) >= 0);
+ transferred = 0;
+
+ arv_uv_device_bulk_transfer (thread_data->uv_device, 0x81 | LIBUSB_ENDPOINT_IN,
+ packet, 65536, &transferred);
+
+/* g_message ("transferred = %d", (int) transferred);*/
if (transferred > 0) {
ArvUvspPacketType packet_type;
@@ -124,7 +128,7 @@ arv_uv_stream_thread (void *data)
break;
case ARV_UVSP_PACKET_TYPE_DATA:
if (buffer != NULL && buffer->priv->status ==
ARV_BUFFER_STATUS_FILLING) {
- if (offset + transferred < buffer->priv->size) {
+ if (offset + transferred <= buffer->priv->size) {
memcpy (((char *) buffer->priv->data) + offset,
packet, transferred);
offset += transferred;
} else
@@ -152,6 +156,7 @@ arv_uv_stream_thread (void *data)
/**
* arv_uv_stream_new: (skip)
+ * @uv_device: a #ArvUvDevice
* @callback: (scope call): image processing callback
* @user_data: (closure): user data for @callback
*
@@ -159,19 +164,65 @@ arv_uv_stream_thread (void *data)
*/
ArvStream *
-arv_uv_stream_new (void *usb, void *usb_device, ArvStreamCallback callback, void *user_data)
+arv_uv_stream_new (ArvUvDevice *uv_device, ArvStreamCallback callback, void *user_data)
{
+ ArvDevice *device;
ArvUvStream *uv_stream;
ArvUvStreamThreadData *thread_data;
ArvStream *stream;
+ guint64 offset;
+ guint64 sirm_offset;
+ guint64 si_req_payload_size;
+ guint32 si_req_leader_size;
+ guint32 si_req_trailer_size;
+ guint32 si_payload_size;
+ guint32 si_payload_count;
+ guint32 si_transfer1_size;
+ guint32 si_transfer2_size;
+ guint32 si_control;
+
+ g_return_val_if_fail (ARV_IS_UV_DEVICE (uv_device), NULL);
+
+ device = ARV_DEVICE (uv_device);
+
+ arv_device_read_memory (device, ARV_ABRM_SBRM_ADDRESS, sizeof (guint64), &offset, NULL);
+ arv_device_read_memory (device, offset + ARV_SBRM_SIRM_ADDRESS, sizeof (guint64), &sirm_offset, NULL);
+ arv_device_read_memory (device, sirm_offset + ARV_SI_REQ_PAYLOAD_SIZE, sizeof (si_req_payload_size),
&si_req_payload_size, NULL);
+ arv_device_read_memory (device, sirm_offset + ARV_SI_REQ_LEADER_SIZE, sizeof (si_req_leader_size),
&si_req_leader_size, NULL);
+ arv_device_read_memory (device, sirm_offset + ARV_SI_REQ_TRAILER_SIZE, sizeof (si_req_trailer_size),
&si_req_trailer_size, NULL);
+
+ g_message ("SI_REQ_PAYLOAD_SIZE = 0x%016lx", si_req_payload_size);
+ g_message ("SI_REQ_LEADER_SIZE = 0x%08x", si_req_leader_size);
+ g_message ("SI_REQ_TRAILER_SIZE = 0x%08x", si_req_trailer_size);
+
+ si_payload_size = 65536;
+ si_payload_count= si_req_payload_size / si_payload_size;
+ si_transfer1_size = si_req_payload_size % si_payload_size;
+ si_transfer2_size = 0;
+
+ arv_device_write_memory (device, sirm_offset + ARV_SI_MAX_LEADER_SIZE, sizeof (si_req_leader_size),
&si_req_leader_size, NULL);
+ arv_device_write_memory (device, sirm_offset + ARV_SI_MAX_TRAILER_SIZE, sizeof (si_req_trailer_size),
&si_req_trailer_size, NULL);
+ arv_device_write_memory (device, sirm_offset + ARV_SI_PAYLOAD_SIZE, sizeof (si_payload_size),
&si_payload_size, NULL);
+ arv_device_write_memory (device, sirm_offset + ARV_SI_PAYLOAD_COUNT, sizeof (si_payload_count),
&si_payload_count, NULL);
+ arv_device_write_memory (device, sirm_offset + ARV_SI_TRANSFER1_SIZE, sizeof (si_transfer1_size),
&si_transfer1_size, NULL);
+ arv_device_write_memory (device, sirm_offset + ARV_SI_TRANSFER2_SIZE, sizeof (si_transfer2_size),
&si_transfer2_size, NULL);
+
+ g_message ("SI_PAYLOAD_SIZE = 0x%08x", si_payload_size);
+ g_message ("SI_PAYLOAD_COUNT = 0x%08x", si_payload_count);
+ g_message ("SI_TRANSFER1_SIZE = 0x%08x", si_transfer1_size);
+ g_message ("SI_TRANSFER2_SIZE = 0x%08x", si_transfer2_size);
+ g_message ("SI_MAX_LEADER_SIZE = 0x%08x", si_req_leader_size);
+ g_message ("SI_MAX_TRAILER_SIZE = 0x%08x", si_req_trailer_size);
+
+ si_control = 0x1;
+ arv_device_write_memory (device, sirm_offset + ARV_SI_CONTROL, sizeof (si_control), &si_control,
NULL);
uv_stream = g_object_new (ARV_TYPE_UV_STREAM, NULL);
stream = ARV_STREAM (uv_stream);
thread_data = g_new (ArvUvStreamThreadData, 1);
- thread_data->usb = usb;
- thread_data->usb_device = usb_device;
+ thread_data->uv_device = g_object_ref (uv_device);
thread_data->stream = stream;
thread_data->callback = callback;
thread_data->user_data = user_data;
@@ -224,6 +275,7 @@ arv_uv_stream_finalize (GObject *object)
thread_data->cancel = TRUE;
g_thread_join (uv_stream->priv->thread);
g_free (thread_data);
+ g_clear_object (&thread_data->uv_device);
uv_stream->priv->thread_data = NULL;
uv_stream->priv->thread = NULL;
diff --git a/src/arvuvstream.h b/src/arvuvstream.h
index 92f9fc2..f37aba5 100644
--- a/src/arvuvstream.h
+++ b/src/arvuvstream.h
@@ -25,6 +25,7 @@
#include <arvtypes.h>
#include <arvstream.h>
+#include <arvuvdevice.h>
G_BEGIN_DECLS
@@ -50,7 +51,7 @@ struct _ArvUvStreamClass {
GType arv_uv_stream_get_type (void);
-ArvStream * arv_uv_stream_new (void *usb, void *usb_device, ArvStreamCallback callback, void
*user_data);
+ArvStream * arv_uv_stream_new (ArvUvDevice *uv_device, ArvStreamCallback callback, void *user_data);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]