• No results found

Chapter 6: Events

6.3 Other Event Services

As with tasks and alarms, an event declaration function declares an event external to a mod-ule.

DeclareEvent(EventIdentifier);

The entry for EventIdentifier is the name of the event as it appears in the OIL configuration file.

6.4 Example Program

At this point, the example program is a fully functional game of Blackjack, which plays as follows.

• When the system first starts, the startup message is displayed.

• Pressing “D” shuffles the cards for the first time and deals the first set of cards.

• An “A” key press hits and a “B” stays.

• The dealer must hit at 16 and stay at 17. Aces count 11 for the dealer unless it causes the dealer to bust, then it counts 1.

• At any time, pressing “D” causes a reshuffle.

• When the hand is complete, pressing “C” deals the next hand. If fewer than 10 cards remain in the deck, the deck is reshuffled first.

Although the program is functionally complete, it has not been optimized, and because it is an example program, I have not included betting, doubling down, or splitting as features.

Example Program

77

You can add this functionality if desired. There is a remote possibility that a change in the program could corrupt the deck of cards so that a card appears twice. This could occur if the deck is being shuffled and a card is dealt through preemption of the shuffling task. I address this problem by making the deck of cards a resource in Chapter 7. In addition, much time is spent sampling inputs, which I address with interrupts in Chapter 8.

6.4.1 Modules

The modules startup.s,initspr.s,cinit.s,init.c,main.c,hw.c, and os.c did not change in this chapter.

debug.c I modified the hook routines PreTaskHook() and PostTaskHook() to measure the time in the background loop. At any point, the system can be stopped and the amount of time that the background task has executed and not executed can be calculated based on ticks of the MPC555 real-time clock. This gives a very good approximation of the amount of idle time in the system. An additional function encapsulates as a 64-bit value the assembly lan-guage instructions required to obtain the real-time clock.

cardgame.c This module has changed extensively in order to support a true card game. A state machine was defined in which the state of the game is modified based on key presses and other events in the system. The ProcessKeyPress task was modified extensively, a number of new functions were added, and the ShufflingComplete task was removed.

ProcessKeyPress task This task was modified extensively to take different actions based on the transition that occurs when a key is pressed. The private function CheckGameTran-sition() determines the type of transition that occurs based on the current state of the game and the key that was pressed. Also, this task is now an extended task and will always reside in memory.

DealCards task This is the first task to run after shuffling is complete or when a new game starts. It clears the display and deals the first four cards; the first card dealt to the dealer is set up as the hole card and is not displayed.

DealerTurn task This task is activated after the player presses the B key to end the turn.

It displays the dealer’s hole card and takes additional cards based on the rule that the dealer must hit at 16 and stay at 17, as discussed earlier in this section. To simulate real play, the task deals one card a time and sets an alarm for two seconds before it deals another card.

GameTransitions CheckGameTransition(char keyPressed) This local function determines which, if any, game transition is to occur when a key is pressed, based on the current state of the game. The transition that is to occur is returned from this function based on the value in gameTransitionTable. The table gameTransitionTable is defined statically as a table of game transitions based upon the current state of the game and the key that was pressed. If a valid transition is not defined, this routine returns NO_ACTION.

78

Chapter 6: Events

void EndGame(void) This local function is executed by the DealerTurn task after the dealer’s turn has completed. It displays the scores for both the dealer and the player and sets the game state to normal in anticipation of the next key press.

dispdrv.c This module was modified to add one more special character to the display: the character to be displayed as the back of a card. In addition, the following function was added.

void SetDisplayPosition(UINT8 row, UINT8 column) This function moves the cursor to an absolute display position defined by the row and the column parameters. The next string to be written to the display will start from this new position.

keypad.c This module was modified to create a buffer of key presses rather than just hold-ing the last key pressed. The support to obtain data from the buffer and to encapsulate the key buffer was added.

char GetKeyValue(void) This routine simply pops the oldest key press from the buffer, updates the buffer pointers, and returns the value.

carddeck.c This module also has been extensively modified to provide more information about dealt cards. The ShuffleCards task is modified only slightly to initialize the remaining-Cards static variable to 52 when the deck reshuffles. However, DealCard() was rewritten extensively, and other functions were added.

UINT8 DealCard(PlayerType player, UINT8 position, BOOLEAN up) This routine now deals the next card based on the player parameter, which defines whether the next card goes to the dealer or the player, the position parameter, which defines which of the five positions of the dealer’s or player’s hand a card is dealt, and the up parameter, which defines whether the value or the back of the card is shown. The return value is now the value of the card that was dealt, from 0 to 51. This task also invokes DisplayCard() to display the card.

void DisplayCard(UINT8 card) This routine copies the codes required to send the card to the display buffer. If card is BLANK, the back of the card is displayed.

UINT8 GetCardValue(UINT8 card) This function returns the value of the card that is passed in the card parameter. An Ace always has a value of 11, and a face card always has a value of 10.

UINT8 GetRemainingCards(void) This function simply returns the number of cards remaining in the deck. It is used to determine when the deck needs to be reshuffled.

shuffle.c This module was changed to use events instead of activating a task when shuf-fling is complete.

Exercises

79

6.5 Exercises

1. Modify the task you created in the last chapter that keeps track of the time the program has been running. Make this an extended task with an event that is set when the alarm expires.

2. Modify the previous task to reset the time when a key is pressed. Use the event mechanism to signal this event from the task ProcessKeyPress.

6.6 Summary

Events differentiate basic from extended tasks and are used primarily as a method of synchro-nization between tasks. An event is a combination of an event and an extended task. An event differs from an event mask, which is a specific bit value in a mask. Multiple tasks can use the event mask to create a series of unique events.

Any task and interrupt service routine and most hook routines can set and check the sta-tus of an event. However, only the extended task that owns the event can wait for it to occur or clear the event.

80

Chapter 6: Events This Page Intentionally Left Blank

81

7

Chapter 7

Resources

Most multitasking/multiprocessing OSs provide a method for sharing a resource between tasks or processes. The typical methods are semaphores and mutexes (MUTual EXclusion). A drawback of these methods is possible priority inversion or deadlock. The OSEK/VDX OS also provides a method for managing resources that avoids these drawbacks. In this chapter, I discuss the issues of priority inversion and deadlock, then introduce the method used by OSEK/VDX to eliminate these issues — the priority ceiling protocol. I then discuss how resources are managed using the scheduler as a resource and the limitations to using resources in a system.

7.1 Priority Inversion and Deadlock

OSEK/VDX was designed to work within the critical environment of the automobile, in which a Ctrl-Alt-Del key does not exist to stop a task or restart the system, and a missed deadline may cause a failure of the system. Priority inversion and deadlock are two situations that are unacceptable in an automobile.

Priority inversion is a situation in which a lower priority task preempts a higher priority task while a resource is locked, as shown in Figure 7.1 for a general RTOS. In this example, Task A has priority 1, B priority 2, and C priority 3. All tasks are fully preemptive. Tasks A and C both use shared resource R. Task A is running at the beginning of the example. The sequence of events is as follows.

1. Task A is running and locks the shared resource R.

2. Task C is activated and preempts task A.