Goby Underwater Autonomy Project
Series: 1.1, revision: 163, released on 2013-02-06 14:23:27 -0500
|
00001 // copyright 2009 t. schneider tes@mit.edu 00002 // 00003 // This program is free software: you can redistribute it and/or modify 00004 // it under the terms of the GNU General Public License as published by 00005 // the Free Software Foundation, either version 3 of the License, or 00006 // (at your option) any later version. 00007 // 00008 // This software is distributed in the hope that it will be useful, 00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 // GNU General Public License for more details. 00012 // 00013 // You should have received a copy of the GNU General Public License 00014 // along with this software. If not, see <http://www.gnu.org/licenses/>. 00015 00016 // 00017 // Usage: 00018 // 1. run abc_modem_simulator running on same port (as TCP server) 00019 // > abc_modem_simulator 54321 00020 // 2. create fake tty terminals connected to TCP as client to port 54321 00021 // > socat -d -d -v pty,raw,echo=0,link=/tmp/ttyFAKE1 TCP:localhost:54321 00022 // > socat -d -d -v pty,raw,echo=0,link=/tmp/ttyFAKE2 TCP:localhost:54321 00023 // > ... 00024 // 3. run your application connecting to /tmp/ttyFAKE1, /tmp/ttyFAKE2, etc. They will all act in the same "broadcast" pool 00025 00026 #include <map> 00027 #include <string> 00028 00029 #include "goby/util/linebasedcomms.h" 00030 #include "goby/util/string.h" 00031 #include "goby/acomms/acomms_constants.h" // for BROADCAST_ID 00032 00033 std::map<int, std::string> modem_id2endpoint; 00034 00035 void parse_in(const std::string& in, std::map<std::string, std::string>* out); 00036 00037 int main(int argc, char* argv[]) 00038 { 00039 if(argc < 2) 00040 { 00041 std::cout << "usage: abc_modem_simulator [tcp listen port]" << std::endl; 00042 exit(1); 00043 } 00044 00045 goby::util::TCPServer server(goby::util::as<unsigned>(argv[1])); 00046 00047 server.start(); 00048 while(server.active()) 00049 { 00050 goby::util::protobuf::Datagram in; 00051 while(server.readline(&in)) 00052 { 00053 // clear off \r\n and other whitespace at ends 00054 boost::trim(*in.mutable_data()); 00055 00056 std::cout << "Received: " << in.ShortDebugString() << std::endl; 00057 00058 std::map<std::string, std::string> parsed; 00059 try 00060 { 00061 parse_in(in.data(), &parsed); 00062 if(parsed["KEY"] == "CONF") 00063 { 00064 std::cout << "Got configuration: " << in.data() << std::endl; 00065 00066 // register a modem id 00067 if(parsed.count("MAC")) 00068 { 00069 int mac = goby::util::as<int>(parsed["MAC"]); 00070 std::cout << "Set MAC address " << mac << " for endpoint " << in.src() << std::endl; 00071 modem_id2endpoint[mac] = in.src(); 00072 } 00073 } 00074 else if(parsed["KEY"] == "SEND") 00075 { 00076 00077 std::cout << "Got send: " << in.data() << std::endl; 00078 00079 goby::util::protobuf::Datagram out; 00080 out.set_src(server.local_endpoint()); 00081 00082 if(!parsed.count("HEX")) 00083 throw(std::runtime_error("No DATA in SEND message")); 00084 00085 if(!parsed.count("FROM")) 00086 throw(std::runtime_error("No FROM in SEND message")); 00087 00088 if(!parsed.count("BITRATE")) 00089 throw(std::runtime_error("No BITRATE in SEND message")); 00090 00091 00092 int src = goby::util::as<int>(parsed["FROM"]); 00093 00094 if(parsed.count("TO")) 00095 { 00096 int dest = goby::util::as<int>(parsed["TO"]); 00097 00098 std::stringstream out_ss; 00099 out_ss << "RECV,FROM:" << src 00100 << ",TO:" << dest 00101 << ",HEX:" << parsed["HEX"] 00102 << ",BITRATE:" << parsed["BITRATE"] << "\r\n"; 00103 out.set_data(out_ss.str()); 00104 00105 if(dest == goby::acomms::BROADCAST_ID) 00106 { 00107 typedef std::map<int, std::string>::const_iterator const_iterator; 00108 for(const_iterator it = modem_id2endpoint.begin(), n = modem_id2endpoint.end(); it !=n; ++it) 00109 { 00110 // do not send it back to the originator 00111 if(it->first != src) 00112 { 00113 out.set_dest(it->second); 00114 std::cout << "Sending: " << out.ShortDebugString() << std::endl; 00115 server.write(out); 00116 } 00117 } 00118 } 00119 else 00120 { 00121 if(!modem_id2endpoint.count(dest)) 00122 throw(std::runtime_error("Unknown destination ID " + goby::util::as<std::string>(dest))); 00123 00124 out.set_dest(modem_id2endpoint[dest]); 00125 std::cout << "Sending: " << out.ShortDebugString() << std::endl; 00126 server.write(out); 00127 00128 if(parsed.count("ACK") && goby::util::as<bool>(parsed["ACK"])) 00129 { 00130 out.set_dest(in.src()); 00131 00132 std::stringstream out_ss; 00133 out_ss << "ACKN,FROM:" << dest 00134 << ",TO:" << src << "\r\n"; 00135 out.set_data(out_ss.str()); 00136 std::cout << "Sending: " << out.ShortDebugString() << std::endl; 00137 00138 server.write(out); 00139 } 00140 } 00141 00142 } 00143 else 00144 throw(std::runtime_error("No TO in SEND message")); 00145 00146 } 00147 } 00148 catch(std::exception& e) 00149 { 00150 std::cout << "Invalid line from modem: " << in.data() << std::endl; 00151 std::cout << "Why: " << e.what() << std::endl; 00152 } 00153 } 00154 00155 usleep(1000); 00156 } 00157 00158 std::cout << "server failed..." << std::endl; 00159 exit(1); 00160 } 00161 00162 00163 void parse_in(const std::string& in, std::map<std::string, std::string>* out) 00164 { 00165 std::vector<std::string> comma_split; 00166 boost::split(comma_split, in, boost::is_any_of(",")); 00167 out->insert(std::make_pair("KEY", comma_split.at(0))); 00168 for(int i = 1, n = comma_split.size(); i < n; ++i) 00169 { 00170 std::vector<std::string> colon_split; 00171 boost::split(colon_split, comma_split[i], 00172 boost::is_any_of(":")); 00173 out->insert(std::make_pair(colon_split.at(0), 00174 colon_split.at(1))); 00175 } 00176 } 00177