--- /dev/null
+/*\r
+ * FreeRTOS Kernel V10.0.0\r
+ * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
+ * this software and associated documentation files (the "Software"), to deal in\r
+ * the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
+ * the Software, and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all\r
+ * copies or substantial portions of the Software. If you wish to use our Amazon\r
+ * FreeRTOS name, please do so in a fair use way that does not cause confusion.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ * http://www.FreeRTOS.org\r
+ * http://aws.amazon.com/freertos\r
+ *\r
+ * 1 tab == 4 spaces!\r
+ */\r
+\r
+/*\r
+ * An example that mimics a message buffer being used to pass data from one core\r
+ * to another. The core that sends the data is referred to as core A. The core\r
+ * that receives the data is referred to as core B. The task implemented by\r
+ * prvCoreATask() runs on core A. Two instances of the task implemented by\r
+ * prvCoreBTasks() run on core B. prvCoreATask() sends messages via message\r
+ * buffers to both instances of prvCoreBTasks(), one message buffer per channel.\r
+ * A third message buffer is used to pass the handle of the message buffer\r
+ * written to by core A to an interrupt service routine that is triggered by\r
+ * core A but executes on core B.\r
+ *\r
+ * The example relies on the FreeRTOS provided default implementation of\r
+ * sbSEND_COMPLETED() being overridden by an implementation in FreeRTOSConfig.h\r
+ * that writes the handle of the message buffer that contains data into the\r
+ * control message buffer, then generates an interrupt in core B. The necessary\r
+ * implementation is provided in this file and can be enabled by adding the\r
+ * following to FreeRTOSConfig.h:\r
+ *\r
+ * #define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer )\r
+ *\r
+ * Core to core communication via message buffer requires the message buffers\r
+ * to be at an address known to both cores within shared memory.\r
+ *\r
+ * Note that, while this example uses three message buffers, the same\r
+ * functionality can be implemented using a single message buffer by using the\r
+ * same design pattern described on the link below for queues, but using message\r
+ * buffers instead. It is actually simpler with a message buffer as variable\r
+ * length data can be written into the message buffer directly:\r
+ * http://www.freertos.org/Pend-on-multiple-rtos-objects.html#alternative_design_pattern\r
+ */\r
+\r
+/* Standard includes. */\r
+#include "stdio.h"\r
+#include "string.h"\r
+\r
+/* FreeRTOS includes. */\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+#include "message_buffer.h"\r
+\r
+/* Demo app includes. */\r
+#include "MessageBufferAMP.h"\r
+\r
+/* Enough for 3 4 byte pointers, including the additional 4 bytes per message\r
+overhead of message buffers. */\r
+#define mbaCONTROL_MESSAGE_BUFFER_SIZE ( 24 )\r
+\r
+/* Enough four 4 8 byte strings, plus the additional 4 bytes per message\r
+overhead of message buffers. */\r
+#define mbaTASK_MESSAGE_BUFFER_SIZE ( 60 )\r
+\r
+/* The number of instances of prvCoreBTasks that are created. */\r
+#define mbaNUMBER_OF_CORE_B_TASKS 2\r
+\r
+/* A block time of 0 simply means, don't block. */\r
+#define mbaDONT_BLOCK 0\r
+\r
+/* Macro that mimics an interrupt service routine executing by simply calling\r
+the routine inline. */\r
+#define mbaGENERATE_CORE_B_INTERRUPT() prvCoreBInterruptHandler()\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/*\r
+ * Implementation of the task that, on a real dual core device, would run on\r
+ * core A and send message to tasks running on core B.\r
+ */\r
+static void prvCoreATask( void *pvParameters );\r
+\r
+/*\r
+ * Implementation of the task that, on a real dual core device, would run on\r
+ * core B and receive message from core A. The demo creates two instances of\r
+ * this task.\r
+ */\r
+static void prvCoreBTasks( void *pvParameters );\r
+\r
+/*\r
+ * The function that, on a real dual core device, would handle inter-core\r
+ * interrupts, but in this case is just called inline.\r
+ */\r
+static void prvCoreBInterruptHandler( void );\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/* The message buffers used to pass data from core A to core B. */\r
+static MessageBufferHandle_t xCoreBMessageBuffers[ mbaNUMBER_OF_CORE_B_TASKS ];\r
+\r
+/* The control message buffer. This is used to pass the handle of the message\r
+message buffer that holds application data into the core to core interrupt\r
+service routine. */\r
+static MessageBufferHandle_t xControlMessageBuffer;\r
+\r
+/* Counters used to indicate to the check that the tasks are still executing. */\r
+static uint32_t ulCycleCounters[ mbaNUMBER_OF_CORE_B_TASKS ];\r
+\r
+/* Set to pdFALSE if any errors are detected. Used to inform the check task\r
+that something might be wrong. */\r
+BaseType_t xDemoStatus = pdPASS;\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+void vStartMessageBufferAMPTasks( void )\r
+{\r
+BaseType_t x;\r
+\r
+ xControlMessageBuffer = xMessageBufferCreate( mbaCONTROL_MESSAGE_BUFFER_SIZE );\r
+\r
+ xTaskCreate( prvCoreATask, /* The function that implements the task. */\r
+ "AMPCoreA", /* Human readable name for the task. */\r
+ configMINIMAL_STACK_SIZE, /* Stack size (in words!). */\r
+ NULL, /* Task parameter is not used. */\r
+ tskIDLE_PRIORITY, /* The priority at which the task is created. */\r
+ NULL ); /* No use for the task handle. */\r
+\r
+ for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )\r
+ {\r
+ xCoreBMessageBuffers[ x ] = xMessageBufferCreate( mbaTASK_MESSAGE_BUFFER_SIZE );\r
+ configASSERT( xCoreBMessageBuffers[ x ] );\r
+\r
+ /* Pass the loop counter into the created task using the task's\r
+ parameter. The task then uses the value as an index into the\r
+ ulCycleCounters and xCoreBMessageBuffers arrays. */\r
+ xTaskCreate( prvCoreBTasks,\r
+ "AMPCoreB1",\r
+ configMINIMAL_STACK_SIZE,\r
+ ( void * ) x,\r
+ tskIDLE_PRIORITY + 1,\r
+ NULL );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvCoreATask( void *pvParameters )\r
+{\r
+BaseType_t x;\r
+uint32_t ulNextValue = 0;\r
+const TickType_t xDelay = pdMS_TO_TICKS( 250 );\r
+char cString[ 15 ]; /* At least large enough to hold "4294967295\0" (0xffffffff). */\r
+\r
+ /* Remove warning about unused parameters. */\r
+ ( void ) pvParameters;\r
+\r
+ for( ;; )\r
+ {\r
+ /* Create the next string to send. The value is incremented on each\r
+ loop iteration, and the length of the string changes as the number of\r
+ digits in the value increases. */\r
+ sprintf( cString, "%lu", ( unsigned long ) ulNextValue );\r
+\r
+ /* Send the value from this (pseudo) Core A to the tasks on the (pseudo)\r
+ Core B via the message buffers. This will result in sbSEND_COMPLETED()\r
+ being executed, which in turn will write the handle of the message\r
+ buffer written to into xControlMessageBuffer then generate an interrupt\r
+ in core B. */\r
+ for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )\r
+ {\r
+ xMessageBufferSend( /* The message buffer to write to. */\r
+ xCoreBMessageBuffers[ x ],\r
+ /* The source of the data to send. */\r
+ ( void * ) cString,\r
+ /* The length of the data to send. */\r
+ strlen( cString ),\r
+ /* The block time, should the buffer be full. */\r
+ mbaDONT_BLOCK );\r
+ }\r
+\r
+ /* Delay before repeating with a different and potentially different\r
+ length string. */\r
+ vTaskDelay( xDelay );\r
+ ulNextValue++;\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvCoreBTasks( void *pvParameters )\r
+{\r
+BaseType_t x;\r
+size_t xReceivedBytes;\r
+uint32_t ulNextValue = 0;\r
+char cExpectedString[ 15 ]; /* At least large enough to hold "4294967295\0" (0xffffffff). */\r
+char cReceivedString[ 15 ];\r
+\r
+ /* The index into the xCoreBMessageBuffers and ulLoopCounter arrays is\r
+ passed into this task using the task's parameter. */\r
+ x = ( BaseType_t ) pvParameters;\r
+ configASSERT( x < mbaNUMBER_OF_CORE_B_TASKS );\r
+\r
+ for( ;; )\r
+ {\r
+ /* Create the string that is expected to be received this time round. */\r
+ sprintf( cExpectedString, "%lu", ( unsigned long ) ulNextValue );\r
+\r
+ /* Wait to receive the next message from core A. */\r
+ memset( cReceivedString, 0x00, sizeof( cReceivedString ) );\r
+ xReceivedBytes = xMessageBufferReceive( /* The message buffer to receive from. */\r
+ xCoreBMessageBuffers[ x ],\r
+ /* Location to store received data. */\r
+ cReceivedString,\r
+ /* Maximum number of bytes to receive. */\r
+ sizeof( cReceivedString ),\r
+ /* Ticks to wait if buffer is empty. */\r
+ portMAX_DELAY );\r
+\r
+ /* Check the number of bytes received was as expected. */\r
+ configASSERT( xReceivedBytes == strlen( cExpectedString ) );\r
+\r
+ /* If the received string matches that expected then increment the loop\r
+ counter so the check task knows this task is still running. */\r
+ if( strcmp( cReceivedString, cExpectedString ) == 0 )\r
+ {\r
+ ( ulCycleCounters[ x ] )++;\r
+ }\r
+ else\r
+ {\r
+ xDemoStatus = pdFAIL;\r
+ }\r
+\r
+ /* Expect the next string in sequence the next time around. */\r
+ ulNextValue++;\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+/* Called by the reimplementation of sbSEND_COMPLETED(), which can be defined\r
+as follows in FreeRTOSConfig.h:\r
+#define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer )\r
+*/\r
+void vGenerateCoreBInterrupt( void * xUpdatedMessageBuffer )\r
+{\r
+MessageBufferHandle_t xUpdatedBuffer = ( MessageBufferHandle_t ) xUpdatedMessageBuffer;\r
+\r
+ /* If sbSEND_COMPLETED() has been implemented as above, then this function\r
+ is called from within xMessageBufferSend(). As this function also calls\r
+ xMessageBufferSend() itself it is necessary to guard against a recursive\r
+ call. If the message buffer just updated is the message buffer written to\r
+ by this function, then this is a recursive call, and the function can just\r
+ exit without taking further action. */\r
+ if( xUpdatedBuffer != xControlMessageBuffer )\r
+ {\r
+ /* Use xControlMessageBuffer to pass the handle of the message buffer\r
+ written to by core A to the interrupt handler about to be generated in\r
+ core B. */\r
+ xMessageBufferSend( xControlMessageBuffer, &xUpdatedBuffer, sizeof( xUpdatedBuffer ), mbaDONT_BLOCK );\r
+\r
+ /* This is where the interrupt would be generated. In this case it is\r
+ not a genuine interrupt handler that executes, just a standard function\r
+ call. */\r
+ mbaGENERATE_CORE_B_INTERRUPT();\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+/* Handler for the interrupts that are triggered on core A but execute on core\r
+B. */\r
+static void prvCoreBInterruptHandler( void )\r
+{\r
+MessageBufferHandle_t xUpdatedMessageBuffer;\r
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
+\r
+ /* xControlMessageBuffer contains the handle of the message buffer that\r
+ contains data. */\r
+ if( xMessageBufferReceive( xControlMessageBuffer,\r
+ &xUpdatedMessageBuffer,\r
+ sizeof( xUpdatedMessageBuffer ),\r
+ mbaDONT_BLOCK ) == sizeof( xUpdatedMessageBuffer ) )\r
+ {\r
+ /* Call the API function that sends a notification to any task that is\r
+ blocked on the xUpdatedMessageBuffer message buffer waiting for data to\r
+ arrive. */\r
+ xMessageBufferSendCompletedFromISR( xUpdatedMessageBuffer, &xHigherPriorityTaskWoken );\r
+ }\r
+\r
+ /* Normal FreeRTOS yield from interrupt semantics, where\r
+ xHigherPriorityTaskWoken is initialzed to pdFALSE and will then get set to\r
+ pdTRUE if the interrupt safe API unblocks a task that has a priority above\r
+ that of the currently executing task. */\r
+ portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+BaseType_t xAreMessageBufferAMPTasksStillRunning( void )\r
+{\r
+static uint32_t ulLastCycleCounters[ mbaNUMBER_OF_CORE_B_TASKS ] = { 0 };\r
+BaseType_t x;\r
+\r
+ /* Called by the check task to determine the health status of the tasks\r
+ implemented in this demo. */\r
+ for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )\r
+ {\r
+ if( ulLastCycleCounters[ x ] == ulCycleCounters[ x ] )\r
+ {\r
+ xDemoStatus = pdFAIL;\r
+ }\r
+ else\r
+ {\r
+ ulLastCycleCounters[ x ] = ulCycleCounters[ x ];\r
+ }\r
+ }\r
+\r
+ return xDemoStatus;\r
+}\r
+\r