void registerPort(CorbaPort& port); bool addPort(PortBase& port); bool addPort(PortService_ptr port); bool addPort(CorbaPort& port); bool addInPort(const char* name, InPortBase& inport); bool addOutPort(const char* name, OutPortBase& outport);
포트의 등록: 기존의 registerPort등의 멤버 함수와의 차이는, 등록의 성공 여부를 |
반환값으로 돌려주는지 아닌지이다. 등록이 실패하는 것은 이미 같은 포트명이나 같은 포트의 인스턴스가 등록되어 있었을 경우이다. 그 이외의 기능은 같다.
bool removePort(PortBase& port); bool removePort(PortService_ptr port); bool removeInPort(InPortBase& port); bool removeOutPort(OutPortBase& port); bool removePort(PortBase& port); bool removePort(PortService_ptr port); bool removePort(CorbaPort& port);
포트의 등록 해제: 기존의 deletePort등의 멤버 함수와의 차이는, 등록의 성공 여부를 |
반환값으로 돌려주는지 아닌지이다. 등록이 실패하는 것은 이미 같은 포트명이나 같은 포트의 인스턴스가 등록되어 있었을 경우이다. 그 이외의 기능은 같다.
bool readAll();
class DataIn: public RTC::DataFlowComponentBase { RTC::TimedLong input_data1_; RTC::InPort<RTC::TimedLong> inport1_; RTC::TimedLong input_data2_; RTC::InPort<RTC::TimedLong> inport2_; public: explicit DataIn(RTC::Manager* manager): RTC::DataFlowComponentBase(manager), input_data1_(), inport1_("inport1", input_data1_), input_data2_(), inport2_("inport2", input_data2_) { } virtual RTC::ReturnCode_t onInitialize() { registerInPort("inport1", inport1_); registerInPort("inport2", inport2_); return RTC::RTC_OK; } virtual RTC::ReturnCode_t onExecute(RTC::UniqueId exec_handle) { // inport1_과 inport2_에 대해서 read를 호출한다 const bool is_read_success = readAll(); if (is_read_success) { std::cout << input_data1_.data << std::endl; std::cout << input_data2_.data << std::endl; } return RTC::RTC_OK; } }; bool writeAll();
class DataOut: public RTC::DataFlowComponentBase { RTC::TimedLong output_data1_; RTC::OutPort<RTC::TimedLong> outport1_; RTC::TimedLong output_data2_; RTC::OutPort<RTC::TimedLong> outport2_; public: explicit DataOut(RTC::Manager* manager): RTC::DataFlowComponentBase(manager), output_data1_(), outport1_("outport1", output_data1_), output_data2_(), outport2_("outport2", output_data2_) { } virtual RTC::ReturnCode_t onInitialize() { registerOutPort("outport1", outport1_); registerOutPort("outport2", outport2_); return RTC::RTC_OK; } virtual RTC::ReturnCode_t onExecute(RTC::UniqueId exec_handle) { output_data1_.data += 2; output_data2_.data += 3; // outport1_과 outport2_에 대해서 write를 호출한다 const bool is_write_success = writeAll(); if (!is_write_success) { std::cout << "write fail" << std::endl; } return RTC::RTC_OK; } }; void setReadAll(bool read=true, bool completion=false);
class DataIn: public RTC::DataFlowComponentBase { RTC::TimedLong input_data1_; RTC::InPort<RTC::TimedLong> inport1_; RTC::TimedLong input_data2_; RTC::InPort<RTC::TimedLong> inport2_; public: explicit DataIn(RTC::Manager* manager): RTC::DataFlowComponentBase(manager), input_data1_(), inport1_("inport1", input_data1_), input_data2_(), inport2_("inport2", input_data2_) { } virtual RTC::ReturnCode_t onInitialize() { registerInPort("inport1", inport1_); registerInPort("inport2", inport2_); setReadAll(); // ★ return RTC::RTC_OK; } virtual RTC::ReturnCode_t onExecute(RTC::UniqueId exec_handle) { // onExecute가 불리기 직전에 inport1_과 inport2_의 read가 불리고 있다 std::cout << input_data1_.data << std::endl; std::cout << input_data2_.data << std::endl; return RTC::RTC_OK; } };
void setWriteAll(bool write=true, bool completion=false);
class DataOut: public RTC::DataFlowComponentBase { RTC::TimedLong output_data1_; RTC::OutPort<RTC::TimedLong> outport1_; RTC::TimedLong output_data2_; RTC::OutPort<RTC::TimedLong> outport2_; public: explicit DataOut(RTC::Manager* manager): RTC::DataFlowComponentBase(manager), output_data1_(), outport1_("outport1", output_data1_), output_data2_(), outport2_("outport2", output_data2_) { } virtual RTC::ReturnCode_t onInitialize() { registerOutPort("outport1", outport1_); registerOutPort("outport2", outport2_); setWriteAll(); // ★ return RTC::RTC_OK; } virtual RTC::ReturnCode_t onExecute(RTC::UniqueId exec_handle) { output_data1_.data += 2; output_data2_.data += 3; return RTC::RTC_OK; // onExecute를 빠진 직후에 outport1_과 outport2_의 write가 불린다 } };
class MyDataListener : public ConnectorDataListenerT<RTC::TimedLong> { public: virtual void operator()(const ConnectorInfo& info, const TimedLong& data) { // 콜백의 처리 }; };
MyDataListener *listner = new MyDataListener(); m_port.addConnectorDataListener(ON_BUFFER_WRITE, listner);
m_port.removeConnectorDataListener(ON_BUFFER_WRITE, listner);
class MyConnectorListener : public ConnectorListener { public: virtual void operator()(const ConnectorInfo& info) { // 콜백의 처리 }; };
MyConnectorListener *listner = new MyConnectorListener(); m_port.addConnectorListener(ON_BUFFER_EMPTY, listner);
m_port.removeConnectorListener(ON_BUFFER_EMPTY, listner);
void setOnPublishInterfaces(ConnectionCallback* on_publish);
void setOnSubscribeInterfaces(ConnectionCallback* on_subscribe);
void setOnConnected(ConnectionCallback* on_connected);
뮤텍스가 락 되고 있기 때문에, 콜백내에서 콜백을 설정한 포트에 대해서 get_connector_profiles나 get_port_profile 등을 호출하면 데드 락 되는 것에 주의. 콜백을 설정한 포트 이외의 포트에 대해서는 뮤텍스가 락 되어 있지 않기 때문에, get_port_profile등의 호출은 가능. 예를 들면, 포트1으로 포트2를 접속하는 것을 생각한다. 포트1에 setOnConnected로 콜백을 설정해 둔다. 이 콜백내로부터 포트1에 대해서 get_port_profile등의 호출을 실시하면 데드 락 된다. 포트2에 대해서는 get_port_profile등을 호출할 수 있다.
void setOnUnsubscribeInterfaces(ConnectionCallback* on_subscribe);
뮤텍스가 락 되고 있기 때문에, 콜백내에서 접속 대상 포트의 get_connector_profiles나 get_port_profile 등을 호출하면 데드 락 되는 것에 주의. setOnConnected와 달라, 콜백을 설정하고 있지 않는 포트에 대해도 get_port_profile 등을 호출할 수 없는 것에 주의. 예를 들면, 포트1으로 포트2를 접속하는 것을 생각한다. 포트1에 setOnConnected로 콜백을 설정해 둔다. 이 콜백내에서는 포트1, 포트2 모두 get_port_profile등의 호출을 실시하면 데드 록 된다.
void setOnDisconnected(ConnectionCallback* on_disconnected);
절단 처리의 도중에 어떠한 에러가 있어도 콜백은 불려 가는 것에 주의. 또, 뮤텍스의 락 되고 있기 때문에, setOnUnsubscribeInterfaces와 같이, 데드 락에 주의.
void setOnConnectionLost(ConnectionCallback* on_connection_lost);
다만, 이 콜백에 관해서는, PortBase에서는 처리의 구현을 하고 있지 않고, 상속 클래스측에서 구현하게 되어 있다. 현재는, OutPort에만 구현되고 있어 InPort와 CorbaPort에서는 콜백을 설정해도 불려 갈 것은 없다.
다만, addPort나 registerPort등에서 포트를 RTC에 등록하고 있지 않는 상태에서는,.[포트명]이 되어 있다. 또, addPort나 registerPort등의 호출을 onInitialize 이전(constructor등)에 실시하면, RTC의 인스턴스명이 확정하고 있지 않기 때문에, 포트명은 .[포트명]이 되어 버린다.
subscribeInterfaces의 호출에 대해서, 도중에 1개에서도 실패했을 경우, 즉석에서 에러 복귀한다
subscribeInterfaces의 호출에 대해서, 도중에 실패해도, 그대로 처리는 속행한다. 접속 대상 포트 모두에 대해서 처리를 한 후, 발생한 에러에 대응하는 에러 반환값을 돌려준다.
const char* getName() const;
·PortBase의 protected 멤버 함수 eraseConnectorProfile가
뮤텍스의 락을 실시하지 않게 되었다.
·PortBase의 이하의 멤버 함수를 호출했을 때,
접속하고 있는 포트를 모두 체크해 무효가 된 포트가 있으면, 절단 처리를 실시하게 되었다. get_port_profile() get_connector_profiles() get_connector_profile()
·포트의 프호퍼티"connection_limit"를 지정하면,
접속수의 제한을 할 수 있게 되었다.
■데이터 포트 【콜백 관련】 ·InPort의 이하의 콜백 설정 함수가 삭제되었다.
그 대신해, addConnectorDataListener를 사용한다. void setOnWrite(OnWrite<DataType>* on_write); void setOnWriteConvert(OnWriteConvert<DataType>* on_wconvert); void setOnOverflow(OnOverflow<DataType>* on_overflow); void setOnUnderflow(OnUnderflow<DataType>* on_underflow);
·OutPot의 이하의 멤버 함수가 삭제되었다.
콜백의 설정은 addConnectorDataListener를 사용한다. bool read(DataType& value); void setReadBlock(bool block); void setWriteBlock(bool block); void setReadTimeout(long int timeout); void setWriteTimeout(long int timeout); void setOnOverflow(OnOverflow<DataType>* on_overflow); void setOnRead(OnRead<DataType>* on_read); void setOnReadConvert(OnReadConvert<DataType>* on_rconvert); void setOnUnderflow(OnUnderflow<DataType>* on_underflow); void setOnConnect(OnConnect* on_connect); void setOnDisconnect(OnConnect* on_disconnect); void onConnect(const char* id, PublisherBase* publisher); void onDisconnect(const char* id);
【접속시의 정책 설정】 ·RT System Editor로 데이터 포트를 접속할 때,
송신 정책과 버퍼링 정책을 지정할 수 있게 되었다.
송신 정책(접속 방식이 flush(디폴트)의 경우는 사용할 수 없다) - All: InPort의 버퍼에 쌓여 있는 데이터를 한 번에 모두 송신한다 - Fifo: InPort의 버퍼에 쌓여 있는 데이터를 FIFO로 간주해(오래된 것부터 1개씩) 송신한다 - Skip: InPort의 버퍼에 쌓여 있는 데이터를 스킵해 송신한다 - New: InPort의 버퍼에 쌓여 있는 데이터의 최신값만을 송신한다
버퍼링 정책 ·버퍼 기입시에 버퍼가 풀이었던 경우의 동작을 지정할 수 있다. - overwrite: 덮어쓰기한다 - do_nothing: 아무것도 하지 않는다 - block: 블록 한다. 타임 아웃 설정가능.
·버퍼 읽기시에 버퍼가 빈 경우의 동작을 지정할 수 있다. - readback: 최신의 값을 다시 읽는다 - do_nothing: 아무것도 하지 않는다 - block: 블록 한다. 타임 아웃 설정가능.
·데이터 포트의 접속시의 프로퍼티에"dataport.serializer.cdr.endian"
을 지정하면, 송수신 하는 데이터의 endian를 변경할 수 있다. 그러나, RT System Editor는 대응하고 있지 않다.
【그 외】 ·DataPortStatus에 BUFFER_ERROR가 추가되었다.
·데이터 포트로 CORBA 대신에 TCP/IP를 이용하고 통신을 실시하는 것이
할 수 없게 되었다. (TCP/IP용의 Provider/Consumer를 자작하면 가능하다고 생각된다)
·InPort::read의 반환값의 형태가 변경되었다.
(RC1) 읽어들인 데이터 (RELEASE) 읽을 성공 여부를 나타내는 bool
·Timed*의 데이터에 대해서 현재 시각을 부여하는 함수 setTimestamp()가 추가되었다.
·OutPort::write()로 타임 스탬프를 부여하지 않게 되었다.
·OutPot에 이하의 멤버 함수가 추가되었다.
이것을 이용하면 1대 다접속 시에 접속마다의 write의 결과를 취득할 수 있다. DataPortStatus::Enum getStatus(int index); DataPortStatusList getStatusList();
·데이터 포트의 pull의 동작
- InPort::isNew()는 항상 false를 돌려준다. - 송신측의 버퍼에 데이터가 없는 경우는, InPort::read()의 반환값이 false가 된다. - OutPort측의 Buffer empty policy의 설정에 의해, 버퍼가 빈 경우의 동작이 다르다. 디폴트로는 readback이 되어 있기 때문에, 한 번 데이터를 write() 하는과 같은 값을 계속읽는다.
데이터 포트를 push로 접속했을 경우와 pull로 접속했을 경우에서는 프로그래밍 스타일이 다르다.
[push의 경우] RTC::ReturnCode_t ConsoleOut::onExecute(RTC::UniqueId ec_id) { if (m_inport.isNew()) { m_inport.read(); // 데이터를 이용한 처리 } return RTC::RTC_OK; }
[pull의 경우] RTC::ReturnCode_t ConsoleOut::onExecute(RTC::UniqueId ec_id) { bool ret = m_inport.read(); if (ret == true) { // 데이터를 이용한 처리 } return RTC::RTC_OK; }
■서비스 포트 【접속시의 정책 설정】 ·CorbaPort의 접속에 대해 ConnectorProfile::properties에 "port.connection.strictness"라고 하는 프로퍼티를 설정할 수 있게 되었다. 이 프로퍼티에는 "strict" 나 "best_effort"를 설정한다.
CorbaPort.h에서 인용 * strict: 모든 컨슈머(consumer)로 지정한 참조가 존재해, 한편 네로잉에도 * 성공해 컨슈머(consumer)에게 적절히 세트 할 수 있었을 경우에게만 Port * 사이의 접속을 확립한다. * * best_effort: 네로잉등에 실패했을 경우에서도, 에러를 돌려주는 것 * 구 Port 간의 접속을 확립한다.
【그 외】 ·CorbaPort로, 접속중에 RTC를 Activate, Deactivate 해, 재차 Activate 하면 컨슈머(consumer)측으로부터 액세스 할 수 없는 문제가 해결되었다.
■Manager 관계 Manager에 마스터와 슬레이브라고 하는 관계를 할 수 있었다. 자세한 것은[openrtm-users 01099]의 安藤씨의 해설을 참조.
【rtc.conf에게 주는 프로퍼티의 변경】 ·Manager의 프로퍼티(rtc.conf에게 주는 프로퍼티)로 변경이 있었다.
"corba.endpoint" 사용할 수 없게 되었다.대신에"corba.endpoints"를 사용하게 되었다.
"manager.is_master" NO로 하면 Manager의 CORBA 오브젝트를 네이밍 서비스에 등록하지 않게 되었다.
"manager.corba_servant" NO로 하면 Manager의 CORBA 오브젝트를 생성하지 않는다.
"manager.is_master" YES이면, Manager의 프로퍼티"corba.master_manager"로 지정되어 있는 포트 번호를 ORB의 엔드 포인트로서 추가하게 되었다.
"manager.shutdown_on_nortcs" YES의 경우,"manager.is_master"NO이면, 프로세스내의 RTC가 0개에 된 타이밍에 Manager가 자동 종료하게 되었다. 다만,[openrtm-users 01149]의 패치를 대는 것.
【RTC 기동시의 커멘드 라인 인수의 옵션의 추가】
-a 지정하면, Manager의 CORBA 오브젝트를 생성하지 않는다. 다만, ManagerConfig::parseArgs()에 버그가 있기 위해, 이 옵션을 지정해도 Manager의 CORBA 오브젝트의 생성이 유효하게 된다.("maanger.corba_servant"로 스펠 미스) SVN의 최신 소스에서는 수정되고 있는 모양. -d 지정하면, Manager가 마스터가 된다. -o Manager의 프로퍼티를 추가할 수 있다. 이 옵션에 이어 (프로퍼티의 키):(프로퍼티의 값)라고 쓴다. 예를 들면, -o test.property:100 -p Manager의 프로퍼티"corba.endpoints"에 포트 번호를 추가한다. 예를 들면, -p 50000
【Manager의 내부 구현의 변경】 ·RC1에서는 미구현이었던 ModuleManager::getLoadableModules()가 구현되었다.
→ Manager::getLoadableModules()를 사용할 수 있게 되었다.
·Manager::setModuleInitProc()로 설정한 함수가 실행된다
타이밍이 변경되었다. Manager::activateManager()로 실행되는 것 자체는 변경되어 있지 않다. 그러나, Manager의 프로퍼티"manager.components.precreate"로 지정된 RTC를 기동하는 처리와의 차례가 변경되고 있다. (RC1) "manager.components.precreate"의 RTC를 생성한 후 (RELEASE) "manager.components.precreate"의 RTC를 생성하기 전
·Manager에 RTC의 가비지 콜렉션과 같은 기능이 추가되었다.
RTC를 exit 하면, Manager가 1초 주기에 exit 된 RTC를 delete 한다. 다만, 버그 있어.[openrtm-users 01149]의 패치를 대는 것. 또, createComponent로 생성한 RTC가 on_initialize로 실패하면 그 RTC는 delete 되지 않고, 메모리 리크 한다. RTC의 initialize가 실패하면 RTC를 exit 하지만, exit는 initialize가 성공하지 않았다고 처리를 거부하기 위해, Manager::notifyFinalized가 불리지 않고, Manager의 RTC 가비지 콜렉션이 일하지 않기 때문에.
·Manager가 RTC를 삭제할 때, delete를 직접 사용하는 것이 아니라,
Manager::registerFactory로 등록된 RTC 삭제 함수를 사용하도록 수정되었다.
·Manager::load()로, 제2 인수의 초기화 함수명이 빈 경우의 처리가 추가되었다.
초기화 함수명이 빈 경우는, 제1 인수의 모듈명에"Init"를 부여했다 초기화 함수명으로 모듈의 로드를 시도하게 되었다.
·Manager::createComponent로, 지정한 RTC를 생성하는 Factory가
등록되지 않은 경우, Manager의 프로퍼티"manager.modules.load_path"로 지정한 패스로부터, 지정한 RTC를 생성 가능한 모듈을 검색해, 자동 로드하는 기능이 추가되었다.
【IDL 인터페이스의 변경】 ·IDL 인터페이스 RTM::Manager가 변경되었다.
(추가) boolean is_master(); ManagerList get_master_managers(); RTC::ReturnCode_t add_master_manager(in Manager mgr); RTC::ReturnCode_t remove_master_manager(in Manager mgr); ManagerList get_slave_managers(); RTC::ReturnCode_t add_slave_manager(in Manager mgr); RTC::ReturnCode_t remove_slave_manager(in Manager mgr); (삭제) Manager get_owner(); Manager set_owner(in Manager mgr); Manager get_child(); Manager set_child(in Manager mgr);
·ManagerServant::get_loadable_modules(),
ManagerServant::get_loaded_modules(), ManagerServant::get_factory_profiles()는, 본래, 자신의 것 뿐만이 아니라, 슬레이브의 모듈도 취득할 수 있는 메소드같지만, 현재의 실장에서는 자신의 모듈 밖에 취득할 수 없다.