diff --git a/clover/CMakeLists.txt b/clover/CMakeLists.txt index a97efc8d..23c48451 100644 --- a/clover/CMakeLists.txt +++ b/clover/CMakeLists.txt @@ -81,6 +81,7 @@ add_service_files( SetAttitude.srv SetRates.srv SetLEDEffect.srv + Execute.srv ) ## Generate actions in the 'action' folder @@ -167,6 +168,8 @@ add_executable(vpe_publisher src/vpe_publisher.cpp) add_executable(led src/led.cpp) +add_executable(shell src/shell.cpp) + target_link_libraries(simple_offboard ${catkin_LIBRARIES} ${GeographicLib_LIBRARIES} @@ -180,10 +183,14 @@ target_link_libraries(vpe_publisher ${catkin_LIBRARIES}) target_link_libraries(led ${catkin_LIBRARIES}) +target_link_libraries(shell ${catkin_LIBRARIES}) + add_dependencies(simple_offboard ${PROJECT_NAME}_generate_messages_cpp) add_dependencies(led ${PROJECT_NAME}_generate_messages_cpp) +add_dependencies(shell ${PROJECT_NAME}_generate_messages_cpp) + ## Rename C++ executable without prefix ## The above recommended prefix causes long target names, the following renames the ## target back to the shorter version for ease of user use diff --git a/clover/launch/clover.launch b/clover/launch/clover.launch index 50646e66..61a03084 100644 --- a/clover/launch/clover.launch +++ b/clover/launch/clover.launch @@ -10,6 +10,7 @@ + @@ -76,4 +77,7 @@ + + + diff --git a/clover/src/shell.cpp b/clover/src/shell.cpp new file mode 100644 index 00000000..06a9bd54 --- /dev/null +++ b/clover/src/shell.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +ros::Duration timeout; + +// TODO: handle timeout +bool handle(clover::Execute::Request& req, clover::Execute::Response& res) +{ + ROS_INFO("Execute: %s", req.cmd.c_str()); + + std::array buffer; + std::string result; + + FILE *fp = popen(req.cmd.c_str(), "r"); + + if (fp == NULL) { + res.code = clover::Execute::Request::CODE_FAIL; + res.output = "popen() failed"; + return true; + } + + while (fgets(buffer.data(), buffer.size(), fp) != nullptr) { + res.output += buffer.data(); + } + + res.code = pclose(fp); + return true; +} + + +int main(int argc, char **argv) +{ + ros::init(argc, argv, "shell"); + ros::NodeHandle nh, nh_priv("~"); + + timeout = ros::Duration(nh_priv.param("timeout", 3.0)); + + auto gt_serv = nh.advertiseService("exec", &handle); + + ROS_INFO("shell: ready"); + ros::spin(); +} diff --git a/clover/srv/Execute.srv b/clover/srv/Execute.srv new file mode 100644 index 00000000..b61a9509 --- /dev/null +++ b/clover/srv/Execute.srv @@ -0,0 +1,7 @@ +int32 CODE_FAIL = -1 +int32 CODE_TIMEOUT = -2 + +string cmd +--- +string output +int32 code diff --git a/clover/test/basic.py b/clover/test/basic.py index 39efc0bb..fe546f7d 100755 --- a/clover/test/basic.py +++ b/clover/test/basic.py @@ -2,6 +2,7 @@ import rospy import pytest from mavros_msgs.msg import State +from clover import srv @pytest.fixture() def node(): @@ -27,3 +28,19 @@ def test_simple_offboard_services_available(): def test_web_video_server(node): import urllib2 urllib2.urlopen("http://localhost:8080").read() + +def test_shell(node): + execute = rospy.ServiceProxy('exec', srv.Execute) + execute.wait_for_service(5) + + res = execute(cmd='echo foo') + assert res.code == 0 + assert res.output == 'foo\n' + + res = execute(cmd='foo') + assert res.code == 32512 + assert res.output == '' + + res = execute(cmd='ls foo') + assert res.code == 512 + assert res.output == '' diff --git a/clover/test/basic.test b/clover/test/basic.test index aa297005..46a923e6 100755 --- a/clover/test/basic.test +++ b/clover/test/basic.test @@ -32,6 +32,8 @@ + + startup: { r: 255, g: 255, b: 255 } diff --git a/clover/www/index.html b/clover/www/index.html index d25ea74d..3da27946 100644 --- a/clover/www/index.html +++ b/clover/www/index.html @@ -8,7 +8,17 @@
  • 3D visualization for markers map (ros3djs)
  • +
    + +