summaryrefslogtreecommitdiffstats
path: root/mnsl/mns_segmentation.c
diff options
context:
space:
mode:
Diffstat (limited to 'mnsl/mns_segmentation.c')
-rw-r--r--mnsl/mns_segmentation.c555
1 files changed, 555 insertions, 0 deletions
diff --git a/mnsl/mns_segmentation.c b/mnsl/mns_segmentation.c
new file mode 100644
index 0000000..7bfa2ff
--- /dev/null
+++ b/mnsl/mns_segmentation.c
@@ -0,0 +1,555 @@
+/*
+ * MOST NetServices "Light" V3.2.7.0.1796 MultiInstance Patch
+ *
+ * Copyright (C) 2015 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 3 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.
+ *
+ */
+
+/*!
+ * \file
+ * \brief Implementation of AMS Segmentation Class
+ *
+ * \cond MNS_INTERNAL_DOC
+ * \addtogroup G_AMSSEGM
+ * @{
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Includes */
+/*------------------------------------------------------------------------------------------------*/
+#include "mns_segmentation.h"
+#include "mns_ams.h"
+#include "mns_misc.h"
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal constants */
+/*------------------------------------------------------------------------------------------------*/
+ /*!\brief Timeout for garbage collector */
+static const uint16_t SEGM_GC_TIMEOUT = 5000U; /* parasoft-suppress MISRA2004-8_7 "intended usage as configuration parameter" */
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal typedefs */
+/*------------------------------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------------------------*/
+/* Internal prototypes */
+/*------------------------------------------------------------------------------------------------*/
+static Mns_AmsRx_Msg_t *Segm_RxRetrieveProcessingHandle(CSegmentation *self, Msg_MostTel_t *tel_ptr);
+static void Segm_RxStoreProcessingHandle(CSegmentation *self, Mns_AmsRx_Msg_t *msg_ptr);
+static bool Segm_RxSearchProcessingHandle(void *current_data, void *search_data);
+static bool Segm_RxGcSetLabel(void *current_data, void *search_data);
+static Mns_AmsRx_Msg_t* Segm_RxProcessTelId0(CSegmentation *self, Msg_MostTel_t *tel_ptr, Segm_Result_t *result_ptr);
+static void Segm_RxProcessTelId1(CSegmentation *self, Msg_MostTel_t *tel_ptr, Segm_Result_t *result_ptr);
+static void Segm_RxProcessTelId2(CSegmentation *self, Msg_MostTel_t *tel_ptr);
+static Mns_AmsRx_Msg_t* Segm_RxProcessTelId3(CSegmentation *self, Msg_MostTel_t *tel_ptr);
+static void Segm_RxProcessTelId4(CSegmentation *self, Msg_MostTel_t *tel_ptr, Segm_Result_t *result_ptr);
+
+/*------------------------------------------------------------------------------------------------*/
+/* Initialization methods */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Constructor of class CSegmentation
+ * \param self The instance
+ * \param base_ptr Reference to base services
+ * \param pool_ptr Reference to the (Rx) message pool
+ * \param rx_def_payload_sz Default memory size that is allocated when receiving segmented messages
+ * without size prefix
+ */
+void Segm_Ctor(CSegmentation *self, CBase *base_ptr, CAmsMsgPool *pool_ptr, uint16_t rx_def_payload_sz)
+{
+ MISC_MEM_SET(self, 0, sizeof(*self));
+ self->base_ptr = base_ptr; /* initialize members */
+ self->pool_ptr = pool_ptr;
+
+ self->rx_default_payload_sz = rx_def_payload_sz;
+
+ Dl_Ctor(&self->processing_list, self->base_ptr->mns_inst_id);
+ T_Ctor(&self->gc_timer);
+ Tm_SetTimer(&self->base_ptr->tm, /* start garbage collector timer */
+ &self->gc_timer,
+ &Segm_RxGcScanProcessingHandles,
+ self,
+ SEGM_GC_TIMEOUT,
+ SEGM_GC_TIMEOUT
+ );
+}
+
+/*! \brief Constructor of class CSegmentation
+ * \param self The instance
+ * \param error_fptr Reference to segmentation error callback function
+ * \param error_inst Reference to segmentation error instance
+ */
+void Segm_AssignRxErrorHandler(CSegmentation *self, Segm_OnError_t error_fptr, void *error_inst)
+{
+ self->error_fptr = error_fptr;
+ self->error_inst = error_inst;
+}
+
+/*! \brief Performs cleanup of pending messages
+ * \param self The instance
+ */
+void Segm_Cleanup(CSegmentation *self)
+{
+ CDlNode *node_ptr = NULL;
+ /* cleanup Tx queue */
+ for (node_ptr = Dl_PopHead(&self->processing_list); node_ptr != NULL; node_ptr = Dl_PopHead(&self->processing_list))
+ {
+ Mns_AmsRx_Msg_t *rx_ptr = (Mns_AmsRx_Msg_t*)Dln_GetData(node_ptr);
+
+ Amsp_FreeRxPayload(self->pool_ptr, rx_ptr);
+ Amsp_FreeRxObj(self->pool_ptr, rx_ptr);
+ }
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Tx segmentation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Builds next MOST telegram according to given Application Messages
+ * \param self The instance
+ * \param msg_ptr Reference to the Application Message Tx handle
+ * \param tel_ptr Reference to the MOST Telegram handle
+ * \return Returns \c True if segmentation was completed for the Application Message. Otherwise \c false.
+ */
+bool Segm_TxBuildSegment(CSegmentation *self, Mns_AmsTx_Msg_t* msg_ptr, Msg_MostTel_t *tel_ptr)
+{
+ bool finished = false;
+ MISC_UNUSED(self);
+
+ tel_ptr->destination_addr = msg_ptr->destination_address;
+ tel_ptr->id.fblock_id = msg_ptr->fblock_id;
+ tel_ptr->id.instance_id = msg_ptr->instance_id;
+ tel_ptr->id.function_id = msg_ptr->function_id;
+ tel_ptr->id.op_type = msg_ptr->op_type;
+ tel_ptr->opts.llrbc = msg_ptr->llrbc;
+ tel_ptr->info_ptr = msg_ptr; /* info_ptr must carry the reference to AMS Tx message object */
+ tel_ptr->opts.cancel_id = Amsg_TxGetFollowerId(msg_ptr);
+
+ if (msg_ptr->data_size <= SEGM_MAX_SIZE_TEL) /* is single transfer? */
+ {
+ Msg_SetExtPayload((CMessage*)(void*)tel_ptr, msg_ptr->data_ptr, (uint8_t)msg_ptr->data_size, NULL);
+ finished = true;
+ }
+ else /* is segmented transfer? */
+ {
+ uint16_t next_segm_cnt = Amsg_TxGetNextSegmCnt(msg_ptr);
+
+ if (next_segm_cnt == 0xFFFFU) /* first segment: size prefixed segmented message TelId = "4" */
+ {
+ tel_ptr->tel.tel_id = 4U;
+ tel_ptr->tel.tel_data_ptr[0] = MISC_HB(msg_ptr->data_size);
+ tel_ptr->tel.tel_data_ptr[1] = MISC_LB(msg_ptr->data_size);
+ tel_ptr->tel.tel_len = 2U;
+ }
+ else /* further segments: TelId = "1,2,3" */
+ {
+ uint16_t index = next_segm_cnt * ((uint16_t)SEGM_MAX_SIZE_TEL - 1U);
+ uint16_t remaining_sz = msg_ptr->data_size - index;
+ uint8_t tel_sz = SEGM_MAX_SIZE_TEL - 1U;
+
+ if (remaining_sz < SEGM_MAX_SIZE_TEL)
+ {
+ tel_ptr->tel.tel_id = 3U; /* is last segment */
+ tel_sz = (uint8_t)remaining_sz;
+ finished = true;
+ }
+ else
+ {
+ if (0U == index)
+ {
+ tel_ptr->tel.tel_id = 1U; /* is first segment */
+ }
+ else
+ {
+ tel_ptr->tel.tel_id = 2U; /* is subsequent segment */
+ }
+ }
+
+ tel_ptr->tel.tel_cnt = (uint8_t)next_segm_cnt;
+ Msg_SetExtPayload((CMessage*)(void*)tel_ptr, &msg_ptr->data_ptr[index], tel_sz, NULL);
+ }
+
+ Amsg_TxIncrementNextSegmCnt(msg_ptr);
+ }
+
+ return finished;
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Rx pools */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Retrieves a processing Rx Application message object to a corresponding MOST telegram
+ * \param self The instance
+ * \param tel_ptr Reference to the MOST telegram
+ * \return The reference to the corresponding Rx Application Message or \c NULL if no appropriate
+ * Rx Application Message is available.
+ */
+static Mns_AmsRx_Msg_t* Segm_RxRetrieveProcessingHandle(CSegmentation *self, Msg_MostTel_t *tel_ptr)
+{
+ Mns_AmsRx_Msg_t *msg_ptr = NULL;
+ CDlNode *result_node_ptr = Dl_Foreach(&self->processing_list, &Segm_RxSearchProcessingHandle, tel_ptr);
+
+ if (result_node_ptr != NULL)
+ {
+ Dl_Ret_t ret = Dl_Remove(&self->processing_list, result_node_ptr);
+ TR_ASSERT(self->base_ptr->mns_inst_id, "[SEGM]", (ret == DL_OK));
+ msg_ptr = (Mns_AmsRx_Msg_t*)Dln_GetData(result_node_ptr);
+ MISC_UNUSED(ret);
+ }
+
+ return msg_ptr;
+}
+
+/*! \brief Stores a processing Rx Application message object into a dedicated list
+ * \param self The instance
+ * \param msg_ptr Reference to the Rx Application Message
+ */
+static void Segm_RxStoreProcessingHandle(CSegmentation *self, Mns_AmsRx_Msg_t *msg_ptr)
+{
+ Amsg_RxSetGcMarker(msg_ptr, false);
+ Amsg_RxEnqueue(msg_ptr, &self->processing_list); /* insert at tail, since garbage collector starts at head */
+}
+
+/*! \brief Performs garbage collection of outdated message objects
+ * \param self The instance
+ */
+void Segm_RxGcScanProcessingHandles(void *self)
+{
+ CSegmentation *self_ = (CSegmentation*)self;
+ /* first remove outdated messages */
+ CDlNode *node_ptr = Dl_PeekHead(&self_->processing_list); /* get first candidate from head */
+
+ while (node_ptr != NULL)
+ {
+ Mns_AmsRx_Msg_t *msg_ptr = (Mns_AmsRx_Msg_t*)Dln_GetData(node_ptr);
+
+ if (Amsg_RxGetGcMarker(msg_ptr) != false)
+ {
+ Msg_MostTel_t tel;
+
+ Amsg_RxCopySignatureToTel(msg_ptr, &tel);
+ self_->error_fptr(self_->error_inst, &tel, SEGM_ERR_5);
+
+ (void)Dl_Remove(&self_->processing_list, node_ptr);
+
+ Amsp_FreeRxPayload(self_->pool_ptr, msg_ptr);
+ Amsp_FreeRxObj(self_->pool_ptr, msg_ptr);
+
+ node_ptr = Dl_PeekHead(&self_->processing_list); /* get next candidate from head */
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ (void)Dl_Foreach(&self_->processing_list, &Segm_RxGcSetLabel, NULL); /* set label of all remaining messages */
+}
+
+/*! \brief Sets garbage collector flags for all list members
+ * \param current_data The Application message object present in list
+ * \param search_data unused (\c NULL)
+ * \return Returns always false in order to handle all list members */
+static bool Segm_RxGcSetLabel(void *current_data, void *search_data)
+{
+ Mns_AmsRx_Msg_t *msg_ptr = (Mns_AmsRx_Msg_t*)current_data;
+ Amsg_RxSetGcMarker(msg_ptr, true);
+ MISC_UNUSED(search_data);
+ return false;
+}
+
+/*! \brief Search routine to identify message objects with the same signature
+ * than a given MOST telegram
+ * \param current_data The Application message object present in list
+ * \param search_data The MOST Telegram object
+ * \return Returns \c true if both handles have the same functional signature,
+ * otherwise \c false. */
+static bool Segm_RxSearchProcessingHandle(void *current_data, void *search_data)
+{
+ Mns_AmsRx_Msg_t *msg_ptr = (Mns_AmsRx_Msg_t*)current_data;
+ Msg_MostTel_t *tel_ptr = (Msg_MostTel_t*)search_data;
+
+ return Amsg_RxHandleIsIdentical(msg_ptr, tel_ptr);
+}
+
+/*------------------------------------------------------------------------------------------------*/
+/* Rx segmentation */
+/*------------------------------------------------------------------------------------------------*/
+/*! \brief Processes segmentation for a received MOST telegram
+ * \param self The instance
+ * \param tel_ptr The received MOST telegram
+ * \param result_ptr The result of the segmentation process
+ * \return The completed Rx Application Message or \c NULL if segmentation process is still
+ * ongoing.
+ */
+Mns_AmsRx_Msg_t* Segm_RxExecuteSegmentation(CSegmentation *self, Msg_MostTel_t *tel_ptr, Segm_Result_t *result_ptr)
+{
+ Mns_AmsRx_Msg_t *msg_ptr = NULL;
+ *result_ptr = SEGM_RES_OK;
+
+ switch (tel_ptr->tel.tel_id) /* parasoft-suppress MISRA2004-15_3 "ignore unexpected TelIds" */
+ {
+ case 0U:
+ msg_ptr = Segm_RxProcessTelId0(self, tel_ptr, result_ptr);
+ break;
+ case 1U:
+ Segm_RxProcessTelId1(self, tel_ptr, result_ptr);
+ break;
+ case 2U:
+ Segm_RxProcessTelId2(self, tel_ptr);
+ break;
+ case 3U:
+ msg_ptr = Segm_RxProcessTelId3(self, tel_ptr);
+ break;
+ case 4U:
+ Segm_RxProcessTelId4(self, tel_ptr, result_ptr);
+ break;
+ default:
+ break;
+ }
+
+ return msg_ptr; /* return completed message */
+}
+
+/*! \brief Processes segmentation for a received MOST telegram with \c TelId="0"
+ * \param self The instance
+ * \param tel_ptr The received MOST telegram
+ * \param result_ptr Result of segmentation process
+ * \return The completed Rx Application Message or \c NULL if segmentation process
+ * does not finish successfully.
+ */
+static Mns_AmsRx_Msg_t* Segm_RxProcessTelId0(CSegmentation *self, Msg_MostTel_t *tel_ptr, Segm_Result_t *result_ptr)
+{
+ Mns_AmsRx_Msg_t *msg_ptr = Segm_RxRetrieveProcessingHandle(self, tel_ptr);
+ *result_ptr = SEGM_RES_OK;
+
+ if (msg_ptr != NULL) /* treat error: segmentation process is ongoing */
+ {
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_7);
+ Amsp_FreeRxPayload(self->pool_ptr, msg_ptr);/* free assigned user payload and throw segmentation error */
+ Amsp_FreeRxObj(self->pool_ptr, msg_ptr);
+ msg_ptr = NULL;
+ }
+ /* try to allocate handle, memory is NetServices provided (payload <= 45 bytes) */
+ msg_ptr = Amsp_AllocRxObj(self->pool_ptr, (uint16_t)tel_ptr->tel.tel_len);
+
+ if (msg_ptr == NULL)
+ {
+ msg_ptr = Amsp_AllocRxRsvd(self->pool_ptr);
+ }
+
+ if (msg_ptr != NULL) /* handle available: setup Rx Application Message */
+ {
+ Amsg_RxCopySignatureFromTel(msg_ptr, tel_ptr);
+
+ if (tel_ptr->tel.tel_len > 0U)
+ { /* copy payload to message */
+ Amsg_RxCopyToPayload(msg_ptr, tel_ptr->tel.tel_data_ptr, tel_ptr->tel.tel_len);
+ }
+ else
+ { /* set payload length to zero */
+ msg_ptr->data_ptr = NULL;
+ msg_ptr->data_size = 0U;
+ }
+ }
+ else
+ {
+ *result_ptr = SEGM_RES_RETRY; /* retry when next Rx object is released */
+ }
+
+ return msg_ptr;
+}
+
+/*! \brief Processes segmentation for a received MOST telegram with \c TelId="1"
+ * \param self The instance
+ * \param tel_ptr The received MOST telegram
+ * \param result_ptr Result of segmentation process
+ */
+static void Segm_RxProcessTelId1(CSegmentation *self, Msg_MostTel_t *tel_ptr, Segm_Result_t *result_ptr)
+{
+ *result_ptr = SEGM_RES_OK;
+
+ if (tel_ptr->tel.tel_cnt != 0U) /* handle incorrect tel_cnt */
+ {
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_3);
+ }
+ else /* tel_cnt is correct -> continue segmentation */
+ {
+ Mns_AmsRx_Msg_t *msg_ptr = Segm_RxRetrieveProcessingHandle(self, tel_ptr);
+ bool is_size_prefixed = false;
+
+ if (msg_ptr != NULL) /* has previous message */
+ {
+ if ((Amsg_RxGetExpTelCnt(msg_ptr) != 0U) || (msg_ptr->data_size > 0U))
+ { /* error: previous message already contains segments */
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_7);
+ Amsp_FreeRxPayload(self->pool_ptr, msg_ptr);
+ Amsg_RxHandleSetup(msg_ptr); /* initialize message for re-use */
+ }
+ else /* message and payload had been allocated by TelId '4' */
+ {
+ is_size_prefixed = true;
+ }
+ }
+ else /* allocate message object if pre-allocation was not initiated by TelId "4" */
+ {
+ msg_ptr = Amsp_AllocRxObj(self->pool_ptr, 0U);
+ }
+
+ if (msg_ptr != NULL) /* now allocate payload */
+ {
+ if (is_size_prefixed == false)
+ {
+ Amsg_RxCopySignatureFromTel(msg_ptr, tel_ptr); /* save signature and try to allocate */
+ (void)Amsp_AllocRxPayload(self->pool_ptr, self->rx_default_payload_sz, msg_ptr);
+ }
+
+ if (!Amsg_RxHasExternalPayload(msg_ptr)) /* allocation of payload failed */
+ {
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_2);
+ Amsp_FreeRxObj(self->pool_ptr, msg_ptr);
+ msg_ptr = NULL;
+ }
+ else /* allocation of payload succeeded */
+ {
+ (void)Amsg_RxAppendPayload(msg_ptr, tel_ptr);
+ Segm_RxStoreProcessingHandle(self, msg_ptr);
+ msg_ptr = NULL;
+ }
+ }
+ else /* no message object allocated */
+ { /* send segmentation error */
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_4);
+ }
+ }
+}
+
+/*! \brief Processes segmentation for a received MOST telegram with \c TelId="2"
+ * \param self The instance
+ * \param tel_ptr The received MOST telegram
+ */
+static void Segm_RxProcessTelId2(CSegmentation *self, Msg_MostTel_t *tel_ptr)
+{
+ Mns_AmsRx_Msg_t *msg_ptr = Segm_RxProcessTelId3(self, tel_ptr); /* pretend having TelId '2' but store the */
+ /* assembled message again */
+ if (msg_ptr != NULL)
+ {
+ Segm_RxStoreProcessingHandle(self, msg_ptr);
+ }
+}
+
+/*! \brief Processes segmentation for a received MOST telegram with \c TelId="3"
+ * \param self The instance
+ * \param tel_ptr The received MOST telegram
+ * \return The assembled Rx Application Message or \c NULL if segmentation process
+ * did not process successfully.
+ */
+static Mns_AmsRx_Msg_t* Segm_RxProcessTelId3(CSegmentation *self, Msg_MostTel_t *tel_ptr)
+{
+ Mns_AmsRx_Msg_t *msg_ptr = Segm_RxRetrieveProcessingHandle(self, tel_ptr);
+
+ if (msg_ptr == NULL) /* is first segment missing */
+ {
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_1);
+ }
+ else
+ {
+ uint8_t exp_tel_cnt = Amsg_RxGetExpTelCnt(msg_ptr);
+
+ if ((exp_tel_cnt == 0U) && (msg_ptr->data_size == 0U))
+ { /* error: did not receive first segment */
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_1);
+ Segm_RxStoreProcessingHandle(self, msg_ptr);
+ msg_ptr = NULL;
+ }
+ else if (exp_tel_cnt != tel_ptr->tel.tel_cnt)
+ { /* has wrong TelCnt */
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_3);
+ Segm_RxStoreProcessingHandle(self, msg_ptr);
+ msg_ptr = NULL;
+ }
+
+ if (msg_ptr != NULL)
+ {
+ bool succ = Amsg_RxAppendPayload(msg_ptr, tel_ptr);
+
+ if (succ == false)
+ {
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_2);
+ Amsp_FreeRxPayload(self->pool_ptr, msg_ptr);
+ Amsp_FreeRxObj(self->pool_ptr, msg_ptr);
+ msg_ptr = NULL;
+ }
+ }
+ }
+
+ return msg_ptr;
+}
+
+/*! \brief Processes segmentation for a received MOST telegram with \c TelId="4"
+ * \param self The instance
+ * \param tel_ptr The received MOST telegram
+ * \param result_ptr Result of segmentation process
+ */
+static void Segm_RxProcessTelId4(CSegmentation *self, Msg_MostTel_t *tel_ptr, Segm_Result_t *result_ptr)
+{
+ *result_ptr = SEGM_RES_OK;
+
+ if (tel_ptr->tel.tel_len >= 2U) /* telegrams has necessary length */
+ {
+ uint16_t msg_size;
+ MISC_DECODE_WORD(&msg_size, tel_ptr->tel.tel_data_ptr);
+
+ if (msg_size > SEGM_MAX_SIZE_TEL) /* application message has correct size */
+ {
+ Mns_AmsRx_Msg_t *msg_ptr = Segm_RxRetrieveProcessingHandle(self, tel_ptr);
+
+ if (msg_ptr != NULL) /* treat error: segmentation process is ongoing */
+ {
+ Amsp_FreeRxPayload(self->pool_ptr, msg_ptr);
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_7);
+ Amsg_RxHandleSetup(msg_ptr); /* initialize message for re-use */
+ }
+ else
+ { /* try to allocate handle, memory is NetServices provided (payload <= 45 bytes) */
+ msg_ptr = Amsp_AllocRxObj(self->pool_ptr, 0U);
+ }
+
+ if (msg_ptr != NULL) /* allocation succeeded: decode length and allocate payload */
+ {
+ Amsg_RxCopySignatureFromTel(msg_ptr, tel_ptr);
+ (void)Amsp_AllocRxPayload(self->pool_ptr, msg_size, msg_ptr);
+ Segm_RxStoreProcessingHandle(self, msg_ptr);/* store handle and don't care if payload was allocated or not */
+ msg_ptr = NULL; /* segmentation error 2 is treated by TelId 1 */
+ }
+ else
+ {
+ self->error_fptr(self->error_inst, tel_ptr, SEGM_ERR_4);
+ }
+ }
+ }
+}
+
+/*!
+ * @}
+ * \endcond
+ */
+
+/*------------------------------------------------------------------------------------------------*/
+/* End of file */
+/*------------------------------------------------------------------------------------------------*/
+