Implement handling of GPIO, I2C, Routes
authorThorsten Kummermehr <thorsten.kummermehr@k2l.de>
Wed, 26 Jul 2017 14:54:13 +0000 (16:54 +0200)
committerThorsten Kummermehr <thorsten.kummermehr@k2l.de>
Wed, 26 Jul 2017 14:54:13 +0000 (16:54 +0200)
ucs2-afb/ucs_binding.c
ucs2-interface/ucs-xml/UcsXml.c
ucs2-interface/ucs_config.h
ucs2-interface/ucs_interface.h
ucs2-interface/ucs_lib_interf.c

index fc8d613..59e1532 100644 (file)
@@ -185,6 +185,14 @@ void UCSI_CB_OnAmsMessageReceived(void *pTag)
           Don't forget to call UCSI_ReleaseAmsMessage after that */
 }
 
+void UCSI_CB_OnRouteResult(void *pTag, uint16_t routeId, bool isActive)
+{
+}
+
+void UCSI_CB_OnGpioStateChange(void *pTag, uint16_t nodeAddress, uint8_t gpioPinId, bool isHighState)
+{
+}
+
 bool Cdev_Init(CdevData_t *d, const char *fileName, bool read, bool write)
 {
     if (NULL == d || NULL == fileName)  goto OnErrorExit;
index efce887..8837356 100644 (file)
@@ -1158,12 +1158,11 @@ static ParseResult_t ParseScriptMsgSend(mxml_node_t *act, Ucs_Ns_Script_t *scr,
     if (!GetUInt8(act, OP_TYPE_REQUEST, &req->OpCode, true))\r
         RETURN_ASSERT(Parse_XmlError);\r
 \r
-    if (!GetUInt8(act, OP_TYPE_RESPONSE, &res->OpCode, true))\r
-        RETURN_ASSERT(Parse_XmlError);\r
-\r
     res->FBlockId = req->FBlockId;\r
     res->FunktId = req->FunktId;\r
-    GetPayload(act, PAYLOAD_RES_HEX, &res->DataPtr, &res->DataLen, 0, &priv->objList, false);\r
+\r
+    if (GetUInt8(act, OP_TYPE_RESPONSE, &res->OpCode, false))\r
+        GetPayload(act, PAYLOAD_RES_HEX, &res->DataPtr, &res->DataLen, 0, &priv->objList, false);\r
 \r
     if (!GetPayload(act, PAYLOAD_REQ_HEX, &req->DataPtr, &req->DataLen, 0, &priv->objList, true))\r
         RETURN_ASSERT(Parse_XmlError);\r
index 74c82c6..16210af 100644 (file)
@@ -39,6 +39,7 @@
 #define DEBUG_XRM
 #define BOARD_PMS_TX_SIZE       (72)
 #define CMD_QUEUE_LEN           (6)
+#define I2C_WRITE_MAX_LEN       (32)
 
 #include <string.h>
 #include <stdarg.h>
@@ -72,7 +73,10 @@ typedef enum
     UnicensCmd_Init,
     UnicensCmd_Stop,
     UnicensCmd_RmSetRoute,
-    UnicensCmd_NsRun
+    UnicensCmd_NsRun,
+    UnicensCmd_GpioCreatePort,
+    UnicensCmd_GpioWritePort,
+    UnicensCmd_I2CWrite
 } UnicensCmd_t;
 
 /**
@@ -100,6 +104,39 @@ typedef struct
     Ucs_Rm_Node_t * node_ptr;
 } UnicensCmdNsRun_t;
 
+/**
+ * \brief Internal struct for Unicens Integration
+ */
+typedef struct
+{
+    uint16_t destination;
+    uint16_t debounceTime;
+} UnicensCmdGpioCreatePort_t;
+
+/**
+ * \brief Internal struct for Unicens Integration
+ */
+typedef struct
+{
+    uint16_t destination;
+    uint16_t mask;
+    uint16_t data;
+} UnicensCmdGpioWritePort_t;
+
+/**
+ * \brief Internal struct for Unicens Integration
+ */
+typedef struct
+{
+    uint16_t destination;
+    bool isBurst;
+    uint8_t blockCount;
+    uint8_t slaveAddr;
+    uint16_t timeout;
+    uint8_t dataLen;
+    uint8_t data[I2C_WRITE_MAX_LEN];
+} UnicensCmdI2CWrite_t;
+
 /**
  * \brief Internal struct for Unicens Integration
  */
@@ -111,6 +148,9 @@ typedef struct
         UnicensCmdInit_t Init;
         UnicensCmdRmSetRoute_t RmSetRoute;
         UnicensCmdNsRun_t NsRun;
+        UnicensCmdGpioCreatePort_t GpioCreatePort;
+        UnicensCmdGpioWritePort_t GpioWritePort;
+        UnicensCmdI2CWrite_t I2CWrite;
     } val;
 } UnicensCmdEntry_t;
 
index b7dda35..c18d440 100644 (file)
@@ -160,13 +160,44 @@ void UCSI_ReleaseAmsMessage(UCSI_Data_t *my);
  * \note Call this function only from single context (not from ISR)
  *
  * \param pPriv - private data section of this instance
- * \param routeId - identifier as given in XML file along with MOST socket
+ * \param routeId - identifier as given in XML file along with MOST socket (unique)
  * \param isActive - true, route will become active. false, route will be deallocated
  * 
  * \return true, if route was found and the specific command was enqueued to Unicens.
  */
 bool UCSI_SetRouteActive(UCSI_Data_t *pPriv, uint16_t routeId, bool isActive);
 
+/**
+ * \brief Enables or disables a route by the given routeId
+ * \note Call this function only from single context (not from ISR)
+ *
+ * \param pPriv - private data section of this instance
+ * \param targetAddress - targetAddress - The node / group target address
+ * \param isBurst - true, write blockCount I2C telegrams dataLen with a single call. false, write a single I2C message.
+ * \param blockCount - amount of blocks to write. Only used when isBurst is set to true.
+ * \param slaveAddr - The I2C address.
+ * \param timeout - Timeout in milliseconds.
+ * \param dataLen - Amount of bytes to send via I2C
+ * \param pData - The payload to be send.
+ *
+ * \return true, if route command was enqueued to Unicens.
+ */
+bool UCSI_I2CWrite(UCSI_Data_t *pPriv, uint16_t targetAddress, bool isBurst, uint8_t blockCount,
+    uint8_t slaveAddr, uint16_t timeout, uint8_t dataLen, uint8_t *pData);
+
+/**
+ * \brief Enables or disables a route by the given routeId
+ * \note Call this function only from single context (not from ISR)
+ *
+ * \param pPriv - private data section of this instance
+ * \param targetAddress - targetAddress - The node / group target address
+ * \param gpioPinId - INIC GPIO PIN starting with 0 for the first GPIO.
+ * \param isHighState - true, high state = 3,3V. false, low state = 0V.
+ *
+ * \return true, if GPIO command was enqueued to Unicens.
+ */
+bool UCSI_SetGpioState(UCSI_Data_t *pPriv, uint16_t targetAddress, uint8_t gpioPinId, bool isHighState);
+
 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
 /*                        CALLBACK SECTION                              */
 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
@@ -239,6 +270,25 @@ extern void UCSI_CB_OnStop(void *pTag);
  */
 extern void UCSI_CB_OnAmsMessageReceived(void *pTag);
 
+/**
+ * \brief Callback when a route become active / inactive.
+ * \note This function must be implemented by the integrator
+ * \param pTag - Pointer given by the integrator by UCSI_Init
+ * \param routeId - identifier as given in XML file along with MOST socket (unique)
+ * \param isActive - true, if the route is now in use. false, the route is not established.
+ */
+extern void UCSI_CB_OnRouteResult(void *pTag, uint16_t routeId, bool isActive);
+
+/**
+ * \brief Callback when a INIC GPIO changes its state
+ * \note This function must be implemented by the integrator
+ * \param pTag - Pointer given by the integrator by UCSI_Init
+ * \param nodeAddress - Node Address of the INIC sending the update.
+ * \param gpioPinId - INIC GPIO PIN starting with 0 for the first GPIO.
+ * \param isHighState - true, high state = 3,3V. false, low state = 0V.
+ */
+extern void UCSI_CB_OnGpioStateChange(void *pTag, uint16_t nodeAddress, uint8_t gpioPinId, bool isHighState);
+
 #ifdef __cplusplus
 }
 #endif
index 5a6c08b..3eda07f 100644 (file)
@@ -64,9 +64,15 @@ static void OnUnicensDebugXrmResources(Ucs_Xrm_ResourceType_t resource_type,
     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 OnUcsGpioPortCreate(uint16_t node_address, uint16_t gpio_port_handle, Ucs_Gpio_Result_t result, void *user_ptr);
+static void OnUcsGpioPortWrite(uint16_t node_address, uint16_t gpio_port_handle, uint16_t current_state, uint16_t sticky_state, Ucs_Gpio_Result_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);
 static void OnUcsAmsRxMsgReceived(void *user_ptr);
+static void OnUcsGpioTriggerEventStatus(uint16_t node_address, uint16_t gpio_port_handle,
+    uint16_t rising_edges, uint16_t falling_edges, uint16_t levels, void * user_ptr);
+static void OnUcsI2CWrite(uint16_t node_address, uint16_t i2c_port_handle,
+    uint8_t i2c_slave_address, uint8_t data_len, Ucs_I2c_Result_t result, void *user_ptr);
 
 /************************************************************************/
 /* Public Function Implementations                                      */
@@ -116,6 +122,8 @@ void UCSI_Init(UCSI_Data_t *my, void *pTag)
     my->uniInitData.rm.xrm.most_port_status_fptr = &OnUnicensMostPortStatus;
     my->uniInitData.rm.debug_resource_status_fptr = &OnUnicensDebugXrmResources;
 
+    my->uniInitData.gpio.trigger_event_status_fptr = &OnUcsGpioTriggerEventStatus;
+
     RB_Init(&my->rb, CMD_QUEUE_LEN, sizeof(UnicensCmdEntry_t), my->rbBuf);
 }
 
@@ -197,6 +205,26 @@ void UCSI_Service(UCSI_Data_t *my)
             if (UCS_RET_SUCCESS != Ucs_Ns_Run(my->unicens, e->val.NsRun.node_ptr, OnUcsNsRun))
                 UCSI_CB_OnUserMessage(my->tag, true, "Ucs_Ns_Run failed", 0);
             break;
+        case UnicensCmd_GpioCreatePort:
+            if (UCS_RET_SUCCESS == Ucs_Gpio_CreatePort(my->unicens, e->val.GpioCreatePort.destination, 0, e->val.GpioCreatePort.debounceTime, OnUcsGpioPortCreate))
+                popEntry = false;
+            else
+                UCSI_CB_OnUserMessage(my->tag, true, "Ucs_Gpio_CreatePort failed", 0);
+            break;
+        case UnicensCmd_GpioWritePort:
+            if (UCS_RET_SUCCESS == Ucs_Gpio_WritePort(my->unicens, e->val.GpioWritePort.destination, 0x1D00, e->val.GpioWritePort.mask, e->val.GpioWritePort.data, OnUcsGpioPortWrite))
+                popEntry = false;
+            else
+                UCSI_CB_OnUserMessage(my->tag, true, "UnicensCmd_GpioWritePort failed", 0);
+            break;
+        case UnicensCmd_I2CWrite:
+            if (UCS_RET_SUCCESS == Ucs_I2c_WritePort(my->unicens, e->val.I2CWrite.destination, 0x0F00, 
+                (e->val.I2CWrite.isBurst ? UCS_I2C_BURST_MODE : UCS_I2C_DEFAULT_MODE), e->val.I2CWrite.blockCount,
+                e->val.I2CWrite.slaveAddr, e->val.I2CWrite.timeout, e->val.I2CWrite.dataLen, e->val.I2CWrite.data, OnUcsI2CWrite))
+                popEntry = false;
+            else
+                UCSI_CB_OnUserMessage(my->tag, true, "Ucs_Gpio_CreatePort failed", 0);
+            break;
         default:
             assert(false);
             break;
@@ -279,6 +307,38 @@ bool UCSI_SetRouteActive(UCSI_Data_t *my, uint16_t routeId, bool isActive)
     return false;
 }
 
+bool UCSI_I2CWrite(UCSI_Data_t *my, uint16_t targetAddress, bool isBurst, uint8_t blockCount,
+    uint8_t slaveAddr, uint16_t timeout, uint8_t dataLen, uint8_t *pData)
+{
+    UnicensCmdEntry_t entry;
+    assert(MAGIC == my->magic);
+    if (NULL == my || NULL == pData || 0 == dataLen) return false;
+    if (dataLen > I2C_WRITE_MAX_LEN) return false;
+    entry.cmd = UnicensCmd_I2CWrite;
+    entry.val.I2CWrite.destination = targetAddress;
+    entry.val.I2CWrite.isBurst = isBurst;
+    entry.val.I2CWrite.blockCount = blockCount;
+    entry.val.I2CWrite.slaveAddr = slaveAddr;
+    entry.val.I2CWrite.timeout = timeout;
+    entry.val.I2CWrite.dataLen = dataLen;
+    memcpy(entry.val.I2CWrite.data, pData, dataLen);
+    return EnqueueCommand(my, &entry);
+}
+
+bool UCSI_SetGpioState(UCSI_Data_t *my, uint16_t targetAddress, uint8_t gpioPinId, bool isHighState)
+{
+    uint16_t mask;
+    UnicensCmdEntry_t entry;
+    assert(MAGIC == my->magic);
+    if (NULL == my) return false;
+    mask = 1 << gpioPinId;
+    entry.cmd = UnicensCmd_GpioWritePort;
+    entry.val.GpioWritePort.destination = targetAddress;
+    entry.val.GpioWritePort.mask = mask;
+    entry.val.GpioWritePort.data = isHighState ? mask : 0;
+    return EnqueueCommand(my, &entry);
+}
+
 /************************************************************************/
 /* Private Functions                                                    */
 /************************************************************************/
@@ -488,10 +548,9 @@ 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)
 {
-    /*TODO: implement*/
-    route_ptr = route_ptr;
-    route_infos = route_infos;
-    user_ptr = user_ptr;
+    UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
+    assert(MAGIC == my->magic);
+    UCSI_CB_OnRouteResult(my->tag, route_ptr->route_id, UCS_RM_ROUTE_INFOS_BUILT == route_infos);
 }
 
 static void OnUnicensMostPortStatus(uint16_t most_port_handle,
@@ -668,17 +727,24 @@ static void OnUcsStopResult(Ucs_StdResult_t result, void *user_ptr)
     UCSI_CB_OnStop(my->tag);
 }
 
+static void OnUcsGpioPortCreate(uint16_t node_address, uint16_t gpio_port_handle, Ucs_Gpio_Result_t result, void *user_ptr)
+{
+    UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
+    assert(MAGIC == my->magic);
+    OnCommandExecuted(my, UnicensCmd_GpioCreatePort);
+}
+
+static void OnUcsGpioPortWrite(uint16_t node_address, uint16_t gpio_port_handle, uint16_t current_state, uint16_t sticky_state, Ucs_Gpio_Result_t result, void *user_ptr)
+{
+    UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
+    assert(MAGIC == my->magic);
+    OnCommandExecuted(my, UnicensCmd_GpioWritePort);
+}
+
 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);
-    }
     switch (code)
     {
     case UCS_MGR_REP_IGNORED_UNKNOWN:
@@ -688,8 +754,23 @@ static void OnUcsMgrReport(Ucs_MgrReport_t code, uint16_t node_address, Ucs_Rm_N
         UCSI_CB_OnUserMessage(my->tag, true, "Node=%X: Ignored, because duplicated", 1, node_address);
         break;
     case UCS_MGR_REP_AVAILABLE:
+    {
+        UnicensCmdEntry_t e;
         UCSI_CB_OnUserMessage(my->tag, false, "Node=%X: Available", 1, node_address);
+        /* Enable usage of remote GPIO ports */
+        e.cmd = UnicensCmd_GpioCreatePort;
+        e.val.GpioCreatePort.destination = node_address;
+        e.val.GpioCreatePort.debounceTime = 20;
+        EnqueueCommand(my, &e);
+        /* Execute scripts, if there are any */
+        if (node_ptr && node_ptr->script_list_ptr && node_ptr->script_list_size)
+        {
+            e.cmd = UnicensCmd_NsRun;
+            e.val.NsRun.node_ptr = node_ptr;
+            EnqueueCommand(my, &e);
+        }
         break;
+    }
     case UCS_MGR_REP_NOT_AVAILABLE:
         UCSI_CB_OnUserMessage(my->tag, false, "Node=%X: Not available", 1, node_address);
         break;
@@ -722,6 +803,31 @@ static void OnUcsAmsRxMsgReceived(void *user_ptr)
     UCSI_CB_OnAmsMessageReceived(my->tag);
 }
 
+static void OnUcsGpioTriggerEventStatus(uint16_t node_address, uint16_t gpio_port_handle,
+    uint16_t rising_edges, uint16_t falling_edges, uint16_t levels, void * user_ptr)
+{
+    uint8_t i;
+    UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
+    assert(MAGIC == my->magic);
+    for (i = 0; i < 16; i++)
+    {
+        if (0 != ((rising_edges >> i) & 0x1))
+            UCSI_CB_OnGpioStateChange(my->tag, node_address, i, true);
+        if (0 != ((falling_edges >> i) & 0x1))
+            UCSI_CB_OnGpioStateChange(my->tag, node_address, i, false);
+    }
+}
+
+static void OnUcsI2CWrite(uint16_t node_address, uint16_t i2c_port_handle,
+    uint8_t i2c_slave_address, uint8_t data_len, Ucs_I2c_Result_t result, void *user_ptr)
+{
+    UCSI_Data_t *my = (UCSI_Data_t *)user_ptr;
+    assert(MAGIC == my->magic);
+    OnCommandExecuted(my, UnicensCmd_I2CWrite);
+    if (UCS_I2C_RES_SUCCESS != result.code)
+        UCSI_CB_OnUserMessage(my->tag, true, "Remote I2C Write to node=0x%X failed", 1, node_address);
+}
+
 /*----------------------------------------
  * Debug Message output from Unicens stack:
  *----------------------------------------