Sunteți pe pagina 1din 8

RADIOCOUNTTOLEDS NesC Program: #include "Timer.h" #include "RadioCountToLeds.

.h" module RadioCountToLedsC @safe() { uses { interface Leds; interface Boot; interface Receive; interface AMSend; interface Timer as MilliTimer; interface SplitControl as AMControl; interface Packet; } } implementation { message_t packet; bool locked; uint16_t counter = 0; event void Boot.booted() { call AMControl.start(); } event void AMControl.startDone(error_t err) { if (err == SUCCESS) { call MilliTimer.startPeriodic(250); } else { call AMControl.start(); } } event void AMControl.stopDone(error_t err) { // do nothing } event void MilliTimer.fired() { counter++; dbg("RadioCountToLedsC", "RadioCountToLedsC: timer fired, counter is %hu.\n", counter); if (locked) { return; } else {

radio_count_msg_t* rcm = (radio_count_msg_t*)call Packet.getPayload(&packet, sizeof(radio_count_msg_t)); if (rcm == NULL) { return; } rcm->counter = counter; if (call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(radio_count_msg_t)) == SUCCESS) { dbg("RadioCountToLedsC", "RadioCountToLedsC: packet sent.\n", counter); locked = TRUE; } } } event message_t* Receive.receive(message_t* bufPtr, void* payload, uint8_t len) { dbg("RadioCountToLedsC", "Received packet of length %hhu.\n", len); if (len != sizeof(radio_count_msg_t)) {return bufPtr;} else { radio_count_msg_t* rcm = (radio_count_msg_t*)payload; if (rcm->counter & 0x1) { call Leds.led0On(); } else { call Leds.led0Off(); } if (rcm->counter & 0x2) { call Leds.led1On(); } else { call Leds.led1Off(); } if (rcm->counter & 0x4) { call Leds.led2On(); } else { call Leds.led2Off(); } return bufPtr; } } event void AMSend.sendDone(message_t* bufPtr, error_t error) { if (&packet == bufPtr) { locked = FALSE; } } }

The Interfaces used:

Packet:

Provides the basic accessors for the message_t abstract data type.

This interface provides commands for clearing a message's contents, getting its payload length, and getting a pointer to its payload area. Commands Used from Packet interface:

getPayload
command void *getPayload(message_t *msg, uint8_t len) Return a pointer to a protocol's payload region in a packet. If the caller intends to write to the payload region then the len parameter must reflect the maximum required length. If the caller (only) wants to read from the payload region, then len may be set to the value of payloadLength(). If the payload region is smaller than len this command returns NULL. The offset where the payload region starts within a packet is fixed, i.e. for a given msg this command will always return the same pointer or NULL.

Receive: Provides the basic message reception interface. This interface provides an
event for receiving messages. It also provides, for convenience, commands for getting a message's payload length and getting a pointer to a message's payload area. Events Used from Receive interface:

receive
event message_t *receive(message_t *msg, void *payload, uint8_t len) Receive a packet buffer, returning a buffer for the signaling component to use for the next reception. The return value can be the same as msg, as long as the handling component copies out the data it needs. Note that misuse of this interface is one of the most common bugs in TinyOS code. For example, if a component both calls a send on the passed message and returns it, then it is possible the buffer will be reused before the send occurs, overwriting the component's data. This would cause the mote to possibly instead send a packet it most recently received.

AMSend: The term "AM type" refers to the field used for multiplexing. AM types are
similar in function to the Ethernet frame type field, IP protocol field, and the UDP port in that all of them are used to multiplex access to a communication service. An AM packet also includes a destination field, which stores an "AM address" to address packets to particular motes. Similar to Send, provides the basic Active Message sending interface.

The key difference between AMSend and Send is thatAMSend takes a destination AM address in its send command. Commands used from AMSend interface: send command error_t send(am_addr_t addr, message_t *msg, uint8_t len) Send a packet with a data payload of len to address addr. To determine the maximum available size, use the Packet interface of the component providing AMSend. If send returns SUCCESS, then the component will signal the sendDone event in the future; if send returns an error, it will not signal the event. Note that a component may accept a send request which it later finds it cannot satisfy; in this case, it will signal sendDone with error code. Arguments: addr - address to which to send the packet 'message_t* ONE msg' the packet len - the length of the data in the packet payload Returns: SUCCESS if the request to send succeeded and a sendDone will be signaled later, EBUSY if the abstraction cannot send now but will be able to later, or FAIL if the communication layer is not in a state that can send Events used from AMSend interface:

sendDone
event void sendDone(message_t *msg, error_t error) Signaled in response to an accepted send request. msg is the message buffer sent, and error indicates whether the send was successful. Arguments: 'message_t* ONE msg' the packet which was submitted as a send request error - SUCCESS if it was sent successfully, FAIL if it was not, ECANCEL if it was cancelled

SplitControl:
The ability to optimize across component boundaries is very important in TinyOS, because it has no blocking operations. Instead, every long-running operation is splitphase. In a blocking system, when a program calls a long-running operation, the call does not return until the operation is complete: the program blocks. In a split-phase system, when a program calls a long-running operation, the call returns immediately, and the called abstraction issues a callback when it completes. This approach is called split-phase because it splits invocation and completion into two separate phases of execution. The SplitControl Interface is the split-phase counterpart to the StdContol interface. It should be used for switching between the on and off power states of the component providing it. For each start() or stop()command, if the command returns SUCCESS, then a corresponding startDone() or stopDone() event must be signalled. Commands used in SplitControl Interface:

start
command error_t start() Start this component and all of its subcomponents. Return values of SUCCESS will always result in a startDone() event being signalled.

Returns:
SUCCESS if the device is already in the process of starting or the device was off and the device is now ready to turn on. After receiving this return value, you should expect a startDone event in the near future. EBUSY if the component is in the middle of powering down i.e. a stop() command has been called, and a stopDone() event is pending EALREADY if the device is already on FAIL Otherwise Events used in SplitControl Interface:

startDone
event void startDone(error_t error) Notify caller that the component has been started and is ready to receive other commands. Arguments: error -- SUCCESS if the component was successfully turned on, FAIL otherwise Other interfaces are already explained in previous editions like Boot,Leds and Timer

Simple explanation of the NesC program: module RadioCountToLedsC @safe() { uses { interface Leds; interface Boot; interface Receive; interface AMSend; interface Timer as MilliTimer; interface SplitControl as AMControl; interface Packet; } } The module shows the interfaces which are used in this program. The implementation will show how to implement various commands and events of the interfaces. message_t packet;

message_t is a message buffer abstraction described as:


typedef nx_struct message_t { nx_uint8_t header[sizeof(message_header_t)]; nx_uint8_t data[TOSH_DATA_LENGTH]; nx_uint8_t footer[sizeof(message_footer_t)]; nx_uint8_t metadata[sizeof(message_metadata_t)]; } message_t;

bool locked; uint16_t counter = 0;

bool and uint16_t are data types. bool is the logical data type while uint16_t is used to represent a 16bit number. event void Boot.booted() { call AMControl.start(); }

The Booted event of the Boot interface initializes our system and this is done here, by the help of the start command of the SplitControl interface(which is used as AMControl here). As we have already said, that the start command will return the state of the device. And so we have to configure the startdone event of the SplitControl interface as:

event void AMControl.startDone(error_t err) { if (err == SUCCESS) { call MilliTimer.startPeriodic(250); } else { call AMControl.start(); } }

So, if the start command returns SUCCESS, a millisecond Timer MilliTimer is started by the help of the command startperiodic with a period of 250 ms. In case, it does not return SUCCESS, the start command is called again and the process is repeated. event void MilliTimer.fired() { counter++; dbg("RadioCountToLedsC", "RadioCountToLedsC: timer fired, counter is %hu.\n", counter); if (locked) { return; } else { radio_count_msg_t* rcm = (radio_count_msg_t*)call Packet.getPayload(&packet, sizeof(radio_count_msg_t)); if (rcm == NULL) { return; } rcm->counter = counter; if (call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(radio_count_msg_t)) == SUCCESS) { dbg("RadioCountToLedsC", "RadioCountToLedsC: packet sent.\n", counter); locked = TRUE; } } }

The fired() event of the MilliTimer is defined. The counter is incremented and a pointer to a payload type radio_count_msg_t allows the payload counter variable to be set. This command creates and sets the packet.

The AMSend.send() command then broadcasts the packet over the radio ----------------------------------------------------------------typedef nx_struct radio_count_msg_t { nx_uint16_t counter; //counter value } radio_count_msg_t; ------------------------------------------------------------------

event message_t* Receive.receive(message_t* bufPtr, void* payload, uint8_t len) { dbg("RadioCountToLedsC", "Received packet of length %hhu.\n", len); if (len != sizeof(radio_count_msg_t)) {return bufPtr;} else { radio_count_msg_t* rcm = (radio_count_msg_t*)payload; if (rcm->counter & 0x1) { call Leds.led0On(); } else { call Leds.led0Off(); } if (rcm->counter & 0x2) { call Leds.led1On(); } else { call Leds.led1Off(); } if (rcm->counter & 0x4) { call Leds.led2On(); } else { call Leds.led2Off(); } return bufPtr; } } The receipt of a radio message is handled in the same manner as the receipt of a serial packet in the TestSerial application. Upon receipt of a packet, the Receive.receive() event is signaled, which provides a pointer to the TinyOS message_t packet including headers and metadata, a pointer to the message_t payload, and the payload length. RadioCountToLeds maintains a 4Hz counter, broadcasting its value in an AM packet every time it gets updated. A RadioCountToLeds node that hears a counter displays the bottom three bits on its LEDs. This application is a useful test to show that basic AM communication and timers work.

S-ar putea să vă placă și