mirror of
https://github.com/eddyem/small_tel.git
synced 2026-06-21 11:26:30 +03:00
start new 10-micron stellarium daemon
This commit is contained in:
284
Daemons/10micron_stellarium/stellarium.c
Normal file
284
Daemons/10micron_stellarium/stellarium.c
Normal file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* 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);
|
||||
// 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);
|
||||
return (mount_setInpRA(tagRA) && mount_setInpDec(tagDec));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)) 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 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;
|
||||
newsock = accept(sockfd, (struct sockaddr*)&myaddr, &size);
|
||||
if(newsock <= 0){
|
||||
if(errno == EAGAIN) 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);
|
||||
}
|
||||
Reference in New Issue
Block a user