PA 8001 2013 Practical 3
Contents
Objectives
There are two main objectives for this practical:
- Learn about and use the abstractions provided by reactive objects
- Understand the issues involved in real-time systems and use TinyTimber for a basic implementation
Instructions
Submit a single .zip file on blackboard with two folders, each containing the solutions to the below-specified parts.
For each function in the code, you need to write a piece of comment, describing its pre- and post-condition and one or more test-cases. In particular for the second part, in addition to comments on the functions, write down before you start with programming 4 scenarios that you would like to test after the implementation of the second part is finished.
For both parts, you need to use the Tiny Timber kernel. In order to compile and run this program we will have to modify the makefile so that the lines for TARGET and SRC look as follows:
TARGET = yourprogram SRC = $(TARGET).c TinyTimber.c
For the second part, you need to play some sound. In order to produce sounds we will use the piezo element available in the Butterfly. The piezo element contains a sheet of material that deforms when electricity is applied to it. This deformation can be made at audio frequencies allowing the element to produce sound waves in the air. It is connected to pin 5 in port B. To produce a given sound you just have to alternate low and high on this pin at a suitable frequency. You will have to configure the pin for output by setting bit 5 in the DDRB register (this is the data direction register for port B that you can find described in the register description for the I/O ports in ATmega169 manual). For audible sounds you will need to turn the piezo on and off with periods shorter than 1 millisecond (frequencies higher than 1000 Hz).
Part 1: Reactive Objects
In this exercise you will reprogram your application that has a moving symbol, computes prime numbers and responds to the joystick by using reactive objects. To this end you will have to define the following objects:
LCD Driver
An LCD driver, that provides the interface
int writeDigit(LCD *self, int digitPos); int writeInt(LCD *self, int val); int segmentOn(LCD *self, int segment); int segmentOff(LCD *self, int segment);
You should declare the new type, define the constructor and declare the methods' signatures in a file called lcd.h. You should implement the methods in a file called lcd.c. Here is an explanation of what the methods should do:
writeDigit(self,digitPos)
shows digit digitPos/10 in position digitPos%10. For example, writeDigit(self,31) should show digit 3 in position 1 of the LCD.
writeInt(self,val)
shows val on the LCD. If val has more than 6 digits, it should display the 6 less significant digits.
segmentOn(self,segment)
shows segment number segment on the LCD. This refers to the segments that are not used for drawing digits!
segmentOff(self,segment)
clears segment number segment on the LCD. This refers to the segments that are not used for drawing digits!
An application that can test your reactive object might be
#include "TinyTimber.h" #include "lcd.h" LCD lcdDriver = initLCD(); int main(){ CONFLCD; return TINYTIMBER(&lcdDriver,writeInt,12345); }
You should collect lcd initialization code in the macro CONFLCD defined in lcd.h.
Prime Number Calculator
A prime number calculator that provides the following interface:
int primes(PrimeCalculator *self, int x);
You should declare the new type, the constructor and the method signature in a file primes.h. You should implement the method in a file primes.c. Because the prime number calculator will want to write to the LCD it requires an LCD. You should have an instance of an LCD driver as part of the prime calculator's state! An application that can test your reactive object might be
#include "TinyTimber.h" #include "lcd.h" #include "primes.h" LCD lcdDriver = initLCD(); PrimeCalculator primeCalc = initPrimeCalculator(&lcdDriver); int main(){ CONFLCD; return TINYTIMBER(&primeCalc,primes,0); }
Marquee
A marquee that moves a symbol around at topmost part part of the LCD The marquee should provide the following interface:
int startMarquee(Marquee *self, int nothing); int move(Marquee *self, int nothing); int turnCurrentOn(Marquee *self, int nothing); int turnCurrentOff(Marquee *self, int nothing); int setPeriod(Marquee *self, int period);
You should declare the new type, the constructor and the methods' signature in marquee.h and you should implement the methods in marquee.c. In order to know what current segment, the constructor initMarquee should include an integer argument for it and the internal state of the marquee should include an integer for this purpose.
Because the marquee will want to write to the LCD it requires an LCD. You should have an instance of an LCD driver as part of the marquee's state. Also, because there is a method for changing the period of the marquee, you will need to have the period as part of the state. To take care of time you can use the TinyTimber AFTER operation. Check lecture 7 and the Tiny Timber Documentation to see how to do periodic actions.
In the implementation of startMarquee we recommend you to use a method marquee (not exposed in the interface, just included in the marquee.c file) for doing the periodic task of turning on and off the specified segment.
An application that can test your reactive objects might be
#include "primes.h" #include "marquee.h" LCD lcdDriver = initLCD(); PrimeCalculator primeCalc = initPrimeCalculator(&lcdDriver); Marquee marquee = initMarquee(&lcdDriver,segment,500); typedef struct{ Object super; PrimeCalculator* pctr; Marquee* mrq; } APP; #define initAPP(p,b) {initObject(),p,b} int startup(APP * self, int x){ ASYNC(self -> pctr, primes,0); ASYNC(self -> mrq, startMarquee, 0); }
APP app = initAPP(&primeCalc,&mrq);
int main(){ CONFLCD; return TINYTIMBER(&app,startup,0); }
Joystick
An object to control the joystick so that the displayed symbol moves to right and left at the bottom row of the LCD. This will have to be handled via an interrupt in the application. With all these you can write an application that does all things at the same time! For the Joystick, you need to install an interrupt handler for the interrupt IRQ_PCINT0 .
Part 2: Shouting Philosophers
The second part of the assignment involves first modularizing the dining philosopher made in the previous practical and then adapting it so that the philosophers start making noise and eventually shouting once they cannot eat in time.
First, modularize the protocol in at least 3 types of reactive objects: one type for forks, another one for philosophers and a third one for the joystick. Forks should provide interfaces for being taken and released and philosophers should have interfaces for changing state (to the next state as specified before ). The interface for the joystick is similar to Part 1 .
Specialize the behavior of the philosopher so that the first philosopher changes state as a result of pressing the joystick button. (Eating still takes a fixed amount of time.) The second philosopher changes state automatically after fixed time intervals (two seconds each). For the timing behavior of the philosophers use the timing interface in Tiny Timber.
Then, modify the philosophers object so that when it is hungry, it starts making some noise if it does not get a fork in 3 seconds and also when it has one fork and does not get the other one in 3 seconds. If the waiting time reaches 5 seconds, it will start shouting by producing a different noise. For this case, you may add a reactive object for the beeper. Please note that the beeper is a shared resource and at most one philosopher can use it at each moment of time.
Write a short text explaining the issues encountered and your solution. Include all the programs and the short report (in pdf) in the zip file under the folder Part 2.