13 #include "LibCyberRadio/Driver/RadioTransport.h" 14 #include "LibCyberRadio/Common/Pythonesque.h" 15 #include "json/json.h" 18 #include <sys/socket.h> 19 #include <arpa/inet.h> 23 #include <sys/select.h> 42 _httpsConnTestUrl(
""),
46 this->
debug(
"CONSTRUCTED\n");
53 if (_httpsSession != NULL)
63 this->
debug(
"DESTROYED\n");
69 _isJson = other._isJson;
70 _tcpSocket = other._tcpSocket;
71 _udpSocket = other._udpSocket;
72 _serial = other._serial;
73 _httpsSession = other._httpsSession;
74 _httpsConnTestUrl = other._httpsConnTestUrl;
75 _httpsApiCmdUrl = other._httpsApiCmdUrl;
76 _lastCmdErrInfo = other._lastCmdErrInfo;
85 _isJson = other._isJson;
86 _tcpSocket = other._tcpSocket;
87 _udpSocket = other._udpSocket;
88 _serial = other._serial;
89 _httpsSession = other._httpsSession;
90 _httpsConnTestUrl = other._httpsConnTestUrl;
91 _httpsApiCmdUrl = other._httpsApiCmdUrl;
92 _lastCmdErrInfo = other._lastCmdErrInfo;
99 this->
debug(
"[setJson] %s\n", json);
105 const std::string &mode,
106 const std::string &host_or_dev,
107 const int port_or_baudrate
110 this->
debug(
"[connect] Called; mode=\"%s\", HorD=\"%s\", PorB=%d\n", mode.c_str(), host_or_dev.c_str(), port_or_baudrate);
116 else if (mode ==
"udp")
118 ret =
connectUdp(host_or_dev, port_or_baudrate);
120 else if (mode ==
"tcp")
122 ret =
connectTcp(host_or_dev, port_or_baudrate);
124 else if (mode ==
"tty")
126 ret =
connectTty(host_or_dev, port_or_baudrate);
134 this->
debug(
"[disconnect] Called\n");
135 if (_httpsSession != NULL)
137 delete _httpsSession;
138 _httpsSession = NULL;
140 else if (_udpSocket > 0)
142 int ok = shutdown(_udpSocket, SHUT_RDWR);
146 else if (_tcpSocket > 0)
148 int ok = shutdown(_tcpSocket, SHUT_RDWR);
152 else if (_serial != NULL)
158 this->
debug(
"[disconnect] Returning\n");
164 (_httpsSession != NULL) ||
173 const std::string &cmdString,
177 this->
debug(
"[sendCommand] Called; cmd=\"%s\"\n",
180 if (_httpsSession != NULL)
184 else if (_serial != NULL)
188 else if (_udpSocket > 0)
192 else if (_tcpSocket > 0)
197 _lastCmdErrInfo =
"Transport is not connected";
198 this->
debug(
"[sendCommand] Returning %s\n", this->
debugBool(ret));
206 this->
debug(
"[receive] Called\n");
216 this->
debug(
"[receive] Returning %u element%s\n", ret.size(),
217 ret.size() == 1 ?
"" :
"s");
223 return _lastCmdErrInfo;
227 const std::string &host,
231 this->
debug(
"[connectTcp] Called; host=\"%s\", port=%d\n", host.c_str(), port);
232 _tcpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
233 this->
debug(
"[connectTcp] Socket created; FD=%d\n", _tcpSocket);
236 struct hostent *hent = gethostbyname(host.c_str());
238 memset(buf, 0,
sizeof(buf));
239 inet_ntop(AF_INET, hent->h_addr_list[0], buf,
sizeof(buf));
240 this->
debug(
"[connectTcp] Host IP address: %s\n", buf);
241 struct sockaddr_in addr;
242 memset(&addr, 0,
sizeof(
struct sockaddr_in));
243 addr.sin_family = AF_INET;
244 memcpy(&(addr.sin_addr.s_addr), hent->h_addr_list[0], hent->h_length);
245 addr.sin_port = htons(port);
246 this->
debug(
"[connectTcp] Connecting\n");
247 int ok =
::connect(_tcpSocket, (
const sockaddr*)&addr,
sizeof(
struct sockaddr_in));
248 this->
debug(
"[connectTcp] -- ok = %d\n", ok);
257 bool ret = (_tcpSocket > 0);
262 const std::string& host,
266 this->
debug(
"[connectUdp] Called; host=\"%s\", port=%d\n", host.c_str(), port);
268 _udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
269 this->
debug(
"[connectUdp] Socket created; FD=%d\n", _udpSocket);
272 struct hostent *hent = gethostbyname(host.c_str());
274 memset(buf, 0,
sizeof(buf));
275 inet_ntop(AF_INET, hent->h_addr_list[0], buf,
sizeof(buf));
276 this->
debug(
"[connectUdp] Host IP address: %s\n", buf);
277 struct sockaddr_in addr;
278 memset(&addr, 0,
sizeof(
struct sockaddr_in));
279 addr.sin_family = AF_INET;
280 memcpy(&(addr.sin_addr.s_addr), hent->h_addr_list[0], hent->h_length);
281 addr.sin_port = htons(port);
282 this->
debug(
"[connectUdp] Connecting\n");
283 int ok =
::connect(_udpSocket, (
const sockaddr*)&addr,
sizeof(
struct sockaddr_in));
284 this->
debug(
"[connectUdp] -- ok = %d\n", ok);
293 bool ret = (_udpSocket > 0);
298 const std::string &host,
302 this->
debug(
"[connectHttps] Called; host=\"%s\", port=%d\n", host.c_str(), port);
305 if ( _httpsSession == NULL )
307 if ( _httpsSession != NULL )
309 this->
debug(
"[connectHttps] Session initialized\n");
311 std::ostringstream oss;
312 oss <<
"https://" << host <<
":" << port <<
"/";
313 _httpsConnTestUrl = oss.str();
314 oss <<
"api/command";
315 _httpsApiCmdUrl = oss.str();
317 this->
debug(
"[connectHttps] Testing connection; URL=%s\n",
318 _httpsConnTestUrl.c_str());
319 ret = _httpsSession->
get(_httpsConnTestUrl,
false);
324 delete _httpsSession;
325 _httpsSession = NULL;
329 _lastCmdErrInfo =
"Failed to establish HTTPS session";
330 this->
debug(
"[connectHttps] Returning %s\n", this->
debugBool(ret));
335 const std::string& dev,
339 this->
debug(
"[connectTty] Called; dev=\"%s\", baudrate=%d\n",
340 dev.c_str(), baudrate);
343 if ( _serial == NULL )
344 _serial = new ::LibCyberRadio::SerialPort(
345 dev, baudrate,
'N', 8, 1,
348 ret = _serial->
open();
351 this->
debug(
"[connectTty] Serial link established\n");
353 this->
debug(
"[connectTty] Testing connection\n");
360 std::ostringstream oss;
361 oss <<
"Connection test FAILED: ";
363 _lastCmdErrInfo = oss.str();
369 std::ostringstream oss;
370 oss <<
"Serial link FAILED: ";
371 if ( _serial != NULL )
374 oss <<
"Failed to establish serial link";
375 _lastCmdErrInfo = oss.str();
383 const std::string &cmdString,
387 this->
debug(
"[sendCommandTcp] Called; cmd=\"%s\"\n",
390 int bytes = send(_tcpSocket, cmdString.c_str(), cmdString.length(), 0);
391 this->
debug(
"[sendCommandTcp] -- Bytes sent: %d\n", bytes);
404 const std::string& cmdString,
408 this->
debug(
"[sendCommandUdp] Called; cmd=%s\n",
411 int bytes = send(_udpSocket, cmdString.c_str(), cmdString.length(), 0);
412 this->
debug(
"[sendCommandUdp] -- Bytes sent: %d\n", bytes);
425 const std::string &cmdString,
429 this->
debug(
"[sendCommandHttps] Called; cmd=\"%s\"\n",
432 if ( _httpsSession != NULL )
434 ret = _httpsSession->
post(_httpsApiCmdUrl,
435 (
void*)cmdString.c_str(),
439 this->
debug(
"[sendCommandHttps] HTTPS response code = %d\n",
451 Json::Value jsonResponse;
453 jsonResponse,
false) )
466 _lastCmdErrInfo =
"Transport is not connected";
467 this->
debug(
"[sendCommandHttps] Returning %s\n", this->
debugBool(ret));
472 const std::string& cmdString,
476 this->
debug(
"[sendCommandTty] Called; cmd=\"%s\"\n",
479 if ( _serial->
write(cmdString) )
481 this->
debug(
"[sendCommandTty] -- Command sent\n");
495 std::deque<std::string> ret;
496 if (_httpsSession != NULL) {
499 ret = receiveJsonUdp(timeout);
508 this->
debug(
"[receiveJsonUdp] Called; timeout=%0.1f\n", timeout);
510 std::ostringstream oss;
513 tv.tv_sec = (long)timeout;
514 tv.tv_usec = (long)(1000000 * (timeout - (
long)timeout));
518 memset(buf, 0,
sizeof(buf));
519 recv(_udpSocket, buf,
sizeof(buf), 0);
520 this->
debug(
"[receiveJsonUdp] Received chunk: \"%s\"\n", buf);
522 this->
debug(
"[receiveJsonUdp] Received: \"%s\"\n",
527 bool parsingSuccessful = reader.parse( t.c_str(), root );
528 if ( !parsingSuccessful )
530 this->
debug(
"[receiveJsonUdp] Parsing JSON Error\n");
532 Json::FastWriter fastWriter;
533 std::string output = fastWriter.write(root);
534 ret.push_back(output);
543 this->
debug(
"[receiveJsonHttps] Called; timeout=%0.1f\n", timeout);
548 if ( _httpsSession != NULL )
550 this->
debug(
"[receiveJsonHttps] HTTPS response body = \"%s\"\n",
555 _lastCmdErrInfo =
"Transport is not connected";
563 std::deque<std::string> ret;
566 else if (_tcpSocket > 0)
568 else if (_serial != NULL)
577 this->
debug(
"[receiveCliTcp] Called; timeout=%0.1f\n", timeout);
579 std::ostringstream oss;
582 tv.tv_sec = (long)timeout;
583 tv.tv_usec = (long)(1000000 * (timeout - (
long)timeout));
589 FD_SET(_tcpSocket, &ins);
590 this->
debug(
"[receiveCliTcp] Selecting\n");
591 nfds = select(_tcpSocket + 1, &ins, NULL, NULL, timeout < 0 ? NULL : &tv);
592 this->
debug(
"[receiveCliTcp] -- nfds = %d\n", nfds);
596 memset(buf, 0,
sizeof(buf));
597 recv(_tcpSocket, buf,
sizeof(buf), 0);
598 this->
debug(
"[receiveCliTcp] Received chunk: \"%s\"\n", buf);
601 if ( oss.str().rfind(
'>') != std::string::npos )
607 this->
debug(
"[receiveCliTcp] Timeout\n");
608 _lastCmdErrInfo =
"Timeout";
615 this->
debug(
"[receiveCliTcp] Socket select error: %s\n", _lastCmdErrInfo.c_str());
619 this->
debug(
"[receiveCliTcp] Received: \"%s\"\n",
627 for (BasicStringList::iterator it = tmpList.begin(); it != tmpList.end(); it++)
633 this->
debug(
"[receiveCliTcp] Returning %u elements\n", ret.size());
649 this->
debug(
"[receiveCliTty] Called; timeout=%0.1f\n", timeout);
651 std::ostringstream oss;
652 std::string rsp =
"X";
655 rsp = _serial->
read();
660 this->
debug(
"[receiveCliTty] Received: \"%s\"\n",
668 for (BasicStringList::iterator it = tmpList.begin(); it != tmpList.end(); it++)
674 this->
debug(
"[receiveCliTty] Returning %u elements\n", ret.size());
681 memset(buf, 0,
sizeof(buf));
682 this->
debug(strerror_r(errno, buf,
sizeof(buf)));
683 _lastCmdErrInfo = buf;
static std::string Rstrip(const std::string &str, const std::string &chars=" \\\)
Strips trailing whitespace from the given string.
virtual bool connect(const std::string &mode, const std::string &host_or_dev, const int port_or_baudrate)
Connects to the radio.
virtual BasicStringList receiveCliUdp(double timeout=-1)
Receives a client (AT-command-style) command response over UDP.
virtual std::string getLastCommandErrorInfo() const
Gets the error information for the last command.
virtual BasicStringList receiveCli(double timeout=-1)
Receives a client (AT-command-style) command response from the radio.
virtual long getResponseCode() const
Gets the HTTPS response code from the last request.
Debuggable & operator=(const Debuggable &other)
Assignment operator for Debuggable objects.
bool write(const std::string &data)
Writes data to the serial port.
virtual void disconnect()
Disconnects from the radio.
static std::string Replace(const std::string &str, const std::string &oldstr, const std::string &newstr, int count=INT_MAX)
Replaces occurrences of one substring with another within the given string.
Class that supports debug output.
virtual BasicStringList receiveJson(double timeout=-1)
Receives a JSON-formatted command response from the radio.
bool open()
Open the serial port.
virtual ~RadioTransport()
Destroys a RadioTransport object.
virtual bool connectTty(const std::string &dev, int baudrate)
Connects to the radio using a serial link.
static BasicStringList Split(const std::string &str, const std::string &sep, int maxsplit=INT_MAX)
Splits the given string into a list of string tokens.
std::string getLastError() const
Gets the last error message.
virtual bool connectUdp(const std::string &host, int port)
Connects to the radio using UDP.
virtual int debug(const char *format,...)
Outputs debug information.
BASIC_LIST_CONTAINER< std::string > BasicStringList
Type representing a list of strings.
virtual std::string getResponseBody() const
Gets the HTTPS response body from the last request.
virtual bool connectHttps(const std::string &host, int port)
Connects to the radio using HTTPS.
static bool Endswith(const std::string &str, const std::string &suffix, int start=0, int end=INT_MAX)
Determines if the given string ends with the specified suffix.
virtual bool sendCommandTty(const std::string &cmdString, bool clearRx=true)
Sends a command to the radio over TTY.
Defines functionality for LibCyberRadio applications.
Generic radio transport class.
virtual bool get(const std::string &url, bool verify=true)
Gets data from a given URL over HTTPS.
virtual const char * debugBool(bool x)
Gets a debug output string for a Boolean value.
bool close()
Close the serial port.
virtual bool sendCommandHttps(const std::string &cmdString, bool clearRx=true)
Sends a command to the radio over HTTPS.
virtual std::string rawString(const std::string &data)
Gets a "raw" string representation of a given data string.
virtual bool post(const std::string &url, void *data, size_t length, const char *contentType="text/plain", bool verify=true)
Posts data to a given URL over HTTPS.
virtual void translateErrno()
Translates an errno value into an error message.
virtual BasicStringList receiveCliTty(double timeout=-1)
Receives a client (AT-command-style) command response over TTY.
Class that encapsulates an HTTPS session.
virtual bool sendCommandTcp(const std::string &cmdString, bool clearRx=true)
Sends a command to the radio over TCP.
virtual BasicStringList receiveCliTcp(double timeout=-1)
Receives a client (AT-command-style) command response over TCP.
virtual bool sendCommand(const std::string &cmdString, bool clearRx=true)
Sends a command to the radio over the transport.
void setJson(bool json)
Allows user to set JSON.
virtual BasicStringList receive(double timeout=-1)
Receives a command response from the radio.
virtual bool isConnected() const
Gets whether the transport is connected.
virtual std::string getLastRequestErrorInfo() const
Gets the error information for the last request.
virtual BasicStringList receiveJsonHttps(double timeout=-1)
Receives a JSON-formatted command response from the radio using HTTPS.
RadioTransport & operator=(const RadioTransport &other)
Assignment operator for RadioTransport objects.
std::string read()
Reads data from the serial port.
RadioTransport(bool json=false, bool debug=false)
Constructs a RadioTransport object.
virtual bool sendCommandUdp(const std::string &cmdString, bool clearRx=true)
Sends a command to the radio over UDP.
virtual bool connectTcp(const std::string &host, int port)
Connects to the radio using TCP.