Service Manager for Wiring Architecture

Where to Find?

The experimental source code for the service manager implementation in the SOS operating system can be currently found on Atlantis SVN.

To obtain sources:

svn co http://atlantis.eng.yale.edu/svn/enalab/branches/neeraj/ 

You have to build /sos-1.x/config/svcmgr_test, /sos-1.x/config/nic, and /sos-1.x/tools/sos_server/bin/ with
'make sim -B.'

Then you can go up to the top-level directory and run simnetwork.bat to start a simulated network with 3 nodes, a nic, and a sossrv.
The python code is in /tools/python/ and you'll want to add this to your Python environment somehow. Here's one way: create an environmental variable (in Windows: System Properties->Advanced->Environmental Variables...) defining PYTHONPATH = <path to /tools/python>.

Introduction:

The service manager is the node-side component of the SOS scripting system. It allows a user to query the modules on a node and find out how they are interconnected. Interconnections are handled through wire structures which connect an output "pin" (a message that a module can send) to an input pin (a message that a different module can receive).

Python Interface

To use the service manager interface from a class-based interface in python, you can import the pysossm module. Python is a pretty self-documenting system. To see the docs for any python object, type help(obj). PysosSM is available in /tools/python/pysossm.py.

Here is an example that goes through the use of nearly all of the functions in pysosSM. You are meant to use it with the svcmgr_test config.

import pysossm as svc

sm = svc.svcmgr()
nodes = sm.get_nodes()
print nodes

#start the test configuration in its ping-pong ritual
sm.send(did = 211, type=svc.MSG_DONE)

#get the wires from the nodes for printing and modification
wires = sm.get_wires()
print wires

donewires = filter(lambda(w):w.spid == 210, wires)
sm.del_wires(donewires)

for i in xrange(len(donewires)):
donewires[i].daddr=donewires[(i+1)%len(donewires)].saddr

sm.make_wires(donewires)
print sm.get_wires()
sm.send(did = 211, type=svc.MSG_DONE, daddr=donewires[0].saddr);

Note: the svcmgr class derives from sossrv in the pysos module, so it supports all normal sossrv operations.

 

Module Interface

Modules which wish to participate in the service manager wiring system must register with the service manager when initializing. They also should use the sm_post() function to send messages over wires rather than the native SOS post_xxx() functions. The service manager internally uses these functions to send messages to all destinations.

The module interface is declared in $(SOSROOT)/modules/include/svcmgr.h for easy inclusion into any module.

There are currently only two functions defined: TODO! Add support for deregistration.

int8_t sm_register(sos_pid_t modpid, uint8_t noutputs);

A minimum registered module should have:

#include <svcmgr.h>

int8_t module(void* state, Message* msg) {
app_state_t* s = (app_state_t*) state;

switch(msg->type) {
case MSG_INIT:
sm_register(s->pid, NOUT); //NOUT is the number of output pins this module exposes
return SOS_OK;
}
//There is no way to deregister right now.
//TODO: Change this when versioning support is added.
}

There is also the posting function. Output pins are numbered from 0 for ease of finding them in the svcmgr data structures. Otherwise, posting is quite similar to the normal SOS post_xxx system. We currently do not properly handle messages with flag SOS_MSG_RELIABLE. This will be fixed with the next point release of svcmgr.

int8_t sm_post(sos_pid_t spid,   //source module pid
uint8_t oidx, //source pin index
uint8_t size,
void* data,
uint16_t flag);

Host Interface:

The service manager also implements a command interface for communication with the host computer or any other module that wishes to manipulate the wiring table. This is used by the Python scripting library to communicate with the nodes, for instance. The interface is declared in $(SOSROOT)/modules/include/svcmgr_interface.h.

The interface defines 5 messages which can be used to get or set node information:

 	SM_MSG_HELO           =  MOD_MSG_START+1,   //Number: 33
	/* Returns a response packet with a uint8_t array of PIDs 
* of the modules registered on the target node */
SM_CMD_GETMODLIST = MOD_CMD_START, //Number: 192
	/* Makes a wire between two modules if the input is compatible with the 
* output. Uses a sm_make_wire_t struct as the data. */
SM_CMD_MAKEWIRE = MOD_CMD_START + 3, //constructs wires according to host_wire_t structures in the message
        /* Lists wires between modules on a node */
SM_CMD_LISTWIRE = MOD_CMD_START + 4, //sends a set of host_wire_t structures after the resp_header
SM_CMD_DELETEWIRE = MOD_CMD_START + 5 //deletes all wires with the host_wire_t structures in the message

SM_MSG_HELO is used primarily for discovery of the service manager and will eventually be replaced by a better node discovery mechanism. A node that receives this message will send the same message back to the saddr of the message.

The other packets use a response packet structure to determine what particular message is the cause of the response. We use response packets rather than a simpler scheme with different SOS message types so that we can sequence messages and tie a message with a particular request (though this hasn't been done yet).

The response packet struct is below:

//This packet is returned with a MSG_SM_RESP message after every request
typedef struct sm_response_packet_t {
/* PID of the target of the original command */
sos_pid_t tpid;

/* Message we are responding to. */
uint8_t msg;

/* Error code (0 on success). */
int8_t status;

uint8_t seqno; //global packet sequence number... increments until wraparound
/* Size of response (bytes of data after this header). */
uint16_t size;
} PACK_STRUCT sm_response_packet_t;

The response packet structure is followed by zero or more data elements. The total size of the data elements sent is recorded in the size field of sm_response_packet_t. For example, SM_CMD_GETMODLIST returns a list of uint8_ts that are the pids of all of the modules. TODO: This needs to change for versioned modules.

In the case of the GETWIRE command, we return a list of host_wire_t structures that describe the wires:

typedef struct {
sos_pid_t spid;
uint8_t oidx;
sos_pid_t dpid;
uint8_t dmsgtype;
uint16_t daddr; //when using in MAKEWIRE, daddr==0 implies same node
} PACK_STRUCT host_wire_t;

These structures are also returned for wires that fail for SM_CMD_MAKEWIRE and SM_CMD_DELWIRE.

NOTE: If you want to make default wires in your configuration, just send a message to the service manager:

	hw = (host_wire_t*) ker_malloc(sizeof(hw[0]), 0);
hw2 =(host_wire_t*) ker_malloc(sizeof(hw2[0]), 0);

hw->spid = DIRECTOR_PID;
hw->oidx = OIDX_START_BLINK;
hw->dpid = ACTOR_PID;
hw->dmsgtype = MSG_START_BLINK;
hw->daddr = 0;

post_long(SVCMGR_PID, 0, SM_CMD_MAKEWIRE, sizeof(hw[0]), hw, SOS_MSG_RELEASE);

hw2->spid = ACTOR_PID;
hw2->oidx = OIDX_DONE;
hw2->dpid = DIRECTOR_PID;
hw2->dmsgtype = MSG_DONE;
hw2->daddr = 0;
post_long(SVCMGR_PID, 0, SM_CMD_MAKEWIRE, sizeof(hw2[0]), hw2, SOS_MSG_RELEASE);