Files
handleaiuinew/env/LMI/include/GoSdk/Tools/GoTool.c
T
2024-05-18 23:53:26 +08:00

744 lines
21 KiB
C

/**
* @file GoTool.c
*
* @internal
* Copyright (C) 2016-2021 by LMI Technologies Inc.
* Licensed under the MIT License.
* Redistributed files must retain the above copyright notice.
*/
#include <GoSdk/Tools/GoTool.h>
#include <GoSdk/GoUtils.h>
#include <GoSdk/GoSensor.h>
kBeginClassEx(Go, GoTool)
kAddVMethod(GoTool, kObject, VRelease)
kAddVMethod(GoTool, GoTool, VInit)
kAddVMethod(GoTool, GoTool, VRead)
kAddVMethod(GoTool, GoTool, VWrite)
kEndClassEx()
GoFx(kStatus) GoTool_Construct(GoTool* tool, kType type, kObject sensor, kAlloc allocator)
{
kAlloc alloc = kAlloc_Fallback(allocator);
kStatus status;
kCheck(kAlloc_GetObject(alloc, type, tool));
if (!kSuccess(status = kType_VTableT(type, GoTool)->VInit(*tool, type, sensor, alloc)))
{
kAlloc_FreeRef(alloc, tool);
}
return status;
}
GoFx(kStatus) GoTool_VInit(GoTool tool, kType type, kObject sensor, kAlloc alloc)
{
return kERROR_UNIMPLEMENTED; //this function must be overriden by every tool
}
GoFx(kStatus) GoTool_Init(GoTool tool, kType type, GoToolType typeId, kObject sensor, kAlloc alloc)
{
kObjR(GoTool, tool);
kStatus exception;
kCheck(kObject_Init(tool, type, alloc));
obj->index = 0;
kZero(obj->xml);
kZero(obj->xmlItem);
obj->name[0] = 0;
obj->format = GO_TOOL_FORMAT_STANDARD;
kZero(obj->featureOutputs);
kZero(obj->featureOptions);
kZero(obj->featureNodesToMerge);
kZero(obj->measurements);
kZero(obj->measurementOptions);
kZero(obj->measurementNodesToMerge);
obj->id = GO_UNASSIGNED_ID;
obj->sensor = sensor;
obj->typeId = typeId;
kTry
{
kTest(kArrayList_Construct(&obj->featureNodesToMerge, kTypeOf(kPointer), 0, alloc));
kTest(kArrayList_Construct(&obj->measurementNodesToMerge, kTypeOf(kPointer), 0, alloc));
kTest(kArrayList_Construct(&obj->measurements, kTypeOf(GoMeasurement), 0, alloc));
kTest(kArrayList_Construct(&obj->featureOutputs, kTypeOf(GoFeature), 0, alloc));
//kTest(kArrayList_Construct(&obj->measurementOptions, kTypeOf(kPointer), 0, alloc));
//kTest(kArrayList_Construct(&obj->featureOptions, kTypeOf(kPointer), 0, alloc));
}
kCatch(&exception)
{
GoTool_VRelease(tool);
kEndCatch(exception);
}
return kOK;
}
GoFx(kStatus) GoTool_VRelease(GoTool tool)
{
kObj(GoTool, tool);
kCheck(kDestroyRef(&obj->featureNodesToMerge));
kCheck(kDestroyRef(&obj->measurementNodesToMerge));
kCheck(kDisposeRef(&obj->measurements));
kCheck(kDisposeRef(&obj->featureOutputs));
//kCheck(kDisposeRef(&obj->measurementOptions));
//kCheck(kDisposeRef(&obj->featureOptions));
return kObject_VRelease(tool);
}
// Reads the tool XML node specified by "item".
GoFx(kStatus) GoTool_VRead(GoTool tool, kXml xml, kXmlItem item)
{
kObj(GoTool, tool);
kXmlItem toolNameItem = kNULL;
kXmlItem measurements = kNULL;
kXmlItem features = kNULL;
kText64 toolType;
obj->xml = xml;
obj->xmlItem = item;
if (kXml_AttrExists(xml, item, GO_XML_TAG_NAME_ATTR_TOOL_ID))
{
kCheck(kXml_Attr32s(xml, item, GO_XML_TAG_NAME_ATTR_TOOL_ID, &obj->id));
}
else
{
obj->id = GO_UNASSIGNED_ID;
}
// GOC-14127: The format is used to validate/correct the tool name and
// Feature/Measurement/ToolDataOutput name so this must be set up
// before reading Features/Measurements/ToolDataOutputs.
if (kXml_AttrExists(xml, item, GO_XML_TAG_NAME_ATTR_FORMAT))
{
kCheck(kXml_Attr32s(xml, item, GO_XML_TAG_NAME_ATTR_FORMAT, &obj->format));
}
else
{
obj->format = GO_TOOL_FORMAT_UNKNOWN;
}
kCheck(kArrayList_Clear(obj->measurementNodesToMerge));
kCheck(kArrayList_Clear(obj->featureNodesToMerge));
kCheck(GoTool_ReadToolName(tool, xml, item));
// GOC-14127: Get the tool name, making use of the tool format version to determine
// if tool is an internal GDK tool or not, which requires special handling
// to map tool type to a tool name.
// NOTE: the GoTools_FormatToolType() call would also work by providing
// GoTool_ReadMeasurements() and GoTool_ReadFeatures() with a tool name
// they can use in their lookup tables, but the
// new API is used instead because the returned result is more correct.
kCheck(GoTools_FormatToolTypeExtToolFormat(kObject_Type(tool), GoTool_IsGdkInternal(tool), toolType, kCountOf(toolType)));
kCheck(!kIsNull(measurements = kXml_Child(xml, item, "Measurements")));
kCheck(GoTool_ReadMeasurements(tool, xml, measurements, toolType));
if (!kIsNull(features = kXml_Child(xml, item, "Features")))
{
kCheck(GoTool_ReadFeatures(tool, xml, features, toolType));
}
return kOK;
}
GoFx(kStatus) GoTool_VWrite(GoTool tool, kXml xml, kXmlItem item)
{
kObj(GoTool, tool);
kXmlItem temp = kNULL;
kXmlItem child = kNULL;
kXmlItem toolItem = kNULL;
kXmlItem measurementsItem = kNULL;
kXmlItem measurementItem = kNULL;
GoMeasurement measurement = kNULL;
kText64 measurementName;
kXmlItem featuresItem = kNULL;
kXmlItem featureItem = kNULL;
GoFeature feature = kNULL;
kText64 featureName;
kSize i;
kXml xmlCopy = kNULL;
if (obj->id != GO_UNASSIGNED_ID)
{
kCheck(kXml_SetAttr32s(xml, item, "id", obj->id));
}
if (obj->format != GO_TOOL_FORMAT_UNKNOWN)
{
kCheck(kXml_SetAttr32s(xml, item, "format", obj->format));
}
kCheck(kXml_SetChildText(xml, item, "Name", obj->name));
kCheck(kXml_AddItem(xml, item, "Measurements", &measurementsItem));
for (i = 0; i < kArrayList_Count(obj->measurements); i++)
{
measurement = kArrayList_AsT(obj->measurements, i, GoMeasurement);
// GOC-14127: on write, choose the correct measurement name
// for GDK tools based on whether the tool is a USER GDK or
// INTERNAL GDK tool.
kCheck(GoMeasurements_FormatTypeExtToolFormat(kObject_Type(measurement), GoTool_IsGdkInternal(tool), measurementName, kCountOf(measurementName)));
kCheck(kXml_AddItem(xml, measurementsItem, measurementName, &measurementItem));
kCheck(GoMeasurement_Write(measurement, xml, measurementItem));
}
for (i = 0; i < kArrayList_Count(obj->measurementNodesToMerge); i++)
{
kXmlItem itemToMerge = *kArrayList_AtT(obj->measurementNodesToMerge, i, kXmlItem);
kCheck(kXml_CopyItem(xml, measurementsItem, kNULL, obj->xml, itemToMerge, kNULL));
}
kCheck(kXml_AddItem(xml, item, "Features", &featuresItem));
for (i = 0; i < kArrayList_Count(obj->featureOutputs); i++)
{
feature = kArrayList_AsT(obj->featureOutputs, i, GoFeature);
// GOC-14127: on write, choose the correct feature name
// for GDK tools based on whether the tool is a USER GDK or
// INTERNAL GDK tool.
kCheck(GoFeatures_FormatTypeExtToolFormat(kObject_Type(feature), GoTool_IsGdkInternal(tool), featureName, kCountOf(featureName)));
kCheck(kXml_AddItem(xml, featuresItem, featureName, &featureItem));
kCheck(GoFeature_Write(feature, xml, featureItem));
}
for (i = 0; i < kArrayList_Count(obj->featureNodesToMerge); i++)
{
kXmlItem itemToMerge = *kArrayList_AtT(obj->featureNodesToMerge, i, kXmlItem);
kCheck(kXml_CopyItem(xml, featuresItem, kNULL, obj->xml, itemToMerge, kNULL));
}
kCheck(GoUtils_XmlMerge(obj->xml, obj->xmlItem, xml, item));
return kOK;
}
GoFx(kStatus) GoTool_Read(GoTool tool, kXml xml, kXmlItem item)
{
kObj(GoTool, tool);
return kCast(GoToolVTable*, xkObject_VTable(tool))->VRead(tool, xml, item);
}
GoFx(kStatus) GoTool_Write(GoTool tool, kXml xml, kXmlItem item)
{
kObj(GoTool, tool);
return kCast(GoToolVTable*, xkObject_VTable(tool))->VWrite(tool, xml, item);
}
GoFx(kStatus) GoTool_ReadMeasurements(GoTool tool, kXml xml, kXmlItem measurements, const kText64 toolType)
{
kObj(GoTool, tool);
kXmlItem measurementItem = kNULL;
GoMeasurement measurement;
kType measurementType;
kBool insertMeasurement;
kBool isFilterable;
kSize i;
for (i = 0; i < kXml_ChildCount(xml, measurements); i++)
{
measurementItem = kXml_ChildAt(xml, measurements, i);
measurement = kNULL;
insertMeasurement = kFALSE;
isFilterable = kTRUE;
if (kSuccess(GoMeasurements_ParseType(toolType, kXml_ItemName(xml, measurementItem), &measurementType)))
{
if (i >= kArrayList_Count(obj->measurements)
|| kIsNull(measurement = kArrayList_AsT(obj->measurements, i, GoMeasurement))
|| !kObject_Is(measurement, measurementType))
{
if (measurementType == kTypeOf(GoScriptOutput))
{
isFilterable = kFALSE;
}
if (!kIsNull(measurement))
{
kCheck(kArrayList_Discard(obj->measurements, i));
kDestroyRef(&measurement);
}
kCheck(GoMeasurement_Construct(&measurement, measurementType, obj->sensor, tool, isFilterable, kObject_Alloc(tool)));
insertMeasurement = kTRUE;
}
kCheck(GoMeasurement_Read(measurement, xml, measurementItem));
if (insertMeasurement)
{
if (i >= kArrayList_Count(obj->measurements))
kCheck(kArrayList_AddT(obj->measurements, &measurement));
else
kCheck(kArrayList_InsertT(obj->measurements, i, &measurement));
}
}
else
{
kCheck(kArrayList_AddT(obj->measurementNodesToMerge, &measurementItem));
}
}
while (kXml_ChildCount(xml, measurements) < kArrayList_Count(obj->measurements)) //arraylist is accessed directly due to refresh behavior when the remove measurement function is used
{
kCheck(kArrayList_RemoveT(obj->measurements, kArrayList_Count(obj->measurements) - 1, &measurement));
kDestroyRef(&measurement);
}
return kOK;
}
GoFx(kStatus) GoTool_ReadFeatures(GoTool tool, kXml xml, kXmlItem features, const kText64 toolType)
{
kObj(GoTool, tool);
kXmlItem featureItem = kNULL;
GoFeature feature;
kType featureType;
kBool insertFeature;
kSize i;
kSize numFeatures;
numFeatures = kXml_ChildCount(xml, features);
for (i = 0; i < numFeatures; i++)
{
featureItem = kXml_ChildAt(xml, features, i);
feature = kNULL;
insertFeature = kFALSE;
if (kSuccess(GoFeatures_ParseType(toolType, kXml_ItemName(xml, featureItem), &featureType)))
{
if (i >= kArrayList_Count(obj->featureOutputs)
|| kIsNull(feature = kArrayList_AsT(obj->featureOutputs, i, GoFeature))
|| !kObject_Is(feature, featureType))
{
if (!kIsNull(feature))
{
kCheck(kArrayList_Discard(obj->featureOutputs, i));
kDestroyRef(&feature);
}
kCheck(GoFeature_Construct(&feature, featureType, obj->sensor, tool, kObject_Alloc(tool)));
insertFeature = kTRUE;
}
kCheck(GoFeature_Read(feature, xml, featureItem));
if (insertFeature)
{
kCheck(kArrayList_InsertT(obj->featureOutputs, i, &feature));
}
}
else
{
if (i >= kArrayList_Count(obj->featureNodesToMerge))
kCheck(kArrayList_AddT(obj->featureNodesToMerge, &featureItem));
else
kCheck(kArrayList_InsertT(obj->featureNodesToMerge, i, &featureItem));
}
}
// Arraylist is accessed directly due to refresh behavior when the remove measurement function is used
while (kXml_ChildCount(xml, features) < kArrayList_Count(obj->featureOutputs))
{
kCheck(kArrayList_RemoveT(obj->featureOutputs, kArrayList_Count(obj->featureOutputs) - 1, &feature));
kDestroyRef(&feature);
}
return kOK;
}
GoFx(kSize) GoTool_MeasurementCount(GoTool tool)
{
kObj(GoTool, tool);
GoSensor_SyncConfig(obj->sensor);
return kArrayList_Count(obj->measurements);
}
GoFx(GoMeasurement) GoTool_MeasurementAt(GoTool tool, kSize index)
{
kObj(GoTool, tool);
GoSensor_SyncConfig(obj->sensor);
kAssert(index < kArrayList_Count(obj->measurements));
return kArrayList_AsT(obj->measurements, index, GoMeasurement);
}
GoFx(kStatus) GoTool_AddMeasurement(GoTool tool, kType type, kBool isFilterable, GoMeasurement* measurement)
{
kObj(GoTool, tool);
GoMeasurement output = kNULL;
kStatus exception;
//private method, no need to check configurable or set modified
kTry
{
kTest(GoMeasurement_Construct(&output, type, obj->sensor, tool, isFilterable, kObject_Alloc(tool)));
kTest(kArrayList_AddT(obj->measurements, &output));
if(!kIsNull(measurement))
{
*measurement = output;
}
}
kCatch(&exception)
{
kDestroyRef(&output);
kEndCatch(exception);
}
return kOK;
}
GoFx(kStatus) GoTool_AddExtMeasurement(GoTool tool, kType type, kBool isFilterable, GoExtMeasurement* measurement)
{
kObj(GoTool, tool);
GoMeasurement output = kNULL;
kStatus exception;
//private method, no need to check configurable or set modified
kTry
{
kTest(GoExtMeasurement_Construct(&output, type, obj->sensor, tool, isFilterable, kObject_Alloc(tool)));
kTest(GoSensor_IsConfigurable(obj->sensor));
kTest(GoSensor_CacheConfig(obj->sensor));
kTest(kArrayList_AddT(obj->measurements, &output));
kTest(GoSensor_SetConfigModified(obj->sensor));
if (!kIsNull(measurement))
{
*measurement = output;
}
}
kCatch(&exception)
{
kDestroyRef(&output);
kEndCatch(exception);
}
return kOK;
}
GoFx(kStatus) GoTool_RemoveMeasurement(GoTool tool, kSize index)
{
kObj(GoTool, tool);
GoMeasurement measurement = kNULL;
kCheckState(GoSensor_IsConfigurable(obj->sensor));
kCheck(GoSensor_CacheConfig(obj->sensor));
//private method, no need to check configurable or set modified
kCheck(kArrayList_RemoveT(obj->measurements, index, &measurement));
kCheck(kDestroyRef(&measurement));
kCheck(GoSensor_SetConfigModified(obj->sensor));
return kOK;
}
GoFx(kStatus) GoTool_ClearMeasurements(GoTool tool)
{
kObj(GoTool, tool);
kCheckState(GoSensor_IsConfigurable(obj->sensor));
kCheck(GoSensor_CacheConfig(obj->sensor));
//private method, no need to check configurable or set modified
kCheck(kArrayList_Purge(obj->measurements));
kCheck(GoSensor_SetConfigModified(obj->sensor));
return kOK;
}
GoFx(kSize) GoTool_FeatureOutputCount(GoTool tool)
{
kObj(GoTool, tool);
GoSensor_SyncConfig(obj->sensor);
return kArrayList_Count(obj->featureOutputs);
}
GoFx(GoFeature) GoTool_FeatureOutputAt(GoTool tool, kSize index)
{
kObj(GoTool, tool);
GoSensor_SyncConfig(obj->sensor);
kAssert(index < kArrayList_Count(obj->featureOutputs));
return kArrayList_AsT(obj->featureOutputs, index, GoFeature);
}
GoFx(kStatus) GoTool_AddFeatureOutput(GoTool tool, kType type, GoFeature* featureOutput)
{
kObj(GoTool, tool);
GoFeature output = kNULL;
kStatus exception;
//private method, no need to check configurable or set modified
kTry
{
kTest(GoFeature_Construct(&output, type, obj->sensor, tool, kObject_Alloc(tool)));
kTest(kArrayList_AddT(obj->featureOutputs, &output));
if(!kIsNull(featureOutput))
{
*featureOutput = output;
}
}
kCatch(&exception)
{
kDestroyRef(&output);
kEndCatch(exception);
}
return kOK;
}
GoFx(kStatus) GoTool_RemoveFeatureOutput(GoTool tool, kSize index)
{
kObj(GoTool, tool);
GoFeature featureOutput = kNULL;
kCheckState(GoSensor_IsConfigurable(obj->sensor));
kCheck(GoSensor_CacheConfig(obj->sensor));
//private method, no need to check configurable or set modified
kCheck(kArrayList_RemoveT(obj->featureOutputs, index, &featureOutput));
kCheck(kDestroyRef(&featureOutput));
kCheck(GoSensor_SetConfigModified(obj->sensor));
return kOK;
}
GoFx(kStatus) GoTool_ClearFeatureOutputs(GoTool tool)
{
kObj(GoTool, tool);
kCheckState(GoSensor_IsConfigurable(obj->sensor));
kCheck(GoSensor_CacheConfig(obj->sensor));
//private method, no need to check configurable or set modified
kCheck(kArrayList_Purge(obj->featureOutputs));
kCheck(GoSensor_SetConfigModified(obj->sensor));
return kOK;
}
GoFx(kStatus) GoTool_SetName(GoTool tool, const kChar* name)
{
kObj(GoTool, tool);
kCheckState(GoSensor_IsConfigurable(obj->sensor));
kCheck(GoSensor_CacheConfig(obj->sensor));
kStrCopy(obj->name, kCountOf(obj->name), name);
kCheck(GoSensor_SetConfigModified(obj->sensor));
return kOK;
}
GoFx(kStatus) GoTool_Name(GoTool tool, kChar* name, kSize capacity)
{
kObj(GoTool, tool);
GoSensor_SyncConfig(obj->sensor);
kStrCopy(name, capacity, obj->name);
return kOK;
}
GoFx(kObject) GoTool_Sensor(GoTool tool)
{
kObj(GoTool, tool);
return obj->sensor;
}
GoFx(GoMeasurement) GoTool_FindMeasurementByType(GoTool tool, GoMeasurementType type)
{
kSize i;
GoMeasurement measurement = kNULL;
kBool found = kFALSE;
for (i = 0; i < GoTool_MeasurementCount(tool); i++)
{
measurement = GoTool_MeasurementAt(tool, i);
if (GoMeasurement_Type(measurement) == type)
{
found = kTRUE;
break;
}
}
if (!found)
{
return kNULL;
}
return measurement;
}
GoFx(GoFeature) GoTool_FindFeatureOutputByType(GoTool tool, GoFeatureType type)
{
kObj(GoTool, tool);
kSize i;
GoFeature feature = kNULL;
kBool found = kFALSE;
GoSensor_SyncConfig(obj->sensor);
for (i = 0; i < GoTool_FeatureOutputCount(tool); i++)
{
feature = GoTool_FeatureOutputAt(tool, i);
if (GoFeature_TypeId(feature) == type)
{
found = kTRUE;
break;
}
}
if (!found)
{
return kNULL;
}
return feature;
}
GoFx(GoToolType) GoTool_Type(GoTool tool)
{
kObj(GoTool, tool);
GoSensor_SyncConfig(obj->sensor);
return obj->typeId;
}
GoFx(k32s) GoTool_Id(GoTool tool)
{
kObj(GoTool, tool);
GoSensor_SyncConfig(obj->sensor);
return obj->id;
}
GoFx(kStatus) GoTool_SetIndex(GoTool tool, kSize index)
{
kObj(GoTool, tool);
obj->index = index;
return kOK;
}
// Helper function to set the tool name member variable.
GoFx(kStatus) GoTool_ReadToolName(GoTool tool, kXml xml, kXmlItem item)
{
kObj(GoTool, tool);
kXmlItem toolNameItem = kNULL;
kCheck(!kIsNull(toolNameItem = kXml_Child(xml, item, "Name")));
kCheck(kXml_ItemText(xml, toolNameItem, obj->name, kCountOf(obj->name)));
return kOK;
}
// GOC-14127: This function checks the GDK tool format to determine if it is
// an INTERNAL GDK tool or not.
// It is useful when formatting the XML configuration file for
// a GDK tool to know if the tool is a USER GDK tool or an
// INTERNAL GDK tool.
GoFx(kBool) GoTool_IsGdkInternal(GoTool tool)
{
kObj(GoTool, tool);
return (obj->format == GO_TOOL_FORMAT_GDK_INTERNAL);
}
GoFx(kStatus) GoToolUtil_ParseStreamOptions(GoTool tool, kXml xml, kXmlItem item, kArrayList list)
{
kObj(GoTool, tool);
kXml tempItem = kNULL;
kString csvList = kNULL;
kArrayList tempArrayList = kNULL;
kTry
{
kTest(kString_Construct(&csvList, "", kObject_Alloc(tool)));
if (kXml_ChildExists(xml, item, "StreamOptions"))
{
kXmlItem streamItem = kXml_Child(xml, item, "StreamOptions");
kSize i,j;
kTest(kArrayList_Clear(list));
for (i = 0; i < kXml_ChildCount(xml, streamItem); i++)
{
GoDataStream option;
tempItem = kXml_ChildAt(xml, streamItem, i);
if (!kIsNull(tempItem))
{
kTest(kXml_Attr32s(xml, tempItem, "step", &option.step));
kTest(kXml_AttrString(xml, tempItem, "ids", csvList));
kTest(kString_Split(csvList, ",", &tempArrayList, kObject_Alloc(tool)));
for (j = 0; j < kArrayList_Count(tempArrayList); j++)
{
kString token = *kArrayList_AtT(tempArrayList, j, kString);
kTest(k32s_Parse(&option.id, kString_Chars(token)));
kTest(kArrayList_AddT(list, &option));
}
// GOC-14516 Dispose memory allocation per iteration to avoid memory leak.
kDisposeRef(&tempArrayList);
}
}
}
}
kFinally
{
kDestroyRef(&csvList);
// GOC-14516 Dispose memory allocation here in case of last iteration fails.
kDisposeRef(&tempArrayList);
kEndFinally();
}
return kOK;
}