ECE 455/555 Embedded System Design TinyOS: Sending and Receiving Messages Wei Gao Fall 2015 1 Active Message Model Each network packet contains a handler ID Multiple access on the radio Think TCP/UDP port number! Your handler ID specifies which process is going to trigger and do something with the message. Message format Header Data Footer Metadata Data type: message_t, specified in /opt/tinyos-2.x/tos/types/message.h ECE 455/555 Embedded System Design 2 Details of Message Format \opt\tinyos-2.x\tos\chips\cc2420\CC2420.h typedef nx_struct cc2420_header_t { nxle_uint8_t length; nxle_uint16_t fcf; nxle_uint8_t dsn; nxle_uint16_t destpan; nxle_uint16_t dest; nxle_uint16_t src; nxle_uint8_t network; nxle_uint8_t type; } cc2420_header_t; Reserved address: 1. 0x007E – UART for serial port comm 2. 0xFFFF – broadcast address typedef nx_struct cc2420_footer_t { } cc2420_footer_t; typedef nx_struct cc2420_metadata_t { nx_uint8_t tx_power; nx_uint8_t rssi; nx_uint8_t lqi; nx_bool crc; nx_bool ack; nx_uint16_t time; nx_uint16_t rxInterval; nx_uint16_t maxRetries; nx_uint16_t retryDelay; } cc2420_metadata_t; ECE 455/555 Embedded System Design 3 Message Accessing Interfaces /opt/tinyos-2.x/tos/system AMPacket Accessors to the fields specified in message_t AMSend Send out an AM packet to the radio (taking message_t as input) Receive Receive an AM packet from the radio (taking message_t as input) ECE 455/555 Embedded System Design 4 Example: RadioCountToLeds /opt/tinyos-2.x/apps/RadioCountToLeds Sending packets periodically based on a 4Hz counter Two motes: duplex communication ECE 455/555 Embedded System Design 5 1. Declare message format In RadioCountToLeds.h Will be put in the data field of message_t! typedef nx_struct radio_count_msg { nx_uint16_t counter; } radio_count_msg_t; enum { AM_RADIO_COUNT_MSG = 6, }; AM packet type: handler ID/port ECE 455/555 Embedded System Design 6 2. Configuration In RadioCountToLedsAppC.nc configuration RadioCountToLedsAppC {} implementation { components MainC, RadioCountToLedsC as App, LedsC; components new AMSenderC(AM_RADIO_COUNT_MSG); components new AMReceiverC(AM_RADIO_COUNT_MSG); components new TimerMilliC(); components ActiveMessageC; Specify the ID used. AMReceiver monitors the radio App.Boot -> MainC.Boot; } App.Receive -> AMReceiverC; App.AMSend -> AMSenderC; App.AMControl -> ActiveMessageC; App.Leds -> LedsC; App.MilliTimer -> TimerMilliC; App.Packet -> AMSenderC; ECE 455/555 Embedded System Design Send/Receive interfaces When to send msg Message accessor. Must be wired to AMSender to access the msg 7 3. Implementation In RadioCountToLedsC.nc module RadioCountToLedsC { uses { interface Leds; interface Boot; interface Receive; interface AMSend; interface Timer<TMilli> as MilliTimer; interface SplitControl as AMControl; interface Packet; }} implementation { message_t packet; bool locked; uint16_t counter = 0; • Reset the timer every 250ms • Why use control: keep trying until the radio starts successfully 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 } ECE 455/555 Embedded System Design 8 Sending messages event void MilliTimer.fired() { counter++; Radio is busy if (locked) { Message accessor get return; payload from message_t } else { radio_count_msg_t* rcm = (radio_count_msg_t*)call Packet.getPayload(&packet, NULL); if (call Packet.maxPayloadLength() < sizeof(radio_count_msg_t)) { return; } Message is broadcasted every 250ms 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; } } } ECE 455/555 Embedded System Design 9 Sending messages event void AMSend.sendDone(message_t* bufPtr, error_t error) { if (&packet == bufPtr) { locked = FALSE; } } Release radio when finished ECE 455/555 Embedded System Design 10 Receiving messages 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(); } Triggered when packet is else { call Leds.led0Off(); } received by the radio if (rcm->counter & 0x2) { call Leds.led1On(); } else { call Leds.led1Off(); } if (rcm->counter & 0x4) { call Leds.led2On(); } else { call Leds.led2Off(); } return bufPtr; } } ECE 455/555 Embedded System Design 11 Lab 2 Announcement Lab 2 is due 10/7 (5:30pm Wednesday) Sensor reading and message sending/receiving Need to program two motes • Everyone should check out two more motes from the TA Mote1 periodically reads light sensor, displays the readings on the LEDs, and sends it to the radio Mote2 receives the reading and displays it on the LEDs ECE 455/555 Embedded System Design 12