28 #include <boost/math/special_functions/fpclassify.hpp> 34 #include "goby/moos/moos_geodesy.h" 35 #include "goby/util/as.h" 36 #include "goby/util/linebasedcomms.h" 38 double datum_lat = std::numeric_limits<double>::quiet_NaN();
39 double datum_lon = std::numeric_limits<double>::quiet_NaN();
46 double current_hdg = 0;
50 void parse_in(
const std::string& in, std::map<std::string, std::string>* out);
51 bool started() {
return !boost::math::isnan(datum_lat) && !boost::math::isnan(datum_lon); }
53 int main(
int argc,
char* argv[])
57 std::cout <<
"usage: abc_modem_simulator [tcp listen port]" << std::endl;
66 int time_in_mission = 0;
67 while (server.active())
70 while (server.readline(&in))
73 boost::trim(*in.mutable_data());
75 std::cout <<
"Received: " << in.ShortDebugString() << std::endl;
77 std::map<std::string, std::string> parsed;
80 parse_in(in.data(), &parsed);
81 if (started() && parsed[
"KEY"] ==
"CMD")
85 if (!parsed.count(
"HEADING"))
86 throw std::runtime_error(
"Invalid CMD: missing HEADING field");
87 if (!parsed.count(
"SPEED"))
88 throw std::runtime_error(
"Invalid CMD: missing SPEED field");
89 if (!parsed.count(
"DEPTH"))
90 throw std::runtime_error(
"Invalid CMD: missing DEPTH field");
92 current_z = -goby::util::as<double>(parsed[
"DEPTH"]);
93 current_v = goby::util::as<double>(parsed[
"SPEED"]);
94 current_hdg = goby::util::as<double>(parsed[
"HEADING"]);
95 std::cout <<
"Updated z: " << current_z <<
" m, v: " << current_v
96 <<
" m/s, heading: " << current_hdg <<
" deg" << std::endl;
98 server.write(
"CMD,RESULT:OK\r\n");
100 catch (std::exception& e)
102 server.write(
"CMD,RESULT:ERROR\r\n");
105 else if (parsed[
"KEY"] ==
"START")
107 if (!parsed.count(
"LAT"))
108 throw std::runtime_error(
"Invalid START: missing LAT field");
109 if (!parsed.count(
"LON"))
110 throw std::runtime_error(
"Invalid START: missing LON field");
111 if (!parsed.count(
"DURATION"))
112 throw std::runtime_error(
"Invalid START: missing DURATION field");
113 datum_lat = goby::util::as<double>(parsed[
"LAT"]);
114 datum_lon = goby::util::as<double>(parsed[
"LON"]);
115 duration = goby::util::as<int>(parsed[
"DURATION"]);
116 geodesy.Initialise(datum_lat, datum_lon);
119 server.write(
"CTRL,STATE:PAYLOAD\r\n");
123 std::cout <<
"Unknown key from payload: " << in.data() << std::endl;
126 catch (std::exception& e)
128 std::cout <<
"Invalid line from payload: " << in.data() << std::endl;
129 std::cout <<
"Why: " << e.what() << std::endl;
138 if (started() && time_in_mission > duration)
140 datum_lat = std::numeric_limits<double>::quiet_NaN();
141 datum_lon = std::numeric_limits<double>::quiet_NaN();
142 server.write(
"CTRL,STATE:IDLE\r\n");
147 double theta = (90 - current_hdg) * 3.14 / 180;
148 current_x += current_v * std::cos(theta);
149 current_y += current_v * std::sin(theta);
151 std::cout <<
"new x: " << current_x <<
", y: " << current_y << std::endl;
154 geodesy.UTM2LatLong(current_x, current_y, lat, lon);
155 std::stringstream nav_ss;
157 <<
"LAT:" << std::setprecision(10) << lat <<
"," 158 <<
"LON:" << std::setprecision(10) << lon <<
"," 159 <<
"DEPTH:" << -current_z <<
"," 160 <<
"HEADING:" << current_hdg <<
"," 161 <<
"SPEED:" << current_v <<
"\r\n";
162 server.write(nav_ss.str());
167 std::cout <<
"server failed..." << std::endl;
171 void parse_in(
const std::string& in, std::map<std::string, std::string>* out)
173 std::vector<std::string> comma_split;
174 boost::split(comma_split, in, boost::is_any_of(
","));
175 out->insert(std::make_pair(
"KEY", comma_split.at(0)));
176 for (
int i = 1, n = comma_split.size(); i < n; ++i)
178 std::vector<std::string> colon_split;
179 boost::split(colon_split, comma_split[i], boost::is_any_of(
":"));
180 out->insert(std::make_pair(colon_split.at(0), colon_split.at(1)));
provides a basic TCP server for line by line text based communications to a one or more remote TCP cl...