From 13467035d686c2b6ed312a823037455984d494f5 Mon Sep 17 00:00:00 2001 From: eddyem Date: Sun, 17 Mar 2019 13:55:56 +0300 Subject: [PATCH] Add new MMPP_control - for better scripting & external calls --- MMPP_control/mmppco.geanypro | 32 -- MMPP_control/{ => new}/MMPP_control.c.tags | 0 MMPP_control/new/MMPP_control.config | 3 + MMPP_control/new/MMPP_control.creator | 1 + MMPP_control/new/MMPP_control.creator.user | 170 +++++++ MMPP_control/new/MMPP_control.files | 10 + MMPP_control/new/MMPP_control.includes | 1 + MMPP_control/new/Makefile | 44 ++ MMPP_control/new/Readme.md | 54 +++ MMPP_control/new/cmdlnopts.c | 111 +++++ MMPP_control/new/cmdlnopts.h | 57 +++ MMPP_control/new/main.c | 201 ++++++++ MMPP_control/new/tty_procs.c | 530 +++++++++++++++++++++ MMPP_control/new/tty_procs.h | 54 +++ STM32/steppers/MMPP_steppers.config | 5 + STM32/steppers/MMPP_steppers.creator | 1 + STM32/steppers/MMPP_steppers.creator.user | 178 +++++++ STM32/steppers/MMPP_steppers.files | 13 + STM32/steppers/MMPP_steppers.includes | 3 + 19 files changed, 1436 insertions(+), 32 deletions(-) delete mode 100644 MMPP_control/mmppco.geanypro rename MMPP_control/{ => new}/MMPP_control.c.tags (100%) create mode 100644 MMPP_control/new/MMPP_control.config create mode 100644 MMPP_control/new/MMPP_control.creator create mode 100644 MMPP_control/new/MMPP_control.creator.user create mode 100644 MMPP_control/new/MMPP_control.files create mode 100644 MMPP_control/new/MMPP_control.includes create mode 100644 MMPP_control/new/Makefile create mode 100644 MMPP_control/new/Readme.md create mode 100644 MMPP_control/new/cmdlnopts.c create mode 100644 MMPP_control/new/cmdlnopts.h create mode 100644 MMPP_control/new/main.c create mode 100644 MMPP_control/new/tty_procs.c create mode 100644 MMPP_control/new/tty_procs.h create mode 100644 STM32/steppers/MMPP_steppers.config create mode 100644 STM32/steppers/MMPP_steppers.creator create mode 100644 STM32/steppers/MMPP_steppers.creator.user create mode 100644 STM32/steppers/MMPP_steppers.files create mode 100644 STM32/steppers/MMPP_steppers.includes diff --git a/MMPP_control/mmppco.geanypro b/MMPP_control/mmppco.geanypro deleted file mode 100644 index e69be0a..0000000 --- a/MMPP_control/mmppco.geanypro +++ /dev/null @@ -1,32 +0,0 @@ -[editor] -line_wrapping=false -line_break_column=100 -auto_continue_multiline=true - -[file_prefs] -final_new_line=true -ensure_convert_new_lines=true -strip_trailing_spaces=true -replace_tabs=true - -[indentation] -indent_width=4 -indent_type=0 -indent_hard_tab_width=4 -detect_indent=false -detect_indent_width=false -indent_mode=3 - -[project] -name=MMPP control -base_path=/tmp/1/Docs/MMPP_control/ - -[long line marker] -long_line_behaviour=1 -long_line_column=100 - -[files] -current_page=0 - -[VTE] -last_dir=/home/eddy diff --git a/MMPP_control/MMPP_control.c.tags b/MMPP_control/new/MMPP_control.c.tags similarity index 100% rename from MMPP_control/MMPP_control.c.tags rename to MMPP_control/new/MMPP_control.c.tags diff --git a/MMPP_control/new/MMPP_control.config b/MMPP_control/new/MMPP_control.config new file mode 100644 index 0000000..f38d70b --- /dev/null +++ b/MMPP_control/new/MMPP_control.config @@ -0,0 +1,3 @@ +// Add predefined macros for your project here. For example: +// #define THE_ANSWER 42 +#define BAUD_RATE 9600 diff --git a/MMPP_control/new/MMPP_control.creator b/MMPP_control/new/MMPP_control.creator new file mode 100644 index 0000000..e94cbbd --- /dev/null +++ b/MMPP_control/new/MMPP_control.creator @@ -0,0 +1 @@ +[General] diff --git a/MMPP_control/new/MMPP_control.creator.user b/MMPP_control/new/MMPP_control.creator.user new file mode 100644 index 0000000..1758733 --- /dev/null +++ b/MMPP_control/new/MMPP_control.creator.user @@ -0,0 +1,170 @@ + + + + + + EnvironmentId + {cf63021e-ef53-49b0-b03b-2f2570cdf3b6} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + KOI8-R + false + 4 + false + 80 + true + true + 1 + true + false + 1 + true + true + 0 + 8 + true + 2 + true + false + true + false + + + + ProjectExplorer.Project.PluginSettings + + + true + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {91347f2c-5221-46a7-80b1-0a054ca02f79} + 0 + 0 + 0 + + /home/eddy/Docs/SAO/Zeiss-1000/Simple_photometer/MMPP_control + + + + all + + false + + + false + true + Сборка + + GenericProjectManager.GenericMakeStep + + 1 + Сборка + + ProjectExplorer.BuildSteps.Build + + + + + clean + + false + + + false + true + Сборка + + GenericProjectManager.GenericMakeStep + + 1 + Очистка + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + По умолчанию + По умолчанию + GenericProjectManager.GenericBuildConfiguration + + 1 + + + 0 + Установка + + ProjectExplorer.BuildSteps.Deploy + + 1 + Конфигурация установки + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + false + false + 1000 + + true + 2 + + + Особая программа + + ProjectExplorer.CustomExecutableRunConfiguration + + 3768 + false + true + false + false + true + + + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 20 + + + Version + 20 + + diff --git a/MMPP_control/new/MMPP_control.files b/MMPP_control/new/MMPP_control.files new file mode 100644 index 0000000..4ac5fdc --- /dev/null +++ b/MMPP_control/new/MMPP_control.files @@ -0,0 +1,10 @@ +Makefile +Makefile +cmdlnopts.c +cmdlnopts.h +main.c +parseargs.h +tty_procs.c +tty_procs.h +usefull_macros.c +usefull_macros.h diff --git a/MMPP_control/new/MMPP_control.includes b/MMPP_control/new/MMPP_control.includes new file mode 100644 index 0000000..9c558e3 --- /dev/null +++ b/MMPP_control/new/MMPP_control.includes @@ -0,0 +1 @@ +. diff --git a/MMPP_control/new/Makefile b/MMPP_control/new/Makefile new file mode 100644 index 0000000..3e46add --- /dev/null +++ b/MMPP_control/new/Makefile @@ -0,0 +1,44 @@ +# run `make DEF=...` to add extra defines +PROGRAM := MMPP_control +LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all +LDFLAGS += -lusefull_macros +SRCS := $(wildcard *.c) +DEFINES := $(DEF) -DBAUD_RATE=9600 -D_GNU_SOURCE -D_XOPEN_SOURCE=1111 +#DEFINES += -DEBUG +OBJDIR := mk +CFLAGS += -O2 -Wall -Werror -Wextra -Wno-trampolines -std=gnu99 +OBJS := $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.o)) +DEPS := $(OBJS:.o=.d) +CC = gcc +#CXX = g++ + + +all : $(OBJDIR) $(PROGRAM) + +$(PROGRAM) : $(OBJS) + @echo -e "\t\tLD $(PROGRAM)" + $(CC) $(LDFLAGS) $(OBJS) -o $(PROGRAM) + +$(OBJDIR): + mkdir $(OBJDIR) + +ifneq ($(MAKECMDGOALS),clean) +-include $(DEPS) +endif + +$(OBJDIR)/%.o: %.c + @echo -e "\t\tCC $<" + $(CC) -MD -c $(LDFLAGS) $(CFLAGS) $(DEFINES) -o $@ $< + +clean: + @echo -e "\t\tCLEAN" + @rm -f $(OBJS) $(DEPS) + @rmdir $(OBJDIR) 2>/dev/null || true + +xclean: clean + @rm -f $(PROGRAM) + +gentags: + CFLAGS="$(CFLAGS) $(DEFINES)" geany -g $(PROGRAM).c.tags *[hc] 2>/dev/null + +.PHONY: gentags clean xclean diff --git a/MMPP_control/new/Readme.md b/MMPP_control/new/Readme.md new file mode 100644 index 0000000..3a61a2a --- /dev/null +++ b/MMPP_control/new/Readme.md @@ -0,0 +1,54 @@ +Simple CLI control tool allowing bash scripting +=================================== + + +## Command line arguments + + -A, --absmove absolute move (without this flag moving is relative) + -E, --reset reset given mcu (may be included several times) + -L, --lin1=arg move polaroid linear stage to N steps + -R, --rot1=arg rotate polaroid to given angle + -S, --stop stop any moving + -a, --sendraw=arg send RAW string to port and read the answer + -b, --baudrate=arg TTY baudrate + -d, --comdev=arg terminal device filename + -h, --help show this help + -l, --lin2=arg move waveplate linear stage to N steps + -p, --pidfile=arg PID-file name + -q, --quiet don't show anything @screen from stdout + -r, --rot2=arg rotate lambda/4 to given angle + -s, --status get device status + -t, --temp show temperature of both MCU + -w, --wait wait while all previous moving ends + -y, --async asynchronous moving - don't wait + + + + +## Keywords in *quiet* mode + + +- - temperature of x'th MCU; +- POLTEMP=35 +L4TEMP=32.9 +- POLMOTOR0=SLEEP +POLPOS0=0 +POLESW00=RLSD +POLESW01=RLSD +POLMOTOR1=SLEEP +POLPOS1=0 +POLESW10=RLSD +POLESW11=RLSD +POLSTEPSLEFT0 +POLSTEPSLEFT1 +L4MOTOR0=SLEEP +L4POS0=-40001 +L4ESW00=RLSD +L4ESW01=RLSD +L4MOTOR1=SLEEP +L4POS1=-40001 +L4ESW10=RLSD +L4ESW11=RLSD +L4STEPSLEFT0 +L4STEPSLEFT1 + diff --git a/MMPP_control/new/cmdlnopts.c b/MMPP_control/new/cmdlnopts.c new file mode 100644 index 0000000..198a9d7 --- /dev/null +++ b/MMPP_control/new/cmdlnopts.c @@ -0,0 +1,111 @@ +/* + * cmdlnopts.c - the only function that parse cmdln args and returns glob parameters + * + * Copyright 2013 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 "cmdlnopts.h" +#include +#include +#include +#include +#include +#include + +/* + * here are global parameters initialisation + */ +static int help; +static glob_pars G; + +int quiet = 0; // less messages @ stdout + +// DEFAULTS +// default global parameters +glob_pars const Gdefault = { + .showtemp = 0 + ,.comdev = "/dev/ttyUSB0" + ,.pidfile = "/tmp/MMPP_control.pid" + ,.speed = BAUD_RATE + ,.rot1angle = -1000. + ,.rot2angle = -1000. + ,.l1steps = INT_MAX + ,.l2steps = INT_MAX +}; + +/* + * Define command line options by filling structure: + * name has_arg flag val type argptr help +*/ +static myoption cmdlnopts[] = { + {"help", NO_ARGS, NULL, 'h', arg_none, APTR(&help), N_("show this help")}, + {"quiet", NO_ARGS, NULL, 'q', arg_none, APTR(&quiet), N_("don't show anything @screen from stdout")}, + {"absmove", NO_ARGS, NULL, 'A', arg_none, APTR(&G.absmove), N_("absolute move (without this flag moving is relative)")}, + {"temp", NO_ARGS, NULL, 't', arg_none, APTR(&G.showtemp), N_("show temperature of both MCU")}, + {"comdev", NEED_ARG, NULL, 'd', arg_string, APTR(&G.comdev), N_("terminal device filename")}, + {"sendraw", NEED_ARG, NULL, 'a', arg_string, APTR(&G.sendraw), N_("send RAW string to port and read the answer")}, + {"reset", MULT_PAR, NULL, 'E', arg_int, APTR(&G.reset), N_("reset given mcu (may be included several times)")}, + {"rot1", NEED_ARG, NULL, 'R', arg_double, APTR(&G.rot1angle), N_("rotate polaroid to given angle")}, + {"rot2", NEED_ARG, NULL, 'r', arg_double, APTR(&G.rot2angle), N_("rotate lambda/4 to given angle")}, + {"status", NO_ARGS, NULL, 's', arg_none, APTR(&G.getstatus), N_("get device status")}, + {"baudrate",NEED_ARG, NULL, 'b', arg_int, APTR(&G.speed), N_("TTY baudrate")}, + {"wait", NO_ARGS, NULL, 'w', arg_none, APTR(&G.waitold), N_("wait while all previous moving ends")}, + {"async", NO_ARGS, NULL, 'y', arg_none, APTR(&G.dontwait), N_("asynchronous moving - don't wait")}, + {"lin1", NEED_ARG, NULL, 'L', arg_int, APTR(&G.l1steps), N_("move polaroid linear stage to N steps")}, + {"lin2", NEED_ARG, NULL, 'l', arg_int, APTR(&G.l2steps), N_("move waveplate linear stage to N steps")}, + {"pidfile", NEED_ARG, NULL, 'p', arg_string, APTR(&G.pidfile), N_("PID-file name")}, + {"stop", NO_ARGS, NULL, 'S', arg_none, APTR(&G.stopall), N_("stop any moving")}, + end_option +}; + + +/** + * Parse 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 *parse_args(int argc, char **argv){ + void *ptr; + ptr = memcpy(&G, &Gdefault, sizeof(G)); assert(ptr); + // format of help: "Usage: progname [args]\n" + // parse arguments + parseargs(&argc, &argv, cmdlnopts); + if(help) showhelp(-1, cmdlnopts); + if(argc > 0){ + WARNX("%d unused parameters:\n", argc); + for(int i = 0; i < argc; ++i) + printf("\t%4d: %s\n", i+1, argv[i]); + } + return &G; +} + +/** + * @brief MSG show coloured message if `quiet` not set + * !! This function adds trailing '\n' to message + * @param s1 - green part of message (may be null) + * @param s2 - normal colored part of messate (may be null) + */ +void MSG(const char *s1, const char *s2){ + if(quiet) return; + if(s1){ + green("%s%s", s1, s2 ? ": " : "\n"); + } + if(s2) printf("%s\n", s2); +} diff --git a/MMPP_control/new/cmdlnopts.h b/MMPP_control/new/cmdlnopts.h new file mode 100644 index 0000000..671c15e --- /dev/null +++ b/MMPP_control/new/cmdlnopts.h @@ -0,0 +1,57 @@ +/* + * cmdlnopts.h - comand line options for parceargs + * + * Copyright 2013 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. + */ + +#pragma once +#ifndef CMDLNOPTS_H__ +#define CMDLNOPTS_H__ + +#include +#include + +/* + * here are some typedef's for global data + */ +typedef struct{ + int showtemp; // show temperatures of both MCU + char *comdev; // TTY device + char *sendraw; // send RAW string + char *pidfile; // pid file name + double rot1angle; // rotator 1 angle + double rot2angle; // rotator 2 angle + int speed; // TTY speed + int getstatus; // get both MCU status + int waitold; // wait for previous moving ends + int dontwait; // don't wait for moving end + int l1steps; // move linear stage 1 (polaroid) for N steps + int l2steps; // move linear stage 2 (L/4) for N steps + int absmove; // absolute move (to given position from zero-esw) + int stopall; // stop all moving + int **reset; // reset given MCU's +} glob_pars; + +// default & global parameters +extern glob_pars const Gdefault; +extern int quiet; + +glob_pars *parse_args(int argc, char **argv); +void MSG(const char *s1, const char *s2); + +#endif // CMDLNOPTS_H__ diff --git a/MMPP_control/new/main.c b/MMPP_control/new/main.c new file mode 100644 index 0000000..b9878f9 --- /dev/null +++ b/MMPP_control/new/main.c @@ -0,0 +1,201 @@ +/* + * geany_encoding=koi8-r + * main.c + * + * Copyright 2018 Edward V. Emelianov + * + * 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 "cmdlnopts.h" +#include "signal.h" +#include "tty_procs.h" +#include +#include +#include + +// All return states of main(): +enum{ + RET_ALLOK = 0, + RET_NOTFOUND, // none of MCU found or didn't found seeking MCU + RET_ONLYONE, // only one MCU found + RET_COMMERR, // communication error + RET_CANTINIT, // can't init motors: error during initiation or some of motors are moving + RET_WAITERR, // error occured during waiting procedure + RET_ERROR = 9, // uncoverable error - from libsnippets + RET_HELPCALL = 255 // user call help (or give wrong parameter[s]) - from libsnippets +}; + +static glob_pars *G; + +/** + * We REDEFINE the default WEAK function of signal processing + */ +void __attribute__((noreturn)) signals(int sig){ + if(sig){ + signal(sig, SIG_IGN); + DBG("Get signal %d, quit.\n", sig); + } + if(G->pidfile) // remove unnesessary PID file + unlink(G->pidfile); + restore_console(); + tty_close(); + exit(sig); +} + +void __attribute__((noreturn)) iffound_default(pid_t pid){ + ERRX("Another copy of this process found, pid=%d. Exit.", pid); +} + +static double convangle(double val){ + int X = (int)(val / 360.); + val -= 360. * (double)X; + return val; +} + +/** + * @return 1 if motor start moving else return 0 + */ +static int parsemotans(ttysend_status ans, const char *prefix){ + DBG("parse ans: %d (prefix: %s)", ans, prefix); + if(ans == SEND_ALLOK) return 1; + else if(ans == SEND_ERR) WARNX(_("%s moving error!"), prefix); + else if(ans == SEND_ESWITCH) WARNX(_("%s is on end-switch and can't move further"), prefix); + else if(ans == SEND_OTHER) WARNX(_("Can't move %s: bad steps amount or still moving"), prefix); + return 0; +} + +/** + * move motor + * @return 0 if motor can't move, else return 1 + */ +/** + * @brief movemotor - move motor + * @param mcu - MCU# (controller No, 1 or 2) + * @param motnum - motor# (0 or 1) + * @param steps - steps amount ( + * @param name + * @return 0 if motor can't move, else return 1 + */ +static int movemotor(int mcu, int motnum, int steps, const char *name){ + char buf[32]; + int curpos = mot_getpos(mcu, motnum); + if(curpos == INT_MIN){ + WARNX(_("Can't get current %s position"), name); + return 0; + } + if(curpos < 0){ // need to init + WARNX(_("Init of %s failed"), name); + return 0; + } + if(G->absmove){ + if(steps < 0){ + if(motnum == 1){ + steps += (mcu == 1) ? STEPSREV1 : STEPSREV2; // convert rotator angle to positive + }else{ + WARNX(_("Can't move to negative position")); + return 0; + } + } + steps -= curpos; + } + if(steps == 0){ + MSG(name, _("already at position")); + return 0; + } + DBG("try to move motor%d of mcu %d for %d steps", motnum, mcu, steps); + snprintf(buf, 32, "%dM%dM%d", mcu, motnum, steps); + ttysend_status ans = tty_sendcmd(buf); + return parsemotans(ans, name); +} + +int main(int argc, char **argv){ +// char cmd[32]; + int waitforstop = 0; + int rtn_status = RET_ALLOK; + initial_setup(); + signal(SIGTERM, signals); // kill (-15) + signal(SIGINT, signals); // ctrl+C + signal(SIGQUIT, SIG_IGN); // ctrl+\ . + signal(SIGTSTP, SIG_IGN); // ctrl+Z + setbuf(stdout, NULL); + G = parse_args(argc, argv); + char *self = strdup(argv[0]); + check4running(self, G->pidfile); + DBG("Try to open serial %s", G->comdev); + if(tty_tryopen(G->comdev, G->speed)){ + ERR(_("Can't open %s with speed %d. Exit."), G->comdev, G->speed); + } + + if(handshake()) signals(RET_NOTFOUND); // test connection & get all positions + if(G->waitold) if(tty_wait()) signals(RET_WAITERR); + if(G->showtemp){ + if(tty_showtemp() != 2) rtn_status = RET_ONLYONE; + } + if(G->stopall){ // stop everything before analyze other commands + if(tty_stopall()) rtn_status = RET_COMMERR; + else MSG(_("All motors stopped"), NULL); + } + if(G->sendraw){ + MSG(_("Send raw string"), G->sendraw); + char *got = tty_sendraw(G->sendraw); + if(got){ + MSG(_("Receive"), got); + if(quiet) printf("%s", got); + }else WARNX(_("Nothing received")); + } + if(G->rot1angle > -999. || G->rot2angle > -999. || G->l1steps != INT_MAX || G->l2steps != INT_MAX){ + // all other commands are tied with moving, so check if motors are inited + if(init_motors()) rtn_status = RET_CANTINIT; + else{ + if(G->rot1angle > -999.){ + double angle = convangle(G->rot1angle); + int steps = (int)((STEPSREV1/360.) * angle); + waitforstop = movemotor(1, 1, steps, "polaroid"); + } + if(G->rot2angle > -999.){ + double angle = convangle(G->rot2angle); + int steps = (int)((STEPSREV2/360.) * angle); + waitforstop = movemotor(2, 1, steps, "lambda/4"); + } + if(G->l1steps != INT_MAX){ + waitforstop = movemotor(1, 0, G->l1steps, "polaroid stage"); + } + if(G->l2steps != INT_MAX){ + waitforstop = movemotor(2, 0, G->l2steps, "lambda/4 stage"); + } + } + } + if((waitforstop && !G->dontwait)) if(tty_wait()) rtn_status = RET_WAITERR; + if(G->getstatus) tty_getstatus(); + if(G->reset){ + int **N = G->reset; + while(*N){ + char cmd[3]; + if(**N < 1 || **N > 2){ + WARNX(_("Wrong MCU number (%d)"), **N); + }else{ + if(!quiet) green("Reset controller #%d\n", **N); + snprintf(cmd, 3, "%dR", **N); + ttysend_status _U_ rt = tty_sendcmd(cmd); + DBG("reset %d, result: %d", **N, rt); + } + ++N; + } + } + signals(rtn_status); +} diff --git a/MMPP_control/new/tty_procs.c b/MMPP_control/new/tty_procs.c new file mode 100644 index 0000000..d951700 --- /dev/null +++ b/MMPP_control/new/tty_procs.c @@ -0,0 +1,530 @@ +/* + * geany_encoding=koi8-r + * tty_procs.c + * + * Copyright 2018 Edward V. Emelianov + * + * 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 "cmdlnopts.h" // for `verbose` +#include "tty_procs.h" +#include +#include +#include +#include + +// tty Rx static buffer +#define TBUFLEN (1024) +// read timeout (in seconds) +#define TTYTIMEOUT (0.05) + +static TTY_descr *dev = NULL; + +// two buffers for data +static char buf[TBUFLEN+1]; +static char bufo[TBUFLEN+1]; + +static int motpos[3][2]; // motor's positions, 1 - number of mcu, 2 - number of motor +static int reset[3]; // reset occured +static int endswitches[3][2]; // ESW of motors: 0 - zero esw, 1 - limit esw, -1 - clear +static int alive[3] = {0,0,0}; // ==1 if controller answers, 0 if no + +/** + * @brief tty_tryopen - try to open serial device + * @param devnm - path to device + * @param spd - speed (number) + * @return 0 if all OK + */ +int tty_tryopen(char *devnm, int spd){ + dev = new_tty(devnm, spd, 256); + if(!tty_open(dev, TRUE)) return 1; + return 0; +} + +void tty_close(){ + close_tty(&dev); +} + +/** + * read data from TTY + * WARNING! Not thread-safe!!! + * @return static buffer with data read or NULL + */ +static char *tty_get(){ + char *ptr = buf; + size_t L = 0, l = TBUFLEN; + double t0 = dtime(); + *ptr = 0; + while(dtime() - t0 < TTYTIMEOUT && l){ + size_t r = read_tty(dev); + if(!r) continue; + t0 = dtime(); + if(r > l) r = l; + DBG("got %zd bytes: %s", r, dev->buf); + strncpy(ptr, dev->buf, r); + L += r; l -= r; ptr += r; + } + buf[L] = 0; + if(L){ + return buf; + } + DBG("no answer"); + return NULL; +} + +/** + * copy given string to `buf` & add '\n' if need + * @return 0 if failed + */ +static size_t cpy2buf(char *string){ + size_t l = strlen(string); + if(l > TBUFLEN-1){ + WARNX(_("String too long! Nothing would be send.")); + return 0; + } + strcpy(bufo, string); + if(bufo[l-1] != '\n'){ + bufo[l++] = '\n'; + bufo[l] = 0; + } + return l; +} + +/** + * Send given string command to port + * @return 0 if failed + */ +static int ttysend(char *cmd){ + size_t l = cpy2buf(cmd); + if(!l) return 0; + if(write_tty(dev->comfd, bufo, l)) return 0; + return 1; +} + +/** + * send RAW string to port device + * @param string - string to send + * @return string received or NULL in case of error + */ +char* tty_sendraw(char *string){ + DBG("sendraw %s", string); + if(!ttysend(string)) return NULL; + return tty_get(); +} + +/** + * Send given string command to port with answer analysis + * @return status + */ +ttysend_status tty_sendcmd(char *cmd){ + DBG("SEND: %s", cmd); + if(!ttysend(cmd)) return SEND_ERR; + char *got = tty_get(); + if(!got) return SEND_ERR; + DBG("GOT: %s", got); + if(strcmp(got, "ALLOK\n") == 0) return SEND_ALLOK; + if(strcmp(got, "OnEndSwitch\n") == 0) return SEND_ESWITCH; + return SEND_OTHER; +} + +/** + * return static buffer - value of `key` + * NOT THREAD SAFE! + */ +static char *keyval(char *key){ + //DBG("search %s in\n%s", key, buf); + static char buff[32]; + char *got = strstr(buf, key); + if(!got) return NULL; + got = strchr(got, '='); + if(!got) return NULL; + ++got; + char *el = strchr(got, '\n'); + if(!el) return NULL; + size_t L = (size_t)(el - got); + if(L > 31 || L == 0 || !*got) return NULL; + strncpy(buff, got, L); + buff[L] = 0; + return buff; +} + +/** + * parse status with given command `cmd` + * @return: + * 1 if one of motors still moving + * 0 if both are stopped + * -1 if failed + */ +static int parsestatus(char *cmd){ + if(!cmd) return 0; + if(!tty_sendraw(cmd)) return -1; + char buff[32], stat[2][5], left[2][7], pos[2][7]; + int mvng = 0; + for(int i = 0; i < 2; ++i){ + sprintf(buff, "POS%d", i); + char *val = keyval(buff); + if(!val) return -1; + strncpy(pos[i], val, 7); + sprintf(buff, "MOTOR%d", i); + val = keyval(buff); + if(!val) return -1; + if(strcmp(val, "SLEEP") == 0){ + strcpy(stat[i], "STOP"); + strcpy(left[i], "0"); + continue; + }else if(strcmp(val, "UNKNOWN")){ + strcpy(stat[i], "MOVE"); + mvng = 1; + sprintf(buff, "STEPSLEFT%d", i); + val = keyval(buff); + if(!val) return -1; + strncpy(left[i], val, 7); + }else return -1; + } + snprintf(bufo, TBUFLEN, "%4s %6s %6s - %4s %6s %6s", + stat[0], left[0], pos[0], stat[1], left[1], pos[1]); + if(mvng){ + return 1; + } else return 0; +} + +/** + * Wait for all motors stop with current data indication + * @return 0 if all OK + */ +int tty_wait(){ + FNAME(); + int failcount = 0, chk1 = 1, chk2 = 1; + if(!quiet) + green("Pol: M0ST M0LEFT M0POS - M1ST M1LEFT M1POS || L/4: M0ST M0LEFT M0POS - M1ST M1LEFT M1POS \n"); + while(failcount < 5 && (chk1 || chk2)){ // 5 tries + if(alive[1]){ + chk1 = parsestatus("1GS"); + if(!quiet){ + printf("Pol: "); + if(chk1 == -1){ + chk1 = 1; + ++failcount; + printf("%39s", "failed"); + }else printf("%s", bufo); + } + }else if(!quiet) printf("%39s", "failed"); + if(alive[2]){ + chk2 = parsestatus("2GS"); + if(!quiet){ + printf(" || L/4: "); + if(chk2 == -1){ + chk2 = 1; + ++failcount; + printf("%39s", "failed"); + }else printf("%s", bufo); + printf(" \r"); + } + }else if(!quiet) printf("%39s", "failed"); + } + if(!quiet) printf("\n\n"); + if(failcount > 4){ + WARNX(_("Can't get status answer!")); + return 1; + } + return 0; +} + +#if 0 +MOTOR0=SLEEP +POS0=43 +ESW00=RLSD +ESW01=HALL +MOTOR1=MOVE +STEPSLEFT1=6921 +POS1=3238 +ESW10=HALL +ESW11=RLSD +#endif + +// tty_getstatus when `quiet==1` +static void ttystatq(){ + char st[4] = "xGS"; + char *nm[3] = {NULL, "POL", "L4"}; + for(int Nmcu = 1; Nmcu < 3; ++Nmcu){ + if(!alive[Nmcu]) continue; + st[0] = '0' + Nmcu; + if(!tty_sendraw(st)) continue; + char *str = strtok(buf, "\n"); + while(str){ + printf("%s%s\n", nm[Nmcu], str); + str = strtok(NULL, "\n"); + } + } +} + +// tty_getstatus when `quiet==0` +static void ttystat(){ + int chk1 = -1, chk2 = -1; + char buff[TBUFLEN+1]; + if(!quiet) green("Pol: M0ST M0LEFT M0POS - M1ST M1LEFT M1POS || L/4: M0ST M0LEFT M0POS - M1ST M1LEFT M1POS \n"); + if(alive[1]) chk1 = parsestatus("1GS"); + MSG(NULL, "Pol: "); + if(chk1 == -1){ + if(!quiet) printf("%39s", "failed"); + }else printf("%s", bufo); + char *val = keyval("ESW00"); + if(!val) val = " "; + sprintf(buff, "%5s ", val); + val = keyval("ESW01"); + if(!val) val = " "; + sprintf(&buff[6], "%5s ", val); + val = keyval("ESW10"); + if(!val) val = " "; + sprintf(&buff[12], "%5s ", val); + val = keyval("ESW11"); + if(!val) val = " "; + sprintf(&buff[18], "%5s ", val); + if(alive[2]) chk2 = parsestatus("2GS"); + printf(" || L/4: "); + if(chk2 == -1){ + printf("%39s", "failed"); + }else printf("%s", bufo); + printf("\n"); + sprintf(&buff[24], "|| "); + val = keyval("ESW00"); + DBG("ESW00=%s", val); + if(!val) val = " "; + sprintf(&buff[27], "%5s ", val); + val = keyval("ESW01"); + if(!val) val = " "; + sprintf(&buff[33], "%5s ", val); + val = keyval("ESW10"); + if(!val) val = " "; + sprintf(&buff[39], "%5s ", val); + val = keyval("ESW11"); + if(!val) val = " "; + sprintf(&buff[45], "%5s ", val); + // end-switches + green("ESW00 ESW01 ESW10 ESW11 || ESW00 ESW01 ESW10 ESW11\n"); + printf("%s\n", buff); + for(int i = 1; i < 3; ++i){ + if(reset[i]) printf("RESET%d=1\n", i); + } +} + +void tty_getstatus(){ + FNAME(); + if(quiet) ttystatq(); + else ttystat(); +} + + +/** + * Show temperature of both MCU + * @return amount of successful calls + */ +int tty_showtemp(){ + char *val, buff[] = "xGT\n"; + const char *nm[3] = {NULL, "POL", "L4"}; + int ret = 0; + for(int i = 1; i < 3; ++i){ + if(!alive[i]){ + DBG("MCU %d didn't respond!", i); + continue; + } + buff[0] = '0' + (char)i; + if(tty_sendraw(buff)){ + val = keyval("TEMP"); + if(val){ + ++ret; + double t; + if(str2double(&t, val)){ + if(quiet){ + printf("%sTEMP=%g\n", nm[i], t/10.); + }else{ + green("MCU%d temperature:", i); + printf(" %g degC\n", t/10.); + } + } + } + } + } + return ret; +} + +/** + * get current motor position (if move or error return INT_MIN) + * + */ +int mot_getpos(int mcu, int motor){ + if(mcu < 1 || mcu > 2){ + WARNX(_("Bad MCU number")); + return INT_MIN; + } + if(motor < 0 || motor > 1){ + WARNX(_("Bad motor number")); + return INT_MIN; + } + return motpos[mcu][motor]; +} + +/** + * get motor endswitches status + * @return -1 if error or intermediate position, 0 - on zero's esw, 1 - on end's esw + */ +int mot_getesw(int mcu, int motor){ + if(mcu < 1 || mcu > 2){ + WARNX(_("Bad MCU number")); + return -1; + } + if(motor < 0 || motor > 1){ + WARNX(_("Bad motor number")); + return -1; + } + return endswitches[mcu][motor]; +} + +/** + * test connection (1,2 -> ALIVE) + * and get positions + * @return 1 if none of MCU found, 0 if at least 1 found + */ +int handshake(){ + char buff[32], *val; + int mcu, motor; + FNAME(); + for(mcu = 1; mcu < 3; ++ mcu){ + // check if MCU alive + sprintf(buff, "%d", mcu); + int notresp = 1; + // make HANDSHAKE_TRIES tries + for(int tr = 0; tr < HANDSHAKE_TRIES; ++tr){ + if(tty_sendraw(buff) && 0 == strcmp(buf, "ALIVE\n")){ + notresp = 0; + break; + } + } + if(notresp){ + WARNX(_("MCU %d not response!"), mcu); + continue; + } + alive[mcu] = 1; + sprintf(buff, "%dGS", mcu); + if(tty_sendraw(buff)){ + // check reboot states + if(strstr(buf, "RESET")){ + reset[mcu] = 1; + WARNX(_("MCU %d had reset state!"), mcu); + }else + reset[mcu] = 0; + for(motor = 0; motor < 2; ++motor){ + /*sprintf(buff, "MOTOR%d", motor); + val = keyval(buff); + if(!val || strcmp(val, "SLEEP")){ + motpos[mcu][motor] = INT_MIN; + continue; + }*/ + sprintf(buff, "POS%d", motor); + val = keyval(buff); + DBG("----%s=%s", buff, val); + motpos[mcu][motor] = val ? atoi(val) : INT_MIN; + DBG("MOTPOS[%d][%d] = %d", mcu, motor, motpos[mcu][motor]); + // end-switches + sprintf(buff, "ESW%d0", motor); + val = keyval(buff); + if(!val || strcmp(val, "HALL")){ + sprintf(buff, "ESW%d1", motor); + val = keyval(buff); + if(!val || strcmp(val, "HALL")){ + endswitches[mcu][motor] = -1; + }else + endswitches[mcu][motor] = 1; + }else endswitches[mcu][motor] = 0; + DBG("ENDSWITCHES[%d][%d] = %d", mcu, motor, endswitches[mcu][motor]); + } + }else{ + motpos[mcu][0] = INT_MIN; + motpos[mcu][1] = INT_MIN; + } + } + if(alive[1] == 0 && alive[2] == 0) return 1; + return 0; +} + +/** + * @brief tty_stopall - send commands to stop all motors + * @return 0 if all OK, else return amount of motors failed to stop + */ +int tty_stopall(){ + int ret = 4; + if(alive[1]){ + if(SEND_ALLOK == tty_sendcmd("1M0S")) --ret; + if(SEND_ALLOK == tty_sendcmd("1M1S")) --ret; + } + if(alive[2]){ + if(SEND_ALLOK == tty_sendcmd("2M0S")) --ret; + if(SEND_ALLOK == tty_sendcmd("2M1S")) --ret; + } + return ret; +} + +/** + * @brief init_motors - init all motors simultaneously (if they need to) + * @return 0 if all OK, or Nmcu*10+motnum for problem motor + */ +int init_motors(){ +#define RETVAL() (Nmcu*10+motnum) + int Nmcu, motnum, needinit = 0; + for(Nmcu = 1; Nmcu < 3; ++Nmcu){ + for(motnum = 0; motnum < 2; ++motnum){ + // check position + int pos = motpos[Nmcu][motnum]; + if(pos == INT_MIN) continue; // communication error on handshake + if(pos < 0) needinit = 1; + }} + if(!needinit) return 0; + DBG("Need to init, start!"); + for(Nmcu = 1; Nmcu < 3; ++Nmcu){ + for(motnum = 0; motnum < 2; ++motnum){ + int pos = motpos[Nmcu][motnum]; + if(pos >= 0) continue; + // check if we are on zero endswitch + int esw = mot_getesw(Nmcu, motnum); + if(esw == 0){ // move a little from zero esw + sprintf(buf, "%dM%dM100", Nmcu, motnum); + if(SEND_ERR == tty_sendcmd(buf)){ + WARNX(_("Can't move from endswitch")); + return RETVAL(); + } + tty_wait(); + } + sprintf(buf, "%dM%dM-40000", Nmcu, motnum); + if(SEND_ALLOK != tty_sendcmd(buf)){ + WARNX(_("Can't move to endwsitch 0")); + return RETVAL(); + } + }} + tty_wait(); + handshake(); + for(Nmcu = 1; Nmcu < 3; ++Nmcu){ + for(motnum = 0; motnum < 2; ++motnum){ + int curpos = mot_getpos(Nmcu, motnum); + if(curpos){ + WARNX(_("Can't return to zero")); + return RETVAL(); + } + }} + return 0; +#undef RETVAL +} + diff --git a/MMPP_control/new/tty_procs.h b/MMPP_control/new/tty_procs.h new file mode 100644 index 0000000..6c26f0f --- /dev/null +++ b/MMPP_control/new/tty_procs.h @@ -0,0 +1,54 @@ +/* + * tty_procs.h + * + * Copyright 2018 Edward V. Emelianov + * + * 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 TTY_PROCS_H__ +#define TTY_PROCS_H__ + +#include + +// amount of tries to establish handshake +#define HANDSHAKE_TRIES (10) +// steps per full revolution for both rotation stages (1 - polaroid, 2 - waveplate) +#define STEPSREV1 (36000) +#define STEPSREV2 (28800) + +typedef enum{ + SEND_ERR, + SEND_ALLOK, + SEND_ESWITCH, + SEND_OTHER +} ttysend_status; + +int tty_tryopen(char *dev, int spd); +void tty_close(); +char* tty_sendraw(char *string); +int tty_wait(); +ttysend_status tty_sendcmd(char *cmd); +int tty_showtemp(); +int tty_stopall(); +void tty_getstatus(); +int handshake(); +int mot_getpos(int mcu, int motor); +int mot_getesw(int mcu, int motor); +int init_motors(); + +#endif // TTY_PROCS_H__ diff --git a/STM32/steppers/MMPP_steppers.config b/STM32/steppers/MMPP_steppers.config new file mode 100644 index 0000000..2296bb8 --- /dev/null +++ b/STM32/steppers/MMPP_steppers.config @@ -0,0 +1,5 @@ +#define FAMILY F0 +#define MCU F030x4 +#define STM32F0 1 +#define STM32F030x4 1 +#define EBUG 1 diff --git a/STM32/steppers/MMPP_steppers.creator b/STM32/steppers/MMPP_steppers.creator new file mode 100644 index 0000000..e94cbbd --- /dev/null +++ b/STM32/steppers/MMPP_steppers.creator @@ -0,0 +1 @@ +[General] diff --git a/STM32/steppers/MMPP_steppers.creator.user b/STM32/steppers/MMPP_steppers.creator.user new file mode 100644 index 0000000..8970a8d --- /dev/null +++ b/STM32/steppers/MMPP_steppers.creator.user @@ -0,0 +1,178 @@ + + + + + + EnvironmentId + {cf63021e-ef53-49b0-b03b-2f2570cdf3b6} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + KOI8-R + false + 4 + false + 80 + true + true + 1 + true + false + 1 + true + true + 0 + 8 + true + 2 + true + false + true + false + + + + ProjectExplorer.Project.PluginSettings + + + true + false + Builtin.TidyAndClazy + + /home/eddy/Docs/SAO/Zeiss-1000/Simple_photometer/STM32/steppers/MMPP_steppers.creator + + + + true + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {91347f2c-5221-46a7-80b1-0a054ca02f79} + 0 + 0 + 0 + + /home/eddy/Docs/SAO/Zeiss-1000/Simple_photometer/STM32/steppers + + + + all + + false + + + false + true + Сборка + + GenericProjectManager.GenericMakeStep + + 1 + Сборка + + ProjectExplorer.BuildSteps.Build + + + + + clean + + false + + + false + true + Сборка + + GenericProjectManager.GenericMakeStep + + 1 + Очистка + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + По умолчанию + По умолчанию + GenericProjectManager.GenericBuildConfiguration + + 1 + + + 0 + Установка + + ProjectExplorer.BuildSteps.Deploy + + 1 + Конфигурация установки + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + false + false + 1000 + + true + 2 + + + Особая программа + + ProjectExplorer.CustomExecutableRunConfiguration + + 3768 + false + true + false + false + true + + + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 20 + + + Version + 20 + + diff --git a/STM32/steppers/MMPP_steppers.files b/STM32/steppers/MMPP_steppers.files new file mode 100644 index 0000000..87bb7dd --- /dev/null +++ b/STM32/steppers/MMPP_steppers.files @@ -0,0 +1,13 @@ +Makefile +Readme.md +adc.c +adc.h +flash.c +flash.h +main.c +proto.c +proto.h +steppers.c +steppers.h +usart.c +usart.h diff --git a/STM32/steppers/MMPP_steppers.includes b/STM32/steppers/MMPP_steppers.includes new file mode 100644 index 0000000..9efdf88 --- /dev/null +++ b/STM32/steppers/MMPP_steppers.includes @@ -0,0 +1,3 @@ +. +../inc/F0 +../inc/cm