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