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