Move command line parsing in external delegate to DelegateOptions

 * Moves the creation of a DelegateOption object from
   armnn_external_delegate to DelegateOptions.
 * This allows this code to be reused elsewhere
 * Allow boolean values of DelegateOptions to be passed as
   strings e.g. 'true' or 'false'
 * Add unit tests

Signed-off-by: Jan Eilers <jan.eilers@arm.com>
Change-Id: I0ada17f511027dd3f47a85142cae346464682f5a
diff --git a/delegate/include/DelegateOptions.hpp b/delegate/include/DelegateOptions.hpp
index 24a2e5c..5bc2e59 100644
--- a/delegate/include/DelegateOptions.hpp
+++ b/delegate/include/DelegateOptions.hpp
@@ -37,6 +37,141 @@
                     const armnn::Optional<armnn::LogSeverity>& logSeverityLevel = armnn::EmptyOptional(),
                     const armnn::Optional<armnn::DebugCallbackFunction>& func = armnn::EmptyOptional());
 
+
+    /**
+     * This constructor processes delegate options in form of command line arguments.
+     * It works in conjunction with the TfLite external delegate plugin.
+     *
+     * Available options:
+     *
+     *    Option key: "backends" \n
+     *    Possible values: ["EthosNPU"/"GpuAcc"/"CpuAcc"/"CpuRef"] \n
+     *    Descriptions: A comma separated list without whitespaces of
+     *                  backends which should be used for execution. Falls
+     *                  back to next backend in list if previous doesn't
+     *                  provide support for operation. e.g. "GpuAcc,CpuAcc"
+     *
+     *    Option key: "dynamic-backends-path" \n
+     *    Possible values: [filenameString] \n
+     *    Descriptions: This is the directory that will be searched for any dynamic backends.
+     *
+     *    Option key: "logging-severity" \n
+     *    Possible values: ["trace"/"debug"/"info"/"warning"/"error"/"fatal"] \n
+     *    Description: Sets the logging severity level for ArmNN. Logging
+     *                 is turned off if this option is not provided.
+     *
+     *    Option key: "gpu-tuning-level" \n
+     *    Possible values: ["0"/"1"/"2"/"3"] \n
+     *    Description: 0=UseOnly(default), 1=RapidTuning, 2=NormalTuning,
+     *                 3=ExhaustiveTuning. Requires option gpu-tuning-file.
+     *                 1,2 and 3 will create a tuning-file, 0 will apply the
+     *                 tunings from an existing file
+     *
+     *    Option key: "gpu-mlgo-tuning-file" \n
+     *    Possible values: [filenameString] \n
+     *    Description: File name for the MLGO tuning file
+     *
+     *    Option key: "gpu-tuning-file" \n
+     *    Possible values: [filenameString] \n
+     *    Description: File name for the tuning file.
+     *
+     *    Option key: "gpu-enable-profiling" \n
+     *    Possible values: ["true"/"false"] \n
+     *    Description: Enables GPU profiling
+     *
+     *    Option key: "gpu-kernel-profiling-enabled" \n
+     *    Possible values: ["true"/"false"] \n
+     *    Description: Enables GPU kernel profiling
+     *
+     *    Option key: "save-cached-network" \n
+     *    Possible values: ["true"/"false"] \n
+     *    Description: Enables saving of the cached network to a file,
+     *                 specified with the cached-network-filepath option
+     *
+     *    Option key: "cached-network-filepath" \n
+     *    Possible values: [filenameString] \n
+     *    Description: If non-empty, the given file will be used to load/save the cached network.
+     *                 If save-cached-network is given then the cached network will be saved to the given file.
+     *                 To save the cached network a file must already exist.
+     *                 If save-cached-network is not given then the cached network will be loaded from the given file.
+     *                 This will remove initial compilation time of kernels and speed up the first execution.
+     *
+     *    Option key: "enable-fast-math" \n
+     *    Possible values: ["true"/"false"] \n
+     *    Description: Enables fast_math options in backends that support it
+     *
+     *    Option key: "number-of-threads" \n
+     *    Possible values: ["1"-"64"] \n
+     *    Description: Assign the number of threads used by the CpuAcc backend.
+     *                 Default is set to 0 (Backend will decide number of threads to use).
+     *
+     *    Option key: "reduce-fp32-to-fp16" \n
+     *    Possible values: ["true"/"false"] \n
+     *    Description: Reduce Fp32 data to Fp16 for faster processing
+     *
+     *    Option key: "reduce-fp32-to-bf16" \n
+     *    Possible values: ["true"/"false"] \n
+     *    Description: Reduce Fp32 data to Bf16 for faster processing
+     *
+     *    Option key: "debug-data" \n
+     *    Possible values: ["true"/"false"] \n
+     *    Description: Add debug data for easier troubleshooting
+     *
+     *    Option key: "memory-import" \n
+     *    Possible values: ["true"/"false"] \n
+     *    Description: Enable memory import
+     *
+     *    Option key: "enable-internal-profiling" \n
+     *    Possible values: ["true"/"false"] \n
+     *    Description: Enable the internal profiling feature.
+     *
+     *    Option key: "internal-profiling-detail" \n
+     *    Possible values: [1/2] \n
+     *    Description: Set the detail on the internal profiling. 1 = DetailsWithEvents, 2 = DetailsOnly.
+     *
+     *    Option key: "enable-external-profiling" \n
+     *    Possible values: ["true"/"false"] \n
+     *    Description: Enable the external profiling feature.
+     *
+     *    Option key: "timeline-profiling" \n
+     *    Possible values: ["true"/"false"] \n
+     *    Description: Indicates whether external timeline profiling is enabled or not.
+     *
+     *    Option key: "outgoing-capture-file" \n
+     *    Possible values: [filenameString] \n
+     *    Description: Path to a file in which outgoing timeline profiling messages will be stored.
+     *
+     *    Option key: "incoming-capture-file" \n
+     *    Possible values: [filenameString] \n
+     *    Description: Path to a file in which incoming timeline profiling messages will be stored.
+     *
+     *    Option key: "file-only-external-profiling" \n
+     *    Possible values: ["true"/"false"] \n
+     *    Description: Enable profiling output to file only.
+     *
+     *    Option key: "counter-capture-period" \n
+     *    Possible values: Integer, Default is 10000u
+     *    Description: Value in microseconds of the profiling capture period. \n
+     *
+     *    Option key: "profiling-file-format" \n
+     *    Possible values: String of ["binary"] \n
+     *    Description: The format of the file used for outputting profiling data. Currently on "binary" is supported.
+     *
+     *    Option key: "serialize-to-dot" \n
+     *    Possible values: [filenameString] \n
+     *    Description: Serialize the optimized network to the file specified in "dot" format.
+     *
+     * @param[in]     option_keys     Delegate option names
+     * @param[in]     options_values  Delegate option values
+     * @param[in]     num_options     Number of delegate options
+     * @param[in,out] report_error    Error callback function
+     *
+     */
+    DelegateOptions(char const* const* options_keys,
+                    char const* const* options_values,
+                    size_t num_options,
+                    void (*report_error)(const char*));
+
     const std::vector<armnn::BackendId>& GetBackends() const { return m_Backends; }
 
     void SetBackends(const std::vector<armnn::BackendId>& backends) { m_Backends = backends; }
diff --git a/delegate/src/DelegateOptions.cpp b/delegate/src/DelegateOptions.cpp
index c19697d..d477d98 100644
--- a/delegate/src/DelegateOptions.cpp
+++ b/delegate/src/DelegateOptions.cpp
@@ -4,6 +4,8 @@
 //
 
 #include <DelegateOptions.hpp>
+#include <armnn/utility/NumericCast.hpp>
+#include <armnn/utility/StringUtils.hpp>
 
 namespace armnnDelegate
 {
@@ -48,4 +50,189 @@
 {
 }
 
+DelegateOptions::DelegateOptions(char const* const* options_keys,
+                                 char const* const* options_values,
+                                 size_t num_options,
+                                 void (*report_error)(const char*))
+{
+    armnn::IRuntime::CreationOptions runtimeOptions;
+    armnn::OptimizerOptions optimizerOptions;
+    bool internalProfilingState = false;
+    armnn::ProfilingDetailsMethod internalProfilingDetail = armnn::ProfilingDetailsMethod::DetailsWithEvents;
+    armnn::IRuntime::CreationOptions::ExternalProfilingOptions extProfilingParams;
+    for (size_t i = 0; i < num_options; ++i)
+    {
+        // Process backends
+        if (std::string(options_keys[i]) == std::string("backends"))
+        {
+            // The backend option is a comma separated string of backendIDs that needs to be split
+            std::vector<armnn::BackendId> backends;
+            char* dup = strdup(options_values[i]);
+            char* pch = std::strtok(dup, ",");
+            while (pch != NULL)
+            {
+                backends.push_back(pch);
+                pch = strtok (NULL, ",");
+            }
+            this->SetBackends(backends);
+        }
+            // Process dynamic-backends-path
+        else if (std::string(options_keys[i]) == std::string("dynamic-backends-path"))
+        {
+            runtimeOptions.m_DynamicBackendsPath = std::string(options_values[i]);
+        }
+            // Process logging level
+        else if (std::string(options_keys[i]) == std::string("logging-severity"))
+        {
+            this->SetLoggingSeverity(options_values[i]);
+        }
+            // Process GPU backend options
+        else if (std::string(options_keys[i]) == std::string("gpu-tuning-level"))
+        {
+            armnn::BackendOptions option("GpuAcc", {{"TuningLevel", atoi(options_values[i])}});
+            runtimeOptions.m_BackendOptions.push_back(option);
+        }
+        else if (std::string(options_keys[i]) == std::string("gpu-mlgo-tuning-file"))
+        {
+            armnn::BackendOptions option("GpuAcc", {{"MLGOTuningFilePath", std::string(options_values[i])}});
+            optimizerOptions.m_ModelOptions.push_back(option);
+        }
+        else if (std::string(options_keys[i]) == std::string("gpu-tuning-file"))
+        {
+            armnn::BackendOptions option("GpuAcc", {{"TuningFile", std::string(options_values[i])}});
+            runtimeOptions.m_BackendOptions.push_back(option);
+        }
+        else if (std::string(options_keys[i]) == std::string("gpu-enable-profiling"))
+        {
+            runtimeOptions.m_EnableGpuProfiling = (*options_values[i] != '0');
+        }
+        else if (std::string(options_keys[i]) == std::string("gpu-kernel-profiling-enabled"))
+        {
+            armnn::BackendOptions option("GpuAcc", {{"KernelProfilingEnabled",
+                                                     armnn::stringUtils::StringToBool(options_values[i])}});
+            runtimeOptions.m_BackendOptions.push_back(option);
+        }
+        else if (std::string(options_keys[i]) == std::string("save-cached-network"))
+        {
+            armnn::BackendOptions option("GpuAcc", {{"SaveCachedNetwork",
+                                                     armnn::stringUtils::StringToBool(options_values[i])}});
+            optimizerOptions.m_ModelOptions.push_back(option);
+        }
+        else if (std::string(options_keys[i]) == std::string("cached-network-filepath"))
+        {
+            armnn::BackendOptions option("GpuAcc", {{"CachedNetworkFilePath", std::string(options_values[i])}});
+            optimizerOptions.m_ModelOptions.push_back(option);
+        }
+            // Process GPU & CPU backend options
+        else if (std::string(options_keys[i]) == std::string("enable-fast-math"))
+        {
+            armnn::BackendOptions modelOptionGpu("GpuAcc", {{"FastMathEnabled",
+                                                             armnn::stringUtils::StringToBool(options_values[i])}});
+            optimizerOptions.m_ModelOptions.push_back(modelOptionGpu);
+
+            armnn::BackendOptions modelOptionCpu("CpuAcc", {{"FastMathEnabled",
+                                                             armnn::stringUtils::StringToBool(options_values[i])}});
+            optimizerOptions.m_ModelOptions.push_back(modelOptionCpu);
+        }
+            // Process CPU backend options
+        else if (std::string(options_keys[i]) == std::string("number-of-threads"))
+        {
+            unsigned int numberOfThreads = armnn::numeric_cast<unsigned int>(atoi(options_values[i]));
+            armnn::BackendOptions modelOption("CpuAcc", {{"NumberOfThreads", numberOfThreads}});
+            optimizerOptions.m_ModelOptions.push_back(modelOption);
+        }
+            // Process reduce-fp32-to-fp16 option
+        else if (std::string(options_keys[i]) == std::string("reduce-fp32-to-fp16"))
+        {
+            optimizerOptions.m_ReduceFp32ToFp16 = armnn::stringUtils::StringToBool(options_values[i]);
+        }
+            // Process reduce-fp32-to-bf16 option
+        else if (std::string(options_keys[i]) == std::string("reduce-fp32-to-bf16"))
+        {
+            optimizerOptions.m_ReduceFp32ToBf16 = armnn::stringUtils::StringToBool(options_values[i]);
+        }
+            // Process debug-data
+        else if (std::string(options_keys[i]) == std::string("debug-data"))
+        {
+            optimizerOptions.m_Debug = armnn::stringUtils::StringToBool(options_values[i]);
+        }
+            // Process memory-import
+        else if (std::string(options_keys[i]) == std::string("memory-import"))
+        {
+            optimizerOptions.m_ImportEnabled = armnn::stringUtils::StringToBool(options_values[i]);
+        }
+            // Process enable-internal-profiling
+        else if (std::string(options_keys[i]) == std::string("enable-internal-profiling"))
+        {
+            internalProfilingState = *options_values[i] != '0';
+            optimizerOptions.m_ProfilingEnabled = internalProfilingState;
+        }
+            // Process internal-profiling-detail
+        else if (std::string(options_keys[i]) == std::string("internal-profiling-detail"))
+        {
+            uint32_t detailLevel = static_cast<uint32_t>(std::stoul(options_values[i]));
+            switch (detailLevel)
+            {
+                case 1:
+                    internalProfilingDetail = armnn::ProfilingDetailsMethod::DetailsWithEvents;
+                    break;
+                case 2:
+                    internalProfilingDetail = armnn::ProfilingDetailsMethod::DetailsOnly;
+                    break;
+                default:
+                    internalProfilingDetail = armnn::ProfilingDetailsMethod::Undefined;
+                    break;
+            }
+        }
+            // Process enable-external-profiling
+        else if (std::string(options_keys[i]) == std::string("enable-external-profiling"))
+        {
+            extProfilingParams.m_EnableProfiling = armnn::stringUtils::StringToBool(options_values[i]);
+        }
+            // Process timeline-profiling
+        else if (std::string(options_keys[i]) == std::string("timeline-profiling"))
+        {
+            extProfilingParams.m_TimelineEnabled = armnn::stringUtils::StringToBool(options_values[i]);
+        }
+            // Process outgoing-capture-file
+        else if (std::string(options_keys[i]) == std::string("outgoing-capture-file"))
+        {
+            extProfilingParams.m_OutgoingCaptureFile = options_values[i];
+        }
+            // Process incoming-capture-file
+        else if (std::string(options_keys[i]) == std::string("incoming-capture-file"))
+        {
+            extProfilingParams.m_IncomingCaptureFile = options_values[i];
+        }
+            // Process file-only-external-profiling
+        else if (std::string(options_keys[i]) == std::string("file-only-external-profiling"))
+        {
+            extProfilingParams.m_FileOnly = armnn::stringUtils::StringToBool(options_values[i]);
+        }
+            // Process counter-capture-period
+        else if (std::string(options_keys[i]) == std::string("counter-capture-period"))
+        {
+            extProfilingParams.m_CapturePeriod = static_cast<uint32_t>(std::stoul(options_values[i]));
+        }
+            // Process profiling-file-format
+        else if (std::string(options_keys[i]) == std::string("profiling-file-format"))
+        {
+            extProfilingParams.m_FileFormat = options_values[i];
+        }
+            // Process serialize-to-dot
+        else if (std::string(options_keys[i]) == std::string("serialize-to-dot"))
+        {
+            this->SetSerializeToDot(options_values[i]);
+        }
+        else
+        {
+            throw armnn::Exception("Unknown option for the ArmNN Delegate given: " + std::string(options_keys[i]));
+        }
+    }
+
+    this->SetRuntimeOptions(runtimeOptions);
+    this->SetOptimizerOptions(optimizerOptions);
+    this->SetInternalProfilingParams(internalProfilingState, internalProfilingDetail);
+    this->SetExternalProfilingParams(extProfilingParams);
+}
 } // namespace armnnDelegate
diff --git a/delegate/src/armnn_external_delegate.cpp b/delegate/src/armnn_external_delegate.cpp
index 5919a6c..c387574 100644
--- a/delegate/src/armnn_external_delegate.cpp
+++ b/delegate/src/armnn_external_delegate.cpp
@@ -26,327 +26,23 @@
 
 extern "C"
 {
-std::vector<std::string> gpu_options {"gpu-tuning-level",
-                                      "gpu-tuning-file",
-                                      "gpu-kernel-profiling-enabled"};
-
 
 /**
- * Create an ArmNN delegate plugin
- *
- * Available options:
- *
- *    Option key: "backends" \n
- *    Possible values: ["EthosNPU"/"GpuAcc"/"CpuAcc"/"CpuRef"] \n
- *    Descriptions: A comma separated list without whitespaces of
- *                  backends which should be used for execution. Falls
- *                  back to next backend in list if previous doesn't
- *                  provide support for operation. e.g. "GpuAcc,CpuAcc"
- *
- *    Option key: "dynamic-backends-path" \n
- *    Possible values: [filenameString] \n
- *    Descriptions: This is the directory that will be searched for any dynamic backends.
- *
- *    Option key: "logging-severity" \n
- *    Possible values: ["trace"/"debug"/"info"/"warning"/"error"/"fatal"] \n
- *    Description: Sets the logging severity level for ArmNN. Logging
- *                 is turned off if this option is not provided.
- *
- *    Option key: "gpu-tuning-level" \n
- *    Possible values: ["0"/"1"/"2"/"3"] \n
- *    Description: 0=UseOnly(default), 1=RapidTuning, 2=NormalTuning,
- *                 3=ExhaustiveTuning. Requires option gpu-tuning-file.
- *                 1,2 and 3 will create a tuning-file, 0 will apply the
- *                 tunings from an existing file
- *
- *    Option key: "gpu-mlgo-tuning-file" \n
- *    Possible values: [filenameString] \n
- *    Description: File name for the MLGO tuning file
- *
- *    Option key: "gpu-tuning-file" \n
- *    Possible values: [filenameString] \n
- *    Description: File name for the tuning file.
- *
- *    Option key: "gpu-enable-profiling" \n
- *    Possible values: ["true"/"false"] \n
- *    Description: Enables GPU profiling
- *
- *    Option key: "gpu-kernel-profiling-enabled" \n
- *    Possible values: ["true"/"false"] \n
- *    Description: Enables GPU kernel profiling
- *
- *    Option key: "save-cached-network" \n
- *    Possible values: ["true"/"false"] \n
- *    Description: Enables saving of the cached network to a file,
- *                 specified with the cached-network-filepath option
- *
- *    Option key: "cached-network-filepath" \n
- *    Possible values: [filenameString] \n
- *    Description: If non-empty, the given file will be used to load/save the cached network.
- *                 If save-cached-network is given then the cached network will be saved to the given file.
- *                 To save the cached network a file must already exist.
- *                 If save-cached-network is not given then the cached network will be loaded from the given file.
- *                 This will remove initial compilation time of kernels and speed up the first execution.
- *
- *    Option key: "enable-fast-math" \n
- *    Possible values: ["true"/"false"] \n
- *    Description: Enables fast_math options in backends that support it
- *
- *    Option key: "number-of-threads" \n
- *    Possible values: ["1"-"64"] \n
- *    Description: Assign the number of threads used by the CpuAcc backend.
- *                 Default is set to 0 (Backend will decide number of threads to use).
- *
- *    Option key: "reduce-fp32-to-fp16" \n
- *    Possible values: ["true"/"false"] \n
- *    Description: Reduce Fp32 data to Fp16 for faster processing
- *
- *    Option key: "reduce-fp32-to-bf16" \n
- *    Possible values: ["true"/"false"] \n
- *    Description: Reduce Fp32 data to Bf16 for faster processing
- *
- *    Option key: "debug-data" \n
- *    Possible values: ["true"/"false"] \n
- *    Description: Add debug data for easier troubleshooting
- *
- *    Option key: "memory-import" \n
- *    Possible values: ["true"/"false"] \n
- *    Description: Enable memory import
- *
- *    Option key: "enable-internal-profiling" \n
- *    Possible values: ["true"/"false"] \n
- *    Description: Enable the internal profiling feature.
- *
- *    Option key: "internal-profiling-detail" \n
- *    Possible values: [1/2] \n
- *    Description: Set the detail on the internal profiling. 1 = DetailsWithEvents, 2 = DetailsOnly.
- *
- *    Option key: "enable-external-profiling" \n
- *    Possible values: ["true"/"false"] \n
- *    Description: Enable the external profiling feature.
- *
- *    Option key: "timeline-profiling" \n
- *    Possible values: ["true"/"false"] \n
- *    Description: Indicates whether external timeline profiling is enabled or not.
- *
- *    Option key: "outgoing-capture-file" \n
- *    Possible values: [filenameString] \n
- *    Description: Path to a file in which outgoing timeline profiling messages will be stored.
- *
- *    Option key: "incoming-capture-file" \n
- *    Possible values: [filenameString] \n
- *    Description: Path to a file in which incoming timeline profiling messages will be stored.
- *
- *    Option key: "file-only-external-profiling" \n
- *    Possible values: ["true"/"false"] \n
- *    Description: Enable profiling output to file only.
- *
- *    Option key: "counter-capture-period" \n
- *    Possible values: Integer, Default is 10000u
- *    Description: Value in microseconds of the profiling capture period. \n
- *
- *    Option key: "profiling-file-format" \n
- *    Possible values: String of ["binary"] \n
- *    Description: The format of the file used for outputting profiling data. Currently on "binary" is supported.
- *
- *    Option key: "serialize-to-dot" \n
- *    Possible values: [filenameString] \n
- *    Description: Serialize the optimized network to the file specified in "dot" format.
- *
- * @param[in]     option_keys     Delegate option names
- * @param[in]     options_values  Delegate option values
- * @param[in]     num_options     Number of delegate options
- * @param[in,out] report_error    Error callback function
- *
- * @return An ArmNN delegate if it succeeds else NULL
- */
+  * Implementation of the TfLite external delegate plugin
+  *
+  * For details about what options_keys and option_values are supported please see:
+  * armnnDelegate::DelegateOptions::DelegateOptions(char const* const*, char const* const*,size_t,void (*)(const char*))
+  */
 TfLiteDelegate* tflite_plugin_create_delegate(char** options_keys,
                                               char** options_values,
                                               size_t num_options,
                                               void (*report_error)(const char*))
 {
-    // Returning null indicates an error during delegate creation so we initialize with that
+    // Returning null indicates an error during delegate creation, we initialize with that
     TfLiteDelegate* delegate = nullptr;
     try
     {
-        // (Initializes with CpuRef backend)
-        armnnDelegate::DelegateOptions options = armnnDelegate::TfLiteArmnnDelegateOptionsDefault();
-
-        armnn::IRuntime::CreationOptions runtimeOptions;
-        armnn::OptimizerOptions optimizerOptions;
-        bool internalProfilingState = false;
-        armnn::ProfilingDetailsMethod internalProfilingDetail = armnn::ProfilingDetailsMethod::DetailsWithEvents;
-        armnn::IRuntime::CreationOptions::ExternalProfilingOptions extProfilingParams;
-        for (size_t i = 0; i < num_options; ++i)
-        {
-            // Process backends
-            if (std::string(options_keys[i]) == std::string("backends"))
-            {
-                // The backend option is a comma separated string of backendIDs that needs to be split
-                std::vector<armnn::BackendId> backends;
-                char* pch;
-                pch = strtok(options_values[i],",");
-                while (pch != NULL)
-                {
-                    backends.push_back(pch);
-                    pch = strtok (NULL, ",");
-                }
-                options.SetBackends(backends);
-            }
-            // Process dynamic-backends-path
-            else if (std::string(options_keys[i]) == std::string("dynamic-backends-path"))
-            {
-                runtimeOptions.m_DynamicBackendsPath = std::string(options_values[i]);
-            }
-            // Process logging level
-            else if (std::string(options_keys[i]) == std::string("logging-severity"))
-            {
-                options.SetLoggingSeverity(options_values[i]);
-            }
-            // Process GPU backend options
-            else if (std::string(options_keys[i]) == std::string("gpu-tuning-level"))
-            {
-                armnn::BackendOptions option("GpuAcc", {{"TuningLevel", atoi(options_values[i])}});
-                runtimeOptions.m_BackendOptions.push_back(option);
-            }
-            else if (std::string(options_keys[i]) == std::string("gpu-mlgo-tuning-file"))
-            {
-                armnn::BackendOptions option("GpuAcc", {{"MLGOTuningFilePath", std::string(options_values[i])}});
-                optimizerOptions.m_ModelOptions.push_back(option);
-            }
-            else if (std::string(options_keys[i]) == std::string("gpu-tuning-file"))
-            {
-                armnn::BackendOptions option("GpuAcc", {{"TuningFile", std::string(options_values[i])}});
-                runtimeOptions.m_BackendOptions.push_back(option);
-            }
-            else if (std::string(options_keys[i]) == std::string("gpu-enable-profiling"))
-            {
-                runtimeOptions.m_EnableGpuProfiling = (*options_values[i] != '0');
-            }
-            else if (std::string(options_keys[i]) == std::string("gpu-kernel-profiling-enabled"))
-            {
-                armnn::BackendOptions option("GpuAcc", {{"KernelProfilingEnabled", (*options_values[i] != '0')}});
-                runtimeOptions.m_BackendOptions.push_back(option);
-            }
-            else if (std::string(options_keys[i]) == std::string("save-cached-network"))
-            {
-                armnn::BackendOptions option("GpuAcc", {{"SaveCachedNetwork", (*options_values[i] != '0')}});
-                optimizerOptions.m_ModelOptions.push_back(option);
-            }
-            else if (std::string(options_keys[i]) == std::string("cached-network-filepath"))
-            {
-                armnn::BackendOptions option("GpuAcc", {{"CachedNetworkFilePath", std::string(options_values[i])}});
-                optimizerOptions.m_ModelOptions.push_back(option);
-            }
-            // Process GPU & CPU backend options
-            else if (std::string(options_keys[i]) == std::string("enable-fast-math"))
-            {
-                armnn::BackendOptions modelOptionGpu("GpuAcc", {{"FastMathEnabled", (*options_values[i] != '0')}});
-                optimizerOptions.m_ModelOptions.push_back(modelOptionGpu);
-
-                armnn::BackendOptions modelOptionCpu("CpuAcc", {{"FastMathEnabled", (*options_values[i] != '0')}});
-                optimizerOptions.m_ModelOptions.push_back(modelOptionCpu);
-            }
-            // Process CPU backend options
-            else if (std::string(options_keys[i]) == std::string("number-of-threads"))
-            {
-                unsigned int numberOfThreads = armnn::numeric_cast<unsigned int>(atoi(options_values[i]));
-                armnn::BackendOptions modelOption("CpuAcc", {{"NumberOfThreads", numberOfThreads}});
-                optimizerOptions.m_ModelOptions.push_back(modelOption);
-            }
-            // Process reduce-fp32-to-fp16 option
-            else if (std::string(options_keys[i]) == std::string("reduce-fp32-to-fp16"))
-            {
-               optimizerOptions.m_ReduceFp32ToFp16 = *options_values[i] != '0';
-            }
-            // Process reduce-fp32-to-bf16 option
-            else if (std::string(options_keys[i]) == std::string("reduce-fp32-to-bf16"))
-            {
-               optimizerOptions.m_ReduceFp32ToBf16 = *options_values[i] != '0';
-            }
-            // Process debug-data
-            else if (std::string(options_keys[i]) == std::string("debug-data"))
-            {
-               optimizerOptions.m_Debug = *options_values[i] != '0';
-            }
-            // Process memory-import
-            else if (std::string(options_keys[i]) == std::string("memory-import"))
-            {
-               optimizerOptions.m_ImportEnabled = *options_values[i] != '0';
-            }
-            // Process enable-internal-profiling
-            else if (std::string(options_keys[i]) == std::string("enable-internal-profiling"))
-            {
-                internalProfilingState = *options_values[i] != '0';
-                optimizerOptions.m_ProfilingEnabled = internalProfilingState;
-            }
-            // Process internal-profiling-detail
-            else if (std::string(options_keys[i]) == std::string("internal-profiling-detail"))
-            {
-                uint32_t detailLevel = static_cast<uint32_t>(std::stoul(options_values[i]));
-                switch (detailLevel)
-                {
-                    case 1:
-                        internalProfilingDetail = armnn::ProfilingDetailsMethod::DetailsWithEvents;
-                        break;
-                    case 2:
-                        internalProfilingDetail = armnn::ProfilingDetailsMethod::DetailsOnly;
-                        break;
-                    default:
-                        internalProfilingDetail = armnn::ProfilingDetailsMethod::Undefined;
-                        break;
-                }
-            }
-            // Process enable-external-profiling
-            else if (std::string(options_keys[i]) == std::string("enable-external-profiling"))
-            {
-                extProfilingParams.m_EnableProfiling = *options_values[i] != '0';
-            }
-            // Process timeline-profiling
-            else if (std::string(options_keys[i]) == std::string("timeline-profiling"))
-            {
-                extProfilingParams.m_TimelineEnabled = *options_values[i] != '0';
-            }
-            // Process outgoing-capture-file
-            else if (std::string(options_keys[i]) == std::string("outgoing-capture-file"))
-            {
-                extProfilingParams.m_OutgoingCaptureFile = options_values[i];
-            }
-            // Process incoming-capture-file
-            else if (std::string(options_keys[i]) == std::string("incoming-capture-file"))
-            {
-                extProfilingParams.m_IncomingCaptureFile = options_values[i];
-            }
-            // Process file-only-external-profiling
-            else if (std::string(options_keys[i]) == std::string("file-only-external-profiling"))
-            {
-                extProfilingParams.m_FileOnly = *options_values[i] != '0';
-            }
-            // Process counter-capture-period
-            else if (std::string(options_keys[i]) == std::string("counter-capture-period"))
-            {
-                extProfilingParams.m_CapturePeriod = static_cast<uint32_t>(std::stoul(options_values[i]));
-            }
-            // Process profiling-file-format
-            else if (std::string(options_keys[i]) == std::string("profiling-file-format"))
-            {
-                extProfilingParams.m_FileFormat = options_values[i];
-            }
-            // Process serialize-to-dot
-            else if (std::string(options_keys[i]) == std::string("serialize-to-dot"))
-            {
-                options.SetSerializeToDot(options_values[i]);
-            }
-            else
-            {
-                throw armnn::Exception("Unknown option for the ArmNN Delegate given: " + std::string(options_keys[i]));
-            }
-        }
-
-        options.SetRuntimeOptions(runtimeOptions);
-        options.SetOptimizerOptions(optimizerOptions);
-        options.SetInternalProfilingParams(internalProfilingState, internalProfilingDetail);
-        options.SetExternalProfilingParams(extProfilingParams);
+        armnnDelegate::DelegateOptions options (options_keys, options_values, num_options, (*report_error));
         delegate = TfLiteArmnnDelegateCreate(options);
     }
     catch (const std::exception& ex)
diff --git a/delegate/src/test/DelegateOptionsTest.cpp b/delegate/src/test/DelegateOptionsTest.cpp
index 3387725..54f9c8f 100644
--- a/delegate/src/test/DelegateOptionsTest.cpp
+++ b/delegate/src/test/DelegateOptionsTest.cpp
@@ -223,6 +223,90 @@
     fs::remove(filename);
 }
 
+void CreateFp16StringParsingTestRun(std::vector<std::string>& keys,
+                                    std::vector<std::string>& values,
+                                    std::stringstream& ss)
+{
+    StreamRedirector redirect(std::cout, ss.rdbuf());
+
+    std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
+    std::vector<int32_t> tensorShape { 1, 2, 2, 1 };
+    std::vector<float> inputData = { 1, 2, 3, 4 };
+    std::vector<float> divData = { 2, 2, 3, 4 };
+    std::vector<float> expectedResult = { 1, 2, 2, 2 };
+
+    // Create options_keys and options_values char array
+    size_t num_options = keys.size();
+    std::unique_ptr<const char*> options_keys =
+            std::unique_ptr<const char*>(new const char*[num_options + 1]);
+    std::unique_ptr<const char*> options_values =
+            std::unique_ptr<const char*>(new const char*[num_options + 1]);
+    for (size_t i=0; i<num_options; ++i)
+    {
+        options_keys.get()[i]   = keys[i].c_str();
+        options_values.get()[i] = values[i].c_str();
+    }
+
+    armnnDelegate::DelegateOptions delegateOptions(options_keys.get(), options_values.get(), num_options, nullptr);
+    DelegateOptionTest<float>(::tflite::TensorType_FLOAT32,
+                              backends,
+                              tensorShape,
+                              inputData,
+                              inputData,
+                              divData,
+                              expectedResult,
+                              delegateOptions);
+}
+
+TEST_CASE ("ArmnnDelegateStringParsingOptionReduceFp32ToFp16")
+{
+    SUBCASE("Fp16=1")
+    {
+        std::stringstream ss;
+        std::vector<std::string> keys   {  "backends", "debug-data", "reduce-fp32-to-fp16", "logging-severity"};
+        std::vector<std::string> values {    "CpuRef",          "1",                   "1",             "info"};
+        CreateFp16StringParsingTestRun(keys, values, ss);
+        CHECK(ss.str().find("convert_fp32_to_fp16") != std::string::npos);
+        CHECK(ss.str().find("convert_fp16_to_fp32") != std::string::npos);
+    }
+    SUBCASE("Fp16=true")
+    {
+        std::stringstream ss;
+        std::vector<std::string> keys   {  "backends", "debug-data", "reduce-fp32-to-fp16"};
+        std::vector<std::string> values {    "CpuRef",       "TRUE",                "true"};
+        CreateFp16StringParsingTestRun(keys, values, ss);
+        CHECK(ss.str().find("convert_fp32_to_fp16") != std::string::npos);
+        CHECK(ss.str().find("convert_fp16_to_fp32") != std::string::npos);
+    }
+    SUBCASE("Fp16=True")
+    {
+        std::stringstream ss;
+        std::vector<std::string> keys   {  "backends", "debug-data", "reduce-fp32-to-fp16"};
+        std::vector<std::string> values {    "CpuRef",       "true",                "True"};
+        CreateFp16StringParsingTestRun(keys, values, ss);
+        CHECK(ss.str().find("convert_fp32_to_fp16") != std::string::npos);
+        CHECK(ss.str().find("convert_fp16_to_fp32") != std::string::npos);
+    }
+    SUBCASE("Fp16=0")
+    {
+        std::stringstream ss;
+        std::vector<std::string> keys   {  "backends", "debug-data", "reduce-fp32-to-fp16"};
+        std::vector<std::string> values {    "CpuRef",       "true",                   "0"};
+        CreateFp16StringParsingTestRun(keys, values, ss);
+        CHECK(ss.str().find("convert_fp32_to_fp16") == std::string::npos);
+        CHECK(ss.str().find("convert_fp16_to_fp32") == std::string::npos);
+    }
+    SUBCASE("Fp16=false")
+    {
+        std::stringstream ss;
+        std::vector<std::string> keys   {  "backends", "debug-data", "reduce-fp32-to-fp16"};
+        std::vector<std::string> values {    "CpuRef",     "1",               "false"};
+        CreateFp16StringParsingTestRun(keys, values, ss);
+        CHECK(ss.str().find("convert_fp32_to_fp16") == std::string::npos);
+        CHECK(ss.str().find("convert_fp16_to_fp32") == std::string::npos);
+    }
+}
+
 
 }