From c3e4c9a25c2910d2d66d52215b3406b13d5b23d5 Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Sun, 29 Jun 2014 12:34:32 +0300 Subject: Add more board models --- boards/dk-tm4c129x/freertos_demo/spider_task.c | 855 +++++++++++++++++++++++++ 1 file changed, 855 insertions(+) create mode 100644 boards/dk-tm4c129x/freertos_demo/spider_task.c (limited to 'boards/dk-tm4c129x/freertos_demo/spider_task.c') diff --git a/boards/dk-tm4c129x/freertos_demo/spider_task.c b/boards/dk-tm4c129x/freertos_demo/spider_task.c new file mode 100644 index 0000000..2f530c0 --- /dev/null +++ b/boards/dk-tm4c129x/freertos_demo/spider_task.c @@ -0,0 +1,855 @@ +//***************************************************************************** +// +// spider_task.c - Tasks to animate a set of spiders on the LCD, one task per +// spider. +// +// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved. +// Software License Agreement +// +// Texas Instruments (TI) is supplying this software for use solely and +// exclusively on TI's microcontroller products. The software is owned by +// TI and/or its suppliers, and is protected under applicable copyright +// laws. You may not combine this software with "viral" open-source +// software in order to form a larger program. +// +// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. +// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT +// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY +// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL +// DAMAGES, FOR ANY REASON WHATSOEVER. +// +// This is part of revision 2.1.0.12573 of the DK-TM4C129X Firmware Package. +// +//***************************************************************************** + +#include +#include +#include "inc/hw_ints.h" +#include "inc/hw_types.h" +#include "driverlib/interrupt.h" +#include "grlib/grlib.h" +#include "grlib/widget.h" +#include "drivers/touch.h" +#include "display_task.h" +#include "idle_task.h" +#include "images.h" +#include "priorities.h" +#include "random.h" +#include "freertos_demo.h" +#include "spider_task.h" +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" +//***************************************************************************** +// +// The stack size for the spider control task. +// +//***************************************************************************** +# define STACKSIZE_CONTROLTASK 128 + +//***************************************************************************** +// +// The stack sizes for the spider tasks. +// +//***************************************************************************** +# define STACKSIZE_SPIDERTASK 128 + +//***************************************************************************** +// +// The following define the screen area in which the spiders are allowed to +// roam +// +//***************************************************************************** +#define AREA_X 8 +#define AREA_Y 24 +#define AREA_WIDTH 303 +#define AREA_HEIGHT (231 - 24 - 20) + +//***************************************************************************** +// +// The size of the spider images. +// +//***************************************************************************** +#define SPIDER_WIDTH 24 +#define SPIDER_HEIGHT 24 + +//***************************************************************************** +// +// The following define the extents of the centroid of the spiders. +// +//***************************************************************************** +#define SPIDER_MIN_X (AREA_X + (SPIDER_WIDTH / 2)) +#define SPIDER_MAX_X (AREA_X + AREA_WIDTH - (SPIDER_WIDTH / 2)) +#define SPIDER_MIN_Y (AREA_Y + (SPIDER_HEIGHT / 2)) +#define SPIDER_MAX_Y (AREA_Y + AREA_HEIGHT - (SPIDER_HEIGHT / 2)) + +//***************************************************************************** +// +// The item size, queue size, and memory size for the spider control message +// queue. +// +//***************************************************************************** +#define CONTROL_ITEM_SIZE sizeof(unsigned long) +#define CONTROL_QUEUE_SIZE 10 + +//***************************************************************************** +// +// The queue that holds messages sent to the spider control task. +// +//***************************************************************************** +static xQueueHandle g_pControlQueue; + +//***************************************************************************** +// +// The amount the spider moves horizontally for each direction of movement. +// +// For this and all subsequent arrays that are indexed by direction of +// movement, the indices are as follows: +// +// 0 => right +// 1 => right and down +// 2 => down +// 3 => left and down +// 4 => left +// 5 => left and up +// 6 => up +// 7 => right and up +// +//***************************************************************************** +static const int32_t g_pi32SpiderStepX[8] = +{ + 1, 1, 0, -1, -1, -1, 0, 1 +}; + +//***************************************************************************** +// +// The amount the spider moves vertically for each direction of movement. +// +//***************************************************************************** +static const int32_t g_pi32SpiderStepY[8] = +{ + 0, 1, 1, 1, 0, -1, -1, -1 +}; + +//***************************************************************************** +// +// The animation images for the spider, two per direction of movement. In +// other words, entries 0 and 1 correspond to direction 0 (right), entries 2 +// and 3 correspond to direction 1 (right and down), etc. +// +//***************************************************************************** +static const uint8_t *g_ppui8SpiderImage[16] = +{ + g_pui8SpiderR1Image, + g_pui8SpiderR2Image, + g_pui8SpiderDR1Image, + g_pui8SpiderDR2Image, + g_pui8SpiderD1Image, + g_pui8SpiderD2Image, + g_pui8SpiderDL1Image, + g_pui8SpiderDL2Image, + g_pui8SpiderL1Image, + g_pui8SpiderL2Image, + g_pui8SpiderUL1Image, + g_pui8SpiderUL2Image, + g_pui8SpiderU1Image, + g_pui8SpiderU2Image, + g_pui8SpiderUR1Image, + g_pui8SpiderUR2Image +}; + +//***************************************************************************** +// +// The number of ticks to delay a spider task based on the direction of +// movement. This array has only two entries; the first corresponding to +// horizontal and vertical movement, and the second corresponding to diagonal +// movement. By having the second entry be 1.4 times the first, the spiders +// are updated slower when moving along the diagonal to compensate for the +// fact that each step is further (since it is moving one step in both the +// horizontal and vertical). +// +//***************************************************************************** +uint32_t g_pui32SpiderDelay[2]; + +//***************************************************************************** +// +// The horizontal position of the spiders. +// +//***************************************************************************** +static int32_t g_pi32SpiderX[MAX_SPIDERS]; + +//***************************************************************************** +// +// The vertical position of the spiders. +// +//***************************************************************************** +static int32_t g_pi32SpiderY[MAX_SPIDERS]; + +//***************************************************************************** +// +// A bitmap that indicates which spiders are alive (which corresponds to a +// running task for that spider). +// +//***************************************************************************** +static uint32_t g_ui32SpiderAlive; + +//***************************************************************************** +// +// A bitmap that indicates which spiders have been killed (by touching them). +// +//***************************************************************************** +static uint32_t g_ui32SpiderDead; +xTaskHandle g_sSpiderTask; // FIXME +//***************************************************************************** +// +// Determines if a given point collides with one of the spiders. The spider +// specified is ignored when doing collision detection in order to prevent a +// false collision with itself (when checking to see if it is safe to move the +// spider). +// +//***************************************************************************** +static int32_t +SpiderCollide(int32_t i32Spider, int32_t i32X, int32_t i32Y) +{ + int32_t i32Idx, i32DX, i32DY; + + // + // Loop through all the spiders. + // + for(i32Idx = 0; i32Idx < MAX_SPIDERS; i32Idx++) + { + // + // Skip this spider if it is not alive or is the spider that should be + // ignored. + // + if((HWREGBITW(&g_ui32SpiderAlive, i32Idx) == 0) || + (i32Idx == i32Spider)) + { + continue; + } + + // + // Compute the horizontal and vertical difference between this spider's + // position and the point in question. + // + i32DX = ((g_pi32SpiderX[i32Idx] > i32X) ? + (g_pi32SpiderX[i32Idx] - i32X) : + (i32X - g_pi32SpiderX[i32Idx])); + i32DY = ((g_pi32SpiderY[i32Idx] > i32Y) ? + (g_pi32SpiderY[i32Idx] - i32Y) : + (i32Y - g_pi32SpiderY[i32Idx])); + + // + // Return this spider index if the point in question collides with it. + // + if((i32DX < SPIDER_WIDTH) && (i32DY < SPIDER_HEIGHT)) + { + return(i32Idx); + } + } + + // + // No collision was detected. + // + return(-1); +} + +//***************************************************************************** +// +// This task manages the scurrying about of a spider. +// +//***************************************************************************** +static void +SpiderTask(void *pvParameters) +{ + uint32_t ui32Dir, ui32Image, ui32Temp; + int32_t i32X, i32Y, i32Spider; + + // + // Get the spider number from the parameter. + // + i32Spider = (long)pvParameters; + + // + // Add the current tick count to the random entropy pool. + // + RandomAddEntropy(xTaskGetTickCount()); + + // + // Reseed the random number generator. + // + RandomSeed(); + + // + // Indicate that this spider is alive. + // + HWREGBITW(&g_ui32SpiderAlive, i32Spider) = 1; + + // + // Indicate that this spider is not dead yet. + // + HWREGBITW(&g_ui32SpiderDead, i32Spider) = 0; + + // + // Get a local copy of the spider's starting position. + // + i32X = g_pi32SpiderX[i32Spider]; + i32Y = g_pi32SpiderY[i32Spider]; + + // + // Choose a random starting direction for the spider. + // + ui32Dir = RandomNumber() >> 29; + + // + // Start by displaying the first of the two spider animation images. + // + ui32Image = 0; + + // + // Loop forever. + // + while(1) + { + // + // See if this spider has been killed. + // + if(HWREGBITW(&g_ui32SpiderDead, i32Spider) == 1) + { + // + // Wait for 2 seconds. + // + vTaskDelay((1000 / portTICK_RATE_MS) * 2); + + // + // Clear the spider from the display. + // + DisplayImage(i32X - (SPIDER_WIDTH / 2), i32Y - (SPIDER_HEIGHT / 2), + g_pui8SpiderBlankImage); + + // + // Indicate that this spider is not alive. + // + HWREGBITW(&g_ui32SpiderAlive, i32Spider) = 0; + + // + // Delete the current task. This should never return. + // + vTaskDelete(NULL); + + // + // In case it does return, loop forever. + // + while(1) + { + } + } + + // + // Enter a critical section while the next move for the spider is + // determined. Having more than one spider trying to move at a time + // (via preemption) would make the collision detection check fail. + // + taskENTER_CRITICAL(); + + // + // Move the spider. + // + i32X += g_pi32SpiderStepX[ui32Dir]; + i32Y += g_pi32SpiderStepY[ui32Dir]; + + // + // See if the spider has cross the boundary of its area, if it has + // collided with another spider, or if random chance says that the + // spider should turn despite not having collided with anything. + // + if((i32X < SPIDER_MIN_X) || (i32X > SPIDER_MAX_X) || + (i32Y < SPIDER_MIN_Y) || (i32Y > SPIDER_MAX_Y) || + (SpiderCollide(i32Spider, i32X, i32Y) != -1) || + (RandomNumber() < 0x08000000)) + { + // + // Undo the previous movement of the spider. + // + i32X -= g_pi32SpiderStepX[ui32Dir]; + i32Y -= g_pi32SpiderStepY[ui32Dir]; + + // + // Get a random number to determine the turn to be made. + // + ui32Temp = RandomNumber(); + + // + // Determine how to turn the spider based on the random number. + // Half the time the spider turns to the left and half the time it + // turns to the right. Of each half, it turns a quarter of a turn + // 12.5% of the time and an eighth of a turn 87.5% of the time. + // + if(ui32Temp < 0x10000000) + { + ui32Dir = (ui32Dir + 2) & 7; + } + else if(ui32Temp < 0x80000000) + { + ui32Dir = (ui32Dir + 1) & 7; + } + else if(ui32Temp < 0xf0000000) + { + ui32Dir = (ui32Dir - 1) & 7; + } + else + { + ui32Dir = (ui32Dir - 2) & 7; + } + } + + // + // Update the position of the spider. + // + g_pi32SpiderX[i32Spider] = i32X; + g_pi32SpiderY[i32Spider] = i32Y; + + // + // Exit the critical section now that the spider has been moved. + // + taskEXIT_CRITICAL(); + + // + // Have the display task draw the spider at the new position. Since + // there is a one pixel empty border around all the images, and the + // position of the spider is incremented by only one pixel, this also + // erases any traces of the spider in its previous position. + // + DisplayImage(i32X - (SPIDER_WIDTH / 2), i32Y - (SPIDER_HEIGHT / 2), + g_ppui8SpiderImage[(ui32Dir * 2) + ui32Image]); + + // + // Toggle the spider animation index. + // + ui32Image ^= 1; + + // + // Delay this task for an amount of time based on the direction the + // spider is moving. + // + vTaskDelay(g_pui32SpiderDelay[ui32Dir & 1]); + + // + // Add the new tick count to the random entropy pool. + // + RandomAddEntropy(xTaskGetTickCount()); + + // + // Reseed the random number generator. + // + RandomSeed(); + } +} + +//***************************************************************************** +// +// Creates a spider task. +// +//***************************************************************************** +static uint32_t +CreateSpider(int32_t i32X, int32_t i32Y) +{ + uint32_t ui32Spider; + + // + // Search to see if there is a spider task available. + // + for(ui32Spider = 0; ui32Spider < MAX_SPIDERS; ui32Spider++) + { + if(HWREGBITW(&g_ui32SpiderAlive, ui32Spider) == 0) + { + break; + } + } + + // + // Return a failure if no spider tasks are available (in other words, the + // maximum number of spiders are already alive). + // + if(ui32Spider == MAX_SPIDERS) + { + return(1); + } + + // + // Adjust the starting horizontal position to make sure it is inside the + // allowable area for the spiders. + // + if(i32X < SPIDER_MIN_X) + { + i32X = SPIDER_MIN_X; + } + else if(i32X > SPIDER_MAX_X) + { + i32X = SPIDER_MAX_X; + } + + // + // Adjust the starting vertical position to make sure it is inside the + // allowable area for the spiders. + // + if(i32Y < SPIDER_MIN_Y) + { + i32Y = SPIDER_MIN_Y; + } + else if(i32Y > SPIDER_MAX_Y) + { + i32Y = SPIDER_MAX_Y; + } + + // + // Save the starting position for this spider. + // + g_pi32SpiderX[ui32Spider] = i32X; + g_pi32SpiderY[ui32Spider] = i32Y; + + // + // Create a task to animate this spider. + // + if(xTaskCreate(SpiderTask, (signed portCHAR *)"Spider", + STACKSIZE_SPIDERTASK, (void *)ui32Spider, + tskIDLE_PRIORITY + PRIORITY_SPIDER_TASK, NULL) != pdTRUE) + { + return(1); + } + + // + // Success. + // + return(0); +} + +//***************************************************************************** +// +// The callback function for messages from the touch screen driver. +// +//***************************************************************************** +static int32_t +ControlTouchCallback(uint32_t ui32Message, int32_t i32X, int32_t i32Y) +{ + portBASE_TYPE bTaskWaken; + + // + // Ignore all messages other than pointer down messages. + // + if(ui32Message != WIDGET_MSG_PTR_DOWN) + { + return(0); + } + + // + // Pack the position into a message to send to the spider control task. + // + ui32Message = ((i32X & 65535) << 16) | (i32Y & 65535); + + // + // Send the position message to the spider control task. + // + xQueueSendFromISR(g_pControlQueue, &ui32Message, &bTaskWaken); + + // + // Perform a task yield if necessary. + // +#if defined(__Check_Later) + taskYIELD_FROM_ISR(bTaskWaken); +#endif + + // + // This message has been handled. + // + return(0); +} + +//***************************************************************************** +// +// Determines if a given touch screen point collides with one of the spiders. +// +//***************************************************************************** +static int32_t +SpiderTouchCollide(int32_t i32X, int32_t i32Y) +{ + int32_t i32Idx, i32DX, i32DY, i32Best, i32Dist; + + // + // Until a collision is found, there is no best spider choice. + // + i32Best = -1; + i32Dist = 1000000; + + // + // Loop through all the spiders. + // + for(i32Idx = 0; i32Idx < MAX_SPIDERS; i32Idx++) + { + // + // Skip this spider if it is not alive. + // + if((HWREGBITW(&g_ui32SpiderAlive, i32Idx) == 0) || + (HWREGBITW(&g_ui32SpiderDead, i32Idx) == 1)) + { + continue; + } + + // + // Compute the horizontal and vertical difference between this spider's + // position and the point in question. + // + i32DX = ((g_pi32SpiderX[i32Idx] > i32X) ? + (g_pi32SpiderX[i32Idx] - i32X) : + (i32X - g_pi32SpiderX[i32Idx])); + i32DY = ((g_pi32SpiderY[i32Idx] > i32Y) ? + (g_pi32SpiderY[i32Idx] - i32Y) : + (i32Y - g_pi32SpiderY[i32Idx])); + + // + // See if the point in question collides with this spider. + // + if((i32DX < (SPIDER_WIDTH + 4)) && (i32DY < (SPIDER_HEIGHT + 4))) + { + // + // Compute distance (squared) between this point and the spider. + // + i32DX = (i32DX * i32DX) + (i32DY * i32DY); + + // + // See if this spider is closer to the point in question than any + // other spider encountered. + // + if(i32DX < i32Dist) + { + // + // Save this spider as the new best choice. + // + i32Best = i32Idx; + i32Dist = i32DX; + } + } + } + + // + // Return the best choice, if one was found. + // + if(i32Best != -1) + { + return(i32Best); + } + + // + // Loop through all the spiders. This time, the spiders that are dead but + // not cleared from the screen are not ignored. + // + for(i32Idx = 0; i32Idx < MAX_SPIDERS; i32Idx++) + { + // + // Skip this spider if it is not alive. + // + if(HWREGBITW(&g_ui32SpiderAlive, i32Idx) == 0) + { + continue; + } + + // + // Compute the horizontal and vertical difference between this spider's + // position and the point in question. + // + i32DX = ((g_pi32SpiderX[i32Idx] > i32X) ? + (g_pi32SpiderX[i32Idx] - i32X) : + (i32X - g_pi32SpiderX[i32Idx])); + i32DY = ((g_pi32SpiderY[i32Idx] > i32Y) ? + (g_pi32SpiderY[i32Idx] - i32Y) : + (i32Y - g_pi32SpiderY[i32Idx])); + + // + // See if the point in question collides with this spider. + // + if((i32DX < (SPIDER_WIDTH + 4)) && (i32DY < (SPIDER_HEIGHT + 4))) + { + // + // Compute distance (squared) between this point and the spider. + // + i32DX = (i32DX * i32DX) + (i32DY * i32DY); + + // + // See if this spider is closer to the point in question than any + // other spider encountered. + // + if(i32DX < i32Dist) + { + // + // Save this spider as the new best choice. + // + i32Best = i32Idx; + i32Dist = i32DX; + } + } + } + + // + // Return the best choice, if one was found. + // + return(i32Best); +} + +//***************************************************************************** +// +// This task provides overall control of the spiders, spawning and killing them +// in response to presses on the touch screen. +// +//***************************************************************************** +static void +ControlTask(void *pvParameters) +{ + uint32_t ui32Message; + int32_t i32X, i32Y, i32Spider; + + // + // Initialize the touch screen driver and register a callback function. + // + TouchScreenInit(g_ui32SysClock); + TouchScreenCallbackSet(ControlTouchCallback); + + // + // Lower the priority of the touch screen interrupt handler. This is + // required so that the interrupt handler can safely call the interrupt- + // safe FreeRTOS functions (specifically to send messages to the queue). + // + IntPrioritySet(INT_ADC0SS3, 0xc0); + + // + // Loop forever. + // + while(1) + { + // + // Read the next message from the queue. + // + if(xQueueReceive(g_pControlQueue, &ui32Message, portMAX_DELAY) == + pdPASS) + { + // + // Extract the position of the screen touch from the message. + // + i32X = ui32Message >> 16; + i32Y = ui32Message & 65535; + + // + // Ignore this screen touch if it is not inside the spider area. + // + if((i32X >= AREA_X) && (i32X < (AREA_X + AREA_WIDTH)) && + (i32Y >= AREA_Y) && (i32Y < (AREA_Y + AREA_HEIGHT))) + { + // + // See if this position collides with any of the spiders. + // + i32Spider = SpiderTouchCollide(i32X, i32Y); + if(i32Spider == -1) + { + // + // There is no collision, so create a new spider (if + // possible) at this position. + // + CreateSpider(i32X, i32Y); + } + else + { + // + // There is a collision, so kill this spider. + // + HWREGBITW(&g_ui32SpiderDead, i32Spider) = 1; + } + } + } + } +} + +//***************************************************************************** +// +// Sets the speed of the spiders by specifying the number of milliseconds +// between updates to the spider's position. +// +//***************************************************************************** +void +SpiderSpeedSet(uint32_t ui32Speed) +{ + // + // Convert the update rate from milliseconds to ticks. The second entry + // of the array is 1.4 times the first so that updates when moving along + // the diagonal, which are longer steps, are done less frequently by a + // proportional amount. + // + g_pui32SpiderDelay[0] = (ui32Speed * (1000 / portTICK_RATE_MS)) / 1000; + g_pui32SpiderDelay[1] = (ui32Speed * 14 * (1000 / portTICK_RATE_MS)) / + 10000; +} + +//***************************************************************************** +// +// Initializes the spider tasks. +// +//***************************************************************************** +uint32_t +SpiderTaskInit(void) +{ + uint32_t ui32Idx; + + // + // Set the initial speed of the spiders. + // + SpiderSpeedSet(10); + + // + // Create a queue for sending messages to the spider control task. + // + g_pControlQueue = xQueueCreate(CONTROL_QUEUE_SIZE, CONTROL_QUEUE_SIZE); + if(g_pControlQueue == NULL) + { + return(1); + } + + // + // Create the spider control task. + // + if(xTaskCreate(ControlTask, (signed portCHAR *)"ControlTask", + STACKSIZE_CONTROLTASK, NULL, + tskIDLE_PRIORITY + PRIORITY_CONTROL_TASK, &g_sSpiderTask) != pdTRUE) + {// FIXME + return(1); + } + + // + // Create eight spiders initially. + // + for(ui32Idx = 0; ui32Idx < 8; ui32Idx++) + { + // + // Create a spider that is centered vertically and equally spaced + // horizontally across the display. + // + if(CreateSpider((ui32Idx * (AREA_WIDTH / 8)) + (AREA_WIDTH / 16), + (AREA_HEIGHT / 2) + AREA_Y) == 1) + { + return(1); + } + + // + // Provide an early indication that this spider is alive. The task is + // not running yet (since this function is called before the scheduler + // has been started) so this variable is not set by the task (yet). + // Manually setting it allows the remaining initial spiders to be + // created properly. + // + HWREGBITW(&g_ui32SpiderAlive, ui32Idx) = 1; + } + + // + // Success. + // + return(0); +} -- cgit v1.3.1