[ Pobierz całość w formacie PDF ]
.That is, you could either have a configuration like thisconfiguration NetworkProtocolC {.}implementation {components NetworkProtocolP, PacketLayerC;NetworkProtocolP.Send -> PacketLayerC.Send15;}Listing 6.4: Wiring to AM type 15 by nameor the network protocol code could look like this:call Send.send(15, msg, sizeof(payload_t));Listing 6.5: Calling AM type 15 with a compile time parameterNeither of these solutions is very appealing.The first leads to a lot of redundant code, wasting codememory.Also, as the wiring is by name, it is also difficult to wire to.That is, there is no way to manipulateconstants in order to control the wiring.For example, if a sensor filter and a routing stack both wire to2http://www.iana.org/assignments/protocol-numbers71Timer3, there s no way to separate them without changing the code text of one of them to read Timer4.One way to manage the namespace would be to have components leave their timers unwired and thenexpect the application to resolve all of them.But this places a large burden on an application developer.Forexample, a small application that builds on top of a lot of large libraries might have to wire eight differenttimers.Additionally, it means that the components it includes aren t self-contained, working abstractions:they have remaining dependencies that an application developer needs to resolve.The second approach is superior to the first at first glance, but it turns out to have even more significantproblems.First, in many cases the identifier is a compile-time constant.Requiring the caller to pass it as arun-time parameter is unnecessary and is a possible source of bugs.Second, and more importantly, it pushesidentifier management into the caller.For example, let s return to the timer example:call Timer.startPeriodic(timerDescriptor, 1024); // Fire at 1HzListing 6.6: Starting a timer with a run time parameterFrom the calling component s perspective, it doesn t care which timer it s using.All it cares is that ithas its own timer.By making the identifier part of the call, this forces the module to know (and manage)the name of the identifier.The third and largest problem, however, isn t with calls out to other components:it s with calls in from other components.In Timer, for example, how does the timer service signal a fired()event? Because the identifier is a runtime parameter, the only way is for Timer.fired() fan-out to all timers,and have them all check the identifier.To support abstractions that have sets of interfaces, nesC has parameterized interfaces.You ve seen themin a few of the earlier example signatures.A parameterized interface is essentially an array of interfaces,and the array index is the parameter.For example, this is the signature of ActiveMessageC:configuration ActiveMessageC {provides {interface Init;interface SplitControl;interface AMSend[uint8_t id];interface Receive[uint8_t id];interface Receive as Snoop[uint8_t id];interface Packet;interface AMPacket;interface PacketAcknowledgements;}}72 CHAPTER 6.PARAMETERIZED WIRINGListing 6.7: ActiveMessageC signatureAMSend, Receive, and Snoop are all parameterized interfaces.Their parameter is the AM type of themessage (the protocol identifier).Normally, components don t wire directly to ActiveMessageC.Instead,3they use AMSenderC, AMReceiverC, and the other virtualized abstractions.However, there are sometest applications for the basic AM abstraction, such as TestAM.The module TestAMC sends and receivespackets:module TestAMC {uses {.interface Receive;interface AMSend;.}}Listing 6.8: Signature of TestAMCTestAMAppC is the configuration that wires up the TestAMC module:configuration TestAMAppC {}implementation {components MainC, TestAMC as App;components ActiveMessageC;MainC.SoftwareInit -> ActiveMessageC;App.Receive -> ActiveMessageC.Receive[240];App.AMSend -> ActiveMessageC.AMSend[240];.}Listing 6.9: Wiring TestAMC to ActiveMessageCNote that TestAM has to wire SoftwareInit to ActiveMessageC because it doesn t use the standardabstractions, which auto-wire it.This configuration means that when TestAMC calls AMSend.send, itcalls ActiveMessageC.AMSend number 240, so packets with protocol ID 240.Similarly, TestAMC receivespackets with protocol ID 240.Because these constants are specified in the configuration, they are not boundin the module: from the module s perspective, they don t even exist.That is, from TestAMC s perspective,these two lines of code are identical:3See TEP 116: Packet Protocols, for details.73TestAMC.AMSend -> ActiveMessageC.AMSend240; // Not real TinyOS codeTestAMC.AMSend -> ActiveMessageC.AMSend[240];Listing 6.10: Wiring to a single interface versus an instance of a parameterized interfaceThe different lies in the component with the parameterized interface.The parameter is essentially an-other argument in functions of that interface.In ActiveMessageC.AMSend, for example, the parameter isan argument passed to it in calls to send() and which it must pass in signals of sendDone().But the parame-terized interface gives you two key things.First, it automatically fills in this parameter when TestAMC callssend (nesC generates a stub function to do so, and inlining makes the cost negligible).Second, it automat-ically dispatches on the parameter when ActiveMessageC signals sendDone (nesC generates a switch tablebased on the identifier).In reality, ActiveMessageC is a configuration that encapsulates a particular chip, such as CC2420ActiveMessageC,which encapsulates that chip s implementation, such as CC2420ActiveMessageP:module CC2420ActiveMessageP {provides {interface AMSend[am_id_t id];.}}Listing 6.11: A possible module underneath ActiveMessageCWithin CC2420ActiveMessageP, this is what the parameterized interface looks like:command error_t AMSend.send[am_id_t id](am_addr_t addr, message_t* msg, uint8_t len) {cc2420_header_t* header = getHeader( msg );header->type = id;.}Listing 6.12: Parameterized interface syntaxThe interface parameter precedes the function argument list, and the implementation can treat it like anyother argument.Basically, it is a function argument that the nesC compiler fills in when components arecomposed
[ Pobierz całość w formacie PDF ]