/* * main.c - main file * * Copyright 2015 Edward V. Emelianoff * * 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 // tcsetattr #include // tcsetattr, close, read, write #include // ioctl #include // printf, getchar, fopen, perror #include // exit #include // read #include // read #include // signal #include // time #include // memcpy #include // int types #include // gettimeofday #include // assert #include // 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 = parse_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; }