2
* Author and Copyright of this file and of the stellarium telescope feature:
3
* Johannes Gajdosik, 2006
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License
7
* as published by the Free Software Foundation; either version 2
8
* of the License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
#include "telescope.h"
24
#include <windows.h> // GetSystemTimeAsFileTime
26
#define ERRNO WSAGetLastError()
28
#define EAGAIN WSAEWOULDBLOCK
30
#define EINTR WSAEINTR
32
#define EINPROGRESS WSAEINPROGRESS
33
static u_long ioctlsocket_arg = 1;
34
#define SET_NONBLOCKING_MODE(s) ioctlsocket(s,FIONBIO,&ioctlsocket_arg)
36
#define close closesocket
37
#define IS_INVALID_SOCKET(fd) (fd==INVALID_SOCKET)
40
#include <netinet/in.h>
41
#include <sys/socket.h>
47
#define SET_NONBLOCKING_MODE(s) fcntl(s,F_SETFL,O_NONBLOCK)
48
#define SOCKLEN_T socklen_t
50
#define IS_INVALID_SOCKET(fd) (fd<0)
51
#define INVALID_SOCKET (-1)
54
class TelescopeDummy : public Telescope {
56
TelescopeDummy(const string &name,const string ¶ms) : Telescope(name) {
57
desired_pos[0] = XYZ[0] = 1.0;
58
desired_pos[1] = XYZ[1] = 0.0;
59
desired_pos[2] = XYZ[2] = 0.0;
62
bool isConnected(void) const {return true;}
63
bool hasKnownPosition(void) const {return true;}
64
Vec3d getObsJ2000Pos(const Navigator *nav=0) const {return XYZ;}
65
void prepareSelectFds(fd_set&,fd_set&,int&) {
66
XYZ = XYZ*31.0+desired_pos;
67
const double lq = XYZ.lengthSquared();
68
if (lq > 0.0) XYZ *= (1.0/sqrt(lq));
69
else XYZ = desired_pos;
71
void telescopeGoto(const Vec3d &j2000_pos) {
72
desired_pos = j2000_pos;
73
desired_pos.normalize();
75
Vec3d XYZ; // j2000 position
80
class TelescopeTcp : public Telescope {
82
TelescopeTcp(const string &name,const string ¶ms);
83
~TelescopeTcp(void) {hangup();}
85
bool isConnected(void) const
86
{return (!IS_INVALID_SOCKET(fd) && !wait_for_connection_establishment);}
87
Vec3d getObsJ2000Pos(const Navigator *nav=0) const;
88
void prepareSelectFds(fd_set &read_fds,fd_set &write_fds,int &fd_max);
89
void handleSelectFds(const fd_set &read_fds,const fd_set &write_fds);
90
void telescopeGoto(const Vec3d &j2000_pos);
91
bool isInitialized(void) const {return (ntohs(address.sin_port)!=0);}
92
void performReading(void);
93
void performWriting(void);
96
struct sockaddr_in address;
98
bool wait_for_connection_establishment;
99
long long int next_connection_attempt;
102
char write_buff[120];
103
char *write_buff_end;
104
long long int time_delay;
106
long long int server_micros;
107
long long int client_micros;
112
Position positions[16];
113
Position *position_pointer;
114
Position *const end_position;
115
virtual bool hasKnownPosition(void) const
116
{return (position_pointer->client_micros!=0x7FFFFFFFFFFFFFFFLL);}
119
Telescope *Telescope::create(const string &url) {
120
string::size_type i = url.find(':');
121
if (i == string::npos) {
122
cerr << "Telescope::create(" << url << "): bad url: \"" << url
123
<< "\", ':' missing" << endl;
126
const string name = url.substr(0,i);
127
if (i+2 > url.length()) {
128
cerr << "Telescope::create(" << url << "): bad url: \"" << url
129
<< "\", too short" << endl;
132
string::size_type j = url.find(':',i+1);
133
if (j == string::npos) {
134
cerr << "Telescope::create(" << url << "): bad url: \"" << url
135
<< "\", 2nd ':' missing" << endl;
138
const string type = url.substr(i+1,j-i-1);
139
if (j+2 > url.length()) {
140
cerr << "Telescope::create(" << url << "): bad url: \"" << url
141
<< "\", too short" << endl;
144
const string params = url.substr(j+1);
145
cout << "Telescope::create(" << url << "): trying to create telescope \""
146
<< name << "\" of type \"" << type << "\" with parameters \""
147
<< params << '"' << endl;
149
if (type == "Dummy") {
150
rval = new TelescopeDummy(name,params);
151
} else if (type == "TCP") {
152
rval = new TelescopeTcp(name,params);
154
cerr << "Telescope::create(" << url << "): unknown telescop type \""
155
<< type << '"' << endl;
157
if (rval && !rval->isInitialized()) {
165
Telescope::Telescope(const string &name) : name(name) {
166
std::wostringstream oss;
168
nameI18n = oss.str();
171
wstring Telescope::getInfoString(const Navigator *nav) const {
172
const Vec3d equatorial_pos = get_earth_equ_pos(nav);
174
rect_to_sphe(&ra,&dec,equatorial_pos);
175
std::wostringstream oss;
176
oss << nameI18n << endl
177
<< "RA/DE: " << StelUtility::printAngleHMS(ra)
178
<< "/" << StelUtility::printAngleDMS(dec) << endl;
182
wstring Telescope::getShortInfoString(const Navigator*) const {
188
long long int GetNow(void) {
191
GetSystemTimeAsFileTime(&file_time);
192
return (*((__int64*)(&file_time))/10) - 86400000000LL*134774;
196
return tv.tv_sec * 1000000LL + tv.tv_usec;
200
TelescopeTcp::TelescopeTcp(const string &name,const string ¶ms)
201
:Telescope(name),fd(INVALID_SOCKET),
202
end_position(positions+(sizeof(positions)/sizeof(positions[0]))) {
204
address.sin_port = htons(0);
205
string::size_type i = params.find(':');
206
if (i == string::npos) {
207
cerr << "TelescopeTcp::TelescopeTcp(" << name << ',' << params << "): "
208
"bad params: ':' missing" << endl;
211
const string host = params.substr(0,i);
212
if (i+2 > params.length()) {
213
cerr << "TelescopeTcp::TelescopeTcp(" << name << ',' << params << "): "
214
"bad params: too short"
218
string::size_type j = params.find(':',i+1);
219
if (j == string::npos) {
220
cerr << "TelescopeTcp::TelescopeTcp(" << name << ',' << params << "): "
221
"bad params: ':' missing" << endl;
225
if (1!=sscanf(params.substr(i+1,j-i-1).c_str(),"%d",&port) ||
226
port<=0 || port>0xFFFF) {
227
cerr << "TelescopeTcp::TelescopeTcp(" << name << ',' << params << "): "
231
if (1!=sscanf(params.substr(j+1).c_str(),"%Ld",&time_delay) ||
232
time_delay<=0 || time_delay>10000000) {
233
cerr << "TelescopeTcp::TelescopeTcp(" << name << ',' << params << "): "
234
"bad time_delay" << endl;
237
struct hostent *hep = gethostbyname(host.c_str());
239
cerr << "TelescopeTcp::TelescopeTcp(" << name << ',' << params << "): "
240
"unknown host" << endl;
243
if (hep->h_length != 4) {
244
cerr << "TelescopeTcp::TelescopeTcp(" << name << ',' << params << "): "
245
"only IPv4 implemented"
249
memset(&address,0,sizeof(struct sockaddr_in));
250
memcpy(&(address.sin_addr),hep->h_addr,4);
251
address.sin_port = htons(port);
252
address.sin_family = AF_INET;
253
next_connection_attempt = -0x8000000000000000LL;
255
for (position_pointer = positions;
256
position_pointer < end_position;
257
position_pointer++) {
258
position_pointer->server_micros = 0x7FFFFFFFFFFFFFFFLL;
259
position_pointer->client_micros = 0x7FFFFFFFFFFFFFFFLL;
260
position_pointer->ra_int = 0;
261
position_pointer->dec_int = 0;
262
position_pointer->status = 0;
264
position_pointer = positions;
267
void TelescopeTcp::hangup(void) {
268
if (!IS_INVALID_SOCKET(fd)) {
272
read_buff_end = read_buff;
273
write_buff_end = write_buff;
274
wait_for_connection_establishment = false;
277
void TelescopeTcp::telescopeGoto(const Vec3d &j2000_pos) {
279
if (write_buff_end-write_buff+20 < (int)sizeof(write_buff)) {
280
const double ra = atan2(j2000_pos[1],j2000_pos[0]);
281
const double dec = atan2(j2000_pos[2],
282
sqrt(j2000_pos[0]*j2000_pos[0]+j2000_pos[1]*j2000_pos[1]));
283
unsigned int ra_int = (unsigned int)floor(
284
0.5 + ra*(((unsigned int)0x80000000)/M_PI));
285
int dec_int = (int)floor(0.5 + dec*(((unsigned int)0x80000000)/M_PI));
286
// cout << "TelescopeTcp(" << name << ")::telescopeGoto: "
287
// "queuing packet: "
288
// << (12*ra/M_PI) << ',' << (180*dec/M_PI)
289
// << "; " << ra_int << ',' << dec_int << endl;
291
*write_buff_end++ = 20;
292
*write_buff_end++ = 0;
294
*write_buff_end++ = 0;
295
*write_buff_end++ = 0;
297
long long int now = GetNow();
298
*write_buff_end++ = now;now>>=8;
299
*write_buff_end++ = now;now>>=8;
300
*write_buff_end++ = now;now>>=8;
301
*write_buff_end++ = now;now>>=8;
302
*write_buff_end++ = now;now>>=8;
303
*write_buff_end++ = now;now>>=8;
304
*write_buff_end++ = now;now>>=8;
305
*write_buff_end++ = now;
307
*write_buff_end++ = ra_int;ra_int>>=8;
308
*write_buff_end++ = ra_int;ra_int>>=8;
309
*write_buff_end++ = ra_int;ra_int>>=8;
310
*write_buff_end++ = ra_int;
312
*write_buff_end++ = dec_int;dec_int>>=8;
313
*write_buff_end++ = dec_int;dec_int>>=8;
314
*write_buff_end++ = dec_int;dec_int>>=8;
315
*write_buff_end++ = dec_int;
317
cerr << "TelescopeTcp(" << name << ")::telescopeGoto: "
318
"communication is too slow, I will ignore this command" << endl;
323
void TelescopeTcp::performWriting(void) {
324
const int to_write = write_buff_end - write_buff;
325
const int rc = send(fd,write_buff,to_write,0);
327
if (ERRNO != EINTR && ERRNO != EAGAIN) {
328
cerr << "TelescopeTcp(" << name << ")::performWriting: "
329
"send failed" << endl;
333
if (rc >= to_write) {
334
// everything written
335
write_buff_end = write_buff;
338
memmove(write_buff,write_buff+rc,to_write-rc);
339
write_buff_end -= rc;
344
void TelescopeTcp::performReading(void) {
345
const int to_read = read_buff + sizeof(read_buff) - read_buff_end;
346
const int rc = recv(fd,read_buff_end,to_read,0);
348
if (ERRNO != EINTR && ERRNO != EAGAIN) {
349
cerr << "TelescopeTcp(" << name << ")::performReading: "
350
"recv failed" << endl;
353
} else if (rc == 0) {
354
cerr << "TelescopeTcp(" << name << ")::performReading: "
355
"server has closed the connection" << endl;
360
while (read_buff_end-p >= 2) {
361
const int size = (int)( ((unsigned char)(p[0])) |
362
(((unsigned int)(unsigned char)(p[1])) << 8) );
363
if (size > (int)sizeof(read_buff) || size < 4) {
364
cerr << "TelescopeTcp(" << name << ")::performReading: "
365
"bad packet size: " << size << endl;
369
if (size > read_buff_end-p) {
370
// wait for complete packet
373
const int type = (int)( ((unsigned char)(p[2])) |
374
(((unsigned int)(unsigned char)(p[3])) << 8) );
379
cerr << "TelescopeTcp(" << name << ")::performReading: "
380
"type 0: bad packet size: " << size << endl;
384
const long long int server_micros = (long long int)
385
( ((unsigned long long int)(unsigned char)(p[ 4])) |
386
(((unsigned long long int)(unsigned char)(p[ 5])) << 8) |
387
(((unsigned long long int)(unsigned char)(p[ 6])) << 16) |
388
(((unsigned long long int)(unsigned char)(p[ 7])) << 24) |
389
(((unsigned long long int)(unsigned char)(p[ 8])) << 32) |
390
(((unsigned long long int)(unsigned char)(p[ 9])) << 40) |
391
(((unsigned long long int)(unsigned char)(p[10])) << 48) |
392
(((unsigned long long int)(unsigned char)(p[11])) << 56) );
393
const unsigned int ra_int =
394
((unsigned int)(unsigned char)(p[12])) |
395
(((unsigned int)(unsigned char)(p[13])) << 8) |
396
(((unsigned int)(unsigned char)(p[14])) << 16) |
397
(((unsigned int)(unsigned char)(p[15])) << 24);
399
(int)( ((unsigned int)(unsigned char)(p[16])) |
400
(((unsigned int)(unsigned char)(p[17])) << 8) |
401
(((unsigned int)(unsigned char)(p[18])) << 16) |
402
(((unsigned int)(unsigned char)(p[19])) << 24) );
404
(int)( ((unsigned int)(unsigned char)(p[20])) |
405
(((unsigned int)(unsigned char)(p[21])) << 8) |
406
(((unsigned int)(unsigned char)(p[22])) << 16) |
407
(((unsigned int)(unsigned char)(p[23])) << 24) );
410
if (position_pointer >= end_position) position_pointer = positions;
411
position_pointer->server_micros = server_micros;
412
position_pointer->client_micros = GetNow();
413
position_pointer->ra_int = ra_int;
414
position_pointer->dec_int = dec_int;
415
position_pointer->status = status;
416
// cout << "TelescopeTcp(" << name << ")::performReading: "
417
// "Client Time: " << position_pointer->client_micros
418
// << ", ra: " << position_pointer->ra_int
419
// << ", dec: " << position_pointer->dec_int
423
cout << "TelescopeTcp(" << name << ")::performReading: "
424
"ignoring unknown packet, type: " << type << endl;
429
if (p >= read_buff_end) {
430
// everything handled
431
read_buff_end = read_buff;
434
memmove(read_buff,p,read_buff_end-p);
435
read_buff_end -= (p-read_buff);
440
Vec3d TelescopeTcp::getObsJ2000Pos(const Navigator*) const {
441
if (position_pointer->client_micros == 0x7FFFFFFFFFFFFFFFLL) {
444
const long long int now = GetNow() - time_delay;
445
const Position *p = position_pointer;
447
const Position *pp = p;
448
if (pp == positions) pp = end_position;
450
if (pp->client_micros == 0x7FFFFFFFFFFFFFFFLL) break;
451
if (pp->client_micros <= now && now <= p->client_micros) {
452
const double h = (M_PI/(unsigned int)0x80000000)
453
/ (p->client_micros - pp->client_micros);
454
const long long int f0 = (now - pp->client_micros);
455
const long long int f1 = (p->client_micros - now);
458
if (pp->ra_int <= p->ra_int) {
459
if (p->ra_int - pp->ra_int <= (unsigned int)0x80000000) {
460
ra = h*(f1*pp->ra_int + f0*p->ra_int);
462
ra = h*(f1*(0*0x100000000LL + pp->ra_int) + f0*p->ra_int);
465
if (pp->ra_int - p->ra_int <= (unsigned int)0x80000000) {
466
ra = h*(f1*pp->ra_int + f0*p->ra_int);
468
ra = h*(f1*pp->ra_int + f0*(0*0x100000000LL + p->ra_int));
471
const double dec = h*(f1*pp->dec_int + f0*p->dec_int);
472
// cout << "TelescopeTcp(" << name << ")::getObsJ2000Pos: "
474
// << ", ra: " << ra*(((unsigned int)0x80000000)/M_PI)
475
// << ", dec: " << dec*(((unsigned int)0x80000000)/M_PI)
477
const double cdec = cos(dec);
478
return Vec3d(cos(ra)*cdec,sin(ra)*cdec,sin(dec));
481
} while (p != position_pointer);
482
const double h = (M_PI/(unsigned int)0x80000000);
483
const double ra = h*position_pointer->ra_int;
484
const double dec = h*position_pointer->dec_int;
485
const double cdec = cos(dec);
486
return Vec3d(cos(ra)*cdec,sin(ra)*cdec,sin(dec));
489
void TelescopeTcp::prepareSelectFds(fd_set &read_fds,fd_set &write_fds,
491
if (IS_INVALID_SOCKET(fd)) {
493
const long long int now = GetNow();
494
if (now < next_connection_attempt) return;
495
next_connection_attempt = now + 5000000;
496
fd = socket(AF_INET,SOCK_STREAM,0);
497
if (IS_INVALID_SOCKET(fd)) {
498
cerr << "TelescopeTcp(" << name << ")::prepareSelectFds: socket() failed" << endl;
501
if (SET_NONBLOCKING_MODE(fd) != 0) {
502
cerr << "TelescopeTcp(" << name << ")::prepareSelectFds: "
503
"could not set nonblocking mode" << endl;
507
if (connect(fd,(struct sockaddr*)(&address),sizeof(address)) != 0) {
508
if (ERRNO != EINPROGRESS && ERRNO != EAGAIN) {
509
cerr << "TelescopeTcp(" << name << ")::prepareSelectFds: "
510
"connect() failed" << endl;
514
wait_for_connection_establishment = true;
516
wait_for_connection_establishment = false;
517
// connection established, wait for next call of prepareSelectFds
520
// socked is already connected
521
if (fd_max < (int)fd) fd_max = (int)fd;
522
if (wait_for_connection_establishment) {
523
FD_SET(fd,&write_fds);
525
if (write_buff_end > write_buff) FD_SET(fd,&write_fds);
526
FD_SET(fd,&read_fds);
531
void TelescopeTcp::handleSelectFds(const fd_set &read_fds,
532
const fd_set &write_fds) {
533
if (!IS_INVALID_SOCKET(fd)) {
534
if (wait_for_connection_establishment) {
535
if (FD_ISSET(fd,&write_fds)) {
536
wait_for_connection_establishment = false;
538
SOCKLEN_T length = sizeof(err);
539
if (getsockopt(fd,SOL_SOCKET,SO_ERROR,(char*)(&err),&length) != 0) {
540
cerr << "TelescopeTcp(" << name << ")::handleSelectFds: "
541
"getsockopt failed" << endl;
545
// cerr << "TelescopeTcp(" << name << ")::handleSelectFds: "
546
// "connect failed: " << err << endl;
549
cout << "TelescopeTcp(" << name << ")::handleSelectFds: "
550
"connection established" << endl;
554
} else { // connection already established
555
if (FD_ISSET(fd,&write_fds)) {
558
if (!IS_INVALID_SOCKET(fd) && FD_ISSET(fd,&read_fds)) {