<commit_before>/* Aravis - Digital camera library
 *
 * Copyright © 2009-2019 <NAME>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 * Author: <NAME> <<EMAIL>>
 */

/**
 * SECTION: arvgcregisternode
 * @short_description: Class for Register, IntReg, MaskedIntReg, FloatReg, StringReg and StructReg nodes
 */

#include <arvgcregisternode.h>
#include <arvgcindexnode.h>
#include <arvgcinvalidatornode.h>
#include <arvgcswissknife.h>
#include <arvgcregister.h>
#include <arvgcinteger.h>
#include <arvgcfloat.h>
#include <arvgcstring.h>
#include <arvgcport.h>
#include <arvgc.h>
#include <arvmisc.h>
#include <arvdebug.h>
#include <stdlib.h>
#include <string.h>

static GObjectClass *parent_class = NULL;

/* ArvDomNode implementation */

static const char *
arv_gc_register_node_get_node_name (ArvDomNode *node)
{
	ArvGcRegisterNode *gc_register_node = ARV_GC_REGISTER_NODE (node);

	switch (gc_register_node->type) {
		case ARV_GC_REGISTER_NODE_TYPE_REGISTER:
			return "Register";
		case ARV_GC_REGISTER_NODE_TYPE_INTEGER:
			return "IntReg";
		case ARV_GC_REGISTER_NODE_TYPE_MASKED_INTEGER:
			return "MaskedIntReg";
		case ARV_GC_REGISTER_NODE_TYPE_FLOAT:
			return "FloatReg";
		case ARV_GC_REGISTER_NODE_TYPE_STRING:
			return "StringReg";
		case ARV_GC_REGISTER_NODE_TYPE_STRUCT_REGISTER:
			return "StuctReg";
	}

	return NULL;
}

static void
arv_gc_register_node_post_new_child (ArvDomNode *self, ArvDomNode *child)
{
	ArvGcRegisterNode *node = ARV_GC_REGISTER_NODE (self);

	if (ARV_IS_GC_PROPERTY_NODE (child)) {
		ArvGcPropertyNode *property_node = ARV_GC_PROPERTY_NODE (child);

		switch (arv_gc_property_node_get_node_type (property_node)) {
			case ARV_GC_PROPERTY_NODE_TYPE_ADDRESS:
			case ARV_GC_PROPERTY_NODE_TYPE_P_ADDRESS:
				node->addresses = g_slist_prepend (node->addresses, child);
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_P_INDEX:
				node->index = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_LENGTH:
			case ARV_GC_PROPERTY_NODE_TYPE_P_LENGTH:
				node->length = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_P_PORT:
				node->port = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_ACCESS_MODE:
				/* TODO */
				node->access_mode = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_CACHABLE:
				node->cachable = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_POLLING_TIME:
				/* TODO */
				node->polling_time = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_ENDIANESS:
				node->endianess = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_SIGN:
				node->sign = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_LSB:
				node->lsb = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_MSB:
				node->msb = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_BIT:
				node->msb = property_node;
				node->lsb = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_P_INVALIDATOR:
				node->invalidators = g_slist_prepend (node->invalidators, property_node);
				break;
			default:
				ARV_DOM_NODE_CLASS (parent_class)->post_new_child (self, child);
				break;
		}
	} else if (ARV_IS_GC_SWISS_KNIFE (child))
		node->swiss_knives = g_slist_prepend (node->swiss_knives, child);
	else
		ARV_DOM_NODE_CLASS (parent_class)->post_new_child (self, child);
}

static void
arv_gc_register_node_pre_remove_child (ArvDomNode *self, ArvDomNode *child)
{
	g_assert_not_reached ();
}

/* ArvGcFeatureNode implementation */

static GType
arv_gc_register_node_get_value_type (ArvGcFeatureNode *node)
{
	ArvGcRegisterNode *gc_register_node = ARV_GC_REGISTER_NODE (node);

	return gc_register_node->value_type;
}

static void
arv_gc_register_node_set_value_from_string (ArvGcFeatureNode *node, const char *string, GError **error)
{
	ArvGcRegisterNode *gc_register_node = ARV_GC_REGISTER_NODE (node);

	switch (gc_register_node->value_type) {
		case G_TYPE_INT64:
			arv_gc_integer_set_value (ARV_GC_INTEGER (node), g_ascii_strtoll (string, NULL, 0), error);
			break;
		case G_TYPE_DOUBLE:
			arv_gc_float_set_value (ARV_GC_FLOAT (node), g_ascii_strtod (string, NULL), error);
			break;
		case G_TYPE_STRING:
			arv_gc_string_set_value (ARV_GC_STRING (node), string, error);
			break;
		default:
			break;
	}

	arv_warning_genicam ("[GcRegisterNode::set_value_from_string] Invalid value type");
}

static const char *
arv_gc_register_node_get_value_as_string (ArvGcFeatureNode *node, GError **error)
{
	ArvGcRegisterNode *gc_register_node = ARV_GC_REGISTER_NODE (node);
	GError *local_error = NULL;
	const char *string;

	switch (gc_register_node->value_type) {
		case G_TYPE_INT64:
			g_snprintf (gc_register_node->v_string, G_ASCII_DTOSTR_BUF_SIZE,
				    "0x%08" G_GINT64_MODIFIER "x",
				    arv_gc_integer_get_value (ARV_GC_INTEGER (node), &local_error));

			if (local_error != NULL) {
				g_propagate_error (error, local_error);
				return NULL;
			}

			return gc_register_node->v_string;
		case G_TYPE_DOUBLE:
			g_ascii_dtostr (gc_register_node->v_string, G_ASCII_DTOSTR_BUF_SIZE,
					arv_gc_float_get_value (ARV_GC_FLOAT (node), &local_error));

			if (local_error != NULL) {
				g_propagate_error (error, local_error);
				return NULL;
			}

			return gc_register_node->v_string;
		case G_TYPE_STRING:
			string = arv_gc_string_get_value (ARV_GC_STRING (node), &local_error);

			if (local_error != NULL) {
				g_propagate_error (error, local_error);
				return NULL;
			}

			return string;
		default:
			break;
	}

	arv_warning_genicam ("[GcRegisterNode::get_value_as_string] Invalid value type");

	return NULL;
}

/* ArvGcRegisterNode implementation */

gboolean
_get_cache_validity (ArvGcRegisterNode *gc_register_node)
{
	GSList *iter;
	gint modification_count;
	gint feature_modification_count;
	gboolean is_cache_valid = gc_register_node->is_cache_valid;

	for (iter = gc_register_node->invalidators; iter != NULL; iter = iter->next) {
		ArvGcInvalidatorNode *invalidator = iter->data;
		ArvGcNode *node;

		modification_count = arv_gc_invalidator_node_get_modification_count (invalidator);
		node = arv_gc_property_node_get_linked_node (ARV_GC_PROPERTY_NODE (invalidator));
		feature_modification_count = arv_gc_feature_node_get_modification_count (ARV_GC_FEATURE_NODE (node));
		arv_gc_invalidator_node_set_modification_count (invalidator, feature_modification_count);
		if (modification_count != feature_modification_count)
			is_cache_valid = FALSE;
	}

	return is_cache_valid;
}

static gint64
_get_length (ArvGcRegisterNode *gc_register_node, GError **error)
{
	if (gc_register_node->length == NULL)
		return 4;

	return arv_gc_property_node_get_int64 (gc_register_node->length, error);
}

static guint64
_get_address (ArvGcRegisterNode *gc_register_node, GError **error)
{
	ArvGc *genicam;
	GError *local_error = NULL;
	GSList *iter;
	guint64 value = 0;

	genicam = arv_gc_node_get_genicam (ARV_GC_NODE (gc_register_node));
	g_return_val_if_fail (ARV_IS_GC (genicam), 0);

	for (iter = gc_register_node->addresses; iter != NULL; iter = iter->next) {
		value += arv_gc_property_node_get_int64 (iter->data, &local_error);

		if (local_error != NULL) {
			g_propagate_error (error, local_error);
			return 0;
		}
	}

	for (iter = gc_register_node->swiss_knives; iter != NULL; iter = iter->next) {
		value += arv_gc_integer_get_value (iter->data, &local_error);

		if (local_error != NULL) {
			g_propagate_error (error, local_error);
			return 0;
		}
	}

	if (gc_register_node->index != NULL) {
		gint64 length;

		length = _get_length (gc_register_node, &local_error);

		if (local_error != NULL) {
			g_propagate_error (error, local_error);
			return 0;
		}

		value += arv_gc_index_node_get_index (ARV_GC_INDEX_NODE (gc_register_node->index), length, &local_error);

		if (local_error != NULL) {
			g_propagate_error (error, local_error);
			return 0;
		}
	}

	return value;
}

static void
_update_cache_size (ArvGcRegisterNode *gc_register_node, GError **error)
{
	GError *local_error = NULL;
	gint64 length;

	length = _get_length (gc_register_node, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return;
	}

	if (length != gc_register_node->cache_size) {
		g_free (gc_register_node->cache);
		gc_register_node->cache = g_malloc (length);
		gc_register_node->cache_size = length;
	}

}

static ArvGcCachable
_get_cachable (ArvGcRegisterNode *gc_register_node, GError **error)
{
	GError *local_error = NULL;
	const char *cachable;

	if (gc_register_node->cachable == NULL)
		return ARV_GC_CACHABLE_NO_CACHE;

	cachable = arv_gc_property_node_get_string (gc_register_node->cachable, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return ARV_GC_CACHABLE_NO_CACHE;
	}

	if (g_strcmp0 (cachable, "WriteThrough") == 0)
		return ARV_GC_CACHABLE_WRITE_TRHOUGH;
	else if (strcmp (cachable, "WriteAround") == 0)
		return ARV_GC_CACHABLE_WRITE_AROUND;

	return ARV_GC_CACHABLE_NO_CACHE;
}

/* Set default to read only 32 bits little endian integer register */

static guint
_get_endianess (ArvGcRegisterNode *gc_register_node, GError **error)
{
	GError *local_error = NULL;
	const char *endianess;

	if (gc_register_node->endianess == NULL)
		return G_LITTLE_ENDIAN;

	endianess = arv_gc_property_node_get_string (gc_register_node->endianess, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return G_LITTLE_ENDIAN;
	}

	if (g_strcmp0 (endianess, "BigEndian") == 0)
		return G_BIG_ENDIAN;

	return G_LITTLE_ENDIAN;
}

static ArvGcSignedness
_get_signedness (ArvGcRegisterNode *gc_register_node, GError **error)
{
	GError *local_error = NULL;
	const char *sign;

	if (gc_register_node->sign == NULL)
		return gc_register_node->type == ARV_GC_REGISTER_NODE_TYPE_REGISTER ?
			ARV_GC_SIGNEDNESS_SIGNED :
			ARV_GC_SIGNEDNESS_UNSIGNED;

	sign = arv_gc_property_node_get_string (gc_register_node->sign, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return ARV_GC_SIGNEDNESS_SIGNED;
	}

	if (g_strcmp0 (sign, "Unsigned") == 0)
		return ARV_GC_SIGNEDNESS_UNSIGNED;

	return ARV_GC_SIGNEDNESS_SIGNED;
}

static gint64
_get_lsb (ArvGcRegisterNode *gc_register_node, GError **error)
{
	if (gc_register_node->lsb == NULL)
		return 0;

	return arv_gc_property_node_get_int64 (gc_register_node->lsb, error);
}

static gint64
_get_msb (ArvGcRegisterNode *gc_register_node, GError **error)
{
	if (gc_register_node->msb == NULL)
		return 31;

	return arv_gc_property_node_get_int64 (gc_register_node->msb, error);
}

static void
_read_cache (ArvGcRegisterNode *gc_register_node, GError **error)
{
	GError *local_error = NULL;
	ArvGcNode *port;
	gboolean cachable;
	gint64 address;

	if (gc_register_node->is_cache_valid == TRUE) {
		arv_log_genicam ("[GcRegisterNode::read_cache] Cache is valid");
		return;
	}

	port = arv_gc_property_node_get_linked_node (gc_register_node->port);
	if (!ARV_IS_GC_PORT (port))
		return;

	_update_cache_size (gc_register_node, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return;
	}

	address = _get_address (gc_register_node, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return;
	}

	arv_gc_port_read (ARV_GC_PORT (port),
			  gc_register_node->cache,
			  address,
			  gc_register_node->cache_size, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return;
	}

	cachable = _get_cachable (gc_register_node, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return;
	}

	if (cachable != ARV_GC_CACHABLE_NO_CACHE)
		gc_register_node->is_cache_valid = TRUE;
	else
		gc_register_node->is_cache_valid = FALSE;
}

static void
_write_cache (ArvGcRegisterNode *gc_register_node, GError **error)
{
	GError *local_error = NULL;
	gint64 address;
	gboolean cachable;
	ArvGcNode *port;

	arv_gc_feature_node_inc_modification_count (ARV_GC_FEATURE_NODE (gc_register_node));

	port = arv_gc_property_node_get_linked_node (gc_register_node->port);
	if (!ARV_IS_GC_PORT (port))
		return;

	_update_cache_size (gc_register_node, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return;
	}

	address = _get_address (gc_register_node, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return;
	}

	arv_gc_port_write (ARV_GC_PORT (port),
			   gc_register_node->cache,
			   address,<commit_msg>gcregisternode: fix cachable variable type<commit_after>/* Aravis - Digital camera library
 *
 * Copyright © 2009-2019 <NAME>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 * Author: <NAME> <<EMAIL>>
 */

/**
 * SECTION: arvgcregisternode
 * @short_description: Class for Register, IntReg, MaskedIntReg, FloatReg, StringReg and StructReg nodes
 */

#include <arvgcregisternode.h>
#include <arvgcindexnode.h>
#include <arvgcinvalidatornode.h>
#include <arvgcswissknife.h>
#include <arvgcregister.h>
#include <arvgcinteger.h>
#include <arvgcfloat.h>
#include <arvgcstring.h>
#include <arvgcport.h>
#include <arvgc.h>
#include <arvmisc.h>
#include <arvdebug.h>
#include <stdlib.h>
#include <string.h>

static GObjectClass *parent_class = NULL;

/* ArvDomNode implementation */

static const char *
arv_gc_register_node_get_node_name (ArvDomNode *node)
{
	ArvGcRegisterNode *gc_register_node = ARV_GC_REGISTER_NODE (node);

	switch (gc_register_node->type) {
		case ARV_GC_REGISTER_NODE_TYPE_REGISTER:
			return "Register";
		case ARV_GC_REGISTER_NODE_TYPE_INTEGER:
			return "IntReg";
		case ARV_GC_REGISTER_NODE_TYPE_MASKED_INTEGER:
			return "MaskedIntReg";
		case ARV_GC_REGISTER_NODE_TYPE_FLOAT:
			return "FloatReg";
		case ARV_GC_REGISTER_NODE_TYPE_STRING:
			return "StringReg";
		case ARV_GC_REGISTER_NODE_TYPE_STRUCT_REGISTER:
			return "StuctReg";
	}

	return NULL;
}

static void
arv_gc_register_node_post_new_child (ArvDomNode *self, ArvDomNode *child)
{
	ArvGcRegisterNode *node = ARV_GC_REGISTER_NODE (self);

	if (ARV_IS_GC_PROPERTY_NODE (child)) {
		ArvGcPropertyNode *property_node = ARV_GC_PROPERTY_NODE (child);

		switch (arv_gc_property_node_get_node_type (property_node)) {
			case ARV_GC_PROPERTY_NODE_TYPE_ADDRESS:
			case ARV_GC_PROPERTY_NODE_TYPE_P_ADDRESS:
				node->addresses = g_slist_prepend (node->addresses, child);
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_P_INDEX:
				node->index = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_LENGTH:
			case ARV_GC_PROPERTY_NODE_TYPE_P_LENGTH:
				node->length = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_P_PORT:
				node->port = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_ACCESS_MODE:
				/* TODO */
				node->access_mode = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_CACHABLE:
				node->cachable = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_POLLING_TIME:
				/* TODO */
				node->polling_time = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_ENDIANESS:
				node->endianess = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_SIGN:
				node->sign = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_LSB:
				node->lsb = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_MSB:
				node->msb = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_BIT:
				node->msb = property_node;
				node->lsb = property_node;
				break;
			case ARV_GC_PROPERTY_NODE_TYPE_P_INVALIDATOR:
				node->invalidators = g_slist_prepend (node->invalidators, property_node);
				break;
			default:
				ARV_DOM_NODE_CLASS (parent_class)->post_new_child (self, child);
				break;
		}
	} else if (ARV_IS_GC_SWISS_KNIFE (child))
		node->swiss_knives = g_slist_prepend (node->swiss_knives, child);
	else
		ARV_DOM_NODE_CLASS (parent_class)->post_new_child (self, child);
}

static void
arv_gc_register_node_pre_remove_child (ArvDomNode *self, ArvDomNode *child)
{
	g_assert_not_reached ();
}

/* ArvGcFeatureNode implementation */

static GType
arv_gc_register_node_get_value_type (ArvGcFeatureNode *node)
{
	ArvGcRegisterNode *gc_register_node = ARV_GC_REGISTER_NODE (node);

	return gc_register_node->value_type;
}

static void
arv_gc_register_node_set_value_from_string (ArvGcFeatureNode *node, const char *string, GError **error)
{
	ArvGcRegisterNode *gc_register_node = ARV_GC_REGISTER_NODE (node);

	switch (gc_register_node->value_type) {
		case G_TYPE_INT64:
			arv_gc_integer_set_value (ARV_GC_INTEGER (node), g_ascii_strtoll (string, NULL, 0), error);
			break;
		case G_TYPE_DOUBLE:
			arv_gc_float_set_value (ARV_GC_FLOAT (node), g_ascii_strtod (string, NULL), error);
			break;
		case G_TYPE_STRING:
			arv_gc_string_set_value (ARV_GC_STRING (node), string, error);
			break;
		default:
			break;
	}

	arv_warning_genicam ("[GcRegisterNode::set_value_from_string] Invalid value type");
}

static const char *
arv_gc_register_node_get_value_as_string (ArvGcFeatureNode *node, GError **error)
{
	ArvGcRegisterNode *gc_register_node = ARV_GC_REGISTER_NODE (node);
	GError *local_error = NULL;
	const char *string;

	switch (gc_register_node->value_type) {
		case G_TYPE_INT64:
			g_snprintf (gc_register_node->v_string, G_ASCII_DTOSTR_BUF_SIZE,
				    "0x%08" G_GINT64_MODIFIER "x",
				    arv_gc_integer_get_value (ARV_GC_INTEGER (node), &local_error));

			if (local_error != NULL) {
				g_propagate_error (error, local_error);
				return NULL;
			}

			return gc_register_node->v_string;
		case G_TYPE_DOUBLE:
			g_ascii_dtostr (gc_register_node->v_string, G_ASCII_DTOSTR_BUF_SIZE,
					arv_gc_float_get_value (ARV_GC_FLOAT (node), &local_error));

			if (local_error != NULL) {
				g_propagate_error (error, local_error);
				return NULL;
			}

			return gc_register_node->v_string;
		case G_TYPE_STRING:
			string = arv_gc_string_get_value (ARV_GC_STRING (node), &local_error);

			if (local_error != NULL) {
				g_propagate_error (error, local_error);
				return NULL;
			}

			return string;
		default:
			break;
	}

	arv_warning_genicam ("[GcRegisterNode::get_value_as_string] Invalid value type");

	return NULL;
}

/* ArvGcRegisterNode implementation */

gboolean
_get_cache_validity (ArvGcRegisterNode *gc_register_node)
{
	GSList *iter;
	gint modification_count;
	gint feature_modification_count;
	gboolean is_cache_valid = gc_register_node->is_cache_valid;

	for (iter = gc_register_node->invalidators; iter != NULL; iter = iter->next) {
		ArvGcInvalidatorNode *invalidator = iter->data;
		ArvGcNode *node;

		modification_count = arv_gc_invalidator_node_get_modification_count (invalidator);
		node = arv_gc_property_node_get_linked_node (ARV_GC_PROPERTY_NODE (invalidator));
		feature_modification_count = arv_gc_feature_node_get_modification_count (ARV_GC_FEATURE_NODE (node));
		arv_gc_invalidator_node_set_modification_count (invalidator, feature_modification_count);
		if (modification_count != feature_modification_count)
			is_cache_valid = FALSE;
	}

	return is_cache_valid;
}

static gint64
_get_length (ArvGcRegisterNode *gc_register_node, GError **error)
{
	if (gc_register_node->length == NULL)
		return 4;

	return arv_gc_property_node_get_int64 (gc_register_node->length, error);
}

static guint64
_get_address (ArvGcRegisterNode *gc_register_node, GError **error)
{
	ArvGc *genicam;
	GError *local_error = NULL;
	GSList *iter;
	guint64 value = 0;

	genicam = arv_gc_node_get_genicam (ARV_GC_NODE (gc_register_node));
	g_return_val_if_fail (ARV_IS_GC (genicam), 0);

	for (iter = gc_register_node->addresses; iter != NULL; iter = iter->next) {
		value += arv_gc_property_node_get_int64 (iter->data, &local_error);

		if (local_error != NULL) {
			g_propagate_error (error, local_error);
			return 0;
		}
	}

	for (iter = gc_register_node->swiss_knives; iter != NULL; iter = iter->next) {
		value += arv_gc_integer_get_value (iter->data, &local_error);

		if (local_error != NULL) {
			g_propagate_error (error, local_error);
			return 0;
		}
	}

	if (gc_register_node->index != NULL) {
		gint64 length;

		length = _get_length (gc_register_node, &local_error);

		if (local_error != NULL) {
			g_propagate_error (error, local_error);
			return 0;
		}

		value += arv_gc_index_node_get_index (ARV_GC_INDEX_NODE (gc_register_node->index), length, &local_error);

		if (local_error != NULL) {
			g_propagate_error (error, local_error);
			return 0;
		}
	}

	return value;
}

static void
_update_cache_size (ArvGcRegisterNode *gc_register_node, GError **error)
{
	GError *local_error = NULL;
	gint64 length;

	length = _get_length (gc_register_node, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return;
	}

	if (length != gc_register_node->cache_size) {
		g_free (gc_register_node->cache);
		gc_register_node->cache = g_malloc (length);
		gc_register_node->cache_size = length;
	}

}

static ArvGcCachable
_get_cachable (ArvGcRegisterNode *gc_register_node, GError **error)
{
	GError *local_error = NULL;
	const char *cachable;

	if (gc_register_node->cachable == NULL)
		return ARV_GC_CACHABLE_NO_CACHE;

	cachable = arv_gc_property_node_get_string (gc_register_node->cachable, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return ARV_GC_CACHABLE_NO_CACHE;
	}

	if (g_strcmp0 (cachable, "WriteThrough") == 0)
		return ARV_GC_CACHABLE_WRITE_TRHOUGH;
	else if (strcmp (cachable, "WriteAround") == 0)
		return ARV_GC_CACHABLE_WRITE_AROUND;

	return ARV_GC_CACHABLE_NO_CACHE;
}

/* Set default to read only 32 bits little endian integer register */

static guint
_get_endianess (ArvGcRegisterNode *gc_register_node, GError **error)
{
	GError *local_error = NULL;
	const char *endianess;

	if (gc_register_node->endianess == NULL)
		return G_LITTLE_ENDIAN;

	endianess = arv_gc_property_node_get_string (gc_register_node->endianess, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return G_LITTLE_ENDIAN;
	}

	if (g_strcmp0 (endianess, "BigEndian") == 0)
		return G_BIG_ENDIAN;

	return G_LITTLE_ENDIAN;
}

static ArvGcSignedness
_get_signedness (ArvGcRegisterNode *gc_register_node, GError **error)
{
	GError *local_error = NULL;
	const char *sign;

	if (gc_register_node->sign == NULL)
		return gc_register_node->type == ARV_GC_REGISTER_NODE_TYPE_REGISTER ?
			ARV_GC_SIGNEDNESS_SIGNED :
			ARV_GC_SIGNEDNESS_UNSIGNED;

	sign = arv_gc_property_node_get_string (gc_register_node->sign, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return ARV_GC_SIGNEDNESS_SIGNED;
	}

	if (g_strcmp0 (sign, "Unsigned") == 0)
		return ARV_GC_SIGNEDNESS_UNSIGNED;

	return ARV_GC_SIGNEDNESS_SIGNED;
}

static gint64
_get_lsb (ArvGcRegisterNode *gc_register_node, GError **error)
{
	if (gc_register_node->lsb == NULL)
		return 0;

	return arv_gc_property_node_get_int64 (gc_register_node->lsb, error);
}

static gint64
_get_msb (ArvGcRegisterNode *gc_register_node, GError **error)
{
	if (gc_register_node->msb == NULL)
		return 31;

	return arv_gc_property_node_get_int64 (gc_register_node->msb, error);
}

static void
_read_cache (ArvGcRegisterNode *gc_register_node, GError **error)
{
	GError *local_error = NULL;
	ArvGcNode *port;
	ArvGcCachable cachable;
	gint64 address;

	if (gc_register_node->is_cache_valid == TRUE) {
		arv_log_genicam ("[GcRegisterNode::read_cache] Cache is valid");
		return;
	}

	port = arv_gc_property_node_get_linked_node (gc_register_node->port);
	if (!ARV_IS_GC_PORT (port))
		return;

	_update_cache_size (gc_register_node, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return;
	}

	address = _get_address (gc_register_node, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return;
	}

	arv_gc_port_read (ARV_GC_PORT (port),
			  gc_register_node->cache,
			  address,
			  gc_register_node->cache_size, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return;
	}

	cachable = _get_cachable (gc_register_node, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return;
	}

	if (cachable != ARV_GC_CACHABLE_NO_CACHE)
		gc_register_node->is_cache_valid = TRUE;
	else
		gc_register_node->is_cache_valid = FALSE;
}

static void
_write_cache (ArvGcRegisterNode *gc_register_node, GError **error)
{
	GError *local_error = NULL;
	gint64 address;
	ArvGcCachable cachable;
	ArvGcNode *port;

	arv_gc_feature_node_inc_modification_count (ARV_GC_FEATURE_NODE (gc_register_node));

	port = arv_gc_property_node_get_linked_node (gc_register_node->port);
	if (!ARV_IS_GC_PORT (port))
		return;

	_update_cache_size (gc_register_node, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return;
	}

	address = _get_address (gc_register_node, &local_error);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return;
	}

	arv_gc_port_write (ARV_GC_PORT (port),
			   gc_register_node->cache,
			   address,
{'fraction_non_alphanumeric': 0.09529050130924822, 'fraction_numerical': 0.005692383590755569, 'mean_word_length': 5.3606082548877625, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 169, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '479803', 'n_tokens_mistral': 10927, 'n_tokens_neox': 10000, 'n_words': 1987}