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 Playerstage-commit@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/playerstage-commit