1. Review

            Two kinds of communication in our system:

Something like a socket/pipe

                        And something like shared memory

            Two policies for shared memory updates

                        Copy on read

                        Copy on write

2. An Example: A stack to provide shared memory across multiple processors over I2C

                        Application: Responsible for the application semantics: what does the value of the shared variable mean?

                        Transport:   Implements “shared memory” iterface by using the datalink system to send guaranteed messages

                                       between transport layers running on different processors. Might also implement fifos, semaphores, etc.

                                       Exports to application:                          

                                                publish(addr); pubscribe(addr); post(addr,var); update(addr,&var);

                                       Exports to datalink :

transport_recv(message);

                        DataLink: Guarantees error free delivery of messages from one transport to another using the available

   physical layer. Can implement a wide variety of retransmit schemes.

   Exports to transport layer:

datalink_send(message);

                                       Exports to physical layer:

                                                datalink_recv(packet);

                        Physical: Converts a packet into a set of frames for transmission over the bus. Frames are reconstructed and

   passed back to datalink layer at other end. Knows how to drive the physical bus.

   Exports to datalink_layer

            physical_send(packet);

   Exports to physical layer

            ISRs to deal with events on the bus such as start, stop, byte transmission

 

7. Questions for Monday Discussion:

                       

what does subscribe() do in the transport layer ?

            sends SUBSCRIBE message if published (even if published by me)

 

what does publish do in the transport() layer ?

            sends PUBLISH message if not already published

 

what does post do in the transport layer?

 

How does the transport layer process incoming data from the data-link layer?

            It looks at first byte to determine message type and processes accordingly. Looks for transport level communication errors.

 

How does the data-link layer process incoming data from the transport layer?

            if the destination address is SELF then call recv(message);

            otherwise, add message to queue of outgoing messages.

 

/////////// here is the complete stack ////////////

 

///////////////// The Transport Layer                                                                      /////////////////

///////////////// Shows how one Transport Layer talks to another Transport Layer //////////

            // queue ID’s for communication between transport and data-link

            #define SELF 1     // different for each processor

 

            struct shared_mem {

                        char value;

                        int policy;

                        int id;

                        boolean postOK;

                        int publisher;

                        list *subscribers;

}

shared_mem globals[N];

 

transport_init() {

            g = 0;  // number of currently known shared globals

            }

 

///// Outgoing Messages //////////////////////           

            int publish(int dataID, int policy) { //msg = <PUB, publisher, data ID, policy>, broadcast

                        message[0] = PUBLISH;   // Message Type

                        message[1] = SELF;        // ID of Publisher

                        message[2] = dataID;       // ‘Address’ of the shared variable

                        message[3] = policy;        // update policy …

                        datalink_send(0,message, 4);   // broadcast this message (can this block?)

                        return(0);

            }                      

           

            int subscribe(int dataID, int policy) { //msg = <SUB, subscriber, data ID, policy>, to publisher

                        startTimer();

                        while ( (!tmp=lookup(globals,dataID)) && readTimer() < TIMEOUT); // block until published or timeout

                        if (tmp) { // publisher found

                        message[0] = SUBSCRIBE;    // Message Type

message[1] = SELF;              //  I am the subscriber

                        message[2] = dataID;

                        message[3] = policy;              // subscription update policy

                        datalink_send(tmp.publisher, message, 4) ; // send message to publisher

                        return(0)

            }

            send_signal(NETWORKTIMEOUT);  // signal to all tasks on this SELFessor for error handling

}

 

int post(int dataID, char value) {

}  // behavior depends on policy

int update(int dataID, char *value) {

}  // behavior depends on policy

 

///// Incoming Transport Layer Messages //////////////////////

int transport_recv(char *message, int len) {  // called by data link layer when a message is received

            if (len < 4) transport_error();

            switch (message[0])

                        SUBSCRIBE:

                                    if (!tmp = lookup(message[2]))  transport_error(message); // not published

                                    if (tmp.publisher != SELF) transport_error(message);       // by me

                                    ir (tmp.policy != message[3]) transport_error(message);  // policy mismatch

                                    add_subscriber(tmp.subcribers, message[1]);       // add to subscribers list

                                    return(0);                                  

                        PUBLISH:

                                    if (tmp = lookup(message[2])) transport_error(message); // already published

                                    tmp = globals[g++];                                // fill in data structure

                                                tmp.policy = message[3];

                                                tmp.id = message[2];    

                                                tmp.publisher = message[1];

                                                return(0);

                        POST: 

                        UDATE:           

                        default:  transport_error(message); // have to deal with errors

}

 

 

 

 

////////////////// Data-link layer //////////////////////////

                                              

// keep a packet counter so that we can uniquely tag each packet for a period of time

datalink_packet_counter = 0;

char *datalink_packet;  // packet = <dst, src, number, checksum, length, transport_msg>

          // or it can be <dst,src,number,0,0> = NACK

 

 

/////// Outgoing DataLink Packets //////////

datalink_send(int dst, char *transport_msg, int length) {  // called from transport layer with a  transport message

packet = new datalink_packet(transport_msg, dst, length);

if (dst == SELF || dst == 0) datalink_recv(packet);        // loopback in the event of SELF or Broadcast

if (dst != SELF) {                                                  // if not self, send to physical layer

physical_send(packet);

                        save_until _timeout(packet);

            }          

}

 

//////// Incoming DataLink Packets ////////

datalink_recv(char *packet, int length) { // called from physical layer when a packet is received.

            if (isNACK(packet)) {  // receiver had a problem so retransmit if still saved

                        resend = get_saved _packet(get_packet_number(packet));  // lookup saved packet for resend

                        if (resend) physical_send(resend);          

                        else datalink_error(packet);                     // can no longer retransmit, so datalink error has occurred

            } else {  // it must be normal packet

                        char *transport_msg = datalink_verify(packet, length); // validates header and checksum, extracts transport message

                        If (transport_msg)  // if null, then assume that verify failed so send a NACK

                        transport_recv(transport_msg);  // pass extracted message to transport layer

else

                        physical_send(make_NACK_packet(packet)); // send a NACK to the src of the packet.

                                                                                           // a NACK to a NACK should cause error, so don’t save

}

}

 

 

////////////////////////// Physical Layer ////////////////////////

/////////// what datalink needs to know about physical ////////

physical_send(char *packet) {

      //    this was the old version

      //    enq(sendQ, packet);

      //    i2C_send_start();  // if bus is busy, this will retry when stop condition is received

 

// here is the new version: a packet is converted into a set of frames appropriate for the physical interface

// The frame format contains information needed to reconstruct the packet along with the dst address needed by i2C

 

            //  <packet> becomes   <dst, seq#, packet#, [part of packet]>  <dst, seq#, packet#, [part of packet]> ... <dst, seq#, packet#, [part of packet]> 

            // it should be something like this

            make_frames(packet); // chops packet up into frames and puts them on and internal queue.

            I2C_send_start();         // try to send

}

 

physical_init() { // queue of outgoing frames

            master = false;  // we are not currently bus master

            recv = send = null; // clear the send and receive frame buffers

}

 

////////// incoming events from the network interface /////////

                       

// In I2C, frames can be any length. So each packet is converted directly to a frame

// other physical layers might have limited frame sizes so each packet might get split

// up into multiple frames.

 

i2C_recv_start_isr() { // start of a frame

            if (!master) {  // if I’m master then ignore (was sent by SELF)

            recv = null;        // otherwise, get ready to receive

                        recv_ix = 0;

                        wait_for_stop = false;

            } else {  // if I’m master then put address on bus

                        *PORT = send[send_ix++]; // start sending current frame

            }

}

 

i2C_send_start() {

            if (tryStart()) {                 // not guaranteed to succeed in i2C

                        master = true;   // if successful the become master and get a frame to send

                        send = get_frame(); // get a frame to send from the queue

                        send_ix = 0;      // initialize send counter

                        send_length = get_packet_length(send);

            }

}

 

 

i2C_recv_stop_isr() {

            if (wait_for_stop) {  // not our frame so ignore

wait_for_stop = false;

                        return;

            }

            if (!master)  { // just received a frame so send up to datalink layer (frame == packet in i2C)

                        packet = assemble_packet(recv, recv_ix);     // reassembles frames into packets, if packet is complete, return packet else null

if (packet) datalink_recv(recv, recv_ix);

            }

            master = false;

            if (frames_to_send()) { // if outgoing frames are pending, then try to get bus

                        i2C_send_start();

            }

}

 

i2C_recv_byte_isr() {

            if (wait_for_stop) return;  // ignore these events if message is not for me

            if (!master) {                   // must be slave so add to the incoming frame buffer

            if (recv_ix == 0)  { // first byte of incoming frame so process header                                   

            if (*PORT != SELF) {   // check if frame is for me

                                    wait_for_stop = true; // set to ignore until stop if not

                                    return;

            }

// otherwise, this frame is for me

// throw away first byte (physical header)  (or use to authenticate packet!)

recv = new packet;  // start a new frame, which is a packet

}

else recv[recv_ix++] = *PORT;  // we’re in the middle of a frame so add new byte to buffer

            } else {  // we are master so send another byte from send frame buffer

                        if (send_ix == send_length) i2C_send_stop();  // frame is finished, so send a stop condition

                        else {    // we are in the middle of a send frame so continue

                                    *PORT = send[send_ix++];

                        }

}          

}