blob: b95e1899d0643740d57e9286fac1bf044bff6bdd [file] [log] [blame]
Parker Schuh90641112017-02-25 12:18:36 -08001#include "aos/vision/debug/debug_framework.h"
2
3#include <gdk/gdk.h>
4#include <gtk/gtk.h>
5#include <sys/stat.h>
6#include <unistd.h>
7#include <cstdlib>
8#include <fstream>
9#include <functional>
10#include <string>
11
12#include "aos/vision/blob/codec.h"
13#include "aos/vision/events/tcp_client.h"
14
15namespace aos {
16namespace vision {
17
Parker Schuhcd258b82017-04-09 16:28:29 -070018// Reads packets in the form:
19// uint32 length
20// string text (of size length)
Parker Schuh90641112017-02-25 12:18:36 -080021class BufferedLengthDelimReader {
22 public:
23 union data_len {
24 uint32_t len;
25 char buf[4];
26 };
27 BufferedLengthDelimReader() {
28 num_read_ = 0;
29 img_read_ = -1;
30 }
31 template <typename Lamb>
32 void up(int fd, Lamb lam) {
Parker Schuhcd258b82017-04-09 16:28:29 -070033 // Drops older messages with this while loop until we've seeked to
34 // be current.
35 while (true) {
36 ssize_t count;
37 if (img_read_ < 0) {
38 count = read(fd, &len_.buf[num_read_], sizeof(len_.buf) - num_read_);
39 if (count < 0) break;
40 num_read_ += count;
41 if (num_read_ < 4) break;
42 num_read_ = 0;
43 img_read_ = 0;
44 data_.clear();
45 if (len_.len > 200000) {
46 printf("bad size: %d\n", len_.len);
47 exit(-1);
48 }
49 data_.resize(len_.len);
50 } else {
51 count = read(fd, &data_[img_read_], len_.len - img_read_);
52 if (count < 0) break;
53 img_read_ += count;
54 if (img_read_ < (int)len_.len) return;
55 std::swap(prev_data_, data_);
56 has_prev_ = true;
57 img_read_ = -1;
Parker Schuh90641112017-02-25 12:18:36 -080058 }
Parker Schuhcd258b82017-04-09 16:28:29 -070059 }
60 if (has_prev_) {
61 lam(DataRef{&prev_data_[0], len_.len});
62 has_prev_ = false;
Parker Schuh90641112017-02-25 12:18:36 -080063 }
64 }
65
66 private:
67 data_len len_;
68 int num_read_;
Parker Schuhcd258b82017-04-09 16:28:29 -070069 bool has_prev_ = false;
70 std::vector<char> prev_data_;
Parker Schuh90641112017-02-25 12:18:36 -080071 std::vector<char> data_;
72 int img_read_;
73};
74
75bool ParsePort(const std::string &port, int *portno) {
76 if (port.empty()) return false;
77 int value = 0;
78 if (port[0] == '0') return false;
79 for (char item : port) {
80 if (item < '0' || item > '9') return false;
81 value = value * 10 + (item - '0');
82 }
83 *portno = value;
84 return true;
85}
86
87class TCPImageSource : public ImageSource {
88 public:
89 class Impl : public aos::events::TcpClient {
90 public:
91 Impl(const std::string &hostname, int portno,
92 DebugFrameworkInterface *interface)
Parker Schuhef47dbf2017-03-04 16:59:30 -080093 : aos::events::TcpClient(hostname.c_str(), portno),
94 interface_(interface) {}
Parker Schuh90641112017-02-25 12:18:36 -080095
96 void ReadEvent() override {
97 read_.up(fd(), [&](DataRef data) {
98 BlobList blobl;
99 const char *buf = data.data();
100 buf += sizeof(uint32_t);
101
102 ImageFormat fmt;
103 Int64Codec::Read(&buf);
104 fmt.w = Int32Codec::Read(&buf);
105 fmt.h = Int32Codec::Read(&buf);
106 buf = ParseBlobList(&blobl, buf);
107 interface_->NewBlobList(blobl, fmt);
108 });
Parker Schuhcd258b82017-04-09 16:28:29 -0700109 if (errno != EAGAIN) {
110 fprintf(stderr, "disconnected\n");
111 loop()->Delete(this);
112 }
Parker Schuh90641112017-02-25 12:18:36 -0800113 }
114
115 BufferedLengthDelimReader read_;
116 DebugFrameworkInterface *interface_ = nullptr;
117 };
118
119 void Init(const std::string &addr_and_port,
120 DebugFrameworkInterface *interface) override {
121 auto it = addr_and_port.rfind(':');
122 if (it == std::string::npos) {
123 fprintf(stderr, "usage is: tcp:hostname:port\n");
124 exit(-1);
125 }
126 auto hostname = addr_and_port.substr(0, it);
127 auto port = addr_and_port.substr(it + 1);
128 int portno = 0;
129 if (!ParsePort(port, &portno)) {
130 fprintf(stderr, "usage is: tcp:hostname:port\n");
131 exit(-1);
132 }
133
134 impl_.reset(new Impl(hostname, portno, interface));
135
136 interface->Loop()->Add(impl_.get());
137
138 interface->InstallKeyPress([this](uint32_t /*keyval*/) {});
139 }
140
141 const char *GetHelpMessage() override {
142 return &R"(
143 format_spec is in ipaddr:port format.
144 This viewer soure connects to a target_sender binary and views the live
145 blob-stream.
146)"[1];
147 }
148
149 private:
150 std::unique_ptr<Impl> impl_;
151};
152
153REGISTER_IMAGE_SOURCE("tcp", TCPImageSource);
154
155} // namespace vision
156} // namespace aos