2018-06-18 13:29:50 +03:00

285 lines
7.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* main.c - main file
*
* Copyright 2015 Edward V. Emelianoff <eddy@sao.ru>
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include <termios.h> // tcsetattr
#include <unistd.h> // tcsetattr, close, read, write
#include <sys/ioctl.h> // ioctl
#include <stdio.h> // printf, getchar, fopen, perror
#include <stdlib.h> // exit
#include <sys/stat.h> // read
#include <fcntl.h> // read
#include <signal.h> // signal
#include <time.h> // time
#include <string.h> // memcpy
#include <stdint.h> // int types
#include <sys/time.h> // gettimeofday
#include <assert.h> // assert
#include <pthread.h> // threads
#include "bta_shdata.h"
#include "cmdlnopts.h"
#ifndef _U_
#define _U_ __attribute__((__unused__))
#endif
#ifndef fabs
#define fabs(x) ((x > 0.) ? x : -x)
#endif
// scale: how much steps there is in one angular second
const double steps_per_second = 2.054;
// end-switch at 8degr
#define MIN_RESTRICT_ANGLE (29000.)
// end-switch at 100degr
#define MAX_RESTRICT_ANGLE (360000.)
#define BUFLEN 1024
glob_pars *Global_parameters = NULL;
int is_running = 1; // ==0 to exit
int BAUD_RATE = B115200;
struct termio oldtty, tty; // TTY flags
struct termios oldt, newt; // terminal flags
int comfd; // TTY fd
#define DBG(...) do{fprintf(stderr, __VA_ARGS__);}while(0)
/**
* function for different purposes that need to know time intervals
* @return double value: time in seconds
*/
double dtime(){
double t;
struct timeval tv;
gettimeofday(&tv, NULL);
t = tv.tv_sec + ((double)tv.tv_usec)/1e6;
return t;
}
/**
* Exit & return terminal to old state
* @param ex_stat - status (return code)
*/
void quit(int ex_stat){
tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // return terminal to previous state
ioctl(comfd, TCSANOW, &oldtty ); // return TTY to previous state
close(comfd);
printf("Exit! (%d)\n", ex_stat);
exit(ex_stat);
}
/**
* Open & setup TTY, terminal
*/
void tty_init(){
// terminal without echo
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
if(tcsetattr(STDIN_FILENO, TCSANOW, &newt) < 0) quit(-2);
printf("\nOpen port...\n");
if ((comfd = open(Global_parameters->serialdev,O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0){
fprintf(stderr,"Can't use port %s\n",Global_parameters->serialdev);
quit(1);
}
printf(" OK\nGet current settings...\n");
if(ioctl(comfd,TCGETA,&oldtty) < 0) exit(-1); // Get settings
tty = oldtty;
tty.c_lflag = 0; // ~(ICANON | ECHO | ECHOE | ISIG)
tty.c_oflag = 0;
tty.c_cflag = BAUD_RATE|CS8|CREAD|CLOCAL; // 9.6k, 8N1, RW, ignore line ctrl
tty.c_cc[VMIN] = 0; // non-canonical mode
tty.c_cc[VTIME] = 5;
if(ioctl(comfd,TCSETA,&tty) < 0) exit(-1); // set new mode
printf(" OK\n");
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
}
/**
* read tty
* @param buff (o) - buffer for messages readed from tty
* @param length (io) - buff's length (return readed len or 0)
* @return 1 if something was readed here or there
*/
int read_tty(char *buff, size_t *length){
ssize_t L;
size_t buffsz = *length;
struct timeval tv;
int sel, retval = 0;
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(STDIN_FILENO, &rfds);
FD_SET(comfd, &rfds);
tv.tv_sec = 0; tv.tv_usec = 100000;
sel = select(comfd + 1, &rfds, NULL, NULL, &tv);
if(sel > 0){
if(FD_ISSET(comfd, &rfds)){
if((L = read(comfd, buff, buffsz)) < 1){ // disconnect or other troubles
fprintf(stderr, "USB error or disconnected!\n");
quit(1);
}else{
if(L == 0){ // USB disconnected
fprintf(stderr, "USB disconnected!\n");
quit(1);
}
// all OK continue reading
*length = (size_t) L;
retval = 1;
}
}else{
*length = 0;
}
}
return retval;
}
void print_P2(){
int d, m;
double s = val_P;
d = ((int)s / 3600) % 360;
s -= 3600. * d;
m = s / 60;
s -= 60. * m;
printf("P2 value: %02d:%02d:%03.1f\n", d, m, s);
}
/*
void help(){
P("G\tgo to N steps\n");
P("H\tshow this help\n");
P("P\tset stepper period (us)\n");
P("S\tstop motor\n");
P("T\tshow current approx. time\n");
P("W\tshow current steps value\n");
P("X\tshow current stepper period\n");
}
*/
void write_tty(char *str){
while(*str){
write(comfd, str++, 1);
}
}
/**
* give command to move P2 on some angle
* @param rel == 1 for relative moving
* @param angle - angle in seconds
*/
void move_P2(int rel, double angle){
double curP = val_P, targP;
char buf[256];
if(fabs(angle) < 1.) return; // don't move to such little degrees
if(curP > MIN_RESTRICT_ANGLE && curP < MAX_RESTRICT_ANGLE){
fprintf(stderr, "Error: motor is in restricted area!\n");
quit(-1);
}
if(rel) targP = curP + angle;
else targP = angle;
// check for restricted zone
if(targP > MIN_RESTRICT_ANGLE && targP < MAX_RESTRICT_ANGLE){
fprintf(stderr, "Error: you want to move into restricted area!\n");
quit(-10);
}
// now check preferred rotation direction
angle = targP - curP;
//printf("targP: %g, curP: %g, angle: %g\n", targP, curP, angle);
// 360degr = 1296000''; 180degr = 648000''
if(angle < 0.) angle += 1296000.;
if(angle > 648000.){ // it's better to move in negative direction
angle -= 1296000.;
}
// convert angle into steps
angle *= steps_per_second;
_U_ size_t L = snprintf(buf, 256, "G%d\n", ((int)angle));
//printf("BUF: %s\n", buf);
write_tty(buf);
//is_running = 0;
while(is_running);
}
void *moving_thread(_U_ void *buf){
if(Global_parameters->gotopos > 0.){
//printf("gotoval: %g\n", Global_parameters->gotopos);
move_P2(0, Global_parameters->gotopos);
}else if(fabs(Global_parameters->relmove) > 1.){ // move relative current position
//printf("relval: %g\n", Global_parameters->relmove);
move_P2(1, Global_parameters->relmove);
}
// sleep(1); // give a little time for receiving messages
// is_running = 0;
return NULL;
}
int main(int argc, char *argv[]){
char buff[BUFLEN+1];
pthread_t motor_thread;
size_t L;
Global_parameters = parce_args(argc, argv);
assert(Global_parameters != NULL);
if(!get_shm_block(&sdat, ClientSide) || !check_shm_block(&sdat)){
fprintf(stderr, "Can't get SHM block!");
return -1;
}
tty_init();
signal(SIGTERM, quit); // kill (-15)
signal(SIGINT, quit); // ctrl+C
signal(SIGQUIT, SIG_IGN); // ctrl+\ .
signal(SIGTSTP, SIG_IGN); // ctrl+Z
setbuf(stdout, NULL);
double t, t0 = 0;
double p_old = -400.; // impossible value for printing P2 val on first run
if(pthread_create(&motor_thread, NULL, moving_thread, NULL)){
/// "Не могу создать поток для захвата видео"
fprintf(stderr, "Can't create readout thread\n");
quit(-1);
}
while(is_running){
L = BUFLEN;
if((t = dtime()) - t0 > 1.){ // once per second (and on first run) check P2 position
if(fabs(val_P - p_old) > 0.1){
p_old = val_P;
print_P2();
}
t0 = t;
}
if(read_tty(buff, &L)){
if(L){
buff[L] = 0;
printf("GOT: %s", buff);
if(strncmp(buff, "Stop", 4) == 0){
is_running = 0;
sleep(1);
}
}
}
if(!check_shm_block(&sdat)){
fprintf(stderr, "Corruption in SHM block!");
quit(-2);
}
}
quit(0);
return 0;
}