JSONschema and python improvements

* JSON Schema manually updated to be more semantically valid.
* Python script improved to be more verbose with exceptions
* Templating file improved by adding an additional macro.

Signed-off-by: Archana <archana.madhavan@silabs.com>
Signed-off-by: Asfandyar Orakzai <asfandyar.orakzai@silabs.com>
diff --git a/scripts/data_files/driver_jsons/driver_opaque_schema.json b/scripts/data_files/driver_jsons/driver_opaque_schema.json
index 53660c8..4a769f0 100644
--- a/scripts/data_files/driver_jsons/driver_opaque_schema.json
+++ b/scripts/data_files/driver_jsons/driver_opaque_schema.json
@@ -2,25 +2,31 @@
   "$schema": "http://json-schema.org/draft-04/schema#",
   "type": "object",
   "properties": {
-    "prefix": {
+    "_comment": {
       "type": "string"
     },
+    "prefix": {
+      "type": "string",
+      "pattern": "^[A-Z_a-z][0-9A-Z_a-z]*$"
+    },
     "type": {
-      "type": "string"
+      "type": "string",
+      "const": ["opaque"]
     },
     "location": {
-      "type": "string"
+      "type": ["integer","string"],
+      "pattern": "^(0x|0X)?[a-fA-F0-9]+$"
     },
-    "dependency": {
+    "mbedtls/h_depend_on": {
       "type": "string"
     },
     "headers": {
       "type": "array",
-      "items": [
-        {
+      "items": {
           "type": "string"
-        }
-      ]
+        },
+        "minItems": 1,
+        "uniqueItems": true
     },
     "capabilities": {
       "type": "array",
@@ -31,71 +37,33 @@
             "_comment": {
               "type": "string"
             },
-            "depend_on": {
+            "mbedtls/c_depend_on": {
               "type": "string"
             },
             "entry_points": {
               "type": "array",
-              "items": [
-                {
-                  "type": "string"
+              "items": {
+                  "type": "string",
+                  "enum": ["import_key", "export_key", "export_public_key",
+                          "copy_key", "get_builtin_key"]
                 },
-                {
-                  "type": "string"
-                },
-                {
-                  "type": "string"
-                }
-              ]
-            }
-          },
-          "required": [
-            "_comment",
-            "depend_on",
-            "entry_points"
-          ]
-        },
-        {
-          "type": "object",
-          "properties": {
-            "_comment": {
-              "type": "string"
-            },
-            "depend_on": {
-              "type": "string"
-            },
-            "entry_points": {
-              "type": "array",
-              "items": [
-                {
-                  "type": "string"
-                },
-                {
-                  "type": "string"
-                }
-              ]
+                "minItems": 1,
+                "uniqueItems": true
             },
             "name": {
               "type": "object",
-              "properties": {
-                "copy_key": {
-                  "type": "string"
-                },
-                "get_builtin_key": {
-                  "type": "string"
+              "patternProperties": {
+                "^[A-Z_a-z][0-9A-Z_a-z]*$": {
+                  "type": "string",
+                  "pattern": "^[A-Z_a-z][0-9A-Z_a-z]*$"
                 }
               },
-              "required": [
-                "copy_key",
-                "get_builtin_key"
-              ]
+                "minItems": 1,
+                "uniqueItems": true
             }
           },
           "required": [
-            "_comment",
-            "depend_on",
-            "entry_points",
-            "name"
+            "entry_points"
           ]
         }
       ]
@@ -105,8 +73,6 @@
     "prefix",
     "type",
     "location",
-    "dependency",
-    "headers",
     "capabilities"
   ]
 }
diff --git a/scripts/data_files/driver_jsons/driver_transparent_schema.json b/scripts/data_files/driver_jsons/driver_transparent_schema.json
index dd1178d..bf86ceb 100644
--- a/scripts/data_files/driver_jsons/driver_transparent_schema.json
+++ b/scripts/data_files/driver_jsons/driver_transparent_schema.json
@@ -2,22 +2,27 @@
   "$schema": "http://json-schema.org/draft-04/schema#",
   "type": "object",
   "properties": {
-    "prefix": {
+    "_comment": {
       "type": "string"
     },
+    "prefix": {
+      "type": "string",
+      "pattern": "^[A-Z_a-z][0-9A-Z_a-z]*$"
+    },
     "type": {
-      "type": "string"
+      "type": "string",
+      "const": ["transparent"]
     },
-    "dependency": {
+    "mbedtls/h_depend_on": {
       "type": "string"
     },
     "headers": {
       "type": "array",
-      "items": [
-        {
+      "items": {
           "type": "string"
-        }
-      ]
+        },
+        "minItems": 1,
+        "uniqueItems": true
     },
     "capabilities": {
       "type": "array",
@@ -28,79 +33,46 @@
             "_comment": {
               "type": "string"
             },
-            "depend_on": {
+            "mbedtls/c_depend_on": {
               "type": "string"
             },
             "entry_points": {
               "type": "array",
-              "items": [
-                {
-                  "type": "string"
+              "items": {
+                  "type": "string",
+                  "enum": ["import_key", "export_key", "export_public_key",
+                          "copy_key", "get_builtin_key"]
                 },
-                {
-                  "type": "string"
-                }
-              ]
-            },
-            "fallback": {
-              "type": "boolean"
-            }
-          },
-          "required": [
-            "_comment",
-            "depend_on",
-            "entry_points",
-            "fallback"
-          ]
-        },
-        {
-          "type": "object",
-          "properties": {
-            "_comment": {
-              "type": "string"
-            },
-            "depend_on": {
-              "type": "string"
-            },
-            "entry_points": {
-              "type": "array",
-              "items": [
-                {
-                  "type": "string"
-                }
-              ]
-            },
-            "fallback": {
-              "type": "boolean"
+                "minItems": 1,
+                "uniqueItems": true
             },
             "name": {
               "type": "object",
-              "properties": {
-                "export_public_key": {
-                  "type": "string"
+              "patternProperties": {
+                "^[A-Z_a-z][0-9A-Z_a-z]*$": {
+                  "type": "string",
+                  "pattern": "^[A-Z_a-z][0-9A-Z_a-z]*$"
                 }
               },
-              "required": [
-                "export_public_key"
-              ]
+                "minItems": 1,
+                "uniqueItems": true
+            },
+            "fallback": {
+              "type": "boolean",
+              "default": "false"
             }
           },
           "required": [
-            "_comment",
-            "depend_on",
-            "entry_points",
-            "fallback",
-            "name"
+            "entry_points"
           ]
         }
-      ]
+      ],
+      "default": []
     }
   },
   "required": [
     "prefix",
     "type",
-    "dependency",
-    "headers",
     "capabilities"
   ]
 }
diff --git a/scripts/data_files/driver_jsons/mbedtls_test_opaque_driver.json b/scripts/data_files/driver_jsons/mbedtls_test_opaque_driver.json
index 3747404..a38287d 100644
--- a/scripts/data_files/driver_jsons/mbedtls_test_opaque_driver.json
+++ b/scripts/data_files/driver_jsons/mbedtls_test_opaque_driver.json
@@ -2,18 +2,18 @@
     "prefix":       "mbedtls_test",
     "type":         "opaque",
     "location":     "0x7fffff",
-    "dependency":   "defined(PSA_CRYPTO_DRIVER_TEST)",
+    "mbedtls/h_depend_on":   "defined(PSA_CRYPTO_DRIVER_TEST)",
     "headers":      ["test/drivers/test_driver.h"],
     "capabilities": [
         {
-            "_comment":     "The mbedTLS opaque driver supports import key/export key/export_public key",
-            "depend_on":    "defined(PSA_CRYPTO_DRIVER_TEST)",
+            "_comment":     "The Mbed TLS opaque driver supports import key/export key/export_public key",
+            "mbedtls/c_depend_on":    "defined(PSA_CRYPTO_DRIVER_TEST)",
             "entry_points": ["import_key", "export_key", "export_public_key"]
         },
         {
-            "_comment":     "The mbedTLS opaque driver supports copy key/ get builtin key",
-            "depend_on":    "defined(PSA_CRYPTO_DRIVER_TEST)",
-            "entry_points": ["copy_key","get_builtin_key"],
+            "_comment":     "The Mbed TLS opaque driver supports copy key/ get builtin key",
+            "mbedtls/c_depend_on":    "defined(PSA_CRYPTO_DRIVER_TEST)",
+            "entry_points": ["copy_key", "get_builtin_key"],
             "name":         {"copy_key":"mbedtls_test_opaque_copy_key", "get_builtin_key":"mbedtls_test_opaque_get_builtin_key"}
         }
      ]
diff --git a/scripts/data_files/driver_jsons/mbedtls_test_transparent_driver.json b/scripts/data_files/driver_jsons/mbedtls_test_transparent_driver.json
index 52f6cd3..5c9b9fe 100644
--- a/scripts/data_files/driver_jsons/mbedtls_test_transparent_driver.json
+++ b/scripts/data_files/driver_jsons/mbedtls_test_transparent_driver.json
@@ -1,18 +1,18 @@
 {
     "prefix":       "mbedtls_test",
     "type":         "transparent",
-    "dependency":   "defined(PSA_CRYPTO_DRIVER_TEST)",
+    "mbedtls/h_depend_on":   "defined(PSA_CRYPTO_DRIVER_TEST)",
     "headers":      ["test/drivers/test_driver.h"],
     "capabilities": [
         {
-            "_comment":     "The mbedTLS transparent driver supports import key/export key",
-            "depend_on":    "defined(PSA_CRYPTO_DRIVER_TEST)",
+            "_comment":     "The Mbed TLS transparent driver supports import key/export key",
+            "mbedtls/c_depend_on":    "defined(PSA_CRYPTO_DRIVER_TEST)",
             "entry_points": ["import_key", "export_key"],
             "fallback":     true
         },
         {
-            "_comment":     "The mbedTLS transparent driver supports export_public key",
-            "depend_on":    "defined(PSA_CRYPTO_DRIVER_TEST)",
+            "_comment":     "The Mbed TLS transparent driver supports export_public key",
+            "mbedtls/c_depend_on":    "defined(PSA_CRYPTO_DRIVER_TEST)",
             "entry_points": ["export_public_key"],
             "fallback":     true,
             "name":         {"export_public_key":"mbedtls_test_transparent_export_public_key"}
diff --git a/scripts/data_files/driver_templates/OS-template-opaque.jinja b/scripts/data_files/driver_templates/OS-template-opaque.jinja
index f11ac77..115e22c 100644
--- a/scripts/data_files/driver_templates/OS-template-opaque.jinja
+++ b/scripts/data_files/driver_templates/OS-template-opaque.jinja
@@ -1,13 +1,16 @@
+{# One Shot function's dispatch code for opaque drivers.
+Expected inputs:
+* drivers: the list of driver descriptions.
+* entry_point: the name of the entry point that this function dispatches to.
+* entry_point_param(driver): the parameters to pass to the entry point.
+* nest_indent: number of extra spaces to indent the code to.
+-#}
 {% for driver in drivers if driver.type == "opaque" -%}
 {% for capability in driver.capabilities if entry_point in capability.entry_points -%}
-#if ({% if capability.depend_on is defined -%}{{ capability.depend_on }} {% else -%} {{ 1 }} {% endif %})
+#if ({% if capability['mbedtls/c_depend_on'] is defined -%}{{ capability['mbedtls/c_depend_on'] }} {% else -%} {{ 1 }} {% endif %})
 {%- filter indent(width = nest_indent) %}
 case {{ driver.location }}:
-    {% if capability.name is defined and entry_point in capability.name.keys() -%}
-    return({{ capability.name[entry_point]}}({{entry_point_attributes(driver) | indent(20)}}));
-    {% else -%}
-    return({{driver.prefix}}_{{driver.type}}_{{entry_point}}({{entry_point_attributes(driver) | indent(20)}}));
-    {% endif -%}
+    return( {{ entry_point_name(capability, entry_point, driver) }}({{entry_point_param(driver) | indent(20)}}));
 {% endfilter -%}
 #endif
 {% endfor %}
diff --git a/scripts/data_files/driver_templates/OS-template-transparent.jinja b/scripts/data_files/driver_templates/OS-template-transparent.jinja
index 4eadd1e..9ba1155 100644
--- a/scripts/data_files/driver_templates/OS-template-transparent.jinja
+++ b/scripts/data_files/driver_templates/OS-template-transparent.jinja
@@ -1,12 +1,15 @@
+{# One Shot function's dispatch code for transparent drivers.
+Expected inputs:
+* drivers: the list of driver descriptions.
+* entry_point: the name of the entry point that this function dispatches to.
+* entry_point_param(driver): the parameters to pass to the entry point.
+* nest_indent: number of extra spaces to indent the code to.
+-#}
 {% for driver in drivers if driver.type == "transparent" -%}
 {% for capability in driver.capabilities if entry_point in capability.entry_points -%}
-#if ({% if capability.depend_on is defined -%}{{ capability.depend_on }} {% else -%} {{ 1 }} {% endif %})
+#if ({% if capability['mbedtls/c_depend_on'] is defined -%}{{ capability['mbedtls/c_depend_on'] }} {% else -%} {{ 1 }} {% endif %})
 {%- filter indent(width = nest_indent) %}
-{% if capability.name is defined and entry_point in capability.name.keys() -%}
-status = {{ capability.name[entry_point]}}({{entry_point_attributes(driver) | indent(20)}});
-{% else -%}
-status = {{driver.prefix}}_{{driver.type}}_{{entry_point}}({{entry_point_attributes(driver) | indent(20)}});
-{% endif -%}
+status = {{ entry_point_name(capability, entry_point, driver) }}({{entry_point_param(driver) | indent(20)}});
 
 if( status != PSA_ERROR_NOT_SUPPORTED )
     return( status );
diff --git a/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.c.jinja b/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.c.jinja
index bea02a5..b90a9c8 100644
--- a/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.c.jinja
+++ b/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.c.jinja
@@ -1,7 +1,7 @@
 /*
  *  Functions to delegate cryptographic operations to an available
  *  and appropriate accelerator.
- *  Warning: This file will be auto-generated in the future.
+ *  Warning: This file is now auto-generated.
  */
 /*  Copyright The Mbed TLS Contributors
  *  SPDX-License-Identifier: Apache-2.0
@@ -39,13 +39,15 @@
 #if defined(MBEDTLS_PSA_CRYPTO_DRIVERS)
 {% for driver in drivers -%}
 /* Headers for {{driver.prefix}} {{driver.type}} driver */
-{% if driver.dependency is defined -%}
-#if {{ driver.dependency }}
+{% if driver['mbedtls/h_depend_on'] is defined -%}
+#if {{ driver['mbedtls/h_depend_on'] }}
 {% endif -%}
 {% for header in driver.headers -%}
 #include "{{ header }}"
 {% endfor %}
+{% if driver['mbedtls/h_depend_on'] is defined -%}
 #endif
+{% endif -%}
 {% endfor %}
 #endif /* MBEDTLS_PSA_CRYPTO_DRIVERS */
 /* END-driver headers */
@@ -60,6 +62,16 @@
 {% endfor %}
 /* END-driver id */
 
+/* BEGIN-Common Macro definitions */
+{% macro entry_point_name(capability, entry_point, driver) -%}
+    {% if capability.name is defined and entry_point in capability.name.keys() -%}
+    {{ capability.name[entry_point]}}
+    {% else -%}
+    {{driver.prefix}}_{{driver.type}}_{{entry_point}}
+    {% endif -%}
+{% endmacro %}
+/* END-Common Macro definitions */
+
 /* Support the 'old' SE interface when asked to */
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
 /* PSA_CRYPTO_DRIVER_PRESENT is defined when either a new-style or old-style
@@ -595,7 +607,7 @@
     size_t *bits )
 {
 {% set entry_point = "import_key" -%}
-{% macro entry_point_attributes(driver) -%}
+{% macro entry_point_param(driver) -%}
 attributes,
 data,
 data_length,
@@ -677,7 +689,7 @@
 
 {
 {% set entry_point = "export_key" -%}
-{% macro entry_point_attributes(driver) -%}
+{% macro entry_point_param(driver) -%}
 attributes,
 key_buffer,
 key_buffer_size,
@@ -740,7 +752,7 @@
 
 {
 {% set entry_point = "export_public_key" -%}
-{% macro entry_point_attributes(driver) -%}
+{% macro entry_point_param(driver) -%}
 attributes,
 key_buffer,
 key_buffer_size,
@@ -812,7 +824,7 @@
     uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length )
 {
 {% set entry_point = "get_builtin_key" -%}
-{% macro entry_point_attributes(driver) -%}
+{% macro entry_point_param(driver) -%}
 slot_number,
 attributes,
 key_buffer,
@@ -845,7 +857,7 @@
     size_t *target_key_buffer_length )
 {
 {% set entry_point = "copy_key" -%}
-{% macro entry_point_attributes(driver) -%}
+{% macro entry_point_param(driver) -%}
 attributes,
 source_key,
 source_key_length,
diff --git a/scripts/generate_driver_wrappers.py b/scripts/generate_driver_wrappers.py
index 3b60320..3d9be88 100755
--- a/scripts/generate_driver_wrappers.py
+++ b/scripts/generate_driver_wrappers.py
@@ -23,13 +23,15 @@
 import sys
 import os
 import json
-from typing import Tuple
+from typing import Tuple, NewType
 import argparse
 import jsonschema
-from jsonschema import validate
 import jinja2
 from mbedtls_dev import build_tree
 
+JSONSchema = NewType('JSONSchema', object)
+Driver = NewType('Driver', object)
+
 def render(template_path: str, driver_jsoncontext: list) -> str:
     """
     Render template from the input file and driver JSON.
@@ -56,45 +58,68 @@
         out_file.write(result)
 
 
-def validate_json(driverjson_data: list, driverschema: list) -> bool:
+def validate_json(driverjson_data: Driver, driverschema_list: dict) -> bool:
     """
-    Validate the Driver JSON against schema
+    Validate the Driver JSON against an appropriate schema
+    the schema passed could be that matching an opaque/ transparent driver.
     """
+
+    driver_type = driverjson_data["type"]
+    driver_prefix = driverjson_data["prefix"]
     try:
-        validate(instance=driverjson_data, schema=driverschema)
+        _schema = driverschema_list[driver_type]
+        jsonschema.validate(instance=driverjson_data, schema=_schema)
+
+    except KeyError as err:
+        # This could happen if the driverjson_data.type does not exist in the passed in schema list
+        # schemas = {'transparent': transparent_driver_schema, 'opaque': opaque_driver_schema}
+        # Print onto stdout and stderr.
+        print("Unknown Driver type " + driver_type +
+              " for driver " + driver_prefix, str(err))
+        print("Unknown Driver type " + driver_type +
+              " for driver " + driver_prefix, str(err), file=sys.stderr)
+        return False
+
     except jsonschema.exceptions.ValidationError as err:
-        print(err)
-        print("The driver JSON data is InValid")
+        # Print onto stdout and stderr.
+        print("Error: Failed to validate data file: {} using schema: {}."
+              "\n Exception Message: \"{}\""
+              " ".format(driverjson_data, _schema, str(err)))
+        print("Error: Failed to validate data file: {} using schema: {}."
+              "\n Exception Message: \"{}\""
+              " ".format(driverjson_data, _schema, str(err)), file=sys.stderr)
         return False
 
     return True
 
-def merge_driverjsonfiles(mbedtls_root: str, json_directory: str, \
+def read_driver_descriptions(mbedtls_root: str, json_directory: str, \
                           jsondriver_list: str) -> Tuple[bool, list]:
     """
     Merge driver JSON files into a single ordered JSON after validation.
     """
-    result = list()
-    driverlist = list()
-    with open(os.path.join(mbedtls_root, \
-        'scripts/data_files/driver_jsons/driver_transparent_schema.json'), 'r') as file:
+    result = []
+    with open(os.path.join(mbedtls_root,
+                           'scripts',
+                           'data_files',
+                           'driver_jsons',
+                           'driver_transparent_schema.json'), 'r') as file:
         transparent_driver_schema = json.load(file)
-    with open(os.path.join(mbedtls_root, \
-        'scripts/data_files/driver_jsons/driver_opaque_schema.json'), 'r') as file:
+    with open(os.path.join(mbedtls_root,
+                           'scripts',
+                           'data_files',
+                           'driver_jsons',
+                           'driver_opaque_schema.json'), 'r') as file:
         opaque_driver_schema = json.load(file)
 
+    driver_schema_list = {'transparent':transparent_driver_schema,
+                          'opaque':opaque_driver_schema}
+
     with open(os.path.join(json_directory, jsondriver_list), 'r') as driverlistfile:
         driverlist = json.load(driverlistfile)
     for file_name in driverlist:
         with open(os.path.join(json_directory, file_name), 'r') as infile:
             json_data = json.load(infile)
-            if json_data['type'] == 'transparent':
-                ret = validate_json(json_data, transparent_driver_schema)
-            elif json_data['type'] == 'opaque':
-                ret = validate_json(json_data, opaque_driver_schema)
-            else:
-                ret = False
-                print("Unknown Driver type")
+            ret = validate_json(json_data, driver_schema_list)
             if ret is False:
                 return ret, []
             result.append(json_data)
@@ -104,35 +129,45 @@
 def main() -> int:
     """
     Main with command line arguments.
+    returns 1 when read_driver_descriptions returns False
     """
     def_arg_mbedtls_root = build_tree.guess_mbedtls_root()
     def_arg_output_dir = os.path.join(def_arg_mbedtls_root, 'library')
-    def_arg_template_dir = os.path.join(def_arg_mbedtls_root, \
-                           'scripts/data_files/driver_templates/')
-    def_arg_json_dir = os.path.join(def_arg_mbedtls_root, \
-                       'scripts/data_files/driver_jsons/')
+    def_arg_template_dir = os.path.join(def_arg_mbedtls_root,
+                                        'scripts',
+                                        'data_files',
+                                        'driver_templates')
+    def_arg_json_dir = os.path.join(def_arg_mbedtls_root,
+                                    'scripts',
+                                    'data_files',
+                                    'driver_jsons')
 
     parser = argparse.ArgumentParser()
     parser.add_argument('--mbedtls-root', nargs='?', default=def_arg_mbedtls_root,
                         help='root directory of mbedtls source code')
-    parser.add_argument('--template_dir', nargs='?', default=def_arg_template_dir,
+    parser.add_argument('--template-dir', nargs='?', default=def_arg_template_dir,
                         help='root directory of mbedtls source code')
-    parser.add_argument('--json_dir', nargs='?', default=def_arg_json_dir,
+    parser.add_argument('--json-dir', nargs='?', default=def_arg_json_dir,
                         help='root directory of mbedtls source code')
-    parser.add_argument('output_directory', nargs='?',
+    parser.add_argument('output-directory', nargs='?',
                         default=def_arg_output_dir, help='output file\'s location')
     args = parser.parse_args()
 
     mbedtls_root = os.path.abspath(args.mbedtls_root)
-    output_directory = args.output_directory
+    output_directory = def_arg_output_dir
+    if args.template_dir is None:
+        args.template_dir = os.path.join(args.mbedtls_root, def_arg_template_dir)
     template_directory = args.template_dir
+    if args.json_dir is None:
+        args.json_dir = os.path.join(args.mbedtls_root, def_arg_json_dir)
     json_directory = args.json_dir
 
-    # load list of driver jsons from driverlist.json
-    ret, merged_driverjson = merge_driverjsonfiles(mbedtls_root, json_directory, 'driverlist.json')
+    # Read and validate list of driver jsons from driverlist.json
+    ret, merged_driver_json = read_driver_descriptions(mbedtls_root, json_directory,
+                                                       'driverlist.json')
     if ret is False:
         return 1
-    generate_driver_wrapper_file(template_directory, output_directory, merged_driverjson)
+    generate_driver_wrapper_file(template_directory, output_directory, merged_driver_json)
 
     return 0