mirror of
https://github.com/eddyem/small_tel.git
synced 2026-06-21 11:26:30 +03:00
297 lines
9.2 KiB
C
297 lines
9.2 KiB
C
/*
|
|
* This file is part of the mountdaemon_10micron project.
|
|
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
// base functions for sending/receiving data in stellarium protocol
|
|
|
|
#include <stdint.h>
|
|
#include <usefull_macros.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#include "angles.h"
|
|
#include "mount.h"
|
|
#include "stellarium.h"
|
|
|
|
#define BUFLEN 256
|
|
|
|
// running flag
|
|
static volatile bool isrunning = false;
|
|
static pthread_t mainthread;
|
|
|
|
//read: 0x14 0x0 0x0 0x0 0x5b 0x5a 0x2e 0xc6 0x8c 0x23 0x5 0x0 0x23 0x9 0xe5 0xaf 0x23 0x2e 0x34 0xed
|
|
// command: goto 16h29 24.45 -26d25 55.62
|
|
/*
|
|
LITTLE-ENDIAN!!!
|
|
from client:
|
|
LENGTH (2 bytes, integer): length of the message
|
|
TYPE (2 bytes, integer): 0
|
|
TIME (8 bytes, integer): current time on the server computer in microseconds
|
|
since 1970.01.01 UT. Currently unused.
|
|
RA (4 bytes, unsigned integer): right ascension of the telescope (J2000)
|
|
a value of 0x100000000 = 0x0 means 24h=0h,
|
|
a value of 0x80000000 means 12h
|
|
DEC (4 bytes, signed integer): declination of the telescope (J2000)
|
|
a value of -0x40000000 means -90degrees,
|
|
a value of 0x0 means 0degrees,
|
|
a value of 0x40000000 means 90degrees
|
|
|
|
to client:
|
|
LENGTH (2 bytes, integer): length of the message
|
|
TYPE (2 bytes, integer): 0
|
|
TIME (8 bytes, integer): current time on the server computer in microseconds
|
|
since 1970.01.01 UT. Currently unused.
|
|
RA (4 bytes, unsigned integer): right ascension of the telescope (J2000)
|
|
a value of 0x100000000 = 0x0 means 24h=0h,
|
|
a value of 0x80000000 means 12h
|
|
DEC (4 bytes, signed integer): declination of the telescope (J2000)
|
|
a value of -0x40000000 means -90degrees,
|
|
a value of 0x0 means 0degrees,
|
|
a value of 0x40000000 means 90degrees
|
|
STATUS (4 bytes, signed integer): status of the telescope, currently unused.
|
|
status=0 means ok, status<0 means some error
|
|
*/
|
|
|
|
|
|
#define DEG2DEC(degr) ((int32_t)(degr / 90. * ((double)0x40000000)))
|
|
#define DEG2RA(degr) ((uint32_t)(degr / 180. * ((double)0x80000000)))
|
|
#define HRS2RA(degr) ((uint32_t)(degr / 12. * ((double)0x80000000)))
|
|
#define DEC2DEG(i32) (((double)i32)*90./((double)0x40000000))
|
|
#define RA2DEG(u32) (((double)u32)*180. /((double)0x80000000))
|
|
#define RA2HRS(u32) (((double)u32)*12. /((double)0x80000000))
|
|
|
|
typedef struct __attribute__((__packed__)){
|
|
uint16_t len;
|
|
uint16_t type;
|
|
uint64_t time;
|
|
uint32_t ra;
|
|
int32_t dec;
|
|
} indata;
|
|
|
|
typedef struct __attribute__((__packed__)){
|
|
uint16_t len;
|
|
uint16_t type;
|
|
uint64_t time;
|
|
uint32_t ra;
|
|
int32_t dec;
|
|
int32_t status;
|
|
} outdata;
|
|
|
|
/**
|
|
* @brief proc_data - process data received from Stellarium
|
|
* @param data - raw data
|
|
* @param len - its length
|
|
* @return true if all OK
|
|
*/
|
|
static bool proc_data(uint8_t *data, ssize_t len){
|
|
FNAME();
|
|
if(len != sizeof(indata)){
|
|
WARNX("Bad data size: got %zd instead of %zd!", len, sizeof(indata));
|
|
return false;
|
|
}
|
|
indata *dat = (indata*)data;
|
|
uint16_t L, T;
|
|
uint32_t ra;
|
|
int32_t dec;
|
|
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
|
|
L = le16toh(dat->len); T = le16toh(dat->type);
|
|
ra = le32toh(dat->ra);
|
|
dec = (int32_t)le32toh((uint32_t)dat->dec);
|
|
#else
|
|
L = dat->len; T = dat->type;
|
|
ra = dat->ra; dec = dat->dec;
|
|
#endif
|
|
DBG("got message with len %u & type %u", L, T);
|
|
if(L != len){
|
|
WARNX("Length of message != msg->len");
|
|
return false;
|
|
}
|
|
if(T){
|
|
WARNX("Wrong message type");
|
|
return false;
|
|
}
|
|
// convert RA/DEC to degrees
|
|
double tagRA = RA2DEG(ra), tagDec = DEC2DEG(dec);
|
|
DBG("RA: %u (%g degr), DEC: %d (%g degr)", ra, tagRA, dec, tagDec);
|
|
LOGMSG("(stellarium) RA: %u (%g degr), DEC: %d (%g degr)", ra, tagRA, dec, tagDec);
|
|
#if 0
|
|
// check RA/DEC
|
|
horizCrds_t hnow; // without refraction
|
|
polarCrds_t p2000, pnow;
|
|
p2000.ra = DEG2RAD(tagRA);
|
|
p2000.dec = DEG2RAD(tagDec);
|
|
// now J2000 obs Jnow
|
|
if(!get_ObsPlace(NULL, &p2000, &pnow, &hnow)){
|
|
WARNX("Can't convert coordinates to Jnow");
|
|
return false;
|
|
}
|
|
tagRA = RAD2DEG(pnow.ra - pnow.eo);
|
|
tagDec = RAD2DEG(pnow.dec);
|
|
#endif
|
|
return (mount_setInpRA(tagRA) && mount_setInpDec(tagDec) && mount_setInpMJD(ERFA_DJM00));
|
|
}
|
|
|
|
/**
|
|
* Send data to user
|
|
* @param data - data to send
|
|
* @param dlen - data length
|
|
* @param sockfd - socket fd for sending data
|
|
* @return false if client disconnected
|
|
*/
|
|
float send_data(uint8_t *data, size_t dlen, int sockfd){
|
|
ssize_t sent = send(sockfd, data, dlen, MSG_NOSIGNAL);
|
|
if(sent != (ssize_t)dlen){
|
|
if(sent == -1 && errno != EINTR){
|
|
WARN("Disconnected?");
|
|
return false;
|
|
}
|
|
WARN("write()");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* main socket service procedure
|
|
*/
|
|
static void *handle_socket(void *sockd){
|
|
FNAME();
|
|
if(!isrunning) return NULL;
|
|
outdata dout;
|
|
int sock = *(int*)sockd;
|
|
dout.len = htole16(sizeof(outdata));
|
|
dout.type = 0;
|
|
while(isrunning){
|
|
// get coordinates
|
|
double RA = 0., Decl = 0.;
|
|
if((dout.status = mount_getcoords(&RA, &Decl)) == MNT_S_ERROR){
|
|
WARNX("Error: can't get coordinates");
|
|
sleep(1);
|
|
continue;
|
|
}
|
|
//DBG("got : %g/%g", RA, Decl);
|
|
dout.ra = htole32(HRS2RA(RA));
|
|
dout.dec = (int32_t)htole32(DEG2DEC(Decl));
|
|
if(!send_data((uint8_t*)&dout, sizeof(outdata), sock)) break;
|
|
//DBG("sent ra = %g, dec = %g", RA2HRS(dout.ra), DEC2DEG(dout.dec));
|
|
if(!sl_canread(sock)){
|
|
sleep(1);
|
|
continue;
|
|
}
|
|
// fill incoming buffer
|
|
uint8_t buff[BUFLEN];
|
|
ssize_t rd = read(sock, buff, BUFLEN-1);
|
|
if(rd <= 0){ // error or disconnect
|
|
DBG("Nothing to read from fd %d (ret: %zd)", sock, rd);
|
|
WARNX("Client disconnected?");
|
|
break;
|
|
}
|
|
buff[rd] = 0;
|
|
DBG("read %zd (%s)", rd, buff);
|
|
if(!proc_data(buff, rd)) dout.status = -1;
|
|
else{
|
|
DBG("sent OK");
|
|
dout.status = 0;
|
|
}
|
|
}
|
|
close(sock);
|
|
return NULL;
|
|
}
|
|
|
|
// Main loop thread: wait connections over socket and create one thread for each
|
|
static void* start(void *F){
|
|
if(isrunning){
|
|
WARNX("already running");
|
|
return NULL;
|
|
}
|
|
if(!F){
|
|
WARNX("start(): No arg");
|
|
return NULL;
|
|
}
|
|
int sockfd = *((int*)F);
|
|
if(sockfd < 0){
|
|
WARNX("start(): sockfd=%d", sockfd);
|
|
return NULL;
|
|
}
|
|
DBG("Start main loop, sockfd=%d", sockfd);
|
|
isrunning = true;
|
|
// Main loop
|
|
while(isrunning){
|
|
socklen_t size = sizeof(struct sockaddr_in);
|
|
struct sockaddr_in myaddr;
|
|
int newsock;
|
|
DBG("ACCEPT");
|
|
newsock = accept(sockfd, (struct sockaddr*)&myaddr, &size);
|
|
if(newsock <= 0){
|
|
if(errno == EAGAIN){
|
|
usleep(1000);
|
|
continue; // nothing available
|
|
}
|
|
WARN("accept()");
|
|
LOGWARN("Stellarium socket error in accept()");
|
|
sleep(1);
|
|
continue;
|
|
}
|
|
struct sockaddr_in peer;
|
|
socklen_t peer_len = sizeof(peer);
|
|
if(getpeername(newsock, (struct sockaddr*)&peer, &peer_len) == -1){
|
|
LOGWARN("Stellarium socket error in getpeername()");
|
|
WARN("getpeername()");
|
|
close(newsock);
|
|
continue;
|
|
}
|
|
int sockport = -1;
|
|
if(getsockname(newsock, (struct sockaddr*)&peer, &peer_len) == 0){
|
|
sockport = ntohs(peer.sin_port);
|
|
}
|
|
char *peerIP = inet_ntoa(peer.sin_addr);
|
|
LOGMSG("Got connection from %s @ %d", peerIP, sockport);
|
|
DBG("Peer's IP address is: %s (@port %d)\n", peerIP, sockport);
|
|
/*if(strcmp(peerIP, ACCEPT_IP) && strcmp(peerIP, "127.0.0.1")){
|
|
WARNX("Wrong IP");
|
|
close(newsock);
|
|
continue;
|
|
}*/
|
|
pthread_t rthrd;
|
|
if(pthread_create(&rthrd, NULL, handle_socket, (void*)&newsock)){
|
|
WARN("Can't create socket thread");
|
|
LOGERR("Stellarium socket: error creating listen thread");
|
|
}else{
|
|
DBG("Thread created, detouch");
|
|
pthread_detach(rthrd); // don't care about thread state
|
|
}
|
|
}
|
|
close(sockfd);
|
|
return NULL;
|
|
}
|
|
|
|
bool stellarium_start(int sockfd){
|
|
int fd = sockfd;
|
|
if(pthread_create(&mainthread, NULL, start, (void*)&fd)){
|
|
WARN("pthread_create()");
|
|
return false;
|
|
}
|
|
DBG("Stellarium server started");
|
|
return true;
|
|
}
|
|
|
|
void stellarium_stop(){
|
|
if(!isrunning) return;
|
|
isrunning = false;
|
|
pthread_join(mainthread, NULL);
|
|
}
|