Added SMSD non-interactive command line client for Shack-Hartmann control system

This commit is contained in:
eddyem 2015-05-29 10:40:11 +03:00
parent b65a64f635
commit 34bfc07b64
18 changed files with 2549 additions and 63 deletions

View File

@ -149,7 +149,7 @@ int read_console(char *buf, size_t len){
* wait until at least one character pressed * wait until at least one character pressed
* @return character readed * @return character readed
*/ */
int mygetchar(){ // аналог getchar() без необходимости жать Enter int mygetchar(){ // ÁÎÁÌÏÇ getchar() ÂÅÚ ÎÅÏÂÈÏÄÉÍÏÓÔÉ ÖÁÔØ Enter
int ret; int ret;
do ret = read_console(NULL, 1); do ret = read_console(NULL, 1);
while(ret == 0); while(ret == 0);
@ -162,7 +162,7 @@ int mygetchar(){ // аналог getchar() без необходимости ж
* @param length - buffer len * @param length - buffer len
* @return amount of readed bytes * @return amount of readed bytes
*/ */
size_t read_tty(uint8_t *buff, size_t length){ size_t read_tty(char *buff, size_t length){
ssize_t L = 0; ssize_t L = 0;
fd_set rfds; fd_set rfds;
struct timeval tv; struct timeval tv;
@ -175,7 +175,7 @@ size_t read_tty(uint8_t *buff, size_t length){
if(FD_ISSET(comfd, &rfds)){ if(FD_ISSET(comfd, &rfds)){
if((L = read(comfd, buff, length)) < 1){ if((L = read(comfd, buff, length)) < 1){
fprintf(stderr, "ERROR on bus, exit!\n"); fprintf(stderr, "ERROR on bus, exit!\n");
exit(-4); quit(-4);
} }
} }
return (size_t)L; return (size_t)L;
@ -208,11 +208,13 @@ void help(){
printf("\n\nUse this commands:\n" printf("\n\nUse this commands:\n"
"0\tMove to end-switch 0\n" "0\tMove to end-switch 0\n"
"1\tMove to end-switch 1\n" "1\tMove to end-switch 1\n"
"Lxxx\tMake xxx steps toward zero's end-switch (0 main infinity)\n" "-xxx\tMake xxx steps toward zero's end-switch (0 main infinity)\n"
"Rxxx\tMake xxx steps toward end-switch 1 (0 main infinity)\n" "+xxx\tMake xxx steps toward end-switch 1 (0 main infinity)\n"
"S\tStop/start motor when program is running\n" "S\tStop/start motor when program is running\n"
"A\tRun previous command again or stop when running\n" "A\tRun previous command again or stop when running\n"
"E\tErase previous program from controller's memory\n" "E\tErase previous program from controller's memory\n"
"R\tTurn relay ON\n"
"r\tTurn relay OFF\n"
"\n" "\n"
); );
} }
@ -221,11 +223,11 @@ void write_tty(char *str, int L){
ssize_t D = write(comfd, str, L); ssize_t D = write(comfd, str, L);
if(D != L){ if(D != L){
fprintf(stderr, "ERROR on bus, exit!\n"); fprintf(stderr, "ERROR on bus, exit!\n");
exit(-3); quit(-3);
} }
} }
#define dup_pr(...) do{printf(__VA_ARGS__); if(fout) fprintf(fout, __VA_ARGS__);}while(0) //#define dup_pr(...) do{printf(__VA_ARGS__); if(fout) fprintf(fout, __VA_ARGS__);}while(0)
size_t read_ctrl_command(char *buf, size_t L){ // read data from controller to buffer buf size_t read_ctrl_command(char *buf, size_t L){ // read data from controller to buffer buf
int i, j; int i, j;
@ -235,7 +237,7 @@ size_t read_ctrl_command(char *buf, size_t L){ // read data from controller to b
for(j = 0; j < L; j++, ptr++){ for(j = 0; j < L; j++, ptr++){
R = 0; R = 0;
for(i = 0; i < 10 && !R; i++){ for(i = 0; i < 10 && !R; i++){
R = read_tty((uint8_t*)ptr, 1); R = read_tty(ptr, 1);
} }
if(!R){j--; break;} // nothing to read if(!R){j--; break;} // nothing to read
if(*ptr == '*') // read only one command if(*ptr == '*') // read only one command
@ -247,52 +249,71 @@ size_t read_ctrl_command(char *buf, size_t L){ // read data from controller to b
return (size_t) j + 1; return (size_t) j + 1;
} }
int parse_ctrlr_ans(char *ans){
char *E = NULL, *Star = NULL;
if(!ans || !*ans) return 1;
bus_error = NO_ERROR;
if(!(E = strchr(ans, 'E')) || !(Star = strchr(ans, '*')) || E[1] != '1'){
fprintf(stderr, "Answer format error (got: %s)\n", ans);
bus_error = UNDEFINED_ERR;
return 0;
}
switch (E[2]){ // E = "E1x"
case '0': // 10 - normal execution
break;
case '4': // 14 - program end
printf("Last command exectuted normally\n");
break;
case '2': // command interrupt by other signal
fprintf(stderr, "Last command terminated\n");
break;
case '3':
bus_error = CODE_ERR;
fprintf(stderr, "runtime");
break;
case '5':
bus_error = BUS_ERR;
fprintf(stderr, "data bus");
break;
case '6':
bus_error = COMMAND_ERR;
fprintf(stderr, "command");
break;
case '9':
bus_error = CMD_DATA_ERR;
fprintf(stderr, "command data");
break;
default:
bus_error = UNDEFINED_ERR;
fprintf(stderr, "undefined (%s)", ans);
}
if(bus_error != NO_ERROR){
fprintf(stderr, " error in controller\n");
return 0;
}
return 1;
}
int send_command(char *cmd){ int send_command(char *cmd){
int L = strlen(cmd); int L = strlen(cmd);
size_t R = 0; size_t R = 0;
char ans[256]; char ans[256];
write_tty(cmd, L); write_tty(cmd, L);
R = read_ctrl_command(ans, 255); R = read_ctrl_command(ans, 255);
DBG("readed: %s (cmd: %s, R = %zd, L = %d)\n", ans, cmd, R, L); // DBG("readed: %s (cmd: %s, R = %zd, L = %d)\n", ans, cmd, R, L);
if(!R || (strncmp(ans, cmd, L) != 0)){ if(!R || (strncmp(ans, cmd, L) != 0)){
fprintf(stderr, "Error: controller doesn't respond (answer: %s)\n", ans); fprintf(stderr, "Error: controller doesn't respond (answer: %s)\n", ans);
return 0; return 0;
} }
R = read_ctrl_command(ans, 255); R = read_ctrl_command(ans, 255);
DBG("readed: %s\n", ans); // DBG("readed: %s\n", ans);
if(!R){ // controller is running or error if(!R){ // controller is running or error
fprintf(stderr, "Controller doesn't answer!\n"); fprintf(stderr, "Controller doesn't answer!\n");
return 0; return 0;
} }
bus_error = NO_ERROR; return parse_ctrlr_ans(ans);
//if(strncasecmp(ptr, "HM")
//else
if( strncmp(ans, "E10*", 4) != 0 &&
strncmp(ans, "E14*", 4) != 0 &&
strncmp(ans, "E12*", 4) != 0){
fprintf(stderr, "Error in controller: ");
if(strncmp(ans, "E13*", 4) == 0){
bus_error = CODE_ERR;
fprintf(stderr, "runtime");
}else if(strncmp(ans, "E15*", 4) == 0){
bus_error = BUS_ERR;
fprintf(stderr, "databus");
}else if(strncmp(ans, "E16*", 4) == 0){
bus_error = COMMAND_ERR;
fprintf(stderr, "command");
}else if(strncmp(ans, "E19*", 4) == 0){
bus_error = CMD_DATA_ERR;
fprintf(stderr, "command data");
}else{
bus_error = UNDEFINED_ERR;
fprintf(stderr, "undefined (%s)", ans);
}
fprintf(stderr, " error\n");
return 0;
}
DBG("ALL OK\n");
return 1;
} }
/* /*
int send5times(char *cmd){ // sends command 'cmd' up to 5 times (if errors), return 0 in case of false int send5times(char *cmd){ // sends command 'cmd' up to 5 times (if errors), return 0 in case of false
int N, R = 0; int N, R = 0;
@ -310,7 +331,8 @@ int erase_ctrlr(){
if(!send_command("LD1*")){ // start writing a program if(!send_command("LD1*")){ // start writing a program
if(bus_error == COMMAND_ERR){ // motor is moving if(bus_error == COMMAND_ERR){ // motor is moving
printf("Found running program, stop it\n"); printf("Found running program, stop it\n");
if(send_command("ST1*")) if(!send_command("ST1*"))
send_command("SP*");
send_command("LD1*"); send_command("LD1*");
}else{ }else{
fprintf(stderr, "Controller doesn't answer: try to press S or E\n"); fprintf(stderr, "Controller doesn't answer: try to press S or E\n");
@ -332,7 +354,7 @@ void con_sig(int rb){
char command[256]; char command[256];
if(rb < 1) return; if(rb < 1) return;
if(rb == 'q') quit(0); // q == exit if(rb == 'q') quit(0); // q == exit
if(rb == 'L' || rb == 'R'){ if(rb == '-' || rb == '+'){
if(!fgets(command, 255, stdin)){ if(!fgets(command, 255, stdin)){
fprintf(stderr, "You should give amount of steps after commands 'L' and 'R'\n"); fprintf(stderr, "You should give amount of steps after commands 'L' and 'R'\n");
return; return;
@ -344,16 +366,18 @@ void con_sig(int rb){
} }
} }
#define Die_on_error(arg) do{if(!send_command(arg)) goto erase_;}while(0) #define Die_on_error(arg) do{if(!send_command(arg)) goto erase_;}while(0)
if(strchr("LR01", rb)){ // command to execute if(strchr("-+01Rr", rb)){ // command to execute
got_command = 1; got_command = 1;
if(!send_command("LD1*")){ // start writing a program if(!send_command("LD1*")){ // start writing a program
fprintf(stderr, "Error: previous program is running!\n"); fprintf(stderr, "Error: previous program is running!\n");
return; return;
} }
Die_on_error("BG*"); // move address pointer to beginning Die_on_error("BG*"); // move address pointer to beginning
if(strchr("-+01", rb)){
Die_on_error("EN*"); // enable power Die_on_error("EN*"); // enable power
Die_on_error("SD10000*"); // set speed to max (625 steps per second with 1/16) Die_on_error("SD10000*"); // set speed to max (625 steps per second with 1/16)
} }
}
switch(rb){ switch(rb){
case 'h': case 'h':
help(); help();
@ -366,7 +390,7 @@ void con_sig(int rb){
Die_on_error("DR*"); Die_on_error("DR*");
Die_on_error("ML*"); Die_on_error("ML*");
break; break;
case 'R': case '+':
Die_on_error("DR*"); Die_on_error("DR*");
if(stepsN) if(stepsN)
sprintf(command, "MV%d*", stepsN); sprintf(command, "MV%d*", stepsN);
@ -374,7 +398,7 @@ void con_sig(int rb){
sprintf(command, "MV*"); sprintf(command, "MV*");
Die_on_error(command); Die_on_error(command);
break; break;
case 'L': case '-':
Die_on_error("DL*"); Die_on_error("DL*");
if(stepsN) if(stepsN)
sprintf(command, "MV%d*", stepsN); sprintf(command, "MV%d*", stepsN);
@ -383,7 +407,7 @@ void con_sig(int rb){
Die_on_error(command); Die_on_error(command);
break; break;
case 'S': case 'S':
Die_on_error("PS1*"); Die_on_error("SP*");
break; break;
case 'A': case 'A':
Die_on_error("ST1*"); Die_on_error("ST1*");
@ -391,6 +415,12 @@ void con_sig(int rb){
case 'E': case 'E':
erase_ctrlr(); erase_ctrlr();
break; break;
case 'R':
Die_on_error("SF*");
break;
case 'r':
Die_on_error("CF*");
break;
/* default: /* default:
cmd = (uint8_t) rb; cmd = (uint8_t) rb;
write(comfd, &cmd, 1);*/ write(comfd, &cmd, 1);*/
@ -402,7 +432,7 @@ void con_sig(int rb){
} }
return; return;
erase_: erase_:
if(!erase_ctrlr()) quit(1); erase_ctrlr();
} }
/** /**
@ -429,13 +459,13 @@ uint32_t get_int(uint8_t *buff, size_t len){
int main(int argc, char *argv[]){ int main(int argc, char *argv[]){
int rb; int rb;
uint8_t buff[128]; char buff[128], *bufptr = buff;
size_t L; size_t L;
if(argc == 2){ if(argc == 2){
fout = fopen(argv[1], "a"); fout = fopen(argv[1], "a");
if(!fout){ if(!fout){
perror("Can't open output file"); perror("Can't open output file");
exit(-1); return (-1);
} }
setbuf(fout, NULL); setbuf(fout, NULL);
} }
@ -445,16 +475,25 @@ int main(int argc, char *argv[]){
signal(SIGQUIT, SIG_IGN); // ctrl+\ . signal(SIGQUIT, SIG_IGN); // ctrl+\ .
signal(SIGTSTP, SIG_IGN); // ctrl+Z signal(SIGTSTP, SIG_IGN); // ctrl+Z
setbuf(stdout, NULL); setbuf(stdout, NULL);
if(!erase_ctrlr()) quit(1); erase_ctrlr();
//t0 = dtime(); //t0 = dtime();
while(1){ while(1){
rb = read_console(NULL, 1); rb = read_console(NULL, 1);
if(rb > 0) con_sig(rb); if(rb > 0) con_sig(rb);
L = read_tty(buff, 127); L = read_tty(bufptr, 127);
if(L){ if(L){
buff[L] = 0; bufptr += L;
printf("%s", buff); if(bufptr - buff > 127){
fprintf(stderr, "Error: input buffer overflow!\n");
bufptr = buff;
}
if(bufptr[-1] == '*'){ // end of input command
*bufptr = 0;
parse_ctrlr_ans(buff);
//printf("%s", buff);
if(fout) fprintf(fout, "%zd\t%s\n", time(NULL), buff); if(fout) fprintf(fout, "%zd\t%s\n", time(NULL), buff);
bufptr = buff;
}
} }
} }
} }

View File

@ -0,0 +1,22 @@
PROGRAM = client
LDFLAGS =
SRCS = client.c
CC = gcc
DEFINES = -D_XOPEN_SOURCE=501
CXX = gcc
CFLAGS = -Wall -Werror $(DEFINES)
OBJS = $(SRCS:.c=.o)
all : $(PROGRAM) clean
$(PROGRAM) : $(OBJS)
$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -o $(PROGRAM)
# some addition dependencies
# %.o: %.c
# $(CC) $(LDFLAGS) $(CFLAGS) $< -o $@
#$(SRCS) : %.c : %.h $(INDEPENDENT_HEADERS)
# @touch $@
clean:
/bin/rm -f *.o *~
depend:
$(CXX) -MM $(CXX.SRCS)

BIN
Trinamic/SHA_client/client Executable file

Binary file not shown.

View File

@ -0,0 +1,526 @@
/*
* client.c - simple terminal client for operationg with
* Standa's 8MT175-150 translator by SMSD-1.5 driver
*
* Hardware operates in microsterpping mode (1/16),
* max current = 1.2A
* voltage = 12V
* "0" of driver connected to end-switch at opposite from motor side
* switch of motor's side connected to "IN1"
*
* Copyright 2013 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, strcmp etc
#include <stdint.h> // int types
#include <sys/time.h> // gettimeofday
#define DBG(...) do{fprintf(stderr, __VA_ARGS__); }while(0)
//double t0; // start time
static int bus_error = 0; // last error of data output
enum{
NO_ERROR = 0, // normal execution
CODE_ERR, // error of exexuted program code
BUS_ERR, // data transmission error
COMMAND_ERR, // wrong command
CMD_DATA_ERR, // wrong data of command
UNDEFINED_ERR // something else wrong
};
FILE *fout = NULL; // file for messages duplicating
char *comdev = "/dev/ttyUSB0";
int BAUD_RATE = B9600;
uint16_t step_spd = 900; // stepper speed: 225 steps per second in 1/1 mode
struct termio oldtty, tty; // TTY flags
struct termios oldt, newt; // terminal flags
int comfd = -1; // TTY fd
int erase_ctrlr();
/**
* 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
if(comfd > 0){
erase_ctrlr();
ioctl(comfd, TCSANOW, &oldtty ); // return TTY to previous state
close(comfd);
}
if(fout) fclose(fout);
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);
newt.c_lflag &= ~(ICANON);
if(tcsetattr(STDIN_FILENO, TCSANOW, &newt) < 0) quit(-2);
printf("\nOpen port...\n");
if ((comfd = open(comdev,O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0){
fprintf(stderr,"Can't use port %s\n",comdev);
quit(1);
}
printf(" OK\nGet current settings...\n");
if(ioctl(comfd,TCGETA,&oldtty) < 0) quit(-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 | PARENB; // 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) quit(-1); // set new mode
printf(" OK\n");
}
/**
* Read characters from console without echo
* @return char readed
*/
int read_console(char *buf, size_t len){
int rb = 0;
ssize_t L = 0;
struct timeval tv;
int retval;
fd_set rfds;
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
FD_ZERO(&rfds);
FD_SET(STDIN_FILENO, &rfds);
tv.tv_sec = 0; tv.tv_usec = 1000;
retval = select(1, &rfds, NULL, NULL, &tv);
if(retval){
if(FD_ISSET(STDIN_FILENO, &rfds)){
if(len < 2 || !buf) // command works as simple getchar
rb = getchar();
else{ // read all data from console buffer
if((L = read(STDIN_FILENO, buf, len)) > 0) rb = (int)L;
}
}
}
//tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return rb;
}
/**
* getchar() without echo
* wait until at least one character pressed
* @return character readed
*/
int mygetchar(){ // ÁÎÁÌÏÇ getchar() ÂÅÚ ÎÅÏÂÈÏÄÉÍÏÓÔÉ ÖÁÔØ Enter
int ret;
do ret = read_console(NULL, 1);
while(ret == 0);
return ret;
}
/**
* Read data from TTY
* @param buff (o) - buffer for data read
* @param length - buffer len
* @return amount of readed bytes
*/
size_t read_tty(char *buff, size_t length){
ssize_t L = 0;
fd_set rfds;
struct timeval tv;
int retval;
FD_ZERO(&rfds);
FD_SET(comfd, &rfds);
tv.tv_sec = 0; tv.tv_usec = 50000;
retval = select(comfd + 1, &rfds, NULL, NULL, &tv);
if(retval < 1) return 0;
if(FD_ISSET(comfd, &rfds)){
if((L = read(comfd, buff, length)) < 1){
fprintf(stderr, "ERROR on bus, exit!\n");
quit(-4);
}
}
return (size_t)L;
}
/**
* wait for answer from server
* @param sock - socket fd
* @return 0 in case of error or timeout, 1 in case of socket ready
*
int waittoread(int sock){
fd_set fds;
struct timeval timeout;
int rc;
timeout.tv_sec = 0;
timeout.tv_usec = 1000;
FD_ZERO(&fds);
FD_SET(sock, &fds);
rc = select(sock+1, &fds, NULL, NULL, &timeout);
if(rc < 0){
perror("select failed");
return 0;
}
if(rc > 0 && FD_ISSET(sock, &fds)) return 1;
return 0;
}
*/
void help(){
printf("\n\nUse this commands:\n"
"0\tMove to end-switch 0\n"
"1\tMove to end-switch 1\n"
"-xxx\tMake xxx steps toward zero's end-switch (0 main infinity)\n"
"+xxx\tMake xxx steps toward end-switch 1 (0 main infinity)\n"
"S\tPause motor when program is running\n"
"A\tStop motor when programm is running\n"
"E\tErase previous program from controller's memory\n"
"R\tTurn relay ON\n"
"r\tTurn relay OFF\n"
">\tincrease speed for 25pulses per second\n"
"<\tdecrease speed for 25pulses per second\n"
"\n"
);
}
void write_tty(char *str, int L){
ssize_t D = write(comfd, str, L);
if(D != L){
fprintf(stderr, "ERROR on bus, exit!\n");
quit(-3);
}
}
//#define dup_pr(...) do{printf(__VA_ARGS__); if(fout) fprintf(fout, __VA_ARGS__);}while(0)
size_t read_ctrl_command(char *buf, size_t L){ // read data from controller to buffer buf
int i, j;
char *ptr = buf;
size_t R;
memset(buf, 0, L);
for(j = 0; j < L; j++, ptr++){
R = 0;
for(i = 0; i < 10 && !R; i++){
R = read_tty(ptr, 1);
}
if(!R){j--; break;} // nothing to read
if(*ptr == '*') // read only one command
break;
if(*ptr < ' '){ // omit spaces & non-characters
j--; ptr--;
}
}
return (size_t) j + 1;
}
int parse_ctrlr_ans(char *ans){
char *E = NULL, *Star = NULL;
if(!ans || !*ans) return 1;
bus_error = NO_ERROR;
if(!(E = strchr(ans, 'E')) || !(Star = strchr(ans, '*')) || E[1] != '1'){
fprintf(stderr, "Answer format error (got: %s)\n", ans);
bus_error = UNDEFINED_ERR;
return 0;
}
switch (E[2]){ // E = "E1x"
case '0': // 10 - normal execution
break;
case '4': // 14 - program end
printf("Last command exectuted normally\n");
break;
case '2': // command interrupt by other signal
fprintf(stderr, "Last command terminated\n");
break;
case '3':
bus_error = CODE_ERR;
fprintf(stderr, "runtime");
break;
case '5':
bus_error = BUS_ERR;
fprintf(stderr, "data bus");
break;
case '6':
bus_error = COMMAND_ERR;
fprintf(stderr, "command");
break;
case '9':
bus_error = CMD_DATA_ERR;
fprintf(stderr, "command data");
break;
default:
bus_error = UNDEFINED_ERR;
fprintf(stderr, "undefined (%s)", ans);
}
if(bus_error != NO_ERROR){
fprintf(stderr, " error in controller\n");
return 0;
}
return 1;
}
int send_command(char *cmd){
int L = strlen(cmd);
size_t R = 0;
char ans[256];
write_tty(cmd, L);
R = read_ctrl_command(ans, 255);
// DBG("readed: %s (cmd: %s, R = %zd, L = %d)\n", ans, cmd, R, L);
if(!R || (strncmp(ans, cmd, L) != 0)){
fprintf(stderr, "Error: controller doesn't respond (answer: %s)\n", ans);
return 0;
}
R = read_ctrl_command(ans, 255);
// DBG("readed: %s\n", ans);
if(!R){ // controller is running or error
fprintf(stderr, "Controller doesn't answer!\n");
return 0;
}
return parse_ctrlr_ans(ans);
}
/*
int send5times(char *cmd){ // sends command 'cmd' up to 5 times (if errors), return 0 in case of false
int N, R = 0;
for(N = 0; N < 5 && !R; N++){
R = send_command(cmd);
}
return R;
}*/
int erase_ctrlr(){
char *errmsg = "\n\nCan't erase controller's memory: some errors occured!\n\n";
#define safely_send(x) do{ if(bus_error != NO_ERROR){ \
fprintf(stderr, errmsg); return 0;} send_command(x); }while(0)
if(!send_command("LD1*")){ // start writing a program
//if(!send_command("LB*")){ // start writing a program into op-buffer
if(bus_error == COMMAND_ERR){ // motor is moving
printf("Found running program, stop it\n");
if(!send_command("ST1*"))
//if(!send_command("ST*"))
send_command("SP*");
send_command("LD1*");
//send_command("LB*");
}else{
fprintf(stderr, "Controller doesn't answer: try to press S or E\n");
return 1;
}
}
safely_send("BG*"); // move address pointer to beginning
safely_send("DS*"); // turn off motor
safely_send("ED*"); // end of program
if(bus_error != NO_ERROR){
fprintf(stderr, errmsg);
return 0;
}
return 1;
}
void con_sig(int rb){
int stepsN = 0, got_command = 0;
char command[256];
char buf[13];
if(rb < 1) return;
if(rb == 'q') quit(0); // q == exit
if(rb == '-' || rb == '+'){
if(!fgets(command, 255, stdin)){
fprintf(stderr, "You should give amount of steps after commands 'L' and 'R'\n");
return;
}
stepsN = atoi(command); // in ticks
if(stepsN < 0 || stepsN > 10000000){
fprintf(stderr, "\n\nSteps amount should be > -1 and < 10000000 (0 means infinity)!\n\n");
return;
}
}
#define Die_on_error(arg) do{if(!send_command(arg)) goto erase_;}while(0)
if(strchr("-+01Rr", rb)){ // command to execute
got_command = 1;
if(!send_command("LD1*")){ // start writing a program
//if(!send_command("LB*")){ // start writing a program into op-buffer
fprintf(stderr, "Error: previous program is running!\n");
return;
}
Die_on_error("BG*"); // move address pointer to beginning
if(strchr("-+01", rb)){
Die_on_error("EN*"); // enable power
//Die_on_error("SD10000*"); // set speed to max (156.25 steps per second with 1/16)
snprintf(buf, 12, "SD%u*", step_spd);
Die_on_error(buf);
}
}
switch(rb){
case 'h':
help();
break;
case '0':
Die_on_error("DL*");
Die_on_error("HM*");
break;
case '1':
Die_on_error("DR*");
Die_on_error("ML*");
break;
case '+':
Die_on_error("DR*");
if(stepsN)
sprintf(command, "MV%d*", stepsN);
else
sprintf(command, "MV*");
Die_on_error(command);
break;
case '-':
Die_on_error("DL*");
if(stepsN)
sprintf(command, "MV%d*", stepsN);
else
sprintf(command, "MV*");
Die_on_error(command);
break;
case 'S':
Die_on_error("SP*");
break;
case 'A':
Die_on_error("ST1*");
//Die_on_error("ST*");
break;
case 'E':
erase_ctrlr();
break;
case 'R':
Die_on_error("SF*");
break;
case 'r':
Die_on_error("CF*");
break;
case '>': // increase speed for 25 pulses
step_spd += 25;
printf("\nCurrent speed: %u pulses per sec\n", step_spd);
//snprintf(buf, 12, "SD%u*", step_spd);
//Die_on_error(buf);
break;
case '<': // decrease speed for 25 pulses
if(step_spd > 25){
step_spd -= 25;
printf("\nCurrent speed: %u pulses per sec\n", step_spd);
//snprintf(buf, 12, "SD%u*", step_spd);
//Die_on_error(buf);
}else
printf("\nSpeed is too low\n");
break;
/* default:
cmd = (uint8_t) rb;
write(comfd, &cmd, 1);*/
}
if(got_command){ // there was some command: write ending words
Die_on_error("DS*"); // turn off power from motor at end
Die_on_error("ED*"); // signal about command end
Die_on_error("ST1*");// start program
}
return;
erase_:
erase_ctrlr();
}
/**
* Get integer value from buffer
* @param buff (i) - buffer with int
* @param len - length of data in buffer (could be 2 or 4)
* @return
*
uint32_t get_int(uint8_t *buff, size_t len){
int i;
printf("read %zd bytes: ", len);
for(i = 0; i < len; i++) printf("0x%x ", buff[i]);
printf("\n");
if(len != 2 && len != 4){
fprintf(stdout, "Bad data length!\n");
return 0xffffffff;
}
uint32_t data = 0;
uint8_t *i8 = (uint8_t*) &data;
if(len == 2) memcpy(i8, buff, 2);
else memcpy(i8, buff, 4);
return data;
}*/
int main(int argc, char *argv[]){
int rb;
char buff[128], *bufptr = buff;
size_t L;
if(argc == 2){
fout = fopen(argv[1], "a");
if(!fout){
perror("Can't open output file");
return (-1);
}
setbuf(fout, NULL);
}
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);
erase_ctrlr();
//t0 = dtime();
while(1){
rb = read_console(NULL, 1);
if(rb > 0) con_sig(rb);
L = read_tty(bufptr, 127);
if(L){
bufptr += L;
if(bufptr - buff > 127){
fprintf(stderr, "Error: input buffer overflow!\n");
bufptr = buff;
}
if(bufptr[-1] == '*'){ // end of input command
*bufptr = 0;
parse_ctrlr_ans(buff);
//printf("%s", buff);
if(fout) fprintf(fout, "%zd\t%s\n", time(NULL), buff);
bufptr = buff;
}
}
}
}

View File

@ -0,0 +1,22 @@
PROGRAM = client
LDFLAGS =
SRCS = client.c parceargs.c cmdlnopts.c
CC = gcc
DEFINES = -D_XOPEN_SOURCE=701
CXX = gcc
CFLAGS = -Wall -Werror $(DEFINES)
OBJS = $(SRCS:.c=.o)
all : $(PROGRAM) clean
$(PROGRAM) : $(OBJS)
$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -o $(PROGRAM)
# some addition dependencies
# %.o: %.c
# $(CC) $(LDFLAGS) $(CFLAGS) $< -o $@
#$(SRCS) : %.c : %.h $(INDEPENDENT_HEADERS)
# @touch $@
clean:
/bin/rm -f *.o *~
depend:
$(CXX) -MM $(CXX.SRCS)

View File

@ -0,0 +1,405 @@
/*
* client.c - simple terminal client for operationg with
* Standa's 8MT175-150 translator by SMSD-1.5 driver
*
* Hardware operates in microsterpping mode (1/16),
* max current = 1.2A
* voltage = 12V
* "0" of driver connected to end-switch at opposite from motor side
* switch of motor's side connected to "IN1"
*
* Copyright 2013 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, strcmp etc
#include <strings.h> // strcasecmp
#include <stdint.h> // int types
#include <sys/time.h> // gettimeofday
#include "cmdlnopts.h"
#define DBG(...) do{fprintf(stderr, __VA_ARGS__); }while(0)
//double t0; // start time
static int bus_error = 0; // last error of data output
enum{
NO_ERROR = 0, // normal execution
CODE_ERR, // error of exexuted program code
BUS_ERR, // data transmission error
COMMAND_ERR, // wrong command
CMD_DATA_ERR, // wrong data of command
UNDEFINED_ERR // something else wrong
};
int BAUD_RATE = B9600;
uint16_t step_spd = 900; // stepper speed: 225 steps per second in 1/1 mode
struct termio oldtty, tty; // TTY flags
int comfd = -1; // TTY fd
int erase_ctrlr();
/**
* Exit & return terminal to old state
* @param ex_stat - status (return code)
*/
void quit(int ex_stat){
if(comfd > 0){
erase_ctrlr();
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(){
printf("\nOpen port...\n");
if ((comfd = open(G.comdev,O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0){
fprintf(stderr,"Can't use port %s\n", G.comdev);
quit(1);
}
printf(" OK\nGet current settings...\n");
if(ioctl(comfd,TCGETA,&oldtty) < 0) quit(-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 | PARENB; // 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) quit(-1); // set new mode
printf(" OK\n");
}
/**
* Read data from TTY
* @param buff (o) - buffer for data read
* @param length - buffer len
* @return amount of readed bytes
*/
size_t read_tty(char *buff, size_t length){
ssize_t L = 0;
fd_set rfds;
struct timeval tv;
int retval;
FD_ZERO(&rfds);
FD_SET(comfd, &rfds);
tv.tv_sec = 0; tv.tv_usec = 50000;
retval = select(comfd + 1, &rfds, NULL, NULL, &tv);
if(retval < 1) return 0;
if(FD_ISSET(comfd, &rfds)){
if((L = read(comfd, buff, length)) < 1){
fprintf(stderr, "ERROR on bus, exit!\n");
quit(-4);
}
}
return (size_t)L;
}
void write_tty(char *str, int L){
ssize_t D = write(comfd, str, L);
if(D != L){
fprintf(stderr, "ERROR on bus, exit!\n");
quit(-3);
}
}
size_t read_ctrl_command(char *buf, size_t L){ // read data from controller to buffer buf
int i, j;
char *ptr = buf;
size_t R;
memset(buf, 0, L);
for(j = 0; j < L; j++, ptr++){
R = 0;
for(i = 0; i < 10 && !R; i++){
R = read_tty(ptr, 1);
}
if(!R){j--; break;} // nothing to read
if(*ptr == '*') // read only one command
break;
if(*ptr < ' '){ // omit spaces & non-characters
j--; ptr--;
}
}
return (size_t) j + 1;
}
int parse_ctrlr_ans(char *ans){
char *E = NULL, *Star = NULL;
if(!ans || !*ans) return 1;
bus_error = NO_ERROR;
if(!(E = strchr(ans, 'E')) || !(Star = strchr(ans, '*')) || E[1] != '1'){
fprintf(stderr, "Answer format error (got: %s)\n", ans);
bus_error = UNDEFINED_ERR;
return 0;
}
switch (E[2]){ // E = "E1x"
case '0': // 10 - normal execution
break;
case '4': // 14 - program end
printf("Last command exectuted normally\n");
break;
case '2': // command interrupt by other signal
fprintf(stderr, "Last command terminated\n");
break;
case '3':
bus_error = CODE_ERR;
fprintf(stderr, "runtime");
break;
case '5':
bus_error = BUS_ERR;
fprintf(stderr, "data bus");
break;
case '6':
bus_error = COMMAND_ERR;
fprintf(stderr, "command");
break;
case '9':
bus_error = CMD_DATA_ERR;
fprintf(stderr, "command data");
break;
default:
bus_error = UNDEFINED_ERR;
fprintf(stderr, "undefined (%s)", ans);
}
if(bus_error != NO_ERROR){
fprintf(stderr, " error in controller\n");
return 0;
}
return 1;
}
int send_command(char *cmd){
int L = strlen(cmd);
size_t R = 0;
char ans[256];
write_tty(cmd, L);
R = read_ctrl_command(ans, 255);
// DBG("readed: %s (cmd: %s, R = %zd, L = %d)\n", ans, cmd, R, L);
if(!R || (strncmp(ans, cmd, L) != 0)){
fprintf(stderr, "Error: controller doesn't respond (answer: %s)\n", ans);
return 0;
}
R = read_ctrl_command(ans, 255);
// DBG("readed: %s\n", ans);
if(!R){ // controller is running or error
fprintf(stderr, "Controller doesn't answer!\n");
return 0;
}
return parse_ctrlr_ans(ans);
}
int erase_ctrlr(){
char *errmsg = "\n\nCan't erase controller's memory: some errors occured!\n\n";
printf("Erasing old program\n");
#define safely_send(x) do{ if(bus_error != NO_ERROR){ \
fprintf(stderr, errmsg); return 0;} send_command(x); }while(0)
if(!send_command("LD1*")){ // start writing a program
//if(!send_command("LB*")){ // start writing a program into op-buffer
if(bus_error == COMMAND_ERR){ // motor is moving
printf("Found running program, stop it\n");
if(!send_command("ST1*"))
//if(!send_command("ST*"))
send_command("SP*");
send_command("LD1*");
//send_command("LB*");
}else{
fprintf(stderr, "Controller doesn't answer: maybe no power?\n");
return 1;
}
}
safely_send("BG*"); // move address pointer to beginning
safely_send("DS*"); // turn off motor
safely_send("ED*"); // end of program
if(bus_error != NO_ERROR){
fprintf(stderr, errmsg);
return 0;
}
return 1;
}
int con_sig(int rb, int stepsN){
int got_command = 0;
char command[256];
char buf[13];
#define Die_on_error(arg) do{if(!send_command(arg)) goto erase_;}while(0)
if(strchr("-+01Rr", rb)){ // command to execute
got_command = 1;
if(!send_command("LD1*")){ // start writing a program
//if(!send_command("LB*")){ // start writing a program into op-buffer
fprintf(stderr, "Error: previous program is running!\n");
return 0;
}
Die_on_error("BG*"); // move address pointer to beginning
if(strchr("-+01", rb)){
Die_on_error("EN*"); // enable power
//Die_on_error("SD10000*"); // set speed to max (156.25 steps per second with 1/16)
snprintf(buf, 12, "SD%u*", step_spd);
Die_on_error(buf);
}
}
switch(rb){
case '0':
Die_on_error("DL*");
Die_on_error("HM*");
break;
case '1':
Die_on_error("DR*");
Die_on_error("ML*");
break;
case '+':
Die_on_error("DR*");
if(stepsN)
sprintf(command, "MV%d*", stepsN);
else
sprintf(command, "MV*");
Die_on_error(command);
break;
case '-':
Die_on_error("DL*");
if(stepsN)
sprintf(command, "MV%d*", stepsN);
else
sprintf(command, "MV*");
Die_on_error(command);
break;
case 'S':
Die_on_error("SP*");
break;
case 'A':
Die_on_error("ST1*");
//Die_on_error("ST*");
break;
case 'E':
erase_ctrlr();
break;
case 'R':
Die_on_error("SF*");
break;
case 'r':
Die_on_error("CF*");
break;
case '>': // increase speed for 25 pulses
step_spd += 25;
printf("\nCurrent speed: %u pulses per sec\n", step_spd);
//snprintf(buf, 12, "SD%u*", step_spd);
//Die_on_error(buf);
break;
case '<': // decrease speed for 25 pulses
if(step_spd > 25){
step_spd -= 25;
printf("\nCurrent speed: %u pulses per sec\n", step_spd);
//snprintf(buf, 12, "SD%u*", step_spd);
//Die_on_error(buf);
}else
printf("\nSpeed is too low\n");
break;
}
if(got_command){ // there was some command: write ending words
Die_on_error("DS*"); // turn off power from motor at end
Die_on_error("ED*"); // signal about command end
Die_on_error("ST1*");// start program
return 1;
}
return 0;
erase_:
erase_ctrlr();
return 0;
}
void wait_for_answer(){
char buff[128], *bufptr = buff;
size_t L;
while(1){
L = read_tty(bufptr, 127);
if(L){
bufptr += L;
if(bufptr - buff > 127){
fprintf(stderr, "Error: input buffer overflow!\n");
bufptr = buff;
}
if(bufptr[-1] == '*'){ // end of input command
*bufptr = 0;
parse_ctrlr_ans(buff);
return;
}
}
}
}
int main(int argc, char *argv[]){
parce_args(argc, argv);
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);
erase_ctrlr();
if(G.erasecmd) return 0;
if(G.relaycmd == -1 && G.gotopos == NULL){
printf("No commands given!\n");
return -1;
}
if(G.relaycmd != -1){
int ans;
if(G.relaycmd) // turn on
ans = con_sig('R',0);
else // turn off
ans = con_sig('r',0);
if(ans)
wait_for_answer();
else
return -1;
}
if(G.gotopos){
if(strcasecmp(G.gotopos, "refmir") == 0){
if(!con_sig('1',0)) return -1;
printf("Go to last end-switch\n");
wait_for_answer();
if(!con_sig('-',500)) return -1;
}else if(strcasecmp(G.gotopos, "diagmir") == 0){
if(!con_sig('0',0)) return -1;
printf("Go to zero's end-switch\n");
wait_for_answer();
if(!con_sig('+',2500)) return -1;
}else if(strcasecmp(G.gotopos, "shack") == 0){
if(!con_sig('1',0)) return -1;
printf("Go to last end-switch\n");
wait_for_answer();
if(!con_sig('-',30000)) return -1;
}else{
printf("Wrong goto command, should be one of refmir/diagmir/shack\n");
return -1;
}
printf("Go to position\n");
wait_for_answer();
}
return 0;
}

View File

@ -0,0 +1,84 @@
/*
* cmdlnopts.c - the only function that parce cmdln args and returns glob parameters
*
* Copyright 2013 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 <stdio.h>
#include <string.h>
#include <assert.h>
#include "cmdlnopts.h"
/*
* here are global parameters initialisation
*/
glob_pars G; // internal global parameters structure
int help = 0; // whether to show help string
glob_pars Gdefault = {
.comdev = "/dev/ttyUSB0",
.relaycmd = -1,
.erasecmd = 0,
.gotopos = NULL
};
/*
* Define command line options by filling structure:
* name has_arg flag val type argptr help
*/
myoption cmdlnopts[] = {
/// "ÏÔÏÂÒÁÚÉÔØ ÜÔÏ ÓÏÏÂÝÅÎÉÅ"
{"help", 0, NULL, 'h', arg_int, APTR(&help), "show this help"},
/// "ÐÕÔØ Ë ÕÓÔÒÏÊÓÔ×Õ"
{"comdev",1, NULL, 'd', arg_string, APTR(&G.comdev), "input device path"},
/// "×ËÌÀÞÉÔØ (1)/×ÙËÌÀÞÉÔØ (0) ÒÅÌÅ"
{"relay", 1, NULL, 'r', arg_int, APTR(&G.relaycmd), "turn relay on (1)/off (0)"},
/// "ÔÏÌØËÏ ÏÞÉÓÔÉÔØ ÐÁÍÑÔØ ËÏÎÔÒÏÌÌÅÒÁ"
{"erase-old",0,NULL, 'e', arg_none, APTR(&G.erasecmd), "only erase controller's memory"},
/// "ÐÅÒÅÊÔÉ ÎÁ ÐÏÚÉÃÉÀ (refmir/diagmir/shack)"
{"goto", 1, NULL, 'g', arg_string, APTR(&G.gotopos), "go to position (refmir/diagmir/shack)"},
// ...
end_option
};
/**
* Parce command line options and return dynamically allocated structure
* to global parameters
* @param argc - copy of argc from main
* @param argv - copy of argv from main
* @return allocated structure with global parameters
*/
glob_pars *parce_args(int argc, char **argv){
int i;
void *ptr;
ptr = memcpy(&G, &Gdefault, sizeof(G)); assert(ptr);
// format of help: "Usage: progname [args]\n"
/// "éÓÐÏÌØÚÏ×ÁÎÉÅ: %s [ÁÒÇÕÍÅÎÔÙ]\n\n\tçÄÅ ÁÒÇÕÍÅÎÔÙ:\n"
change_helpstring("Usage: %s [args]\n\n\tWhere args are:\n");
// parse arguments
parceargs(&argc, &argv, cmdlnopts);
if(help) showhelp(-1, cmdlnopts);
if(argc > 0){
/// "éÇÎÏÒÉÒÕÀ ÁÒÇÕÍÅÎÔ[Ù]:"
printf("\n%s\n", "Ignore argument[s]:");
for (i = 0; i < argc; i++)
printf("\t%s\n", argv[i]);
}
return &G;
}

View File

@ -0,0 +1,43 @@
/*
* cmdlnopts.h - comand line options for parceargs
*
* Copyright 2013 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.
*/
#pragma once
#ifndef __CMDLNOPTS_H__
#define __CMDLNOPTS_H__
#include "parceargs.h"
/*
* here are some typedef's for global data
*/
typedef struct{
char *comdev; // input device
int relaycmd; // -1 - nothing, 1 - on, 0 - off
int erasecmd; // 1 to erase old
char *gotopos; // position name: refmir, diagmir, shack
}glob_pars;
extern glob_pars G;
glob_pars *parce_args(int argc, char **argv);
#endif // __CMDLNOPTS_H__

View File

@ -0,0 +1,314 @@
/*
* parceargs.c - parcing command line arguments & print help
*
* Copyright 2013 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 <stdio.h> // DBG
#include <getopt.h> // getopt_long
#include <stdlib.h> // calloc, exit, strtoll
#include <assert.h> // assert
#include <string.h> // strdup, strchr, strlen
#include <limits.h> // INT_MAX & so on
#include <libintl.h>// gettext
#include <ctype.h> // isalpha
#include "parceargs.h"
#define DBG(...)
// macro to print help messages
#ifndef PRNT
#define PRNT(x) gettext(x)
#endif
char *helpstring = "%s\n";
/**
* Change standard help header
* MAY consist ONE "%s" for progname
* @param str (i) - new format
*/
void change_helpstring(char *s){
int pcount = 0, scount = 0;
char *str = s;
// check `helpstring` and set it to default in case of error
for(; pcount < 2; str += 2){
if(!(str = strchr(str, '%'))) break;
if(str[1] != '%') pcount++; // increment '%' counter if it isn't "%%"
else{
str += 2; // pass next '%'
continue;
}
if(str[1] == 's') scount++; // increment "%s" counter
};
DBG("pc: %d, sc: %d\n", pcount, scount);
if(pcount > 1 || pcount != scount){ // amount of pcount and/or scount wrong
fprintf(stderr, "Wrong helpstring!\n");
exit(-1);
}
helpstring = s;
DBG("hs: %s\n", helpstring);
}
/**
* Carefull atoll/atoi
* @param num (o) - returning value (or NULL if you wish only check number) - allocated by user
* @param str (i) - string with number must not be NULL
* @param t (i) - T_INT for integer or T_LLONG for long long (if argtype would be wided, may add more)
* @return TRUE if conversion sone without errors, FALSE otherwise
*/
bool myatoll(void *num, char *str, argtype t){
long long tmp, *llptr;
int *iptr;
char *endptr;
assert(str);
assert(num);
tmp = strtoll(str, &endptr, 0);
if(endptr == str || *str == '\0' || *endptr != '\0')
return FALSE;
switch(t){
case arg_longlong:
llptr = (long long*) num;
*llptr = tmp;
break;
case arg_int:
default:
if(tmp < INT_MIN || tmp > INT_MAX){
fprintf(stderr, "Integer out of range\n");
return FALSE;
}
iptr = (int*)num;
*iptr = (int)tmp;
}
return TRUE;
}
// the same as myatoll but for double
// There's no NAN & INF checking here (what if they would be needed?)
bool myatod(void *num, const char *str, argtype t){
double tmp, *dptr;
float *fptr;
char *endptr;
assert(str);
tmp = strtod(str, &endptr);
if(endptr == str || *str == '\0' || *endptr != '\0')
return FALSE;
switch(t){
case arg_double:
dptr = (double *) num;
*dptr = tmp;
break;
case arg_float:
default:
fptr = (float *) num;
*fptr = (float)tmp;
break;
}
return TRUE;
}
/**
* Get index of current option in array options
* @param opt (i) - returning val of getopt_long
* @param options (i) - array of options
* @return index in array
*/
int get_optind(int opt, myoption *options){
int oind;
myoption *opts = options;
assert(opts);
for(oind = 0; opts->name && opts->val != opt; oind++, opts++);
if(!opts->name || opts->val != opt) // no such parameter
showhelp(-1, options);
return oind;
}
/**
* Parce command line arguments
* ! If arg is string, then value will be strdup'ed!
*
* @param argc (io) - address of argc of main(), return value of argc stay after `getopt`
* @param argv (io) - address of argv of main(), return pointer to argv stay after `getopt`
* BE CAREFUL! if you wanna use full argc & argv, save their original values before
* calling this function
* @param options (i) - array of `myoption` for arguments parcing
*
* @exit: in case of error this function show help & make `exit(-1)`
*/
void parceargs(int *argc, char ***argv, myoption *options){
char *short_options, *soptr;
struct option *long_options, *loptr;
size_t optsize, i;
myoption *opts = options;
// check whether there is at least one options
assert(opts);
assert(opts[0].name);
// first we count how much values are in opts
for(optsize = 0; opts->name; optsize++, opts++);
// now we can allocate memory
short_options = calloc(optsize * 3 + 1, 1); // multiply by three for '::' in case of args in opts
long_options = calloc(optsize + 1, sizeof(struct option));
opts = options; loptr = long_options; soptr = short_options;
// fill short/long parameters and make a simple checking
for(i = 0; i < optsize; i++, loptr++, opts++){
// check
assert(opts->name); // check name
if(opts->has_arg){
assert(opts->type != arg_none); // check error with arg type
assert(opts->argptr); // check pointer
}
if(opts->type != arg_none) // if there is a flag without arg, check its pointer
assert(opts->argptr);
// fill long_options
// don't do memcmp: what if there would be different alignment?
loptr->name = opts->name;
loptr->has_arg = opts->has_arg;
loptr->flag = opts->flag;
loptr->val = opts->val;
// fill short options if they are:
if(!opts->flag){
*soptr++ = opts->val;
if(opts->has_arg) // add ':' if option has required argument
*soptr++ = ':';
if(opts->has_arg == 2) // add '::' if option has optional argument
*soptr++ = ':';
}
}
// now we have both long_options & short_options and can parse `getopt_long`
while(1){
int opt;
int oindex = 0, optind = 0; // oindex - number of option in argv, optind - number in options[]
if((opt = getopt_long(*argc, *argv, short_options, long_options, &oindex)) == -1) break;
if(opt == '?'){
opt = optopt;
optind = get_optind(opt, options);
if(options[optind].has_arg == 1) showhelp(optind, options); // need argument
}
else{
if(opt == 0 || oindex > 0) optind = oindex;
else optind = get_optind(opt, options);
}
opts = &options[optind];
#ifdef EBUG
DBG ("\n*******\noption %s (oindex = %d / optind = %d)", options[optind].name, oindex, optind);
if(optarg) DBG (" with arg %s", optarg);
DBG ("\n");
#endif
if(opt == 0 && opts->has_arg == 0) continue; // only long option changing integer flag
DBG("opt = %c, arg type: ", opt);
// now check option
if(opts->has_arg == 1) assert(optarg);
bool result = TRUE;
// even if there is no argument, but argptr != NULL, think that optarg = "1"
if(!optarg) optarg = "1";
switch(opts->type){
default:
case arg_none:
DBG("none\n");
if(opts->argptr) *((int*)opts->argptr) = 1; // set argptr to 1
break;
case arg_int:
DBG("integer\n");
result = myatoll(opts->argptr, optarg, arg_int);
break;
case arg_longlong:
DBG("long long\n");
result = myatoll(opts->argptr, optarg, arg_longlong);
break;
case arg_double:
DBG("double\n");
result = myatod(opts->argptr, optarg, arg_double);
break;
case arg_float:
DBG("double\n");
result = myatod(opts->argptr, optarg, arg_float);
break;
case arg_string:
DBG("string\n");
result = (*((char **)opts->argptr) = strdup(optarg));
break;
case arg_function:
DBG("function\n");
result = ((argfn)opts->argptr)(optarg, optind);
break;
}
if(!result){
DBG("OOOPS! Error in result\n");
showhelp(optind, options);
}
}
*argc -= optind;
*argv += optind;
}
/**
* Show help information based on myoption->help values
* @param oindex (i) - if non-negative, show only help by myoption[oindex].help
* @param options (i) - array of `myoption`
*
* @exit: run `exit(-1)` !!!
*/
void showhelp(int oindex, myoption *options){
// ATTENTION: string `help` prints through macro PRNT(), bu default it is gettext,
// but you can redefine it before `#include "parceargs.h"`
int max_opt_len = 0; // max len of options substring - for right indentation
const int bufsz = 255;
char buf[bufsz+1];
myoption *opts = options;
assert(opts);
assert(opts[0].name); // check whether there is at least one options
if(oindex > -1){ // print only one message
opts = &options[oindex];
printf(" ");
if(!opts->flag && isalpha(opts->val)) printf("-%c, ", opts->val);
printf("--%s", opts->name);
if(opts->has_arg == 1) printf("=arg");
else if(opts->has_arg == 2) printf("[=arg]");
printf(" %s\n", PRNT(opts->help));
exit(-1);
}
// header, by default is just "progname\n"
printf("\n");
if(strstr(helpstring, "%s")) // print progname
printf(helpstring, __progname);
else // only text
printf("%s", helpstring);
printf("\n");
// count max_opt_len
do{
int L = strlen(opts->name);
if(max_opt_len < L) max_opt_len = L;
}while((++opts)->name);
max_opt_len += 14; // format: '-S , --long[=arg]' - get addition 13 symbols
opts = options;
// Now print all help
do{
int p = sprintf(buf, " "); // a little indent
if(!opts->flag && isalpha(opts->val)) // .val is short argument
p += snprintf(buf+p, bufsz-p, "-%c, ", opts->val);
p += snprintf(buf+p, bufsz-p, "--%s", opts->name);
if(opts->has_arg == 1) // required argument
p += snprintf(buf+p, bufsz-p, "=arg");
else if(opts->has_arg == 2) // optional argument
p += snprintf(buf+p, bufsz-p, "[=arg]");
assert(p < max_opt_len); // there would be magic if p >= max_opt_len
printf("%-*s%s\n", max_opt_len+1, buf, PRNT(opts->help)); // write options & at least 2 spaces after
}while((++opts)->name);
printf("\n\n");
exit(-1);
}

View File

@ -0,0 +1,105 @@
/*
* parceargs.h - headers for parcing command line arguments
*
* Copyright 2013 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.
*/
#pragma once
#ifndef __PARCEARGS_H__
#define __PARCEARGS_H__
#include <stdbool.h>// bool
#include <stdlib.h>
#ifndef TRUE
#define TRUE true
#endif
#ifndef FALSE
#define FALSE false
#endif
// macro for argptr
#define APTR(x) ((void*)x)
// if argptr is a function:
typedef bool(*argfn)(void *arg, int N);
/*
* type of getopt's argument
* WARNING!
* My function change value of flags by pointer, so if you want to use another type
* make a latter conversion, example:
* char charg;
* int iarg;
* myoption opts[] = {
* {"value", 1, NULL, 'v', arg_int, &iarg, "char val"}, ..., end_option};
* ..(parce args)..
* charg = (char) iarg;
*/
typedef enum {
arg_none = 0, // no arg
arg_int, // integer
arg_longlong, // long long
arg_double, // double
arg_float, // float
arg_string, // char *
arg_function // parce_args will run function `bool (*fn)(char *optarg, int N)`
} argtype;
/*
* Structure for getopt_long & help
* BE CAREFUL: .argptr is pointer to data or pointer to function,
* conversion depends on .type
*
* ATTENTION: string `help` prints through macro PRNT(), bu default it is gettext,
* but you can redefine it before `#include "parceargs.h"`
*
* if arg is string, then value wil be strdup'ed like that:
* char *str;
* myoption opts[] = {{"string", 1, NULL, 's', arg_string, &str, "string val"}, ..., end_option};
* *(opts[1].str) = strdup(optarg);
* in other cases argptr should be address of some variable (or pointer to allocated memory)
*
* NON-NULL argptr should be written inside macro APTR(argptr) or directly: (void*)argptr
*
* !!!LAST VALUE OF ARRAY SHOULD BE `end_option` or ZEROS !!!
*
*/
typedef struct{
// these are from struct option:
const char *name; // long option's name
int has_arg; // 0 - no args, 1 - nesessary arg, 2 - optionally arg
int *flag; // NULL to return val, pointer to int - to set its value of val (function returns 0)
int val; // short opt name (if flag == NULL) or flag's value
// and these are mine:
argtype type; // type of argument
void *argptr; // pointer to variable to assign optarg value or function `bool (*fn)(char *optarg, int N)`
char *help; // help string which would be shown in function `showhelp` or NULL
} myoption;
// last string of array (all zeros)
#define end_option {0,0,0,0,0,0,0}
extern const char *__progname;
void showhelp(int oindex, myoption *options);
void parceargs(int *argc, char ***argv, myoption *options);
void change_helpstring(char *s);
#endif // __PARCEARGS_H__

View File

@ -28,16 +28,17 @@ static __inline__ unsigned long long rdtsc(void){
} }
int arra[5][3] = {{3,2,1}, {3,6,4}, {7,5,8}, {1024,5543,9875}, {1001,-1001,1002}}; int arra[5][3] = {{3,2,1}, {3,6,4}, {7,5,8}, {1024,5543,9875}, {1001,-1001,1002}};
int arrb[5][3] = {{3,2,1}, {3,6,4}, {7,5,8}, {1024,5543,9875}, {1001,-1001,1002}}; int arrb[5][3] = {{3,2,1}, {3,6,4}, {7,5,8}, {1024,5543,9875}, {1001,-1001,1002}};
int arrc[5][3] = {{3,2,1}, {3,6,4}, {7,5,8}, {1024,5543,9875}, {1001,-1001,1002}};
/* /*
* It seems that this manner of sorting would be less productive than sort3b * It seems that this manner of sorting would be less productive than sort3b or sort3c
* but even on -O1 it gives better results (median by 1000 seq); * but even on -O1 it gives better results (median by 1000 seq):
* sort3c works best until -O3: *
* -Ox timing a timing b timing c * -Ox timing a timing b timing c
* 0 444 396 243 * 0 453 402 366
* 1 108 144 93 * 1 111 174 147
* 2 126 141 93 * 2 126 165 144
* 3 105 138 159 * 3 117 171 141
*/ */
static inline void sort3a(int *d){ static inline void sort3a(int *d){
#define min(x, y) (x<y?x:y) #define min(x, y) (x<y?x:y)
@ -83,7 +84,7 @@ int main(){
time2 = rdtsc() - time2; time2 = rdtsc() - time2;
time3 = rdtsc(); time3 = rdtsc();
for(i = 0; i < 5 ; i++){ for(i = 0; i < 5 ; i++){
sort3c(arrb[i]); sort3c(arrc[i]);
} }
time3 = rdtsc() - time3; time3 = rdtsc() - time3;
printf("%llu, %llu, %llu; ", time1, time2, time3); printf("%llu, %llu, %llu; ", time1, time2, time3);

82
pipe_and_buffering_read.c Normal file
View File

@ -0,0 +1,82 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <err.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define BUFSZ 1024
static void getpath(const char *modname, char *buf, size_t bufsize){
int filedes[2];
char cmd[256];
ssize_t count;
snprintf(cmd, 255, "modinfo -F filename %s", modname);
if(pipe(filedes) == -1)
err(3, "pipe");
pid_t pid = fork();
if(pid == -1)
err(4, "fork");
else if (pid == 0){
while ((dup2(filedes[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
close(filedes[1]);
close(filedes[0]);
system(cmd);
exit(0);
}
while(1){
count = read(filedes[0], buf, bufsize);
if(count == -1){
if(errno == EINTR)
continue;
else
err(7, "read");
}else
break;
}
if(count > 1) buf[count-1] = 0;
close(filedes[0]);
wait(0);
}
int main(){
int fd = open("/proc/modules", O_RDONLY);
if(fd < 0) err(1, "open");
char buf[BUFSZ+1], *end = buf;
size_t readed, toread = BUFSZ;
buf[BUFSZ] = 0;
while(1){
readed = read(fd, end, toread);
if(readed < 1 && end == buf) break;
end += readed;
*end = 0;
char *E;
#define getspace(X) {E = strchr(X, ' '); if(!E) break; *E = 0; E++;}
getspace(buf);
char *name = buf, *start = E;
if(start >= end) break;
getspace(start);
#undef getspace
size_t size = atoll(start);
char path[1024];
getpath(name, path, sizeof(path));
printf("%s: %zd\n", path, size);
if(E < end){
if((start = strchr(E, '\n'))) start++;
else start = end;
}else start = E;
if(start < end){
readed = end - start;
memmove(buf, start, readed);
end = buf + readed;
toread = BUFSZ - readed;
}else{
toread = BUFSZ;
end = buf;
}
}
close(fd);
return 0;
}

22
websockets/Makefile Normal file
View File

@ -0,0 +1,22 @@
PROGRAM = websocktest
LDFLAGS = $(shell pkg-config --libs libwebsockets) -lpthread
SRCS = test.c
CC = gcc
DEFINES = -D_XOPEN_SOURCE=501 -DCUR_PATH=\"$(shell pwd)\"
CXX = gcc
CFLAGS = -Wall -Werror -Wextra $(DEFINES) $(shell pkg-config --cflags libwebsockets)
OBJS = $(SRCS:.c=.o)
all : $(PROGRAM) clean
$(PROGRAM) : $(OBJS)
$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -o $(PROGRAM)
# some addition dependencies
# %.o: %.c
# $(CC) $(LDFLAGS) $(CFLAGS) $< -o $@
#$(SRCS) : %.c : %.h $(INDEPENDENT_HEADERS)
# @touch $@
clean:
/bin/rm -f *.o *~
depend:
$(CXX) -MM $(CXX.SRCS)

BIN
websockets/leaf.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
websockets/leaf1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

631
websockets/test.c Normal file
View File

@ -0,0 +1,631 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <syslog.h>
#include <signal.h>
#include <libwebsockets.h>
#include <termios.h> // tcsetattr
#include <stdint.h> // int types
#include <sys/stat.h> // read
#include <fcntl.h> // read
#include <pthread.h>
#define _U_ __attribute__((__unused__))
#define MESSAGE_QUEUE_SIZE 3
#define MESSAGE_LEN 128
// individual data per session
typedef struct{
int num;
int idxwr;
int idxrd;
char message[MESSAGE_QUEUE_SIZE][MESSAGE_LEN];
}per_session_data;
per_session_data global_queue;
pthread_mutex_t command_mutex;
char cmd_buf[5] = {0};
int data_in_buf = 0; // signals that there's some data in cmd_buf to send to motors
void put_message_to_queue(char *msg, per_session_data *dat){
int L = strlen(msg);
if(dat->num >= MESSAGE_QUEUE_SIZE) return;
dat->num++;
if(L < 1 || L > MESSAGE_LEN - 1) L = MESSAGE_LEN - 1;
strncpy(dat->message[dat->idxwr], msg, L);
dat->message[dat->idxwr][L] = 0;
if((++(dat->idxwr)) >= MESSAGE_QUEUE_SIZE) dat->idxwr = 0;
}
char *get_message_from_queue(per_session_data *dat){
char *R = dat->message[dat->idxrd];
if(dat->num <= 0) return NULL;
if((++dat->idxrd) >= MESSAGE_QUEUE_SIZE) dat->idxrd = 0;
dat->num--;
return R;
}
int force_exit = 0;
uint8_t buf[9];
#define TTYBUFLEN 128
uint8_t ttybuff[TTYBUFLEN];
char *comdev = "/dev/ttyUSB0";
int BAUD_RATE = B115200;
int comfd = -1; // TTY fd
uint32_t motor_speed = 50;
//**************************************************************************//
int32_t get_integer(uint8_t *buff){
int32_t val;
int ii;
uint8_t *valptr = (uint8_t*) &val + 3;
for(ii = 4; ii < 8; ii++)
*valptr-- = buff[ii];
return val;
}
void inttobuf(uint8_t *buf, int32_t value){// copy param to buffer
int i;
uint8_t *bytes = (uint8_t*) &value + 3;
for(i = 4; i < 8; i++)
buf[i] = *bytes--;
}
/**
* read tty
* @return number of readed symbols
*/
size_t read_tty(){
ssize_t L = 0, l, buffsz = TTYBUFLEN;
struct timeval tv;
int sel;
fd_set rfds;
FD_ZERO(&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, ttybuff, buffsz)) < 1){ // disconnect or other troubles
fprintf(stderr, "USB error or disconnected!\n");
exit(1);
}else{
if(L == 0){ // USB disconnected
fprintf(stderr, "USB disconnected!\n");
exit(1);
}
if(L == 9) return 9;
// all OK continue reading
//DBG("readed %zd bytes, try more.. ", L);
buffsz -= L;
select(comfd + 1, &rfds, NULL, NULL, &tv);
while(L < 9 && buffsz > 0 && (l = read(comfd, ttybuff+L, buffsz)) > 0){
L += l;
buffsz -= l;
select(comfd + 1, &rfds, NULL, NULL, &tv);
}
}
}
}
return (size_t) L;
}
static inline uint32_t log_2(const uint32_t x){
if(x == 0) return 0;
return (31 - __builtin_clz (x));
}
int send_command(uint8_t *ninebytes);
#define log2(x) ((int)log_2((uint32_t)x))
/*
* check L bytes of ttybuf (maybe there was a command to check endpoint)
*/
void check_tty_sig(size_t l){
int L = l;
uint8_t movbk[]= {1,4,1,0,0,0,0,0,0};
//if(L < 9) return; // WTF?
uint8_t* buf = ttybuff;
char msg[128];
const uint8_t pattern[] = {2,1,128,138,0,0,0};
while(L > 0){
int32_t Ival = get_integer(buf);
if(memcmp((void*)buf, (void*)pattern, sizeof(pattern)) == 0){ // motor has reached position
int motnum = log2(Ival);
snprintf(msg, 127, "Motor %d has reached position!", motnum);
printf(" %s (%d)\n", msg, Ival);
put_message_to_queue(msg, &global_queue);
if(motnum == 0){ // move motor 0 to 2000 usteps
inttobuf(movbk, 2000);
send_command(movbk);
}else if(motnum == 2){ // move motor 2 to 3450 usteps
movbk[3] = 2;
inttobuf(movbk, 3450);
send_command(movbk);
}else{
printf(" WTF?\n");
}
}else printf(" %d\n", Ival);
L -= 9;
buf += 9;
};
}
int send_command(uint8_t *ninebytes){
uint8_t crc = 0;
size_t L;
int i;
printf("send: ");
for(i = 0; i < 8; crc += ninebytes[i++])
printf("%u,", ninebytes[i]);
ninebytes[8] = crc;
printf("%u\n",ninebytes[8]);
if(9 != write(comfd, ninebytes, 9)){
perror("Can't write to Trinamic");
return 0;
}
if((L = read_tty())){
printf("got %zd bytes from tty: ", L);
check_tty_sig(L);
}
return 1;
}
void process_buf(char *command){
memset(buf, 0, 9);
buf[0] = 1; // controller #
if(command[0] == 'W'){ // 1/16
buf[1] = 5;
buf[2] = 140; // ustep resolution
buf[7] = 4; // 1/16
send_command(buf);
buf[3] = 2; // motor #2
send_command(buf);
return;
}else if(command[0] == 'S'){ // change current speed
long X = strtol(&command[1], NULL, 10);
if(X > 9 && X < 501){
motor_speed = (uint32_t) X;
printf("set speed to %u\n", motor_speed);
buf[1] = 5; // SAP
buf[2] = 4; // max pos speed
inttobuf(buf, motor_speed);
send_command(buf);
buf[3] = 2; // 2nd motor
send_command(buf);
}
return;
}
if(command[1] == '0'){ // go to start point for further moving to middle
if(command[0] == 'U') return;
uint8_t wt[] = {1,138,0,0,0,0,0,5,0};
uint8_t movbk[]= {1,4,1,0,0,0,0,0,0};
inttobuf(movbk, -4500); // 1st motor
send_command(movbk);
movbk[3] = 2;
inttobuf(movbk, -7300); // 2nd motor
send_command(movbk);
send_command(wt); // wait
return;
}
if(command[1] == 'X') buf[3] = 2; // X motor -> #2
else if(command[1] == 'Y') buf[3] = 0; // Y motor -> #0
if(command[0] == 'D'){ // start moving
if(command[2] == '+') buf[1] = 1; // ROR
else if(command[2] == '-') buf[1] = 2; // ROL
}else if(command[0] == 'U'){ // stop
buf[1] = 3; // STP
}
inttobuf(buf, motor_speed);
if(!send_command(buf)){
printf("Can't send command");
};
}
#define MESG(X) do{if(dat) put_message_to_queue(X, dat);}while(0)
void websig(char *command, per_session_data *dat){
if(command[0] == 'W' || command[1] == '0' || command[0] == 'S'){
if(command[0] == 'W'){
MESG("Set microstepping to 1/16");
}else if(command[1] == '0'){
MESG("Go to the middle. Please, wait!");
}else{
MESG("Change speed");
}
goto ret;
}
if(command[1] != 'X' && command[1] != 'Y'){ // error
MESG("Undefined coordinate");
return;
}
if(command[0] != 'D' && command[0] != 'U'){
MESG("Undefined command");
return;
}
ret:
pthread_mutex_lock(&command_mutex);
strncpy(cmd_buf, command, 4);
data_in_buf = 1;
pthread_mutex_unlock(&command_mutex);
while(data_in_buf); // wait for execution
}
static void dump_handshake_info(struct libwebsocket *wsi){
int n;
static const char *token_names[] = {
"GET URI",
"POST URI",
"OPTIONS URI",
"Host",
"Connection",
"key 1",
"key 2",
"Protocol",
"Upgrade",
"Origin",
"Draft",
"Challenge",
/* new for 04 */
"Key",
"Version",
"Sworigin",
/* new for 05 */
"Extensions",
/* client receives these */
"Accept",
"Nonce",
"Http",
/* http-related */
"Accept:",
"Ac-Request-Headers:",
"If-Modified-Since:",
"If-None-Match:",
"Accept-Encoding:",
"Accept-Language:",
"Pragma:",
"Cache-Control:",
"Authorization:",
"Cookie:",
"Content-Length:",
"Content-Type:",
"Date:",
"Range:",
"Referer:",
"Uri-Args:",
"MuxURL",
/* use token storage to stash these */
"Client sent protocols",
"Client peer address",
"Client URI",
"Client host",
"Client origin",
/* always last real token index*/
"WSI token count"
};
char buf[256];
int L = sizeof(token_names) / sizeof(token_names[0]);
for (n = 0; n < L; n++) {
if (!lws_hdr_total_length(wsi, n))
continue;
lws_hdr_copy(wsi, buf, sizeof buf, n);
printf(" %s = %s\n", token_names[n], buf);
}
}
static int my_protocol_callback(_U_ struct libwebsocket_context *context,
_U_ struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason,
_U_ void *user, void *in, _U_ size_t len){
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + MESSAGE_LEN +
LWS_SEND_BUFFER_POST_PADDING];
unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
char client_name[128];
char client_ip[128];
char *M, *msg = (char*) in;
per_session_data *dat = (per_session_data *) user;
int L, W;
void parse_queue_msg(per_session_data *d){
if((M = get_message_from_queue(d))){
L = strlen(M);
strncpy((char *)p, M, L);
W = libwebsocket_write(wsi, p, L, LWS_WRITE_TEXT);
if(L != W){
lwsl_err("Can't write to socket");
}
}
}
//struct lws_tokens *tok = (struct lws_tokens *) user;
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
printf("New Connection\n");
memset(dat, 0, sizeof(per_session_data));
libwebsocket_callback_on_writable(context, wsi);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
if(dat->num == 0 && global_queue.num == 0){
libwebsocket_callback_on_writable(context, wsi);
return 0;
}else{
parse_queue_msg(dat);
parse_queue_msg(&global_queue);
libwebsocket_callback_on_writable(context, wsi);
}
break;
case LWS_CALLBACK_RECEIVE:
websig(msg, dat);
break;
case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
libwebsockets_get_peer_addresses(context, wsi, (int)(long)in,
client_name, 127, client_ip, 127);
printf("Received network connection from %s (%s)\n",
client_name, client_ip);
break;
case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
printf("Client asks for %s\n", msg);
dump_handshake_info(wsi);
break;
case LWS_CALLBACK_CLOSED:
printf("Client disconnected\n");
break;
default:
break;
}
return 0;
}
static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'};
static int mod_table[] = {0, 2, 1};
unsigned char *base64_encode(const unsigned char *data,
size_t input_length,
size_t *output_length) {
size_t i,j;
*output_length = 4 * ((input_length + 2) / 3);
unsigned char *encoded_data = malloc(*output_length);
if (encoded_data == NULL) return NULL;
for (i = 0, j = 0; i < input_length;) {
uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
}
for (i = 0; i < (size_t)mod_table[input_length % 3]; i++)
encoded_data[*output_length - 1 - i] = '=';
return encoded_data;
}
static int improto_callback(_U_ struct libwebsocket_context *context,
_U_ struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason,
_U_ void *user, void *in, _U_ size_t len){
char client_name[128];
char client_ip[128];
char *msg = (char*) in;
void send_image(){
static int c = 0;
struct stat stat_buf;
unsigned char *buffer = NULL, *b64 = NULL;
unsigned char *p = NULL;
int fd;
size_t L, W;
if(c) fd = open("leaf.jpg", O_RDONLY);
else fd = open("leaf1.jpg", O_RDONLY);
c = !c;
if(fd < 0){
lwsl_err("Can't open image file");
return;
}
fstat(fd, &stat_buf);
L = stat_buf.st_size;
printf("image size (c=%d): %zd\n", c, L);
buffer = malloc(L);
if(!buffer) return;
if(L != (size_t)read(fd, buffer, L)){printf("err\n"); goto ret;}
b64 = base64_encode(buffer, L, &W);
L = W; free(buffer);
buffer = malloc(L+LWS_SEND_BUFFER_PRE_PADDING+LWS_SEND_BUFFER_POST_PADDING);
if(!buffer){printf("malloc\n"); free(b64); return;}
memcpy(buffer+LWS_SEND_BUFFER_PRE_PADDING,b64, L);
free(b64);
p = buffer + LWS_SEND_BUFFER_PRE_PADDING;
W = 0;
do{
p += W;
L -= W;
W = libwebsocket_write(wsi, p, L, LWS_WRITE_TEXT);
printf("write: %zd (L=%zd)\n", W, L);
}while(W>0 && W!=L);
if(W<=0) printf("<0\n");
//W = libwebsocket_write(wsi, p, L, LWS_WRITE_BINARY);
if(L != W){
printf("err: needed: %zd, writed %zd\n", L, W);
//lwsl_err("Can't write image to socket");
}
ret:
free(buffer);
close(fd);
}
//struct lws_tokens *tok = (struct lws_tokens *) user;
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
printf("New Connection\n");
send_image();
libwebsocket_callback_on_writable(context, wsi);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
libwebsocket_callback_on_writable(context, wsi);
break;
case LWS_CALLBACK_RECEIVE:
send_image();
break;
case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
libwebsockets_get_peer_addresses(context, wsi, (int)(long)in,
client_name, 127, client_ip, 127);
printf("Received network connection from %s (%s)\n",
client_name, client_ip);
break;
case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
printf("Client asks for %s\n", msg);
dump_handshake_info(wsi);
break;
case LWS_CALLBACK_CLOSED:
printf("Client disconnected\n");
break;
default:
break;
}
return 0;
}
//**************************************************************************//
/* list of supported protocols and callbacks */
//**************************************************************************//
static struct libwebsocket_protocols protocols[] = {
{
"image-protocol",
improto_callback,
0,
0,
0, NULL, 0
},
{
"XY-protocol", // name
my_protocol_callback, // callback
sizeof(per_session_data), // per_session_data_size
10, // max frame size / rx buffer
0, NULL, 0
},
{ NULL, NULL, 0, 0, 0, NULL, 0} /* terminator */
};
//**************************************************************************//
void sighandler(_U_ int sig){
close(comfd);
force_exit = 1;
}
void *websock_thread(_U_ void *buf){
struct libwebsocket_context *context;
int n = 0;
int opts = 0;
const char *iface = NULL;
int syslog_options = LOG_PID | LOG_PERROR;
//unsigned int oldus = 0;
struct lws_context_creation_info info;
int debug_level = 7;
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)){
force_exit = 1;
return NULL;
}
memset(&info, 0, sizeof info);
info.port = 9999;
/* we will only try to log things according to our debug_level */
setlogmask(LOG_UPTO (LOG_DEBUG));
openlog("lwsts", syslog_options, LOG_DAEMON);
/* tell the library what debug level to emit and to send it to syslog */
lws_set_log_level(debug_level, lwsl_emit_syslog);
info.iface = iface;
info.protocols = protocols;
info.extensions = libwebsocket_get_internal_extensions();
info.ssl_cert_filepath = NULL;
info.ssl_private_key_filepath = NULL;
info.gid = -1;
info.uid = -1;
info.options = opts;
context = libwebsocket_create_context(&info);
if (context == NULL){
lwsl_err("libwebsocket init failed\n");
force_exit = 1;
return NULL;
}
while(n >= 0 && !force_exit){
n = libwebsocket_service(context, 500);
}//while n>=0
libwebsocket_context_destroy(context);
lwsl_notice("libwebsockets-test-server exited cleanly\n");
closelog();
return NULL;
}
//**************************************************************************//
int main(_U_ int argc, _U_ char **argv){
pthread_t w_thread;
//size_t L;
signal(SIGINT, sighandler);
/*
if(argc == 2) comdev = argv[1];
printf("\nOpen port %s...\n", comdev);
if ((comfd = open(comdev,O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0){
fprintf(stderr,"Can't use port %s\n",comdev);
return 1;
}
process_buf("W"); // step: 1/16
*/
pthread_create(&w_thread, NULL, websock_thread, NULL);
while(!force_exit){
/* if((L = read_tty())){
printf("got %zd bytes from tty:\n", L);
check_tty_sig(L);
}*/
/*
pthread_mutex_lock(&command_mutex);
if(data_in_buf) process_buf(cmd_buf);
data_in_buf = 0;
pthread_mutex_unlock(&command_mutex);
*/
}
pthread_join(w_thread, NULL); // wait for closing of libsockets thread
return 0;
}//main

175
websockets/test.html Normal file
View File

@ -0,0 +1,175 @@
<html>
<head>
<meta charset=koi8-r http-equiv="Content-Language" content="ru"/>
<title>A test</title>
<style type="text/css">
.content { vertical-align:top; text-align:center; background:#fffff0; padding:12px; border-radius:10px; }
button { display: block; width: 70px; text-align: center; }
.container {border: solid 1px; border-radius:10px; padding:12px; }
</style>
</head>
<body onload="Global.init()">
<div class="container" id="cont">
<table class="content" id="tab">
<tr><td></td>
<td align='center'><button id='Y+'>Y+</button></td>
<td></td></tr>
<tr>
<td align='center'><button id='X-'>X-</button></td>
<td><button id='0'>0</button></td>
<td align='center'><button id='X+'>X+</button></td>
</tr>
<tr><td></td>
<td align='center'><button id='Y-'>Y-</button></td>
<td></td></tr>
</table>
<div class="content">
Speed: <input type="range" min="10" max="200" step="1" id="speed">
<span id="curspeed">50</span>
</div>
<p></p>
<div id = "connected">No connection</div>
<div id = "answer"></div>
</div>
<div id="cntr"></div>
<img id="ws_image">
<script>
Global = function(){
var socket = null;
var imsocket = null;
var connected = 0;
var globSpeed = 50;
function $(nm){return document.getElementById(nm);}
function get_appropriate_ws_url(){
var pcol;
var u = document.URL;
if (u.substring(0, 5) == "https") {
pcol = "wss://";
u = u.substr(8);
} else {
pcol = "ws://";
if (u.substring(0, 4) == "http")
u = u.substr(7);
}
u = u.split('/');
return pcol + u[0] + ":9999";
}
var frames = 0, time = 0;
function getcntr(){
time++;
$("cntr").innerHTML = frames/time;
setTimeout(getcntr, 1000);
}
// function hexToBase64(str) {
// return btoa(String.fromCharCode.apply(null, str.replace(/\r|\n/g, "").replace(/([\da-fA-F]{2}) ?/g, "0x$1 ").replace(/ +$/, "").split(" ")));
// }
// function base64encode(binary) {
// return btoa(unescape(encodeURIComponent(binary)));
// }
function TryConnect(){
if(connected) return;
if(socket) delete socket;
if(imsocket) delete imsocket;
apprURL = get_appropriate_ws_url();
if (typeof MozWebSocket != "undefined") {
console.log("MOZ");
socket = new MozWebSocket(apprURL,
"XY-protocol");
imsocket = new MozWebSocket(apprURL,
"image-protocol");
} else {
console.log("non-MOZ");
socket = new WebSocket(apprURL,
"XY-protocol");
imsocket = new WebSocket(apprURL,
"image-protocol");
}
if(!socket || !imsocket){
alert("Error: can't create websocket!\nMake sure that your browser supports websockets");
return;
}
function send(){
imsocket.send("get");
}
try {
socket.onopen = function(){
$("connected").style.backgroundColor = "#40ff40";
$("connected").textContent = "Connection opened";
connected = 1;
setTimeout(getcntr, 1000);
}
socket.onmessage = function got_packet(msg){
$("answer").textContent = msg.data;
}
imsocket.onmessage = function got_packet(msg){
//var bytes = new Uint8Array(msg.data);
// console.log("got image " + " len64: " + msg.length);
var img = $("ws_image");
img.src = "data:image/jpeg;base64," + msg.data;
frames++;
send();
//setTimeout(send, 100);
// img.src = "data:image/jpeg;base64," + base64encode(msg.data);
//var image = document.createElement('img');
// encode binary data to base64
//image.src = "data:image/jpeg;base64," + window.btoa(msg.data);
//image.src = "data:image/jpeg;" + msg.data;
//document.body.appendChild(image);
}
socket.onclose = function(){
$("connected").style.backgroundColor = "#ff4040";
$("connected").textContent = "Connection closed";
$("answer").textContent = "";
connected = 0;
setTimeout(TryConnect, 1000);
clearTimeout(getcntr);
}
} catch(exception) {
alert('Error' + exception);
}
}
function init(){
console.log("init");
document.getElementById("cont").style.width = document.getElementById("tab").clientWidth;
var Buttons = document.getElementsByTagName("button");
for(var i = 0; i < Buttons.length; i++){
//Buttons[i].addEventListener("click", btnclick);
Buttons[i].addEventListener("mousedown", btnmousedown);
Buttons[i].addEventListener("mouseup", btnmouseup);
Buttons[i].addEventListener("mouseout", btnmouseup);
Buttons[i].pressed = 0;
}
$("speed").value = globSpeed
$("speed").addEventListener("input", ChSpd);
$("speed").addEventListener("mouseup", SetSpd);
TryConnect();
}
/*function btnclick(){
console.log("Click: " + this.id);
}*/
function btnmouseup(){
if(this.pressed == 0) return; // this function calls also from "mouseout", so we must prevent stopping twice
this.pressed = 0;
console.log("Mouse up: " + this.id);
if(connected) socket.send("U"+this.id);
}
function btnmousedown(){
this.pressed = 1;
console.log("Mouse down: " + this.id);
if(connected) socket.send("D"+this.id);
}
function ChSpd(){
if(globSpeed == this.value) return;
globSpeed = this.value;
$("curspeed").textContent = globSpeed;
}
function SetSpd(){
if(connected) socket.send("S"+globSpeed);
}
return{
init: init
}
}();
</script>
</body>
</html>

15
websockets/testlog2.c Normal file
View File

@ -0,0 +1,15 @@
#include <stdio.h>
#include <stdint.h>
static inline uint32_t log_2(const uint32_t x){
if(x == 0) return 0;
return (31 - __builtin_clz (x));
}
int main(){
uint32_t i;
for(i = 0; i < 150; i++){
printf("log2(%u) = %u\n", i, log_2(i));
}
return 0;
}