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/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