1 /***************************************************************************//**
2 * \file cy_ipc_pipe.c
3 * \version 1.130
4 *
5 *  Description:
6 *   IPC Pipe Driver - This source file includes code for the Pipe layer on top
7 *   of the IPC driver.
8 *
9 ********************************************************************************
10 * Copyright 2016-2020 Cypress Semiconductor Corporation
11 * SPDX-License-Identifier: Apache-2.0
12 *
13 * Licensed under the Apache License, Version 2.0 (the "License");
14 * you may not use this file except in compliance with the License.
15 * You may obtain a copy of the License at
16 *
17 *     http://www.apache.org/licenses/LICENSE-2.0
18 *
19 * Unless required by applicable law or agreed to in writing, software
20 * distributed under the License is distributed on an "AS IS" BASIS,
21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 * See the License for the specific language governing permissions and
23 * limitations under the License.
24 *******************************************************************************/
25 
26 #include "cy_device.h"
27 
28 #if defined (CY_IP_M4CPUSS) || defined (CY_IP_M7CPUSS) || defined (CY_IP_MXIPC)
29 
30 #include "cy_ipc_pipe.h"
31 
32 /* Define a pointer to array of endPoints.
33 *  ( This comprises of all channels present in all IPC IP instances. ) */
34 static cy_stc_ipc_pipe_ep_t * cy_ipc_pipe_epArray = NULL;
35 CY_MISRA_DEVIATE_BLOCK_START('MISRA C-2012 Rule 10.8', 12, \
36 'Intentional typecast to IRQn_Type enum.')
37 
38 /*******************************************************************************
39 * Function Name: Cy_IPC_Pipe_Config
40 ****************************************************************************//**
41 *
42 * This function stores a copy of a pointer to the array of endpoints.  All
43 * access to endpoints will be via the index of the endpoint in this array.
44 *
45 * \note In general case, this function is called in the default startup code,
46 * so user doesn't need to call it anywhere.
47 * However, it may be useful in case of some pipe customizations.
48 *
49 * \param theEpArray
50 * This is the pointer to an array of endpoint structures that the designer
51 * created and will be used to reference all endpoints.
52 *
53 * \funcusage
54 * \snippet ipc/snippet/main.c snippet_myIpcPipeEpArray
55 * \snippet ipc/snippet/main.c snippet_Cy_IPC_Pipe_Config
56 *
57 *******************************************************************************/
Cy_IPC_Pipe_Config(cy_stc_ipc_pipe_ep_t * theEpArray)58 void Cy_IPC_Pipe_Config(cy_stc_ipc_pipe_ep_t * theEpArray)
59 {
60     /* Keep copy of this endpoint */
61     if (cy_ipc_pipe_epArray == NULL)
62     {
63         cy_ipc_pipe_epArray = theEpArray;
64     }
65 }
66 
67 
68 /*******************************************************************************
69 * Function Name: Cy_IPC_Pipe_Init
70 ****************************************************************************//**
71 *
72 * Initializes the system pipes. The system pipes are used by BLE.
73 * \note The function should be called on all CPUs.
74 *
75 * \note In general case, this function is called in the default startup code,
76 * so user doesn't need to call it anywhere.
77 * However, it may be useful in case of some pipe customizations.
78 *
79 * \param config
80 * This is the pointer to the pipe configuration structure
81 *
82 * \funcusage
83 * \snippet ipc/snippet/main.c snippet_myIpcPipeCbArray
84 * \snippet ipc/snippet/main.c snippet_myIpcPipeEpConfig
85 * \snippet ipc/snippet/main.c snippet_Cy_IPC_Pipe_Init
86 *
87 *******************************************************************************/
Cy_IPC_Pipe_Init(cy_stc_ipc_pipe_config_t const * config)88 void Cy_IPC_Pipe_Init(cy_stc_ipc_pipe_config_t const *config)
89 {
90     /* Create the interrupt structures and arrays needed */
91     CY_MISRA_DEVIATE_LINE('MISRA C-2012 Rule 10.3','Intentional typecast to IRQn_Type.');
92     cy_stc_sysint_t                 ipc_intr_cypipeConfig={.intrSrc=(IRQn_Type)0U,.intrPriority=0U};
93 
94     cy_stc_ipc_pipe_ep_config_t        epConfigDataA;
95     cy_stc_ipc_pipe_ep_config_t        epConfigDataB;
96 
97     /* Parameters checking begin */
98     CY_ASSERT_L1(NULL != config);
99     #if (CY_CPU_CORTEX_M0P)
100     CY_ASSERT_L2((uint32_t)(1UL << __NVIC_PRIO_BITS) > config->ep0ConfigData.ipcNotifierPriority);
101     #else
102     CY_ASSERT_L2((uint32_t)(1UL << __NVIC_PRIO_BITS) > config->ep1ConfigData.ipcNotifierPriority);
103     #endif
104     CY_ASSERT_L1(NULL != config->endpointsCallbacksArray);
105     CY_ASSERT_L1(NULL != config->userPipeIsrHandler);
106     /* Parameters checking end */
107 
108 #if defined(CY_IP_M4CPUSS)
109 /* Only for CAT1A devices. This Part of code is soon going to deprecated */
110 #if (CY_CPU_CORTEX_M0P)
111 
112     /* Receiver endpoint = EP0, Sender endpoint = EP1 */
113     epConfigDataA = config->ep0ConfigData;
114     epConfigDataB = config->ep1ConfigData;
115 
116     /* Configure CM0 interrupts */
117     ipc_intr_cypipeConfig.intrSrc          = (IRQn_Type)epConfigDataA.ipcNotifierMuxNumber;
118     ipc_intr_cypipeConfig.cm0pSrc          = (cy_en_intr_t)((int32_t)cpuss_interrupts_ipc_0_IRQn + (int32_t)epConfigDataA.ipcNotifierNumber);
119     ipc_intr_cypipeConfig.intrPriority     = epConfigDataA.ipcNotifierPriority;
120 
121 #else
122 
123     /* Receiver endpoint = EP1, Sender endpoint = EP0 */
124     epConfigDataA = config->ep1ConfigData;
125     epConfigDataB = config->ep0ConfigData;
126 
127     #if (defined (CY_IP_M4CPUSS) && (CY_IP_M4CPUSS_VERSION == 2) && (CPUSS_SYSTEM_IRQ_PRESENT))
128     ipc_intr_cypipeConfig.intrSrc          = (IRQn_Type)(((uint32_t)epConfigDataA.ipcNotifierMuxNumber << CY_SYSINT_INTRSRC_MUXIRQ_SHIFT) | (uint32_t)((uint32_t)cpuss_interrupts_ipc_0_IRQn + (uint32_t)epConfigDataA.ipcNotifierNumber));
129     ipc_intr_cypipeConfig.intrPriority     = epConfigDataA.ipcNotifierPriority;
130     #else
131     /* Configure interrupts */
132     ipc_intr_cypipeConfig.intrSrc          = (IRQn_Type)((int32_t)cpuss_interrupts_ipc_0_IRQn + (int32_t)epConfigDataA.ipcNotifierNumber);
133     ipc_intr_cypipeConfig.intrPriority     = epConfigDataA.ipcNotifierPriority;
134     #endif
135 
136 #endif /* (CY_CPU_CORTEX_M0P) */
137 
138     /* Initialize the pipe endpoints */
139     Cy_IPC_Pipe_EndpointInit(epConfigDataA.epAddress,
140                              config->endpointsCallbacksArray,
141                              config->endpointClientsCount,
142                              epConfigDataA.epConfig,
143                              &ipc_intr_cypipeConfig);
144 
145     /* Create the endpoints for the CM4 just for reference */
146     Cy_IPC_Pipe_EndpointInit(epConfigDataB.epAddress, NULL, 0UL, epConfigDataB.epConfig, NULL);
147 
148     (void)Cy_SysInt_Init(&ipc_intr_cypipeConfig, config->userPipeIsrHandler);
149 
150     #if (CY_CPU_CORTEX_M0P)
151     /* Enable the interrupts */
152     NVIC_EnableIRQ(ipc_intr_cypipeConfig.intrSrc);
153     #elif (defined (CY_IP_M4CPUSS) && (CY_IP_M4CPUSS_VERSION == 2) && (CPUSS_SYSTEM_IRQ_PRESENT))
154     {
155         /* Enable the interrupts */
156         IRQn_Type IRQn = (IRQn_Type)(((uint32_t)ipc_intr_cypipeConfig.intrSrc >> CY_SYSINT_INTRSRC_MUXIRQ_SHIFT)
157                                 & CY_SYSINT_INTRSRC_MASK); /* Fetch bit 12-31 to get CPU IRQ value */
158         NVIC_EnableIRQ(IRQn);
159         NVIC_SetPriority(IRQn, ipc_intr_cypipeConfig.intrPriority);
160     }
161     #else
162         /* Enable the interrupts */
163         NVIC_EnableIRQ(ipc_intr_cypipeConfig.intrSrc);
164     #endif
165 
166 #else
167 
168    /* Receiver endpoint = EP0, Sender endpoint = EP1 */
169     epConfigDataA = config->ep0ConfigData;
170     epConfigDataB = config->ep1ConfigData;
171 
172 /* New Implementation which supports all devices */
173 #if (CY_IPC_INSTANCES > 1)
174     /* Configure CM33 interrupts */
175     if(epConfigDataA.ipcNotifierNumber < CY_IPC_IP0_INT)
176     {
177         ipc_intr_cypipeConfig.intrSrc          = (IRQn_Type) ((int32_t)cpuss_interrupts_ipc_0_IRQn +
178                                                  (int32_t)epConfigDataA.ipcNotifierNumber);
179         ipc_intr_cypipeConfig.intrPriority     = epConfigDataA.ipcNotifierPriority;
180     }
181 #if !(CY_CPU_CORTEX_M0P)
182     else if(epConfigDataA.ipcNotifierNumber >= CY_IPC_IP0_INT)
183     {
184          ipc_intr_cypipeConfig.intrSrc          = (IRQn_Type) ((int32_t)cpuss_interrupts_ipc_1_IRQn +
185                                                   (int32_t)(epConfigDataA.ipcNotifierNumber - CY_IPC_IP0_INT));
186          ipc_intr_cypipeConfig.intrPriority     = epConfigDataA.ipcNotifierPriority;
187     }
188 #endif /* !(CY_CPU_CORTEX_M0P) */
189     else
190     {
191         /* Nothing to do */
192     }
193 #elif defined(CY_IP_M4CPUSS) && (CY_CPU_CORTEX_M0P)
194     /* Configure CM0 interrupts */
195     ipc_intr_cypipeConfig.intrSrc          = (IRQn_Type)epConfigDataA.ipcNotifierMuxNumber;
196     ipc_intr_cypipeConfig.cm0pSrc          = (cy_en_intr_t)((int32_t)cpuss_interrupts_ipc_0_IRQn + (int32_t)epConfigDataA.ipcNotifierNumber);
197     ipc_intr_cypipeConfig.intrPriority     = epConfigDataA.ipcNotifierPriority;
198 #elif defined (CY_IP_M7CPUSS) /* CM7 */
199     /* Configure CM0 interrupts */
200     ipc_intr_cypipeConfig.intrSrc          = ((epConfigDataA.ipcNotifierMuxNumber << CY_SYSINT_INTRSRC_MUXIRQ_SHIFT) | (uint32_t)((int32_t)cpuss_interrupts_ipc_0_IRQn + (int32_t)epConfigDataA.ipcNotifierNumber));
201     ipc_intr_cypipeConfig.intrPriority     = epConfigDataA.ipcNotifierPriority;
202 #else
203     /* Configure interrupts */
204     ipc_intr_cypipeConfig.intrSrc          = (IRQn_Type)((int32_t)cpuss_interrupts_ipc_0_IRQn + (int32_t)epConfigDataA.ipcNotifierNumber);
205     ipc_intr_cypipeConfig.intrPriority     = epConfigDataA.ipcNotifierPriority;
206 
207 #endif /* (CY_CPU_CORTEX_M0P && CY_IP_M4CPUSS) */
208 
209 #if (CY_IPC_INSTANCES > 1U)
210     /* Initialize the pipe endpoints */
211     Cy_IPC_Pipe_EndpointInitExt(epConfigDataA.epAddress,
212                              config->endpointsCallbacksArray,
213                              config->endpointClientsCount,
214                              &(epConfigDataA.epConfig),
215                              &ipc_intr_cypipeConfig);
216 
217     /* Create the endpoints for the CM4 just for reference */
218     Cy_IPC_Pipe_EndpointInitExt(epConfigDataB.epAddress, NULL, 0UL, &(epConfigDataB.epConfig), NULL);
219 #else
220     /* Initialize the pipe endpoints */
221     Cy_IPC_Pipe_EndpointInit(epConfigDataA.epAddress,
222                              config->endpointsCallbacksArray,
223                              config->endpointClientsCount,
224                              epConfigDataA.epConfig,
225                              &ipc_intr_cypipeConfig);
226 
227     /* Create the endpoints for the CM4 just for reference */
228     Cy_IPC_Pipe_EndpointInit(epConfigDataB.epAddress, NULL, 0UL, epConfigDataB.epConfig, NULL);
229 #endif /* CY_IPC_INSTANCES */
230 
231     (void)Cy_SysInt_Init(&ipc_intr_cypipeConfig, config->userPipeIsrHandler);
232 
233     /* Enable the interrupts */
234 #if defined (CY_IP_M7CPUSS) || (defined (CY_IP_M4CPUSS) && (CY_IP_M4CPUSS_VERSION == 2) && (CPUSS_SYSTEM_IRQ_PRESENT))
235 {
236     IRQn_Type IRQn = (IRQn_Type)(((uint32_t)ipc_intr_cypipeConfig.intrSrc >> CY_SYSINT_INTRSRC_MUXIRQ_SHIFT)
237                                       & CY_SYSINT_INTRSRC_MASK); /* Fetch bit 12-31 to get CPU IRQ value */
238     NVIC_EnableIRQ(IRQn);
239     NVIC_SetPriority(IRQn, ipc_intr_cypipeConfig.intrPriority);
240 }
241 #else
242     NVIC_EnableIRQ(ipc_intr_cypipeConfig.intrSrc);
243 #endif /* defined (CY_IP_M7CPUSS) */
244 #endif /* CY_IP_M4CPUSS */
245 }
246 
247 
248 /*******************************************************************************
249 * Function Name: Cy_IPC_Pipe_EndpointInit
250 ****************************************************************************//**
251 *
252 * This function initializes the endpoint of a pipe for the current CPU.  The
253 * current CPU is the CPU that is executing the code. An endpoint of a pipe
254 * is for the IPC channel that receives a message for the current CPU.
255 *
256 * After this function is called, the callbackArray needs to be populated
257 * with the callback functions for that endpoint using the
258 * Cy_IPC_Pipe_RegisterCallback() function.
259 *
260 * \note In general case, this function is called within \ref Cy_IPC_Pipe_Init,
261 * so user doesn't need to call it anywhere.
262 * However, it may be useful in case of some pipe/endpoint customizations.
263 *
264 * \param epAddr
265 * This parameter is the address (or index in the array of endpoint structures)
266 * that designates the endpoint you want to initialize.
267 *
268 * \param cbArray
269 * This is a pointer to the callback function array.  Based on the client ID, one
270 * of the functions in this array is called to process the message.
271 *
272 * \param cbCnt
273 * This is the size of the callback array, or the number of defined clients.
274 *
275 * \param epConfig
276 * This value defines the IPC channel, IPC interrupt number, and the interrupt
277 * mask for the entire pipe.
278 * The format of the endpoint configuration
279 *    Bits[31:16] Interrupt Mask
280 *    Bits[15:8 ] IPC interrupt
281 *    Bits[ 7:0 ] IPC channel
282 *
283 * \param epInterrupt
284 * This is a pointer to the endpoint interrupt description structure.
285 *
286 * \funcusage
287 * \snippet ipc/snippet/main.c snippet_myIpcPipeCbArray
288 * \snippet ipc/snippet/main.c snippet_myIpcPipeEpConfig
289 * \snippet ipc/snippet/main.c snippet_Cy_IPC_Pipe_EndpointInit
290 *
291 * \note
292 * This API is available only for the CAT1A, CAT1B and CAT1C devices.
293 *
294 *******************************************************************************/
Cy_IPC_Pipe_EndpointInit(uint32_t epAddr,cy_ipc_pipe_callback_array_ptr_t cbArray,uint32_t cbCnt,uint32_t epConfig,cy_stc_sysint_t const * epInterrupt)295 void Cy_IPC_Pipe_EndpointInit(uint32_t epAddr, cy_ipc_pipe_callback_array_ptr_t cbArray,
296                               uint32_t cbCnt, uint32_t epConfig, cy_stc_sysint_t const *epInterrupt)
297 {
298     cy_stc_ipc_pipe_ep_t * endpoint;
299 
300     CY_ASSERT_L1(NULL != cy_ipc_pipe_epArray);
301 
302     endpoint = &cy_ipc_pipe_epArray[epAddr];
303 
304     /* Extract the channel, interrupt and interrupt mask */
305     endpoint->ipcChan         = _FLD2VAL(CY_IPC_PIPE_CFG_CHAN,  epConfig);
306     endpoint->intrChan        = _FLD2VAL(CY_IPC_PIPE_CFG_INTR,  epConfig);
307     endpoint->pipeIntMask     = _FLD2VAL(CY_IPC_PIPE_CFG_IMASK, epConfig);
308 
309     /* Assign IPC channel to this endpoint */
310     endpoint->ipcPtr   = Cy_IPC_Drv_GetIpcBaseAddress (endpoint->ipcChan);
311 
312     /* Assign interrupt structure to endpoint and Initialize the interrupt mask for this endpoint */
313     endpoint->ipcIntrPtr = Cy_IPC_Drv_GetIntrBaseAddr(endpoint->intrChan);
314 
315     /* Only allow notify and release interrupts from endpoints in this pipe. */
316     Cy_IPC_Drv_SetInterruptMask(endpoint->ipcIntrPtr, endpoint->pipeIntMask, endpoint->pipeIntMask);
317 
318     /* Save the Client count and the callback array pointer */
319     endpoint->clientCount   = cbCnt;
320     endpoint->callbackArray = cbArray;
321     endpoint->busy = CY_IPC_PIPE_ENDPOINT_NOTBUSY;
322 
323     if (NULL != epInterrupt)
324     {
325         #if defined (CY_IP_M7CPUSS) || (defined (CY_IP_M4CPUSS) && (CY_IP_M4CPUSS_VERSION == 2) && (CPUSS_SYSTEM_IRQ_PRESENT))
326             endpoint->pipeIntrSrc     = (IRQn_Type)(((uint32_t)epInterrupt->intrSrc >> CY_SYSINT_INTRSRC_MUXIRQ_SHIFT) & CY_SYSINT_INTRSRC_MASK);
327         #else
328             endpoint->pipeIntrSrc     = epInterrupt->intrSrc;
329         #endif
330     }
331 }
332 
333 
334 #if (CY_IPC_INSTANCES > 1U) || defined (CY_DOXYGEN)
335 /*******************************************************************************
336 * Function Name: Cy_IPC_Pipe_EndpointInitExt
337 ****************************************************************************//**
338 *
339 * This function initializes the endpoint of a pipe for the current CPU.  The
340 * current CPU is the CPU that is executing the code. An endpoint of a pipe
341 * is for the IPC channel that receives a message for the current CPU.
342 *
343 * After this function is called, the callbackArray needs to be populated
344 * with the callback functions for that endpoint using the
345 * Cy_IPC_Pipe_RegisterCallback() function.
346 *
347 * \note In general case, this function is called within \ref Cy_IPC_Pipe_Init,
348 * so user doesn't need to call it anywhere.
349 * However, it may be useful in case of some pipe/endpoint customizations.
350 *
351 * \param epAddr
352 * This parameter is the address (or index in the array of endpoint structures)
353 * that designates the endpoint you want to initialize.
354 *
355 * \param cbArray
356 * This is a pointer to the callback function array.  Based on the client ID, one
357 * of the functions in this array is called to process the message.
358 *
359 * \param cbCnt
360 * This is the size of the callback array, or the number of defined clients.
361 *
362 * \param epConfig
363 * This is a pointer to the structure which defines the IPC channel, IPC
364 * interrupt number, and the interrupt mask for the entire pipe.
365 *
366 * \param epInterrupt
367 * This is a pointer to the endpoint interrupt description structure.
368 *
369 * \funcusage
370 * \snippet ipc/snippet/main.c snippet_myIpcPipeCbArray
371 * \snippet ipc/snippet/main.c snippet_myIpcPipeEpConfig
372 * \snippet ipc/snippet/main.c snippet_Cy_IPC_Pipe_EndpointInit
373 *
374 * \note
375 * This API is available only for the CAT1D devices.
376 *
377 *******************************************************************************/
Cy_IPC_Pipe_EndpointInitExt(uint32_t epAddr,cy_ipc_pipe_callback_array_ptr_t cbArray,uint32_t cbCnt,cy_stc_ipc_pipe_ep_config_mask_t * epConfig,cy_stc_sysint_t const * epInterrupt)378 void Cy_IPC_Pipe_EndpointInitExt(uint32_t epAddr, cy_ipc_pipe_callback_array_ptr_t cbArray,
379                               uint32_t cbCnt, cy_stc_ipc_pipe_ep_config_mask_t *epConfig, cy_stc_sysint_t const *epInterrupt)
380 {
381     cy_stc_ipc_pipe_ep_t * endpoint;
382 
383     CY_ASSERT_L1(NULL != cy_ipc_pipe_epArray);
384 
385     endpoint = &cy_ipc_pipe_epArray[epAddr];
386 
387     /* Parameters checking begin */
388     CY_ASSERT_L2(CY_IPC_PIPE_IS_CHANNEL_INTR_COMBINATION_VALID(epConfig ->epChannel,epConfig ->epIntr));
389 
390     /* Extract the channel, interrupt and interrupt mask */
391     endpoint->ipcChan         = epConfig ->epChannel;
392     endpoint->intrChan        = epConfig ->epIntr;
393     endpoint->pipeIntMask     = CY_IPC_PIPE_COMPUTE_INTR_MASK(epConfig ->epChannel,epConfig ->epIntrmask);
394 
395     /* Assign IPC channel to this endpoint */
396     endpoint->ipcPtr   = Cy_IPC_Drv_GetIpcBaseAddress (endpoint->ipcChan);
397 
398     /* Assign interrupt structure to endpoint and Initialize the interrupt mask for this endpoint */
399     endpoint->ipcIntrPtr = Cy_IPC_Drv_GetIntrBaseAddr(endpoint->intrChan);
400 
401     /* Only allow notify and release interrupts from endpoints in this pipe. */
402     Cy_IPC_Drv_SetInterruptMask(endpoint->ipcIntrPtr, endpoint->pipeIntMask, endpoint->pipeIntMask);
403 
404     /* Save the Client count and the callback array pointer */
405     endpoint->clientCount   = cbCnt;
406     endpoint->callbackArray = cbArray;
407     endpoint->busy = CY_IPC_PIPE_ENDPOINT_NOTBUSY;
408 
409     if (NULL != epInterrupt)
410     {
411         #if defined (CY_IP_M7CPUSS) || (defined (CY_IP_M4CPUSS) && (CY_IP_M4CPUSS_VERSION == 2) && (CPUSS_SYSTEM_IRQ_PRESENT))
412             endpoint->pipeIntrSrc     = (IRQn_Type)(((uint32_t)epInterrupt->intrSrc >> CY_SYSINT_INTRSRC_MUXIRQ_SHIFT) & CY_SYSINT_INTRSRC_MASK);
413         #else
414             endpoint->pipeIntrSrc     = epInterrupt->intrSrc;
415         #endif
416     }
417 }
418 #endif /* CY_IPC_INSTANCES */
419 
420 
421 /*******************************************************************************
422 * Function Name: Cy_IPC_Pipe_SendMessage
423 ****************************************************************************//**
424 *
425 * This function is used to send a message from one endpoint to another.  It
426 * generates an interrupt on the endpoint that receives the message and a
427 * release interrupt to the sender to acknowledge the message has been processed.
428 *
429 * \param toAddr
430 * This parameter is the address (or index in the array of endpoint structures)
431 * of the endpoint to which you are sending the message.
432 *
433 * \param fromAddr
434 * This parameter is the address (or index in the array of endpoint structures)
435 * of the endpoint from which the message is being sent.
436 *
437 * \param msgPtr
438 * Pointer to the message structure to be sent.
439 * msgPtr is a 32 bit value in RRRRDDCC format.
440 * CC :   First 8 bits are for client id.
441 * DD :   Next 8 bits are for user code.
442 * RRRR : Next 16 bits are for Release masks for both pipe endpoints interrupt channels.
443 *
444 * \param callBackPtr
445 * Pointer to the Release callback function.
446 *
447 * \return
448 *    CY_IPC_PIPE_SUCCESS:          Message was sent to the other end of the pipe
449 *    CY_IPC_PIPE_ERROR_BAD_HANDLE: The handle provided for the pipe was not valid
450 *    CY_IPC_PIPE_ERROR_SEND_BUSY:  The pipe is already busy sending a message
451 *
452 * \funcusage
453 * \snippet ipc/snippet/main.c snippet_myReleaseCallback
454 * \snippet ipc/snippet/main.c snippet_Cy_IPC_Pipe_SendMessage
455 *
456 *******************************************************************************/
Cy_IPC_Pipe_SendMessage(uint32_t toAddr,uint32_t fromAddr,void * msgPtr,cy_ipc_pipe_relcallback_ptr_t callBackPtr)457 cy_en_ipc_pipe_status_t Cy_IPC_Pipe_SendMessage(uint32_t toAddr, uint32_t fromAddr,
458                                                 void * msgPtr, cy_ipc_pipe_relcallback_ptr_t callBackPtr)
459 {
460     cy_en_ipc_pipe_status_t  returnStatus;
461     uint32_t releaseMask;
462     uint32_t notifyMask;
463 
464     cy_stc_ipc_pipe_ep_t * fromEp;
465     cy_stc_ipc_pipe_ep_t * toEp;
466 
467     CY_ASSERT_L1(NULL != msgPtr);
468     CY_ASSERT_L1(NULL != cy_ipc_pipe_epArray);
469 
470     toEp   = &(cy_ipc_pipe_epArray[toAddr]);
471     fromEp = &cy_ipc_pipe_epArray[fromAddr];
472 
473     /* Create the release mask for the "fromAddr" channel's interrupt channel */
474     releaseMask =  (uint32_t)(1UL << CY_IPC_PIPE_INTR_NUMBER_WITHIN_INSTANCE(fromEp->intrChan));
475 
476     /* Shift into position */
477     releaseMask = _VAL2FLD(CY_IPC_PIPE_MSG_RELEASE, releaseMask);
478 
479     /* Create the notify mask for the "toAddr" channel's interrupt channel */
480     notifyMask  =  (uint32_t)(1UL << CY_IPC_PIPE_INTR_NUMBER_WITHIN_INSTANCE(toEp->intrChan));
481 
482     /* Check if IPC channel valid */
483     if( toEp->ipcPtr != NULL)
484     {
485         if(fromEp->busy == CY_IPC_PIPE_ENDPOINT_NOTBUSY)
486         {
487             /* Attempt to acquire the channel */
488             if( CY_IPC_DRV_SUCCESS == Cy_IPC_Drv_LockAcquire(toEp->ipcPtr) )
489             {
490                 /* Mask out the release mask area */
491                 * (uint32_t *) msgPtr &= ~(CY_IPC_PIPE_MSG_RELEASE_Msk);
492 
493                 * (uint32_t *) msgPtr |= releaseMask;
494 
495                 #if (defined (CY_CPU_CORTEX_M7) && (CY_CPU_CORTEX_M7)) && (defined (CY_IP_M7CPUSS))
496                     /* Flush the cache */
497                     CY_MISRA_DEVIATE_LINE('SIZEOF_MISMATCH','SizeOf void pointer is passed.');
498                     SCB_CleanDCache_by_Addr((uint32_t *)msgPtr,(int32_t)sizeof(msgPtr));
499                 #endif
500 
501                 /* If the channel was acquired, write the message.   */
502                 Cy_IPC_Drv_WriteDataValue(toEp->ipcPtr, (uint32_t) msgPtr);
503 
504                 /* Set the busy flag.  The ISR clears this after the release */
505                 fromEp->busy = CY_IPC_PIPE_ENDPOINT_BUSY;
506 
507                 /* Setup release callback function */
508                 fromEp->releaseCallbackPtr = callBackPtr;
509 
510                 /* Cause notify event/interrupt */
511                 Cy_IPC_Drv_AcquireNotify(toEp->ipcPtr, notifyMask);
512 
513                 returnStatus = CY_IPC_PIPE_SUCCESS;
514             }
515             else
516             {
517                 /* Channel was already acquired, return Error */
518                 returnStatus = CY_IPC_PIPE_ERROR_SEND_BUSY;
519             }
520         }
521         else
522         {
523             /* Channel may not be acquired, but the release interrupt has not executed yet */
524             returnStatus = CY_IPC_PIPE_ERROR_SEND_BUSY;
525         }
526     }
527     else
528     {
529         /* Null pipe handle. */
530         returnStatus = CY_IPC_PIPE_ERROR_BAD_HANDLE;
531     }
532     return (returnStatus);
533 }
534 
535 
536 /*******************************************************************************
537 * Function Name: Cy_IPC_Pipe_RegisterCallback
538 ****************************************************************************//**
539 *
540 * This function registers a callback that is called when a message is received
541 * on a pipe.
542 * The client_ID is the same as the index of the callback function array.
543 * The callback may be a real function pointer or NULL if no callback is required.
544 *
545 * \param epAddr
546 * This parameter is the address (or index in the array of endpoint structures)
547 * that designates the endpoint to which you want to add callback functions.
548 *
549 * \param callBackPtr
550 * Pointer to the callback function called when the endpoint has received a message.
551 * If this parameters is NULL current callback will be unregistered.
552 *
553 * \param clientId
554 * The index in the callback array (Client ID) where the function pointer is saved.
555 *
556 * \return
557 *    CY_IPC_PIPE_SUCCESS:           Callback registered successfully
558 *    CY_IPC_PIPE_ERROR_BAD_CLIENT:  Client ID out of range, callback not registered.
559 *
560 * \funcusage
561 * \snippet ipc/snippet/main.c snippet_myAcquireCallback
562 * \snippet ipc/snippet/main.c snippet_Cy_IPC_Pipe_RegisterCallback
563 *
564 *******************************************************************************/
Cy_IPC_Pipe_RegisterCallback(uint32_t epAddr,cy_ipc_pipe_callback_ptr_t callBackPtr,uint32_t clientId)565 cy_en_ipc_pipe_status_t Cy_IPC_Pipe_RegisterCallback(uint32_t epAddr, cy_ipc_pipe_callback_ptr_t callBackPtr,  uint32_t clientId)
566 {
567     cy_en_ipc_pipe_status_t returnStatus;
568     cy_stc_ipc_pipe_ep_t * thisEp;
569 
570     CY_ASSERT_L1(NULL != cy_ipc_pipe_epArray);
571 
572     thisEp = &cy_ipc_pipe_epArray[epAddr];
573 
574     CY_ASSERT_L1(NULL != thisEp->callbackArray);
575 
576     /* Check if clientId is between 0 and less than client count */
577     if (clientId < thisEp->clientCount)
578     {
579         /* Copy callback function into callback function pointer array */
580         thisEp->callbackArray[clientId] = callBackPtr;
581 
582         returnStatus = CY_IPC_PIPE_SUCCESS;
583     }
584     else
585     {
586         returnStatus = CY_IPC_PIPE_ERROR_BAD_CLIENT;
587     }
588     return (returnStatus);
589 }
590 
591 
592 /*******************************************************************************
593 * Function Name: Cy_IPC_Pipe_RegisterCallbackRel
594 ****************************************************************************//**
595 *
596 * This function registers a default callback if a release interrupt
597 * is generated but the current release callback function is null.
598 *
599 *
600 * \param epAddr
601 * This parameter is the address (or index in the array of endpoint structures)
602 * that designates the endpoint to which you want to add a release callback function.
603 *
604 * \param callBackPtr
605 * Pointer to the callback executed when the endpoint has received a message.
606 * If this parameters is NULL current callback will be unregistered.
607 *
608 * \return
609 *    None
610 *
611 * \funcusage
612 * \snippet ipc/snippet/main.c snippet_myDefaultReleaseCallback
613 * \snippet ipc/snippet/main.c snippet_Cy_IPC_Pipe_RegisterCallbackRel
614 *
615 *******************************************************************************/
Cy_IPC_Pipe_RegisterCallbackRel(uint32_t epAddr,cy_ipc_pipe_relcallback_ptr_t callBackPtr)616 void Cy_IPC_Pipe_RegisterCallbackRel(uint32_t epAddr, cy_ipc_pipe_relcallback_ptr_t callBackPtr)
617 {
618     cy_stc_ipc_pipe_ep_t * endpoint;
619 
620     CY_ASSERT_L1(NULL != cy_ipc_pipe_epArray);
621 
622     endpoint = &cy_ipc_pipe_epArray[epAddr];
623 
624     /* Copy callback function into callback function pointer array */
625     endpoint->defaultReleaseCallbackPtr = callBackPtr;
626 }
627 
628 
629 /*******************************************************************************
630 * Function Name: Cy_IPC_Pipe_ExecuteCallback
631 ****************************************************************************//**
632 *
633 * This function is called by the ISR for a given pipe endpoint to dispatch
634 * the appropriate callback function based on the client ID for that endpoint.
635 *
636 * \param epAddr
637 * This parameter is the address (or index in the array of endpoint structures)
638 * that designates the endpoint to process.
639 *
640 * \note This function should be used instead of obsolete
641 *       Cy_IPC_Pipe_ExecCallback() function because it will be removed in the
642 *       next releases.
643 *
644 * \funcusage
645 * \snippet ipc/snippet/main.c snippet_myIpcPipeEpArray
646 * \snippet ipc/snippet/main.c snippet_Cy_IPC_Pipe_ExecuteCallback
647 *
648 *******************************************************************************/
Cy_IPC_Pipe_ExecuteCallback(uint32_t epAddr)649 void Cy_IPC_Pipe_ExecuteCallback(uint32_t epAddr)
650 {
651     cy_stc_ipc_pipe_ep_t * endpoint;
652 
653     CY_ASSERT_L1(NULL != cy_ipc_pipe_epArray);
654 
655     endpoint = &cy_ipc_pipe_epArray[epAddr];
656 
657     Cy_IPC_Pipe_ExecCallback(endpoint);
658 }
659 
660 
661 /*******************************************************************************
662 * Function Name: Cy_IPC_Pipe_ExecCallback
663 ****************************************************************************//**
664 *
665 * This function is called by the ISR for a given pipe endpoint to dispatch
666 * the appropriate callback function based on the client ID for that endpoint.
667 *
668 * \param endpoint
669 * Pointer to endpoint structure.
670 *
671 * \note This function is obsolete and will be removed in the next releases.
672 *       Please use Cy_IPC_Pipe_ExecuteCallback() instead.
673 *
674 *******************************************************************************/
Cy_IPC_Pipe_ExecCallback(cy_stc_ipc_pipe_ep_t * endpoint)675 void Cy_IPC_Pipe_ExecCallback(cy_stc_ipc_pipe_ep_t * endpoint)
676 {
677     uint32_t *msgPtr = NULL;
678     uint32_t *msgTempPtr = NULL;
679     uint32_t clientID;
680     uint32_t shadowIntr;
681     uint32_t releaseMask = (uint32_t)0;
682 
683     cy_ipc_pipe_callback_ptr_t callbackPtr;
684 
685     /* Parameters checking begin */
686     CY_ASSERT_L1(NULL != endpoint);
687     CY_ASSERT_L1(NULL != endpoint->ipcPtr);
688     CY_ASSERT_L1(NULL != endpoint->ipcIntrPtr);
689     CY_ASSERT_L1(NULL != endpoint->callbackArray);
690     /* Parameters checking end */
691 
692     shadowIntr = Cy_IPC_Drv_GetInterruptStatusMasked(endpoint->ipcIntrPtr);
693 
694     /* Check to make sure the interrupt was a notify interrupt */
695     if (0UL != Cy_IPC_Drv_ExtractAcquireMask(shadowIntr))
696     {
697         /* Clear the notify interrupt.  */
698         Cy_IPC_Drv_ClearInterrupt(endpoint->ipcIntrPtr, CY_IPC_NO_NOTIFICATION, Cy_IPC_Drv_ExtractAcquireMask(shadowIntr));
699 
700         if ( Cy_IPC_Drv_IsLockAcquired (endpoint->ipcPtr) )
701         {
702             /* Extract Client ID  */
703             if( CY_IPC_DRV_SUCCESS == Cy_IPC_Drv_ReadMsgPtr (endpoint->ipcPtr, (void **)&msgTempPtr))
704             {
705                 msgPtr = (uint32_t *)GET_ALIAS_ADDRESS(msgTempPtr);
706                 #if (defined (CY_CPU_CORTEX_M7) && CY_CPU_CORTEX_M7) && (defined (CY_IP_M7CPUSS))
707                     SCB_InvalidateDCache_by_Addr(msgPtr, (int32_t)sizeof(*msgPtr));
708                 #endif
709 
710                 /* Get release mask */
711                 releaseMask = _FLD2VAL(CY_IPC_PIPE_MSG_RELEASE, *msgPtr);
712                 clientID    = _FLD2VAL(CY_IPC_PIPE_MSG_CLIENT,  *msgPtr);
713 
714                 /* Make sure client ID is within valid range */
715                 if (endpoint->clientCount > clientID)
716                 {
717                     callbackPtr = endpoint->callbackArray[clientID];  /* Get the callback function */
718 
719                     if (callbackPtr != NULL)
720                     {
721                         callbackPtr(msgPtr);   /* Call the function pointer for "clientID" */
722                     }
723                 }
724             }
725 
726             /* Must always release the IPC channel */
727             (void)Cy_IPC_Drv_LockRelease (endpoint->ipcPtr, releaseMask);
728         }
729     }
730 
731     /* Check to make sure the interrupt was a release interrupt */
732     if (0UL != Cy_IPC_Drv_ExtractReleaseMask(shadowIntr))  /* Check for a Release interrupt */
733     {
734         /* Clear the release interrupt  */
735         Cy_IPC_Drv_ClearInterrupt(endpoint->ipcIntrPtr, Cy_IPC_Drv_ExtractReleaseMask(shadowIntr), CY_IPC_NO_NOTIFICATION);
736 
737         if (endpoint->releaseCallbackPtr != NULL)
738         {
739             endpoint->releaseCallbackPtr();
740 
741             /* Clear the pointer after it was called */
742             endpoint->releaseCallbackPtr = NULL;
743         }
744         else
745         {
746             if (endpoint->defaultReleaseCallbackPtr != NULL)
747             {
748                 endpoint->defaultReleaseCallbackPtr();
749             }
750         }
751 
752         /* Clear the busy flag when release is detected */
753         endpoint->busy = CY_IPC_PIPE_ENDPOINT_NOTBUSY;
754     }
755 
756     (void)Cy_IPC_Drv_GetInterruptStatus(endpoint->ipcIntrPtr);
757 }
758 
759 
760 /*******************************************************************************
761 * Function Name: Cy_IPC_Pipe_EndpointPause
762 ****************************************************************************//**
763 *
764 * This function sets the receiver endpoint to paused state.
765 *
766 * \param epAddr
767 * This parameter is the address (or index in the array of endpoint structures)
768 * that designates the endpoint to pause.
769 *
770 * \return
771 *    CY_IPC_PIPE_SUCCESS:           Callback registered successfully
772 *
773 * \funcusage
774 * \snippet ipc/snippet/main.c snippet_Cy_IPC_Pipe_EndpointPauseResume
775 *
776 *******************************************************************************/
Cy_IPC_Pipe_EndpointPause(uint32_t epAddr)777 cy_en_ipc_pipe_status_t Cy_IPC_Pipe_EndpointPause(uint32_t epAddr)
778 {
779     cy_stc_ipc_pipe_ep_t * endpoint;
780 
781     CY_ASSERT_L1(NULL != cy_ipc_pipe_epArray);
782 
783     endpoint = &cy_ipc_pipe_epArray[epAddr];
784 
785     /* Disable the interrupts */
786     NVIC_DisableIRQ(endpoint->pipeIntrSrc);
787 
788     return (CY_IPC_PIPE_SUCCESS);
789 }
790 
791 
792 /*******************************************************************************
793 * Function Name: Cy_IPC_Pipe_EndpointResume
794 ****************************************************************************//**
795 *
796 * This function sets the receiver endpoint to active state.
797 *
798 * \param epAddr
799 * This parameter is the address (or index in the array of endpoint structures)
800 * that designates the endpoint to resume.
801 *
802 * \return
803 *    CY_IPC_PIPE_SUCCESS:           Callback registered successfully
804 *
805 * \funcusage
806 * \snippet ipc/snippet/main.c snippet_Cy_IPC_Pipe_EndpointPauseResume
807 *
808 *******************************************************************************/
Cy_IPC_Pipe_EndpointResume(uint32_t epAddr)809 cy_en_ipc_pipe_status_t Cy_IPC_Pipe_EndpointResume(uint32_t epAddr)
810 {
811     cy_stc_ipc_pipe_ep_t * endpoint;
812 
813     CY_ASSERT_L1(NULL != cy_ipc_pipe_epArray);
814 
815     endpoint = &cy_ipc_pipe_epArray[epAddr];
816 
817     /* Enable the interrupts */
818     NVIC_EnableIRQ(endpoint->pipeIntrSrc);
819 
820     return (CY_IPC_PIPE_SUCCESS);
821 }
822 CY_MISRA_BLOCK_END('MISRA C-2012 Rule 10.8')
823 #endif
824 /* [] END OF FILE */
825