[ Pobierz całość w formacie PDF ]
.7.4 ExamplesBecause generic configurations are a challenging concept, we present four examples of their use for basicabstractions in the TinyOS core.The examples increase in complexity.7.4.1 TimerMilliCThe standard millisecond timer abstraction, TimerMilliC, provides this abstraction.TimerMilliC is a genericconfiguration that provides a single Timer interface.Its implementation wires this interface to an instance ofthe underlying parameterized Timer interface using the right unique key.This means that unique() is calledin only one file; as long as all components allocate timers with TimerMilliC, there is no chance of a keymatch mistake.TimerMilliC s implementation is very simple:generic configuration TimerMilliC() {provides interface Timer;}implementation {components TimerMilliP;Timer = TimerMilliP.TimerMilli[unique(UQ_TIMER_MILLI)];}Listing 7.17: The TimerMilliC generic configurationTimerMilliP is a singleton configuration that auto-wires HilTimerMilliC to the boot sequence and ex-ports HilTimerMilliC s parameterized interface:90 CHAPTER 7.GENERIC COMPONENTSconfiguration TimerMilliP {provides interface Timer as TimerMilli[uint8_t id];}implementation {components HilTimerMilliC, MainC;MainC.SoftwareInit -> HilTimerMilliC;TimerMilli = HilTimerMilliC;}Listing 7.18: TimerMilliP auto wires HilTimerMilliC to Main.SoftwareInitTimerMilliC encapsulates a wiring pattern wiring to the timer service with a call to unique forother components to use.When a component instantiates a TimerMilliC, it creates a copy of the TimerMilliCcode, which includes a call to unique(UQ TIMER MILLI).The line of codecomponents X, new TimerMilliC();X.Timer -> TimerMilliC;Listing 7.19: Instantiating a TimerMilliCis essentially this:components X, TimerMilliP;X.Timer -> TimerMilliP.TimerMilli[unique(UQ_TIMER_MILLI)];Listing 7.20: Expanding a TimerMilliC InstantiationTimerMilliP is itself a configuration, which wires to HilTimerMilliC, which is a configuration.Whena component calls Timer.start() on a TimerMilliC, the actual function it invokes is Timer.start() on Virtual-izeTimerC.Let s step through the complete wiring path for an application that creates a timer.BlinkAppCwires the BlinkC module to its three timers:configuration BlinkAppC{}implementation {components MainC, BlinkC, LedsC;components new TimerMilliC() as Timer0;components new TimerMilliC() as Timer1;components new TimerMilliC() as Timer2;BlinkC -> MainC.Boot;MainC.SoftwareInit -> LedsC;BlinkC.Timer0 -> Timer0;BlinkC.Timer1 -> Timer1;BlinkC.Timer2 -> Timer2;BlinkC.Leds -> LedsC;}7.4.EXAMPLES 91Listing 7.21: The Blink applicationWiring BlinkC.Timer0 to Timer0 establishes this wiring chain (the key to unique, UQ TIMER MILLI,is elided for readability):BlinkC.Timer0 -> Timer0.TimerTimer0.Timer = TimerMilliP.TimerMilli[unique(.)]TimerMilliP.TimerMilli[unique(.)] = HilTimerMilliC[unique(.)]HilTimerMilliC[unique(.)] = VirtualizeTimerC.Timer[unique(.)]Listing 7.22: The full module to module wiring chain in Blink (BlinkC to VirtualizeTimerC)BlinkC and VirtualizeTimerC are the two modules; the intervening components are all configurations.When nesC compiles this code, all of the intermediate layers will be stripped away, and BlinkC.Timer0.startwill be a direct function call on VirtualizeTimerC.Timer[.].start.Many of TinyOS s basic services use this pattern of a generic configuration to managing a keyspace fora parameterized interface.For example, one of the non-volatile storage abstractions in TinyOS is BlockStor-ageC (covered in TEP 103).This abstraction is intended for reading and writing large objects in a randomaccess fashion.This abstraction provides the BlockRead and BlockWrite interfaces.The abstraction sup-ports there being multiple readers and writers with a similar pattern to what Timer uses, although unlikeTimer only one read or write can be outstanding at any time.The underlying implementation thereforekeeps track of who s outstanding and enqueues other requests.7.4.2 AMSenderCTimerMilliC is reasonably simple: all it really does is encapsulate a wiring with unique() in order to makesure there aren t client collisions and in order to simplify wiring.Because HilTimerMilliC has to know thestate of all of the outstanding timers in order to do its job well, it provides a virtualized abstraction, whichTimerMilliC can just export.Active messages are slightly different.The basic platform active message component, ActiveMessageC,provides AMSend, parameterized by the AM id.However, ActiveMessageC can only have a single packetoutstanding at any time.If it is already sending a packet and a component calls SendAM.send, ActiveMes-sageC returns FAIL or EBUSY.From the perspective of a caller, this is a bit of a pain.If it wants to send thepacket, it has to wait until the radio is free, but doesn t have a very easy way of figuring out when this willoccur.92 CHAPTER 7.GENERIC COMPONENTSTinyOS 1.x had a global (not parameterized) sendDone event, which the radio would signal wheneverit finished sending any packet.That way, if a component tried to send and received a FAIL, it could try toresent when it handled the sendDone event.This mostly works, except that if multiple components wireto sendDone, then the fan-out determines the priority of the send requests.E.g., if a hog of a componenthandles sendDone and happens to be first in the fan-out, it will always get first dibs and will monopolize theradio.TinyOS 2.x solves this problem through the AMSender component, which is a generic configuration.AMSender is a virtualized abstraction: every instance of AMSender acts like ActiveMessageC.That is,each AMSender can handle a single outgoing packet.This means that each component that wires to anAMSender can act independently of the other components, and not worry about fan-out scheduling.Theone-deep queue of ActiveMessageC is replaced by N one-deep queues, one for each of the N clients.Each AMSenderC having its own one-deep queue is not sufficient.There s also the question of whatorder the senders get to send their packets.Under the covers, what the active message layer does is maintainan array of N pending packets, where N is the number of AMSenderC components.Each AMSenderC isa client of the active message sending abstraction, and so has a client ID that indexes into this array [ Pobierz całość w formacie PDF ]
zanotowane.pl doc.pisz.pl pdf.pisz.pl trzylatki.xlx.pl
.7.4 ExamplesBecause generic configurations are a challenging concept, we present four examples of their use for basicabstractions in the TinyOS core.The examples increase in complexity.7.4.1 TimerMilliCThe standard millisecond timer abstraction, TimerMilliC, provides this abstraction.TimerMilliC is a genericconfiguration that provides a single Timer interface.Its implementation wires this interface to an instance ofthe underlying parameterized Timer interface using the right unique key.This means that unique() is calledin only one file; as long as all components allocate timers with TimerMilliC, there is no chance of a keymatch mistake.TimerMilliC s implementation is very simple:generic configuration TimerMilliC() {provides interface Timer;}implementation {components TimerMilliP;Timer = TimerMilliP.TimerMilli[unique(UQ_TIMER_MILLI)];}Listing 7.17: The TimerMilliC generic configurationTimerMilliP is a singleton configuration that auto-wires HilTimerMilliC to the boot sequence and ex-ports HilTimerMilliC s parameterized interface:90 CHAPTER 7.GENERIC COMPONENTSconfiguration TimerMilliP {provides interface Timer as TimerMilli[uint8_t id];}implementation {components HilTimerMilliC, MainC;MainC.SoftwareInit -> HilTimerMilliC;TimerMilli = HilTimerMilliC;}Listing 7.18: TimerMilliP auto wires HilTimerMilliC to Main.SoftwareInitTimerMilliC encapsulates a wiring pattern wiring to the timer service with a call to unique forother components to use.When a component instantiates a TimerMilliC, it creates a copy of the TimerMilliCcode, which includes a call to unique(UQ TIMER MILLI).The line of codecomponents X, new TimerMilliC();X.Timer -> TimerMilliC;Listing 7.19: Instantiating a TimerMilliCis essentially this:components X, TimerMilliP;X.Timer -> TimerMilliP.TimerMilli[unique(UQ_TIMER_MILLI)];Listing 7.20: Expanding a TimerMilliC InstantiationTimerMilliP is itself a configuration, which wires to HilTimerMilliC, which is a configuration.Whena component calls Timer.start() on a TimerMilliC, the actual function it invokes is Timer.start() on Virtual-izeTimerC.Let s step through the complete wiring path for an application that creates a timer.BlinkAppCwires the BlinkC module to its three timers:configuration BlinkAppC{}implementation {components MainC, BlinkC, LedsC;components new TimerMilliC() as Timer0;components new TimerMilliC() as Timer1;components new TimerMilliC() as Timer2;BlinkC -> MainC.Boot;MainC.SoftwareInit -> LedsC;BlinkC.Timer0 -> Timer0;BlinkC.Timer1 -> Timer1;BlinkC.Timer2 -> Timer2;BlinkC.Leds -> LedsC;}7.4.EXAMPLES 91Listing 7.21: The Blink applicationWiring BlinkC.Timer0 to Timer0 establishes this wiring chain (the key to unique, UQ TIMER MILLI,is elided for readability):BlinkC.Timer0 -> Timer0.TimerTimer0.Timer = TimerMilliP.TimerMilli[unique(.)]TimerMilliP.TimerMilli[unique(.)] = HilTimerMilliC[unique(.)]HilTimerMilliC[unique(.)] = VirtualizeTimerC.Timer[unique(.)]Listing 7.22: The full module to module wiring chain in Blink (BlinkC to VirtualizeTimerC)BlinkC and VirtualizeTimerC are the two modules; the intervening components are all configurations.When nesC compiles this code, all of the intermediate layers will be stripped away, and BlinkC.Timer0.startwill be a direct function call on VirtualizeTimerC.Timer[.].start.Many of TinyOS s basic services use this pattern of a generic configuration to managing a keyspace fora parameterized interface.For example, one of the non-volatile storage abstractions in TinyOS is BlockStor-ageC (covered in TEP 103).This abstraction is intended for reading and writing large objects in a randomaccess fashion.This abstraction provides the BlockRead and BlockWrite interfaces.The abstraction sup-ports there being multiple readers and writers with a similar pattern to what Timer uses, although unlikeTimer only one read or write can be outstanding at any time.The underlying implementation thereforekeeps track of who s outstanding and enqueues other requests.7.4.2 AMSenderCTimerMilliC is reasonably simple: all it really does is encapsulate a wiring with unique() in order to makesure there aren t client collisions and in order to simplify wiring.Because HilTimerMilliC has to know thestate of all of the outstanding timers in order to do its job well, it provides a virtualized abstraction, whichTimerMilliC can just export.Active messages are slightly different.The basic platform active message component, ActiveMessageC,provides AMSend, parameterized by the AM id.However, ActiveMessageC can only have a single packetoutstanding at any time.If it is already sending a packet and a component calls SendAM.send, ActiveMes-sageC returns FAIL or EBUSY.From the perspective of a caller, this is a bit of a pain.If it wants to send thepacket, it has to wait until the radio is free, but doesn t have a very easy way of figuring out when this willoccur.92 CHAPTER 7.GENERIC COMPONENTSTinyOS 1.x had a global (not parameterized) sendDone event, which the radio would signal wheneverit finished sending any packet.That way, if a component tried to send and received a FAIL, it could try toresent when it handled the sendDone event.This mostly works, except that if multiple components wireto sendDone, then the fan-out determines the priority of the send requests.E.g., if a hog of a componenthandles sendDone and happens to be first in the fan-out, it will always get first dibs and will monopolize theradio.TinyOS 2.x solves this problem through the AMSender component, which is a generic configuration.AMSender is a virtualized abstraction: every instance of AMSender acts like ActiveMessageC.That is,each AMSender can handle a single outgoing packet.This means that each component that wires to anAMSender can act independently of the other components, and not worry about fan-out scheduling.Theone-deep queue of ActiveMessageC is replaced by N one-deep queues, one for each of the N clients.Each AMSenderC having its own one-deep queue is not sufficient.There s also the question of whatorder the senders get to send their packets.Under the covers, what the active message layer does is maintainan array of N pending packets, where N is the number of AMSenderC components.Each AMSenderC isa client of the active message sending abstraction, and so has a client ID that indexes into this array [ Pobierz całość w formacie PDF ]