54fdf0e4945020ff9945b125fa6dbd5f0d0364c1
[apps/agl-service-unicens.git] / ucs2-lib / src / ucs_transceiver.c
1 /*------------------------------------------------------------------------------------------------*/
2 /* UNICENS V2.1.0-3491                                                                            */
3 /* Copyright (c) 2017 Microchip Technology Germany II GmbH & Co. KG.                              */
4 /*                                                                                                */
5 /* This program is free software: you can redistribute it and/or modify                           */
6 /* it under the terms of the GNU General Public License as published by                           */
7 /* the Free Software Foundation, either version 2 of the License, or                              */
8 /* (at your option) any later version.                                                            */
9 /*                                                                                                */
10 /* This program is distributed in the hope that it will be useful,                                */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of                                 */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                  */
13 /* GNU General Public License for more details.                                                   */
14 /*                                                                                                */
15 /* You should have received a copy of the GNU General Public License                              */
16 /* along with this program.  If not, see <http://www.gnu.org/licenses/>.                          */
17 /*                                                                                                */
18 /* You may also obtain this software under a propriety license from Microchip.                    */
19 /* Please contact Microchip for further information.                                              */
20 /*------------------------------------------------------------------------------------------------*/
21
22 /*!
23  * \file
24  * \brief Implementation of class CTransceiver
25  *
26  * \cond UCS_INTERNAL_DOC
27  * \addtogroup  G_TRCV
28  * @{
29  */
30
31 /*------------------------------------------------------------------------------------------------*/
32 /* Includes                                                                                       */
33 /*------------------------------------------------------------------------------------------------*/
34 #include "ucs_transceiver.h"
35 #include "ucs_misc.h"
36 #include "ucs_pmp.h"
37
38 /*------------------------------------------------------------------------------------------------*/
39 /* Internal prototypes                                                                            */
40 /*------------------------------------------------------------------------------------------------*/
41 static void Trcv_OnTxStatusInternal(void *self, Msg_MostTel_t *tel_ptr, Ucs_MsgTxStatus_t status);
42
43 /*------------------------------------------------------------------------------------------------*/
44 /* Implementation                                                                                 */
45 /*------------------------------------------------------------------------------------------------*/
46 /*! \brief  Constructor of class CTransceiver
47  *  \param  self         The instance
48  *  \param  fifo_ptr     Reference to the dedicated port message FIFO
49  *  \param  def_src_addr Source address that is preset in Tx message object
50  *  \param  ucs_user_ptr User reference that needs to be passed in every callback function
51  *  \param  trace_id     ID specifies FIFO in traces if multiple transceivers are running
52  */
53 void Trcv_Ctor(CTransceiver *self, CPmFifo *fifo_ptr, uint16_t def_src_addr, void *ucs_user_ptr, uint8_t trace_id)
54 {
55     MISC_MEM_SET(self, 0, sizeof(*self));
56     self->fifo_ptr = fifo_ptr;
57     self->tx_def_src = def_src_addr;
58     self->ucs_user_ptr = ucs_user_ptr;
59     self->own_id = trace_id;
60     Pool_Ctor(&self->tx_msg_pool, self->tx_msgs, TRCV_SIZE_TX_POOL, ucs_user_ptr);
61     TR_ASSERT(self->ucs_user_ptr, "[TRCV]", (fifo_ptr != NULL));
62 }
63
64 /*! \brief   Assigns a function of another class to receive messages
65  *  \details The assigned function is responsible to call Trcv_RxReleaseMsg() it has finished to process it
66  *  \param   self            The instance
67  *  \param   callback_fptr   Callback function
68  *  \param   inst_ptr        The instance of the receiver class
69  */
70 void Trcv_RxAssignReceiver(CTransceiver *self, Trcv_RxCompleteCb_t callback_fptr, void *inst_ptr)
71 {
72     self->rx_complete_fptr = callback_fptr;
73     self->rx_complete_inst = inst_ptr;
74 }
75
76 /*! \brief   Assigns a function of another class to filter Rx messages
77  *  \details The assigned function is responsible to discard or pass Rx messages
78  *  \param   self            The instance
79  *  \param   callback_fptr   Callback function
80  *  \param   inst_ptr        The instance of the filter class
81  */
82 void Trcv_RxAssignFilter(CTransceiver *self, Trcv_RxFilterCb_t callback_fptr, void *inst_ptr)
83 {
84     self->rx_filter_fptr = callback_fptr;
85     self->rx_filter_inst = inst_ptr;
86 }
87
88 /*! \brief  Releases an Rx message which was received by the assigned receiver
89  *  \param  self    The instance
90  *  \param  tel_ptr Reference to the received message
91  */
92 void Trcv_RxReleaseMsg(CTransceiver *self, Msg_MostTel_t *tel_ptr)
93 {
94     CMessage *msg_ptr = (CMessage*)(void*)tel_ptr;
95     bool check_ok = !Dln_IsNodePartOfAList(Msg_GetNode(msg_ptr));   /* message object shall not be part of a list */
96                                                                     /* because it was provided in an earlier step */
97     TR_ASSERT(self->ucs_user_ptr, "[TRCV]", check_ok);
98     if (check_ok)
99     {
100         Fifo_RxReleaseMsg(self->fifo_ptr, msg_ptr);
101     }
102 }
103
104 /*! \brief  Retrieves a message object from the pool
105  *  \param  self    The instance
106  *  \param  size    Size of the message in bytes. Valid range: 0..45.
107  *  \return Reference to the Msg_MostTel_t structure if a message is available.
108  *          Otherwise \c NULL.
109  */
110 extern Msg_MostTel_t* Trcv_TxAllocateMsg(CTransceiver *self, uint8_t size)
111 {
112     const uint8_t TRCV_CTRL_MAX_SIZE = 45U;         /* replace by PMS constant in future */
113     CMessage        *handle = NULL;
114     Msg_MostTel_t   *tel_ptr = NULL;
115
116     if (size <= TRCV_CTRL_MAX_SIZE)
117     {
118         handle = Pool_GetMsg(&self->tx_msg_pool);
119
120         if (handle != NULL)
121         {
122             Msg_Cleanup(handle);                   /* reset headers and fields */
123             Msg_ReserveHeader(handle, PMP_PM_MAX_SIZE_HEADER + ENC_MAX_SIZE_CONTENT);
124             tel_ptr = Msg_GetMostTel(handle);      /* return public struct of the message object */
125             tel_ptr->tel.tel_id = 0U;
126             tel_ptr->tel.tel_len = size;
127             tel_ptr->tel.tel_cnt = 0U;
128             tel_ptr->source_addr = self->tx_def_src;
129         }
130     }
131
132     return tel_ptr;
133 }
134
135 /*! \brief  Returns a message object to the transceiver pool a message was allocated from
136  *  \param  tel_ptr Reference to the message object which needs to be returned. 
137  */
138 void Trcv_TxReleaseMsg(Msg_MostTel_t *tel_ptr)
139 {
140     CMessage* msg_ptr = (CMessage*)(void*)tel_ptr;                  /* avoid MISRA-C warning by converting to "void*" */
141     bool check_ok = !Dln_IsNodePartOfAList(Msg_GetNode(msg_ptr));   /* message object shall not be part of a list */
142     TR_ASSERT(0U, "[TRCV]", check_ok);                              /* because it was provided in an earlier step */
143
144     if (check_ok)
145     {
146         Pool_ReturnMsg(msg_ptr);
147     }
148 }
149
150 /*! \brief  Prepares a message object for re-transmission
151  *  \param  tel_ptr Reference to the Tx message object which needs
152  *                  to be reused. 
153  */
154 void Trcv_TxReuseMsg(Msg_MostTel_t *tel_ptr)
155 {
156     CMessage* msg_ptr = (CMessage*)(void*)tel_ptr; 
157     TR_ASSERT(0U, "[TRCV]", (!Dln_IsNodePartOfAList(Msg_GetNode(msg_ptr)))); /* message object shall not be part of a list */
158                                                                              /* because it was provided in an earlier step */
159     Msg_Cleanup(msg_ptr);        /* reset headers and fields */
160     Msg_ReserveHeader(msg_ptr, PMP_PM_MAX_SIZE_HEADER + ENC_MAX_SIZE_CONTENT);
161 }
162
163 /*! \brief   Transmits a given message object to the INIC
164  *  \details After completed transmission the message object is released automatically
165  *  \param   self    The instance
166  *  \param   tel_ptr Reference to the message object
167  */
168 void Trcv_TxSendMsg(CTransceiver *self, Msg_MostTel_t *tel_ptr)
169 {
170     CMessage *msg_ptr; 
171
172     TR_ASSERT(self->ucs_user_ptr, "[TRCV]", (tel_ptr != NULL));
173     msg_ptr = (CMessage*)(void*)tel_ptr;
174
175     TR_INFO((self->ucs_user_ptr, "[TRCV]", "Trcv_TxSendMsg(): FIFO: %u, MSG(tgt:0x%04X, id:%02X.%01X.%04X.%01X)", 6U, self->own_id, tel_ptr->destination_addr, tel_ptr->id.fblock_id, tel_ptr->id.instance_id, tel_ptr->id.function_id, tel_ptr->id.op_type));
176     Msg_SetTxStatusHandler(msg_ptr, &Trcv_OnTxStatusInternal, self);        /* just release the message */
177     Fifo_Tx(self->fifo_ptr, msg_ptr, false);
178 }
179
180 /*! \brief  Transmits a given message object to the INIC with a dedicated result callback 
181  *  \param  self          The instance
182  *  \param  tel_ptr       Reference to the message object
183  *  \param  callback_fptr Callback function which is invoked after message transmission has finished.
184  *                        Must be \c NULL to avoid that a callback function is invoked. In this case
185  *                        the message object is freed internally. Hence, the message object must 
186  *                        not provide external payload.
187  *  \param  inst_ptr      Reference to the instance which is invoked with callback_fptr. Has to be \c 
188  *                        NULL if callback_fptr is \c NULL.
189  *  \note   The provided callback function is responsible to free the message object by calling 
190  *          Trcv_TxReleaseMsg() or to reuse the message object by calling Trcv_TxReuseMsg() before
191  *          passing it to one of the transmit functions again.
192  */
193 void Trcv_TxSendMsgExt(CTransceiver *self, Msg_MostTel_t *tel_ptr, Msg_TxStatusCb_t callback_fptr, void *inst_ptr)
194 {
195     CMessage *msg_ptr; 
196
197     TR_ASSERT(self->ucs_user_ptr, "[TRCV]", (tel_ptr != NULL));
198     msg_ptr = (CMessage*)(void*)tel_ptr;
199
200     if (callback_fptr == NULL)
201     {
202         TR_ASSERT(self->ucs_user_ptr, "[TRCV]", (inst_ptr == NULL));
203         callback_fptr = &Trcv_OnTxStatusInternal;
204         inst_ptr = self;
205     }
206
207     TR_INFO((self->ucs_user_ptr, "[TRCV]", "Trcv_TxSendMsgExt(): FIFO: %u, MSG(tgt:0x%04X, id:%02X.%01X.%04X.%01X)", 6U, self->own_id, tel_ptr->destination_addr, tel_ptr->id.fblock_id, tel_ptr->id.instance_id, tel_ptr->id.function_id, tel_ptr->id.op_type));
208     Msg_SetTxStatusHandler(msg_ptr, callback_fptr, inst_ptr);
209     Fifo_Tx(self->fifo_ptr, msg_ptr, false);
210 }
211
212 /*! \brief  Transmits a given message object to the INIC bypassing all other messages in the FIFO
213  *  \param  self          The instance
214  *  \param  tel_ptr       Reference to the message object
215  *  \param  callback_fptr Callback function which is invoked after message transmission has finished.
216  *                        Must be \c NULL to avoid that a callback function is invoked. In this case
217  *                        the message object is freed internally. Hence, the message object must 
218  *                        not provide external payload.
219  *  \param  inst_ptr      Reference to the instance which is invoked
220  *  \note   The provided callback function is responsible to free the message object by calling 
221  *          Trcv_TxReleaseMsg() or to reuse the message object by calling Trcv_TxReuseMsg() before
222  *          passing it to one of the transmit functions again.
223  */
224 void Trcv_TxSendMsgBypass(CTransceiver *self, Msg_MostTel_t *tel_ptr, Msg_TxStatusCb_t callback_fptr, void *inst_ptr)
225 {
226     CMessage *msg_ptr;
227
228     TR_ASSERT(self->ucs_user_ptr, "[TRCV]", (tel_ptr != NULL));
229     msg_ptr = (CMessage*)(void*)tel_ptr;
230
231     if (callback_fptr == NULL)
232     {
233         TR_ASSERT(self->ucs_user_ptr, "[TRCV]", (inst_ptr == NULL));
234         callback_fptr = &Trcv_OnTxStatusInternal;
235         inst_ptr = self;
236     }
237
238     Msg_SetTxStatusHandler(msg_ptr, callback_fptr, inst_ptr);
239     Fifo_Tx(self->fifo_ptr, msg_ptr, true);
240 }
241
242 /*! \brief  Callback function which is invoked instead of an external callback 
243  *          as soon as channel transmission was finished in PMS. 
244  *  \param  self    The instance
245  *  \param  tel_ptr Reference to the message object
246  *  \param  status  Transmission status
247  */
248 static void Trcv_OnTxStatusInternal(void *self, Msg_MostTel_t *tel_ptr, Ucs_MsgTxStatus_t status)
249 {
250     Trcv_TxReleaseMsg(tel_ptr);
251     MISC_UNUSED(self);
252     MISC_UNUSED(status);
253 }
254
255 /*! \brief  Internal callback function which is intended to be 
256  *          invoked by the port message channel on completed reception.
257  *  \param  self    The instance
258  *  \param  tel_ptr Reference to the message object
259  */
260 void Trcv_RxOnMsgComplete(void *self, CMessage *tel_ptr)
261 {
262     CTransceiver *self_ = (CTransceiver*)self;
263     bool discard = false;
264
265     TR_INFO((self_->ucs_user_ptr, "[TRCV]", "Trcv_RxOnMsgComplete(): FIFO: %u, MSG(src:0x%04X, id:%02X.%01X.%04X.%01X)", 6U, self_->own_id, tel_ptr->pb_msg.source_addr, tel_ptr->pb_msg.id.fblock_id, tel_ptr->pb_msg.id.instance_id, tel_ptr->pb_msg.id.function_id, tel_ptr->pb_msg.id.op_type));
266     if (self_->rx_filter_fptr != NULL)
267     {
268         discard = self_->rx_filter_fptr(self_->rx_filter_inst, Msg_GetMostTel(tel_ptr));
269     }
270
271     if ((self_->rx_complete_fptr != NULL) && (discard == false))
272     {
273         /* the assigned Rx function is responsible to release the message */
274         self_->rx_complete_fptr(self_->rx_complete_inst, Msg_GetMostTel(tel_ptr));
275     }
276     else
277     {
278         Fifo_RxReleaseMsg(self_->fifo_ptr, tel_ptr);
279     }
280 }
281
282 /*!
283  * @}
284  * \endcond
285  */
286
287 /*------------------------------------------------------------------------------------------------*/
288 /* End of file                                                                                    */
289 /*------------------------------------------------------------------------------------------------*/
290