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;

                        boolean update;   // flag for use in copy-on-read

}

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) {

    if (!tmp = lookup(dataID)) return (-ENOTPUBLISHED); // trying to post to unpublished data item

    if (tmp.publisher != SELF) return(-ENOTPUBLISHER); // can't write if SELF is not publisher

    tmp.value = value; // finally, write the value

    if (tmp.policy == CR) return(0);  // no need to do anything!

    foreach(p in tmp.subscribers) {

        message[0] = POST;

        message[1] = dataID;

        message[2] = SELF;   // so that receiver can verify!

        message[3] = tmp.value;  // send the data

        datalink_send(p, message, 4); // send post message to p

    }

}  // behavior depends on policy

int update(int dataID, char *value) {

    if (!tmp = lookup(dataID)) return (-ENOTPUBLISHED); // trying to post to unpublished data item

    if (SELF not in tmp.subscribers) return(-ENOTSUBSCRIBER); 

    if (tmp.policy = CW) { 

        *value = tmp.value;

        return(0);

    }

    // its copy on read, so send a message!

   message[0] = UPDATE;

   message[1] = dataID;

   message[2] = SELF;   // so that receiver can verify

   datalink_send(tmp.publisher, message, 3); // send post message to p

   tmp.update = false;

   sleep_on(update_q, TIMEOUT);                    // blocking

   if (!tmp.update) return (-EREADTIMEOUT);

   else *value = tmp.value;

}

///// 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:  

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

                                    if (SELF not in tmp.subscribers) transport_errror(mesage); // not subscribed

                                    if (message[2] != tmp.publisher) transport_error(message); // wrong publisher

                                    tmp.value = message[3];

                                    if (tmp.policy == CR) {

                                            wake_on(update_q); // wake up reader

                                            tmp.update = true;

                                    }

                        UPDATE:

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

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

                                    if (message[2] not in tmp.subscribers) transport_error(message); // not sub

                                    subscriber = message[2]; // save subscriber info

                                    message = make_message(POST, tmp.dataID, SELF, tmp.value);

                                    transport_send(subscriber, message, 4);       

                        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() {

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

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

            // not shown: make queue of outgoing frames

            // see below for plug and play version of this function

}

 

////////// 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 (init) return;

            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 (init) return;

            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)

                        if (physical_control_frame(recv)) process_control_frame(recv); // for plug-and-play

                        else 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 (init) {ack = true; return;}

            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++];

                        }

}          

}

i2C_byte_error_isr() {

    if (init) { nack = true; return; }

    if (wait_for_stop) return;

    if (!master) { // the error was that this processor did not send an acknowledgement!

                      // but there doesn't seem to be anything we can do about it

                wait_for_stop = true;   // may as well ignore rest of message and hope for retransmit

                return;

    } else { // the receiver did not acknowledge the byte so we need to retransmit the frame

            if (get_xmit_count(send) >= MAXRETRY) physical_error(frame);

            else physical_frame_send(send) ; // just puts this frame back on the internal queue and increments 

                                                                // frame's retransmit counter

            i2C_send_stop() ; // abort this frame

    }

}

 

 

Question 1: How can we add plug and play to this?

    1. In init, get the bus and probe each address until no ack is received then claim the address (SELF = i)

 

boolean ack,nack;

i2C_init {

   init = true;

   for (i = 0; (i < MAX & !ack); i++) {

       while (! i2C_try_start());  // get control of the bus

        ack = nak = false;          // variables to be byte or error isr's

       *PORT = i;                    // send the byte

       while (!ack & !nack);    // wait for ack or nack

   }

    if (ack) {        

        SELF = i;

        physical_frame_send(make_control_frame(0,NEWADDRESS, SELF)); // broadcast new addres

    }

    else physical_error();

    init = false;

}

Question 2: How can we add watchdog to the system?

each processor periodically sends a ping message to SELF+1 modulo the highest address in the system.

should this be at the physical, transport, or datalink level?

periodically send, if after a certain number of sends some flag is not cleared, then there is an error 

in the system.

           

 

Question 3: How to I do the pipes

    open(pipeID, READ)    // OPEN message, create local buffer for incoming data

    open( pipeID, WRITE) // OPEN message

    read(pipeID);  // no message (assume copy on write), return item from buffer or -1

    write(pipeID); // DATA message