|
6 | 6 | #include "MOOS/libMOOS/Comms/MOOSMsg.h" |
7 | 7 | #include "MOOS/libMOOS/Comms/MOOSCommClient.h" |
8 | 8 | #include "MOOS/libMOOS/Comms/MOOSAsyncCommClient.h" |
| 9 | +#include "MOOS/libMOOS/App/MOOSApp.h" |
9 | 10 |
|
10 | 11 | #include <pybind11/pybind11.h> |
11 | 12 | #include <pybind11/stl_bind.h> |
@@ -215,6 +216,159 @@ class AsyncCommsWrapper : public MOOS::MOOSAsyncCommClient { |
215 | 216 | /** close connection flag */ |
216 | 217 | bool closing_; |
217 | 218 | }; |
| 219 | + |
| 220 | +/** this is a class which wraps CMOOSApp to provide |
| 221 | + * an interface more suitable for python wrapping |
| 222 | + */ |
| 223 | +class AppWrapper : public CMOOSApp { |
| 224 | +private: |
| 225 | + typedef CMOOSApp BASE; |
| 226 | +public: |
| 227 | + |
| 228 | + ~AppWrapper(){ |
| 229 | + // Clean shutdown |
| 230 | + } |
| 231 | + |
| 232 | + bool Run(const std::string & sServer, int Port, const std::string & sMyName, const std::string & sMissionFile = "") { |
| 233 | + SetAppName(sMyName); |
| 234 | + SetServer(sServer, Port); |
| 235 | + if (!sMissionFile.empty()) { |
| 236 | + SetMissionFile(sMissionFile); |
| 237 | + } |
| 238 | + return BASE::Run(); |
| 239 | + } |
| 240 | + |
| 241 | + //we can support vectors of objects by not lists so |
| 242 | + //here we have a function which copies a list to vector |
| 243 | + MsgVector FetchMailAsVector() { |
| 244 | + MsgVector v; |
| 245 | + MOOSMSG_LIST M; |
| 246 | + if (Fetch(M)) { |
| 247 | + std::copy(M.begin(), M.end(), std::back_inserter(v)); |
| 248 | + } |
| 249 | + return v; |
| 250 | + } |
| 251 | + |
| 252 | + /* python strings can be binary lets make this specific*/ |
| 253 | + bool NotifyBinary(const std::string& sKey, const std::string & sData, |
| 254 | + double dfTime) { |
| 255 | + CMOOSMsg M(MOOS_NOTIFY, sKey, sData.size(), (void *) sData.data(), |
| 256 | + dfTime); |
| 257 | + return BASE::m_Comms.Post(M); |
| 258 | + } |
| 259 | + |
| 260 | + // Virtual methods that can be overridden |
| 261 | + bool OnNewMail(MOOSMSG_LIST &NewMail) override { |
| 262 | + bool bResult = true; |
| 263 | + |
| 264 | + if (on_new_mail_object_) { |
| 265 | + PyGILState_STATE gstate = PyGILState_Ensure(); |
| 266 | + try { |
| 267 | + MsgVector v; |
| 268 | + std::copy(NewMail.begin(), NewMail.end(), std::back_inserter(v)); |
| 269 | + py::object result = on_new_mail_object_(v); |
| 270 | + bResult = py::bool_(result); |
| 271 | + } catch (const py::error_already_set& e) { |
| 272 | + PyGILState_Release(gstate); |
| 273 | + std::string err_msg = "OnNewMail:: caught an exception thrown in python callback:\n"; |
| 274 | + err_msg.append(e.what()); |
| 275 | + throw pyMOOSException(err_msg.c_str()); |
| 276 | + } |
| 277 | + PyGILState_Release(gstate); |
| 278 | + } |
| 279 | + |
| 280 | + return bResult; |
| 281 | + } |
| 282 | + |
| 283 | + bool OnConnectToServer() override { |
| 284 | + bool bResult = true; |
| 285 | + |
| 286 | + if (on_connect_to_server_object_) { |
| 287 | + PyGILState_STATE gstate = PyGILState_Ensure(); |
| 288 | + try { |
| 289 | + py::object result = on_connect_to_server_object_(); |
| 290 | + bResult = py::bool_(result); |
| 291 | + } catch (const py::error_already_set& e) { |
| 292 | + PyGILState_Release(gstate); |
| 293 | + std::string err_msg = "OnConnectToServer:: caught an exception thrown in python callback:\n"; |
| 294 | + err_msg.append(e.what()); |
| 295 | + throw pyMOOSException(err_msg.c_str()); |
| 296 | + } |
| 297 | + PyGILState_Release(gstate); |
| 298 | + } |
| 299 | + |
| 300 | + return bResult; |
| 301 | + } |
| 302 | + |
| 303 | + bool OnStartUp() override { |
| 304 | + bool bResult = true; |
| 305 | + |
| 306 | + if (on_start_up_object_) { |
| 307 | + PyGILState_STATE gstate = PyGILState_Ensure(); |
| 308 | + try { |
| 309 | + py::object result = on_start_up_object_(); |
| 310 | + bResult = py::bool_(result); |
| 311 | + } catch (const py::error_already_set& e) { |
| 312 | + PyGILState_Release(gstate); |
| 313 | + std::string err_msg = "OnStartUp:: caught an exception thrown in python callback:\n"; |
| 314 | + err_msg.append(e.what()); |
| 315 | + throw pyMOOSException(err_msg.c_str()); |
| 316 | + } |
| 317 | + PyGILState_Release(gstate); |
| 318 | + } |
| 319 | + |
| 320 | + return bResult; |
| 321 | + } |
| 322 | + |
| 323 | + bool Iterate() override { |
| 324 | + bool bResult = true; |
| 325 | + |
| 326 | + if (iterate_object_) { |
| 327 | + PyGILState_STATE gstate = PyGILState_Ensure(); |
| 328 | + try { |
| 329 | + py::object result = iterate_object_(); |
| 330 | + bResult = py::bool_(result); |
| 331 | + } catch (const py::error_already_set& e) { |
| 332 | + PyGILState_Release(gstate); |
| 333 | + std::string err_msg = "Iterate:: caught an exception thrown in python callback:\n"; |
| 334 | + err_msg.append(e.what()); |
| 335 | + throw pyMOOSException(err_msg.c_str()); |
| 336 | + } |
| 337 | + PyGILState_Release(gstate); |
| 338 | + } |
| 339 | + |
| 340 | + return bResult; |
| 341 | + } |
| 342 | + |
| 343 | + // Setters for Python callbacks |
| 344 | + bool SetOnNewMailCallback(py::object func) { |
| 345 | + on_new_mail_object_ = func; |
| 346 | + return true; |
| 347 | + } |
| 348 | + |
| 349 | + bool SetOnConnectToServerCallback(py::object func) { |
| 350 | + on_connect_to_server_object_ = func; |
| 351 | + return true; |
| 352 | + } |
| 353 | + |
| 354 | + bool SetOnStartUpCallback(py::object func) { |
| 355 | + on_start_up_object_ = func; |
| 356 | + return true; |
| 357 | + } |
| 358 | + |
| 359 | + bool SetIterateCallback(py::object func) { |
| 360 | + iterate_object_ = func; |
| 361 | + return true; |
| 362 | + } |
| 363 | + |
| 364 | +private: |
| 365 | + /** callback functions (stored) */ |
| 366 | + py::object on_new_mail_object_; |
| 367 | + py::object on_connect_to_server_object_; |
| 368 | + py::object on_start_up_object_; |
| 369 | + py::object iterate_object_; |
| 370 | +}; |
| 371 | + |
218 | 372 | } |
219 | 373 | ;//namesapce |
220 | 374 |
|
@@ -504,6 +658,92 @@ PYBIND11_MODULE(pymoos, m) { |
504 | 658 | ; |
505 | 659 |
|
506 | 660 |
|
| 661 | + /********************************************************************* |
| 662 | + CMOOSApp base class |
| 663 | + *********************************************************************/ |
| 664 | + |
| 665 | + py::class_<CMOOSApp>(m, "base_app") |
| 666 | + .def("register",static_cast<bool(CMOOSApp::*) |
| 667 | + (const std::string&, double)> (&CMOOSApp::Register), |
| 668 | + "Register for notification in changes of named variable.", |
| 669 | + py::arg("name"), py::arg("interval") = 0) |
| 670 | + .def("notify",static_cast<bool(CMOOSApp::*) |
| 671 | + (const std::string&, |
| 672 | + const std::string&, double)> (&CMOOSApp::Notify), |
| 673 | + "Notify the MOOS community that something has changed.", |
| 674 | + py::arg("name"), py::arg("value"), py::arg("time") = -1.) |
| 675 | + .def("notify",static_cast<bool(CMOOSApp::*) |
| 676 | + (const std::string&, double, |
| 677 | + double)> (&CMOOSApp::Notify), |
| 678 | + "Notify the MOOS community that something has changed.", |
| 679 | + py::arg("name"), py::arg("value"), py::arg("time") = -1.) |
| 680 | + .def("get_app_name", &CMOOSApp::GetAppName, |
| 681 | + "Return the name of the application.") |
| 682 | + .def("get_community_name", &CMOOSApp::GetCommunityName, |
| 683 | + "Return name of community the app is attached to.") |
| 684 | + .def("is_connected", &CMOOSApp::IsConnected, |
| 685 | + "Return True if this app is connected to the server.") |
| 686 | + .def("is_registered_for", &CMOOSApp::IsRegisteredFor, |
| 687 | + "Return True if we are registered for name variable") |
| 688 | + .def("set_app_freq", &CMOOSApp::SetAppFreq, |
| 689 | + "Set the frequency at which Iterate() is called.", |
| 690 | + py::arg("freq")) |
| 691 | + .def("get_app_freq", &CMOOSApp::GetAppFreq, |
| 692 | + "Get the frequency at which Iterate() is called.") |
| 693 | + .def("set_comms_freq", &CMOOSApp::SetCommsFreq, |
| 694 | + "Set the frequency at which communications occur.", |
| 695 | + py::arg("freq")) |
| 696 | + .def("get_comms_freq", &CMOOSApp::GetCommsFreq, |
| 697 | + "Get the frequency at which communications occur.") |
| 698 | + ; |
| 699 | + |
| 700 | + |
| 701 | + /*********************************************************************/ |
| 702 | + /** CMOOSApp WRAPPER CLASS FOR PYTHON */ |
| 703 | + /*********************************************************************/ |
| 704 | + |
| 705 | + py::class_<MOOS::AppWrapper, CMOOSApp>(m, "app") |
| 706 | + .def(py::init<>()) |
| 707 | + |
| 708 | + .def("run", &MOOS::AppWrapper::Run, |
| 709 | + "Run the MOOS application.", |
| 710 | + py::arg("server"), py::arg("port"), py::arg("name"), |
| 711 | + py::arg("mission_file") = "") |
| 712 | + |
| 713 | + .def("fetch", &MOOS::AppWrapper::FetchMailAsVector, |
| 714 | + "Fetch incoming mail as a vector.") |
| 715 | + |
| 716 | + .def("notify_binary", &MOOS::AppWrapper::NotifyBinary, |
| 717 | + "Notify binary data. (specific to pymoos.)", |
| 718 | + py::arg("name"), py::arg("binary_data"), py::arg("time")=-1) |
| 719 | + |
| 720 | + .def("set_on_new_mail_callback", |
| 721 | + &MOOS::AppWrapper::SetOnNewMailCallback, |
| 722 | + "Set the callback to be invoked when new mail arrives. " |
| 723 | + "The callback will be passed a list of messages.", |
| 724 | + py::arg("func")) |
| 725 | + |
| 726 | + .def("set_on_connect_to_server_callback", |
| 727 | + &MOOS::AppWrapper::SetOnConnectToServerCallback, |
| 728 | + "Set the callback to be invoked when connected to the server. " |
| 729 | + "This is a good place to register for notifications.", |
| 730 | + py::arg("func")) |
| 731 | + |
| 732 | + .def("set_on_start_up_callback", |
| 733 | + &MOOS::AppWrapper::SetOnStartUpCallback, |
| 734 | + "Set the callback to be invoked at application startup. " |
| 735 | + "This is called before connecting to the server.", |
| 736 | + py::arg("func")) |
| 737 | + |
| 738 | + .def("set_iterate_callback", |
| 739 | + &MOOS::AppWrapper::SetIterateCallback, |
| 740 | + "Set the callback to be invoked at each iteration. " |
| 741 | + "This is the main work loop of the application.", |
| 742 | + py::arg("func")) |
| 743 | + |
| 744 | + ; |
| 745 | + |
| 746 | + |
507 | 747 | /********************************************************************* |
508 | 748 | some MOOS Utilities |
509 | 749 | *********************************************************************/ |
|
0 commit comments