You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
arts/flow/bus.cpp

368 lines
7.1 KiB

/*
Copyright (C) 1998-2000 Stefan Westerfeld
stefan@space.twc.de
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "bus.h"
#include "flowsystem.h"
#include "debug.h"
#include <iostream>
#include <set>
#ifdef __SUNPRO_CC
/* SunPRO CC looses to link this when the_BusManager is static, because
later a template implementation file references this symbol. */
#define the_BusManager __internal_aRts_the_BusManager__Bahh__
#else
static
#endif
Arts::BusManager *the_BusManager = 0;
using namespace Arts;
using namespace std;
// shutdown bus manager on termination
namespace Arts {
static class BusManagerShutdown :public StartupClass
{
public:
void startup() { };
void shutdown()
{
if(::the_BusManager)
{
delete ::the_BusManager;
::the_BusManager = 0;
}
}
} The_BusManagerShutdown;
}
BusManager::BusManager()
{
// this constructor isn't public (Singleton)
}
BusManager *BusManager::the()
{
if(!::the_BusManager) ::the_BusManager = new BusManager;
return(::the_BusManager);
}
BusManager::Bus *BusManager::findBus(const string& name)
{
list<Bus *>::iterator bi;
for(bi = _busList.begin(); bi != _busList.end(); bi++)
{
if((*bi)->name == name) return(*bi);
}
Bus *bus = new Bus;
bus->left.start();
bus->right.start();
bus->name = name;
_busList.push_back(bus);
return(bus);
}
vector<string> *BusManager::busList()
{
set<string> names;
set<string>::iterator si;
list<Bus *>::iterator bi;
for(bi = _busList.begin(); bi != _busList.end(); bi++)
names.insert((*bi)->name);
vector<string> *bl = new vector<string>;
for(si=names.begin();si != names.end();si++) bl->push_back(*si);
return bl;
}
void BusManager::addClient(const string& busname, BusClient *client)
{
Bus *bus = findBus(busname);
bus->clients.push_back(client);
// attach the new client
client->snode()->virtualize("left", bus->left._node(), "invalue");
client->snode()->virtualize("right", bus->right._node(), "invalue");
}
void BusManager::removeClient(BusClient *client)
{
list<Bus *>::iterator bi;
for(bi = _busList.begin(); bi != _busList.end(); bi++)
{
Bus *bus = *bi;
list<BusClient *>::iterator ci;
for(ci = bus->clients.begin(); ci != bus->clients.end(); ci++)
{
if(*ci == client)
{
bus->clients.erase(ci);
if(bus->clients.empty() && bus->servers.empty())
{
_busList.erase(bi);
delete bus;
}
else
{
client->snode()->devirtualize("left",
bus->left._node(), "invalue");
client->snode()->devirtualize("right",
bus->right._node(), "invalue");
}
return;
}
}
}
}
void BusManager::addServer(const string& busname, BusClient *server)
{
Bus *bus = findBus(busname);
bus->servers.push_back(server);
server->snode()->virtualize("left",bus->left._node(),"outvalue");
server->snode()->virtualize("right",bus->right._node(),"outvalue");
}
void BusManager::removeServer(BusClient *server)
{
list<Bus *>::iterator bi;
for(bi = _busList.begin(); bi != _busList.end(); bi++)
{
Bus *bus = *bi;
list<BusClient *>::iterator si;
for(si = bus->servers.begin(); si != bus->servers.end(); si++)
{
if(*si == server)
{
bus->servers.erase(si);
if(bus->clients.empty() && bus->servers.empty())
{
_busList.erase(bi);
delete bus;
}
else
{
server->snode()->devirtualize("left",
bus->left._node(), "outvalue");
server->snode()->devirtualize("right",
bus->right._node(),"outvalue");
}
return;
}
}
}
}
namespace Arts {
class Synth_BUS_UPLINK_impl :public Synth_BUS_UPLINK_skel,
public StdSynthModule, public BusClient
{
BusManager *bm;
bool running, active, relink;
string _busname;
public:
Synth_BUS_UPLINK_impl();
string busname() { return _busname; }
void busname(const string& newname);
AutoSuspendState autoSuspend() { return asSuspend; }
void streamInit();
void streamEnd();
ScheduleNode *snode() { return _node(); }
void CallBack();
void connect();
void disconnect();
};
REGISTER_IMPLEMENTATION(Synth_BUS_UPLINK_impl);
}
Synth_BUS_UPLINK_impl::Synth_BUS_UPLINK_impl() :running(false)
{
bm = BusManager::the();
}
void Synth_BUS_UPLINK_impl::streamInit()
{
assert(!running);
running = true;
active = relink = false;
connect(); // connect to the BusManager
}
void Synth_BUS_UPLINK_impl::busname(const string& newname)
{
_busname = newname;
/* TODO */
// to be sure that reconnection happens when outside the scheduling cycle
if(running)
{
relink = true;
CallBack();
}
}
void Synth_BUS_UPLINK_impl::connect()
{
assert(active == false);
if(!_busname.empty())
{
active = true;
bm->addClient(_busname, this);
}
}
void Synth_BUS_UPLINK_impl::disconnect()
{
if(active == true)
{
bm->removeClient(this);
active = false;
}
}
void Synth_BUS_UPLINK_impl::CallBack()
{
if(relink)
{
disconnect();
connect();
relink = false;
}
}
void Synth_BUS_UPLINK_impl::streamEnd()
{
disconnect();
assert(running);
running = false;
}
namespace Arts {
class Synth_BUS_DOWNLINK_impl :public Synth_BUS_DOWNLINK_skel,
public StdSynthModule, public BusClient
{
bool running, active, relink;
BusManager *bm;
string _busname;
void connect();
void disconnect();
public:
string busname() { return _busname; }
void busname(const string& newname);
Synth_BUS_DOWNLINK_impl();
AutoSuspendState autoSuspend() { return asSuspend; }
void streamInit();
void streamEnd();
void CallBack();
ScheduleNode *snode() { return _node(); }
};
REGISTER_IMPLEMENTATION(Synth_BUS_DOWNLINK_impl);
}
Synth_BUS_DOWNLINK_impl::Synth_BUS_DOWNLINK_impl() :running(false)
{
bm = BusManager::the();
}
void Synth_BUS_DOWNLINK_impl::streamInit()
{
assert(!running);
running = true;
active = relink = false;
connect();
}
void Synth_BUS_DOWNLINK_impl::streamEnd()
{
assert(running);
running = false;
disconnect();
}
void Synth_BUS_DOWNLINK_impl::connect()
{
assert(active == false);
if(!_busname.empty())
{
active = true;
bm->addServer(_busname, this);
}
}
void Synth_BUS_DOWNLINK_impl::disconnect()
{
if(active == true)
{
bm->removeServer(this);
active = false;
}
}
void Synth_BUS_DOWNLINK_impl::CallBack()
{
if(relink)
{
disconnect();
connect();
relink = false;
}
}
void Synth_BUS_DOWNLINK_impl::busname(const string& newname)
{
_busname = newname;
/* TODO */
// to be sure that reconnection happens when outside the scheduling cycle
if(running)
{
relink = true;
CallBack();
}
}