set initial volume from mute to default volume
[apps/agl-service-unicens.git] / ucs2-interface / ucs-xml / UcsXml.c
index f9ec5f8..4c392cd 100644 (file)
@@ -1,5 +1,5 @@
 /*------------------------------------------------------------------------------------------------*/\r
-/* Unicens XML Parser                                                                             */\r
+/* UNICENS XML Parser                                                                             */\r
 /* Copyright 2017, Microchip Technology Inc. and its subsidiaries.                                */\r
 /*                                                                                                */\r
 /* Redistribution and use in source and binary forms, with or without                             */\r
@@ -38,7 +38,7 @@
 /************************************************************************/\r
 \r
 #define COMPILETIME_CHECK(cond)  (void)sizeof(int[2 * !!(cond) - 1])\r
-#define RETURN_ASSERT(result) { assert(false); return result; }\r
+#define RETURN_ASSERT(result) { UcsXml_CB_OnError("Assertion in file=%s, line=%d", 2, __FILE__, __LINE__); return result; }\r
 #define MISC_HB(value)      ((uint8_t)((uint16_t)(value) >> 8))\r
 #define MISC_LB(value)      ((uint8_t)((uint16_t)(value) & (uint16_t)0xFF))\r
 \r
@@ -54,6 +54,7 @@ struct UcsXmlRoute
 \r
 struct UcsXmlScript\r
 {\r
+    bool inUse;\r
     char scriptName[32];\r
     Ucs_Rm_Node_t *node;\r
     struct UcsXmlScript *next;\r
@@ -231,6 +232,7 @@ static bool GetElementArray(mxml_node_t *element, const char *array[], const cha
 static bool GetCount(mxml_node_t *element, const char *name, uint32_t *out, bool mandatory);\r
 static bool GetCountArray(mxml_node_t *element, const char *array[], uint32_t *out, bool mandatory);\r
 static bool GetString(mxml_node_t *element, const char *key, const char **out, bool mandatory);\r
+static bool CheckInteger(const char *val, bool forceHex);\r
 static bool GetUInt16(mxml_node_t *element, const char *key, uint16_t *out, bool mandatory);\r
 static bool GetUInt8(mxml_node_t *element, const char *key, uint8_t *out, bool mandatory);\r
 static bool GetSocketType(const char *txt, MSocketType_t *out);\r
@@ -278,9 +280,9 @@ UcsXmlVal_t *UcsXml_Parse(const char *xmlString)
         return val;\r
 ERROR:\r
     if (Parse_MemoryError == result)\r
-        UcsXml_CB_OnError("XML error, aborting..", 0);\r
+        UcsXml_CB_OnError("XML memory error, aborting..", 0);\r
     else\r
-        UcsXml_CB_OnError("Allocation error, aborting..", 0);\r
+        UcsXml_CB_OnError("XML parsing error, aborting..", 0);\r
     assert(false);\r
     if (!tree)\r
         mxmlDelete(tree);\r
@@ -418,19 +420,70 @@ static bool GetString(mxml_node_t *element, const char *key, const char **out, b
     return false;\r
 }\r
 \r
+static bool CheckInteger(const char *value, bool forceHex)\r
+{\r
+    bool hex = forceHex;\r
+    int32_t len;\r
+    if (!value) return false;\r
+    len = strlen(value);\r
+    if (len >= 3 && '0' == value[0] && 'x' == value[1])\r
+    {\r
+        hex = true;\r
+        value += 2;\r
+    }\r
+    while(value[0])\r
+    {\r
+        bool valid = false;\r
+        uint8_t v = value[0];\r
+        if (v >= '0' && v <= '9') valid = true;\r
+        if (hex)\r
+        {\r
+            if (v >= 'a' && v <= 'f') valid = true;\r
+            if (v >= 'A' && v <= 'F') valid = true;\r
+        }\r
+        if (!valid) return false;\r
+        ++value;\r
+    }\r
+    return true;\r
+}\r
+\r
 static bool GetUInt16(mxml_node_t *element, const char *key, uint16_t *out, bool mandatory)\r
 {\r
+    long int value;\r
     const char* txt;\r
     if (!GetString(element, key, &txt, mandatory)) return false;\r
-    *out = strtol( txt, NULL, 0 );\r
+    if (!CheckInteger(txt, false))\r
+    {\r
+        UcsXml_CB_OnError("key='%s' contained invalid integer='%s'", 2, key, txt);\r
+        return false;\r
+    }\r
+    value = strtol( txt, NULL, 0 );\r
+    if (value > 0xFFFF)\r
+    {\r
+        UcsXml_CB_OnError("key='%s' is out of range='%d'", 2, key, value);\r
+        return false;\r
+    }\r
+    *out = value;\r
     return true;\r
 }\r
 \r
 static bool GetUInt8(mxml_node_t *element, const char *key, uint8_t *out, bool mandatory)\r
 {\r
+    long int value;\r
     const char* txt;\r
     if (!GetString(element, key, &txt, mandatory)) return false;\r
-    *out = strtol( txt, NULL, 0 );\r
+    if (!CheckInteger(txt, false))\r
+    {\r
+        UcsXml_CB_OnError("key='%s' contained invalid integer='%s'", 2, key, txt);\r
+        return false;\r
+    }\r
+    value = strtol( txt, NULL, 0 );\r
+    if (value > 0xFF)\r
+    {\r
+        UcsXml_CB_OnError("key='%s' is out of range='%d'", 2, key, value);\r
+        return false;\r
+    }\r
+    *out = value;\r
     return true;\r
 }\r
 \r
@@ -508,6 +561,13 @@ static bool GetPayload(mxml_node_t *element, const char *name, uint8_t **pPayloa
             assert(false);\r
             return 0;\r
         }\r
+        if (!CheckInteger(token, true))\r
+        {\r
+            UcsXml_CB_OnError("Script payload contains non valid hex number='%s'", 1, token);\r
+            free(txtCopy);\r
+            assert(false);\r
+            return 0;\r
+        }\r
         p[offset + len++] = strtol( token, NULL, 16 );\r
         token = strtok_r( NULL, " ,.-", &tkPtr );\r
     }\r
@@ -650,29 +710,30 @@ static ParseResult_t ParseAll(mxml_node_t *tree, UcsXmlVal_t *ucs, PrivateData_t
         if (Parse_Success != (result = ParseNode(sub, priv)))\r
             return result;\r
         /*/Iterate all connections. Node without any connection is also valid.*/\r
-        if (!GetElementArray(sub->child, ALL_CONNECTIONS, &conType, &con))\r
-            continue;\r
-        while(con)\r
+        if (GetElementArray(sub->child, ALL_CONNECTIONS, &conType, &con))\r
         {\r
-            const char *socTypeStr;\r
-            MSocketType_t socType;\r
-            mxml_node_t *soc;\r
-            memset(&priv->conData, 0, sizeof(ConnectionData_t));\r
-            if (Parse_Success != (result = ParseConnection(con, conType, priv)))\r
-                return result;\r
-            /*Iterate all sockets*/\r
-            if(!GetElementArray(con->child, ALL_SOCKETS, &socTypeStr, &soc)) RETURN_ASSERT(Parse_XmlError);\r
-            while(soc)\r
+            while(con)\r
             {\r
-                if (!GetSocketType(socTypeStr, &socType)) RETURN_ASSERT(Parse_XmlError);\r
-                if (Parse_Success != (result = ParseSocket(soc, (0 == priv->conData.sockCnt), socType, &priv->conData.jobList, priv)))\r
+                const char *socTypeStr;\r
+                MSocketType_t socType;\r
+                mxml_node_t *soc;\r
+                memset(&priv->conData, 0, sizeof(ConnectionData_t));\r
+                if (Parse_Success != (result = ParseConnection(con, conType, priv)))\r
                     return result;\r
-                ++priv->conData.sockCnt;\r
-                if(!GetElementArray(soc, ALL_SOCKETS, &socTypeStr, &soc))\r
+                /*Iterate all sockets*/\r
+                if(!GetElementArray(con->child, ALL_SOCKETS, &socTypeStr, &soc)) RETURN_ASSERT(Parse_XmlError);\r
+                while(soc)\r
+                {\r
+                    if (!GetSocketType(socTypeStr, &socType)) RETURN_ASSERT(Parse_XmlError);\r
+                    if (Parse_Success != (result = ParseSocket(soc, (0 == priv->conData.sockCnt), socType, &priv->conData.jobList, priv)))\r
+                        return result;\r
+                    ++priv->conData.sockCnt;\r
+                    if(!GetElementArray(soc, ALL_SOCKETS, &socTypeStr, &soc))\r
+                        break;\r
+                }\r
+                if(!GetElementArray(con, ALL_CONNECTIONS, &conType, &con))\r
                     break;\r
             }\r
-            if(!GetElementArray(con, ALL_CONNECTIONS, &conType, &con))\r
-                break;\r
         }\r
         ++ucs->nodSize;\r
         if (!GetElement(sub, NODE, false, &sub, false))\r
@@ -687,6 +748,8 @@ static ParseResult_t ParseAll(mxml_node_t *tree, UcsXmlVal_t *ucs, PrivateData_t
     /*Iterate all scripts. No scripts at all is allowed*/\r
     if(GetElement(tree, SCRIPT, true, &sub, false))\r
     {\r
+        bool found = true;\r
+        struct UcsXmlScript *scrlist = priv->pScrLst;\r
         while(sub)\r
         {\r
             result = ParseScript(sub, priv);\r
@@ -695,6 +758,18 @@ static ParseResult_t ParseAll(mxml_node_t *tree, UcsXmlVal_t *ucs, PrivateData_t
             if(!GetElement(sub, SCRIPT, false, &sub, false))\r
                 break;\r
         }\r
+        /* Check if all scripts where referenced */\r
+        while(NULL != scrlist)\r
+        {\r
+            if (!scrlist->inUse)\r
+            {\r
+                UcsXml_CB_OnError("Script not defined:'%s', used by node=0x%X", 1, scrlist->scriptName, scrlist->node->signature_ptr->node_address);\r
+                found = false;\r
+            }\r
+            scrlist = scrlist->next;\r
+        }\r
+        if (!found)\r
+            RETURN_ASSERT(Parse_XmlError);\r
     }\r
     return result;\r
 }\r
@@ -995,6 +1070,7 @@ static ParseResult_t ParseSocket(mxml_node_t *soc, bool isSource, MSocketType_t
     /*Connect in and out socket once they are created*/\r
     if (priv->conData.inSocket && priv->conData.outSocket)\r
     {\r
+        bool mostIsInput;\r
         bool mostIsOutput;\r
         Ucs_Rm_EndPoint_t *ep;\r
         struct UcsXmlRoute *route;\r
@@ -1031,7 +1107,13 @@ static ParseResult_t ParseSocket(mxml_node_t *soc, bool isSource, MSocketType_t
         ep = MCalloc(&priv->objList, 1, sizeof(Ucs_Rm_EndPoint_t));\r
         if (NULL == ep) RETURN_ASSERT(Parse_MemoryError);\r
 \r
+        mostIsInput = (UCS_XRM_RC_TYPE_MOST_SOCKET == *((Ucs_Xrm_ResourceType_t *)priv->conData.inSocket));\r
         mostIsOutput = (UCS_XRM_RC_TYPE_MOST_SOCKET == *((Ucs_Xrm_ResourceType_t *)priv->conData.outSocket));\r
+        if (!mostIsInput && !mostIsOutput)\r
+        {\r
+            UcsXml_CB_OnError("At least one MOST socket required per connection", 0);\r
+            RETURN_ASSERT(Parse_XmlError);\r
+        }\r
         ep->endpoint_type = mostIsOutput ? UCS_RM_EP_SOURCE : UCS_RM_EP_SINK;\r
         ep->jobs_list_ptr = GetJobList(*jobList, &priv->objList);\r
         if(NULL == ep->jobs_list_ptr) RETURN_ASSERT(Parse_MemoryError);\r
@@ -1102,7 +1184,7 @@ static ParseResult_t ParseScript(mxml_node_t *scr, PrivateData_t *priv)
             if (Parse_Success != result) return result;\r
         } else {\r
             UcsXml_CB_OnError("Unknown script action:'%s'", 1, txt);\r
-            /*RETURN_ASSERT(Parse_XmlError);*/\r
+            RETURN_ASSERT(Parse_XmlError);\r
         }\r
         if (!GetElementArray(act, ALL_SCRIPTS, &txt, &act))\r
             break;\r
@@ -1117,6 +1199,7 @@ static ParseResult_t ParseScript(mxml_node_t *scr, PrivateData_t *priv)
             Ucs_Rm_Node_t *node = scrlist->node;\r
             node->script_list_ptr = script;\r
             node->script_list_size = actCnt;\r
+            scrlist->inUse = true;\r
             found = true;\r
         }\r
         scrlist = scrlist->next;\r
@@ -1277,7 +1360,11 @@ static ParseResult_t ParseScriptPortCreate(mxml_node_t *act, Ucs_Ns_Script_t *sc
         speed = 0;\r
     else if (0 == strcmp(txt, I2C_SPEED_FAST))\r
         speed = 1;\r
-    else RETURN_ASSERT(Parse_XmlError);\r
+    else\r
+    {\r
+        UcsXml_CB_OnError("Invalid I2C speed:'%s'", 1, txt);\r
+        RETURN_ASSERT(Parse_XmlError);\r
+    }\r
     req = scr->send_cmd;\r
     res = scr->exp_result;\r
     req->InstId = res->InstId = 1;\r
@@ -1317,6 +1404,11 @@ static ParseResult_t ParseScriptPortWrite(mxml_node_t *act, Ucs_Ns_Script_t *scr
             mode = 1;\r
         else if (0 == strcmp(txt, I2C_WRITE_MODE_BURST))\r
             mode = 2;\r
+        else\r
+        {\r
+            UcsXml_CB_OnError("Invalid I2C mode:'%s'", 1, txt);\r
+            RETURN_ASSERT(Parse_XmlError);\r
+        }\r
     } else {\r
         mode = 0;\r
     }\r
@@ -1458,7 +1550,11 @@ static ParseResult_t ParseRoutes(UcsXmlVal_t *ucs, PrivateData_t *priv)
         }\r
         sourceRoute = sourceRoute->next;\r
     }\r
-    assert(routeAmount == ucs->routesSize);\r
+    if (routeAmount != ucs->routesSize)\r
+    {\r
+        UcsXml_CB_OnError("At least one sink (num=%d) is not connected, because of wrong Route name!", 2, (routeAmount - ucs->routesSize));\r
+        RETURN_ASSERT(Parse_XmlError);\r
+    }\r
 \r
 #ifdef DEBUG\r
     /* Third perform checks when running in debug mode*/\r