Skip to content

Commit ed15ad5

Browse files
committed
test for server
1 parent 1b9f20b commit ed15ad5

File tree

6 files changed

+335
-0
lines changed

6 files changed

+335
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
server/bin/*
12
# Compiled Object files
23
*.slo
34
*.lo

server/Makefile

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CFLAGS=-Iinclude -I../src -O3 -Wall -lboost_system -lpthread -ldcam -std=c++11
2+
3+
all:
4+
mkdir -p bin
5+
g++ src/x3server.cpp ${CFLAGS} -o bin/x3server
6+
g++ src/x3client.cpp ${CFLAGS} -o bin/x3client
7+
clean:
8+
rm bin/*

server/include/msgdef.h

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#ifndef __MSGDEF_H
2+
#define __MSGDEF_H 1
3+
4+
#include <boost/asio.hpp>
5+
6+
static const int PORT_NUMBER = 40042;
7+
8+
static const uint32_t IMAGE_W = 1280;
9+
static const uint32_t IMAGE_H = 720;
10+
static const uint32_t IMAGE_CH = 1;
11+
static const uint32_t HEADER_LEN = 1 * sizeof(uint32_t) + 3 * sizeof(uint32_t) + 2 * sizeof(uint32_t);
12+
static const uint32_t TOTAL_LEN = HEADER_LEN+IMAGE_W*IMAGE_H*IMAGE_CH;
13+
14+
class ImageMsgHeader {
15+
public:
16+
uint32_t header;
17+
uint32_t image_w;
18+
uint32_t image_h;
19+
uint32_t image_ch;
20+
uint32_t secs;
21+
uint32_t usecs;
22+
void parse(uint8_t * p) {
23+
header = ntohl(*(uint32_t *)p); p += sizeof(uint32_t);
24+
image_w = ntohl(*(uint32_t *)p); p += sizeof(uint32_t);
25+
image_h = ntohl(*(uint32_t *)p); p += sizeof(uint32_t);
26+
image_ch = ntohl(*(uint32_t *)p); p += sizeof(uint32_t);
27+
secs = ntohl(*(uint32_t *)p); p += sizeof(uint32_t);
28+
usecs = ntohl(*(uint32_t *)p); p += sizeof(uint32_t);
29+
}
30+
void pack(uint8_t * p) {
31+
*(uint32_t *)p = htonl(header ); p += sizeof(uint32_t);
32+
*(uint32_t *)p = htonl(image_w ); p += sizeof(uint32_t);
33+
*(uint32_t *)p = htonl(image_h ); p += sizeof(uint32_t);
34+
*(uint32_t *)p = htonl(image_ch); p += sizeof(uint32_t);
35+
*(uint32_t *)p = htonl(secs ); p += sizeof(uint32_t);
36+
*(uint32_t *)p = htonl(usecs ); p += sizeof(uint32_t);
37+
}
38+
};
39+
40+
#endif

server/scripts/x3server.conf

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
description "A tcp server for transmit x3-gimbal-camera images"
2+
author "LIUTianbo"
3+
4+
start on ((filesystem
5+
and runlevel [!06]
6+
and started dbus
7+
and plymouth-ready)
8+
or runlevel PREVLEVEL=S)
9+
10+
stop on runlevel [016]
11+
12+
exec /usr/local/bin/x3server
13+

server/src/x3client.cpp

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//
2+
// client.cpp
3+
// ~~~~~~~~~~
4+
//
5+
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6+
//
7+
// Distributed under the Boost Software License, Version 1.0. (See accompanying
8+
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9+
//
10+
11+
#include <iostream>
12+
#include <boost/array.hpp>
13+
#include <boost/asio.hpp>
14+
#include <boost/format.hpp>
15+
#include <sysexits.h>
16+
#include "msgdef.h"
17+
18+
using boost::asio::ip::udp;
19+
using boost::asio::ip::tcp;
20+
using bfmt = boost::format;
21+
22+
using std::cout;
23+
using std::endl;
24+
25+
int main(int argc, char* argv[]) {
26+
try {
27+
boost::asio::io_service io_service;
28+
29+
tcp::endpoint endpoint(boost::asio::ip::address_v4::loopback(), PORT_NUMBER);
30+
31+
// udp::socket socket(io_service);
32+
// socket.open(udp::v4());
33+
tcp::socket socket(io_service);
34+
boost::system::error_code error = boost::asio::error::host_not_found;
35+
std::cout << "Wait for acceptance... \n(Blocked here means server busy. Another x3client is running?)" << std::endl;
36+
socket.connect(endpoint, error);
37+
if (error) {
38+
std::cout << "Server offline, exit..." << std::endl;
39+
return EXIT_FAILURE;
40+
}
41+
42+
boost::array<char, TOTAL_LEN> img;
43+
size_t imgidx = 0;
44+
size_t tfcnt = 0;
45+
ImageMsgHeader h;
46+
for (;;) {
47+
boost::array<char, TOTAL_LEN> buf;
48+
boost::system::error_code error;
49+
50+
size_t len = socket.read_some(boost::asio::buffer(buf), error);
51+
52+
if (error == boost::asio::error::eof) {
53+
std::cerr << "Server down" << std::endl;
54+
return EX_PROTOCOL; // Connection closed cleanly by peer.
55+
} else if (error)
56+
throw boost::system::system_error(error); // Some other error.
57+
// std::cout.write(buf.data(), len);
58+
// std::cout << "receive " << len << "bytes \t";
59+
60+
std::copy(buf.begin(), buf.begin() + len, img.begin() + imgidx);
61+
imgidx += len;
62+
tfcnt++;
63+
if (imgidx == TOTAL_LEN) {
64+
h.parse((uint8_t*)img.c_array());
65+
struct timeval tm;
66+
gettimeofday(&tm, NULL);
67+
std::cout << bfmt("[%X] %dx%dx%d @ %.6f / %4d") % h.header %
68+
h.image_w % h.image_h % h.image_ch %
69+
((double)h.secs + 1e-6 * (double)h.usecs) %
70+
// ((int)(tm.tv_sec-h.secs)*1000000+(int)(tm.tv_usec-h.usecs))
71+
tfcnt
72+
<< std::endl;
73+
imgidx = 0;
74+
tfcnt = 0;
75+
} else if (imgidx > TOTAL_LEN) {
76+
std::cerr << "receive overflow!!!!" << std::endl;
77+
return EX_IOERR;
78+
} else {
79+
// std::cout << std::endl;
80+
}
81+
}
82+
} catch (std::exception& e) {
83+
std::cout << "Big error" << std::endl;
84+
std::cerr << e.what() << std::endl;
85+
}
86+
87+
return 0;
88+
}

server/src/x3server.cpp

+185
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
#include <ctime>
2+
#include <iostream>
3+
#include <fstream>
4+
#include <string>
5+
#include <boost/array.hpp>
6+
#include <boost/asio.hpp>
7+
#include <boost/format.hpp>
8+
#include <boost/bind.hpp>
9+
#include <sys/types.h> /* See NOTES */
10+
#include <sys/socket.h>
11+
#include <sysexits.h>
12+
13+
#include "msgdef.h"
14+
#include "djicam.h"
15+
16+
const size_t FRAME_SIZE = 1280*720*3;
17+
18+
using boost::asio::ip::udp;
19+
using boost::asio::ip::tcp;
20+
21+
typedef boost::asio::detail::socket_option::integer<SOL_SOCKET, SO_SNDBUF> send_buf_opt_t;
22+
23+
uint8_t imgbuf[FRAME_SIZE];
24+
uint8_t sockbuf[TOTAL_LEN];
25+
bool accepted;
26+
27+
std::string make_daytime_string() {
28+
using namespace std; // For time_t, time and ctime;
29+
time_t now = time(0);
30+
return ctime(&now);
31+
}
32+
33+
std::ofstream * pOS;
34+
35+
void accept_handle(const boost::system::error_code& error) {
36+
if (!error)
37+
accepted = true;
38+
else
39+
(*pOS) << "accept handle error=" << error.message() << std::endl;
40+
}
41+
42+
void handle_wait(const boost::system::error_code& error,
43+
boost::asio::io_service& io) {
44+
if (!error)
45+
io.stop();
46+
else
47+
std::cout << "handle_wait error="<< error.message() << std::endl;
48+
}
49+
50+
int main() {
51+
std::ofstream logstream("/tmp/x3server.log");
52+
if (!logstream.is_open()) {
53+
return EX_CANTCREAT;
54+
}
55+
56+
pOS = &logstream;
57+
logstream << "x3server starts at " << make_daytime_string() << std::endl;
58+
59+
int cam_func_ret;
60+
size_t cam_nframe = 0;
61+
bool cam_is_on;
62+
accepted = false;
63+
logstream << "X3 initializing..." << std::endl;
64+
cam_func_ret = manifold_cam_init(GETBUFFER_MODE | TRANSFER_MODE);
65+
if (cam_func_ret == -1) {
66+
logstream << "X3 init error" << std::endl;
67+
return -1;
68+
}
69+
else {
70+
logstream << "X3 inited" << std::endl;
71+
}
72+
73+
logstream << "X3 reading first frame..." << std::endl;
74+
cam_func_ret = manifold_cam_read(imgbuf, &cam_nframe, CAM_BLOCK);
75+
if (cam_func_ret == -1) {
76+
logstream << "X3 first frame error" << std::endl;
77+
return -1;
78+
}
79+
else {
80+
logstream << "X3 first frame read" << std::endl;
81+
cam_is_on = true;
82+
}
83+
84+
try {
85+
boost::asio::io_service io_service;
86+
tcp::acceptor acceptor(io_service, tcp::endpoint(boost::asio::ip::address_v4::loopback(), PORT_NUMBER));
87+
while (cam_is_on) {
88+
tcp::socket socket(io_service);
89+
90+
logstream << "start accept..." << std::endl;
91+
accepted = false;
92+
while(!accepted && cam_is_on) {
93+
io_service.reset();
94+
acceptor.async_accept(socket, accept_handle);
95+
boost::asio::deadline_timer timer(io_service, boost::posix_time::seconds(3));
96+
timer.async_wait(boost::bind(handle_wait,
97+
boost::asio::placeholders::error,
98+
boost::ref(io_service)));
99+
io_service.run();
100+
// usleep(1000000/2);
101+
cam_func_ret = manifold_cam_read(imgbuf, &cam_nframe, CAM_NON_BLOCK);
102+
if (cam_func_ret==-1) {
103+
cam_is_on = false;
104+
break;
105+
}
106+
}
107+
108+
if (!cam_is_on) {
109+
break;
110+
}
111+
112+
if (accepted) {
113+
logstream << "accepted from " << socket.remote_endpoint() << " @ " << make_daytime_string() << std::endl;
114+
}
115+
116+
117+
// send_buf_opt_t opt1(212992);
118+
// socket.set_option(opt1);
119+
120+
int frame_cnt = 0;
121+
struct timeval tm;
122+
ImageMsgHeader h;
123+
h.header = 0xFEDCBA98;
124+
h.image_w = IMAGE_W;
125+
h.image_h = IMAGE_H;
126+
h.image_ch = IMAGE_CH;
127+
while (cam_is_on) {
128+
cam_func_ret = manifold_cam_read(imgbuf, &cam_nframe, CAM_NON_BLOCK);
129+
if (cam_func_ret==-1) {
130+
cam_is_on = false;
131+
break;
132+
}
133+
else if (cam_func_ret == 0) {
134+
usleep(1000);
135+
continue;
136+
}
137+
memcpy(sockbuf+HEADER_LEN, imgbuf, FRAME_SIZE / 3);
138+
try {
139+
frame_cnt++;
140+
boost::asio::mutable_buffers_1 message = boost::asio::buffer(sockbuf, TOTAL_LEN);
141+
142+
gettimeofday(&tm, NULL);
143+
h.secs = tm.tv_sec;
144+
h.usecs = tm.tv_usec;
145+
146+
h.pack((uint8_t *)sockbuf);
147+
// std::string message = make_daytime_string();
148+
149+
boost::system::error_code ignored_error;
150+
int cnt = boost::asio::write(socket, boost::asio::buffer(message),
151+
boost::asio::transfer_all(), ignored_error);
152+
153+
// logout every frame for first 1 sec, every sec for first 1 minutes, and every minute
154+
if (frame_cnt<30 || (frame_cnt<1800 && frame_cnt%30==0) || frame_cnt%1800==0) {
155+
logstream << boost::format("#%d frame sent %d bytes") % frame_cnt % cnt << std::endl;
156+
}
157+
158+
if (!cnt) {
159+
logstream << "remote closed" << std::endl;
160+
socket.close();
161+
break;
162+
}
163+
} catch (std::exception& e) {
164+
logstream << "ERROR in while(1):" << std::endl;
165+
logstream << e.what() << std::endl;
166+
break;
167+
}
168+
}
169+
logstream << "exit write loop..." << std::endl;
170+
}
171+
logstream << "exit accept loop..." << std::endl;
172+
} catch (std::exception& e) {
173+
logstream << "ERROR outside while(1):" << std::endl;
174+
logstream << e.what() << std::endl;
175+
}
176+
177+
logstream << "exit x3..." << std::endl;
178+
while (!manifold_cam_exit()) {
179+
logstream << "X3 failed to exit, retrying..." << std::endl;
180+
sleep(1);
181+
}
182+
logstream << "X3 exit" << std::endl;
183+
184+
return 0;
185+
}

0 commit comments

Comments
 (0)