diff options
author | Fulup Ar Foll <fulup@iot.bzh> | 2017-05-26 18:45:56 +0200 |
---|---|---|
committer | Fulup Ar Foll <fulup@iot.bzh> | 2017-05-26 18:45:56 +0200 |
commit | d2e42029ec04c3f224580f8007cdfbbfe0fc47a6 (patch) | |
tree | ad2ccf167cf7997c84191d41e6ba55cb2efd6bed /ucs2-interface | |
parent | 18e393e1443fd4c38b34979888fb55d30448cf31 (diff) |
Initial Commit
Diffstat (limited to 'ucs2-interface')
-rw-r--r-- | ucs2-interface/CMakeLists.txt | 36 | ||||
-rw-r--r-- | ucs2-interface/ucs-xml/UcsXml.c | 1174 | ||||
-rw-r--r-- | ucs2-interface/ucs-xml/UcsXml.h | 94 | ||||
-rw-r--r-- | ucs2-interface/ucs_config.h | 145 | ||||
-rw-r--r-- | ucs2-interface/ucs_interface.h | 197 | ||||
-rw-r--r-- | ucs2-interface/ucs_lib_interf.c | 647 | ||||
-rw-r--r-- | ucs2-interface/ucs_vol_interf.c | 59 |
7 files changed, 2352 insertions, 0 deletions
diff --git a/ucs2-interface/CMakeLists.txt b/ucs2-interface/CMakeLists.txt new file mode 100644 index 0000000..e4db96b --- /dev/null +++ b/ucs2-interface/CMakeLists.txt @@ -0,0 +1,36 @@ +########################################################################### +# Copyright 2015, 2016, 2017 IoT.bzh +# +# author: Fulup Ar Foll <fulup@iot.bzh> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +########################################################################### + +# Add target to project dependency list +PROJECT_TARGET_ADD(ucs2-inter) + + # Define targets + ADD_LIBRARY(ucs2-inter STATIC ucs_lib_interf.c ucs_vol_interf.c ucs-xml/UcsXml.c) + + # Library properties + SET_TARGET_PROPERTIES(ucs2-inter PROPERTIES OUTPUT_NAME ucs2interface) + + # Depends on Unicens2 lib + TARGET_LINK_LIBRARIES(ucs2-inter ucs2-lib ucs2-vol) + + # Define includes + TARGET_INCLUDE_DIRECTORIES(ucs2-inter + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + ) + + diff --git a/ucs2-interface/ucs-xml/UcsXml.c b/ucs2-interface/ucs-xml/UcsXml.c new file mode 100644 index 0000000..cd7c477 --- /dev/null +++ b/ucs2-interface/ucs-xml/UcsXml.c @@ -0,0 +1,1174 @@ +/* + * Unicens XML Parser + * + * Copyright (C) 2017 Microchip Technology Germany II GmbH & Co. KG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * You may also obtain this software under a propriety license from Microchip. + * Please contact Microchip for further information. + * + */ +#include <assert.h> +#include <string.h> +#include "mxml.h" +#include "UcsXml.h" + +/************************************************************************/ +/* USER ADJUSTABLE CONSTANTS */ +/************************************************************************/ + +#define MAX_JOB_LIST_LEN 6 + +/************************************************************************/ +/* PRIVATE DECLARATIONS */ +/************************************************************************/ + +#define COMPILETIME_CHECK(cond) (void)sizeof(int[!!(cond) - 1]) + +struct UcsXmlObjectList +{ + void *obj; + struct UcsXmlObjectList *next; +}; + +struct UcsXmlRouteInfo +{ + bool isSource; + char routeName[32]; + Ucs_Rm_EndPoint_t *ep; + struct UcsXmlRouteInfo *next; +}; + +struct UcsXmlScriptInfo +{ + char scriptName[32]; + Ucs_Rm_Node_t *node; + struct UcsXmlScriptInfo *next; +}; + +typedef enum +{ + SYNC_DATA = 0, /*!< \brief Specifies the synchronous streaming data type */ + CONTROL_DATA = 2, /*!< \brief Specifies the control data type */ + AV_PACKETIZED = 3, /*!< \brief Specifies the A/V Packetized Isochronous + streaming data type */ + QOS_IP = 4, /*!< \brief Specifies the Quality of Service IP + streaming data type*/ + DISC_FRAME_PHASE = 5, /*!< \brief Specifies the DiscreteFrame Isochronous + streaming phase data type */ + IPC_PACKET = 7, /*!< \brief Specifies the IPC packet data type */ + INVALID = 0xFF /*!< \brief Defined invalid value */ +} MData_t; + +typedef enum +{ + MPORT_MOST, + MPORT_USB, + MPORT_MLB, + MPORT_I2S, + MPORT_INVALID = 0xFF +} MPort_t; + +typedef enum +{ + Parse_Success = 10, + Parse_MemoryError, + Parse_XmlError +} ParseResult_t; + +typedef struct { + struct UcsXmlObjectList objList; + struct UcsXmlRouteInfo *pRtLst; + struct UcsXmlScriptInfo *pScrLst; + Ucs_Rm_Node_t *nod; + Ucs_Xrm_ResObject_t *inSocket; + Ucs_Xrm_ResObject_t *outSocket; + Ucs_Xrm_ResObject_t **jobList; + MData_t dataType; + uint16_t blockWidth; + const char* chName; + uint16_t pause; +} PrivateData_t; + +/************************************************************************/ +/* Constants */ +/************************************************************************/ + +//Key section +static const char* UNICENS = "unicens"; +static const char* ASYNC_BANDWIDTH = "async_bandwidth"; +static const char* CHANNEL = "channel"; +static const char* CHANNEL_NAME = "channel_name"; +static const char* ADDRESS = "channel_addr"; +static const char* BANDWIDTH = "bandwidth"; +static const char* OFFSET = "offset"; +static const char* DATA_TYPE = "data_type"; +static const char* DEVICE = "device"; +static const char* DEVICE_MLB_SPEED = "mlb_port_speed"; +static const char* NODE_ADDR = "node_address"; +static const char* DIR = "dir"; +static const char* I2S_PIN = "i2s_pin"; +static const char* PACKETS_XACT = "packets_per_xact"; +static const char* PORT = "port"; +static const char* SOCKET = "socket"; + +static const char* I2S_FS_SPEED = "i2s_fs_speed"; +static const char* I2S_ALIGN = "i2s_align"; + +//value section +static const char* PORT_MOST = "MOST"; +static const char* PORT_USB = "USB"; +static const char* PORT_MLB = "MLB"; +static const char* PORT_I2S = "I2S"; + +static const char* DATATYPE_SYNC = "SYNC"; +static const char* DATATYPE_AVP = "AVP"; +static const char* DATATYPE_CTRL = "CTRL"; +static const char* DATATYPE_QOS = "QOS"; +static const char* DATATYPE_DFP = "DFP"; +static const char* DATATYPE_IPC = "IPC"; + +static const char* DIR_IN = "IN"; +static const char* DIR_OUT = "OUT"; + +static const char* I2S_PIN_SRXA0 = "SRXA0"; +static const char* I2S_PIN_SRXA1 = "SRXA1"; +static const char* I2S_PIN_SRXB0 = "SRXB0"; +static const char* I2S_PIN_SRXB1 = "SRXB1"; + +static const char* I2S_ALIGN_L16 = "Left16"; +static const char* I2S_ALIGN_L24 = "Left24"; +static const char* I2S_ALIGN_R16 = "Right16"; +static const char* I2S_ALIGN_R24 = "Right24"; +static const char* I2S_ALIGN_SEQUENTIAL = "Seq"; + +static const char* SCRIPT = "script"; +static const char* ACTION = "action"; +static const char* NAME = "name"; +static const char* TYPE = "type"; +static const char* FBLOCK_ID = "fblock_id"; +static const char* FUNCTION_ID = "function_id"; +static const char* OP_TYPE_REQUEST = "op_request"; +static const char* OP_TYPE_RESPONSE = "op_response"; +static const char* PAYLOAD_REQ_HEX = "load_req_hex"; +static const char* PAYLOAD_RES_HEX = "load_res_hex"; +static const char* PAUSE_MS = "pause_ms"; + +static const char* SEND_MSG = "SEND_MSG"; +static const char* PAUSE = "PAUSE"; + +/************************************************************************/ +/* Private Function Prototypes */ +/************************************************************************/ + +static void *MCalloc(struct UcsXmlObjectList *list, uint32_t nElem, uint32_t elemSize); +static void FreeObjList(struct UcsXmlObjectList *cur); +static void FreeVal(UcsXmlVal_t *v); +static bool GetElement(mxml_node_t *element, const char *name, bool goDeep, mxml_node_t **out, bool mandatory); +static bool GetCount(mxml_node_t *element, const char *name, uint32_t *out, bool mandatory); +static bool GetString(mxml_node_t *element, const char *key, const char **out, bool mandatory); +static bool GetUInt16(mxml_node_t *element, const char *key, uint16_t *out, bool mandatory); +static bool GetUInt8(mxml_node_t *element, const char *key, uint8_t *out, bool mandatory); +static bool GetMlbSpeed(mxml_node_t *element, const char *key, Ucs_Mlb_ClockConfig_t *clock, bool mandatory); +static bool GetI2SSpeed(mxml_node_t *element, const char *key, Ucs_Stream_PortClockConfig_t *clock, bool mandatory); +static bool GetI2SPin(mxml_node_t *element, Ucs_Stream_PortPinId_t *pin, uint8_t *portIndex, bool mandatory); +static bool GetI2SAlignment(mxml_node_t *element, Ucs_Stream_PortDataAlign_t *align, bool mandatory); +static bool GetDirection(mxml_node_t *element, Ucs_SocketDirection_t *out); +static bool GetDataType(mxml_node_t *element, MData_t *out); +static bool GetPort(mxml_node_t *element, MPort_t *out); +static bool GetPayload(mxml_node_t *element, const char *name, uint8_t **pPayload, uint8_t *len, + struct UcsXmlObjectList *obj, bool mandatory); +static bool AddJob(Ucs_Xrm_ResObject_t **joblist, Ucs_Xrm_ResObject_t *job); +static void AddRoute(struct UcsXmlRouteInfo **pRtLst, struct UcsXmlRouteInfo *route); +static void AddScript(struct UcsXmlScriptInfo **pScrLst, struct UcsXmlScriptInfo *script); +static ParseResult_t ParseAll(mxml_node_t *tree, UcsXmlVal_t *v, PrivateData_t *vp); +static ParseResult_t ParseDevice(mxml_node_t * dev, PrivateData_t *vp); +static ParseResult_t ParseChannel(mxml_node_t * ch, PrivateData_t *vp); +static ParseResult_t ParseSocket(mxml_node_t *soc, PrivateData_t *vp); +static ParseResult_t ParseMostSoc(Ucs_Xrm_MostSocket_t *mostSoc, mxml_node_t *soc, PrivateData_t *vp); +static ParseResult_t ParseUsbSoc(Ucs_Xrm_UsbSocket_t *usbSoc, mxml_node_t *soc, PrivateData_t *vp); +static ParseResult_t ParseMlbSoc(Ucs_Xrm_MlbSocket_t *mlbSoc, mxml_node_t *soc, PrivateData_t *vp); +static ParseResult_t ParseStreamSoc(Ucs_Xrm_StrmSocket_t *strmSoc, mxml_node_t *soc, PrivateData_t *vp); +static ParseResult_t ParseScript(mxml_node_t *scr, PrivateData_t *vp); +static ParseResult_t ParseScriptAction(mxml_node_t *act, Ucs_Rm_Node_t *n, uint32_t index, PrivateData_t *vp); +static ParseResult_t ParseRoutes(UcsXmlVal_t *v, PrivateData_t *vp); + +/************************************************************************/ +/* Public Functions */ +/************************************************************************/ + +UcsXmlVal_t *UcsXml_Parse(const char *xmlString) +{ + UcsXmlVal_t *v; + ParseResult_t result = Parse_Success; + mxml_node_t *tree = mxmlLoadString(NULL, xmlString, MXML_NO_CALLBACK); + if (!tree) + { + result = Parse_XmlError; + } + if (Parse_Success == result) + { + if (!GetElement(tree, UNICENS, true, &tree, true)) + result = Parse_XmlError; + } + if (Parse_Success == result) + { + //Do not use MCalloc for the root element + v = calloc(1, sizeof(UcsXmlVal_t)); + if (NULL == v) result = Parse_MemoryError; + } + if (Parse_Success == result) + { + //Do not use MCalloc for the private data + v->pInternal = calloc(1, sizeof(PrivateData_t)); + if (NULL == v->pInternal) result = Parse_MemoryError; + } + if (Parse_Success == result) + { + result = ParseAll(tree, v, v->pInternal); + } + if (!tree) + { + mxmlDelete(tree); + } + if (Parse_Success == result) + { + return v; + } + if (Parse_MemoryError == result) + { + UcsXml_CB_OnError("XML error, aborting..", 0); + } + else + { + UcsXml_CB_OnError("Alloc error, aborting..", 0); + } + assert(false); + FreeVal(v); + return NULL; +} + +void UcsXml_FreeVal(UcsXmlVal_t *val) +{ + FreeVal(val); +} + +/************************************************************************/ +/* Private Function Implementations */ +/************************************************************************/ + +static void *MCalloc(struct UcsXmlObjectList *list, uint32_t nElem, uint32_t elemSize) +{ + void *obj; + struct UcsXmlObjectList *tail = list; + if (NULL == list || 0 == nElem || 0 == elemSize) return NULL; + + obj = calloc(nElem, elemSize); + if (NULL == obj) + { + assert(false); + return NULL; + } + if (NULL == list->obj) + { + list->obj = obj; + return obj; + } + while(tail->next) tail = tail->next; + tail->next = calloc(1, sizeof(struct UcsXmlObjectList)); + if (NULL == tail->next) + { + assert(false); + free(obj); + return NULL; + } + tail->next->obj = obj; + return obj; +} + +static void FreeObjList(struct UcsXmlObjectList *cur) +{ + struct UcsXmlObjectList *root = cur; + while(cur) + { + struct UcsXmlObjectList *next = cur->next; + assert(NULL != cur->obj); + if (cur->obj) + free(cur->obj); + if (cur != root) + free(cur); + cur = next; + } +} + +static void FreeVal(UcsXmlVal_t *v) +{ + PrivateData_t *vp; + if (NULL == v || NULL == v->pInternal) + return; + vp = v->pInternal; + FreeObjList(&vp->objList); + free(v->pInternal); + free(v); +} + +static bool GetElement(mxml_node_t *element, const char *name, bool goDeep, mxml_node_t **out, bool mandatory) +{ + mxml_node_t *n = element; + if (NULL == n || NULL == name || NULL == out) return false; + if (goDeep) + { + *out = mxmlFindElement(n, n, name, NULL, NULL, MXML_DESCEND); + return (NULL != *out); + } + while ((n = n->next)) + { + if (MXML_ELEMENT != n->type) + continue; + if (0 == strcmp(name, n->value.opaque)) + { + *out = n; + return true; + } + } + if (mandatory) + UcsXml_CB_OnError("Can not find tag <%s>", 1, name); + return false; +} + +static bool GetCount(mxml_node_t *element, const char *name, uint32_t *out, bool mandatory) +{ + uint32_t cnt = 0; + mxml_node_t *n; + if (NULL == element || NULL == name) return false; + if(!GetElement(element, name, true, &n, false)) + return false; + while(NULL != n) + { + ++cnt; + if(!GetElement(n, name, false, &n, false)) + break; + } + if (mandatory && 0 == cnt) + { + UcsXml_CB_OnError("element count of <%s> is zero", 1, name); + return false; + } + *out = cnt; + return true; +} + +static bool GetString(mxml_node_t *element, const char *key, const char **out, bool mandatory) +{ + uint32_t i; + if (NULL == element || NULL == key) return false; + for (i = 0; i < element->value.element.num_attrs; i++) + { + mxml_attr_t *attr = &element->value.element.attrs[i]; + if (0 == strcmp(key, attr->name)) + { + *out = attr->value; + return true; + } + } + if (mandatory) + UcsXml_CB_OnError("Can not find attribute='%s' from element <%s>", + 2, key, element->value.element.name); + return false; +} + +static bool GetUInt16(mxml_node_t *element, const char *key, uint16_t *out, bool mandatory) +{ + const char* txt; + if (!GetString(element, key, &txt, mandatory)) return false; + *out = strtol( txt, NULL, 0 ); + return true; +} + +static bool GetUInt8(mxml_node_t *element, const char *key, uint8_t *out, bool mandatory) +{ + const char* txt; + if (!GetString(element, key, &txt, mandatory)) return false; + *out = strtol( txt, NULL, 0 ); + return true; +} + +static bool GetMlbSpeed(mxml_node_t *element, const char *key, Ucs_Mlb_ClockConfig_t *clock, bool mandatory) +{ + uint16_t speed; + if (!GetUInt16(element, DEVICE_MLB_SPEED, &speed, false)) + return false; + switch(speed) + { + case 256: *clock = UCS_MLB_CLK_CFG_256_FS; break; + case 512: *clock = UCS_MLB_CLK_CFG_512_FS; break; + case 1024: *clock = UCS_MLB_CLK_CFG_1024_FS; break; + case 2048: *clock = UCS_MLB_CLK_CFG_2048_FS; break; + case 3072: *clock = UCS_MLB_CLK_CFG_3072_FS; break; + case 4096: *clock = UCS_MLB_CLK_CFG_4096_FS; break; + case 6144: *clock = UCS_MLB_CLK_CFG_6144_FS; break; + case 8192: *clock = UCS_MLB_CLK_CFG_8192_FS; break; + case 0: *clock = UCS_MLB_CLK_CFG_WILDCARD; break; + default: + UcsXml_CB_OnError("Invalid MLB clock val:'%d'", 1, clock); + return false; + } + return true; +} + +static bool GetI2SSpeed(mxml_node_t *element, const char *key, Ucs_Stream_PortClockConfig_t *clock, bool mandatory) +{ + uint16_t speed; + if (!GetUInt16(element, I2S_FS_SPEED, &speed, false)) + return false; + switch(speed) + { + case 8: *clock = UCS_STREAM_PORT_CLK_CFG_8FS; break; + case 16: *clock = UCS_STREAM_PORT_CLK_CFG_16FS; break; + case 32: *clock = UCS_STREAM_PORT_CLK_CFG_32FS; break; + case 64: *clock = UCS_STREAM_PORT_CLK_CFG_64FS; break; + case 128: *clock = UCS_STREAM_PORT_CLK_CFG_128FS; break; + case 256: *clock = UCS_STREAM_PORT_CLK_CFG_256FS; break; + case 512: *clock = UCS_STREAM_PORT_CLK_CFG_512FS; break; + case 0: *clock = UCS_MLB_CLK_CFG_WILDCARD; break; + default: + UcsXml_CB_OnError("Invalid I2S clock val:'%d'", 1, clock); + return false; + } + return true; +} + +static bool GetI2SPin(mxml_node_t *element, Ucs_Stream_PortPinId_t *pin, uint8_t *portIndex, bool mandatory) +{ + const char *txt; + if (!GetString(element, I2S_PIN, &txt, true)) + return false; + if (0 == strcmp(I2S_PIN_SRXA0, txt)) + { + *pin = UCS_STREAM_PORT_PIN_ID_SRXA0; + *portIndex = 0; + return true; + } + else if (0 == strcmp(I2S_PIN_SRXA1, txt)) + { + *pin = UCS_STREAM_PORT_PIN_ID_SRXA1; + *portIndex = 0; + return true; + } + else if (0 == strcmp(I2S_PIN_SRXB0, txt)) + { + *pin = UCS_STREAM_PORT_PIN_ID_SRXB0; + *portIndex = 1; + return true; + } + else if (0 == strcmp(I2S_PIN_SRXB1, txt)) + { + *pin = UCS_STREAM_PORT_PIN_ID_SRXB1; + *portIndex = 1; + return true; + } + UcsXml_CB_OnError("Invalid I2S pin val:'%s'", 1, txt); + return false; +} + +static bool GetI2SAlignment(mxml_node_t *element, Ucs_Stream_PortDataAlign_t *align, bool mandatory) +{ + const char *txt; + if (!GetString(element, I2S_ALIGN, &txt, true)) + return false; + if (0 == strcmp(I2S_ALIGN_L16, txt)) + *align = UCS_STREAM_PORT_ALGN_LEFT16BIT; + else if (0 == strcmp(I2S_ALIGN_L24, txt)) + *align = UCS_STREAM_PORT_ALGN_LEFT24BIT; + else if (0 == strcmp(I2S_ALIGN_R16, txt)) + *align = UCS_STREAM_PORT_ALGN_RIGHT16BIT; + else if (0 == strcmp(I2S_ALIGN_R24, txt)) + *align = UCS_STREAM_PORT_ALGN_RIGHT24BIT; + else if (0 == strcmp(I2S_ALIGN_SEQUENTIAL, txt)) + *align = UCS_STREAM_PORT_ALGN_SEQ; + else + { + UcsXml_CB_OnError("Invalid I2S alignment:'%s'", 1, txt); + return false; + } + return true; +} + +static bool GetDirection(mxml_node_t *element, Ucs_SocketDirection_t *out) +{ + const char *txt; + if (!GetString(element, DIR, &txt, true)) return false; + if (0 == strcmp(DIR_IN, txt)) + *out = UCS_SOCKET_DIR_INPUT; + else if (0 == strcmp(DIR_OUT, txt)) + *out = UCS_SOCKET_DIR_OUTPUT; + else + return false; + return true; +} + +static bool GetDataType(mxml_node_t *element, MData_t *out) +{ + const char *txt; + if (!GetString(element, DATA_TYPE, &txt, true)) return false; + if (0 == strcmp(DATATYPE_SYNC, txt)) { + *out = SYNC_DATA; + } else if (0 == strcmp(DATATYPE_CTRL, txt)) { + *out = CONTROL_DATA; + } else if (0 == strcmp(DATATYPE_AVP, txt)) { + *out = AV_PACKETIZED; + } else if (0 == strcmp(DATATYPE_QOS, txt)) { + *out = QOS_IP; + } else if (0 == strcmp(DATATYPE_DFP, txt)) { + *out = DISC_FRAME_PHASE; + } else if (0 == strcmp(DATATYPE_IPC, txt)) { + *out = IPC_PACKET; + } else { + UcsXml_CB_OnError("Unknown data type : '%s'", 1, txt); + return false; + } + return true; +} + +static bool GetPort(mxml_node_t *element, MPort_t *out) +{ + const char *txt; + if (!GetString(element, PORT, &txt, true)) return false; + if (0 == strcmp(txt, PORT_MOST)) { + *out = MPORT_MOST; + } else if (0 == strcmp(txt, PORT_USB)) { + *out = MPORT_USB; + } else if (0 == strcmp(txt, PORT_MLB)) { + *out = MPORT_MLB; + } else if (0 == strcmp(txt, PORT_I2S)) { + *out = MPORT_I2S; + } else { + UcsXml_CB_OnError("Unknown port : '%s'", 1, txt); + return false; + } + return true; +} + +static bool GetPayload(mxml_node_t *element, const char *name, uint8_t **pPayload, uint8_t *outLen, struct UcsXmlObjectList *obj, bool mandatory) +{ + uint32_t tempLen, len = 0; + uint8_t *p; + const char *txt; + char *txtCopy; + char *tkPtr; + char *token; + if (!GetString(element, name, &txt, mandatory)) + return false; + tempLen = strlen(txt) + 1; + txtCopy = malloc(tempLen); + if (NULL == txtCopy) + return false; + strncpy(txtCopy, txt, tempLen); + tempLen = tempLen / 3; /* 2 chars hex value plus space (AA ) */ + p = MCalloc(obj, tempLen, 1); + if (NULL == p) + { + free(txtCopy); + return false; + } + *pPayload = p; + token = strtok_r( txtCopy, " ,.-", &tkPtr ); + while( NULL != token ) + { + if( len >= tempLen ) + { + UcsXml_CB_OnError("Script payload values must be stuffed to two characters", 0); + free(txtCopy); + assert(false); + return 0; + } + p[len++] = strtol( token, NULL, 16 ); + token = strtok_r( NULL, " ,.-", &tkPtr ); + } + *outLen = len; + return true; +} + +static bool AddJob(Ucs_Xrm_ResObject_t **joblist, Ucs_Xrm_ResObject_t *job) +{ + uint32_t i; + if (NULL == joblist || NULL == job) + { + assert(false); + return false; + } + for (i = 0; i < MAX_JOB_LIST_LEN; i++) + { + if (NULL == joblist[i]) + { + joblist[i] = job; + return true; + } + } + assert(false); + return false; +} + +static void AddRoute(struct UcsXmlRouteInfo **pRtLst, struct UcsXmlRouteInfo *route) +{ + struct UcsXmlRouteInfo *tail; + if (NULL == pRtLst || NULL == route) return; + if (NULL == pRtLst[0]) + { + pRtLst[0] = route; + return; + } + tail = pRtLst[0]; + while(tail->next) tail = tail->next; + tail->next = route; +} + +static void AddScript(struct UcsXmlScriptInfo **pScrLst, struct UcsXmlScriptInfo *script) +{ + struct UcsXmlScriptInfo *tail; + if (NULL == pScrLst || NULL == script) return; + if (NULL == pScrLst[0]) + { + pScrLst[0] = script; + return; + } + tail = pScrLst[0]; + while(tail->next) tail = tail->next; + tail->next = script; +} + +static ParseResult_t ParseAll(mxml_node_t *tree, UcsXmlVal_t *v, PrivateData_t *vp) +{ + uint32_t devCount; + mxml_node_t *sub; + ParseResult_t result; + if (!GetCount(tree, DEVICE, &devCount, true)) + return Parse_XmlError; + + v->pNod = MCalloc(&vp->objList, devCount, sizeof(Ucs_Rm_Node_t)); + if (NULL == v->pNod) return Parse_MemoryError; + + if (!GetUInt16(tree, ASYNC_BANDWIDTH, &v->packetBw, true)) + return Parse_XmlError; + + ///Iterate all devices + if (!GetElement(tree, DEVICE, true, &sub, true)) + return Parse_XmlError; + while(sub) + { + mxml_node_t *ch; + vp->nod = &v->pNod[v->nodSize]; + if (Parse_Success != (result = ParseDevice(sub, vp))) + return result; + ///Iterate all channels. Device without any channel is also valid. + if (GetElement(sub->child, CHANNEL, false, &ch, false)) + { + while(ch) + { + mxml_node_t *soc; + uint8_t sockCnt = 0; + if (Parse_Success != (result = ParseChannel(ch, vp))) + return result; + ///Iterate all sockets + if(!GetElement(ch->child, SOCKET, false, &soc, true)) + return Parse_XmlError; + while(soc) + { + ParseResult_t result; + if (Parse_Success != (result = ParseSocket(soc, vp))) + return result; + ++sockCnt; + if (!GetElement(soc, SOCKET, false, &soc, false)) + break; + } + if (2 != sockCnt) + { + UcsXml_CB_OnError("%d sockets per channel found, must be 2", 1, sockCnt); + return Parse_XmlError; + } + if (!GetElement(ch, CHANNEL, false, &ch, false)) + break; + } + } + ++v->nodSize; + if (!GetElement(sub, DEVICE, false, &sub, false)) + break; + } + + ///Fill route structures + result = ParseRoutes(v, vp); + if (Parse_MemoryError == result) return Parse_MemoryError; + else if (Parse_XmlError == result) return Parse_XmlError; + + ///Iterate all scripts. No scripts at all is allowed + if(GetElement(tree, SCRIPT, true, &sub, false)) + { + while(sub) + { + ParseResult_t result = ParseScript(sub, vp); + if (Parse_MemoryError == result) return Parse_MemoryError; + else if (Parse_XmlError == result) return Parse_XmlError; + if(!GetElement(sub, SCRIPT, false, &sub, false)) + break; + } + } + return result; +} + +static ParseResult_t ParseDevice(mxml_node_t * dev, PrivateData_t *vp) +{ + const char *txt; + assert(NULL != dev && NULL != vp); + vp->nod->signature_ptr = MCalloc(&vp->objList, 1, sizeof(Ucs_Signature_t)); + if(NULL == vp->nod->signature_ptr) return Parse_MemoryError; + if (!GetUInt16(dev, NODE_ADDR, &vp->nod->signature_ptr->node_address, true)) + return Parse_XmlError; + if (GetString(dev, SCRIPT, &txt, false)) + { + struct UcsXmlScriptInfo *scr = MCalloc(&vp->objList, 1, sizeof(struct UcsXmlScriptInfo)); + if (NULL == scr) return Parse_MemoryError; + scr->node = vp->nod; + strncpy(scr->scriptName, txt, sizeof(scr->scriptName)); + AddScript(&vp->pScrLst, scr); + } + return Parse_Success;; +} + +static ParseResult_t ParseChannel(mxml_node_t *ch, PrivateData_t *vp) +{ + vp->inSocket = NULL; + vp->outSocket = NULL; + vp->jobList = NULL; + vp->dataType = 0xFF; + vp->blockWidth = 0; + vp->chName = NULL; + assert(NULL != ch && NULL != vp); + if (!GetString(ch, CHANNEL_NAME, &vp->chName, true)) + return Parse_XmlError; + if (!GetDataType(ch, &vp->dataType)) + return Parse_XmlError; + if (!GetUInt16(ch, BANDWIDTH, &vp->blockWidth, true)) + return Parse_XmlError; + vp->jobList = MCalloc(&vp->objList, MAX_JOB_LIST_LEN, sizeof(Ucs_Xrm_ResObject_t *)); + if (NULL == vp->jobList) return Parse_MemoryError; + return Parse_Success; +} + +static ParseResult_t ParseSocket(mxml_node_t *soc, PrivateData_t *vp) +{ + MPort_t port; + bool isIn = false; + bool isSource = false; + uint16_t offset = 0; + assert(NULL != soc && NULL != vp); + Ucs_SocketDirection_t direction; + if (!GetDirection(soc, &direction)) + return Parse_XmlError; + isIn = (UCS_SOCKET_DIR_INPUT == direction); + if (!GetPort(soc, &port)) + return Parse_XmlError; + switch(port) + { + case MPORT_MOST: + { + Ucs_Xrm_MostSocket_t *sock = MCalloc(&vp->objList, 1, sizeof(Ucs_Xrm_MostSocket_t)); + if (NULL == sock) return Parse_MemoryError; + if (!AddJob(vp->jobList, sock)) return Parse_XmlError; + sock->data_type = vp->dataType; + sock->bandwidth = vp->blockWidth; + if (Parse_Success != ParseMostSoc(sock, soc, vp)) + return Parse_XmlError; + isSource = (UCS_SOCKET_DIR_OUTPUT == direction); + if (isIn) vp->inSocket = sock; else vp->outSocket = sock; + break; + } + case MPORT_USB: + { + Ucs_Xrm_UsbSocket_t *sock = MCalloc(&vp->objList, 1, sizeof(Ucs_Xrm_UsbSocket_t)); + if (NULL == sock) return Parse_MemoryError; + if (!AddJob(vp->jobList, sock)) return Parse_XmlError; + sock->data_type = vp->dataType; + if (Parse_Success != ParseUsbSoc(sock, soc, vp)) + return Parse_XmlError; + if (isIn) vp->inSocket = sock; else vp->outSocket = sock; + break; + } + case MPORT_MLB: + { + Ucs_Xrm_MlbSocket_t *sock = MCalloc(&vp->objList, 1, sizeof(Ucs_Xrm_MlbSocket_t)); + if (NULL == sock) return Parse_MemoryError; + if (!AddJob(vp->jobList, sock)) return Parse_XmlError; + sock->data_type = vp->dataType; + sock->bandwidth = vp->blockWidth; + if (Parse_Success != ParseMlbSoc(sock, soc, vp)) + return Parse_XmlError; + if (isIn) vp->inSocket = sock; else vp->outSocket = sock; + break; + } + case MPORT_I2S: + { + Ucs_Xrm_StrmSocket_t *sock = MCalloc(&vp->objList, 1, sizeof(Ucs_Xrm_StrmSocket_t)); + if (NULL == sock) return Parse_MemoryError; + sock->data_type = vp->dataType; + sock->bandwidth = vp->blockWidth; + if (Parse_Success != ParseStreamSoc(sock, soc, vp)) + return Parse_XmlError; + if (isIn) vp->inSocket = sock; else vp->outSocket = sock; + break; + } + default: + assert(false); + return Parse_XmlError; + } + if (GetUInt16(soc, OFFSET, &offset, false)) + { + //TODO: If offset is non zero allocate Splitter / Combiner + } + //Connect in and out socket once they are created + if (vp->inSocket && vp->outSocket) + { + switch(vp->dataType) + { + case AV_PACKETIZED: + { + Ucs_Xrm_AvpCon_t *con = MCalloc(&vp->objList, 1, sizeof(Ucs_Xrm_AvpCon_t)); + if (NULL == con) return Parse_MemoryError; + if (!AddJob(vp->jobList, con)) + return Parse_XmlError; + con->resource_type = UCS_XRM_RC_TYPE_AVP_CON; + con->socket_in_obj_ptr = vp->inSocket; + con->socket_out_obj_ptr = vp->outSocket; + con->isoc_packet_size = UCS_ISOC_PCKT_SIZE_188; //TODO:Read from XML + break; + } + case SYNC_DATA: + { + Ucs_Xrm_SyncCon_t *con = MCalloc(&vp->objList, 1, sizeof(Ucs_Xrm_SyncCon_t)); + if (NULL == con) return Parse_MemoryError; + if (!AddJob(vp->jobList, con)) + return Parse_XmlError; + con->resource_type = UCS_XRM_RC_TYPE_SYNC_CON; + con->socket_in_obj_ptr = vp->inSocket; + con->socket_out_obj_ptr = vp->outSocket; + con->mute_mode = UCS_SYNC_MUTE_MODE_NO_MUTING; //TODO:Read from XML + con->offset = offset; + break; + } + default: + UcsXml_CB_OnError("Could not connect sockets, data type not implemented: %d", 1, vp->dataType); + return Parse_XmlError; + break; + } + Ucs_Rm_EndPoint_t *ep = MCalloc(&vp->objList, 1, sizeof(Ucs_Rm_EndPoint_t)); + if (NULL == ep) return Parse_MemoryError; + ep->endpoint_type = isSource ? UCS_RM_EP_SOURCE : UCS_RM_EP_SINK; + ep->jobs_list_ptr = vp->jobList; + ep->node_obj_ptr = vp->nod; + + struct UcsXmlRouteInfo *route = MCalloc(&vp->objList, 1, sizeof(struct UcsXmlRouteInfo)); + if (NULL == route) return Parse_MemoryError; + route->isSource = isSource; + route->ep = ep; + strncpy(route->routeName, vp->chName, sizeof(route->routeName)); + AddRoute(&vp->pRtLst, route); + } + return Parse_Success; +} + +static ParseResult_t ParseMostSoc(Ucs_Xrm_MostSocket_t *mostSoc, mxml_node_t *soc, PrivateData_t *vp) +{ + assert(NULL != mostSoc && NULL != soc && NULL != vp); + COMPILETIME_CHECK(SYNC_DATA == (MData_t)UCS_MOST_SCKT_SYNC_DATA); + COMPILETIME_CHECK(AV_PACKETIZED == (MData_t)UCS_MOST_SCKT_AV_PACKETIZED); + COMPILETIME_CHECK(QOS_IP == (MData_t)UCS_MOST_SCKT_QOS_IP); + COMPILETIME_CHECK(DISC_FRAME_PHASE == (MData_t)UCS_MOST_SCKT_DISC_FRAME_PHASE); + switch((MData_t)mostSoc->data_type) + { + case SYNC_DATA: + case AV_PACKETIZED: + case QOS_IP: + case DISC_FRAME_PHASE: + break; //Nothing to do, valid values. + default: + UcsXml_CB_OnError("Invalid DataType=%d for MOST socket", 1, mostSoc->data_type); + return Parse_XmlError; + } + mostSoc->resource_type = UCS_XRM_RC_TYPE_MOST_SOCKET; + mostSoc->most_port_handle = 0x0D00; + if (!GetDirection(soc, &mostSoc->direction)) + return Parse_XmlError; + return Parse_Success; +} + +static ParseResult_t ParseUsbSoc(Ucs_Xrm_UsbSocket_t *usbSoc, mxml_node_t *soc, PrivateData_t *vp) +{ + Ucs_Xrm_DefaultCreatedPort_t *p; + assert(NULL != usbSoc && NULL != soc && NULL != vp); + COMPILETIME_CHECK(SYNC_DATA == (MData_t)UCS_USB_SCKT_SYNC_DATA); + COMPILETIME_CHECK(CONTROL_DATA == (MData_t)UCS_USB_SCKT_CONTROL_DATA); + COMPILETIME_CHECK(AV_PACKETIZED == (MData_t)UCS_USB_SCKT_AV_PACKETIZED); + switch((MData_t)usbSoc->data_type) + { + case SYNC_DATA: + case CONTROL_DATA: + case AV_PACKETIZED: + break; //Nothing to do, valid values. + default: + UcsXml_CB_OnError("Invalid DataType=%d for USB socket", 1, usbSoc->data_type); + return Parse_XmlError; + } + usbSoc->resource_type = UCS_XRM_RC_TYPE_USB_SOCKET; + if (!GetDirection(soc, &usbSoc->direction)) + return Parse_XmlError; + if (!GetUInt8(soc, ADDRESS, &usbSoc->end_point_addr, true)) + return Parse_XmlError; + + if (!GetUInt16(soc, PACKETS_XACT, &usbSoc->frames_per_transfer, true)) + return Parse_XmlError; + + //XML provides currently no way to open USB port, so use ConfigString default + p = MCalloc(&vp->objList, 1, sizeof(Ucs_Xrm_DefaultCreatedPort_t)); + if (NULL == p) return Parse_MemoryError; + if (!AddJob(vp->jobList, p)) return Parse_MemoryError; + p->resource_type = UCS_XRM_RC_TYPE_DC_PORT; + p->port_type = UCS_XRM_PORT_TYPE_USB; + p->index = 0; + usbSoc->usb_port_obj_ptr = p; + return Parse_Success; +} + +static ParseResult_t ParseMlbSoc(Ucs_Xrm_MlbSocket_t *mlbSoc, mxml_node_t *soc, PrivateData_t *vp) +{ + Ucs_Mlb_ClockConfig_t clock; + assert(NULL != mlbSoc && NULL != soc && NULL != vp); + COMPILETIME_CHECK(SYNC_DATA == (MData_t)UCS_MLB_SCKT_SYNC_DATA); + COMPILETIME_CHECK(CONTROL_DATA == (MData_t)UCS_MLB_SCKT_CONTROL_DATA); + COMPILETIME_CHECK(AV_PACKETIZED == (MData_t)UCS_USB_SCKT_AV_PACKETIZED); + COMPILETIME_CHECK(QOS_IP == (MData_t)UCS_MLB_SCKT_QOS_IP); + COMPILETIME_CHECK(DISC_FRAME_PHASE == (MData_t)UCS_MLB_SCKT_DISC_FRAME_PHASE); + COMPILETIME_CHECK(IPC_PACKET == (MData_t)UCS_MLB_SCKT_IPC_PACKET); + switch((MData_t)mlbSoc->data_type) + { + case SYNC_DATA: + case CONTROL_DATA: + case AV_PACKETIZED: + case QOS_IP: + case DISC_FRAME_PHASE: + case IPC_PACKET: + break; //Nothing to do, valid values. + default: + UcsXml_CB_OnError("Invalid DataType=%d for MLB socket", 1, mlbSoc->data_type); + return Parse_XmlError; + } + mlbSoc->resource_type = UCS_XRM_RC_TYPE_MLB_SOCKET; + if (!GetDirection(soc, &mlbSoc->direction)) + return Parse_XmlError; + if (!GetUInt16(soc, ADDRESS, &mlbSoc->channel_address, true)) + return Parse_XmlError; + + //Create MLB port when DEVICE_MLB_SPEED is defined, otherwise use ConfigString default + if (GetMlbSpeed(soc, DEVICE_MLB_SPEED, &clock, false)) + { + Ucs_Xrm_MlbPort_t *p = MCalloc(&vp->objList, 1, sizeof(Ucs_Xrm_MlbPort_t)); + if (NULL == p) return Parse_MemoryError; + if (!AddJob(vp->jobList, p)) return Parse_MemoryError; + p->resource_type = UCS_XRM_RC_TYPE_MLB_PORT; + p->index = 0; + p->clock_config = clock; + mlbSoc->mlb_port_obj_ptr = p; + } else { + Ucs_Xrm_DefaultCreatedPort_t *p = MCalloc(&vp->objList, 1, sizeof(Ucs_Xrm_DefaultCreatedPort_t)); + if (NULL == p) return Parse_MemoryError; + if (!AddJob(vp->jobList, p)) return Parse_MemoryError; + p->resource_type = UCS_XRM_RC_TYPE_DC_PORT; + p->port_type = UCS_XRM_PORT_TYPE_MLB; + p->index = 0; + mlbSoc->mlb_port_obj_ptr = p; + } + return Parse_Success; +} + +static ParseResult_t ParseStreamSoc(Ucs_Xrm_StrmSocket_t *strmSoc, mxml_node_t *soc, PrivateData_t *vp) +{ + const char *txt; + Ucs_Xrm_StrmPort_t *strPort; + assert(NULL != strmSoc && NULL != soc && NULL != vp); + COMPILETIME_CHECK(SYNC_DATA == (MData_t)UCS_STREAM_PORT_SCKT_SYNC_DATA); + if (SYNC_DATA != (MData_t)strmSoc->data_type) + { + UcsXml_CB_OnError("Invalid DataType=%d for I2S socket", 1, strmSoc->data_type); + return Parse_XmlError; + } + strPort = MCalloc(&vp->objList, 1, sizeof(Ucs_Xrm_StrmPort_t)); + if (NULL == strPort) return Parse_MemoryError; + if (!AddJob(vp->jobList, strPort)) return Parse_MemoryError; + if (!AddJob(vp->jobList, strmSoc)) return Parse_MemoryError; + strmSoc->resource_type = UCS_XRM_RC_TYPE_STRM_SOCKET; + strmSoc->stream_port_obj_ptr = strPort; + + strPort->resource_type = UCS_XRM_RC_TYPE_STRM_PORT; + if (!GetDirection(soc, &strmSoc->direction)) + return Parse_XmlError; + if (!GetI2SPin(soc, &strmSoc->stream_pin_id, &strPort->index, true)) + return Parse_XmlError; + if (!GetI2SSpeed(soc, I2S_FS_SPEED, &strPort->clock_config, true)) + return Parse_XmlError; + if (!GetString(soc, I2S_ALIGN, &txt, true)) + return Parse_XmlError; + if (!GetI2SAlignment(soc, &strPort->data_alignment, true)) + return Parse_XmlError; + return Parse_Success; +} + +static ParseResult_t ParseScript(mxml_node_t *scr, PrivateData_t *vp) +{ + mxml_node_t *act; + uint32_t actCnt; + uint32_t i = 0; + const char *txt; + assert(NULL != scr && NULL != vp); + vp->pause = 0; + if (!GetString(scr, NAME, &txt, true)) + return Parse_XmlError; + Ucs_Rm_Node_t *n = NULL; + struct UcsXmlScriptInfo *scrlist = vp->pScrLst; + while(NULL != scrlist) + { + if (0 == strcmp(txt, scrlist->scriptName)) + { + n = scrlist->node; + break; + } + scrlist = scrlist->next; + } + if (NULL == n) + { + UcsXml_CB_OnError("Script defined:'%s', which was never referenced", 1, txt); + return Parse_XmlError; + } + if (!GetCount(scr, ACTION, &actCnt, true)) return Parse_XmlError; + if (NULL == (n->script_list_ptr = MCalloc(&vp->objList, actCnt, sizeof(Ucs_Ns_Script_t)))) + return Parse_MemoryError; + n->script_list_size = actCnt; + ///Iterate all actions + if (!GetElement(scr, ACTION, true, &act, true)) return false; + while(act) + { + ParseResult_t result = ParseScriptAction(act, n, i, vp); + if (Parse_Success != result) return result; + if (!GetElement(act, ACTION, false, &act, false)) + break; + ++i; + } + return Parse_Success; +} + +static ParseResult_t ParseScriptAction(mxml_node_t *act, Ucs_Rm_Node_t *n, uint32_t index, PrivateData_t *vp) +{ + const char *txt; + uint8_t opResult; + assert(NULL != act && NULL != vp); + Ucs_Ns_Script_t *scr = &n->script_list_ptr[index]; + if (!GetString(act, TYPE, &txt, true)) + return Parse_XmlError; + if (0 == strcmp(txt, SEND_MSG)) + { + Ucs_Ns_ConfigMsg_t *req; + scr->send_cmd = MCalloc(&vp->objList, 1, sizeof(Ucs_Ns_ConfigMsg_t)); + req = scr->send_cmd; + if (NULL == req) return Parse_MemoryError; + scr->pause = vp->pause; + if (vp->pause) vp->pause = 0; + req->InstId = 1; + if (!GetUInt8(act, FBLOCK_ID, &req->FBlockId, true)) + return Parse_XmlError; + + if (!GetUInt16(act, FUNCTION_ID, &req->FunktId, true)) + return Parse_XmlError; + + if (!GetUInt8(act, OP_TYPE_REQUEST, &req->OpCode, true)) + return Parse_XmlError; + + if (GetUInt8(act, OP_TYPE_RESPONSE, &opResult, false)) + { + //Waiting for response is optional + Ucs_Ns_ConfigMsg_t *res; + scr->exp_result = MCalloc(&vp->objList, 1, sizeof(Ucs_Ns_ConfigMsg_t)); + res = scr->exp_result; + res->FBlockId = req->FBlockId; + res->InstId = req->InstId; + res->FunktId = req->FunktId; + res->OpCode = opResult; + //Not interested in result: + GetPayload(act, PAYLOAD_RES_HEX, &res->DataPtr, &res->DataLen, &vp->objList, false); + } + if (!GetPayload(act, PAYLOAD_REQ_HEX, &req->DataPtr, &req->DataLen, &vp->objList, true)) + return Parse_XmlError; + if (0 == req->DataLen || NULL == req->DataPtr) + return Parse_XmlError; + } + else if (0 == strcmp(txt, PAUSE)) + { + if (!GetUInt16(act, PAUSE_MS, &vp->pause, true)) + return Parse_XmlError; + } + return Parse_Success; +} + +static ParseResult_t ParseRoutes(UcsXmlVal_t *v, PrivateData_t *vp) +{ + uint16_t routeAmount = 0; + struct UcsXmlRouteInfo *sourceRoute; + assert(NULL != v && NULL != vp); + //First: Count the amount of routes and allocate the correct amount + sourceRoute = vp->pRtLst; + while (NULL != sourceRoute) + { + if (!sourceRoute->isSource) //There can be more sinks than sources, so count them + { + ++routeAmount; + } + sourceRoute = sourceRoute->next; + } + if (0 == routeAmount) + return Parse_Success; //Its okay to have no routes at all (e.g. MEP traffic only) + v->pRoutes = MCalloc(&vp->objList, routeAmount, sizeof(Ucs_Rm_Route_t)); + if (NULL == v->pRoutes) return Parse_MemoryError; + + //Second: Fill allocated structure now + sourceRoute = vp->pRtLst; + while (NULL != sourceRoute) + { + if (sourceRoute->isSource) + { + struct UcsXmlRouteInfo *sinkRoute = vp->pRtLst; + while (NULL != sinkRoute) + { + if (sourceRoute != sinkRoute + && !sinkRoute->isSource + && (0 == strncmp(sourceRoute->routeName, sinkRoute->routeName, sizeof(sourceRoute->routeName)))) + { + Ucs_Rm_Route_t *route = &v->pRoutes[v->routesSize++]; + route->source_endpoint_ptr = sourceRoute->ep; + route->sink_endpoint_ptr = sinkRoute->ep; + route->active = 1; + } + sinkRoute = sinkRoute->next; + } + } + sourceRoute = sourceRoute->next; + } + return Parse_Success; +} diff --git a/ucs2-interface/ucs-xml/UcsXml.h b/ucs2-interface/ucs-xml/UcsXml.h new file mode 100644 index 0000000..883a9ff --- /dev/null +++ b/ucs2-interface/ucs-xml/UcsXml.h @@ -0,0 +1,94 @@ +/* + * Unicens XML Parser + * + * Copyright (C) 2017 Microchip Technology Germany II GmbH & Co. KG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * You may also obtain this software under a propriety license from Microchip. + * Please contact Microchip for further information. + * + */ +#ifndef UCSXML_H_ +#define UCSXML_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdbool.h> +#include <stdint.h> +#include "ucs_api.h" + +/** Structure holding informations to startup Unicens (UCS). + * Pass all these variables to the UCS manager structure, but not pInternal. + * */ +typedef struct +{ + /** The amount of bytes assigned to the async channel*/ + uint16_t packetBw; + /** Array of routes */ + Ucs_Rm_Route_t *pRoutes; + /** Route array size */ + uint16_t routesSize; + /** Array of nodes */ + Ucs_Rm_Node_t *pNod; + /** Node array size */ + uint16_t nodSize; + /** Internal data, to be ignored */ + void *pInternal; +} UcsXmlVal_t; + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ +/* Public API */ +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + +/** + * \brief Initializes Unicens XML parser module, parses the given string and + * generate the data needed to run Unicens (UCS) library. + * + * \note In case of errors the callback UcsXml_CB_OnError will be raised. + * \param xmlString - Zero terminated XML string. The string will not be used + * after this function call. + * \return Structure holding the needed data for UCS. NULL, if there was an error. + * The structure will be created dynamically, to free the data call UcsXml_FreeVal. + */ +UcsXmlVal_t *UcsXml_Parse(const char *xmlString); + +/** + * \brief Frees the given structure, generated by UcsXml_Parse. + * + * \note In case of errors the callback UcsXml_CB_OnError will be raised. + * \param val - The structure to be freed. + */ +void UcsXml_FreeVal(UcsXmlVal_t *val); + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ +/* CALLBACK SECTION */ +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + +/** + * \brief Callback whenever a parser error occurs. The message is human readable. + * \note This function must be implemented by the integrator. + * + * \param format - Zero terminated format string (following printf rules) + * \param vargsCnt - Amount of parameters stored in "..." + */ +extern void UcsXml_CB_OnError(const char format[], uint16_t vargsCnt, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* UCSXML_H_ */
\ No newline at end of file diff --git a/ucs2-interface/ucs_config.h b/ucs2-interface/ucs_config.h new file mode 100644 index 0000000..fdca515 --- /dev/null +++ b/ucs2-interface/ucs_config.h @@ -0,0 +1,145 @@ +/* + * Unicens Integration Helper Component + * + * Copyright (C) 2017 Microchip Technology Germany II GmbH & Co. KG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * You may also obtain this software under a propriety license from Microchip. + * Please contact Microchip for further information. + * + */ +#ifndef UNICENSINTEGRATION_H_ +#define UNICENSINTEGRATION_H_ + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ +/* USER ADJUSTABLE VALUES */ +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + +#define ENABLE_INIC_WATCHDOG (false) +#define ENABLE_AMS_LIB (true) +#define DEBUG_XRM +#define BOARD_PMS_TX_SIZE (72) +#define CMD_QUEUE_LEN (4) + +#include <string.h> +#include <stdarg.h> + +#include "ucs_cfg.h" +#include "ucs_api.h" + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ +/* PRIVATE SECTION */ +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + +/** + * \brief Internal enum for Unicens Integration + */ +typedef enum +{ + ///Result is OK and the processing is finished. Safe to dequeue this command. + UniCmdResult_OK_ProcessFinished, + ///Result is OK but the processing is ongoing. Must wait for callback. + UniCmdResult_OK_NeedToWaitForCB, + ///Result is error and the processing is finished. Safe to dequeue this command. + UniCmdResult_ERROR_ProcessFinished +} UnicensCmdResult_t; + +/** + * \brief Internal enum for Unicens Integration + */ +typedef enum +{ + UnicensCmd_Unknown, + UnicensCmd_Init, + UnicensCmd_Stop, + UnicensCmd_RmSetRoute, + UnicensCmd_NsRun +} UnicensCmd_t; + +/** + * \brief Internal struct for Unicens Integration + */ +typedef struct +{ + const Ucs_InitData_t *init_ptr; +} UnicensCmdInit_t; + +/** + * \brief Internal struct for Unicens Integration + */ +typedef struct +{ + Ucs_Rm_Route_t *routePtr; + bool isActive; +} UnicensCmdRmSetRoute_t; + +/** + * \brief Internal struct for Unicens Integration + */ +typedef struct +{ + Ucs_Rm_Node_t * node_ptr; +} UnicensCmdNsRun_t; + +/** + * \brief Internal struct for Unicens Integration + */ +typedef struct +{ + UnicensCmd_t cmd; + union + { + UnicensCmdInit_t Init; + UnicensCmdRmSetRoute_t RmSetRoute; + UnicensCmdNsRun_t NsRun; + } val; +} UnicensCmdEntry_t; + +/** + * \brief Internal variables for one instance of Unicens Integration + * \note Never touch any of this fields! + */ +typedef struct { + volatile uint8_t *dataQueue; + volatile uint8_t *pRx; + volatile uint8_t *pTx; + volatile uint32_t amountOfEntries; + volatile uint32_t sizeOfEntry; + volatile uint32_t rxPos; + volatile uint32_t txPos; +} RB_t; + +/** + * \brief Internal variables for one instance of Unicens Integration + * \note Allocate this structure for each instance (static or malloc) + * and pass it to UCSI_Init() + * \note Never touch any of this fields! + */ +typedef struct +{ + uint32_t magic; + void *tag; + bool initialized; + RB_t rb; + uint8_t rbBuf[(CMD_QUEUE_LEN * sizeof(UnicensCmdEntry_t))]; + Ucs_Inst_t *unicens; + Ucs_InitData_t uniInitData; + bool triggerService; + Ucs_Lld_Api_t *uniLld; + void *uniLldHPtr; + UnicensCmdEntry_t *currentCmd; +} UCSI_Data_t; + +#endif /* UNICENSINTEGRATION_H_ */
\ No newline at end of file diff --git a/ucs2-interface/ucs_interface.h b/ucs2-interface/ucs_interface.h new file mode 100644 index 0000000..39ecdf7 --- /dev/null +++ b/ucs2-interface/ucs_interface.h @@ -0,0 +1,197 @@ +/* + * Unicens Integration Helper Component + * + * Copyright (C) 2017 Microchip Technology Germany II GmbH & Co. KG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * You may also obtain this software under a propriety license from Microchip. + * Please contact Microchip for further information. + * + */ +#ifndef UCSI_H_ +#define UCSI_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ucs_config.h" +#include "ucs-xml/UcsXml.h" + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ +/* Public API */ +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + +// Fulup interface added to support ucs2vol +typedef const struct { + char* name; + int numid; +} UCSI_channelsT; + +typedef void (*UCSI_VolumeServiceCB_t)(uint16_t timeout); +UCSI_channelsT *UCSI_Vol_Init (UCSI_Data_t *pPriv, UCSI_VolumeServiceCB_t serviceCB); +uint8_t UCSI_Vol_Set (UCSI_Data_t *pPriv, int numId, uint8_t volume); +void UCSI_Vol_Service (UCSI_Data_t *pPriv); + + +/** + * \brief Initializes Unicens Integration module. + * \note Must be called before any other function of this component + * + * \param pPriv - External allocated memory area for this particular + * instance (static allocated or allocated with malloc) + * \param pTag - Pointer given by the integrator. This pointer will be + * returned by any callback function of this component + */ +void UCSI_Init(UCSI_Data_t *pPriv, void *pTag); + + +/** + * \brief Executes the given configuration. If already started, all + * existing local and remote INIC resources will be destroyed + * \note All given pointers must stay valid until this callback is + * raised: "UCSI_CB_OnStop" + * + * \param pPriv - private data section of this instance + * \param ucsConfig - UCS config handle + * \return true, configuration successfully enqueued, false otherwise + */ +bool UCSI_NewConfig(UCSI_Data_t *pPriv, UcsXmlVal_t *ucsConfig); + +/** + * \brief Offer the received control data from LLD to Unicens + * \note Call this function only from single context (not from ISR) + * \note This function can be called repeated until it return false + * + * \param pPriv - private data section of this instance + * \param pBuffer - Received bytes from MOST control channel + * \param len - Length of the received data array + * \return true, if the data could be enqueued for processing, remove + * the data from LLD queue in this case. + * false, data could not be processed due to lag of resources. + * In this case do not discard the data. Offer the same + * data again after UCSI_CB_OnServiceRequired was + * raised or any time later. + */ +bool UCSI_ProcessRxData(UCSI_Data_t *pPriv, const uint8_t *pBuffer, uint16_t len); + +/** + * \brief Gives Unicens Integration module time to do its job + * \note Call this function only from single context (not from ISR) + * + * \param pPriv - private data section of this instance + */ +void UCSI_Service(UCSI_Data_t *pPriv); + + +/** + * \brief Call after timer set by UCSI_CB_OnSetServiceTimer + * expired. + * \note Call this function only from single context (not from ISR) + * + * \param pPriv - private data section of this instance + */ +void UCSI_Timeout(UCSI_Data_t *pPriv); + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ +/* CALLBACK SECTION */ +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/ + +/** + * \brief Callback when ever a timestamp is needed + * \note This function must be implemented by the integrator + * \param pTag - Pointer given by the integrator by UCSI_Init + * \return timestamp in milliseconds + */ +extern uint16_t UCSI_CB_OnGetTime(void *pTag); + + +/** + * \brief Callback when the implementer needs to arm a timer. + * \note This function must be implemented by the integrator + * \note After timer expired, call the UCSI_Timeout from service + * Thread. (Not from callback!) + * \param pTag - Pointer given by the integrator by UCSI_Init + * \param timeout - milliseconds from now on to call back. (0=disable) + */ +extern void UCSI_CB_OnSetServiceTimer(void *pTag, uint16_t timeout); + + +/** + * \brief Callback when ever an Unicens forms a human readable message. + * This can be error events or when enabled also debug messages. + * \note This function must be implemented by the integrator + * \param pTag - Pointer given by the integrator by UCSI_Init + * \param format - Zero terminated format string (following printf rules) + * \param vargsCnt - Amount of parameters stored in "..." + */ +extern void UCSI_CB_OnUserMessage(void *pTag, const char format[], + uint16_t vargsCnt, ...); + + +/** + * \brief Callback when ever this instance needs to be serviced. + * \note Call UCSI_Service by your scheduler at the next run + * \note This function must be implemented by the integrator + * \param pTag - Pointer given by the integrator by UCSI_Init + */ +extern void UCSI_CB_OnServiceRequired(void *pTag); + + +/** + * \brief Callback when ever a MOST error message was received. + * \note This function must be implemented by the integrator + * \param pTag - Pointer given by the integrator by UCSI_Init + * \note All following parameters belong to the usual MOST message + */ +extern void UCSI_CB_OnMostError(void *pTag, uint16_t sourceAddr, + uint8_t fblock, uint8_t inst, uint16_t function, uint8_t op, + const uint8_t *pPayload, uint32_t payloadLen); + + +/** + * \brief Callback when ever this instance wants to send a message to INIC. + * \note This function must be implemented by the integrator + * \param pTag - Pointer given by the integrator by UCSI_Init + * \param pPayload - Byte array to be sent on the INIC control channel + * \param payloadLen - Length of pPayload in Byte + */ +extern void UCSI_CB_SendMostMessage(void *pTag, + const uint8_t *pPayload, uint32_t payloadLen); + +/** + * \brief Callback when Unicens instance has been stopped. + * \note This event can be used to free memory holding the resources + * passed with UCSI_NewConfig + * \note This function must be implemented by the integrator + * \param pTag - Pointer given by the integrator by UCSI_Init + */ +extern void UCSI_CB_OnStop(void *pTag); + +/** + * \brief Callback on Unicens management results. + * \note This function must be implemented by the integrator + * \param pTag - Pointer given by the integrator by UCSI_Init + * \param code - Result code + * \param nodeAddress - Node address of the device causing this event + * \param pNode - Pointer to node structure holding details of changed node + */ +extern void UCSI_CB_OnMgrReport(void *pTag, Ucs_MgrReport_t code, uint16_t nodeAddress, Ucs_Rm_Node_t *pNode); + +#ifdef __cplusplus +} +#endif + +#endif /* UCSI_H_ */
\ No newline at end of file diff --git a/ucs2-interface/ucs_lib_interf.c b/ucs2-interface/ucs_lib_interf.c new file mode 100644 index 0000000..842ba5a --- /dev/null +++ b/ucs2-interface/ucs_lib_interf.c @@ -0,0 +1,647 @@ +/* + * Unicens Integration Helper Component + * + * Copyright (C) 2017 Microchip Technology Germany II GmbH & Co. KG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * You may also obtain this software under a propriety license from Microchip. + * Please contact Microchip for further information. + * + */ +#include <assert.h> +#include "ucs_interface.h" + +/************************************************************************/ +/* Private Definitions and variables */ +/************************************************************************/ +#define MAGIC (0xA144BEAF) + +/************************************************************************/ +/* Private Function Prototypes */ +/************************************************************************/ +static bool EnqueueCommand(UCSI_Data_t *my, UnicensCmdEntry_t *cmd); +static void OnCommandExecuted(UCSI_Data_t *my, UnicensCmd_t cmd); +static void RB_Init(RB_t *rb, uint16_t amountOfEntries, uint32_t sizeOfEntry, uint8_t *workingBuffer); +static void *RB_GetReadPtr(RB_t *rb); +static void RB_PopReadPtr(RB_t *rb); +static void *RB_GetWritePtr(RB_t *rb); +static void RB_PopWritePtr(RB_t *rb); +static uint16_t OnUnicensGetTime(void *user_ptr); +static void OnUnicensService( void *user_ptr ); +static void OnUnicensError( Ucs_Error_t error_code, void *user_ptr ); +static void OnUnicensAppTimer( uint16_t timeout, void *user_ptr ); +static void OnUnicensDebugErrorMsg(Msg_MostTel_t *m, void *user_ptr); +static void OnLldCtrlStart( Ucs_Lld_Api_t* api_ptr, void *inst_ptr, void *lld_user_ptr ); +static void OnLldCtrlStop( void *lld_user_ptr ); +static void OnLldCtrlRxMsgAvailable( void *lld_user_ptr ); +static void OnLldCtrlTxTransmitC( Ucs_Lld_TxMsg_t *msg_ptr, void *lld_user_ptr ); +static void OnUnicensRoutingResult(Ucs_Rm_Route_t* route_ptr, Ucs_Rm_RouteInfos_t route_infos, void *user_ptr); +static void OnUnicensMostPortStatus(uint16_t most_port_handle, + Ucs_Most_PortAvail_t availability, Ucs_Most_PortAvailInfo_t avail_info, + uint16_t free_streaming_bw, void* user_ptr); +static void OnUnicensDebugXrmResources(Ucs_Xrm_ResourceType_t resource_type, + Ucs_Xrm_ResObject_t *resource_ptr, Ucs_Xrm_ResourceInfos_t resource_infos, + Ucs_Rm_EndPoint_t *endpoint_inst_ptr, void *user_ptr); +static void OnUcsInitResult(Ucs_InitResult_t result, void *user_ptr); +static void OnUcsStopResult(Ucs_StdResult_t result, void *user_ptr); +static void OnUcsMgrReport(Ucs_MgrReport_t code, uint16_t node_address, Ucs_Rm_Node_t *node_ptr, void *user_ptr); +static void OnUcsNsRun(Ucs_Rm_Node_t * node_ptr, Ucs_Ns_ResultCode_t result, void *ucs_user_ptr); + +/************************************************************************/ +/* Public Function Implementations */ +/************************************************************************/ +void UCSI_Init(UCSI_Data_t *my, void *pTag) +{ + Ucs_Return_t result; + assert(NULL != my); + memset(my, 0, sizeof(UCSI_Data_t)); + my->magic = MAGIC; + my->tag = pTag; + my->unicens = Ucs_CreateInstance(); + if (NULL == my->unicens) + { + UCSI_CB_OnUserMessage(my->tag, "Can not instance a new version of UNICENS, "\ + "increase UCS_NUM_INSTANCES define", 0); + assert(false); + return; + } + result = Ucs_SetDefaultConfig(&my->uniInitData); + if(UCS_RET_SUCCESS != result) + { + UCSI_CB_OnUserMessage(my->tag, "Can not set default values to Unicens config (result=0x%X)", 1, result); + assert(false); + return; + } + my->uniInitData.user_ptr = my; + my->uniInitData.mgr.report_fptr = OnUcsMgrReport; + + my->uniInitData.general.inic_watchdog_enabled = ENABLE_INIC_WATCHDOG; + my->uniInitData.general.get_tick_count_fptr = &OnUnicensGetTime; + my->uniInitData.general.request_service_fptr = &OnUnicensService; + my->uniInitData.general.error_fptr = &OnUnicensError; + my->uniInitData.general.set_application_timer_fptr = &OnUnicensAppTimer; + my->uniInitData.general.debug_error_msg_fptr = &OnUnicensDebugErrorMsg; + my->uniInitData.ams.enabled = ENABLE_AMS_LIB; + + my->uniInitData.lld.lld_user_ptr = my; + my->uniInitData.lld.start_fptr = &OnLldCtrlStart; + my->uniInitData.lld.stop_fptr = &OnLldCtrlStop; + my->uniInitData.lld.rx_available_fptr = &OnLldCtrlRxMsgAvailable; + my->uniInitData.lld.tx_transmit_fptr = &OnLldCtrlTxTransmitC; + + my->uniInitData.rm.report_fptr = &OnUnicensRoutingResult; + my->uniInitData.rm.xrm.most_port_status_fptr = &OnUnicensMostPortStatus; + my->uniInitData.rm.debug_resource_status_fptr = &OnUnicensDebugXrmResources; + + RB_Init(&my->rb, CMD_QUEUE_LEN, sizeof(UnicensCmdEntry_t), my->rbBuf); +} + +bool UCSI_NewConfig(UCSI_Data_t *my, UcsXmlVal_t *ucsConfig) { + + UnicensCmdEntry_t *e; + assert(MAGIC == my->magic); + if (my->initialized) + { + e = (UnicensCmdEntry_t *)RB_GetWritePtr(&my->rb); + if (NULL == e) return false; + e->cmd = UnicensCmd_Stop; + RB_PopWritePtr(&my->rb); + } + my->uniInitData.mgr.packet_bw = ucsConfig->packetBw; + my->uniInitData.mgr.routes_list_ptr = ucsConfig->pRoutes; + my->uniInitData.mgr.routes_list_size = ucsConfig->routesSize; + my->uniInitData.mgr.nodes_list_ptr = ucsConfig->pNod; + my->uniInitData.mgr.nodes_list_size = ucsConfig->nodSize; + my->uniInitData.mgr.enabled = true; + e = (UnicensCmdEntry_t *)RB_GetWritePtr(&my->rb); + if (NULL == e) return false; + e->cmd = UnicensCmd_Init; + e->val.Init.init_ptr = &my->uniInitData; + RB_PopWritePtr(&my->rb); + UCSI_CB_OnServiceRequired(my->tag); + return true; +} + +bool UCSI_ProcessRxData(UCSI_Data_t *my, const uint8_t *pBuffer, uint16_t len) +{ + assert(MAGIC == my->magic); + if (NULL == my->uniLld || NULL == my->uniLldHPtr) return false; + Ucs_Lld_RxMsg_t *msg = NULL; + msg = my->uniLld->rx_allocate_fptr(my->uniLldHPtr, len); + if (NULL == msg) + { + //This may happen by definition, OnLldCtrlRxMsgAvailable() + //will be called, once buffers are available again + return false; + } + msg->data_size = len; + memcpy(msg->data_ptr, pBuffer, len); + my->uniLld->rx_receive_fptr(my->uniLldHPtr, msg); + return true; +} + + +void UCSI_Service(UCSI_Data_t *my) { + UnicensCmdEntry_t *e; + bool popEntry = true; //Set to false in specific case, where function will callback asynchrony. + assert(MAGIC == my->magic); + if (NULL != my->unicens && my->triggerService) { + my->triggerService = false; + Ucs_Service(my->unicens); + } + if (NULL != my->currentCmd) return; + my->currentCmd = e = (UnicensCmdEntry_t *)RB_GetReadPtr(&my->rb); + if (NULL == e) return; + switch (e->cmd) { + case UnicensCmd_Init: + if (UCS_RET_SUCCESS == Ucs_Init(my->unicens, e->val.Init.init_ptr, OnUcsInitResult)) + popEntry = false; + else + UCSI_CB_OnUserMessage(my->tag, "Ucs_Init failed", 0); + break; + case UnicensCmd_Stop: + if (UCS_RET_SUCCESS == Ucs_Stop(my->unicens, OnUcsStopResult)) + popEntry = false; + else + UCSI_CB_OnUserMessage(my->tag, "Ucs_Stop failed", 0); + break; + case UnicensCmd_RmSetRoute: + if (UCS_RET_SUCCESS != Ucs_Rm_SetRouteActive(my->unicens, e->val.RmSetRoute.routePtr, e->val.RmSetRoute.isActive)) + UCSI_CB_OnUserMessage(my->tag, "Ucs_Rm_SetRouteActive failed", 0); + break; + case UnicensCmd_NsRun: + if (UCS_RET_SUCCESS != Ucs_Ns_Run(my->unicens, e->val.NsRun.node_ptr, OnUcsNsRun)) + UCSI_CB_OnUserMessage(my->tag, "Ucs_Ns_Run failed", 0); + break; + default: + assert(false); + break; + } + if (popEntry) + { + my->currentCmd = NULL; + RB_PopReadPtr(&my->rb); + } +} + +void UCSI_Timeout(UCSI_Data_t *my) +{ + assert(MAGIC == my->magic); + if (NULL == my->unicens) return; + Ucs_ReportTimeout(my->unicens); +} + +/************************************************************************/ +/* Private Functions */ +/************************************************************************/ +static bool EnqueueCommand(UCSI_Data_t *my, UnicensCmdEntry_t *cmd) +{ + UnicensCmdEntry_t *e; + if (NULL == my || NULL == cmd) + { + assert(false); + return false; + } + e = RB_GetWritePtr(&my->rb); + if (NULL == e) + { + UCSI_CB_OnUserMessage(my->tag, "Could not enqueue command. Increase CMD_QUEUE_LEN define", 0); + return false; + } + memcpy(e, cmd, sizeof(UnicensCmdEntry_t)); + RB_PopWritePtr(&my->rb); + UCSI_CB_OnServiceRequired(my->tag); + return true; +} + +static void OnCommandExecuted(UCSI_Data_t *my, UnicensCmd_t cmd) +{ + if (NULL == my) + { + assert(false); + return; + } + if (NULL == my->currentCmd) + { + UCSI_CB_OnUserMessage(my->tag, "OnUniCommandExecuted was called, but no "\ + "command is in queue", 0); + assert(false); + return; + } + if (my->currentCmd->cmd != cmd) + { + UCSI_CB_OnUserMessage(my->tag, "OnUniCommandExecuted was called with "\ + "wrong command (Expected=0x%X, Got=0x%X", 2, my->currentCmd->cmd, cmd); + assert(false); + return; + } + my->currentCmd = NULL; + RB_PopReadPtr(&my->rb); +} + +static void RB_Init(RB_t *rb, uint16_t amountOfEntries, uint32_t sizeOfEntry, uint8_t *workingBuffer) +{ + assert(NULL != rb); + assert(NULL != workingBuffer); + rb->dataQueue = workingBuffer; + rb->pRx = rb->dataQueue; + rb->pTx = rb->dataQueue; + rb->amountOfEntries = amountOfEntries; + rb->sizeOfEntry = sizeOfEntry; + rb->rxPos = 0; + rb->txPos = 0; +} + +static void *RB_GetReadPtr(RB_t *rb) +{ + assert(NULL != rb); + assert(0 != rb->dataQueue); + if (rb->txPos - rb->rxPos > 0) + return (void *)rb->pRx; + return NULL; +} + +static void RB_PopReadPtr(RB_t *rb) +{ + assert(NULL != rb); + assert(0 != rb->dataQueue); + + rb->pRx += rb->sizeOfEntry; + if (rb->pRx >= rb->dataQueue + ( rb->amountOfEntries * rb->sizeOfEntry)) + rb->pRx = rb->dataQueue; + ++rb->rxPos; + assert(rb->txPos >= rb->rxPos); +} + +static void *RB_GetWritePtr(RB_t *rb) +{ + assert(NULL != rb); + assert(0 != rb->dataQueue); + if (rb->txPos - rb->rxPos < rb->amountOfEntries) + return (void *)rb->pTx; + return NULL; +} + +static void RB_PopWritePtr(RB_t *rb) +{ + assert(NULL != rb); + assert(0 != rb->dataQueue); + rb->pTx += rb->sizeOfEntry; + if (rb->pTx >= rb->dataQueue + ( rb->amountOfEntries * rb->sizeOfEntry)) + rb->pTx = rb->dataQueue; + ++rb->txPos; + assert(rb->txPos >= rb->rxPos); +} + +static uint16_t OnUnicensGetTime(void *user_ptr) +{ + UCSI_Data_t *my = (UCSI_Data_t *)user_ptr; + assert(MAGIC == my->magic); + return UCSI_CB_OnGetTime(my->tag); +} + +static void OnUnicensService( void *user_ptr ) +{ + UCSI_Data_t *my = (UCSI_Data_t *)user_ptr; + assert(MAGIC == my->magic); + my->triggerService = true; + UCSI_CB_OnServiceRequired(my->tag); +} + +static void OnUnicensError( Ucs_Error_t error_code, void *user_ptr ) +{ + error_code = error_code; + UCSI_Data_t *my = (UCSI_Data_t *)user_ptr; + assert(MAGIC == my->magic); + UCSI_CB_OnUserMessage(my->tag, "Unicens general error, code=0x%X", 1, error_code); +} + +static void OnUnicensAppTimer( uint16_t timeout, void *user_ptr ) +{ + UCSI_Data_t *my = (UCSI_Data_t *)user_ptr; + assert(MAGIC == my->magic); + UCSI_CB_OnSetServiceTimer(my->tag, timeout); +} + +static void OnUnicensDebugErrorMsg(Msg_MostTel_t *m, void *user_ptr) +{ + UCSI_Data_t *my = (UCSI_Data_t *)user_ptr; + assert(MAGIC == my->magic); + UCSI_CB_OnMostError(my->tag, m->source_addr, m->id.fblock_id, m->id.instance_id, + m->id.function_id, m->id.op_type, m->tel.tel_data_ptr, m->tel.tel_len); +} + +static void OnLldCtrlStart( Ucs_Lld_Api_t* api_ptr, void *inst_ptr, void *lld_user_ptr ) +{ + UCSI_Data_t *my = (UCSI_Data_t *)lld_user_ptr; + assert(MAGIC == my->magic); + my->uniLld = api_ptr; + my->uniLldHPtr = inst_ptr; +} + +static void OnLldCtrlStop( void *lld_user_ptr ) +{ + UCSI_Data_t *my = (UCSI_Data_t *)lld_user_ptr; + assert(MAGIC == my->magic); + my->uniLld = NULL; + my->uniLldHPtr = NULL; +} + +static void OnLldCtrlRxMsgAvailable( void *lld_user_ptr ) +{ + UCSI_Data_t *my = (UCSI_Data_t *)lld_user_ptr; + assert(MAGIC == my->magic); + UCSI_CB_OnServiceRequired(my->tag); +} + +static void OnLldCtrlTxTransmitC( Ucs_Lld_TxMsg_t *msg_ptr, void *lld_user_ptr ) +{ + UCSI_Data_t *my = (UCSI_Data_t *)lld_user_ptr; + assert(MAGIC == my->magic); + uint8_t buffer[BOARD_PMS_TX_SIZE]; + uint32_t bufferPos = 0; + Ucs_Mem_Buffer_t * buf_ptr; + if (NULL == msg_ptr || NULL == my || NULL == my->uniLld || NULL == my->uniLldHPtr) + { + assert(false); + return; + } + for (buf_ptr = msg_ptr->memory_ptr; buf_ptr != NULL; buf_ptr = buf_ptr->next_buffer_ptr) + { + if (buf_ptr->data_size + bufferPos > sizeof(buffer)) + { + UCSI_CB_OnUserMessage(my->tag, "TX buffer is too small, increase " \ + "BOARD_PMS_TX_SIZE define (%lu > %lu)", 2, buf_ptr->data_size + bufferPos, sizeof(buffer)); + my->uniLld->tx_release_fptr(my->uniLldHPtr, msg_ptr); + return; + } + memcpy(&buffer[bufferPos], buf_ptr->data_ptr, buf_ptr->data_size); + bufferPos += buf_ptr->data_size; + } + assert(bufferPos == msg_ptr->memory_ptr->total_size); + my->uniLld->tx_release_fptr(my->uniLldHPtr, msg_ptr); + UCSI_CB_SendMostMessage(my->tag, buffer, bufferPos); +} + +static void OnUnicensRoutingResult(Ucs_Rm_Route_t* route_ptr, Ucs_Rm_RouteInfos_t route_infos, void *user_ptr) +{ + //TODO: implement + route_ptr = route_ptr; + route_infos = route_infos; + user_ptr = user_ptr; +} + +static void OnUnicensMostPortStatus(uint16_t most_port_handle, + Ucs_Most_PortAvail_t availability, Ucs_Most_PortAvailInfo_t avail_info, + uint16_t free_streaming_bw, void* user_ptr) +{ + //TODO: implement + most_port_handle = most_port_handle; + availability = availability; + avail_info = avail_info; + free_streaming_bw = free_streaming_bw; + user_ptr = user_ptr; +} + +static void OnUnicensDebugXrmResources(Ucs_Xrm_ResourceType_t resource_type, + Ucs_Xrm_ResObject_t *resource_ptr, Ucs_Xrm_ResourceInfos_t resource_infos, + Ucs_Rm_EndPoint_t *endpoint_inst_ptr, void *user_ptr) +{ +#ifndef DEBUG_XRM + resource_type = resource_type; + resource_ptr = resource_ptr; + resource_infos = resource_infos; + endpoint_inst_ptr = endpoint_inst_ptr; + user_ptr = user_ptr; +#else + endpoint_inst_ptr = endpoint_inst_ptr; + UCSI_Data_t *my = (UCSI_Data_t *)user_ptr; + assert(MAGIC == my->magic); + if (NULL == resource_ptr) return; + char *msg = NULL; + uint16_t adr = 0xFFFF; + if (endpoint_inst_ptr && endpoint_inst_ptr->node_obj_ptr && + endpoint_inst_ptr->node_obj_ptr->signature_ptr) + adr = endpoint_inst_ptr->node_obj_ptr->signature_ptr->node_address; + switch (resource_infos) + { + case UCS_XRM_INFOS_BUILT: + msg = (char *)"has been built"; + break; + case UCS_XRM_INFOS_DESTROYED: + msg = (char *)"has been destroyed"; + break; + case UCS_XRM_INFOS_ERR_BUILT: + msg = (char *)"cannot be built"; + break; + default: + msg = (char *)"cannot be destroyed"; + break; + } + switch(resource_type) + { + case UCS_XRM_RC_TYPE_MOST_SOCKET: + { + Ucs_Xrm_MostSocket_t *ms = (Ucs_Xrm_MostSocket_t *)resource_ptr; + assert(ms->resource_type == resource_type); + UCSI_CB_OnUserMessage(my->tag, "Xrm-Debug (0x%03X): MOST socket %s, handle=%04X, "\ + "direction=%d, type=%d, bandwidth=%d", 6, adr, msg, ms->most_port_handle, + ms->direction, ms->data_type, ms->bandwidth); + break; + } + case UCS_XRM_RC_TYPE_MLB_PORT: + { + Ucs_Xrm_MlbPort_t *m = (Ucs_Xrm_MlbPort_t *)resource_ptr; + assert(m->resource_type == resource_type); + UCSI_CB_OnUserMessage(my->tag, "Xrm-Debug (0x%03X): MLB port %s, index=%d, clock=%d", 4, + adr, msg, m->index, m->clock_config); + break; + } + case UCS_XRM_RC_TYPE_MLB_SOCKET: + { + Ucs_Xrm_MlbSocket_t *m = (Ucs_Xrm_MlbSocket_t *)resource_ptr; + assert(m->resource_type == resource_type); + UCSI_CB_OnUserMessage(my->tag, "Xrm-Debug (0x%03X): MLB socket %s, direction=%d, type=%d,"\ + " bandwidth=%d, channel=%d", 6, adr, msg, m->direction, m->data_type, + m->bandwidth, m->channel_address); + break; + } + case UCS_XRM_RC_TYPE_USB_PORT: + { + Ucs_Xrm_UsbPort_t *m = (Ucs_Xrm_UsbPort_t *)resource_ptr; + assert(m->resource_type == resource_type); + UCSI_CB_OnUserMessage(my->tag, "Xrm-Debug (0x%03X): USB port %s, in-cnt=%d, out-cnt=%d", 4, + adr, msg, m->streaming_if_ep_in_count, m->streaming_if_ep_out_count); + break; + } + case UCS_XRM_RC_TYPE_USB_SOCKET: + { + Ucs_Xrm_UsbSocket_t *m = (Ucs_Xrm_UsbSocket_t *)resource_ptr; + assert(m->resource_type == resource_type); + UCSI_CB_OnUserMessage(my->tag, "Xrm-Debug (0x%03X): USB socket %s, direction=%d, type=%d," \ + " ep-addr=%02X, frames=%d", 6, adr, msg, m->direction, m->data_type, + m->end_point_addr, m->frames_per_transfer); + break; + } + case UCS_XRM_RC_TYPE_STRM_PORT: + { + Ucs_Xrm_StrmPort_t *m = (Ucs_Xrm_StrmPort_t *)resource_ptr; + assert(m->resource_type == resource_type); + UCSI_CB_OnUserMessage(my->tag, "Xrm-Debug (0x%03X): I2S port %s, index=%d, clock=%d, "\ + "align=%d", 5, adr, msg, m->index, m->clock_config, m->data_alignment); + break; + } + case UCS_XRM_RC_TYPE_STRM_SOCKET: + { + Ucs_Xrm_StrmSocket_t *m = (Ucs_Xrm_StrmSocket_t *)resource_ptr; + assert(m->resource_type == resource_type); + UCSI_CB_OnUserMessage(my->tag, "Xrm-Debug (0x%03X): I2S socket %s, direction=%d, type=%d"\ + ", bandwidth=%d, pin=%d", 6, adr, msg, m->direction, m->data_type, + m->bandwidth, m->stream_pin_id); + break; + } + case UCS_XRM_RC_TYPE_SYNC_CON: + { + Ucs_Xrm_SyncCon_t *m = (Ucs_Xrm_SyncCon_t *)resource_ptr; + assert(m->resource_type == resource_type); + UCSI_CB_OnUserMessage(my->tag, "Xrm-Debug (0x%03X): Sync connection %s, mute=%d, "\ + "offset=%d", 4, adr, msg, m->mute_mode, m->offset); + break; + } + case UCS_XRM_RC_TYPE_COMBINER: + { + Ucs_Xrm_Combiner_t *m = (Ucs_Xrm_Combiner_t *)resource_ptr; + assert(m->resource_type == resource_type); + UCSI_CB_OnUserMessage(my->tag, "Xrm-Debug (0x%03X): Combiner %s, bytes per frame=%d", + 3, adr, msg, m->bytes_per_frame); + break; + } + case UCS_XRM_RC_TYPE_SPLITTER: + { + Ucs_Xrm_Splitter_t *m = (Ucs_Xrm_Splitter_t *)resource_ptr; + assert(m->resource_type == resource_type); + UCSI_CB_OnUserMessage(my->tag, "Xrm-Debug (0x%03X): Splitter %s, bytes per frame=%d", + 3, adr, msg, m->bytes_per_frame); + break; + } + case UCS_XRM_RC_TYPE_AVP_CON: + { + Ucs_Xrm_AvpCon_t *m = (Ucs_Xrm_AvpCon_t *)resource_ptr; + assert(m->resource_type == resource_type); + UCSI_CB_OnUserMessage(my->tag, "Xrm-Debug (0x%03X): Isoc-AVP connection %s, packetSize=%d", + 3, adr, msg, m->isoc_packet_size); + break; + } + default: + UCSI_CB_OnUserMessage(my->tag, "Xrm-Debug (0x%03X): Unknown type=%d %s", 3 , adr, resource_type, msg); + } +#endif +} + +static void OnUcsInitResult(Ucs_InitResult_t result, void *user_ptr) +{ + UnicensCmdEntry_t e; + UCSI_Data_t *my = (UCSI_Data_t *)user_ptr; + assert(MAGIC == my->magic); + my->initialized = (UCS_INIT_RES_SUCCESS == result); + OnCommandExecuted(my, UnicensCmd_Init); + if (!my->initialized) + { + UCSI_CB_OnUserMessage(my->tag, "UcsInitResult reported error (0x%X), restarting...", 1, result); + e.cmd = UnicensCmd_Init; + e.val.Init.init_ptr = &my->uniInitData; + EnqueueCommand(my, &e); + } +} + +static void OnUcsStopResult(Ucs_StdResult_t result, void *user_ptr) +{ + result = result; //TODO: check error case + UCSI_Data_t *my = (UCSI_Data_t *)user_ptr; + assert(MAGIC == my->magic); + my->initialized = false; + OnCommandExecuted(my, UnicensCmd_Stop); + UCSI_CB_OnStop(my->tag); +} + +static void OnUcsMgrReport(Ucs_MgrReport_t code, uint16_t node_address, Ucs_Rm_Node_t *node_ptr, void *user_ptr) +{ + UCSI_Data_t *my = (UCSI_Data_t *)user_ptr; + assert(MAGIC == my->magic); + if (node_ptr && node_ptr->script_list_ptr && node_ptr->script_list_size) + { + UnicensCmdEntry_t e; + e.cmd = UnicensCmd_NsRun; + e.val.NsRun.node_ptr = node_ptr; + EnqueueCommand(my, &e); + } + UCSI_CB_OnMgrReport(my->tag, code, node_address, node_ptr); +} + +static void OnUcsNsRun(Ucs_Rm_Node_t * node_ptr, Ucs_Ns_ResultCode_t result, void *ucs_user_ptr) +{ +#ifndef DEBUG_XRM + node_ptr = node_ptr; + result = result; + ucs_user_ptr; +#else + UCSI_Data_t *my = (UCSI_Data_t *)ucs_user_ptr; + assert(MAGIC == my->magic); + UCSI_CB_OnUserMessage(my->tag, "OnUcsNsRun (%03X): script executed %s", + 2, node_ptr->signature_ptr->node_address, + (UCS_NS_RES_SUCCESS == result ? "succeeded" : "false")); +#endif +} + +/*---------------------------------------- + * Debug Message output from Unicens stack: + *---------------------------------------- + */ +#if defined(UCS_TR_ERROR) || defined(UCS_TR_INFO) +#include <stdio.h> +#define TRACE_BUFFER_SZ 200 +void App_TraceError(void *ucs_user_ptr, const char module_str[], const char entry_str[], uint16_t vargs_cnt, ...) +{ + void *tag; + UCSI_Data_t *my = (UCSI_Data_t *)ucs_user_ptr; + if (my) + { + assert(MAGIC == my->magic); + tag = my->tag; + } + char outbuf[TRACE_BUFFER_SZ]; + va_list argptr; + va_start(argptr, vargs_cnt); + vsprintf(outbuf, entry_str, argptr); + va_end(argptr); + UCSI_CB_OnUserMessage(tag, "Error | %s | %s", 2, module_str, outbuf); +} +void App_TraceInfo(void *ucs_user_ptr, const char module_str[], const char entry_str[], uint16_t vargs_cnt, ...) +{ + void *tag; + UCSI_Data_t *my = (UCSI_Data_t *)ucs_user_ptr; + if (my) + { + assert(MAGIC == my->magic); + tag = my->tag; + } + char outbuf[TRACE_BUFFER_SZ]; + va_list argptr; + va_start(argptr, vargs_cnt); + vsprintf(outbuf, entry_str, argptr); + va_end(argptr); + UCSI_CB_OnUserMessage(tag, "Info | %s | %s", 2, module_str, outbuf); +} +#endif
\ No newline at end of file diff --git a/ucs2-interface/ucs_vol_interf.c b/ucs2-interface/ucs_vol_interf.c new file mode 100644 index 0000000..fc2952e --- /dev/null +++ b/ucs2-interface/ucs_vol_interf.c @@ -0,0 +1,59 @@ +/* + * Unicens Integration Helper Component + * + * Copyright (C) 2017 Microchip Technology Germany II GmbH & Co. KG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * You may also obtain this software under a propriety license from Microchip. + * Please contact Microchip for further information. + * + */ +#include <assert.h> +#include "ucs_interface.h" +#include "libmostvolume.h" + + + +static UCSI_channelsT ucsiChannels[] = { + {.name= "FRONT_LEFT" , .numid= (int)LIB_MOST_VOLUME_CH_FRONT_LEFT}, + {.name= "FRONT_RIGHT", .numid= (int)LIB_MOST_VOLUME_CH_FRONT_RIGHT}, + {.name= "REAR_LEFT" , .numid= (int)LIB_MOST_VOLUME_CH_REAR_LEFT}, + {.name= "REAR_LEFT" , .numid= (int)LIB_MOST_VOLUME_CH_REAR_RIGHT}, + {.name= "CENTER" , .numid= (int)LIB_MOST_VOLUME_CH_CENTER}, + {.name= "SUB" , .numid= (int)LIB_MOST_VOLUME_CH_SUB}, + {.name= "MASTER" , .numid= (int)LIB_MOST_VOLUME_MASTER}, + + {.name= NULL} +}; + +// Small wrapper as UCSI and UCSVOL do not use the same handle +void UCSI_Vol_Service (UCSI_Data_t *pPriv) { + (void)lib_most_volume_service(); + +} + +UCSI_channelsT *UCSI_Vol_Init (UCSI_Data_t *pPriv, UCSI_VolumeServiceCB_t serviceCB) { + int err; + err = lib_most_volume_init(pPriv->unicens, (lib_most_volume_service_cb_t) serviceCB); + if (err) return (NULL); + else return (ucsiChannels); +} + +uint8_t UCSI_Vol_Set(UCSI_Data_t *pPriv, int numid, uint8_t volume) { + + return (lib_most_volume_set((enum lib_most_volume_channel_t)numid, volume)); +} + + |