Update of /cvsroot/playerstage/code/player/server/drivers/blackboard/localbb
In directory
sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20366/server/drivers/blackboard/localbb
Added Files:
test.cpp localbb.cpp Makefile.am test.cfg
Log Message:
Commit of Ben Morellis 'Blackboard' driver and interface
--- NEW FILE: Makefile.am ---
noinst_LTLIBRARIES =
if INCLUDE_LOCALBB
noinst_LTLIBRARIES += liblocalbb.la
dnl noinst_PROGRAMS = test
endif
AM_CXXFLAGS = -Wall -I$(top_srcdir) -I$(top_srcdir)/client_libs
liblocalbb_la_SOURCES = localbb.cpp
dnl test_SOURCES = test.cpp
dnl test_LDADD = liblocalbb.la
$(top_srcdir)/client_libs/libplayerc/.libs/libplayerc.la
--- NEW FILE: test.cfg ---
driver
(
name "localbb"
provides [ "blackboard:0" ]
)
--- NEW FILE: test.cpp ---
#include <libplayerc/playerc.h>
#include <iostream>
#define KEY "test"
using namespace std;
void On_First_Device_Event(player_blackboard_entry_t event)
{
printf("First device event fired for key '%s'\n", event.key);
printf("Key value = %d,%d,%d,%d\n", event.data[0], event.data[1],
event.data[2], event.data[3]);
}
void On_Second_Device_Event(player_blackboard_entry_t event)
{
printf("Second device event fired for key '%s'\n", event.key);
printf("Key value = %d,%d,%d,%d\n", event.data[0], event.data[1],
event.data[2], event.data[3]);
}
class BlackBoardTester
{
public:
bool Initialise();
bool CreateFirstDevice();
bool CreateSecondDevice();
bool SubscribeFirstDevice();
bool SubscribeSecondDevice();
bool SubscribeFirstDeviceToKey();
bool SubscribeSecondDeviceToKey();
bool SetFirstDeviceEntry();
bool SetSecondDeviceEntry();
bool UnsubscribeFirstDeviceKey();
bool UnsubscribeSecondDeviceKey();
bool UnsubscribeFirstDevice();
bool UnsubscribeSecondDevice();
void Read();
bool Shutdown();
private:
playerc_client_t* client_first;
playerc_client_t* client_second;
playerc_blackboard_t* first;
playerc_blackboard_t* second;
};
bool BlackBoardTester::Initialise()
{
client_first = NULL;
client_second = NULL;
first = NULL;
second = NULL;
client_first = playerc_client_create(NULL, "localhost", 6665);
if (0 != playerc_client_connect(client_first))
{
printf("Error connecting first client\n");
return false;
}
client_second = playerc_client_create(NULL, "localhost", 6665);
if (0 != playerc_client_connect(client_second))
{
printf("Error connecting second client\n");
return false;
}
return true;
}
bool BlackBoardTester::CreateFirstDevice()
{
first = playerc_blackboard_create(client_first, 0);
if (first == NULL)
{
printf("Failed to create first device.\n");
return false;
}
first->on_blackboard_event = On_First_Device_Event;
return true;
}
bool BlackBoardTester::CreateSecondDevice()
{
second = playerc_blackboard_create(client_second, 0);
if (second == NULL)
{
printf("Failed to create second device.\n");
return false;
}
second->on_blackboard_event = On_Second_Device_Event;
return true;
}
bool BlackBoardTester::SubscribeFirstDevice()
{
if (playerc_blackboard_subscribe(first, PLAYER_OPEN_MODE))
{
printf("Error subscribing first\n");
return false;
}
return true;
}
bool BlackBoardTester::SubscribeSecondDevice()
{
if (playerc_blackboard_subscribe(second, PLAYER_OPEN_MODE))
{
printf("Error subscribing second\n");
return false;
}
return true;
}
bool BlackBoardTester::SubscribeFirstDeviceToKey()
{
player_blackboard_entry_t *t = new player_blackboard_entry_t;
memset(t, 0, sizeof(t));
const char* key = strdup(KEY);
if (playerc_blackboard_subscribe_to_key(first, key, t))
{
printf("Error subscribing to key '%s'\n", KEY);
return false;
}
if (t->data_count == 0)
{
printf("Key '%s' does not exist (EMPTY)\n", KEY);
}
else
{
printf("First subscribed to key '%s'\n", KEY);
printf("Key value = %d,%d,%d,%d\n", t->data[0], t->data[1],
t->data[2], t->data[3]);
}
delete t->data;
delete t->key;
delete t;
return true;
}
bool BlackBoardTester::SubscribeSecondDeviceToKey()
{
player_blackboard_entry_t *t = new player_blackboard_entry_t;
memset(t, 0, sizeof(t));
if (playerc_blackboard_subscribe_to_key(second, KEY, t))
{
printf("Error subscribing to key '%s'\n", KEY);
return false;
}
if (t->data_count == 0)
{
printf("Key '%s' does not exist (EMPTY)\n", KEY);
} else
{
printf("First subscribed to key '%s'\n", KEY);
printf("Key value = %d,%d,%d,%d\n", t->data[0], t->data[1],
t->data[2], t->data[3]);
}
delete t->data;
delete t->key;
delete t;
return true;
}
bool BlackBoardTester::SetFirstDeviceEntry()
{
player_blackboard_entry_t *entry = new player_blackboard_entry_t;
memset(entry, 0, sizeof(entry));
entry->key = strdup(KEY);
entry->key_count = strlen(KEY) + 1;
entry->data = new uint8_t[4];
entry->data[0] = 0;
entry->data[1] = 1;
entry->data[2] = 2;
entry->data[3] = 3;
entry->data_count = 4;
if (playerc_blackboard_set_entry(first, entry))
{
printf("Error setting first entry\n");
return false;
}
delete entry->key;
delete entry->data;
delete entry;
return true;
}
bool BlackBoardTester::SetSecondDeviceEntry()
{
player_blackboard_entry_t *entry = new player_blackboard_entry_t;
memset(entry, 0, sizeof(entry));
entry->key = strdup(KEY);
entry->key_count = strlen(KEY) + 1;
entry->data = new uint8_t[4];
entry->data[0] = 0;
entry->data[1] = 1;
entry->data[2] = 2;
entry->data[3] = 3;
entry->data_count = 4;
if (playerc_blackboard_set_entry(second, entry))
{
printf("Error setting second entry\n");
return false;
}
delete entry->key;
delete entry->data;
delete entry;
return true;
}
bool BlackBoardTester::UnsubscribeFirstDeviceKey()
{
if (playerc_blackboard_unsubscribe_from_key(first, KEY))
{
printf("Error unsubscribing first from key\n");
return false;
}
return true;
}
bool BlackBoardTester::UnsubscribeSecondDeviceKey()
{
if (playerc_blackboard_unsubscribe_from_key(second, KEY))
{
printf("Error unsubscribing second from key\n");
return false;
}
return true;
}
bool BlackBoardTester::UnsubscribeFirstDevice()
{
if (playerc_blackboard_unsubscribe(first))
{
printf("Error unsubscribing first from client\n");
return false;
}
playerc_blackboard_destroy(first);
return true;
}
bool BlackBoardTester::UnsubscribeSecondDevice()
{
if (playerc_blackboard_unsubscribe(second))
{
printf("Error unsubscribing second from client\n");
return false;
}
playerc_blackboard_destroy(second);
return true;
}
void BlackBoardTester::Read()
{
playerc_client_read(client_first);
playerc_client_read(client_second);
}
bool BlackBoardTester::Shutdown()
{
playerc_client_disconnect(client_first);
playerc_client_disconnect(client_second);
playerc_client_destroy(client_first);
playerc_client_destroy(client_second);
return true;
}
int main()
{
BlackBoardTester t;
printf("Initialise\n");
bool res = t.Initialise();
if (res)
{
printf("CreateFirstDevice\n");
res = t.CreateFirstDevice();
}
if (res)
{
printf("CreateSecondDevice\n");
res = t.CreateSecondDevice();
}
if (res)
{
printf("SubscribeFirstDevice\n");
res = t.SubscribeFirstDevice();
}
if (res)
{
printf("SubscribeSecondDevice\n");
res = t.SubscribeSecondDevice();
}
if (res)
{
printf("SubscribeFirstDeviceToKey\n");
res = t.SubscribeFirstDeviceToKey();
}
if (res)
{
printf("SubscribeSecondDeviceToKey\n");
res = t.SubscribeSecondDeviceToKey();
}
if (res)
{
printf("SetFirstDeviceEntry\n");
res = t.SetFirstDeviceEntry();
}
if (res)
{
printf("SetSecondDeviceEntry\n");
res = t.SetSecondDeviceEntry();
}
printf("Read\n");
t.Read();
if (res)
{
printf("UnsubscribeFirstDeviceKey\n");
res = t.UnsubscribeFirstDeviceKey();
}
if (res)
{
printf("UnsubscribeSecondDeviceKey\n");
res = t.UnsubscribeSecondDeviceKey();
}
if (res)
{
printf("UnsubscribeFirstDevice\n");
res = t.UnsubscribeFirstDevice();
}
if (res)
{
printf("UnsubscribeSecondDevice\n");
res = t.UnsubscribeSecondDevice();
}
}
--- NEW FILE: localbb.cpp ---
/*
* Player - One Hell of a Robot Server
* Copyright (C) 2004 Brian Gerkey [EMAIL PROTECTED]
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/*
* $Id: localbb.cpp,v 1.1 2007/09/20 02:50:46 thjc Exp $
*
*
*/
/** @ingroup drivers */
/** @{ */
/** @defgroup driver_LocalBB LocalBB
* @brief Local memory implementation of a blackboard. The data entries are
stored internally in a hash-map.
* Internally information is stored in two hash-maps. One hash-map contains a
map of labels to the entry data.
* This stores the actual data. The second hash-map stores a map of device
queues which are listening to an entry.
* These are the devices that are sent events when an entry is updated.
* CAVEATS:
* -There is no checking to see if a device is already subscribed to a key. If
a device subscribes to a key twice, it will receive two updates.
* -All listening devices are sent updates when an entry is set, even if that
device set the entry.
@par Provides
- @ref interface_blackboard
@par Requires
- None
@par Configuration requests
- None
@par Configuration file options
@par Example
@verbatim
driver
(
name "localbb"
provides [ "blackboard:0" ]
)
@endverbatim
@author Ben Morelli
*/
/** @} */
#include <sys/types.h> // required by Darwin
#include <stdlib.h>
#include <libplayercore/playercore.h>
#include <libplayercore/error.h>
#include <playererror.h>
#include <vector>
#include <map>
#include <strings.h>
#include <iostream>
/[EMAIL PROTECTED] Custom blackboard-entry data representation used internally
by the driver. */
typedef struct EntryData
{
/** Constructor. Sets all members to 0 or NULL. */
EntryData() { interf = 0; type = 0; subtype = 0; data_count = 0; data = NULL;
}
//~EntryData() { if (data != NULL) delete [] data; } Why doesn't it like this?
/** Player interface */
uint16_t interf;
/** Message type */
uint8_t type;
/** Message sub-type */
uint8_t subtype;
/** Data size */
uint32_t data_count;
/** Data */
uint8_t* data;
} EntryData;
/[EMAIL PROTECTED] Custom blackboard entry representation used internally by
the driver.*/
typedef struct BlackBoardEntry
{
/** Constructor. Sets key to an empty string. Data should be
automatically set to empty values. */
BlackBoardEntry() { key = ""; }
/** Entry label */
string key;
/** Entry data */
EntryData data;
} BlackBoardEntry;
// Function prototypes
/** Convienience function to convert from the internal blackboard entry
representation to the player format. The user must clean-up the player
blackboard entry. */
player_blackboard_entry_t ToPlayerBlackBoardEntry(const BlackBoardEntry &entry);
/** Convienience function to convert from the player blackboard entry to the
internal representation. */
BlackBoardEntry FromPlayerBlackBoardEntry(const player_blackboard_entry_t
&entry);
// Remember to clean-up the entry afterwards. Delete the key and data.
player_blackboard_entry_t ToPlayerBlackBoardEntry(const BlackBoardEntry &entry)
{
player_blackboard_entry_t result;
memset(&result, 0, sizeof(player_blackboard_entry_t));
result.interf = entry.data.interf;
result.type = entry.data.type;
result.subtype = entry.data.subtype;
result.key_count = strlen(entry.key.c_str()) + 1;
result.key = new char[result.key_count]; //strdup(entry.key.c_str());
memcpy(result.key, entry.key.c_str(), result.key_count);
result.data_count = entry.data.data_count;
result.data = new uint8_t[result.data_count];
memcpy(result.data, entry.data.data, result.data_count);
return result;
}
// This entry will be cleaned-up automatically by the destructor.
BlackBoardEntry FromPlayerBlackBoardEntry(const player_blackboard_entry_t
&entry)
{
BlackBoardEntry result;
result.data.interf = entry.interf;
result.data.type = entry.type;
result.data.subtype = entry.subtype;
assert(entry.key != NULL);
result.key = string(entry.key);
result.data.data_count = entry.data_count;
result.data.data = new uint8_t[result.data.data_count];
memcpy(result.data.data, entry.data, result.data.data_count);
return result;
}
////////////////////////////////////////////////////////////////////////////////
/** Local memory blackboard driver. Stores entries in a hash-map in local
memory. */
class LocalBB : public Driver
{
public:
/** Default constructor. */
LocalBB(ConfigFile* cf, int section);
/** Default destructor. */
~LocalBB();
/** Driver initialisation. */
int Setup();
/** Driver de-initialisation. */
int Shutdown();
// MessageHandler
/** Process incoming messages. */
int ProcessMessage(QueuePointer &resp_queue, player_msghdr *
hdr, void * data);
private:
// Message subhandlers
/** Process a subscribe to key message. */
int ProcessSubscribeKeyMessage(QueuePointer &resp_queue,
player_msghdr * hdr, void * data);
/** Process an unsubscribe from key message. */
int ProcessUnsubscribeKeyMessage(QueuePointer &resp_queue,
player_msghdr * hdr, void * data);
/** Process a set entry message. */
int ProcessSetEntryMessage(QueuePointer &resp_queue,
player_msghdr * hdr, void * data);
// Blackboard handler functions
/** Add the key and queue combination to the listeners hash-map
and return the entry for the key. */
BlackBoardEntry SubscribeKey(const string &key, const
QueuePointer &resp_queue);
/** Remove the key and queue combination from the listeners
hash-map. */
void UnsubscribeKey(const string &key, const QueuePointer &qp);
/** Set the entry in the entries hashmap. */
void SetEntry(const BlackBoardEntry &entry);
// Helper functions
/** Check that the message has a valid size. */
bool CheckHeader(player_msghdr * hdr);
// Internal blackboard data
/** Map of labels to entry data. */
map<string, BlackBoardEntry> entries;
/** Map of labels to listening queues. */
map<string, vector<QueuePointer> > listeners;
};
////////////////////////////////////////////////////////////////////////////////
// Factory method.
Driver* LocalBB_Init(ConfigFile* cf, int section)
{
return ((Driver*)(new LocalBB(cf, section)));
}
////////////////////////////////////////////////////////////////////////////////
// Driver registration function
void LocalBB_Register(DriverTable* table)
{
table->AddDriver("localbb", LocalBB_Init);
}
////////////////////////////////////////////////////////////////////////////////
// Constructor.
LocalBB::LocalBB(ConfigFile* cf, int section) :
Driver(cf, section, true, PLAYER_MSGQUEUE_DEFAULT_MAXLEN,
PLAYER_BLACKBOARD_CODE)
{
// No settings needed currently.
}
////////////////////////////////////////////////////////////////////////////////
// Destructor.
LocalBB::~LocalBB()
{
// maps clean up themselves
}
////////////////////////////////////////////////////////////////////////////////
// Load resources.
int LocalBB::Setup()
{
PLAYER_MSG0(2, "LocalBB ready");
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// Clean up resources.
int LocalBB::Shutdown()
{
PLAYER_MSG0(2, "LocalBB shut down");
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// Process an incoming message.
int LocalBB::ProcessMessage(QueuePointer &resp_queue, player_msghdr * hdr, void
* data)
{
// Request for a subscription
if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ,
PLAYER_BLACKBOARD_REQ_SUBSCRIBE_TO_KEY, this->device_addr))
{
return ProcessSubscribeKeyMessage(resp_queue, hdr, data);
}
// Request for unsubscribe
else if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ,
PLAYER_BLACKBOARD_REQ_UNSUBSCRIBE_FROM_KEY, this->device_addr))
{
return ProcessUnsubscribeKeyMessage(resp_queue, hdr, data);
}
// Request to update an entry
else if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ,
PLAYER_BLACKBOARD_REQ_SET_ENTRY, this->device_addr))
{
return ProcessSetEntryMessage(resp_queue, hdr, data);
}
// Don't know how to handle this message
return -1;
}
////////////////////////////////////////////////////////////////////////////////
// Subscribe a device to a key.
int LocalBB::ProcessSubscribeKeyMessage(QueuePointer &resp_queue, player_msghdr
* hdr, void * data)
{
if (!CheckHeader(hdr))
return -1;
// Add the device to the listeners map
player_blackboard_entry_t *request =
reinterpret_cast<player_blackboard_entry_t*>(data);
BlackBoardEntry current_value = SubscribeKey(request->key , resp_queue);
// Get the entry for the given key
player_blackboard_entry_t response =
ToPlayerBlackBoardEntry(current_value);
size_t response_size = sizeof(player_blackboard_entry_t) +
response.key_count + response.data_count;
// Publish the blackboard entry
this->Publish(
this->device_addr,
resp_queue,
PLAYER_MSGTYPE_RESP_ACK,
PLAYER_BLACKBOARD_REQ_SUBSCRIBE_TO_KEY,
&response,
response_size,
NULL);
if (response.key)
{
delete [] response.key;
}
if (response.data)
{
delete [] response.data;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// Unsubscribe a device from a key.
int LocalBB::ProcessUnsubscribeKeyMessage(QueuePointer &resp_queue,
player_msghdr * hdr, void * data)
{
if (!CheckHeader(hdr))
return -1;
// Remove the device from the listeners map
player_blackboard_entry_t *request =
reinterpret_cast<player_blackboard_entry_t*>(data);
UnsubscribeKey(request->key, resp_queue);
// Send back an empty ack
this->Publish(
this->device_addr,
resp_queue,
PLAYER_MSGTYPE_RESP_ACK,
PLAYER_BLACKBOARD_REQ_UNSUBSCRIBE_FROM_KEY,
NULL,
0,
NULL);
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// Set an entry and send out update events to all listeners.
int LocalBB::ProcessSetEntryMessage(QueuePointer &resp_queue, player_msghdr *
hdr, void * data)
{
if (!CheckHeader(hdr))
return -1;
player_blackboard_entry_t *request =
reinterpret_cast<player_blackboard_entry_t*>(data);
BlackBoardEntry entry = FromPlayerBlackBoardEntry(*request);
SetEntry(entry);
// Send out update events to other listening devices
vector<QueuePointer> &devices = listeners[entry.key];
for (vector<QueuePointer>::iterator itr=devices.begin(); itr !=
devices.end(); itr++)
{
QueuePointer device_queue = (*itr);
this->Publish(this->device_addr,
device_queue,
PLAYER_MSGTYPE_DATA,
PLAYER_BLACKBOARD_DATA_UPDATE,
data,
hdr->size,
NULL);
}
// Send back an empty ack
this->Publish(this->device_addr,
resp_queue,
PLAYER_MSGTYPE_RESP_ACK,
PLAYER_BLACKBOARD_REQ_SET_ENTRY,
NULL,
0,
NULL);
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// Add a device to the listener list for a key. Return the current value of the
entry.
BlackBoardEntry LocalBB::SubscribeKey(const string &key, const QueuePointer
&resp_queue)
{
listeners[key].push_back(resp_queue);
return entries[key];
}
////////////////////////////////////////////////////////////////////////////////
// Remove a device from the listener list for a key.
void LocalBB::UnsubscribeKey(const string &key, const QueuePointer &qp)
{
vector<QueuePointer> &devices = listeners[key];
for (vector<QueuePointer>::iterator itr = devices.begin(); itr !=
devices.end(); itr++)
{
if ((*itr) == qp)
{
devices.erase(itr);
break;
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Set entry value in the entries map.
void LocalBB::SetEntry(const BlackBoardEntry &entry)
{
entries[entry.key] = entry;
}
////////////////////////////////////////////////////////////////////////////////
// Check that we have some data in the message.
bool LocalBB::CheckHeader(player_msghdr * hdr)
{
if (hdr->size <= 0)
{
PLAYER_ERROR2("request is wrong length (%d <= %d); ignoring",
hdr->size, 0);
return false;
}
return true;
}
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Playerstage-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/playerstage-commit