blob: 37c38d5ca748eae5a6fed58176106a072cfba81b [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
18class BufferedLengthDelimReader {
19 public:
20 union data_len {
21 uint32_t len;
22 char buf[4];
23 };
24 BufferedLengthDelimReader() {
25 num_read_ = 0;
26 img_read_ = -1;
27 }
28 template <typename Lamb>
29 void up(int fd, Lamb lam) {
30 ssize_t count;
31 if (img_read_ < 0) {
32 count = read(fd, &len_.buf[num_read_], sizeof(len_.buf) - num_read_);
33 if (count < 0) return;
34 num_read_ += count;
35 if (num_read_ < 4) return;
36 num_read_ = 0;
37 img_read_ = 0;
38 data_.clear();
39 if (len_.len > 200000) {
40 printf("bad size: %d\n", len_.len);
41 exit(-1);
42 }
43 data_.resize(len_.len);
44 } else {
45 count = read(fd, &data_[img_read_], len_.len - img_read_);
46 if (count < 0) return;
47 img_read_ += count;
48 if (img_read_ < (int)len_.len) return;
49 lam(DataRef{&data_[0], len_.len});
50 img_read_ = -1;
51 }
52 }
53
54 private:
55 data_len len_;
56 int num_read_;
57 std::vector<char> data_;
58 int img_read_;
59};
60
61bool ParsePort(const std::string &port, int *portno) {
62 if (port.empty()) return false;
63 int value = 0;
64 if (port[0] == '0') return false;
65 for (char item : port) {
66 if (item < '0' || item > '9') return false;
67 value = value * 10 + (item - '0');
68 }
69 *portno = value;
70 return true;
71}
72
73class TCPImageSource : public ImageSource {
74 public:
75 class Impl : public aos::events::TcpClient {
76 public:
77 Impl(const std::string &hostname, int portno,
78 DebugFrameworkInterface *interface)
Parker Schuhef47dbf2017-03-04 16:59:30 -080079 : aos::events::TcpClient(hostname.c_str(), portno),
80 interface_(interface) {}
Parker Schuh90641112017-02-25 12:18:36 -080081
82 void ReadEvent() override {
83 read_.up(fd(), [&](DataRef data) {
84 BlobList blobl;
85 const char *buf = data.data();
86 buf += sizeof(uint32_t);
87
88 ImageFormat fmt;
89 Int64Codec::Read(&buf);
90 fmt.w = Int32Codec::Read(&buf);
91 fmt.h = Int32Codec::Read(&buf);
92 buf = ParseBlobList(&blobl, buf);
93 interface_->NewBlobList(blobl, fmt);
94 });
95 }
96
97 BufferedLengthDelimReader read_;
98 DebugFrameworkInterface *interface_ = nullptr;
99 };
100
101 void Init(const std::string &addr_and_port,
102 DebugFrameworkInterface *interface) override {
103 auto it = addr_and_port.rfind(':');
104 if (it == std::string::npos) {
105 fprintf(stderr, "usage is: tcp:hostname:port\n");
106 exit(-1);
107 }
108 auto hostname = addr_and_port.substr(0, it);
109 auto port = addr_and_port.substr(it + 1);
110 int portno = 0;
111 if (!ParsePort(port, &portno)) {
112 fprintf(stderr, "usage is: tcp:hostname:port\n");
113 exit(-1);
114 }
115
116 impl_.reset(new Impl(hostname, portno, interface));
117
118 interface->Loop()->Add(impl_.get());
119
120 interface->InstallKeyPress([this](uint32_t /*keyval*/) {});
121 }
122
123 const char *GetHelpMessage() override {
124 return &R"(
125 format_spec is in ipaddr:port format.
126 This viewer soure connects to a target_sender binary and views the live
127 blob-stream.
128)"[1];
129 }
130
131 private:
132 std::unique_ptr<Impl> impl_;
133};
134
135REGISTER_IMAGE_SOURCE("tcp", TCPImageSource);
136
137} // namespace vision
138} // namespace aos