Goby v2
abc_frontseat_simulator.cpp
1 // Copyright 2009-2018 Toby Schneider (http://gobysoft.org/index.wt/people/toby)
2 // GobySoft, LLC (2013-)
3 // Massachusetts Institute of Technology (2007-2014)
4 //
5 //
6 // This file is part of the Goby Underwater Autonomy Project Binaries
7 // ("The Goby Binaries").
8 //
9 // The Goby Binaries are free software: you can redistribute them and/or modify
10 // them under the terms of the GNU General Public License as published by
11 // the Free Software Foundation, either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // The Goby Binaries are distributed in the hope that they will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with Goby. If not, see <http://www.gnu.org/licenses/>.
21 
22 //
23 // Usage:
24 // 1. run abc_frontseat_simulator running on some port (as TCP server)
25 // > abc_modem_simulator 54321
26 // 2. run iFrontSeat connecting to that port
27 
28 #include <boost/math/special_functions/fpclassify.hpp>
29 #include <limits>
30 #include <map>
31 #include <sstream>
32 #include <string>
33 
34 #include "goby/moos/moos_geodesy.h"
35 #include "goby/util/as.h"
36 #include "goby/util/linebasedcomms.h"
37 
38 double datum_lat = std::numeric_limits<double>::quiet_NaN();
39 double datum_lon = std::numeric_limits<double>::quiet_NaN();
40 int duration = 0;
41 
42 double current_x = 0;
43 double current_y = 0;
44 double current_z = 0;
45 double current_v = 0;
46 double current_hdg = 0;
47 
48 CMOOSGeodesy geodesy;
49 
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); }
52 
53 int main(int argc, char* argv[])
54 {
55  if (argc < 2)
56  {
57  std::cout << "usage: abc_modem_simulator [tcp listen port]" << std::endl;
58  exit(1);
59  }
60 
61  goby::util::TCPServer server(goby::util::as<unsigned>(argv[1]));
62  server.start();
63  sleep(1);
64 
65  int i = 0;
66  int time_in_mission = 0;
67  while (server.active())
68  {
70  while (server.readline(&in))
71  {
72  // clear off \r\n and other whitespace at ends
73  boost::trim(*in.mutable_data());
74 
75  std::cout << "Received: " << in.ShortDebugString() << std::endl;
76 
77  std::map<std::string, std::string> parsed;
78  try
79  {
80  parse_in(in.data(), &parsed);
81  if (started() && parsed["KEY"] == "CMD")
82  {
83  try
84  {
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");
91 
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;
97 
98  server.write("CMD,RESULT:OK\r\n");
99  }
100  catch (std::exception& e)
101  {
102  server.write("CMD,RESULT:ERROR\r\n");
103  }
104  }
105  else if (parsed["KEY"] == "START")
106  {
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);
117 
118  time_in_mission = 0;
119  server.write("CTRL,STATE:PAYLOAD\r\n");
120  }
121  else
122  {
123  std::cout << "Unknown key from payload: " << in.data() << std::endl;
124  }
125  }
126  catch (std::exception& e)
127  {
128  std::cout << "Invalid line from payload: " << in.data() << std::endl;
129  std::cout << "Why: " << e.what() << std::endl;
130  }
131  }
132  usleep(1000);
133  ++i;
134  if (i == 1000)
135  {
136  i = 0;
137  time_in_mission++;
138  if (started() && time_in_mission > duration)
139  {
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");
143  }
144 
145  if (started())
146  {
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);
150 
151  std::cout << "new x: " << current_x << ", y: " << current_y << std::endl;
152 
153  double lat, lon;
154  geodesy.UTM2LatLong(current_x, current_y, lat, lon);
155  std::stringstream nav_ss;
156  nav_ss << "NAV,"
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());
163  }
164  }
165  }
166 
167  std::cout << "server failed..." << std::endl;
168  exit(1);
169 }
170 
171 void parse_in(const std::string& in, std::map<std::string, std::string>* out)
172 {
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)
177  {
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)));
181  }
182 }
provides a basic TCP server for line by line text based communications to a one or more remote TCP cl...
Definition: tcp_server.h:49