Update of /cvsroot/playerstage/code/player/design
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2796

Added Files:
        module.c player.c 
Log Message:


--- NEW FILE: module.c ---
// Implementation of mymodule, a module that does laser-based obstacle
// avoidance

// My message-processing function
int mymodule_processmessage(player_io_t *io, player_msghdr_t* hdr, void* data);

// My configuration function
int mymodule_configure(player_io_t* io, player_module_options_t* opt);

// My run function
void mymodule_run(player_io_t* io);

int
main(int argc, char** argv)
{
  player_io_t* io;
  player_tcp_io_t tcpio;
  player_devaddr_t addr;
  player_module_options_t* opt = NULL;

  // Initialize player
  io = player_init(argc, argv);

  // Parse config file to create option table
  player_parse_config_file(&opt, argv[1]);

  // Configure module
  mymodule_configure(opt);

  // Construct my address
  addr.host = 0; // 0 means localhost
  addr.robot = 6665;
  addr.interf = PLAYER_POSITION2D_CODE;
  addr.index = 0;

  // Add my interface (could add more in the same way)
  player_add_interface(io,&addr);

  // In this case we'll use TCP, so do the necessary transport-specific
  // binding
  player_tcp_add_io(&tcpio, io);
  player_tcp_bind(&tcpio);

  // Start up my module
  mymodule_run(io);

  return(0);
}

int 
mymodule_configure(player_io_t* io, player_module_options_t* opt)
{
  // Step through table, storing options to where?
}

int 
mymodule_processmessage(player_io_t *io, player_msghdr_t* hdr, void* data)
{
  // If no ack is requested, just cache it.  New messages overwrite old
  // ones, so if I want to see *every* message, I must process them here,
  // instead of caching them like this.
  if(!hdr->ack)
  {
    player_cache_insert(io->message_cache, hdr, data);
    return(0);
  }
  else
  {
    // An ack was requested.  What kind of message is it?
    
    // Is it a message to me to set odometry?
    if(player_match_message_to(io, hdr, 
                               io->addrs[0].host,
                               io->addrs[0].robot,
                               io->addrs[0].interf,
                               io->addrs[0].index,
                               PLAYER_POSITION2D_REQ_SET_ODOM))
    {
      // Try to set odometry, return 0 on success, -1 on failure
      if(set_odometry() == 0)
        return(0);
      else
        return(-1);
    }
    // Is it a message to me to enable motor power?
    else if(player_match_message_to(io, hdr, 
                                    io->addrs[0].host,
                                    io->addrs[0].robot,
                                    io->addrs[0].interf,
                                    io->addrs[0].index,
                                    PLAYER_POSITION2D_REQ_MOTOR_POWER))
    {
      // Forward it to the underlying device, somehow...
    }
    else
    {
      // don't know this message
      return(-1);
    }
  }
}

// Run, with me in control of the event loop
void
mymodule_run(player_io_t* io)
{
  for(;;)
  {
    // Read incoming messages, with short timeout
    player_tcp_readmessages(io->tcp_io,10);
   
    // Call my update method
    mymodule_update(io);

    // Write outgoing messages
    player_tcp_writemessages(io->tcp_io);
  }
}

// Execute one loop of my module
void
mymodule_update(player_io_t* io)
{
  // Read from my inqueue, processing each message:
  //
  player_processmessages(io, mymodule_processmessage);

  // Alternatively, I could just use the default processor, which puts
  // incoming messages into a cache:
  //
  //player_processmessages(io, player_processmessage_default);

  // Do some module-specific stuff here

  // Get latest laser scan, from anybody, to anybody, and delete it from 
  // the cache
  player_laser_data_t scan;
  if(player_get_laser_scan(io, NULL, NULL, PLAYER_LASER_DATA_SCAN,
                           &scan, 1))
  {
    // handle data in 'scan'
  }

  // Construct an outgoing message (fill it in)
  player_position2d_data_t msg;
  // Publish the message, to all interested parties, from my first address
  player_broadcast_position2d_pose(io, 
                                   io->addrs[0],
                                   &msg);
}


--- NEW FILE: player.c ---
typedef struct player_devaddr
{
  /** The "host" on which the device resides.  Transport-dependent. */
  uint32_t host;
  /** The "robot" or device collection in which the device resides.
      Transport-dependent */
  uint32_t robot;
  /** The interface provided by the device; must be one of PLAYER_*_CODE */
  uint16_t interf;
  /** Which device of that interface */
  uint16_t index;
} player_devaddr_t;

// Generic message header.
typedef struct player_msghdr
{
  /** Origin address */
  player_devaddr_t from;
  /** Destination address */
  player_devaddr_t to;
  /** Message type; interface-specific */
  uint8_t type;
  /** Time associated with message contents (seconds since epoch) */
  double timestamp;
  /** For keeping track of associated messages.  Transport-specific. */
  uint32_t seq;
  /** Whether an acknowledgement is requeested */
  uint8_t ack;
  /** Size in bytes of the payload to follow */
  uint32_t size;
} player_msghdr_t;

// An acknowledgement message
typedef struct player_player_ack
{
  uint8_t value;
} player_player_ack_t;

typedef struct player_msgqueue
{
  // A linked list gets implemented here, using glib
} player_msgqueue_t;

typedef struct player_cache
{
  // A dictionary of messages, keyed by message signature, goes here
  // (use glib).  New messages overwrite old ones with the same signature.
} player_cache_t;

// Insert data, with signature hdr, into the cache
int player_cache_insert(player_cache_t* cache, 
                        player_msghdr_t* hdr,
                        void* data);
// Retrieve message with signature hdr, and put it in data.
int player_cache_retrieve(player_cache_t* cache, 
                          player_msghdr_t* hdr,
                          void* data);

// Similar to player_cache_retrieve, but deletes message from the cache 
// after retrieval
int player_cache_remove(player_cache_t* cache,
                        player_msghdr_t* hdr,
                        void* data);

// Forward declaration of TCP manager;
struct player_tcp_io;

// A player_io_t object contains all the state necessary for a single
// module.  A single module may have multiple addresses.
typedef struct player_io
{
  // A list of my addresses
  player_devaddr_t* addrs;
  // My input queue
  player_msgqueue_t* inqueue;
  // My output queue
  player_msgqueue_t* outqueue;
  // A cache of incoming message
  player_cache_t* message_cache;
  // Which transport are we using?
  uint8_t transport_id;
  // TCP manager object, in case we're using TCP
  player_tcp_io_t* tcp_io;
  // Other local state goes here
} player_io_t; 

typedef struct player_module_options
{
  // A dictionary/hash-table of module name-value options goes here, 
  // using glib
} player_module_options_t;

// initialize player. returns some local state.
player_io_t* player_init(int argc, char* argv);

// clean up
int player_fini(player_io_t* io);

// Parse a config file to build an option table
//
// If (*opt) is NULL, a new table is created.
int
player_parse_config_file(player_module_options_t** opt,
                         const char* fname);

// Declare an interface that I'll support
int player_add_interface(player_io_t* io, player_devaddr_t* addr);

// A message structure
typedef struct player_$(INTERFACE)_$(TYPE)
{
  // ...
} player_$(INTERFACE)_$(TYPE)_t;

// connect to a device somewhere out there. returns a handle to the device.
int
player_subscribe_$(INTERFACE)_$(TYPE)(player_io_t* io, 
                                      player_devaddr_t* addr)
{
  // Contact the device.  Now, this should be done in a transport-specific
  // way.
  if(io->transport == PLAYER_TRANSPORT_TCP)
  {
    // Do a TCP-specific subscription
  }
}

// disconnect from a device somewhere out there.
int
player_unsubscribe_$(INTERFACE)_$(TYPE)(player_io_t* io, 
                                        player_devaddr_t* addr);
{
  // Contact the device.  Now, this should be done in a transport-specific
  // way.
  if(io->transport == PLAYER_TRANSPORT_TCP)
  {
    // Do a TCP-specific unsubscription
  }
}

// Publish a message.
//
//   io: Local io handle
//   from: Address of originating device.  Needed to distinguish between
//         multiple interfaces.  If NULL, 
//   to: Address of destination device.  If NULL, then the message is sent
//       to all subscribers.
//   data: The message itself.
//   ack: If 1, then an acknowledgement from the destination device is
//        requested.  Cannot be 1 if 'to' is NULL (i.e., cannot request
//        acknowledgement for a multicast message).
//   ack_timeout: how long to wait for acknowledgement; 0 for no waiting,
//                -1 for indefinite timeout
//
// Returns: 0 on success, non-zero on error.  If ack is 0, then the return
// value only indicates whether the message was sent.  If ack is 1, then
// the return value is a response from the destination device (may need a
// special value to distinguish timeout from device-generated error).
int 
player_publish_$(INTERFACE)_$(TYPE)(player_io_t* io, 
                                     player_devaddr_t* from, 
                                     player_devaddr_t* to, 
                                     player_$(INTERFACE)_$(TYPE)_t* data,
                                     int ack,
                                     int ack_timeout);

// Short form of publishing, for convenience
int player_broadcast_$(INTERFACE)_$(TYPE)(player_io_t* io,
                                          player_devaddr_t* from,
                                          player_$(INTERFACE)_$(TYPE)_t* data)
{
  return(player_publish_$(INTERFACE)_$(TYPE)(io, from, NULL, data, 0, -1));
}

// A utility function to retrieve a certain type of message from the local 
// cache.  The 'remove' argument indicates whether the message should be
// removed from the cache.
int player_get_$(INTERFACE)_$(TYPE)(player_io_t* io,
                                    player_devaddr_t* from,
                                    player_devaddr_t* to,
                                    player_$(INTERFACE)_$(TYPE)_t* data,
                                    int remove)
{
  player_msghdr_t hdr;
  hdr.from = from;
  hdr.to = to;
  hdr.type = $(TYPE);
  if(remove)
    return(player_cache_remove(io->cache, &hdr, data));
  else
    return(player_cache_retrieve(io->cache, &hdr, data));
}

// A utility function to wait for a specific message to arrive on my
// inqueue.   The message is popped (?)
int player_waitfor_$(INTERFACE)_$(THING)(player_io_t* io, 
                                         player_devaddr_t* from, 
                                         player_devaddr_t* to, 
                                         player_$(INTERFACE)_$(TYPE)_t* data);

// A utility function to send an acknowledgement
int player_send_ack(player_io_t* io,
                    player_devaddr_t* from,
                    player_devaddr_t* to,
                    uint8_t value)
{
  player_player_ack_t ack;
  ack.value = value;
  return(player_publish_player_ack(io, from, to, &ack, 0, 0));
}

// A utility function to match message signature, using from address.  -1
// for any field means don't care
int player_match_message_from(player_io_t* io,
                              player_msghdr_t* hdr,
                              int host,
                              int robot,
                              int interf,
                              int index,
                              int type);

// A utility function to match message signature, using to address.  -1
// for any field means don't care
int player_match_message_to(player_io_t* io,
                            player_msghdr_t* hdr,
                            int host,
                            int robot,
                            int interf,
                            int index,
                            int type);

// Other message-match functions could be provided....

// Signature for a message-processing function
typedef int 
(*player_processmessage_fn_t)(player_io_t *io,
                              player_msghdr_t* hdr,
                              void* data);

// A default message processer, which simply caches the messages for later
// perusal
int
player_processmessage_default(player_io_t* io,
                              player_msghdr_t* hdr,
                              void* data)
{
  player_cache_insert(io->message_cache, hdr, data);

  // If an ack was requested, send a success code (might not be the right
  // behavior, but what other option is there if the module is not
  // personally processing each messagee?)
  if(hdr->ack)
    player_send_ack(io, hdr->to, hdr->from, 0);
}

// A utility function to pop and process messages, one by one
int player_processmessages(player_io_t* io, 
                           player_processmessage_fn_t process_fn)
{
  int retval;
  while(!player_queue_empty(io->inqueue))
  {
    // Pop a message off the queue
    player_msghdr_t* hdr;
    void* data;
    player_queue_pop(&hdr, &data, io->inqueue);

    // Process the message and catch the return value
    retval = (process_fn)(io,hdr,data);

    // If an ack was requested, send it
    if(hdr->ack)
      player_send_ack(io, hdr->to, hdr->from, retval);
  }
}


/////////////////////////////////////////////////////////////////////////
//
// TCP-specific functionality
//
typedef struct player_tcp_io
{
  // List of player_io objects that I'm managing (one per module)
  player_io_t** ios;
  // TCP state, like ports and sockets that I'm managing
} player_tcp_io_t;

// Add an io object (i.e., a module) to this TCP manager
int player_tcp_add_io(player_tcp_io_t* tcpio, player_io_t* io);

// Bind to one or more TCP ports, as indicated by the modules embedded
// in 'tcpio'.
int player_tcp_bind(player_tcp_io_t* io);

// Read incoming messages from bound TCP sockets and push them onto
// appropriate tcpio->io->inqueue.
int player_tcp_readmessages(player_tcp_io_t* tcpio, int timeout);

// Pop outgoing messages from all tcpio->io->outqueue and write them out 
// on TCP sockets
int player_tcp_writemessages(player_tcp_io_t* tcpio);
/////////////////////////////////////////////////////////////////////////







-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
Playerstage-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/playerstage-commit

Reply via email to