mirror of
https://github.com/eddyem/eddys_snippets.git
synced 2026-06-21 10:56:20 +03:00
restructurization
This commit is contained in:
102
_deprecated/Binary_search/errors.c
Normal file
102
_deprecated/Binary_search/errors.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "errors.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static const abortcodes AC[] = {
|
||||
//while read l; do N=$(echo $l|awk '{print $1 $2}'); R=$(echo $l|awk '{$1=$2=""; print substr($0,3)}'|sed 's/\.//'); echo -e "{0x$N, \"$R\"},"; done < codes.b
|
||||
{0x05030000, "Toggle bit not alternated"},
|
||||
{0x05040000, "SDO protocol timed out"},
|
||||
{0x05040001, "Client/server command specifier not valid or unknown"},
|
||||
{0x05040002, "Invalid block size (block mode only)"},
|
||||
{0x05040003, "Invalid sequence number (block mode only)"},
|
||||
{0x05040004, "CRC error (block mode only)"},
|
||||
{0x05040005, "Out of memory"},
|
||||
{0x06010000, "Unsupported access to an object"},
|
||||
{0x06010001, "Attempt to read a write only object"},
|
||||
{0x06010002, "Attempt to write a read only object"},
|
||||
{0x06020000, "Object does not exist in the object dictionary"},
|
||||
{0x06040041, "Object cannot be mapped to the PDO"},
|
||||
{0x06040042, "The number and length of the objects to be mapped would exceed PDO length"},
|
||||
{0x06040043, "General parameter incompatibility reason"},
|
||||
{0x06040047, "General internal incompatibility in the device"},
|
||||
{0x06060000, "Access failed due to a hardware error"},
|
||||
{0x06070010, "Data type does not match; length of service parameter does not match"},
|
||||
{0x06070012, "Data type does not match; length of service parameter too high"},
|
||||
{0x06070013, "Data type does not match; length of service parameter too low"},
|
||||
{0x06090011, "Sub-index does not exist"},
|
||||
{0x06090030, "Value range of parameter exceeded (only for write access)"},
|
||||
{0x06090031, "Value of parameter written too high"},
|
||||
{0x06090032, "Value of parameter written too low"},
|
||||
{0x06090036, "Maximum value is less than minimum value"},
|
||||
{0x08000000, "General error"},
|
||||
{0x08000020, "Data cannot be transferred or stored to the application"},
|
||||
{0x08000021, "Data cannot be transferred or stored to the application because of local control"},
|
||||
{0x08000022, "Data cannot be transferred or stored to the application because of the present device state"},
|
||||
{0x08000023, "Object dictionary dynamic generation fails or no object dictionary is present"},
|
||||
};
|
||||
|
||||
const int ACmax = sizeof(AC)/sizeof(abortcodes) - 1;
|
||||
|
||||
const char *ACtext(uint32_t abortcode, int *n){
|
||||
int idx = ACmax/2, min_ = 0, max_ = ACmax, newidx = 0, iter=0;
|
||||
do{
|
||||
++iter;
|
||||
uint32_t c = AC[idx].code;
|
||||
printf("idx=%d, min=%d, max=%d\n", idx, min_, max_);
|
||||
if(c == abortcode){
|
||||
if(n) *n = iter;
|
||||
return AC[idx].errmsg;
|
||||
}else if(c > abortcode){
|
||||
newidx = (idx + min_)/2;
|
||||
max_ = idx;
|
||||
|
||||
}else{
|
||||
newidx = (idx + max_ + 1)/2;
|
||||
min_ = idx;
|
||||
}
|
||||
if(newidx == idx || min_ < 0 || max_ > ACmax){
|
||||
if(n) *n = 0;
|
||||
return NULL;
|
||||
}
|
||||
idx = newidx;
|
||||
}while(1);
|
||||
}
|
||||
|
||||
void check_all(){
|
||||
int iter = 0, N;
|
||||
for(int i = 0; i <= ACmax; ++i){
|
||||
printf("code 0x%X: %s\n\n", AC[i].code, ACtext(AC[i].code, &N));
|
||||
iter += N;
|
||||
}
|
||||
printf("\n\ntotal: %d iterations, mean: %d, (%d for direct lookup)\n", iter, iter/(ACmax+1), (ACmax+1)/2);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
if(argc != 2){
|
||||
check_all();
|
||||
return 0;
|
||||
}
|
||||
uint32_t x = (uint32_t)strtol(argv[1], NULL, 0);
|
||||
printf("x=0x%X\n", x);
|
||||
const char *text = ACtext(x, NULL);
|
||||
if(text) printf("%s\n", text);
|
||||
else printf("Unknown error code\n");
|
||||
return 0;
|
||||
}
|
||||
28
_deprecated/Binary_search/errors.h
Normal file
28
_deprecated/Binary_search/errors.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef ERRORS_H__
|
||||
#define ERRORS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct{
|
||||
uint32_t code;
|
||||
char *errmsg;
|
||||
} abortcodes;
|
||||
|
||||
#endif // ERRORS_H__
|
||||
22
_deprecated/FITS/Makefile
Normal file
22
_deprecated/FITS/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
PROGRAM = fitsread
|
||||
LDFLAGS = -lcfitsio
|
||||
SRCS = $(wildcard *.c)
|
||||
CC = gcc
|
||||
DEFINES = -D_XOPEN_SOURCE=1111 -DEBUG
|
||||
CXX = gcc
|
||||
CFLAGS = -Wall -Werror -Wextra $(DEFINES)
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
all : $(PROGRAM)
|
||||
$(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)
|
||||
1
_deprecated/FITS/README
Normal file
1
_deprecated/FITS/README
Normal file
@@ -0,0 +1 @@
|
||||
Simple routines for FITS reading/writing
|
||||
161
_deprecated/FITS/fits.c
Normal file
161
_deprecated/FITS/fits.c
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* fits.c - cfitsio routines
|
||||
*
|
||||
* Copyright 2015 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include <fitsio.h>
|
||||
|
||||
#include "fits.h"
|
||||
#include "usefull_macros.h"
|
||||
|
||||
static int fitsstatus = 0;
|
||||
|
||||
/*
|
||||
* Macros for error processing when working with cfitsio functions
|
||||
*/
|
||||
#define TRYFITS(f, ...) \
|
||||
do{ fitsstatus = 0; \
|
||||
f(__VA_ARGS__, &fitsstatus); \
|
||||
if(fitsstatus){ \
|
||||
fits_report_error(stderr, fitsstatus); \
|
||||
return FALSE;} \
|
||||
}while(0)
|
||||
#define FITSFUN(f, ...) \
|
||||
do{ fitsstatus = 0; \
|
||||
int ret = f(__VA_ARGS__, &fitsstatus); \
|
||||
if(ret || fitsstatus) \
|
||||
fits_report_error(stderr, fitsstatus); \
|
||||
}while(0)
|
||||
#define WRITEKEY(...) \
|
||||
do{ fitsstatus = 0; \
|
||||
fits_write_key(__VA_ARGS__, &fitsstatus); \
|
||||
if(status) fits_report_error(stderr, status);\
|
||||
}while(0)
|
||||
|
||||
void imfree(IMAGE **img){
|
||||
size_t i, sz = (*img)->keynum;
|
||||
char **list = (*img)->keylist;
|
||||
for(i = 0; i < sz; ++i) FREE(list[i]);
|
||||
FREE((*img)->keylist);
|
||||
FREE((*img)->data);
|
||||
FREE(*img);
|
||||
}
|
||||
|
||||
bool readFITS(char *filename, IMAGE **fits){
|
||||
FNAME();
|
||||
bool ret = TRUE;
|
||||
fitsfile *fp;
|
||||
// float nullval = 0., imBits, bZero = 0., bScale = 1.;
|
||||
int i, j, hdunum, hdutype, nkeys, keypos;
|
||||
int naxis;
|
||||
long naxes[2];
|
||||
char card[FLEN_CARD];
|
||||
IMAGE *img = MALLOC(IMAGE, 1);
|
||||
|
||||
TRYFITS(fits_open_file, &fp, filename, READONLY);
|
||||
FITSFUN(fits_get_num_hdus, fp, &hdunum);
|
||||
if(hdunum < 1){
|
||||
WARNX(_("Can't read HDU"));
|
||||
ret = FALSE;
|
||||
goto returning;
|
||||
}
|
||||
// get image dimensions
|
||||
TRYFITS(fits_get_img_param, fp, 2, &img->dtype, &naxis, naxes);
|
||||
if(naxis > 2){
|
||||
WARNX(_("Images with > 2 dimensions are not supported"));
|
||||
ret = FALSE;
|
||||
goto returning;
|
||||
}
|
||||
img->width = naxes[0];
|
||||
img->height = naxes[1];
|
||||
DBG("got image %ldx%ld pix, bitpix=%d", naxes[0], naxes[1], img->dtype);
|
||||
// loop through all HDUs
|
||||
for(i = 1; !(fits_movabs_hdu(fp, i, &hdutype, &fitsstatus)); ++i){
|
||||
TRYFITS(fits_get_hdrpos, fp, &nkeys, &keypos);
|
||||
int oldnkeys = img->keynum;
|
||||
img->keynum += nkeys;
|
||||
if(!(img->keylist = realloc(img->keylist, sizeof(char*) * img->keynum))){
|
||||
ERR(_("Can't realloc"));
|
||||
}
|
||||
char **currec = &(img->keylist[oldnkeys]);
|
||||
DBG("HDU # %d of %d keys", i, nkeys);
|
||||
for(j = 1; j <= nkeys; ++j){
|
||||
FITSFUN(fits_read_record, fp, j, card);
|
||||
if(!fitsstatus){
|
||||
*currec = MALLOC(char, FLEN_CARD);
|
||||
memcpy(*currec, card, FLEN_CARD);
|
||||
DBG("key %d: %s", oldnkeys + j, *currec);
|
||||
++currec;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(fitsstatus == END_OF_FILE){
|
||||
fitsstatus = 0;
|
||||
}else{
|
||||
fits_report_error(stderr, fitsstatus);
|
||||
ret = FALSE;
|
||||
goto returning;
|
||||
}
|
||||
size_t sz = naxes[0] * naxes[1];
|
||||
img->data = MALLOC(double, sz);
|
||||
int stat = 0;
|
||||
TRYFITS(fits_read_img, fp, TDOUBLE, 1, sz, NULL, img->data, &stat);
|
||||
if(stat) WARNX(_("Found %d pixels with undefined value"), stat);
|
||||
DBG("ready");
|
||||
|
||||
returning:
|
||||
FITSFUN(fits_close_file, fp);
|
||||
if(!ret){
|
||||
imfree(&img);
|
||||
}
|
||||
if(fits) *fits = img;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool writeFITS(char *filename, IMAGE *fits){
|
||||
int w = fits->width, h = fits->height;
|
||||
long naxes[2] = {w, h};
|
||||
size_t sz = w * h, keys = fits->keynum;
|
||||
fitsfile *fp;
|
||||
|
||||
TRYFITS(fits_create_file, &fp, filename);
|
||||
TRYFITS(fits_create_img, fp, fits->dtype, 2, naxes);
|
||||
|
||||
if(keys){ // there's keys
|
||||
size_t i;
|
||||
char **records = fits->keylist;
|
||||
for(i = 0; i < keys; ++i){
|
||||
char *rec = records[i];
|
||||
if(strncmp(rec, "SIMPLE", 6) == 0 || strncmp(rec, "EXTEND", 6) == 0) // key "file does conform ..."
|
||||
continue;
|
||||
else if(strncmp(rec, "COMMENT", 7) == 0) // comment of obligatory key in FITS head
|
||||
continue;
|
||||
else if(strncmp(rec, "NAXIS", 5) == 0 || strncmp(rec, "BITPIX", 6) == 0) // NAXIS, NAXISxxx, BITPIX
|
||||
continue;
|
||||
FITSFUN(fits_write_record, fp, rec);
|
||||
}
|
||||
}
|
||||
FITSFUN(fits_write_record, fp, "COMMENT modified by simple test routine");
|
||||
|
||||
TRYFITS(fits_write_img, fp, TDOUBLE, 1, sz, fits->data);
|
||||
TRYFITS(fits_close_file, fp);
|
||||
return TRUE;
|
||||
}
|
||||
42
_deprecated/FITS/fits.h
Normal file
42
_deprecated/FITS/fits.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* fits.h
|
||||
*
|
||||
* Copyright 2015 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
||||
*
|
||||
* 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 __FITS_H__
|
||||
#define __FITS_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
typedef struct{
|
||||
int width; // width
|
||||
int height; // height
|
||||
int dtype; // data type
|
||||
double *data; // picture data
|
||||
char **keylist; // list of options for each key
|
||||
size_t keynum; // full number of keys (size of *keylist)
|
||||
} IMAGE;
|
||||
|
||||
void imfree(IMAGE **ima);
|
||||
bool readFITS(char *filename, IMAGE **fits);
|
||||
bool writeFITS(char *filename, IMAGE *fits);
|
||||
|
||||
#endif // __FITS_H__
|
||||
44
_deprecated/FITS/main.c
Normal file
44
_deprecated/FITS/main.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* main.c
|
||||
*
|
||||
* Copyright 2015 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
||||
*
|
||||
* 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 "usefull_macros.h"
|
||||
#include "fits.h"
|
||||
|
||||
void signals(int signo){
|
||||
exit(signo);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
IMAGE *fits;
|
||||
//size_t i, s;
|
||||
initial_setup();
|
||||
if(argc != 3) ERRX("Usage: %s infile outfile", argv[0]);
|
||||
readFITS(argv[1], &fits);
|
||||
DBG("ima: %dx%d", fits->width, fits->height);
|
||||
//s = fits->width * fits->height;
|
||||
//double *img = fits->data;
|
||||
//for(i = 0; i < s; ++i) *img++ /= 2.;
|
||||
unlink(argv[2]);
|
||||
writeFITS(argv[2], fits);
|
||||
imfree(&fits);
|
||||
return 0;
|
||||
}
|
||||
327
_deprecated/FITS/usefull_macros.c
Normal file
327
_deprecated/FITS/usefull_macros.c
Normal file
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* usefull_macros.h - a set of usefull functions: memory, color etc
|
||||
*
|
||||
* 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 "usefull_macros.h"
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/******************************************************************************\
|
||||
* Coloured terminal
|
||||
\******************************************************************************/
|
||||
int globErr = 0; // errno for WARN/ERR
|
||||
|
||||
// pointers to coloured output printf
|
||||
int (*red)(const char *fmt, ...);
|
||||
int (*green)(const char *fmt, ...);
|
||||
int (*_WARN)(const char *fmt, ...);
|
||||
|
||||
/*
|
||||
* format red / green messages
|
||||
* name: r_pr_, g_pr_
|
||||
* @param fmt ... - printf-like format
|
||||
* @return number of printed symbols
|
||||
*/
|
||||
int r_pr_(const char *fmt, ...){
|
||||
va_list ar; int i;
|
||||
printf(RED);
|
||||
va_start(ar, fmt);
|
||||
i = vprintf(fmt, ar);
|
||||
va_end(ar);
|
||||
printf(OLDCOLOR);
|
||||
return i;
|
||||
}
|
||||
int g_pr_(const char *fmt, ...){
|
||||
va_list ar; int i;
|
||||
printf(GREEN);
|
||||
va_start(ar, fmt);
|
||||
i = vprintf(fmt, ar);
|
||||
va_end(ar);
|
||||
printf(OLDCOLOR);
|
||||
return i;
|
||||
}
|
||||
/*
|
||||
* print red error/warning messages (if output is a tty)
|
||||
* @param fmt ... - printf-like format
|
||||
* @return number of printed symbols
|
||||
*/
|
||||
int r_WARN(const char *fmt, ...){
|
||||
va_list ar; int i = 1;
|
||||
fprintf(stderr, RED);
|
||||
va_start(ar, fmt);
|
||||
if(globErr){
|
||||
errno = globErr;
|
||||
vwarn(fmt, ar);
|
||||
errno = 0;
|
||||
globErr = 0;
|
||||
}else
|
||||
i = vfprintf(stderr, fmt, ar);
|
||||
va_end(ar);
|
||||
i++;
|
||||
fprintf(stderr, OLDCOLOR "\n");
|
||||
return i;
|
||||
}
|
||||
|
||||
static const char stars[] = "****************************************";
|
||||
/*
|
||||
* notty variants of coloured printf
|
||||
* name: s_WARN, r_pr_notty
|
||||
* @param fmt ... - printf-like format
|
||||
* @return number of printed symbols
|
||||
*/
|
||||
int s_WARN(const char *fmt, ...){
|
||||
va_list ar; int i;
|
||||
i = fprintf(stderr, "\n%s\n", stars);
|
||||
va_start(ar, fmt);
|
||||
if(globErr){
|
||||
errno = globErr;
|
||||
vwarn(fmt, ar);
|
||||
errno = 0;
|
||||
globErr = 0;
|
||||
}else
|
||||
i = +vfprintf(stderr, fmt, ar);
|
||||
va_end(ar);
|
||||
i += fprintf(stderr, "\n%s\n", stars);
|
||||
i += fprintf(stderr, "\n");
|
||||
return i;
|
||||
}
|
||||
int r_pr_notty(const char *fmt, ...){
|
||||
va_list ar; int i;
|
||||
i = printf("\n%s\n", stars);
|
||||
va_start(ar, fmt);
|
||||
i += vprintf(fmt, ar);
|
||||
va_end(ar);
|
||||
i += printf("\n%s\n", stars);
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run this function in the beginning of main() to setup locale & coloured output
|
||||
*/
|
||||
void initial_setup(){
|
||||
// setup coloured output
|
||||
if(isatty(STDOUT_FILENO)){ // make color output in tty
|
||||
red = r_pr_; green = g_pr_;
|
||||
}else{ // no colors in case of pipe
|
||||
red = r_pr_notty; green = printf;
|
||||
}
|
||||
if(isatty(STDERR_FILENO)) _WARN = r_WARN;
|
||||
else _WARN = s_WARN;
|
||||
// Setup locale
|
||||
setlocale(LC_ALL, "");
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
#if defined GETTEXT_PACKAGE && defined LOCALEDIR
|
||||
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
|
||||
textdomain(GETTEXT_PACKAGE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************\
|
||||
* Memory
|
||||
\******************************************************************************/
|
||||
/*
|
||||
* safe memory allocation for macro ALLOC
|
||||
* @param N - number of elements to allocate
|
||||
* @param S - size of single element (typically sizeof)
|
||||
* @return pointer to allocated memory area
|
||||
*/
|
||||
void *my_alloc(size_t N, size_t S){
|
||||
void *p = calloc(N, S);
|
||||
if(!p) ERR("malloc");
|
||||
//assert(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mmap file to a memory area
|
||||
*
|
||||
* @param filename (i) - name of file to mmap
|
||||
* @return stuct with mmap'ed file or die
|
||||
*/
|
||||
mmapbuf *My_mmap(char *filename){
|
||||
int fd;
|
||||
char *ptr;
|
||||
size_t Mlen;
|
||||
struct stat statbuf;
|
||||
if(!filename) ERRX(_("No filename given!"));
|
||||
if((fd = open(filename, O_RDONLY)) < 0)
|
||||
ERR(_("Can't open %s for reading"), filename);
|
||||
if(fstat (fd, &statbuf) < 0)
|
||||
ERR(_("Can't stat %s"), filename);
|
||||
Mlen = statbuf.st_size;
|
||||
if((ptr = mmap (0, Mlen, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
|
||||
ERR(_("Mmap error for input"));
|
||||
if(close(fd)) ERR(_("Can't close mmap'ed file"));
|
||||
mmapbuf *ret = MALLOC(mmapbuf, 1);
|
||||
ret->data = ptr;
|
||||
ret->len = Mlen;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void My_munmap(mmapbuf *b){
|
||||
if(munmap(b->data, b->len))
|
||||
ERR(_("Can't munmap"));
|
||||
FREE(b);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************\
|
||||
* Terminal in no-echo mode
|
||||
\******************************************************************************/
|
||||
static struct termios oldt, newt; // terminal flags
|
||||
static int console_changed = 0;
|
||||
// run on exit:
|
||||
void restore_console(){
|
||||
if(console_changed)
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // return terminal to previous state
|
||||
console_changed = 0;
|
||||
}
|
||||
|
||||
// initial setup:
|
||||
void setup_con(){
|
||||
if(console_changed) return;
|
||||
tcgetattr(STDIN_FILENO, &oldt);
|
||||
newt = oldt;
|
||||
newt.c_lflag &= ~(ICANON | ECHO);
|
||||
if(tcsetattr(STDIN_FILENO, TCSANOW, &newt) < 0){
|
||||
WARN(_("Can't setup console"));
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
||||
signals(0); //quit?
|
||||
}
|
||||
console_changed = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read character from console without echo
|
||||
* @return char readed
|
||||
*/
|
||||
int read_console(){
|
||||
int rb;
|
||||
struct timeval tv;
|
||||
int retval;
|
||||
fd_set rfds;
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(STDIN_FILENO, &rfds);
|
||||
tv.tv_sec = 0; tv.tv_usec = 10000;
|
||||
retval = select(1, &rfds, NULL, NULL, &tv);
|
||||
if(!retval) rb = 0;
|
||||
else {
|
||||
if(FD_ISSET(STDIN_FILENO, &rfds)) rb = getchar();
|
||||
else rb = 0;
|
||||
}
|
||||
return rb;
|
||||
}
|
||||
|
||||
/**
|
||||
* getchar() without echo
|
||||
* wait until at least one character pressed
|
||||
* @return character readed
|
||||
*/
|
||||
int mygetchar(){ // getchar() without need of pressing ENTER
|
||||
int ret;
|
||||
do ret = read_console();
|
||||
while(ret == 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************\
|
||||
* TTY with select()
|
||||
\******************************************************************************/
|
||||
static struct termio oldtty, tty; // TTY flags
|
||||
static int comfd = -1; // TTY fd
|
||||
|
||||
// run on exit:
|
||||
void restore_tty(){
|
||||
if(comfd == -1) return;
|
||||
ioctl(comfd, TCSANOW, &oldtty ); // return TTY to previous state
|
||||
close(comfd);
|
||||
comfd = -1;
|
||||
}
|
||||
|
||||
#ifndef BAUD_RATE
|
||||
#define BAUD_RATE B9600
|
||||
#endif
|
||||
// init:
|
||||
void tty_init(char *comdev){
|
||||
DBG("\nOpen port...\n");
|
||||
if ((comfd = open(comdev,O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0){
|
||||
WARN("Can't use port %s\n",comdev);
|
||||
ioctl(comfd, TCSANOW, &oldtty); // return TTY to previous state
|
||||
close(comfd);
|
||||
signals(0); // quit?
|
||||
}
|
||||
DBG(" OK\nGet current settings... ");
|
||||
if(ioctl(comfd,TCGETA,&oldtty) < 0){ // Get settings
|
||||
WARN(_("Can't get settings"));
|
||||
signals(0);
|
||||
}
|
||||
tty = oldtty;
|
||||
tty.c_lflag = 0; // ~(ICANON | ECHO | ECHOE | ISIG)
|
||||
tty.c_oflag = 0;
|
||||
tty.c_cflag = BAUD_RATE|CS8|CREAD|CLOCAL; // 9.6k, 8N1, RW, ignore line ctrl
|
||||
tty.c_cc[VMIN] = 0; // non-canonical mode
|
||||
tty.c_cc[VTIME] = 5;
|
||||
if(ioctl(comfd,TCSETA,&tty) < 0){
|
||||
WARN(_("Can't set settings"));
|
||||
signals(0);
|
||||
}
|
||||
DBG(" 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(uint8_t *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; // wait for 50ms
|
||||
retval = select(comfd + 1, &rfds, NULL, NULL, &tv);
|
||||
if (!retval) return 0;
|
||||
if(FD_ISSET(comfd, &rfds)){
|
||||
if((L = read(comfd, buff, length)) < 1) return 0;
|
||||
}
|
||||
return (size_t)L;
|
||||
}
|
||||
|
||||
int write_tty(uint8_t *buff, size_t length){
|
||||
ssize_t L = write(comfd, buff, length);
|
||||
if((size_t)L != length){
|
||||
WARN("Write error!");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
124
_deprecated/FITS/usefull_macros.h
Normal file
124
_deprecated/FITS/usefull_macros.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* usefull_macros.h - a set of usefull macros: memory, color etc
|
||||
*
|
||||
* 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 __USEFULL_MACROS_H__
|
||||
#define __USEFULL_MACROS_H__
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <err.h>
|
||||
#include <locale.h>
|
||||
#if defined GETTEXT_PACKAGE && defined LOCALEDIR
|
||||
/*
|
||||
* GETTEXT
|
||||
*/
|
||||
#include <libintl.h>
|
||||
#define _(String) gettext(String)
|
||||
#define gettext_noop(String) String
|
||||
#define N_(String) gettext_noop(String)
|
||||
#else
|
||||
#define _(String) (String)
|
||||
#define N_(String) (String)
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <termios.h>
|
||||
#include <termio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// unused arguments with -Wall -Werror
|
||||
#define _U_ __attribute__((__unused__))
|
||||
|
||||
/*
|
||||
* Coloured messages output
|
||||
*/
|
||||
#define RED "\033[1;31;40m"
|
||||
#define GREEN "\033[1;32;40m"
|
||||
#define OLDCOLOR "\033[0;0;0m"
|
||||
|
||||
/*
|
||||
* ERROR/WARNING messages
|
||||
*/
|
||||
extern int globErr;
|
||||
extern void signals(int sig);
|
||||
#define ERR(...) do{globErr=errno; _WARN(__VA_ARGS__); signals(0);}while(0)
|
||||
#define ERRX(...) do{globErr=0; _WARN(__VA_ARGS__); signals(0);}while(0)
|
||||
#define WARN(...) do{globErr=errno; _WARN(__VA_ARGS__);}while(0)
|
||||
#define WARNX(...) do{globErr=0; _WARN(__VA_ARGS__);}while(0)
|
||||
|
||||
/*
|
||||
* print function name, debug messages
|
||||
* debug mode, -DEBUG
|
||||
*/
|
||||
#ifdef EBUG
|
||||
#define FNAME() fprintf(stderr, "\n%s (%s, line %d)\n", __func__, __FILE__, __LINE__)
|
||||
#define DBG(...) do{fprintf(stderr, "%s (%s, line %d): ", __func__, __FILE__, __LINE__); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n");} while(0)
|
||||
#else
|
||||
#define FNAME() do{}while(0)
|
||||
#define DBG(...) do{}while(0)
|
||||
#endif //EBUG
|
||||
|
||||
/*
|
||||
* Memory allocation
|
||||
*/
|
||||
#define ALLOC(type, var, size) type * var = ((type *)my_alloc(size, sizeof(type)))
|
||||
#define MALLOC(type, size) ((type *)my_alloc(size, sizeof(type)))
|
||||
#define FREE(ptr) do{free(ptr); ptr = NULL;}while(0)
|
||||
|
||||
double dtime();
|
||||
|
||||
// functions for color output in tty & no-color in pipes
|
||||
extern int (*red)(const char *fmt, ...);
|
||||
extern int (*_WARN)(const char *fmt, ...);
|
||||
extern int (*green)(const char *fmt, ...);
|
||||
void * my_alloc(size_t N, size_t S);
|
||||
void initial_setup();
|
||||
|
||||
// mmap file
|
||||
typedef struct{
|
||||
char *data;
|
||||
size_t len;
|
||||
} mmapbuf;
|
||||
mmapbuf *My_mmap(char *filename);
|
||||
void My_munmap(mmapbuf *b);
|
||||
|
||||
void restore_console();
|
||||
void setup_con();
|
||||
int read_console();
|
||||
int mygetchar();
|
||||
|
||||
void restore_tty();
|
||||
void tty_init(char *comdev);
|
||||
size_t read_tty(uint8_t *buff, size_t length);
|
||||
int write_tty(uint8_t *buff, size_t length);
|
||||
|
||||
#endif // __USEFULL_MACROS_H__
|
||||
674
_deprecated/GLUT_window/LICENSE
Normal file
674
_deprecated/GLUT_window/LICENSE
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
45
_deprecated/GLUT_window/Makefile
Normal file
45
_deprecated/GLUT_window/Makefile
Normal file
@@ -0,0 +1,45 @@
|
||||
# run `make DEF=...` to add extra defines
|
||||
PROGRAM := opengl
|
||||
LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all
|
||||
LDFLAGS += -lusefull_macros -lflycapture-c -lflycapture -L/usr/local/lib
|
||||
LDFLAGS += -lm -pthread -lglut -lGL -lX11 -lGLEW
|
||||
SRCS := $(wildcard *.c)
|
||||
DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111
|
||||
OBJDIR := mk
|
||||
CFLAGS += -O2 -Wno-trampolines -std=gnu99
|
||||
CFLAGS += -I/usr/local/include/flycapture
|
||||
OBJS := $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.o))
|
||||
DEPS := $(OBJS:.o=.d)
|
||||
CC = gcc
|
||||
#CXX = g++
|
||||
|
||||
|
||||
all : $(OBJDIR) $(PROGRAM)
|
||||
|
||||
debug: CFLAGS += -DEBUG -Werror -Wall -Wextra
|
||||
debug: all
|
||||
|
||||
$(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)
|
||||
|
||||
.PHONY: clean xclean
|
||||
1
_deprecated/GLUT_window/Readme
Normal file
1
_deprecated/GLUT_window/Readme
Normal file
@@ -0,0 +1 @@
|
||||
imagewiew with GLUT
|
||||
4
_deprecated/GLUT_window/Readme.md
Normal file
4
_deprecated/GLUT_window/Readme.md
Normal file
@@ -0,0 +1,4 @@
|
||||
Simplest tool for Grasshopper3 control
|
||||
======================================
|
||||
|
||||
(pre-pre-alpha version)
|
||||
58
_deprecated/GLUT_window/aux.c
Normal file
58
_deprecated/GLUT_window/aux.c
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is part of the opengl project.
|
||||
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/limits.h> // PATH_MAX
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "aux.h"
|
||||
#include "cmdlnopts.h"
|
||||
|
||||
// print messages for given verbose_level
|
||||
int verbose(verblevel levl, const char *fmt, ...){
|
||||
if((unsigned)verbose_level < levl) return 0;
|
||||
va_list ar; int i;
|
||||
va_start(ar, fmt);
|
||||
i = vprintf(fmt, ar);
|
||||
va_end(ar);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check_filename - find file name "outfile_xxxx.suff" NOT THREAD-SAFE!
|
||||
* @param outfile - file name prefix
|
||||
* @param suff - file name suffix
|
||||
* @return NULL or next free file name like "outfile_0010.suff" (don't free() it!)
|
||||
*/
|
||||
char *check_filename(char *outfile, char *suff){
|
||||
static char buff[PATH_MAX];
|
||||
struct stat filestat;
|
||||
int num;
|
||||
for(num = 1; num < 10000; num++){
|
||||
if(snprintf(buff, PATH_MAX, "%s_%04d.%s", outfile, num, suff) < 1)
|
||||
return NULL;
|
||||
if(stat(buff, &filestat)) // OK, file not exists
|
||||
return buff;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
35
_deprecated/GLUT_window/aux.h
Normal file
35
_deprecated/GLUT_window/aux.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of the opengl project.
|
||||
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef AUX_H__
|
||||
#define AUX_H__
|
||||
|
||||
typedef enum{
|
||||
VERB_NONE,
|
||||
VERB_MESG,
|
||||
VERB_DEBUG
|
||||
} verblevel;
|
||||
|
||||
int verbose(verblevel levl, const char *fmt, ...);
|
||||
char *check_filename(char *outfile, char *suff);
|
||||
|
||||
#define VMESG(...) do{verbose(VERB_MESG, __VA_ARGS__);}while(0)
|
||||
#define VDBG(...) do{verbose(VERB_DEBUG, __VA_ARGS__);}while(0)
|
||||
|
||||
#endif // AUX_H__
|
||||
97
_deprecated/GLUT_window/cmdlnopts.c
Normal file
97
_deprecated/GLUT_window/cmdlnopts.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* This file is part of the opengl project.
|
||||
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <usefull_macros.h>
|
||||
|
||||
#include "cmdlnopts.h"
|
||||
|
||||
static int help;
|
||||
|
||||
/*
|
||||
* here are global parameters initialisation
|
||||
*/
|
||||
int verbose_level;
|
||||
glob_pars G;
|
||||
|
||||
// default PID filename:
|
||||
#define DEFAULT_PIDFILE "/tmp/opengl.pid"
|
||||
|
||||
// DEFAULTS
|
||||
// default global parameters
|
||||
static glob_pars const Gdefault = {
|
||||
.device = NULL,
|
||||
.pidfile = DEFAULT_PIDFILE,
|
||||
.exptime = NAN,
|
||||
.gain = NAN
|
||||
};
|
||||
|
||||
/*
|
||||
* Define command line options by filling structure:
|
||||
* name has_arg flag val type argptr help
|
||||
*/
|
||||
static myoption cmdlnopts[] = {
|
||||
// common options
|
||||
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), _("show this help")},
|
||||
{"device", NEED_ARG, NULL, 'd', arg_string, APTR(&G.device), _("camera device name")},
|
||||
{"pidfile", NEED_ARG, NULL, 'P', arg_string, APTR(&G.pidfile), _("pidfile (default: " DEFAULT_PIDFILE ")")},
|
||||
{"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&verbose_level), _("verbose level (each 'v' increases it)")},
|
||||
{"camno", NEED_ARG, NULL, 'n', arg_int, APTR(&G.camno), _("camera number (if many connected)")},
|
||||
{"exptime", NEED_ARG, NULL, 'x', arg_float, APTR(&G.exptime), _("exposure time (ms)")},
|
||||
{"gain", NEED_ARG, NULL, 'g', arg_float, APTR(&G.gain), _("gain value (dB)")},
|
||||
{"display", NO_ARGS, NULL, 'D', arg_int, APTR(&G.showimage), _("display captured image")},
|
||||
{"nimages", NEED_ARG, NULL, 'N', arg_int, APTR(&G.nimages), _("number of images to capture")},
|
||||
{"png", NO_ARGS, NULL, 'p', arg_int, APTR(&G.save_png), _("save png too")},
|
||||
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){
|
||||
int i;
|
||||
void *ptr;
|
||||
ptr = memcpy(&G, &Gdefault, sizeof(G)); assert(ptr);
|
||||
size_t hlen = 1024;
|
||||
char helpstring[1024], *hptr = helpstring;
|
||||
snprintf(hptr, hlen, "Usage: %%s [args] [filename prefix]\n\n\tWhere args are:\n");
|
||||
// format of help: "Usage: progname [args]\n"
|
||||
change_helpstring(helpstring);
|
||||
// parse arguments
|
||||
parseargs(&argc, &argv, cmdlnopts);
|
||||
if(help) showhelp(-1, cmdlnopts);
|
||||
if(argc > 0){
|
||||
G.rest_pars_num = argc;
|
||||
G.rest_pars = MALLOC(char *, argc);
|
||||
for (i = 0; i < argc; i++){
|
||||
DBG("Found free parameter %s", argv[i]);
|
||||
G.rest_pars[i] = strdup(argv[i]);
|
||||
}
|
||||
}
|
||||
return &G;
|
||||
}
|
||||
|
||||
45
_deprecated/GLUT_window/cmdlnopts.h
Normal file
45
_deprecated/GLUT_window/cmdlnopts.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of the opengl project.
|
||||
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
#ifndef CMDLNOPTS_H__
|
||||
#define CMDLNOPTS_H__
|
||||
|
||||
/*
|
||||
* here are some typedef's for global data
|
||||
*/
|
||||
typedef struct{
|
||||
char *device; // camera device name
|
||||
char *pidfile; // name of PID file
|
||||
int camno; // number of camera to work with
|
||||
float exptime; // exposition time
|
||||
float gain; // gain value
|
||||
int showimage; // display last captured image in OpenGL screen
|
||||
int nimages; // number of images to capture
|
||||
int save_png; // save png file
|
||||
int rest_pars_num; // number of rest parameters
|
||||
char** rest_pars; // the rest parameters: array of char*
|
||||
} glob_pars;
|
||||
|
||||
|
||||
glob_pars *parse_args(int argc, char **argv);
|
||||
extern glob_pars G;
|
||||
extern int verbose_level;
|
||||
|
||||
#endif // CMDLNOPTS_H__
|
||||
204
_deprecated/GLUT_window/events.c
Normal file
204
_deprecated/GLUT_window/events.c
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* events.c
|
||||
*
|
||||
* Copyright 2015 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
||||
*
|
||||
* 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 <GL/glew.h>
|
||||
#include <GL/glut.h>
|
||||
#include <GL/glext.h>
|
||||
#include <GL/freeglut.h>
|
||||
#include <usefull_macros.h>
|
||||
|
||||
#include "events.h"
|
||||
#include "imageview.h"
|
||||
|
||||
/**
|
||||
* manage pressed keys & menu items
|
||||
*/
|
||||
static void processKeybrd(unsigned char key, int mod, _U_ int x, _U_ int y){
|
||||
windowData *win = getWin();
|
||||
if(!win) return;
|
||||
DBG("key=%d (%c), mod=%d", key, key, mod);
|
||||
if(mod == GLUT_ACTIVE_CTRL){ // 'a' == 1, 'b' == 2...
|
||||
key += 'a'-1;
|
||||
DBG("CTRL+%c", key);
|
||||
switch(key){
|
||||
case 'r': // roll colorfun
|
||||
win->winevt |= WINEVT_ROLLCOLORFUN;
|
||||
break;
|
||||
case 's': // save image
|
||||
win->winevt |= WINEVT_SAVEIMAGE;
|
||||
break;
|
||||
case 'q': // exit case 17:
|
||||
//signals(1);
|
||||
win->killthread = 1;
|
||||
break;
|
||||
}
|
||||
}else if(mod == GLUT_ACTIVE_ALT){
|
||||
; // ALT
|
||||
}else switch(key){
|
||||
case '0': // return zoom to 1 & image to 0
|
||||
win->zoom = 1;
|
||||
win->x = 0; win->y = 0;
|
||||
break;
|
||||
case 27: // esc - kill
|
||||
win->killthread = 1;
|
||||
break;
|
||||
case 'c': // capture in pause mode
|
||||
DBG("winevt = %d", win->winevt);
|
||||
if(win->winevt & WINEVT_PAUSE)
|
||||
win->winevt |= WINEVT_GETIMAGE;
|
||||
break;
|
||||
case 'l': // flip left-right
|
||||
win->flip ^= WIN_FLIP_LR;
|
||||
break;
|
||||
case 'p': // pause capturing
|
||||
win->winevt ^= WINEVT_PAUSE;
|
||||
break;
|
||||
case 'u': // flip up-down
|
||||
win->flip ^= WIN_FLIP_UD;
|
||||
break;
|
||||
case 'Z': // zoom+
|
||||
win->zoom *= 1.1f;
|
||||
calc_win_props(NULL, NULL);
|
||||
break;
|
||||
case 'z': // zoom-
|
||||
win->zoom /= 1.1f;
|
||||
calc_win_props(NULL, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Process keyboard
|
||||
*/
|
||||
void keyPressed(unsigned char key, int x, int y){
|
||||
int mod = glutGetModifiers();
|
||||
//mod: GLUT_ACTIVE_SHIFT, GLUT_ACTIVE_CTRL, GLUT_ACTIVE_ALT; result is their sum
|
||||
DBG("Key pressed. mod=%d, keycode=%d (%c), point=(%d,%d)\n", mod, key, key, x,y);
|
||||
processKeybrd(key, mod, x, y);
|
||||
}
|
||||
/*
|
||||
void keySpPressed(_U_ int key, _U_ int x, _U_ int y){
|
||||
// int mod = glutGetModifiers();
|
||||
DBG("Sp. key pressed. mod=%d, keycode=%d, point=(%d,%d)\n", glutGetModifiers(), key, x,y);
|
||||
}*/
|
||||
|
||||
static int oldx, oldy; // coordinates when mouse was pressed
|
||||
static int movingwin = 0; // ==1 when user moves image by middle button
|
||||
|
||||
void mousePressed(int key, int state, int x, int y){
|
||||
// key: GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON
|
||||
// state: GLUT_UP, GLUT_DOWN
|
||||
int mod = glutGetModifiers();
|
||||
windowData *win = getWin();
|
||||
if(!win) return;
|
||||
if(state == GLUT_DOWN){
|
||||
oldx = x; oldy = y;
|
||||
float X,Y, Zoom = win->zoom;
|
||||
conv_mouse_to_image_coords(x,y,&X,&Y,win);
|
||||
DBG("press in (%d, %d) == (%f, %f) on image; mod == %d", x,y,X,Y, mod);
|
||||
if(key == GLUT_LEFT_BUTTON){
|
||||
DBG("win->x=%g, win->y=%g", win->x, win->y);
|
||||
win->x += Zoom * (win->w/2.f - (float)x);
|
||||
win->y -= Zoom * (win->h/2.f - (float)y);
|
||||
}else if(key == GLUT_MIDDLE_BUTTON) movingwin = 1;
|
||||
else if(key == 3){ // wheel UP
|
||||
if(mod == 0) win->y += 10.f*win->zoom; // nothing pressed - scroll up
|
||||
else if(mod == GLUT_ACTIVE_SHIFT) win->x -= 10.f*Zoom; // shift pressed - scroll left
|
||||
else if(mod == GLUT_ACTIVE_CTRL) win->zoom *= 1.1f; // ctrl+wheel up == zoom+
|
||||
}else if(key == 4){ // wheel DOWN
|
||||
if(mod == 0) win->y -= 10.f*win->zoom; // nothing pressed - scroll down
|
||||
else if(mod == GLUT_ACTIVE_SHIFT) win->x += 10.f*Zoom; // shift pressed - scroll right
|
||||
else if(mod == GLUT_ACTIVE_CTRL) win->zoom /= 1.1f; // ctrl+wheel down == zoom-
|
||||
}
|
||||
calc_win_props(NULL, NULL);
|
||||
}else{
|
||||
movingwin = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void mouseMove(int x, int y){
|
||||
windowData *win = getWin();
|
||||
if(!win) return;
|
||||
if(movingwin){
|
||||
float X, Y, nx, ny, w2, h2;
|
||||
float a = win->Daspect;
|
||||
X = (x - oldx) * a; Y = (y - oldy) * a;
|
||||
nx = win->x + X;
|
||||
ny = win->y - Y;
|
||||
w2 = win->image->w / 2.f * win->zoom;
|
||||
h2 = win->image->h / 2.f * win->zoom;
|
||||
if(nx < w2 && nx > -w2)
|
||||
win->x = nx;
|
||||
if(ny < h2 && ny > -h2)
|
||||
win->y = ny;
|
||||
oldx = x;
|
||||
oldy = y;
|
||||
calc_win_props(NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void menuEvents(int opt){
|
||||
DBG("opt: %d, key: %d (%c), mod: %d", opt, opt&0xff, opt&0xff, opt>>8);
|
||||
// just work as shortcut pressed
|
||||
processKeybrd((unsigned char)(opt&0xff), opt>>8, 0, 0);
|
||||
} // GLUT_ACTIVE_CTRL
|
||||
|
||||
typedef struct{
|
||||
char *name; // menu entry name
|
||||
int symbol; // shortcut symbol + rolled modifier
|
||||
} menuentry;
|
||||
|
||||
#define CTRL_K(key) ((key-'a'+1) | (GLUT_ACTIVE_CTRL<<8))
|
||||
#define SHIFT_K(key) (key | (GLUT_ACTIVE_SHIFT<<8))
|
||||
#define ALT_K(key) (key | (GLUT_ACTIVE_ALT<<8))
|
||||
static const menuentry entries[] = {
|
||||
{"Capture in pause mode (c)", 'c'},
|
||||
{"Flip image LR (l)", 'l'},
|
||||
{"Flip image UD (u)", 'u'},
|
||||
{"Make a pause/continue (p)", 'p'},
|
||||
{"Restore zoom (0)", '0'},
|
||||
{"Roll colorfun (ctrl+r)", CTRL_K('r')},
|
||||
{"Save image (ctrl+s)", CTRL_K('s')},
|
||||
{"Close this window (ESC)", 27},
|
||||
{"Quit (ctrl+q)", CTRL_K('q')},
|
||||
{NULL, 0}
|
||||
};
|
||||
#undef CTRL_K
|
||||
#undef SHIFT_K
|
||||
#undef ALT_K
|
||||
|
||||
void createMenu(){
|
||||
FNAME();
|
||||
windowData *win = getWin();
|
||||
if(!win) return;
|
||||
DBG("menu for win ID %d", win->ID);
|
||||
//glutSetWindow(win->ID);
|
||||
if(win->menu) glutDestroyMenu(win->menu);
|
||||
win->menu = glutCreateMenu(menuEvents);
|
||||
const menuentry *ptr = entries;
|
||||
while(ptr->name){
|
||||
glutAddMenuEntry(ptr->name, ptr->symbol);
|
||||
++ptr;
|
||||
}
|
||||
DBG("created menu %d\n", win->menu);
|
||||
glutAttachMenu(GLUT_RIGHT_BUTTON);
|
||||
}
|
||||
|
||||
39
_deprecated/GLUT_window/events.h
Normal file
39
_deprecated/GLUT_window/events.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* events.h
|
||||
*
|
||||
* Copyright 2015 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
||||
*
|
||||
* 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 __EVENTS_H__
|
||||
#define __EVENTS_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern float Z; // ËÏÏÒÄÉÎÁÔÁ Z (zoom)
|
||||
|
||||
void keyPressed(unsigned char key, int x, int y);
|
||||
//void keySpPressed(int key, int x, int y);
|
||||
void mousePressed(int key, int state, int x, int y);
|
||||
void mouseMove(int x, int y);
|
||||
void createMenu();
|
||||
void menuEvents(int opt);
|
||||
//void mouseWheel(int button, int dir, int x, int y);
|
||||
|
||||
#endif // __EVENTS_H__
|
||||
136
_deprecated/GLUT_window/image_functions.c
Normal file
136
_deprecated/GLUT_window/image_functions.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* This file is part of the opengl project.
|
||||
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <fitsio.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <usefull_macros.h>
|
||||
|
||||
#include "cmdlnopts.h"
|
||||
#include "image_functions.h"
|
||||
|
||||
/**
|
||||
* Convert gray (unsigned short) into RGB components (GLubyte)
|
||||
* @argument L - gray level (0..1)
|
||||
* @argument rgb - rgb array (GLubyte [3])
|
||||
*/
|
||||
void gray2rgb(double gray, GLubyte *rgb){
|
||||
int i = gray * 4.;
|
||||
double x = (gray - (double)i * .25) * 4.;
|
||||
GLubyte r = 0, g = 0, b = 0;
|
||||
//r = g = b = (gray < 1) ? gray * 256 : 255;
|
||||
switch(i){
|
||||
case 0:
|
||||
g = (GLubyte)(255. * x);
|
||||
b = 255;
|
||||
break;
|
||||
case 1:
|
||||
g = 255;
|
||||
b = (GLubyte)(255. * (1. - x));
|
||||
break;
|
||||
case 2:
|
||||
r = (GLubyte)(255. * x);
|
||||
g = 255;
|
||||
break;
|
||||
case 3:
|
||||
r = 255;
|
||||
g = (GLubyte)(255. * (1. - x));
|
||||
break;
|
||||
default:
|
||||
r = 255;
|
||||
}
|
||||
*rgb++ = r;
|
||||
*rgb++ = g;
|
||||
*rgb = b;
|
||||
}
|
||||
|
||||
static colorfn_type ft = COLORFN_LINEAR;
|
||||
|
||||
// all colorfun's should get argument in [0, 1] and return in [0, 1]
|
||||
static double linfun(double arg){ return arg; } // bung for PREVIEW_LINEAR
|
||||
static double logfun(double arg){ return log(1.+arg) / 0.6931472; } // for PREVIEW_LOG [log_2(x+1)]
|
||||
static double (*colorfun)(double) = linfun; // default function to convert color
|
||||
|
||||
colorfn_type get_colorfun(){return ft;}
|
||||
|
||||
void change_colorfun(colorfn_type f){
|
||||
DBG("New colorfn: %d", f);
|
||||
switch (f){
|
||||
case COLORFN_LOG:
|
||||
colorfun = logfun;
|
||||
ft = COLORFN_LOG;
|
||||
break;
|
||||
case COLORFN_SQRT:
|
||||
colorfun = sqrt;
|
||||
ft = COLORFN_SQRT;
|
||||
break;
|
||||
default: // linear
|
||||
colorfun = linfun;
|
||||
ft = COLORFN_LINEAR;
|
||||
}
|
||||
}
|
||||
|
||||
// cycle switch between palettes
|
||||
void roll_colorfun(){
|
||||
FNAME();
|
||||
colorfn_type t = ++ft;
|
||||
if(t == COLORFN_MAX) t = COLORFN_LINEAR;
|
||||
change_colorfun(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief equalize - hystogram equalization
|
||||
* @param ori (io) - input/output data
|
||||
* @param w,h - image width and height
|
||||
* @return data allocated here
|
||||
*/
|
||||
static uint8_t *equalize(uint16_t *ori, int w, int h){
|
||||
uint8_t *retn = MALLOC(uint8_t, w*h);
|
||||
double orig_hysto[65536] = {0.}; // original hystogram
|
||||
uint8_t eq_levls[65536] = {0}; // levels to convert: newpix = eq_levls[oldpix]
|
||||
int s = w*h;
|
||||
for(int i = 0; i < s; ++i) ++orig_hysto[ori[i]];
|
||||
double part = (double)(s + 1)/ 256., N = 0.;
|
||||
for(int i = 0; i < 65536; ++i){
|
||||
N += orig_hysto[i];
|
||||
eq_levls[i] = (uint8_t)(N/part);
|
||||
//printf("N=%g, orig_hysto=%g, eq_levls[%d]=%d\n", N, orig_hysto[i], i, eq_levls[i]);
|
||||
}
|
||||
//exit(1);
|
||||
|
||||
for(int i = 0; i < s; ++i){
|
||||
retn[i] = eq_levls[ori[i]];
|
||||
}
|
||||
return retn;
|
||||
}
|
||||
|
||||
void change_displayed_image(windowData *win, IMG *img){
|
||||
if(!win || !win->image) return;
|
||||
rawimage *im = win->image;
|
||||
//DBG("imh=%d, imw=%d, ch=%u, cw=%u", im->h, im->w, img->w, img->h);
|
||||
pthread_mutex_lock(&win->mutex);
|
||||
int w = img->w, h = img->h, s = w*h;
|
||||
uint8_t *newima = equalize(img->data, w, h);
|
||||
GLubyte *dst = im->rawdata;
|
||||
for(int i = 0; i < s; ++i, dst += 3){
|
||||
gray2rgb(colorfun(newima[i] / 256.), dst);
|
||||
}
|
||||
FREE(newima);
|
||||
win->image->changed = 1;
|
||||
pthread_mutex_unlock(&win->mutex);
|
||||
}
|
||||
47
_deprecated/GLUT_window/image_functions.h
Normal file
47
_deprecated/GLUT_window/image_functions.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of the opengl project.
|
||||
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef IMAGE_FUNCTIONS__
|
||||
#define IMAGE_FUNCTIONS__
|
||||
|
||||
#include <GL/glut.h>
|
||||
#include "imageview.h"
|
||||
|
||||
// functions for converting grayscale value into colour
|
||||
typedef enum{
|
||||
COLORFN_LINEAR, // linear
|
||||
COLORFN_LOG, // ln
|
||||
COLORFN_SQRT, // sqrt
|
||||
COLORFN_MAX // end of list
|
||||
} colorfn_type;
|
||||
|
||||
typedef struct{
|
||||
uint16_t *data;
|
||||
int w;
|
||||
int h;
|
||||
} IMG;
|
||||
|
||||
void change_displayed_image(windowData *win, IMG *convertedImage);
|
||||
|
||||
void gray2rgb(double gray, GLubyte *rgb);
|
||||
colorfn_type get_colorfun();
|
||||
void change_colorfun(colorfn_type f);
|
||||
void roll_colorfun();
|
||||
|
||||
#endif // IMAGE_FUNCTIONS__
|
||||
353
_deprecated/GLUT_window/imageview.c
Normal file
353
_deprecated/GLUT_window/imageview.c
Normal file
@@ -0,0 +1,353 @@
|
||||
// bmpview.c
|
||||
//
|
||||
// Copyright 2010 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.
|
||||
//-lglut
|
||||
|
||||
#include <X11/Xlib.h> // XInitThreads();
|
||||
//#include <GL/glew.h>
|
||||
#include <GL/glut.h>
|
||||
#include <GL/glext.h>
|
||||
#include <GL/freeglut.h>
|
||||
#include <math.h> // roundf(), log(), sqrt()
|
||||
#include <pthread.h>
|
||||
#include <usefull_macros.h>
|
||||
|
||||
#include "imageview.h"
|
||||
|
||||
static windowData *win = NULL; // main window
|
||||
static pthread_t GLUTthread; // main GLUT thread
|
||||
|
||||
static int initialized = 0; // ==1 if GLUT is initialized; ==0 after clear_GL_context
|
||||
|
||||
static void createWindow();
|
||||
static void RedrawWindow();
|
||||
static void *Redraw(_U_ void *arg);
|
||||
static void Resize(int width, int height);
|
||||
|
||||
/**
|
||||
* calculate window properties on creating & resizing
|
||||
*/
|
||||
void calc_win_props(GLfloat *Wortho, GLfloat *Hortho){
|
||||
if(!win || ! win->image) return;
|
||||
float a, A, w, h, W, H;
|
||||
float Zoom = win->zoom;
|
||||
w = (float)win->image->w / 2.f;
|
||||
h = (float)win->image->h / 2.f;
|
||||
W = (float)win->w;
|
||||
H =(float) win->h;
|
||||
A = W / H;
|
||||
a = w / h;
|
||||
if(A > a){ // now W & H are parameters for glOrtho
|
||||
win->Daspect = (float)h / H * 2.f;
|
||||
W = h * A; H = h;
|
||||
}else{
|
||||
win->Daspect = (float)w / W * 2.f;
|
||||
H = w / A; W = w;
|
||||
}
|
||||
if(Wortho) *Wortho = W;
|
||||
if(Hortho) *Hortho = H;
|
||||
// calculate coordinates of center
|
||||
win->x0 = W/Zoom - w + win->x / Zoom;
|
||||
win->y0 = H/Zoom + h - win->y / Zoom;
|
||||
}
|
||||
|
||||
/**
|
||||
* create window & run main loop
|
||||
*/
|
||||
static void createWindow(){
|
||||
FNAME();
|
||||
DBG("ini=%d, win %s", initialized, win ? "yes" : "no");
|
||||
if(!initialized) return;
|
||||
if(!win) return;
|
||||
int w = win->w, h = win->h;
|
||||
DBG("create window with title %s", win->title);
|
||||
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
|
||||
glutInitWindowSize(w, h);
|
||||
|
||||
win->ID = glutCreateWindow(win->title);
|
||||
//glewInit();
|
||||
DBG("created GL_ID=%d", win->ID);
|
||||
glGenTextures(1, &(win->Tex));
|
||||
calc_win_props(NULL, NULL);
|
||||
win->zoom = 1. / win->Daspect;
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, win->Tex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, win->image->w, win->image->h, 0,
|
||||
GL_RGB, GL_UNSIGNED_BYTE, win->image->rawdata);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
createMenu();
|
||||
DBG("Window opened");
|
||||
glutReshapeFunc(Resize);
|
||||
glutDisplayFunc(RedrawWindow);
|
||||
glutKeyboardFunc(keyPressed);
|
||||
//glutSpecialFunc(keySpPressed);
|
||||
//glutMouseWheelFunc(mouseWheel);
|
||||
glutMouseFunc(mousePressed);
|
||||
glutMotionFunc(mouseMove);
|
||||
//glutIdleFunc(glutPostRedisplay);
|
||||
glutIdleFunc(RedrawWindow);
|
||||
//pthread_create(&GLUTthread, NULL, &Redraw, NULL);
|
||||
}
|
||||
|
||||
int killwindow(){
|
||||
FNAME();
|
||||
if(!win) return 0;
|
||||
if(!win->killthread){
|
||||
// say changed thread to die
|
||||
win->killthread = 1;
|
||||
}
|
||||
pthread_mutex_lock(&win->mutex);
|
||||
//glutSetWindow(win->ID); // obviously set window (for closing from menu)
|
||||
DBG("wait for changed thread");
|
||||
pthread_join(win->thread, NULL); // wait while thread dies
|
||||
if(win->menu) glutDestroyMenu(win->menu);
|
||||
glutDestroyWindow(win->ID);
|
||||
DBG("destroy menu, wundow & texture %d", win->Tex);
|
||||
glDeleteTextures(1, &(win->Tex));
|
||||
//glFinish();
|
||||
windowData *old = win;
|
||||
win->ID = 0;
|
||||
win = NULL;
|
||||
DBG("free(rawdata)");
|
||||
FREE(old->image->rawdata);
|
||||
DBG("free(image)");
|
||||
FREE(old->image);
|
||||
pthread_mutex_unlock(&old->mutex);
|
||||
DBG("free(win)");
|
||||
FREE(old);
|
||||
DBG("return");
|
||||
return 1;
|
||||
}
|
||||
|
||||
void renderBitmapString(float x, float y, void *font, char *string, GLubyte *color){
|
||||
if(!initialized) return;
|
||||
char *c;
|
||||
int x1=x, W=0;
|
||||
for(c = string; *c; c++){
|
||||
W += glutBitmapWidth(font,*c);// + 1;
|
||||
}
|
||||
x1 -= W/2;
|
||||
glColor3ubv(color);
|
||||
glLoadIdentity();
|
||||
glTranslatef(0.,0., -150);
|
||||
//glTranslatef(x,y, -4000.);
|
||||
for (c = string; *c != '\0'; c++){
|
||||
glColor3ubv(color);
|
||||
glRasterPos2f(x1,y);
|
||||
glutBitmapCharacter(font, *c);
|
||||
//glutStrokeCharacter(GLUT_STROKE_ROMAN, *c);
|
||||
x1 = x1 + glutBitmapWidth(font,*c);// + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void RedrawWindow(){
|
||||
if(!initialized || !win) return;
|
||||
if(pthread_mutex_trylock(&win->mutex) != 0) return;
|
||||
GLfloat w = win->image->w, h = win->image->h;
|
||||
glClearColor(0.0, 0.0, 0.5, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glLoadIdentity();
|
||||
glTranslatef(win->x, win->y, 0.);
|
||||
glScalef(-win->zoom, -win->zoom, 1.);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, win->Tex);
|
||||
if(win->image->changed){
|
||||
DBG("Changed");
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, win->image->w, win->image->h,
|
||||
GL_RGB, GL_UNSIGNED_BYTE, win->image->rawdata);
|
||||
win->image->changed = 0;
|
||||
}
|
||||
|
||||
w /= 2.f; h /= 2.f;
|
||||
float lr = 1., ud = 1.; // flipping coefficients
|
||||
if(win->flip & WIN_FLIP_LR) lr = -1.;
|
||||
if(win->flip & WIN_FLIP_UD) ud = -1.;
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(1.0f, 1.0f); glVertex2f( -1.f*lr*w, ud*h ); // top right
|
||||
glTexCoord2f(1.0f, 0.0f); glVertex2f( -1.f*lr*w, -1.f*ud*h ); // bottom right
|
||||
glTexCoord2f(0.0f, 0.0f); glVertex2f(lr*w, -1.f*ud*h ); // bottom left
|
||||
glTexCoord2f(0.0f, 1.0f); glVertex2f(lr*w, ud*h ); // top left
|
||||
glEnd();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glFinish();
|
||||
glutSwapBuffers();
|
||||
pthread_mutex_unlock(&win->mutex);
|
||||
usleep(10000);
|
||||
}
|
||||
|
||||
/**
|
||||
* main freeGLUT loop
|
||||
* waits for global signals to create windows & make other actions
|
||||
*/
|
||||
static void *Redraw(_U_ void *arg){
|
||||
FNAME();
|
||||
createWindow();
|
||||
glutMainLoop();
|
||||
/* while(1){
|
||||
if(!initialized){
|
||||
DBG("!initialized -> exit thread");
|
||||
return NULL;
|
||||
}
|
||||
if(!win || win->killthread){
|
||||
DBG("Thread killed");
|
||||
return NULL;
|
||||
}
|
||||
if(win && win->ID > 0){
|
||||
//glutSetWindow(win->ID);
|
||||
glutPostRedisplay();
|
||||
//RedrawWindow();
|
||||
glutMainLoopEvent();
|
||||
usleep(10000);
|
||||
}
|
||||
}*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void Resize(int width, int height){
|
||||
if(!initialized) return;
|
||||
//int window = glutGetWindow();
|
||||
if(!win/* || !window*/) return;
|
||||
glutReshapeWindow(width, height);
|
||||
win->w = width;
|
||||
win->h = height;
|
||||
glViewport(0, 0, width, height);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
GLfloat W, H;
|
||||
calc_win_props(&W, &H);
|
||||
glOrtho(-W,W, -H,H, -1., 1.);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
/**
|
||||
* create new window, run thread & return pointer to its structure or NULL
|
||||
* asynchroneous call from outside
|
||||
* wait for window creating & return its data
|
||||
* @param title - header (copyed inside this function)
|
||||
* @param w,h - image size
|
||||
* @param rawdata - NULL (then the memory will be allocated here with size w x h)
|
||||
* or allocated outside data
|
||||
*/
|
||||
windowData *createGLwin(char *title, int w, int h, rawimage *rawdata){
|
||||
FNAME();
|
||||
if(!initialized) return NULL;
|
||||
if(win) killwindow();
|
||||
win = MALLOC(windowData, 1);
|
||||
rawimage *raw;
|
||||
if(rawdata){
|
||||
raw = rawdata;
|
||||
}else{
|
||||
raw = MALLOC(rawimage, 1);
|
||||
if(raw){
|
||||
raw->rawdata = MALLOC(GLubyte, w*h*3);
|
||||
raw->w = w;
|
||||
raw->h = h;
|
||||
raw->changed = 1;
|
||||
// raw->protected is zero automatically
|
||||
}
|
||||
}
|
||||
if(!raw || !raw->rawdata){
|
||||
free(raw);
|
||||
return NULL;
|
||||
}
|
||||
win->title = strdup(title);
|
||||
win->image = raw;
|
||||
if(pthread_mutex_init(&win->mutex, NULL)){
|
||||
WARN(_("Can't init mutex!"));
|
||||
killwindow();
|
||||
return NULL;
|
||||
}
|
||||
win->w = w;
|
||||
win->h = h;
|
||||
pthread_create(&GLUTthread, NULL, &Redraw, NULL);
|
||||
return win;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init freeGLUT
|
||||
*/
|
||||
void imageview_init(){
|
||||
FNAME();
|
||||
char *v[] = {"Sample window", NULL};
|
||||
int c = 1;
|
||||
static int glutnotinited = 1;
|
||||
if(initialized){
|
||||
WARNX(_("Already initialized!"));
|
||||
return;
|
||||
}
|
||||
if(glutnotinited){
|
||||
DBG("init");
|
||||
// XInitThreads(); // we need it for threaded windows
|
||||
glutInit(&c, v);
|
||||
glutnotinited = 0;
|
||||
}
|
||||
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all opened windows and terminate main GLUT thread
|
||||
*/
|
||||
void clear_GL_context(){
|
||||
FNAME();
|
||||
if(!initialized) return;
|
||||
initialized = 0;
|
||||
glutLeaveMainLoop();
|
||||
DBG("kill");
|
||||
killwindow();
|
||||
DBG("join");
|
||||
pthread_join(GLUTthread, NULL); // wait while main thread exits
|
||||
DBG("main GL thread cancelled");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Coordinates transformation from CS of drawingArea into CS of picture
|
||||
* x,y - pointer coordinates
|
||||
* X,Y - coordinates of appropriate point at picture
|
||||
*/
|
||||
void conv_mouse_to_image_coords(int x, int y,
|
||||
float *X, float *Y,
|
||||
windowData *window){
|
||||
float a = window->Daspect / window->zoom;
|
||||
*X = (float)x * a - window->x0;
|
||||
*Y = window->y0 - (float)y * a;
|
||||
}
|
||||
|
||||
void conv_image_to_mouse_coords(float X, float Y,
|
||||
int *x, int *y,
|
||||
windowData *window){
|
||||
float a = window->zoom / window->Daspect;
|
||||
*x = (int)roundf((X + window->x0) * a);
|
||||
*y = (int)roundf((window->y0 - Y) * a);
|
||||
}
|
||||
|
||||
|
||||
windowData *getWin(){
|
||||
return win;
|
||||
}
|
||||
88
_deprecated/GLUT_window/imageview.h
Normal file
88
_deprecated/GLUT_window/imageview.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* imageview.h
|
||||
*
|
||||
* Copyright 2015 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
||||
*
|
||||
* 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 __BMPVIEW_H__
|
||||
#define __BMPVIEW_H__
|
||||
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "events.h"
|
||||
|
||||
typedef struct{
|
||||
GLubyte *rawdata; // raw image data
|
||||
int w; // size of image
|
||||
int h;
|
||||
int changed; // == 1 if data was changed outside (to redraw)
|
||||
} rawimage;
|
||||
|
||||
// events from menu:
|
||||
// temporaly stop capture of regular sequence
|
||||
#define WINEVT_PAUSE (1<<0)
|
||||
// capture one image in pause mode
|
||||
#define WINEVT_GETIMAGE (1<<1)
|
||||
// save current image
|
||||
#define WINEVT_SAVEIMAGE (1<<2)
|
||||
// change color palette function
|
||||
#define WINEVT_ROLLCOLORFUN (1<<3)
|
||||
|
||||
// flip image
|
||||
#define WIN_FLIP_LR (1<<0)
|
||||
#define WIN_FLIP_UD (1<<1)
|
||||
|
||||
typedef struct{
|
||||
int ID; // identificator of OpenGL window
|
||||
char *title; // title of window
|
||||
GLuint Tex; // texture for image inside window
|
||||
rawimage *image; // raw image data
|
||||
int w; int h; // window size
|
||||
float x; float y; // image offset coordinates
|
||||
float x0; float y0; // center of window for coords conversion
|
||||
float zoom; // zoom aspect
|
||||
float Daspect; // aspect ratio between image & window sizes
|
||||
int menu; // window menu identifier
|
||||
uint32_t winevt; // window menu events
|
||||
uint8_t flip; // flipping settings
|
||||
pthread_t thread; // identificator of thread that changes window data
|
||||
pthread_mutex_t mutex;// mutex for operations with image
|
||||
int killthread; // flag for killing data changing thread & also signal that there's no threads
|
||||
} windowData;
|
||||
|
||||
typedef enum{
|
||||
INNER,
|
||||
OPENGL
|
||||
} winIdType;
|
||||
|
||||
void imageview_init();
|
||||
windowData *createGLwin(char *title, int w, int h, rawimage *rawdata);
|
||||
windowData *getWin();
|
||||
int killwindow();
|
||||
void renderBitmapString(float x, float y, void *font, char *string, GLubyte *color);
|
||||
void clear_GL_context();
|
||||
|
||||
void calc_win_props(GLfloat *Wortho, GLfloat *Hortho);
|
||||
|
||||
void conv_mouse_to_image_coords(int x, int y, float *X, float *Y, windowData *window);
|
||||
void conv_image_to_mouse_coords(float X, float Y, int *x, int *y, windowData *window);
|
||||
|
||||
#endif // __BMPVIEW_H__
|
||||
162
_deprecated/GLUT_window/opengl.c
Normal file
162
_deprecated/GLUT_window/opengl.c
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* This file is part of the opengl project.
|
||||
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <usefull_macros.h>
|
||||
|
||||
#include "aux.h"
|
||||
#include "cmdlnopts.h"
|
||||
#include "image_functions.h"
|
||||
#include "imageview.h"
|
||||
|
||||
void signals(int sig){
|
||||
if(sig){
|
||||
signal(sig, SIG_IGN);
|
||||
DBG("Get signal %d, quit.\n", sig);
|
||||
}
|
||||
putlog("Exit with status %d", sig);
|
||||
if(G.pidfile) // remove unnesessary PID file
|
||||
unlink(G.pidfile);
|
||||
exit(sig);
|
||||
}
|
||||
|
||||
// manage some menu/shortcut events
|
||||
static void winevt_manage(windowData *win, IMG *convertedImage){
|
||||
if(win->winevt & WINEVT_SAVEIMAGE){ // save image
|
||||
VDBG("Try to make screenshot");
|
||||
DBG("Try to make screenshot");
|
||||
//saveImages(convertedImage, "ScreenShot");
|
||||
win->winevt &= ~WINEVT_SAVEIMAGE;
|
||||
}
|
||||
if(win->winevt & WINEVT_ROLLCOLORFUN){
|
||||
roll_colorfun();
|
||||
win->winevt &= ~WINEVT_ROLLCOLORFUN;
|
||||
change_displayed_image(win, convertedImage);
|
||||
}
|
||||
}
|
||||
|
||||
// main thread to deal with image
|
||||
static void* image_thread(_U_ void *data){
|
||||
FNAME();
|
||||
IMG *img = (IMG*) data;
|
||||
while(1){
|
||||
windowData *win = getWin();
|
||||
if(!win){
|
||||
DBG("!win");
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
if(win->killthread){
|
||||
DBG("got killthread");
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
if(win->winevt) winevt_manage(win, img);
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
|
||||
static void modifyImg(IMG* ima){
|
||||
for(int x = 0; x < ima->w; ++x){
|
||||
uint16_t c = rand() & 0xffff;
|
||||
int y = rand() % ima->h;
|
||||
ima->data[x + y*ima->w] = c;
|
||||
ima->data[5 + x*ima->w] = 1000;
|
||||
ima->data[105 + x*ima->w] = 10000;
|
||||
ima->data[205 + x*ima->w] = 50000;
|
||||
ima->data[305 + x*ima->w] = 0xffff;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int ret = 0;
|
||||
initial_setup();
|
||||
char *self = strdup(argv[0]);
|
||||
parse_args(argc, argv);
|
||||
char *outfprefix = NULL;
|
||||
if(G.rest_pars_num){
|
||||
if(G.rest_pars_num != 1){
|
||||
WARNX("You should point only one free argument - filename prefix");
|
||||
signals(1);
|
||||
}else outfprefix = G.rest_pars[0];
|
||||
}
|
||||
check4running(self, G.pidfile);
|
||||
FREE(self);
|
||||
signal(SIGTERM, signals); // kill (-15) - quit
|
||||
signal(SIGHUP, SIG_IGN); // hup - ignore
|
||||
signal(SIGINT, signals); // ctrl+C - quit
|
||||
signal(SIGQUIT, signals); // ctrl+\ - quit
|
||||
signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z
|
||||
|
||||
windowData *mainwin = NULL;
|
||||
|
||||
if(!G.showimage && !outfprefix){ // not display image & not save it?
|
||||
ERRX("You should point file name or option `display image`");
|
||||
}
|
||||
if(G.showimage){
|
||||
imageview_init();
|
||||
}
|
||||
IMG convertedImage = {.h = 400, .w = 400};
|
||||
convertedImage.data = MALLOC(uint16_t, convertedImage.h * convertedImage.w);
|
||||
for(int i = 0; i < convertedImage.h * convertedImage.w; ++i) convertedImage.data[i] = 100;
|
||||
DBG("data[200*200]=%d", convertedImage.data[200*200]);
|
||||
if(G.showimage){
|
||||
if(!mainwin){
|
||||
DBG("Create window @ start");
|
||||
mainwin = createGLwin("Sample window", convertedImage.w, convertedImage.h, NULL);
|
||||
if(!mainwin){
|
||||
WARNX("Can't open OpenGL window, image preview will be inaccessible");
|
||||
}else
|
||||
pthread_create(&mainwin->thread, NULL, &image_thread, (void*)&convertedImage); //(void*)mainwin);
|
||||
}
|
||||
if((mainwin = getWin())){
|
||||
DBG("change image");
|
||||
if(mainwin->killthread) goto destr;
|
||||
modifyImg(&convertedImage);
|
||||
change_displayed_image(mainwin, &convertedImage);
|
||||
while((mainwin = getWin())){ // test paused state & grabbing custom frames
|
||||
if((mainwin->winevt & WINEVT_PAUSE) == 0) break;
|
||||
if(mainwin->winevt & WINEVT_GETIMAGE){
|
||||
mainwin->winevt &= ~WINEVT_GETIMAGE;
|
||||
modifyImg(&convertedImage);
|
||||
change_displayed_image(mainwin, &convertedImage);
|
||||
}
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
}
|
||||
if((mainwin = getWin())) mainwin->winevt |= WINEVT_PAUSE;
|
||||
destr:
|
||||
if(G.showimage){
|
||||
while((mainwin = getWin())){
|
||||
modifyImg(&convertedImage);
|
||||
change_displayed_image(mainwin, &convertedImage);
|
||||
if(mainwin->killthread) break;
|
||||
if(mainwin->winevt & WINEVT_GETIMAGE){
|
||||
mainwin->winevt &= ~WINEVT_GETIMAGE;
|
||||
modifyImg(&convertedImage);
|
||||
change_displayed_image(mainwin, &convertedImage);
|
||||
}
|
||||
}
|
||||
DBG("Close window");
|
||||
clear_GL_context();
|
||||
}
|
||||
signals(ret);
|
||||
return ret;
|
||||
}
|
||||
1
_deprecated/GLUT_window/opengl.cflags
Normal file
1
_deprecated/GLUT_window/opengl.cflags
Normal file
@@ -0,0 +1 @@
|
||||
-std=c17
|
||||
2
_deprecated/GLUT_window/opengl.config
Normal file
2
_deprecated/GLUT_window/opengl.config
Normal file
@@ -0,0 +1,2 @@
|
||||
// Add predefined macros for your project here. For example:
|
||||
// #define THE_ANSWER 42
|
||||
1
_deprecated/GLUT_window/opengl.creator
Normal file
1
_deprecated/GLUT_window/opengl.creator
Normal file
@@ -0,0 +1 @@
|
||||
[General]
|
||||
170
_deprecated/GLUT_window/opengl.creator.user
Normal file
170
_deprecated/GLUT_window/opengl.creator.user
Normal file
@@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 4.12.3, 2020-12-07T13:16:57. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
<value type="QByteArray">{cf63021e-ef53-49b0-b03b-2f2570cdf3b6}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="int">0</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||
<value type="QString" key="language">Cpp</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||
<value type="QString" key="language">QmlJS</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||
<value type="QByteArray" key="EditorConfiguration.Codec">KOI8-R</value>
|
||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">false</value>
|
||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">2</value>
|
||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">true</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"/>
|
||||
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
|
||||
<value type="QString" key="ClangCodeModel.WarningConfigId">Builtin.Questionable</value>
|
||||
<valuemap type="QVariantMap" key="ClangTools">
|
||||
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||
<value type="int" key="ClangTools.ParallelJobs">4</value>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{91347f2c-5221-46a7-80b1-0a054ca02f79}</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/tmp/g</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">false</value>
|
||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand"></value>
|
||||
<value type="bool" key="GenericProjectManager.GenericMakeStep.OverrideMakeflags">false</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">true</value>
|
||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand"></value>
|
||||
<value type="bool" key="GenericProjectManager.GenericMakeStep.OverrideMakeflags">false</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">По умолчанию</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
||||
<value type="QString" key="RunConfiguration.Arguments"></value>
|
||||
<value type="bool" key="RunConfiguration.Arguments.multi">false</value>
|
||||
<value type="QString" key="RunConfiguration.OverrideDebuggerStartup"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory"></value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default"></value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||
<value type="int">1</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>Version</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
</qtcreator>
|
||||
165
_deprecated/GLUT_window/opengl.creator.user.7bd84e3
Normal file
165
_deprecated/GLUT_window/opengl.creator.user.7bd84e3
Normal file
@@ -0,0 +1,165 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 4.10.1, 2020-03-30T18:57:01. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
<value type="QByteArray">{7bd84e39-ca37-46d3-be9d-99ebea85bc0d}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="int">0</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||
<value type="QString" key="language">Cpp</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||
<value type="QString" key="language">QmlJS</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||
<value type="QByteArray" key="EditorConfiguration.Codec">KOI8-R</value>
|
||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
|
||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">false</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"/>
|
||||
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{65a14f9e-e008-4c1b-89df-4eaa4774b6e3}</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Big/Data/Cameras/Grasshopper/My/src</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">false</value>
|
||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand"></value>
|
||||
<value type="bool" key="GenericProjectManager.GenericMakeStep.OverrideMakeflags">false</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">false</value>
|
||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand"></value>
|
||||
<value type="bool" key="GenericProjectManager.GenericMakeStep.OverrideMakeflags">false</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">По умолчанию</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">По умолчанию</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Конфигурация развёртывания</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Особая программа</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||
<value type="QString" key="RunConfiguration.Arguments"></value>
|
||||
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory"></value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default"></value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||
<value type="int">1</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>Version</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
</qtcreator>
|
||||
1
_deprecated/GLUT_window/opengl.cxxflags
Normal file
1
_deprecated/GLUT_window/opengl.cxxflags
Normal file
@@ -0,0 +1 @@
|
||||
-std=c++17
|
||||
12
_deprecated/GLUT_window/opengl.files
Normal file
12
_deprecated/GLUT_window/opengl.files
Normal file
@@ -0,0 +1,12 @@
|
||||
aux.c
|
||||
aux.h
|
||||
camera_functions.h
|
||||
cmdlnopts.c
|
||||
cmdlnopts.h
|
||||
events.c
|
||||
events.h
|
||||
opengl.c
|
||||
image_functions.c
|
||||
image_functions.h
|
||||
imageview.c
|
||||
imageview.h
|
||||
2
_deprecated/GLUT_window/opengl.includes
Normal file
2
_deprecated/GLUT_window/opengl.includes
Normal file
@@ -0,0 +1,2 @@
|
||||
.
|
||||
/usr/local/include/flycapture
|
||||
29
_deprecated/GPS/Makefile
Normal file
29
_deprecated/GPS/Makefile
Normal file
@@ -0,0 +1,29 @@
|
||||
PROGRAM = gpstest
|
||||
LDFLAGS = -lm
|
||||
SRCS = $(wildcard *.c)
|
||||
OBJDIR = mk
|
||||
CC = gcc
|
||||
DEFINES = -D_XOPEN_SOURCE=1001
|
||||
CFLAGS = -DEBUG -Wall -Werror -Wextra $(DEFINES)
|
||||
OBJS = $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.o))
|
||||
|
||||
all : $(OBJDIR) $(OBJS) $(PROGRAM)
|
||||
|
||||
$(PROGRAM) : $(OBJDIR) $(OBJS)
|
||||
$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -o $(PROGRAM)
|
||||
|
||||
$(OBJDIR):
|
||||
mkdir $(OBJDIR)
|
||||
|
||||
$(OBJDIR)/%.o: %.c
|
||||
@printf " CC $<\n"
|
||||
$(CC) $(LDFLAGS) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
# some addition dependencies
|
||||
#$(SRCS) : %.c : %.h $(INDEPENDENT_HEADERS)
|
||||
# @touch $@
|
||||
|
||||
clean:
|
||||
/bin/rm -rf $(OBJDIR)
|
||||
depend:
|
||||
$(CXX) -MM $(CXX.SRCS)
|
||||
1
_deprecated/GPS/README
Normal file
1
_deprecated/GPS/README
Normal file
@@ -0,0 +1 @@
|
||||
Small utility for working with GPS module NEO-6M
|
||||
93
_deprecated/GPS/cmdlnopts.c
Normal file
93
_deprecated/GPS/cmdlnopts.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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 "cmdlnopts.h"
|
||||
#include "usefull_macros.h"
|
||||
|
||||
/*
|
||||
* here are global parameters initialisation
|
||||
*/
|
||||
glob_pars G; // internal global parameters structure
|
||||
int help = 0; // whether to show help string
|
||||
|
||||
glob_pars Gdefault = {
|
||||
.devpath = "/dev/ttyUSB0"
|
||||
,.pollubx = 0
|
||||
,.pollinterval = 1.
|
||||
,.block_msg = {0,1,0,0,0,0} // all exept RMC are blocked by default
|
||||
,.polltmout = 10.
|
||||
,.stationary = 0
|
||||
,.gettimediff = 0
|
||||
,.meancoords = 0
|
||||
,.silent = 0
|
||||
,.date = 0
|
||||
};
|
||||
|
||||
/*
|
||||
* 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), N_("show this help")},
|
||||
/// "ÐÕÔØ Ë ÕÓÔÒÏÊÓÔ×Õ"
|
||||
{"device",1, NULL, 'd', arg_string, APTR(&G.devpath), N_("device path")},
|
||||
{"poll-udx", 0, NULL, 'p', arg_none, APTR(&G.pollubx), N_("poll UDX,00")},
|
||||
{"pollinterval",1,NULL, 'i', arg_double, APTR(&G.pollinterval),N_("polling interval")},
|
||||
{"no-rmc",0,&G.block_msg[GPRMC], 0, arg_none, NULL, N_("block RMC message")},
|
||||
{"gsv", 0, &G.block_msg[GPGSV], 1, arg_none, NULL, N_("process GSV message")},
|
||||
{"gsa", 0, &G.block_msg[GPGSA], 1, arg_none, NULL, N_("process GSA message")},
|
||||
{"gga", 0, &G.block_msg[GPGGA], 1, arg_none, NULL, N_("process GGA message")},
|
||||
{"gll", 0, &G.block_msg[GPGLL], 1, arg_none, NULL, N_("process GLL message")},
|
||||
{"vtg", 0, &G.block_msg[GPVTG], 1, arg_none, NULL, N_("process VTG message")},
|
||||
{"timeout", 1, NULL, 't', arg_double, APTR(&G.polltmout), N_("polling timeout")},
|
||||
{"stationary",0, NULL, 's', arg_int, APTR(&G.stationary),N_("configure as stationary")},
|
||||
{"timediff",0, NULL, 'T', arg_int, APTR(&G.gettimediff),N_("calculate mean time difference")},
|
||||
{"coords",0, NULL, 'C', arg_int, APTR(&G.meancoords),N_("calculate mean coordinates")},
|
||||
{"silent",0, NULL, 'S', arg_int, APTR(&G.silent), N_("don't write intermediate messages")},
|
||||
{"print-date",0,NULL, 'D', arg_int, APTR(&G.date), N_("print date in format MMDDhhmmCCYY.ss")},
|
||||
// ...
|
||||
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;
|
||||
memcpy(&G, &Gdefault, sizeof(G));
|
||||
/// "éÓÐÏÌØÚÏ×ÁÎÉÅ: %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;
|
||||
}
|
||||
|
||||
58
_deprecated/GPS/cmdlnopts.h
Normal file
58
_deprecated/GPS/cmdlnopts.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
// GSV, RMC, GSA, GGA, GLL, VTG, TXT
|
||||
extern char *GPmsgs[];
|
||||
typedef enum{
|
||||
GPGSV = 0,
|
||||
GPRMC,
|
||||
GPGSA,
|
||||
GPGGA,
|
||||
GPGLL,
|
||||
GPVTG,
|
||||
GPMAXMSG
|
||||
}GPmsg_type;
|
||||
|
||||
/*
|
||||
* here are some typedef's for global data
|
||||
*/
|
||||
typedef struct{
|
||||
char *devpath; // device path
|
||||
int pollubx; // flag of polling ubx00
|
||||
double pollinterval; // ubx00 polling interval (in seconds)
|
||||
int block_msg[GPMAXMSG]; // array of messages: 1-show, 0-block
|
||||
double polltmout; // polling timeout (program ends after this interval)
|
||||
int stationary; // configure as stationary
|
||||
int gettimediff; // calculate mean time difference
|
||||
int meancoords; // calculate mean coordinates
|
||||
int silent; // don't write intermediate messages
|
||||
int date; // print date for initial time setup
|
||||
}glob_pars;
|
||||
|
||||
glob_pars *parce_args(int argc, char **argv);
|
||||
|
||||
#endif // __CMDLNOPTS_H__
|
||||
140
_deprecated/GPS/daemon.c
Normal file
140
_deprecated/GPS/daemon.c
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* daemon.c - functions for running in background like a daemon
|
||||
*
|
||||
* 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 "daemon.h"
|
||||
#include <stdio.h> // printf, fopen, ...
|
||||
#include <unistd.h> // getpid
|
||||
#include <stdio.h> // perror
|
||||
#include <sys/types.h> // opendir
|
||||
#include <dirent.h> // opendir
|
||||
#include <sys/stat.h> // stat
|
||||
#include <fcntl.h> // fcntl
|
||||
#include <stdlib.h> // exit
|
||||
#include <string.h> // memset
|
||||
|
||||
/**
|
||||
* read process name from /proc/PID/cmdline
|
||||
* @param pid - PID of interesting process
|
||||
* @return filename or NULL if not found
|
||||
* don't use this function twice for different names without copying
|
||||
* its returning by strdup, because `name` contains in static array
|
||||
*/
|
||||
char *readname(pid_t pid){
|
||||
static char name[256];
|
||||
char *pp = name, byte, path[256];
|
||||
FILE *file;
|
||||
int cntr = 0;
|
||||
size_t sz;
|
||||
snprintf (path, 255, PROC_BASE "/%d/cmdline", pid);
|
||||
file = fopen(path, "r");
|
||||
if(!file) return NULL; // there's no such file
|
||||
do{ // read basename
|
||||
sz = fread(&byte, 1, 1, file);
|
||||
if(sz != 1) break;
|
||||
if(byte != '/') *pp++ = byte;
|
||||
else{
|
||||
pp = name;
|
||||
cntr = 0;
|
||||
}
|
||||
}while(byte && cntr++ < 255);
|
||||
name[cntr] = 0;
|
||||
fclose(file);
|
||||
return name;
|
||||
}
|
||||
|
||||
void iffound_default(pid_t pid){
|
||||
fprintf(stderr, "\nFound running process (pid=%d), exit.\n", pid);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* check wether there is a same running process
|
||||
* exit if there is a running process or error
|
||||
* Checking have 3 steps:
|
||||
* 1) lock executable file
|
||||
* 2) check pidfile (if you run a copy?)
|
||||
* 3) check /proc for executables with the same name (no/wrong pidfile)
|
||||
* @param argv - argument of main() or NULL for non-locking, call this function before getopt()
|
||||
* @param pidfilename - name of pidfile or NULL if none
|
||||
* @param iffound - action to run if file found or NULL for exit(0)
|
||||
*/
|
||||
void check4running(char **argv, char *pidfilename, void (*iffound)(pid_t pid)){
|
||||
DIR *dir;
|
||||
FILE *pidfile, *fself;
|
||||
struct dirent *de;
|
||||
struct stat s_buf;
|
||||
pid_t pid = 0, self;
|
||||
struct flock fl;
|
||||
char *name, *myname;
|
||||
if(!iffound) iffound = iffound_default;
|
||||
if(argv){ // block self
|
||||
fself = fopen(argv[0], "r"); // open self binary to lock
|
||||
memset(&fl, 0, sizeof(struct flock));
|
||||
fl.l_type = F_WRLCK;
|
||||
if(fcntl(fileno(fself), F_GETLK, &fl) == -1){ // check locking
|
||||
perror("fcntl");
|
||||
exit(1);
|
||||
}
|
||||
if(fl.l_type != F_UNLCK){ // file is locking - exit
|
||||
printf("Found locker, PID = %d!\n", fl.l_pid);
|
||||
exit(1);
|
||||
}
|
||||
fl.l_type = F_RDLCK;
|
||||
if(fcntl(fileno(fself), F_SETLKW, &fl) == -1){
|
||||
perror("fcntl");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
self = getpid(); // get self PID
|
||||
if(!(dir = opendir(PROC_BASE))){ // open /proc directory
|
||||
perror(PROC_BASE);
|
||||
exit(1);
|
||||
}
|
||||
if(!(name = readname(self))){ // error reading self name
|
||||
perror("Can't read self name");
|
||||
exit(1);
|
||||
}
|
||||
myname = strdup(name);
|
||||
if(pidfilename && stat(pidfilename, &s_buf) == 0){ // pidfile exists
|
||||
pidfile = fopen(pidfilename, "r");
|
||||
if(pidfile){
|
||||
if(fscanf(pidfile, "%d", &pid) > 0){ // read PID of (possibly) running process
|
||||
if((name = readname(pid)) && strncmp(name, myname, 255) == 0)
|
||||
iffound(pid);
|
||||
}
|
||||
fclose(pidfile);
|
||||
}
|
||||
}
|
||||
// There is no pidfile or it consists a wrong record
|
||||
while((de = readdir(dir))){ // scan /proc
|
||||
if(!(pid = (pid_t)atoi(de->d_name)) || pid == self) // pass non-PID files and self
|
||||
continue;
|
||||
if((name = readname(pid)) && strncmp(name, myname, 255) == 0)
|
||||
iffound(pid);
|
||||
}
|
||||
closedir(dir);
|
||||
if(pidfilename){
|
||||
pidfile = fopen(pidfilename, "w");
|
||||
fprintf(pidfile, "%d\n", self); // write self PID to pidfile
|
||||
fclose(pidfile);
|
||||
}
|
||||
free(myname);
|
||||
}
|
||||
28
_deprecated/GPS/daemon.h
Normal file
28
_deprecated/GPS/daemon.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* daemon.h
|
||||
*
|
||||
* Copyright 2015 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef PROC_BASE
|
||||
#define PROC_BASE "/proc"
|
||||
#endif
|
||||
|
||||
#include <unistd.h> // pid_t
|
||||
|
||||
void iffound_default(pid_t pid);
|
||||
void check4running(char **argv, char *pidfilename, void (*iffound)(pid_t pid));
|
||||
685
_deprecated/GPS/main.c
Normal file
685
_deprecated/GPS/main.c
Normal file
@@ -0,0 +1,685 @@
|
||||
/*
|
||||
* main.c
|
||||
*
|
||||
* Copyright 2015 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
||||
*
|
||||
* 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 "usefull_macros.h"
|
||||
#include "cmdlnopts.h"
|
||||
#include "daemon.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <math.h> // sqrt
|
||||
|
||||
|
||||
#ifndef PIDFILE
|
||||
#define PIDFILE "/tmp/GPStest.pid"
|
||||
#endif
|
||||
|
||||
glob_pars *GP = NULL;
|
||||
|
||||
#define PRINT(...) do{if(!GP->silent) printf(__VA_ARGS__);}while(0)
|
||||
|
||||
// Messages for blocking: GSV, RMC, GSA, GGA, GLL, VTG
|
||||
char *GPmsgs[] = {"GSV", "RMC", "GSA", "GGA", "GLL", "VTG"};
|
||||
|
||||
static void signals(int sig){
|
||||
DBG("Get signal %d, quit.\n", sig);
|
||||
unlink(PIDFILE);
|
||||
restore_tty();
|
||||
exit(sig);
|
||||
}
|
||||
|
||||
uint8_t *get_portdata(){
|
||||
static uint8_t buf[1025];
|
||||
uint8_t *ptr = buf;
|
||||
size_t L = 0, rest = 1024;
|
||||
while(rest && (L = read_tty(ptr, rest))){
|
||||
rest -= L;
|
||||
ptr += L;
|
||||
}
|
||||
if(ptr != buf){
|
||||
*ptr = 0;
|
||||
ptr = buf;
|
||||
}else ptr = NULL;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate checksum & write message to port
|
||||
* @param buf - command to write (with leading $ and trailing *)
|
||||
* return 0 if fails
|
||||
*/
|
||||
int write_with_checksum(uint8_t *buf){
|
||||
static char CS[3];
|
||||
//uint8_t *ptr = buf;
|
||||
uint8_t checksum = 0;
|
||||
if(*buf != '$') return 0;
|
||||
if(write_tty(buf, strlen((char*)buf))) return 0;
|
||||
++buf; // skip leaders
|
||||
do{
|
||||
checksum ^= *buf++;
|
||||
}while(*buf && *buf != '*');
|
||||
snprintf(CS, 3, "%X", checksum);
|
||||
if(write_tty((uint8_t*)CS, 2)) return 0;
|
||||
if(write_tty((uint8_t*)"\r\n", 2)) return 0;
|
||||
//DBG("Write: %s%c%c", ptr, CS[0], CS[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check checksum
|
||||
int checksum(uint8_t *buf){
|
||||
uint8_t *eol;
|
||||
char chs[3];
|
||||
uint8_t checksum = 0;
|
||||
if(*buf != '$' || !(eol = (uint8_t*)strchr((char*)buf, '*'))){
|
||||
DBG("Wrong data: %s\n", buf);
|
||||
return 0;
|
||||
}
|
||||
while(++buf != eol)
|
||||
checksum ^= *buf;
|
||||
snprintf(chs, 3, "%02X", checksum);
|
||||
if(strncmp(chs, (char*)++buf, 2)){
|
||||
DBG("Wrong checksum: %s", chs);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t *nextpos(uint8_t **buf, int pos){
|
||||
int i;
|
||||
if(pos < 1) pos = 1;
|
||||
for(i = 0; i < pos; ++i){
|
||||
*buf = (uint8_t*)strchr((char*)*buf, ',');
|
||||
if(!*buf) break;
|
||||
++(*buf);
|
||||
}
|
||||
return *buf;
|
||||
}
|
||||
#define NEXT() do{if(!nextpos(&buf, 1)) goto ret;}while(0)
|
||||
#define SKIP(NPOS) do{if(!nextpos(&buf, NPOS)) goto ret;}while(0)
|
||||
|
||||
|
||||
double timediff_aver = 0.;
|
||||
int timediff_N = 0;
|
||||
/**
|
||||
* difference (in seconds) in system & GPS clock
|
||||
* @return system_time - GPS_time
|
||||
*/
|
||||
double timediff(int h, int m, double s){
|
||||
struct timeval tv;
|
||||
// struct timezone tz;
|
||||
gettimeofday(&tv, NULL);
|
||||
time_t tm0 = time(NULL);
|
||||
struct tm *gmt = gmtime(&tm0);
|
||||
double td = (gmt->tm_hour - h) * 3600.;
|
||||
td += (gmt->tm_min - m) * 60.;
|
||||
td += ((double)tv.tv_usec)/1e6 + (gmt->tm_sec - s);
|
||||
timediff_aver += td;
|
||||
++timediff_N;
|
||||
return td;
|
||||
}
|
||||
|
||||
double Latt_mean = 0., Long_mean = 0., Latt_sq = 0., Long_sq = 0.;
|
||||
int Latt_N = 0, Long_N = 0;
|
||||
|
||||
/**
|
||||
* acquire last command
|
||||
* @return 0 if failed
|
||||
*/
|
||||
int get_ACK(uint8_t *conf) {
|
||||
int i;
|
||||
uint8_t ack[10] = {0xb5, 0x62, // header
|
||||
0x05, 0x01, // ACK-ACK
|
||||
2, 0}; // 2 bytes, little-endian
|
||||
// send ACK to recent CONF changes
|
||||
ack[6] = conf[2];
|
||||
ack[7] = conf[3];
|
||||
double T0 = dtime();
|
||||
// checksum
|
||||
for (i = 2; i < 8; ++i){
|
||||
ack[8] += ack[i];
|
||||
ack[9] += ack[8];
|
||||
}
|
||||
/*
|
||||
printf("ack: ");
|
||||
for(i = 0; i < 10; ++i)
|
||||
printf("%X ", ack[i]);
|
||||
printf("\n");
|
||||
*/
|
||||
uint8_t buf[10], *ptr = buf, *cmp = ack;
|
||||
size_t remain = 10;
|
||||
// wait not more than 3 seconds
|
||||
while(dtime() - T0 < 3. && remain){
|
||||
size_t L = read_tty(ptr, remain);
|
||||
if(L){
|
||||
remain -= L;
|
||||
for(i = 0; i < (int)L; ++i){
|
||||
//DBG("got: %X (%c)", *ptr, *ptr);
|
||||
if(*ptr++ != *cmp++){
|
||||
//DBG("NEQ: %X != %X", ptr[-1], cmp[-1]);
|
||||
ptr = buf; cmp = ack; remain = 10;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!remain) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cfg_stationary(){
|
||||
int i;
|
||||
uint8_t stat[44] = {0xb5, 0x62, // header
|
||||
0x06, 0x24, // CFG-NAV5
|
||||
36, 0, // 36 bytes, little-endian
|
||||
1, 0, // mask: only dynamic model
|
||||
2}; // stationary model
|
||||
// stat[44] = '\r';
|
||||
// stat[45] = '\n';
|
||||
/*
|
||||
uint8_t stat[] = {
|
||||
0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xFF, 0xFF, 0x02, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x05, 0x00,
|
||||
0xFA, 0x00, 0xFA, 0x00, 0x64, 0x00, 0x2C, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, '\r', '\n'};
|
||||
*/
|
||||
for(i = 2; i < 42; ++i){
|
||||
stat[42] += stat[i];
|
||||
stat[43] += stat[42];
|
||||
}
|
||||
/*
|
||||
printf("conf: ");
|
||||
for(i = 0; i < 44; ++i)
|
||||
printf("%X ", conf[i]);
|
||||
printf("\n");
|
||||
*/
|
||||
i = 0;
|
||||
do{
|
||||
write_tty(stat, 44);
|
||||
DBG("Written, aquire");
|
||||
}while(!get_ACK(stat) && ++i < 11);
|
||||
// precise point position
|
||||
uint8_t prec[48] = {0xb5, 0x62, // header
|
||||
0x06, 0x23, // CFG-NAVX5
|
||||
40, 0, // 40 bytes, little-endian
|
||||
0, 0, 0, 0x20}; // mask for PPP
|
||||
prec[32] = 1; // usePPP = TRUE (field 26)
|
||||
for(i = 2; i < 46; ++i){
|
||||
prec[46] += prec[i];
|
||||
prec[47] += prec[46];
|
||||
}
|
||||
i = 0;
|
||||
do{
|
||||
write_tty(prec, 48);
|
||||
DBG("Written, aquire");
|
||||
}while(!get_ACK(prec) && ++i < 11);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show current date in appropriate format for initial clock setup (MMDDhhmmCCYY.ss)
|
||||
* make from root:
|
||||
* date $(gpstest -sSD)
|
||||
*/
|
||||
void show_date(int H, int M, double S, int d, int m, int y){
|
||||
printf("--utc %02d%02d%02d%02d%02d.%02d\n", m, d, H, M, y, (int)(S + 0.3));
|
||||
signals(0); // appropriate exit
|
||||
}
|
||||
|
||||
/*
|
||||
* Satellites in View
|
||||
* $GPGSV,NoMsg,MsgNo,NoSv,{,sv,elv,az,cno}*cs
|
||||
* 1 = total number of GPGSV messages being output
|
||||
* 2 = Number of this message
|
||||
* 3 = Satellites in View
|
||||
* 4-7 will be repeated 1..4 times
|
||||
* sv = Satellite ID
|
||||
* elv = Elevation, range 0..90deg
|
||||
* az = Azimuth, range 0..359deg
|
||||
* cno = SNR, range 0.99dB
|
||||
* cs = control sum
|
||||
* 3,1,11,01,68,278,,03,39,292,08,04,66,190,30,11,55,231,34*79
|
||||
* 3,2,11,14,30,050,10,17,11,322,,19,09,202,,22,14,096,*74
|
||||
* 3,3,11,23,20,232,30,31,43,118,33,32,76,352,*43
|
||||
*/
|
||||
void gsv(uint8_t *buf){
|
||||
//DBG("gsv: %s\n", buf);
|
||||
int Nrec = -1, Ncur, inview = 0;
|
||||
static int sat_scanned = 0;
|
||||
if(sscanf((char*)buf, "%d,%d,", &Nrec, &Ncur) != 2) goto ret;
|
||||
SKIP(2);
|
||||
if(sscanf((char*)buf, "%d,", &inview) != 1) goto ret;
|
||||
if(inview < 1) goto ret;
|
||||
NEXT();
|
||||
if(Ncur == 1)
|
||||
PRINT("%d satellites in view field: (No: ID, elevation, azimuth, SNR)\n", inview);
|
||||
do{
|
||||
int id, el, az, snr;
|
||||
// there could be no "SNR" field if we can't find this satellite on sky
|
||||
if(sscanf((char*)buf, "%d,%d,%d,%d,", &id, &el, &az, &snr) < 3) break;
|
||||
PRINT(" (%d: %d, %d, %d, %d)", ++sat_scanned, id, el, az, snr);
|
||||
SKIP(4);
|
||||
}while(1);
|
||||
ret:
|
||||
if(inview < 1) PRINT("There's no GPS satellites in viewfield\n");
|
||||
if(Nrec > 0 && Nrec == Ncur){
|
||||
sat_scanned = 0;
|
||||
PRINT("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Recommended minimum specific GPS/Transit data
|
||||
* $GPRMC,hhmmss,status,latitude,N,longitude,E,spd,cog,ddmmyy,mv,mvE,mode*cs
|
||||
* 1 = UTC of position fix
|
||||
* 2 = Data status (V=navigation receiver warning)
|
||||
* 3 = Latitude of fix
|
||||
* 4 = N or S
|
||||
* 5 = Longitude of fix
|
||||
* 6 = E or W
|
||||
* 7 = Speed over ground in knots
|
||||
* 8 = Cource over ground in degrees
|
||||
* 9 = UT date
|
||||
* 10 = Magnetic variation degrees (Easterly var. subtracts from true course)
|
||||
* 11 = E or W
|
||||
* 12 = Mode: N(bad), E(approx), A(auto), D(diff)
|
||||
* 213457.00,A,4340.59415,N,04127.47560,E,2.494,,290615,,,A*7B
|
||||
*/
|
||||
void rmc(uint8_t *buf){
|
||||
//DBG("rmc: %s\n", buf);
|
||||
int H, M, LO, LA, d, m, y, getdate = 0;
|
||||
double S, longitude, lattitude, speed, track, mag;
|
||||
char varn = 'V', north = '0', east = '0', mageast = '0', mode = 'N';
|
||||
sscanf((char*)buf, "%2d%2d%lf", &H, &M, &S);
|
||||
NEXT();
|
||||
if(*buf != ',') varn = *buf;
|
||||
if(varn != 'A')
|
||||
PRINT("(data could be wrong)");
|
||||
else{
|
||||
PRINT("(data valid)");
|
||||
if(GP->date) getdate = 1; // as only we have valid data we show it to user
|
||||
}
|
||||
PRINT(" time: %02d:%02d:%05.2f", H, M, S);
|
||||
PRINT(" timediff: %g", timediff(H, M, S));
|
||||
NEXT();
|
||||
sscanf((char*)buf, "%2d%lf", &LA, &lattitude);
|
||||
NEXT();
|
||||
if(*buf != ','){
|
||||
north = *buf;
|
||||
lattitude = (double)LA + lattitude / 60.;
|
||||
if(north == 'S') lattitude = -lattitude;
|
||||
PRINT(" latt: %g", lattitude);
|
||||
Latt_mean += lattitude;
|
||||
Latt_sq += lattitude*lattitude;
|
||||
++Latt_N;
|
||||
}
|
||||
NEXT();
|
||||
sscanf((char*)buf, "%3d%lf", &LO, &longitude);
|
||||
NEXT();
|
||||
if(*buf != ','){
|
||||
east = *buf;
|
||||
longitude = (double)LO + longitude / 60.;
|
||||
if(east == 'W') longitude = -longitude;
|
||||
PRINT(" long: %g", longitude);
|
||||
Long_mean += longitude;
|
||||
Long_sq += longitude*longitude;
|
||||
++Long_N;
|
||||
}
|
||||
NEXT();
|
||||
if(*buf != ','){
|
||||
sscanf((char*)buf, "%lf", &speed);
|
||||
PRINT(" speed: %gknots", speed);
|
||||
}
|
||||
NEXT();
|
||||
if(*buf != ','){
|
||||
sscanf((char*)buf, "%lf", &track);
|
||||
PRINT(" track: %gdeg,True", track);
|
||||
}
|
||||
NEXT();
|
||||
if(sscanf((char*)buf, "%2d%2d%2d", &d, &m, &y) == 3)
|
||||
PRINT(" date(dd/mm/yy): %02d/%02d/%02d", d, m, y);
|
||||
if(getdate) show_date(H,M,S,d,m,y); // show date & exit
|
||||
NEXT();
|
||||
sscanf((char*)buf, "%lf,%c", &mag, &mageast);
|
||||
if(mageast == 'E' || mageast == 'W'){
|
||||
if(mageast == 'W') mag = -mag;
|
||||
PRINT(" magnetic var: %g", mag);
|
||||
}
|
||||
SKIP(2);
|
||||
if(*buf != ','){
|
||||
mode = *buf;
|
||||
PRINT(" mode: %c", mode);
|
||||
}
|
||||
ret:
|
||||
PRINT("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Overall Satellite data
|
||||
* $GPGSA,Smode,FS{,sv},PDOP,HDOP,VDOP*cs
|
||||
* 1 = mode: 'M' - manual, 'A' - auto
|
||||
* 2 = fix status: 1 - not available, 2 - 2D, 3 - 3D
|
||||
* 3..14 = used satellite number
|
||||
* 15 = position dilution
|
||||
* 16 = horizontal dilution
|
||||
* 17 = vertical dilution
|
||||
* A,2,04,31,32,14,19,,,,,,,,2.77,2.58,1.00*05
|
||||
*/
|
||||
void gsa(uint8_t *buf){
|
||||
//DBG("gsa: %s\n", buf);
|
||||
int used[12];
|
||||
int i, Nused = 0;
|
||||
if(*buf == 'M') PRINT("Mode: manual; ");
|
||||
else if(*buf == 'A') PRINT("Mode: auto; ");
|
||||
else return; // wrong data
|
||||
NEXT();
|
||||
switch(*buf){
|
||||
case '1':
|
||||
PRINT("no fix; ");
|
||||
break;
|
||||
case '2':
|
||||
PRINT("2D fix; ");
|
||||
break;
|
||||
case '3':
|
||||
PRINT("3D fix; ");
|
||||
break;
|
||||
default:
|
||||
goto ret;
|
||||
}
|
||||
NEXT();
|
||||
for(i = 0; i < 12; ++i){
|
||||
int N;
|
||||
if(sscanf((char*)buf, "%d,", &N) == 1)
|
||||
used[Nused++] = N;
|
||||
NEXT();
|
||||
}
|
||||
if(Nused){
|
||||
PRINT("%d satellites used: ", Nused);
|
||||
for(i = 0; i < Nused; ++i)
|
||||
PRINT("%d, ", used[i]);
|
||||
}
|
||||
double pos, hor, vert;
|
||||
if(sscanf((char*)buf, "%lf,%lf,%lf", &pos, &hor, &vert) == 3){
|
||||
PRINT("DILUTION: pos=%.2f, hor=%.2f, vert=%.2f", pos, hor, vert);
|
||||
}
|
||||
ret:
|
||||
PRINT("\n");
|
||||
}
|
||||
|
||||
// 213457.00,4340.59415,N,04127.47560,E,1,05,2.58,1275.8,M,17.0,M,,*60
|
||||
void gga(_U_ uint8_t *buf){
|
||||
//DBG("gga: %s\n", buf);
|
||||
}
|
||||
|
||||
//4340.59415,N,04127.47560,E,213457.00,A,A*60
|
||||
void gll(_U_ uint8_t *buf){
|
||||
//DBG("gll: %s\n", buf);
|
||||
}
|
||||
|
||||
// ,T,,M,2.494,N,4.618,K,A*23
|
||||
void vtg(_U_ uint8_t *buf){
|
||||
//DBG("vtg: %s\n", buf);
|
||||
}
|
||||
|
||||
|
||||
void txt(_U_ uint8_t *buf){
|
||||
DBG("txt: %s\n", buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUBX,00
|
||||
* $PUBX,00,hhmmss.ss,Latitude,N,Longitude,E,AltRef,NavStat,Hacc,Vacc,SOG,COG,Vvel,ageC,HDOP,VDOP,TDOP,GU,RU,DR,*cs
|
||||
* here buf starts from hhmmss.ss == 1
|
||||
* 1 = UTC time
|
||||
* 2 = lattitude
|
||||
* 3 = N/S
|
||||
* 4 = longitude
|
||||
* 5 = E/W
|
||||
* 6 = altitude
|
||||
* 7 = nav.stat: NF/DR/G2/G3/D2/D3/RK/TT
|
||||
* 8 = horizontal accuracy
|
||||
* 9 = vertical accuracy
|
||||
* 10 = speed over ground (km/h)
|
||||
* 11 = cource over ground (deg)
|
||||
* 12 = vertical velocy ("+" -- down, "-" -- up)
|
||||
* 13 = age of most recent DGPS correction
|
||||
* 14 = hor. dilution
|
||||
* 15 = vert. dilution
|
||||
* 16 = time dilution
|
||||
* 17 = number of GPS satell. used
|
||||
* 18 = number of GLONASS sat. used
|
||||
* 19 = DR used
|
||||
* $PUBX,00,113123.00,4340.61823,N,04127.45581,E,1295.919,G2,30,6.9,1.875,38.17,0.000,,2.77,1.00,1.41,3,0,0*4C
|
||||
*/
|
||||
void pubx(uint8_t *buf){
|
||||
//DBG("pubx_00: %s\n", buf);
|
||||
int H, M, LO, LA, gps, glo, dr;
|
||||
double S, longitude, lattitude, altitude, hacc, vacc, speed, track, vertspd,
|
||||
age, hdop, vdop, tdop;
|
||||
char north = '0', east = '0';
|
||||
sscanf((char*)buf, "%2d%2d%lf", &H, &M, &S);
|
||||
PRINT("time: %02d:%02d:%05.2f", H, M, S);
|
||||
PRINT(" timediff: %g", timediff(H, M, S));
|
||||
NEXT();
|
||||
sscanf((char*)buf, "%2d%lf", &LA, &lattitude);
|
||||
NEXT();
|
||||
if(*buf != ','){
|
||||
north = *buf;
|
||||
lattitude = (double)LA + lattitude / 60.;
|
||||
if(north == 'S') lattitude = -lattitude;
|
||||
PRINT(" latt: %g", lattitude);
|
||||
Latt_mean += lattitude;
|
||||
Latt_sq += lattitude*lattitude;
|
||||
++Latt_N;
|
||||
}
|
||||
NEXT();
|
||||
sscanf((char*)buf, "%3d%lf", &LO, &longitude);
|
||||
NEXT();
|
||||
if(*buf != ','){
|
||||
east = *buf;
|
||||
longitude = (double)LO + longitude / 60.;
|
||||
if(east == 'W') longitude = -longitude;
|
||||
PRINT(" long: %g", longitude);
|
||||
Long_mean += longitude;
|
||||
Long_sq += longitude*longitude;
|
||||
++Long_N;
|
||||
}
|
||||
NEXT();
|
||||
#define FSCAN(par, nam) do{if(*buf != ','){sscanf((char*)buf, "%lf", &par); \
|
||||
PRINT(" " nam ": %g", par);} NEXT();}while(0)
|
||||
FSCAN(altitude, "altitude");
|
||||
if(*buf != ','){
|
||||
PRINT(" nav. status: %c%c", buf[0], buf[1]);
|
||||
}
|
||||
NEXT();
|
||||
FSCAN(hacc,"hor.accuracy");
|
||||
FSCAN(vacc, "vert.accuracy");
|
||||
FSCAN(speed,"speed");
|
||||
FSCAN(track,"cource");
|
||||
FSCAN(vertspd,"vertical speed ('+'-down)");
|
||||
FSCAN(age,"DGPS age");
|
||||
FSCAN(hdop, "hor. dilution");
|
||||
FSCAN(vdop, "vert. dilution");
|
||||
FSCAN(tdop, "time dilution");
|
||||
#undef FSCAN
|
||||
#define ISCAN(par, nam) do{if(*buf != ','){sscanf((char*)buf, "%d", &par); \
|
||||
PRINT(" " nam ": %d", par);} NEXT();}while(0)
|
||||
ISCAN(gps, "GPS used");
|
||||
ISCAN(glo, "GLONASS used");
|
||||
ISCAN(dr, "DR used");
|
||||
#undef ISCAN
|
||||
ret:
|
||||
PRINT("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parce content of buffer with GPS data
|
||||
* WARNING! This function changes data content
|
||||
*/
|
||||
void parce_data(uint8_t *buf){
|
||||
uint8_t *eol;
|
||||
//DBG("GOT: %s", buf);
|
||||
while(*buf && (eol = (uint8_t*)strchr((char*)buf, '\r'))){
|
||||
*eol = 0;
|
||||
// now make checksum checking:
|
||||
if(!checksum(buf)) goto cont;
|
||||
if(strncmp((char*)buf, "$GP", 3)){
|
||||
if(strncmp((char*)buf, "$PUBX,00,", 9) == 0){
|
||||
buf += 9;
|
||||
pubx(buf);
|
||||
}else{
|
||||
DBG("Bad string: %s\n", buf);
|
||||
}
|
||||
goto cont;
|
||||
}
|
||||
buf += 3;
|
||||
// PARSE variants: GSV, RMC, GSA, GGA, GLL, VTG, TXT
|
||||
// 1st letter, cold be one of G,R,V or T
|
||||
switch(*buf){
|
||||
case 'G': // GSV, GSA, GGA, GLL
|
||||
++buf;
|
||||
if(strncmp((char*)buf, "SV", 2) == 0){
|
||||
gsv(buf+3);
|
||||
}else if(strncmp((char*)buf, "SA", 2) == 0){
|
||||
gsa(buf+3);
|
||||
}else if(strncmp((char*)buf, "GA", 2) == 0){
|
||||
gga(buf+3);
|
||||
}else if(strncmp((char*)buf, "LL", 2) == 0){
|
||||
gll(buf+3);
|
||||
}else{
|
||||
DBG("Unknown: $GPG%s", buf);
|
||||
goto cont;
|
||||
}
|
||||
break;
|
||||
case 'R': // RMC
|
||||
++buf;
|
||||
if(strncmp((char*)buf, "MC", 2) == 0){
|
||||
rmc(buf+3);
|
||||
}else{
|
||||
DBG("Unknown: $GPR%s", buf);
|
||||
goto cont;
|
||||
}
|
||||
break;
|
||||
case 'V': // VTG
|
||||
++buf;
|
||||
if(strncmp((char*)buf, "TG", 2) == 0){
|
||||
vtg(buf+3);
|
||||
}else{
|
||||
DBG("Unknown: $GPV%s", buf);
|
||||
goto cont;
|
||||
}
|
||||
break;
|
||||
case 'T': // TXT
|
||||
++buf;
|
||||
if(strncmp((char*)buf, "XT", 2) == 0){
|
||||
txt(buf+3);
|
||||
}else{
|
||||
DBG("Unknown: $GPT%s", buf);
|
||||
goto cont;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DBG("Unknown: $GP%s", buf);
|
||||
goto cont;
|
||||
}
|
||||
cont:
|
||||
if(eol[1] != '\n') break;
|
||||
buf = eol + 2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set rate for given NMEA field
|
||||
* @param field - name of NMEA field
|
||||
* @param rate - rate in seconds (0 disables field)
|
||||
* @return -1 if fails, rate if OK
|
||||
*/
|
||||
int nmea_fieldrate(uint8_t *field, int rate){
|
||||
uint8_t buf[256];
|
||||
if(rate < 0) return -1;
|
||||
snprintf((char*)buf, 255, "$PUBX,40,%s,0,%d,0,0*", field, rate);
|
||||
if(write_with_checksum(buf)) return rate;
|
||||
else return -1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
check4running(argv, PIDFILE, NULL);
|
||||
initial_setup();
|
||||
GP = parce_args(argc, argv);
|
||||
assert(GP);
|
||||
DBG("Device path: %s\n", GP->devpath);
|
||||
tty_init(GP->devpath);
|
||||
signal(SIGTERM, signals); // kill (-15) - quit
|
||||
signal(SIGHUP, signals); // hup - quit
|
||||
signal(SIGINT, signals); // ctrl+C - quit
|
||||
signal(SIGQUIT, signals); // ctrl+\ - quit
|
||||
signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z
|
||||
int i;
|
||||
if(GP->date) GP->block_msg[GPRMC] = 1; // we calculate date in RMC events
|
||||
for(i = 0; i < GPMAXMSG; ++i){
|
||||
int block = 0;
|
||||
if(GP->block_msg[i])
|
||||
block = 1; // unblock message
|
||||
if(nmea_fieldrate((uint8_t*)GPmsgs[i], block) != block)
|
||||
WARN("Can't %sblock %s!", block?"un":"", GPmsgs[i]);
|
||||
else
|
||||
PRINT("%sblock %s\n", block?"un":"", GPmsgs[i]);
|
||||
}
|
||||
if(GP->stationary){
|
||||
PRINT("stationary config\n");
|
||||
cfg_stationary();
|
||||
}
|
||||
double T, T0 = dtime(), Tpoll = 0., tmout = GP->polltmout;
|
||||
uint8_t *str = NULL;
|
||||
while(((T=dtime()) - T0 < tmout) || GP->date){ // if we want get date, we should wait a lot
|
||||
if(GP->pollubx && T-Tpoll > GP->pollinterval){
|
||||
Tpoll = T;
|
||||
write_tty((uint8_t*)"$PUBX,00*33\r\n", 13);
|
||||
}
|
||||
if((str = get_portdata())){
|
||||
parce_data(str);
|
||||
}
|
||||
}
|
||||
if(GP->gettimediff)
|
||||
printf("\nAverage time difference (local-GPS) = %g seconds\n", timediff_aver/timediff_N);
|
||||
if(GP->meancoords){
|
||||
printf("\nAverage coordinates:\n\tLattitude");
|
||||
double mean, std, s;
|
||||
int d, m;
|
||||
if(Latt_N){
|
||||
mean = Latt_mean / Latt_N;
|
||||
std = sqrt(Latt_sq/Latt_N - mean*mean);
|
||||
d = (int)mean; m = (int)(60.*(mean-d)); s = 3600*fabs(mean-d-m/60.);
|
||||
if(m < 0) m = -m;
|
||||
printf(" = %.6f (%d %d' %.2f''), std = %g (%.2f'')\n", mean, d, m, s, std, std*3600.);
|
||||
}else printf(": no data\n");
|
||||
printf("\tLongitude");
|
||||
if(Long_N){
|
||||
mean = Long_mean / Long_N;
|
||||
std = sqrt(Long_sq/Long_N - mean*mean);
|
||||
d = (int)mean; m = (int)(60.*(mean-d)); s = 3600*fabs(mean-d-m/60.);
|
||||
if(m < 0) m = -m;
|
||||
printf(" = %.6f (%d %d' %.2f''), std = %g (%.2f'')\n", mean, d, m, s, std, std*3600.);
|
||||
}else printf(": no data\n");
|
||||
}
|
||||
signals(0);
|
||||
return 0;
|
||||
}
|
||||
296
_deprecated/GPS/parceargs.c
Normal file
296
_deprecated/GPS/parceargs.c
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
// 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
|
||||
};
|
||||
if(pcount > 1 || pcount != scount){ // amount of pcount and/or scount wrong
|
||||
fprintf(stderr, "Wrong helpstring!\n");
|
||||
exit(-1);
|
||||
}
|
||||
helpstring = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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];
|
||||
if(opt == 0 && opts->has_arg == 0) continue; // only long option changing integer flag
|
||||
// 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:
|
||||
if(opts->argptr) *((int*)opts->argptr) = 1; // set argptr to 1
|
||||
break;
|
||||
case arg_int:
|
||||
result = myatoll(opts->argptr, optarg, arg_int);
|
||||
break;
|
||||
case arg_longlong:
|
||||
result = myatoll(opts->argptr, optarg, arg_longlong);
|
||||
break;
|
||||
case arg_double:
|
||||
result = myatod(opts->argptr, optarg, arg_double);
|
||||
break;
|
||||
case arg_float:
|
||||
result = myatod(opts->argptr, optarg, arg_float);
|
||||
break;
|
||||
case arg_string:
|
||||
result = (*((char **)opts->argptr) = strdup(optarg));
|
||||
break;
|
||||
case arg_function:
|
||||
result = ((argfn)opts->argptr)(optarg, optind);
|
||||
break;
|
||||
}
|
||||
if(!result){
|
||||
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(), by 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);
|
||||
}
|
||||
105
_deprecated/GPS/parceargs.h
Normal file
105
_deprecated/GPS/parceargs.h
Normal 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__
|
||||
320
_deprecated/GPS/usefull_macros.c
Normal file
320
_deprecated/GPS/usefull_macros.c
Normal file
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* usefull_macros.h - a set of usefull functions: memory, color etc
|
||||
*
|
||||
* 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 "usefull_macros.h"
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/******************************************************************************\
|
||||
* Coloured terminal
|
||||
\******************************************************************************/
|
||||
int globErr = 0; // errno for WARN/ERR
|
||||
|
||||
// pointers to coloured output printf
|
||||
int (*red)(const char *fmt, ...);
|
||||
int (*green)(const char *fmt, ...);
|
||||
int (*_WARN)(const char *fmt, ...);
|
||||
|
||||
/*
|
||||
* format red / green messages
|
||||
* name: r_pr_, g_pr_
|
||||
* @param fmt ... - printf-like format
|
||||
* @return number of printed symbols
|
||||
*/
|
||||
int r_pr_(const char *fmt, ...){
|
||||
va_list ar; int i;
|
||||
printf(RED);
|
||||
va_start(ar, fmt);
|
||||
i = vprintf(fmt, ar);
|
||||
va_end(ar);
|
||||
printf(OLDCOLOR);
|
||||
return i;
|
||||
}
|
||||
int g_pr_(const char *fmt, ...){
|
||||
va_list ar; int i;
|
||||
printf(GREEN);
|
||||
va_start(ar, fmt);
|
||||
i = vprintf(fmt, ar);
|
||||
va_end(ar);
|
||||
printf(OLDCOLOR);
|
||||
return i;
|
||||
}
|
||||
/*
|
||||
* print red error/warning messages (if output is a tty)
|
||||
* @param fmt ... - printf-like format
|
||||
* @return number of printed symbols
|
||||
*/
|
||||
int r_WARN(const char *fmt, ...){
|
||||
va_list ar; int i = 1;
|
||||
fprintf(stderr, RED);
|
||||
va_start(ar, fmt);
|
||||
if(globErr){
|
||||
errno = globErr;
|
||||
vwarn(fmt, ar);
|
||||
errno = 0;
|
||||
globErr = 0;
|
||||
}else
|
||||
i = vfprintf(stderr, fmt, ar);
|
||||
va_end(ar);
|
||||
i++;
|
||||
fprintf(stderr, OLDCOLOR "\n");
|
||||
return i;
|
||||
}
|
||||
|
||||
static const char stars[] = "****************************************";
|
||||
/*
|
||||
* notty variants of coloured printf
|
||||
* name: s_WARN, r_pr_notty
|
||||
* @param fmt ... - printf-like format
|
||||
* @return number of printed symbols
|
||||
*/
|
||||
int s_WARN(const char *fmt, ...){
|
||||
va_list ar; int i;
|
||||
i = fprintf(stderr, "\n%s\n", stars);
|
||||
va_start(ar, fmt);
|
||||
if(globErr){
|
||||
errno = globErr;
|
||||
vwarn(fmt, ar);
|
||||
errno = 0;
|
||||
globErr = 0;
|
||||
}else
|
||||
i = +vfprintf(stderr, fmt, ar);
|
||||
va_end(ar);
|
||||
i += fprintf(stderr, "\n%s\n", stars);
|
||||
i += fprintf(stderr, "\n");
|
||||
return i;
|
||||
}
|
||||
int r_pr_notty(const char *fmt, ...){
|
||||
va_list ar; int i;
|
||||
i = printf("\n%s\n", stars);
|
||||
va_start(ar, fmt);
|
||||
i += vprintf(fmt, ar);
|
||||
va_end(ar);
|
||||
i += printf("\n%s\n", stars);
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run this function in the beginning of main() to setup locale & coloured output
|
||||
*/
|
||||
void initial_setup(){
|
||||
// setup coloured output
|
||||
if(isatty(STDOUT_FILENO)){ // make color output in tty
|
||||
red = r_pr_; green = g_pr_;
|
||||
}else{ // no colors in case of pipe
|
||||
red = r_pr_notty; green = printf;
|
||||
}
|
||||
if(isatty(STDERR_FILENO)) _WARN = r_WARN;
|
||||
else _WARN = s_WARN;
|
||||
// Setup locale
|
||||
setlocale(LC_ALL, "");
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
#if defined GETTEXT_PACKAGE && defined LOCALEDIR
|
||||
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
|
||||
textdomain(GETTEXT_PACKAGE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************\
|
||||
* Memory
|
||||
\******************************************************************************/
|
||||
/*
|
||||
* safe memory allocation for macro ALLOC
|
||||
* @param N - number of elements to allocate
|
||||
* @param S - size of single element (typically sizeof)
|
||||
* @return pointer to allocated memory area
|
||||
*/
|
||||
void *my_alloc(size_t N, size_t S){
|
||||
void *p = calloc(N, S);
|
||||
if(!p) ERR("malloc");
|
||||
//assert(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mmap file to a memory area
|
||||
*
|
||||
* @param filename (i) - name of file to mmap
|
||||
* @return stuct with mmap'ed file or die
|
||||
*/
|
||||
mmapbuf *My_mmap(char *filename){
|
||||
int fd;
|
||||
char *ptr;
|
||||
size_t Mlen;
|
||||
struct stat statbuf;
|
||||
if(!filename) ERRX(_("No filename given!"));
|
||||
if((fd = open(filename, O_RDONLY)) < 0)
|
||||
ERR(_("Can't open %s for reading"), filename);
|
||||
if(fstat (fd, &statbuf) < 0)
|
||||
ERR(_("Can't stat %s"), filename);
|
||||
Mlen = statbuf.st_size;
|
||||
if((ptr = mmap (0, Mlen, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
|
||||
ERR(_("Mmap error for input"));
|
||||
if(close(fd)) ERR(_("Can't close mmap'ed file"));
|
||||
mmapbuf *ret = MALLOC(mmapbuf, 1);
|
||||
ret->data = ptr;
|
||||
ret->len = Mlen;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void My_munmap(mmapbuf *b){
|
||||
if(munmap(b->data, b->len))
|
||||
ERR(_("Can't munmap"));
|
||||
FREE(b);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************\
|
||||
* Terminal in no-echo mode
|
||||
\******************************************************************************/
|
||||
static struct termios oldt, newt; // terminal flags
|
||||
static int console_changed = 0;
|
||||
// run on exit:
|
||||
void restore_console(){
|
||||
if(console_changed)
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // return terminal to previous state
|
||||
console_changed = 0;
|
||||
}
|
||||
|
||||
// initial setup:
|
||||
void setup_con(){
|
||||
if(console_changed) return;
|
||||
tcgetattr(STDIN_FILENO, &oldt);
|
||||
newt = oldt;
|
||||
newt.c_lflag &= ~(ICANON | ECHO);
|
||||
if(tcsetattr(STDIN_FILENO, TCSANOW, &newt) < 0){
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
||||
exit(-2); //quit?
|
||||
}
|
||||
console_changed = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read character from console without echo
|
||||
* @return char readed
|
||||
*/
|
||||
int read_console(){
|
||||
int rb;
|
||||
struct timeval tv;
|
||||
int retval;
|
||||
fd_set rfds;
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(STDIN_FILENO, &rfds);
|
||||
tv.tv_sec = 0; tv.tv_usec = 10000;
|
||||
retval = select(1, &rfds, NULL, NULL, &tv);
|
||||
if(!retval) rb = 0;
|
||||
else {
|
||||
if(FD_ISSET(STDIN_FILENO, &rfds)) rb = getchar();
|
||||
else rb = 0;
|
||||
}
|
||||
return rb;
|
||||
}
|
||||
|
||||
/**
|
||||
* getchar() without echo
|
||||
* wait until at least one character pressed
|
||||
* @return character readed
|
||||
*/
|
||||
int mygetchar(){ // getchar() without need of pressing ENTER
|
||||
int ret;
|
||||
do ret = read_console();
|
||||
while(ret == 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************\
|
||||
* TTY with select()
|
||||
\******************************************************************************/
|
||||
static struct termio oldtty, tty; // TTY flags
|
||||
static int comfd = -1; // TTY fd
|
||||
|
||||
// run on exit:
|
||||
void restore_tty(){
|
||||
if(comfd == -1) return;
|
||||
ioctl(comfd, TCSANOW, &oldtty ); // return TTY to previous state
|
||||
close(comfd);
|
||||
comfd = -1;
|
||||
}
|
||||
|
||||
#ifndef BAUD_RATE
|
||||
#define BAUD_RATE B9600
|
||||
#endif
|
||||
// init:
|
||||
void tty_init(char *comdev){
|
||||
DBG("\nOpen port...\n");
|
||||
if ((comfd = open(comdev,O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0){
|
||||
WARN("Can't use port %s\n",comdev);
|
||||
ioctl(comfd, TCSANOW, &oldtty); // return TTY to previous state
|
||||
close(comfd);
|
||||
exit(1); // quit?
|
||||
}
|
||||
DBG(" OK\nGet current settings... ");
|
||||
if(ioctl(comfd,TCGETA,&oldtty) < 0) exit(-1); // Get settings
|
||||
tty = oldtty;
|
||||
tty.c_lflag = 0; // ~(ICANON | ECHO | ECHOE | ISIG)
|
||||
tty.c_oflag = 0;
|
||||
tty.c_cflag = BAUD_RATE|CS8|CREAD|CLOCAL; // 9.6k, 8N1, RW, ignore line ctrl
|
||||
tty.c_cc[VMIN] = 0; // non-canonical mode
|
||||
tty.c_cc[VTIME] = 5;
|
||||
if(ioctl(comfd,TCSETA,&tty) < 0) exit(-1); // set new mode
|
||||
DBG(" 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(uint8_t *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; // wait for 50ms
|
||||
retval = select(comfd + 1, &rfds, NULL, NULL, &tv);
|
||||
if (!retval) return 0;
|
||||
if(FD_ISSET(comfd, &rfds)){
|
||||
if((L = read(comfd, buff, length)) < 1) return 0;
|
||||
}
|
||||
return (size_t)L;
|
||||
}
|
||||
|
||||
int write_tty(uint8_t *buff, size_t length){
|
||||
ssize_t L = write(comfd, buff, length);
|
||||
if((size_t)L != length){
|
||||
WARN("Write error!");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
123
_deprecated/GPS/usefull_macros.h
Normal file
123
_deprecated/GPS/usefull_macros.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* usefull_macros.h - a set of usefull macros: memory, color etc
|
||||
*
|
||||
* 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 __USEFULL_MACROS_H__
|
||||
#define __USEFULL_MACROS_H__
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <err.h>
|
||||
#include <locale.h>
|
||||
#if defined GETTEXT_PACKAGE && defined LOCALEDIR
|
||||
/*
|
||||
* GETTEXT
|
||||
*/
|
||||
#include <libintl.h>
|
||||
#define _(String) gettext(String)
|
||||
#define gettext_noop(String) String
|
||||
#define N_(String) gettext_noop(String)
|
||||
#else
|
||||
#define _(String) (String)
|
||||
#define N_(String) (String)
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <termios.h>
|
||||
#include <termio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// unused arguments with -Wall -Werror
|
||||
#define _U_ __attribute__((__unused__))
|
||||
|
||||
/*
|
||||
* Coloured messages output
|
||||
*/
|
||||
#define RED "\033[1;31;40m"
|
||||
#define GREEN "\033[1;32;40m"
|
||||
#define OLDCOLOR "\033[0;0;0m"
|
||||
|
||||
/*
|
||||
* ERROR/WARNING messages
|
||||
*/
|
||||
extern int globErr;
|
||||
#define ERR(...) do{globErr=errno; _WARN(__VA_ARGS__); exit(-1);}while(0)
|
||||
#define ERRX(...) do{globErr=0; _WARN(__VA_ARGS__); exit(-1);}while(0)
|
||||
#define WARN(...) do{globErr=errno; _WARN(__VA_ARGS__);}while(0)
|
||||
#define WARNX(...) do{globErr=0; _WARN(__VA_ARGS__);}while(0)
|
||||
|
||||
/*
|
||||
* print function name, debug messages
|
||||
* debug mode, -DEBUG
|
||||
*/
|
||||
#ifdef EBUG
|
||||
#define FNAME() fprintf(stderr, "\n%s (%s, line %d)\n", __func__, __FILE__, __LINE__)
|
||||
#define DBG(...) do{fprintf(stderr, "%s (%s, line %d): ", __func__, __FILE__, __LINE__); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n");} while(0)
|
||||
#else
|
||||
#define FNAME() do{}while(0)
|
||||
#define DBG(...) do{}while(0)
|
||||
#endif //EBUG
|
||||
|
||||
/*
|
||||
* Memory allocation
|
||||
*/
|
||||
#define ALLOC(type, var, size) type * var = ((type *)my_alloc(size, sizeof(type)))
|
||||
#define MALLOC(type, size) ((type *)my_alloc(size, sizeof(type)))
|
||||
#define FREE(ptr) do{free(ptr); ptr = NULL;}while(0)
|
||||
|
||||
double dtime();
|
||||
|
||||
// functions for color output in tty & no-color in pipes
|
||||
extern int (*red)(const char *fmt, ...);
|
||||
extern int (*_WARN)(const char *fmt, ...);
|
||||
extern int (*green)(const char *fmt, ...);
|
||||
void * my_alloc(size_t N, size_t S);
|
||||
void initial_setup();
|
||||
|
||||
// mmap file
|
||||
typedef struct{
|
||||
char *data;
|
||||
size_t len;
|
||||
} mmapbuf;
|
||||
mmapbuf *My_mmap(char *filename);
|
||||
void My_munmap(mmapbuf *b);
|
||||
|
||||
void restore_console();
|
||||
void setup_con();
|
||||
int read_console();
|
||||
int mygetchar();
|
||||
|
||||
void restore_tty();
|
||||
void tty_init(char *comdev);
|
||||
size_t read_tty(uint8_t *buff, size_t length);
|
||||
int write_tty(uint8_t *buff, size_t length);
|
||||
|
||||
#endif // __USEFULL_MACROS_H__
|
||||
13
_deprecated/Ncurses/Makefile
Normal file
13
_deprecated/Ncurses/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
CC=gcc
|
||||
CFLAGS= -Wall -Werror -Wextra -O3 `pkg-config --libs --cflags ncurses`
|
||||
|
||||
all: menu mouse_menu acs rolling readf ncurses_and_readline
|
||||
|
||||
ncurses_and_readline: ncurses_and_readline.c
|
||||
@echo -e "\t\tCC $<"
|
||||
$(CC) $(CFLAGS) -lreadline -o $@ $<
|
||||
|
||||
%: %.c
|
||||
@echo -e "\t\tCC $<"
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
45
_deprecated/Ncurses/acs.c
Normal file
45
_deprecated/Ncurses/acs.c
Normal file
@@ -0,0 +1,45 @@
|
||||
#include <ncurses.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
initscr();
|
||||
|
||||
printw("Upper right corner "); addch(ACS_URCORNER); printw("\n");
|
||||
printw("Upper left corner "); addch(ACS_ULCORNER); printw("\n");
|
||||
printw("Lower left corner "); addch(ACS_LLCORNER); printw("\n");
|
||||
printw("Lower right corner "); addch(ACS_LRCORNER); printw("\n");
|
||||
printw("Tee pointing right "); addch(ACS_LTEE); printw("\n");
|
||||
printw("Tee pointing left "); addch(ACS_RTEE); printw("\n");
|
||||
printw("Tee pointing up "); addch(ACS_BTEE); printw("\n");
|
||||
printw("Tee pointing down "); addch(ACS_TTEE); printw("\n");
|
||||
printw("Horizontal line "); addch(ACS_HLINE); printw("\n");
|
||||
printw("Vertical line "); addch(ACS_VLINE); printw("\n");
|
||||
printw("Large Plus or cross over "); addch(ACS_PLUS); printw("\n");
|
||||
printw("Scan Line 1 "); addch(ACS_S1); printw("\n");
|
||||
printw("Scan Line 3 "); addch(ACS_S3); printw("\n");
|
||||
printw("Scan Line 7 "); addch(ACS_S7); printw("\n");
|
||||
printw("Scan Line 9 "); addch(ACS_S9); printw("\n");
|
||||
printw("Diamond "); addch(ACS_DIAMOND); printw("\n");
|
||||
printw("Checker board (stipple) "); addch(ACS_CKBOARD); printw("\n");
|
||||
printw("Degree Symbol "); addch(ACS_DEGREE); printw("\n");
|
||||
printw("Plus/Minus Symbol "); addch(ACS_PLMINUS); printw("\n");
|
||||
printw("Bullet "); addch(ACS_BULLET); printw("\n");
|
||||
printw("Arrow Pointing Left "); addch(ACS_LARROW); printw("\n");
|
||||
printw("Arrow Pointing Right "); addch(ACS_RARROW); printw("\n");
|
||||
printw("Arrow Pointing Down "); addch(ACS_DARROW); printw("\n");
|
||||
printw("Arrow Pointing Up "); addch(ACS_UARROW); printw("\n");
|
||||
printw("Board of squares "); addch(ACS_BOARD); printw("\n");
|
||||
printw("Lantern Symbol "); addch(ACS_LANTERN); printw("\n");
|
||||
printw("Solid Square Block "); addch(ACS_BLOCK); printw("\n");
|
||||
printw("Less/Equal sign "); addch(ACS_LEQUAL); printw("\n");
|
||||
printw("Greater/Equal sign "); addch(ACS_GEQUAL); printw("\n");
|
||||
printw("Pi "); addch(ACS_PI); printw("\n");
|
||||
printw("Not equal "); addch(ACS_NEQUAL); printw("\n");
|
||||
printw("UK pound sign "); addch(ACS_STERLING); printw("\n");
|
||||
|
||||
refresh();
|
||||
getch();
|
||||
endwin();
|
||||
|
||||
return 0;
|
||||
}
|
||||
94
_deprecated/Ncurses/menu.c
Normal file
94
_deprecated/Ncurses/menu.c
Normal file
@@ -0,0 +1,94 @@
|
||||
#include <stdio.h>
|
||||
#include <ncurses.h>
|
||||
|
||||
#define WIDTH 30
|
||||
#define HEIGHT 10
|
||||
|
||||
int startx = 0;
|
||||
int starty = 0;
|
||||
|
||||
char *choices[] = {
|
||||
"Choice 1",
|
||||
"Choice 2",
|
||||
"Choice 3",
|
||||
"Choice 4",
|
||||
"Exit",
|
||||
};
|
||||
int n_choices = sizeof(choices) / sizeof(char *);
|
||||
void print_menu(WINDOW *menu_win, int highlight);
|
||||
|
||||
int main()
|
||||
{ WINDOW *menu_win;
|
||||
int highlight = 1;
|
||||
int choice = 0;
|
||||
int c;
|
||||
|
||||
initscr();
|
||||
clear();
|
||||
noecho();
|
||||
cbreak(); /* Line buffering disabled. pass on everything */
|
||||
startx = (80 - WIDTH) / 2;
|
||||
starty = (24 - HEIGHT) / 2;
|
||||
|
||||
menu_win = newwin(HEIGHT, WIDTH, starty, startx);
|
||||
keypad(menu_win, TRUE);
|
||||
mvprintw(0, 0, "Use arrow keys to go up and down, Press enter to select a choice");
|
||||
refresh();
|
||||
print_menu(menu_win, highlight);
|
||||
while(1)
|
||||
{ c = wgetch(menu_win);
|
||||
switch(c)
|
||||
{ case KEY_UP:
|
||||
if(highlight == 1)
|
||||
highlight = n_choices;
|
||||
else
|
||||
--highlight;
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
if(highlight == n_choices)
|
||||
highlight = 1;
|
||||
else
|
||||
++highlight;
|
||||
break;
|
||||
case 10:
|
||||
choice = highlight;
|
||||
break;
|
||||
default:
|
||||
mvprintw(24, 0, "Charcter pressed is = %3d", c);
|
||||
if(c > 32 && c < 256) printw(" (%c)", c);
|
||||
clrtoeol();
|
||||
refresh();
|
||||
break;
|
||||
}
|
||||
print_menu(menu_win, highlight);
|
||||
if(choice != 0) /* User did a choice come out of the infinite loop */
|
||||
break;
|
||||
}
|
||||
mvprintw(23, 0, "You chose choice %d with choice string %s\n", choice, choices[choice - 1]);
|
||||
clrtoeol();
|
||||
refresh();
|
||||
sleep(1);
|
||||
endwin();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void print_menu(WINDOW *menu_win, int highlight)
|
||||
{
|
||||
int x, y, i;
|
||||
|
||||
x = 2;
|
||||
y = 2;
|
||||
box(menu_win, 0, 0);
|
||||
for(i = 0; i < n_choices; ++i)
|
||||
{ if(highlight == i + 1) /* High light the present choice */
|
||||
{ wattron(menu_win, A_REVERSE);
|
||||
mvwprintw(menu_win, y, x, "%s", choices[i]);
|
||||
wattroff(menu_win, A_REVERSE);
|
||||
}
|
||||
else
|
||||
mvwprintw(menu_win, y, x, "%s", choices[i]);
|
||||
++y;
|
||||
}
|
||||
wrefresh(menu_win);
|
||||
}
|
||||
132
_deprecated/Ncurses/mouse_menu.c
Normal file
132
_deprecated/Ncurses/mouse_menu.c
Normal file
@@ -0,0 +1,132 @@
|
||||
#include <ncurses.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#define WIDTH 30
|
||||
#define HEIGHT 10
|
||||
|
||||
int startx = 0;
|
||||
int starty = 0;
|
||||
|
||||
char *choices[] = { "Choice 1",
|
||||
"Choice 2",
|
||||
"Choice 3",
|
||||
"Choice 4",
|
||||
"Exit",
|
||||
};
|
||||
|
||||
int n_choices = sizeof(choices) / sizeof(char *);
|
||||
|
||||
void print_menu(WINDOW *menu_win, int choice);
|
||||
void report_choice(int mouse_x, int mouse_y, int *p_choice);
|
||||
|
||||
int main()
|
||||
{ int c, choice = 0, highlight = 1;
|
||||
WINDOW *menu_win;
|
||||
MEVENT event;
|
||||
|
||||
/* Initialize curses */
|
||||
initscr();
|
||||
clear();
|
||||
noecho();
|
||||
cbreak(); //Line buffering disabled. pass on everything
|
||||
|
||||
/* Try to put the window in the middle of screen */
|
||||
startx = (80 - WIDTH) / 2;
|
||||
starty = (24 - HEIGHT) / 2;
|
||||
|
||||
attron(A_REVERSE);
|
||||
mvprintw(23, 1, "startx=%d, starty=%d", startx, starty);
|
||||
refresh();
|
||||
attroff(A_REVERSE);
|
||||
|
||||
/* Print the menu for the first time */
|
||||
menu_win = newwin(HEIGHT, WIDTH, starty, startx);
|
||||
keypad(menu_win, TRUE);
|
||||
print_menu(menu_win, 1);
|
||||
/* Get all the mouse events */
|
||||
mousemask(ALL_MOUSE_EVENTS, NULL);
|
||||
while(1)
|
||||
{ c = wgetch(menu_win);
|
||||
mvprintw(4, 1, "Character pressed is = %3d", c);
|
||||
refresh();
|
||||
switch(c)
|
||||
{ case KEY_MOUSE:
|
||||
if(getmouse(&event) == OK){ /* When the user clicks left mouse button */
|
||||
mvprintw(5, 1, "x=%d, y=%d, bstate=0x%08x", event.x, event.y, event.bstate);
|
||||
clrtoeol();
|
||||
refresh();
|
||||
if(event.bstate & (BUTTON1_PRESSED|BUTTON1_CLICKED))
|
||||
{
|
||||
report_choice(event.x + 1, event.y + 1, &choice);
|
||||
if(choice == -1) //Exit chosen
|
||||
goto end;
|
||||
mvprintw(22, 1, "Choice made is : %d String Chosen is \"%10s\"", choice, choices[choice - 1]);
|
||||
clrtoeol();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KEY_UP:
|
||||
refresh();
|
||||
if(highlight == 1)
|
||||
highlight = n_choices;
|
||||
else
|
||||
--highlight;
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
if(highlight == n_choices)
|
||||
highlight = 1;
|
||||
else
|
||||
++highlight;
|
||||
break;
|
||||
case 10:
|
||||
choice = highlight;
|
||||
mvprintw(2, 1, "Choice: %d", choice);
|
||||
break;
|
||||
}
|
||||
print_menu(menu_win, highlight);
|
||||
refresh();
|
||||
if(choice == n_choices) break;
|
||||
}
|
||||
end:
|
||||
endwin();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void print_menu(WINDOW *menu_win, int choice)
|
||||
{
|
||||
int x, y, i;
|
||||
|
||||
x = 2;
|
||||
y = 2;
|
||||
box(menu_win, 0, 0);
|
||||
for(i = 0; i < n_choices; ++i)
|
||||
{ if(choice == i + 1)
|
||||
{ wattron(menu_win, A_REVERSE);
|
||||
mvwprintw(menu_win, y, x, "%s", choices[i]);
|
||||
wattroff(menu_win, A_REVERSE);
|
||||
}
|
||||
else
|
||||
mvwprintw(menu_win, y, x, "%s", choices[i]);
|
||||
++y;
|
||||
}
|
||||
wrefresh(menu_win);
|
||||
}
|
||||
|
||||
/* Report the choice according to mouse position */
|
||||
void report_choice(int mouse_x, int mouse_y, int *p_choice)
|
||||
{ int i,j, choice;
|
||||
|
||||
i = startx + 2;
|
||||
j = starty + 3;
|
||||
|
||||
for(choice = 0; choice < n_choices; ++choice)
|
||||
if(mouse_y == j + choice && mouse_x >= i && mouse_x <= i + (int)strlen(choices[choice]))
|
||||
{ if(choice == n_choices - 1)
|
||||
*p_choice = -1;
|
||||
else
|
||||
*p_choice = choice + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
1
_deprecated/Ncurses/ncurses.cflags
Normal file
1
_deprecated/Ncurses/ncurses.cflags
Normal file
@@ -0,0 +1 @@
|
||||
-std=c17
|
||||
2
_deprecated/Ncurses/ncurses.config
Normal file
2
_deprecated/Ncurses/ncurses.config
Normal file
@@ -0,0 +1,2 @@
|
||||
// Add predefined macros for your project here. For example:
|
||||
// #define THE_ANSWER 42
|
||||
1
_deprecated/Ncurses/ncurses.creator
Normal file
1
_deprecated/Ncurses/ncurses.creator
Normal file
@@ -0,0 +1 @@
|
||||
[General]
|
||||
1
_deprecated/Ncurses/ncurses.cxxflags
Normal file
1
_deprecated/Ncurses/ncurses.cxxflags
Normal file
@@ -0,0 +1 @@
|
||||
-std=c++17
|
||||
7
_deprecated/Ncurses/ncurses.files
Normal file
7
_deprecated/Ncurses/ncurses.files
Normal file
@@ -0,0 +1,7 @@
|
||||
acs.c
|
||||
menu.c
|
||||
mouse_menu.c
|
||||
ncurses_and_readline.c
|
||||
rolling.c
|
||||
scroll.c
|
||||
scrollfile.c
|
||||
1
_deprecated/Ncurses/ncurses.includes
Normal file
1
_deprecated/Ncurses/ncurses.includes
Normal file
@@ -0,0 +1 @@
|
||||
.
|
||||
336
_deprecated/Ncurses/ncurses_and_readline.c
Normal file
336
_deprecated/Ncurses/ncurses_and_readline.c
Normal file
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* This file is part of the ncurses project.
|
||||
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// based on https://stackoverflow.com/a/28709979/1965803 ->
|
||||
// https://github.com/ulfalizer/readline-and-ncurses
|
||||
// Copyright (c) 2015-2019, Ulf Magnusson
|
||||
// SPDX-License-Identifier: ISC
|
||||
|
||||
#include <curses.h>
|
||||
#include <readline/history.h>
|
||||
#include <readline/readline.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// Keeps track of the terminal mode so we can reset the terminal if needed on errors
|
||||
static bool visual_mode = false;
|
||||
// insert commands when true; roll upper screen when false
|
||||
static bool insert_mode = true;
|
||||
static bool should_exit = false;
|
||||
|
||||
static void fail_exit(const char *msg){
|
||||
// Make sure endwin() is only called in visual mode. As a note, calling it
|
||||
// twice does not seem to be supported and messed with the cursor position.
|
||||
if(visual_mode) endwin();
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static WINDOW *msg_win; // Message window
|
||||
static WINDOW *sep_win; // Separator line above the command (readline) window
|
||||
static WINDOW *cmd_win; // Command (readline) window
|
||||
|
||||
// string list
|
||||
typedef struct _Line{
|
||||
int Nline;
|
||||
char *contents;
|
||||
struct _Line *prev, *next;
|
||||
} Line;
|
||||
// head of list, current item and first line on screen
|
||||
Line *head = NULL, *curr = NULL, *firstline = NULL;
|
||||
int nr_lines = 0; // total anount of data portions @ input
|
||||
|
||||
static unsigned char input; // Input character for readline
|
||||
|
||||
// Used to signal "no more input" after feeding a character to readline
|
||||
static bool input_avail = false;
|
||||
|
||||
// Not bothering with 'input_avail' and just returning 0 here seems to do the
|
||||
// right thing too, but this might be safer across readline versions
|
||||
static int readline_input_avail(){
|
||||
return input_avail;
|
||||
}
|
||||
|
||||
static int readline_getc(__attribute__((__unused__)) FILE *dummy){
|
||||
input_avail = false;
|
||||
return input;
|
||||
}
|
||||
|
||||
static void forward_to_readline(char c){
|
||||
input = c;
|
||||
input_avail = true;
|
||||
rl_callback_read_char();
|
||||
}
|
||||
|
||||
static void msg_win_redisplay(bool for_resize){
|
||||
werase(msg_win);
|
||||
Line *l = firstline;
|
||||
int nlines = 0; // total amount of lines @ output
|
||||
for(; l && (nlines < LINES - 2); l = l->next){
|
||||
size_t contlen = strlen(l->contents) + 128;
|
||||
char *buf = malloc(contlen);
|
||||
// don't add trailing '\n' (or last line will be empty with cursor)
|
||||
contlen = snprintf(buf, contlen, "%s", l->contents);
|
||||
int nlnext = (contlen - 1) / COLS + 1;
|
||||
wmove(msg_win, nlines, 0);
|
||||
if(nlines + nlnext < LINES-2){ // can put out the full line
|
||||
waddstr(msg_win, buf);
|
||||
//wprintw(msg_win, "%d (%d): %s -> %d", l->Nline, firstline->Nline, l->contents, nlnext);
|
||||
nlines += nlnext;
|
||||
}else{ // put only first part
|
||||
int rest = LINES-2 - nlines;
|
||||
waddnstr(msg_win, buf, rest *COLS);
|
||||
break;
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
curs_set(0);
|
||||
if(for_resize) wnoutrefresh(msg_win);
|
||||
else wrefresh(msg_win);
|
||||
}
|
||||
|
||||
static void got_command(char *line){
|
||||
if(!line) // Ctrl-D pressed on empty line
|
||||
should_exit = true;
|
||||
else{
|
||||
if(!*line) return; // zero length
|
||||
add_history(line);
|
||||
Line *lp = malloc(sizeof(Line));
|
||||
lp->contents = line;
|
||||
lp->prev = curr;
|
||||
lp->next = NULL;
|
||||
lp->Nline = nr_lines++;
|
||||
if(!curr || !head){
|
||||
head = curr = firstline = lp;
|
||||
}else
|
||||
curr->next = lp;
|
||||
curr = lp;
|
||||
// roll back to show last input
|
||||
if(curr->prev){
|
||||
firstline = curr;
|
||||
int totalln = (strlen(firstline->contents) - 1)/COLS + 1;
|
||||
while(firstline->prev){
|
||||
totalln += (strlen(firstline->prev->contents) - 1)/COLS + 1;
|
||||
if(totalln > LINES-2) break;
|
||||
firstline = firstline->prev;
|
||||
}
|
||||
}
|
||||
msg_win_redisplay(false);
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_win_redisplay(bool for_resize){
|
||||
int cursor_col = 2 + rl_point; // "> " width is 2
|
||||
werase(cmd_win);
|
||||
int x = 0, maxw = COLS-2;
|
||||
if(cursor_col > maxw){
|
||||
x = cursor_col - maxw;
|
||||
cursor_col = maxw;
|
||||
}
|
||||
char abuf[4096];
|
||||
snprintf(abuf, 4096, "> %s", rl_line_buffer);
|
||||
waddstr(cmd_win, abuf+x);
|
||||
wmove(cmd_win, 0, cursor_col);
|
||||
curs_set(2);
|
||||
if(for_resize) wnoutrefresh(cmd_win);
|
||||
else wrefresh(cmd_win);
|
||||
}
|
||||
|
||||
static void readline_redisplay(void){
|
||||
cmd_win_redisplay(false);
|
||||
}
|
||||
|
||||
static void show_mode(bool for_resize){
|
||||
wclear(sep_win);
|
||||
if(insert_mode) waddstr(sep_win, "INSERT (TAB to switch, ctrl+D to quit)");
|
||||
else waddstr(sep_win, "SCROLL (TAB to switch, q to quit)");
|
||||
if(for_resize) wnoutrefresh(sep_win);
|
||||
else wrefresh(sep_win);
|
||||
cmd_win_redisplay(for_resize);
|
||||
}
|
||||
|
||||
static void resize(void){
|
||||
if(LINES > 2){
|
||||
wresize(msg_win, LINES - 2, COLS);
|
||||
wresize(sep_win, 1, COLS);
|
||||
wresize(cmd_win, 1, COLS);
|
||||
mvwin(sep_win, LINES - 2, 0);
|
||||
mvwin(cmd_win, LINES - 1, 0);
|
||||
}
|
||||
msg_win_redisplay(true);
|
||||
show_mode(true);
|
||||
doupdate();
|
||||
}
|
||||
|
||||
static void init_ncurses(void){
|
||||
if (!initscr())
|
||||
fail_exit("Failed to initialize ncurses");
|
||||
visual_mode = true;
|
||||
if(has_colors()){
|
||||
start_color();
|
||||
use_default_colors();
|
||||
}
|
||||
cbreak();
|
||||
noecho();
|
||||
nonl();
|
||||
intrflush(NULL, FALSE);
|
||||
// Do not enable keypad() since we want to pass unadulterated input to readline
|
||||
keypad(cmd_win, 0);
|
||||
// Explicitly specify a "very visible" cursor to make sure it's at least
|
||||
// consistent when we turn the cursor on and off (maybe it would make sense
|
||||
// to query it and use the value we get back too). "normal" vs. "very
|
||||
// visible" makes no difference in gnome-terminal or xterm. Let this fail
|
||||
// for terminals that do not support cursor visibility adjustments.
|
||||
curs_set(2);
|
||||
if(LINES > 2){
|
||||
msg_win = newwin(LINES - 2, COLS, 0, 0);
|
||||
sep_win = newwin(1, COLS, LINES - 2, 0);
|
||||
cmd_win = newwin(1, COLS, LINES - 1, 0);
|
||||
}
|
||||
else{
|
||||
// Degenerate case. Give the windows the minimum workable size to
|
||||
// prevent errors from e.g. wmove().
|
||||
msg_win = newwin(1, COLS, 0, 0);
|
||||
sep_win = newwin(1, COLS, 0, 0);
|
||||
cmd_win = newwin(1, COLS, 0, 0);
|
||||
}
|
||||
if(!msg_win || !sep_win || !cmd_win)
|
||||
fail_exit("Failed to allocate windows");
|
||||
// Allow strings longer than the command window and show only the last part if the string doesn't fit
|
||||
// scrollok(cmd_win, TRUE);
|
||||
if(has_colors()){
|
||||
// Use white-on-blue cells for the separator window...
|
||||
init_pair(1, COLOR_WHITE, COLOR_BLUE);
|
||||
wbkgd(sep_win, COLOR_PAIR(1));
|
||||
}
|
||||
else
|
||||
// ...or the "best highlighting mode of the terminal" if it doesn't
|
||||
// support colors
|
||||
wbkgd(sep_win, A_STANDOUT);
|
||||
show_mode(false);
|
||||
mousemask(BUTTON4_PRESSED|BUTTON5_PRESSED, NULL);
|
||||
}
|
||||
|
||||
static void deinit_ncurses(void){
|
||||
delwin(msg_win);
|
||||
delwin(sep_win);
|
||||
delwin(cmd_win);
|
||||
endwin();
|
||||
visual_mode = false;
|
||||
}
|
||||
|
||||
static void init_readline(void){
|
||||
// Let ncurses do all terminal and signal handling
|
||||
rl_catch_signals = 0;
|
||||
rl_catch_sigwinch = 0;
|
||||
rl_deprep_term_function = NULL;
|
||||
rl_prep_term_function = NULL;
|
||||
// Prevent readline from setting the LINES and COLUMNS environment
|
||||
// variables, which override dynamic size adjustments in ncurses. When
|
||||
// using the alternate readline interface (as we do here), LINES and
|
||||
// COLUMNS are not updated if the terminal is resized between two calls to
|
||||
// rl_callback_read_char() (which is almost always the case).
|
||||
rl_change_environment = 0;
|
||||
// Handle input by manually feeding characters to readline
|
||||
rl_getc_function = readline_getc;
|
||||
rl_input_available_hook = readline_input_avail;
|
||||
rl_redisplay_function = readline_redisplay;
|
||||
rl_callback_handler_install("> ", got_command);
|
||||
}
|
||||
|
||||
static void deinit_readline(void){
|
||||
rl_callback_handler_remove();
|
||||
}
|
||||
|
||||
static void rolldown(){
|
||||
if(firstline && firstline->prev){
|
||||
firstline = firstline->prev;
|
||||
msg_win_redisplay(false);
|
||||
}
|
||||
}
|
||||
|
||||
static void rollup(){
|
||||
if(firstline && firstline->next){
|
||||
firstline = firstline->next;
|
||||
msg_win_redisplay(false);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void){
|
||||
init_ncurses();
|
||||
init_readline();
|
||||
MEVENT event;
|
||||
do{
|
||||
int c = wgetch(cmd_win);
|
||||
bool processed = true;
|
||||
switch(c){
|
||||
case KEY_MOUSE:
|
||||
if(getmouse(&event) == OK){
|
||||
if(event.bstate & (BUTTON4_PRESSED)) rolldown(); // wheel up
|
||||
else if(event.bstate & (BUTTON5_PRESSED)) rollup(); // wheel down
|
||||
}
|
||||
break;
|
||||
case '\t': // tab switch between scroll and edit mode
|
||||
keypad(cmd_win, insert_mode); // enable/disable reaction @ special characters
|
||||
insert_mode = !insert_mode;
|
||||
show_mode(false);
|
||||
break;
|
||||
case KEY_RESIZE:
|
||||
resize();
|
||||
break;
|
||||
default:
|
||||
processed = false;
|
||||
}
|
||||
if(processed) continue;
|
||||
if(insert_mode){
|
||||
forward_to_readline(c);
|
||||
}else{
|
||||
switch(c){
|
||||
case KEY_UP: // roll down for one item
|
||||
rolldown();
|
||||
break;
|
||||
case KEY_DOWN: // roll up for one item
|
||||
rollup();
|
||||
break;
|
||||
case KEY_PPAGE: // PageUp: roll down for 10 items
|
||||
for(int i = 0; i < 10; ++i){
|
||||
if(firstline && firstline->prev) firstline = firstline->prev;
|
||||
else break;
|
||||
}
|
||||
msg_win_redisplay(false);
|
||||
break;
|
||||
case KEY_NPAGE: // PageUp: roll up for 10 items
|
||||
for(int i = 0; i < 10; ++i){
|
||||
if(firstline && firstline->next) firstline = firstline->next;
|
||||
else break;
|
||||
}
|
||||
msg_win_redisplay(false);
|
||||
break;
|
||||
default:
|
||||
if(c == 'q' || c == 'Q') should_exit = true; // quit
|
||||
}
|
||||
}
|
||||
}while(!should_exit);
|
||||
deinit_ncurses();
|
||||
deinit_readline();
|
||||
puts("Shut down cleanly");
|
||||
return 0;
|
||||
}
|
||||
28
_deprecated/Ncurses/rolling.c
Normal file
28
_deprecated/Ncurses/rolling.c
Normal file
@@ -0,0 +1,28 @@
|
||||
#include <curses.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static int maxx, maxy;
|
||||
|
||||
|
||||
void initscreen(){
|
||||
initscr();
|
||||
getmaxyx(stdscr, maxy, maxx); // getyx - get current coords
|
||||
cbreak();
|
||||
keypad(stdscr, TRUE); // We get F1, F2 etc..
|
||||
noecho();
|
||||
nodelay(stdscr, TRUE); // getch() returns ERR if no keys pressed
|
||||
start_color();
|
||||
init_pair(1, COLOR_RED, COLOR_BLACK);
|
||||
init_pair(2, COLOR_GREEN, COLOR_BLACK);
|
||||
init_pair(3, COLOR_YELLOW, COLOR_BLACK);
|
||||
init_pair(4, COLOR_BLUE, COLOR_BLACK);
|
||||
init_pair(5, COLOR_MAGENTA, COLOR_BLACK);
|
||||
init_pair(6, COLOR_CYAN, COLOR_BLACK);
|
||||
init_pair(7, COLOR_WHITE, COLOR_BLACK);
|
||||
clear();
|
||||
}
|
||||
|
||||
int main(){
|
||||
initscreen();
|
||||
return 0;
|
||||
}
|
||||
110
_deprecated/Ncurses/scroll.c
Normal file
110
_deprecated/Ncurses/scroll.c
Normal file
@@ -0,0 +1,110 @@
|
||||
#include <ncurses.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MAXLEN 127
|
||||
|
||||
typedef struct Line {
|
||||
char *contents;
|
||||
struct Line *prev, *next;
|
||||
} Line;
|
||||
|
||||
char inputstr[MAXLEN+1] = {0};
|
||||
int currinp = 0;
|
||||
|
||||
Line *head = NULL, *curr = NULL, *firstline = NULL;
|
||||
|
||||
int refreshmain = 1, refreshstr = 1;
|
||||
|
||||
int nr_lines;
|
||||
int curr_line;
|
||||
WINDOW *mainwin, *onestring;
|
||||
|
||||
int term_rows, term_cols;
|
||||
|
||||
void draw(Line *l);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Line *lp;
|
||||
// printf("\033c"); - cls
|
||||
initscr();
|
||||
noecho();
|
||||
getmaxyx(stdscr, term_rows, term_cols);
|
||||
term_rows -= 2;
|
||||
mainwin = newwin(term_rows, term_cols, 0, 0);
|
||||
onestring = newwin(1, term_cols, term_rows+1, 0);
|
||||
keypad(onestring, TRUE); // for KEY_UP, KEY_DOWN
|
||||
|
||||
curr_line = 0;
|
||||
|
||||
draw(curr);
|
||||
|
||||
int ch;
|
||||
while ((ch = wgetch(onestring)) != EOF)
|
||||
{
|
||||
if (ch == KEY_UP && firstline->prev != NULL)
|
||||
{
|
||||
curr_line--;
|
||||
firstline = firstline->prev;
|
||||
refreshmain = 1;
|
||||
}
|
||||
else if (ch == KEY_DOWN && firstline->next != NULL && curr_line + term_rows < nr_lines)
|
||||
{
|
||||
curr_line++;
|
||||
firstline = firstline->next;
|
||||
refreshmain = 1;
|
||||
}
|
||||
else if(ch == 10 && currinp){
|
||||
lp = malloc(sizeof(Line));
|
||||
lp->contents = strdup(inputstr);
|
||||
lp->prev = curr;
|
||||
lp->next = NULL;
|
||||
if(!curr || !head){
|
||||
head = curr = firstline = lp;
|
||||
}else
|
||||
curr->next = lp;
|
||||
curr = lp;
|
||||
++nr_lines;
|
||||
while(nr_lines - curr_line > term_rows){
|
||||
curr_line++;
|
||||
firstline = firstline->next;
|
||||
}
|
||||
currinp = 0;
|
||||
inputstr[0] = 0;
|
||||
refreshstr = 1;
|
||||
refreshmain = 1;
|
||||
}else if(ch >= ' ' && ch < 256 && ch != 127){
|
||||
if(currinp > MAXLEN){
|
||||
wclear(onestring);
|
||||
waddstr(onestring, "Limit reached!");
|
||||
wrefresh(onestring);
|
||||
}else{
|
||||
inputstr[currinp++] = ch;
|
||||
inputstr[currinp] = 0;
|
||||
}
|
||||
refreshstr = 1;
|
||||
}
|
||||
draw(firstline);
|
||||
}
|
||||
|
||||
endwin();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void draw(Line *l){
|
||||
if(refreshmain){
|
||||
refreshmain = 0;
|
||||
wclear(mainwin);
|
||||
for(int i = 0; i < term_rows && l != NULL; i++, l = l->next)
|
||||
wprintw(mainwin, "%s\n", l->contents);
|
||||
wrefresh(mainwin);
|
||||
}
|
||||
if(refreshstr){
|
||||
refreshstr = 0;
|
||||
wclear(onestring);
|
||||
wprintw(onestring, " > %s", inputstr);
|
||||
wrefresh(onestring);
|
||||
}
|
||||
}
|
||||
128
_deprecated/Ncurses/scrollfile.c
Normal file
128
_deprecated/Ncurses/scrollfile.c
Normal file
@@ -0,0 +1,128 @@
|
||||
#include <ncurses.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MAXLEN 128
|
||||
|
||||
typedef struct Line {
|
||||
char contents[MAXLEN];
|
||||
struct Line *prev, *next;
|
||||
} Line;
|
||||
|
||||
#define MAXSTRL 120
|
||||
char inputstr[MAXSTRL+1] = {0};
|
||||
int currinp = 0;
|
||||
|
||||
Line *head, *curr;
|
||||
|
||||
int refreshmain = 1, refreshstr = 1;
|
||||
|
||||
int nr_lines;
|
||||
int curr_line;
|
||||
WINDOW *mainwin, *onestring;
|
||||
|
||||
int term_rows, term_cols;
|
||||
|
||||
void load(const char *filename);
|
||||
void draw(Line *l);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc == 1)
|
||||
{
|
||||
fputs("less: No file to open\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
initscr();
|
||||
noecho();
|
||||
getmaxyx(stdscr, term_rows, term_cols);
|
||||
term_rows -= 2;
|
||||
mainwin = newwin(term_rows, term_cols, 0, 0);
|
||||
onestring = newwin(1, term_cols, term_rows+1, 0);
|
||||
keypad(onestring, TRUE); // for KEY_UP, KEY_DOWN
|
||||
|
||||
waddstr(mainwin, "Reading text...\n");
|
||||
wrefresh(mainwin);
|
||||
sleep(1);
|
||||
load(argv[1]);
|
||||
|
||||
curr = head;
|
||||
curr_line = 0;
|
||||
|
||||
draw(curr);
|
||||
|
||||
int ch;
|
||||
while ((ch = wgetch(onestring)) != EOF)
|
||||
{
|
||||
if (ch == KEY_UP && curr->prev != NULL)
|
||||
{
|
||||
curr_line--;
|
||||
curr = curr->prev;
|
||||
refreshmain = 1;
|
||||
}
|
||||
else if (ch == KEY_DOWN && curr->next != NULL
|
||||
&& curr_line + term_rows < nr_lines)
|
||||
{
|
||||
curr_line++;
|
||||
curr = curr->next;
|
||||
refreshmain = 1;
|
||||
}
|
||||
else if(ch == 10){
|
||||
currinp = 0;
|
||||
inputstr[0] = 0;
|
||||
refreshstr = 1;
|
||||
}else if(ch >= ' ' && ch < 256 && ch != 127){
|
||||
if(currinp > MAXSTRL){
|
||||
wclear(onestring);
|
||||
waddstr(onestring, "Limit reached!");
|
||||
wrefresh(onestring);
|
||||
}else{
|
||||
inputstr[currinp++] = ch;
|
||||
inputstr[currinp] = 0;
|
||||
}
|
||||
refreshstr = 1;
|
||||
}
|
||||
draw(curr);
|
||||
}
|
||||
|
||||
endwin();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void load(const char *filename)
|
||||
{
|
||||
FILE *fp = fopen(filename, "r");
|
||||
Line *lp;
|
||||
|
||||
head = malloc(sizeof(Line));
|
||||
head->prev = head->next = NULL;
|
||||
curr = head;
|
||||
|
||||
while (fgets(curr->contents, MAXLEN, fp))
|
||||
{
|
||||
lp = malloc(sizeof(Line));
|
||||
lp->prev = curr;
|
||||
curr->next = lp;
|
||||
curr = lp;
|
||||
nr_lines++;
|
||||
}
|
||||
curr->next = NULL;
|
||||
}
|
||||
|
||||
void draw(Line *l)
|
||||
{
|
||||
if(refreshmain){
|
||||
refreshmain = 0;
|
||||
wclear(mainwin);
|
||||
for(int i = 0; i < term_rows && l != NULL; i++, l = l->next)
|
||||
waddstr(mainwin, l->contents);
|
||||
wrefresh(mainwin);
|
||||
}
|
||||
if(refreshstr){
|
||||
refreshstr = 0;
|
||||
wclear(onestring);
|
||||
wprintw(onestring, " > %s", inputstr);
|
||||
wrefresh(onestring);
|
||||
}
|
||||
}
|
||||
22
_deprecated/SMSD-1.5/Makefile
Normal file
22
_deprecated/SMSD-1.5/Makefile
Normal 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)
|
||||
3
_deprecated/SMSD-1.5/README
Normal file
3
_deprecated/SMSD-1.5/README
Normal file
@@ -0,0 +1,3 @@
|
||||
Simple CLI interface for motorized linear translator Standa 8MT175-150 moving by SMSD-1.5 driver
|
||||
|
||||
Run ./client & press h for help.
|
||||
499
_deprecated/SMSD-1.5/client.c
Normal file
499
_deprecated/SMSD-1.5/client.c
Normal file
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
* 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;
|
||||
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\tStop/start motor when program is running\n"
|
||||
"A\tRun previous command again or stop when running\n"
|
||||
"E\tErase previous program from controller's memory\n"
|
||||
"R\tTurn relay ON\n"
|
||||
"r\tTurn relay OFF\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(bus_error == COMMAND_ERR){ // motor is moving
|
||||
printf("Found running program, stop it\n");
|
||||
if(!send_command("ST1*"))
|
||||
send_command("SP*");
|
||||
send_command("LD1*");
|
||||
}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];
|
||||
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) * 16; // microstepping
|
||||
if(stepsN < 0 || stepsN > 10000000){
|
||||
fprintf(stderr, "\n\nSteps amount should be > -1 and < 625000 (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
|
||||
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 (625 steps per second with 1/16)
|
||||
}
|
||||
}
|
||||
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*");
|
||||
break;
|
||||
case 'E':
|
||||
erase_ctrlr();
|
||||
break;
|
||||
case 'R':
|
||||
Die_on_error("SF*");
|
||||
break;
|
||||
case 'r':
|
||||
Die_on_error("CF*");
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
45
_deprecated/Socket_snippet/Makefile
Normal file
45
_deprecated/Socket_snippet/Makefile
Normal file
@@ -0,0 +1,45 @@
|
||||
# run `make DEF=...` to add extra defines
|
||||
PROGRAM := socket
|
||||
LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all
|
||||
LDFLAGS += -lusefull_macros -lm -L/usr/local/lib/
|
||||
SRCS := $(wildcard *.c)
|
||||
DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111
|
||||
OBJDIR := mk
|
||||
CFLAGS += -O3 -Wno-trampolines -std=gnu99
|
||||
OBJS := $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.o))
|
||||
DEPS := $(OBJS:.o=.d)
|
||||
CC = gcc
|
||||
#CXX = g++
|
||||
|
||||
|
||||
all : $(PROGRAM)
|
||||
|
||||
debug: CFLAGS += -DEBUG -Werror -Wall -Wextra
|
||||
debug: all
|
||||
|
||||
$(OBJS): $(OBJDIR)
|
||||
|
||||
$(PROGRAM) : $(OBJS)
|
||||
@echo -e "\t\tLD $(PROGRAM)"
|
||||
$(CC) $(OBJS) $(LDFLAGS) -o $(PROGRAM)
|
||||
|
||||
$(OBJDIR):
|
||||
mkdir $(OBJDIR)
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
-include $(DEPS)
|
||||
endif
|
||||
|
||||
$(OBJDIR)/%.o: %.c
|
||||
@echo -e "\t\tCC $<"
|
||||
$(CC) $< -MD -c $(CFLAGS) $(DEFINES) -o $@
|
||||
|
||||
clean:
|
||||
@echo -e "\t\tCLEAN"
|
||||
@rm -f $(OBJS) $(DEPS)
|
||||
@rmdir $(OBJDIR) 2>/dev/null || true
|
||||
|
||||
xclean: clean
|
||||
@rm -f $(PROGRAM)
|
||||
|
||||
.PHONY: clean xclean
|
||||
7
_deprecated/Socket_snippet/Readme.md
Normal file
7
_deprecated/Socket_snippet/Readme.md
Normal file
@@ -0,0 +1,7 @@
|
||||
Socket server and client snippet
|
||||
================================
|
||||
|
||||
This snippet allows to create some utilities than can be run both in client or server mode.
|
||||
The sockets are **local** TCP or UNIX sockets. Server-side polling use `poll()`.
|
||||
|
||||
The pieces of user code may be in comments marked `USERCODE`
|
||||
120
_deprecated/Socket_snippet/client.c
Normal file
120
_deprecated/Socket_snippet/client.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* This file is part of the socksnippet project.
|
||||
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// client-side functions
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <usefull_macros.h>
|
||||
|
||||
#include "client.h"
|
||||
#include "socket.h"
|
||||
|
||||
/**
|
||||
* @brief processData - process here some actions and make messages for server
|
||||
* @param buf (o) - buffer for answer
|
||||
* @param l - max length of buf
|
||||
* @return amount of answer bytes
|
||||
*/
|
||||
static int process_data(char *buf, int l){
|
||||
if(!buf || !l) return 0;
|
||||
/* USERCODE: get here some data to send */
|
||||
static double t0 = 0.;
|
||||
if(dtime() - t0 > 1.){
|
||||
t0 = dtime();
|
||||
// send random commands each 1 second
|
||||
int x = rand() % 600;
|
||||
const char *cmd = NULL;
|
||||
if(x < 100) cmd = "time";
|
||||
else if(x < 200) cmd = "getval1";
|
||||
else if(x < 300) cmd = "getval2";
|
||||
else if(x < 400) cmd = "ping";
|
||||
if(cmd) snprintf(buf, l, "%s", cmd);
|
||||
else{
|
||||
if(x < 500) snprintf(buf, l, "setval1=%d", rand() & 0xff);
|
||||
else snprintf(buf, l, "setval2=%d", rand() & 0xff);
|
||||
}
|
||||
return strlen(buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief process_server_message - parse messages from server and make an answer
|
||||
* @param buf (io) - incoming message (the answer will be in this buffer)
|
||||
* @param l - buff max length
|
||||
* @return amount of answer bytes
|
||||
*/
|
||||
static int process_server_message(char *buf, int l){
|
||||
/* USERCODE inside this funtion */
|
||||
if(!buf || !l) return 0;
|
||||
// just show on screen
|
||||
green("SERVER send: %s\n", buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* check data from fd (polling function for client)
|
||||
* @param fd - file descriptor
|
||||
* @return 0 in case of timeout, 1 in case of fd have data, -1 if error
|
||||
*/
|
||||
static int canberead(int fd){
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 100;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
do{
|
||||
int rc = select(fd+1, &fds, NULL, NULL, &timeout);
|
||||
if(rc < 0){
|
||||
if(errno != EINTR){
|
||||
LOGWARN("select()");
|
||||
WARN("select()");
|
||||
return -1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}while(1);
|
||||
if(FD_ISSET(fd, &fds)){
|
||||
//DBG("FD_ISSET");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void client(int sock){
|
||||
char buf[BUFLEN];
|
||||
while(1){
|
||||
int l = process_data(buf, BUFLEN-1);
|
||||
if(l) sendmessage(sock, buf, l);
|
||||
if(1 != canberead(sock)) continue;
|
||||
int n = read(sock, buf, BUFLEN-1);
|
||||
if(n == 0){
|
||||
WARNX("Server disconnected");
|
||||
signals(0);
|
||||
}
|
||||
buf[n] = 0;
|
||||
DBG("Got from server: %s", buf);
|
||||
LOGMSG("Got from server: %s", buf);
|
||||
l = process_server_message(buf, n);
|
||||
if(l) sendmessage(sock, buf, l);
|
||||
}
|
||||
}
|
||||
26
_deprecated/Socket_snippet/client.h
Normal file
26
_deprecated/Socket_snippet/client.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This file is part of the socksnippet project.
|
||||
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef CLIENT_H__
|
||||
#define CLIENT_H__
|
||||
|
||||
// client-side functions
|
||||
void client(int fd);
|
||||
|
||||
#endif // CLIENT_H__
|
||||
83
_deprecated/Socket_snippet/cmdlnopts.c
Normal file
83
_deprecated/Socket_snippet/cmdlnopts.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* This file is part of the socksnippet project.
|
||||
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "cmdlnopts.h"
|
||||
#include "usefull_macros.h"
|
||||
|
||||
// default PID filename:
|
||||
#define DEFAULT_PIDFILE "/tmp/usbsock.pid"
|
||||
|
||||
static int help;
|
||||
static glob_pars G = {
|
||||
.pidfile = DEFAULT_PIDFILE,
|
||||
};
|
||||
glob_pars *GP = &G;
|
||||
|
||||
/*
|
||||
* Define command line options by filling structure:
|
||||
* name has_arg flag val type argptr help
|
||||
*/
|
||||
static myoption cmdlnopts[] = {
|
||||
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), _("show this help")},
|
||||
{"logfile", NEED_ARG, NULL, 'l', arg_string, APTR(&G.logfile), _("file to save logs (default: none)")},
|
||||
{"pidfile", NEED_ARG, NULL, 'p', arg_string, APTR(&G.pidfile), _("pidfile (default: " DEFAULT_PIDFILE ")")},
|
||||
{"client", NO_ARGS, NULL, 'c', arg_int, APTR(&G.client), _("run as client")},
|
||||
{"path", NEED_ARG, NULL, 'N', arg_string, APTR(&G.path), _("UNIX socket path/name (start from \\0 for no files)")},
|
||||
{"port", NEED_ARG, NULL, 'P', arg_string, APTR(&G.port), _("port to connect (for local TCP socket)")},
|
||||
{"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&G.verbose), _("increase log verbose level (default: LOG_WARN) and messages (default: none)")},
|
||||
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
|
||||
*/
|
||||
void parse_args(int argc, char **argv){
|
||||
int i;
|
||||
size_t hlen = 1024;
|
||||
char helpstring[1024], *hptr = helpstring;
|
||||
snprintf(hptr, hlen, "Usage: %%s [args]\n\n\tWhere args are:\n");
|
||||
// format of help: "Usage: progname [args]\n"
|
||||
change_helpstring(helpstring);
|
||||
// parse arguments
|
||||
parseargs(&argc, &argv, cmdlnopts);
|
||||
for(i = 0; i < argc; i++)
|
||||
printf("Ignore parameter\t%s\n", argv[i]);
|
||||
if(help) showhelp(-1, cmdlnopts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief verbose - print additional messages depending of G.verbose (add '\n' at end)
|
||||
* @param levl - message level
|
||||
* @param fmt - message
|
||||
*/
|
||||
void verbose(int levl, const char *fmt, ...){
|
||||
va_list ar;
|
||||
if(levl > G.verbose) return;
|
||||
va_start(ar, fmt);
|
||||
vprintf(fmt, ar);
|
||||
va_end(ar);
|
||||
printf("\n");
|
||||
}
|
||||
40
_deprecated/Socket_snippet/cmdlnopts.h
Normal file
40
_deprecated/Socket_snippet/cmdlnopts.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of the socksnippet project.
|
||||
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef CMDLNOPTS_H__
|
||||
#define CMDLNOPTS_H__
|
||||
|
||||
/*
|
||||
* here are some typedef's for global data
|
||||
*/
|
||||
typedef struct{
|
||||
char *pidfile; // name of PID file
|
||||
char *logfile; // logging to this file
|
||||
char *path; // path to UNIX-socket file
|
||||
char *port; // local TCP socket port
|
||||
int verbose; // verbose level: for messages & logging
|
||||
int client; // ==1 if application runs in client mode
|
||||
} glob_pars;
|
||||
|
||||
extern glob_pars *GP;
|
||||
|
||||
void parse_args(int argc, char **argv);
|
||||
void verbose(int levl, const char *fmt, ...);
|
||||
|
||||
#endif // CMDLNOPTS_H__
|
||||
108
_deprecated/Socket_snippet/main.c
Normal file
108
_deprecated/Socket_snippet/main.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of the socksnippet project.
|
||||
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <usefull_macros.h>
|
||||
|
||||
#include "cmdlnopts.h"
|
||||
#include "socket.h"
|
||||
|
||||
static pid_t childpid = 0;
|
||||
static int isserver = 1;
|
||||
|
||||
void signals(int sig){
|
||||
if(childpid){ // slave process
|
||||
DBG("Child killed with sig=%d", sig);
|
||||
LOGWARN("Child killed with sig=%d", sig);
|
||||
exit(sig);
|
||||
}
|
||||
// master process
|
||||
DBG("Master process");
|
||||
if(sig){
|
||||
DBG("Exit with signal %d", sig);
|
||||
signal(sig, SIG_IGN);
|
||||
LOGERR("Exit with signal %d", sig);
|
||||
}else LOGERR("Exit");
|
||||
if(GP->pidfile && isserver){
|
||||
DBG("Unlink pid file");
|
||||
unlink(GP->pidfile);
|
||||
}
|
||||
exit(sig);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
char *self = strdup(argv[0]);
|
||||
initial_setup();
|
||||
parse_args(argc, argv);
|
||||
if(GP->logfile){
|
||||
int lvl = LOGLEVEL_WARN + GP->verbose;
|
||||
DBG("level = %d", lvl);
|
||||
if(lvl > LOGLEVEL_ANY) lvl = LOGLEVEL_ANY;
|
||||
verbose(1, "Log file %s @ level %d\n", GP->logfile, lvl);
|
||||
OPENLOG(GP->logfile, lvl, 1);
|
||||
if(!globlog) WARNX("Can't create log file");
|
||||
}
|
||||
if(GP->client) isserver = 0;
|
||||
if(GP->port){
|
||||
if(GP->path){
|
||||
WARNX("Options `port` and `path` can't be used together! Point `port` for TCP socket or `path` for UNIX.");
|
||||
return 1;
|
||||
}
|
||||
int port = atoi(GP->port);
|
||||
if(port < PORTN_MIN || port > PORTN_MAX){
|
||||
WARNX("Wrong port value: %d", port);
|
||||
return 1;
|
||||
}
|
||||
}else if(!GP->path) ERRX("You should point option `port` or `path`!");
|
||||
|
||||
if(isserver) check4running(self, GP->pidfile);
|
||||
// signal reactions:
|
||||
signal(SIGTERM, signals); // kill (-15) - quit
|
||||
signal(SIGHUP, SIG_IGN); // hup - ignore
|
||||
signal(SIGINT, signals); // ctrl+C - quit
|
||||
signal(SIGQUIT, signals); // ctrl+\ - quit
|
||||
signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z
|
||||
LOGMSG("Started");
|
||||
#ifndef EBUG
|
||||
if(isserver){
|
||||
unsigned int pause = 5;
|
||||
while(1){
|
||||
childpid = fork();
|
||||
if(childpid){ // master
|
||||
double t0 = dtime();
|
||||
LOGMSG("Created child with pid %d", childpid);
|
||||
wait(NULL);
|
||||
LOGWARN("Child %d died", childpid);
|
||||
if(dtime() - t0 < 1.) pause += 5;
|
||||
else pause = 1;
|
||||
if(pause > 900) pause = 900;
|
||||
sleep(pause); // wait a little before respawn
|
||||
}else{ // slave
|
||||
prctl(PR_SET_PDEATHSIG, SIGTERM); // send SIGTERM to child when parent dies
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(GP->path) return start_socket(isserver, GP->path, FALSE);
|
||||
if(GP->port) return start_socket(isserver, GP->port, TRUE);
|
||||
}
|
||||
150
_deprecated/Socket_snippet/server.c
Normal file
150
_deprecated/Socket_snippet/server.c
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* This file is part of the socksnippet project.
|
||||
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <netdb.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <usefull_macros.h>
|
||||
|
||||
#include "server.h"
|
||||
#include "socket.h"
|
||||
|
||||
// server-side functions
|
||||
|
||||
// command handlers
|
||||
hresult pinghandler(int fd, _U_ const char *key, _U_ const char *val){
|
||||
sendstrmessage(fd, "PING");
|
||||
return RESULT_SILENCE;
|
||||
}
|
||||
|
||||
static int sendtime = 0;
|
||||
hresult timehandler(_U_ int fd, _U_ const char *key, _U_ const char *val){
|
||||
sendtime = 1;
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
static int value1 = 0, value2 = 0;
|
||||
hresult valsethandler(_U_ int fd, const char *key, const char *val){
|
||||
if(!val || !*val) return RESULT_BADVAL;
|
||||
int i = atoi(val);
|
||||
if(i < -65535 || i > 65535) return RESULT_BADVAL;
|
||||
if(strcmp(key, "setval1") == 0) value1 = i;
|
||||
else value2 = i;
|
||||
return RESULT_OK;
|
||||
}
|
||||
hresult valgethandler(int fd, const char *key, _U_ const char *val){
|
||||
char buf[32];
|
||||
if(strcmp(key, "getval1") == 0) snprintf(buf, 32, "VAL1=%d", value1);
|
||||
else snprintf(buf, 32, "VAL2=%d", value2);
|
||||
sendstrmessage(fd, buf);
|
||||
return RESULT_SILENCE;
|
||||
}
|
||||
|
||||
/*
|
||||
hresult handler(_U_ int fd, _U_ const char *key, _U_ const char *val){
|
||||
;
|
||||
}
|
||||
*/
|
||||
|
||||
static handleritem items[] = {
|
||||
{pinghandler, "ping"},
|
||||
{timehandler, "time"},
|
||||
{valsethandler, "setval1"},
|
||||
{valsethandler, "setval2"},
|
||||
{valgethandler, "getval1"},
|
||||
{valgethandler, "getval2"},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief processData - process here some actions and make messages for all clients
|
||||
* @param buf (o) - buffer for answer
|
||||
* @param l - max length of buf
|
||||
* @return amount of answer bytes
|
||||
*/
|
||||
static int process_data(char *buf, int l){
|
||||
if(!buf || !l) return 0;
|
||||
/* USERCODE: get here some data to send all clients */
|
||||
if(sendtime){
|
||||
snprintf(buf, l, "TIME=%.2f", dtime());
|
||||
sendtime = 0;
|
||||
return strlen(buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CLBUFSZ BUFSIZ
|
||||
|
||||
void server(int sock){
|
||||
if(listen(sock, MAXCLIENTS) == -1){
|
||||
WARN("listen");
|
||||
LOGWARN("listen");
|
||||
return;
|
||||
}
|
||||
int nfd = 1; // only one socket @start
|
||||
struct pollfd poll_set[MAXCLIENTS+1];
|
||||
char buffers[MAXCLIENTS][CLBUFSZ]; // buffers for data reading
|
||||
bzero(poll_set, sizeof(poll_set));
|
||||
// ZERO - listening server socket
|
||||
poll_set[0].fd = sock;
|
||||
poll_set[0].events = POLLIN;
|
||||
while(1){
|
||||
poll(poll_set, nfd, 1); // max timeout - 1ms
|
||||
if(poll_set[0].revents & POLLIN){ // check main for accept()
|
||||
struct sockaddr_in addr;
|
||||
socklen_t len = sizeof(addr);
|
||||
int client = accept(sock, (struct sockaddr*)&addr, &len);
|
||||
DBG("New connection");
|
||||
LOGMSG("SERVER got connection, fd=%d", client);
|
||||
if(nfd == MAXCLIENTS + 1){
|
||||
LOGWARN("Max amount of connections, disconnect fd=%d", client);
|
||||
WARNX("Limit of connections reached");
|
||||
close(client);
|
||||
}else{
|
||||
memset(&poll_set[nfd], 0, sizeof(struct pollfd));
|
||||
poll_set[nfd].fd = client;
|
||||
poll_set[nfd].events = POLLIN;
|
||||
++nfd;
|
||||
}
|
||||
}
|
||||
char buff[BUFLEN];
|
||||
int l = 0;
|
||||
// process some data & send messages to ALL
|
||||
if((l = process_data(buff, BUFLEN-1))){
|
||||
DBG("Send to %d clients", nfd - 1);
|
||||
for(int i = 1; i < nfd; ++i)
|
||||
sendmessage(poll_set[i].fd, buff, l);
|
||||
}
|
||||
// scan connections
|
||||
for(int fdidx = 1; fdidx < nfd; ++fdidx){
|
||||
if((poll_set[fdidx].revents & POLLIN) == 0) continue;
|
||||
int fd = poll_set[fdidx].fd;
|
||||
if(!processData(fd, items, buffers[fdidx-1], CLBUFSZ)){ // socket closed
|
||||
DBG("Client fd=%d disconnected", fd);
|
||||
LOGMSG("SERVER client fd=%d disconnected", fd);
|
||||
buffers[fdidx-1][0] = 0; // clear rest of data in buffer
|
||||
close(fd);
|
||||
// move last FD to current position
|
||||
poll_set[fdidx] = poll_set[nfd - 1];
|
||||
--nfd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
26
_deprecated/Socket_snippet/server.h
Normal file
26
_deprecated/Socket_snippet/server.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This file is part of the socksnippet project.
|
||||
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef SERVER_H__
|
||||
#define SERVER_H__
|
||||
|
||||
// server-side functions
|
||||
void server(int fd);
|
||||
|
||||
#endif // SERVER_H__
|
||||
213
_deprecated/Socket_snippet/socket.c
Normal file
213
_deprecated/Socket_snippet/socket.c
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* This file is part of the socksnippet project.
|
||||
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <ctype.h> // isspace
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/un.h> // unix socket
|
||||
#include <usefull_macros.h>
|
||||
|
||||
#include "cmdlnopts.h"
|
||||
#include "client.h"
|
||||
#include "server.h"
|
||||
#include "socket.h"
|
||||
|
||||
/**
|
||||
* @brief start_socket - create socket and run client or server
|
||||
* @param isserver - TRUE for server, FALSE for client
|
||||
* @param path - UNIX-socket path or local INET socket port
|
||||
* @param isnet - TRUE for INET socket, FALSE for UNIX
|
||||
* @return 0 if OK
|
||||
*/
|
||||
int start_socket(int isserver, char *path, int isnet){
|
||||
if(!path) return 1;
|
||||
DBG("path/port: %s", path);
|
||||
int sock = -1;
|
||||
struct addrinfo hints = {0}, *res;
|
||||
struct sockaddr_un unaddr = {0};
|
||||
if(isnet){
|
||||
DBG("Network socket");
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
if(getaddrinfo("127.0.0.1", path, &hints, &res) != 0){
|
||||
ERR("getaddrinfo");
|
||||
}
|
||||
}else{
|
||||
DBG("UNIX socket");
|
||||
char apath[128];
|
||||
if(*path == 0){
|
||||
DBG("convert name");
|
||||
apath[0] = 0;
|
||||
strncpy(apath+1, path+1, 126);
|
||||
}else if(strncmp("\\0", path, 2) == 0){
|
||||
DBG("convert name");
|
||||
apath[0] = 0;
|
||||
strncpy(apath+1, path+2, 126);
|
||||
}else strcpy(apath, path);
|
||||
unaddr.sun_family = AF_UNIX;
|
||||
hints.ai_addr = (struct sockaddr*) &unaddr;
|
||||
hints.ai_addrlen = sizeof(unaddr);
|
||||
memcpy(unaddr.sun_path, apath, 106); // if sun_path[0] == 0 we don't create a file
|
||||
hints.ai_family = AF_UNIX;
|
||||
hints.ai_socktype = SOCK_SEQPACKET;
|
||||
res = &hints;
|
||||
}
|
||||
for(struct addrinfo *p = res; p; p = p->ai_next){
|
||||
if((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0){ // or SOCK_STREAM?
|
||||
LOGWARN("socket()");
|
||||
WARN("socket()");
|
||||
continue;
|
||||
}
|
||||
if(isserver){
|
||||
int reuseaddr = 1;
|
||||
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)) == -1){
|
||||
LOGWARN("setsockopt()");
|
||||
WARN("setsockopt()");
|
||||
close(sock); sock = -1;
|
||||
continue;
|
||||
}
|
||||
if(bind(sock, p->ai_addr, p->ai_addrlen) == -1){
|
||||
LOGWARN("bind()");
|
||||
WARN("bind()");
|
||||
close(sock); sock = -1;
|
||||
continue;
|
||||
}
|
||||
int enable = 1;
|
||||
if(ioctl(sock, FIONBIO, (void *)&enable) < 0){ // make socket nonblocking
|
||||
LOGERR("Can't make socket nonblocking");
|
||||
ERRX("ioctl()");
|
||||
}
|
||||
}else{
|
||||
if(connect(sock, p->ai_addr, p->ai_addrlen) == -1){
|
||||
LOGWARN("connect()");
|
||||
WARN("connect()");
|
||||
close(sock); sock = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(sock < 0){
|
||||
LOGERR("Can't open socket");
|
||||
ERRX("Can't open socket");
|
||||
}
|
||||
if(isnet) freeaddrinfo(res);
|
||||
if(isserver) server(sock);
|
||||
else client(sock);
|
||||
close(sock);
|
||||
signals(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// simple wrapper over write: add missed newline and log data
|
||||
void sendmessage(int fd, const char *msg, int l){
|
||||
if(fd < 1 || !msg || l < 1) return;
|
||||
DBG("send to fd %d: %s [%d]", fd, msg, l);
|
||||
char *tmpbuf = MALLOC(char, l+1);
|
||||
memcpy(tmpbuf, msg, l);
|
||||
if(msg[l-1] != '\n') tmpbuf[l++] = '\n';
|
||||
if(l != send(fd, tmpbuf, l, MSG_NOSIGNAL)){
|
||||
LOGWARN("write()");
|
||||
WARN("write()");
|
||||
}else{
|
||||
if(globlog){ // logging turned ON
|
||||
tmpbuf[l-1] = 0; // remove trailing '\n' for logging
|
||||
LOGMSG("SEND to fd %d: %s", fd, tmpbuf);
|
||||
}
|
||||
}
|
||||
FREE(tmpbuf);
|
||||
}
|
||||
void sendstrmessage(int fd, const char *msg){
|
||||
if(fd < 1 || !msg) return;
|
||||
int l = strlen(msg);
|
||||
sendmessage(fd, msg, l);
|
||||
}
|
||||
|
||||
// text messages for `hresult`
|
||||
static const char *resmessages[] = {
|
||||
[RESULT_OK] = "OK",
|
||||
[RESULT_FAIL] = "FAIL",
|
||||
[RESULT_BADKEY] = "BADKEY",
|
||||
[RESULT_BADVAL] = "BADVAL",
|
||||
[RESULT_SILENCE] = "",
|
||||
};
|
||||
|
||||
const char *hresult2str(hresult r){
|
||||
if(r >= RESULT_NUM) return "BADRESULT";
|
||||
return resmessages[r];
|
||||
}
|
||||
|
||||
// parse string of data (command or key=val)
|
||||
// the CONTENT of buffer `str` WILL BE BROKEN!
|
||||
static void parsestring(int fd, handleritem *handlers, char *str){
|
||||
if(fd < 1 || !handlers || !handlers->key || !str || !*str) return;
|
||||
DBG("Got string %s", str);
|
||||
// remove starting spaces in key
|
||||
while(isspace(*str)) ++str;
|
||||
char *val = strchr(str, '=');
|
||||
if(val){ // get value: remove starting spaces in val
|
||||
*val++ = 0;
|
||||
while(isspace(*val)) ++val;
|
||||
}
|
||||
// remove trailing spaces in key
|
||||
char *e = str + strlen(str) - 1; // last key symbol
|
||||
while(isspace(*e) && e > str) --e;
|
||||
e[1] = 0;
|
||||
// now we have key (`str`) and val (or NULL)
|
||||
DBG("key=%s, val=%s", str, val);
|
||||
for(handleritem *h = handlers; h->handler; ++h){
|
||||
if(strcmp(str, h->key) == 0){ // found command
|
||||
if(h->handler){
|
||||
hresult r = h->handler(fd, str, val);
|
||||
sendstrmessage(fd, hresult2str(r));
|
||||
}else sendstrmessage(fd, resmessages[RESULT_FAIL]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
sendstrmessage(fd, resmessages[RESULT_BADKEY]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief processData - read (if available) data from fd and run processing, sending to fd messages for each command
|
||||
* @param fd - socket file descriptor
|
||||
* @param handlers - NULL-terminated array of handlers
|
||||
* @param buf (io) - zero-terminated buffer for storing rest of data (without newline), its content will be changed
|
||||
* @param buflen - its length
|
||||
* @return FALSE if client closed (nothing to read)
|
||||
*/
|
||||
int processData(int fd, handleritem *handlers, char *buf, int buflen){
|
||||
int curlen = strlen(buf);
|
||||
if(curlen == buflen-1) curlen = 0; // buffer overflow - clear old content
|
||||
ssize_t rd = read(fd, buf + curlen, buflen-1 - curlen);
|
||||
if(rd <= 0) return FALSE;
|
||||
DBG("got %s[%zd] from %d", buf, rd, fd);
|
||||
char *restofdata = buf, *eptr = buf + curlen + rd;
|
||||
*eptr = 0;
|
||||
do{
|
||||
char *nl = strchr(restofdata, '\n');
|
||||
if(!nl) break;
|
||||
*nl++ = 0;
|
||||
parsestring(fd, handlers, restofdata);
|
||||
restofdata = nl;
|
||||
DBG("rest of data: %s", restofdata);
|
||||
}while(1);
|
||||
if(restofdata != buf) memmove(buf, restofdata, eptr - restofdata + 1);
|
||||
return TRUE;
|
||||
}
|
||||
56
_deprecated/Socket_snippet/socket.h
Normal file
56
_deprecated/Socket_snippet/socket.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of the socksnippet project.
|
||||
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef SERSOCK_H__
|
||||
#define SERSOCK_H__
|
||||
|
||||
// max & min TCP socket port number
|
||||
#define PORTN_MAX (65535)
|
||||
#define PORTN_MIN (1024)
|
||||
|
||||
#define BUFLEN (1024)
|
||||
// Max amount of connections
|
||||
#define MAXCLIENTS (30)
|
||||
|
||||
typedef enum{
|
||||
RESULT_OK, // all OK
|
||||
RESULT_FAIL, // failed running command
|
||||
RESULT_BADVAL, // bad key's value
|
||||
RESULT_BADKEY, // bad key
|
||||
RESULT_SILENCE, // send nothing to client
|
||||
RESULT_NUM
|
||||
} hresult;
|
||||
|
||||
const char *hresult2str(hresult r);
|
||||
|
||||
// fd - socket fd to send private messages, key, val - key and its value
|
||||
typedef hresult (*mesghandler)(int fd, const char *key, const char *val);
|
||||
|
||||
typedef struct{
|
||||
mesghandler handler;
|
||||
const char *key;
|
||||
} handleritem;
|
||||
|
||||
int start_socket(int server, char *path, int isnet);
|
||||
void sendmessage(int fd, const char *msg, int l);
|
||||
void sendstrmessage(int fd, const char *msg);
|
||||
|
||||
int processData(int fd, handleritem *handlers, char *buf, int buflen);
|
||||
|
||||
#endif // SERSOCK_H__
|
||||
1
_deprecated/Socket_snippet/socksnippet.cflags
Normal file
1
_deprecated/Socket_snippet/socksnippet.cflags
Normal file
@@ -0,0 +1 @@
|
||||
-std=c17
|
||||
6
_deprecated/Socket_snippet/socksnippet.config
Normal file
6
_deprecated/Socket_snippet/socksnippet.config
Normal file
@@ -0,0 +1,6 @@
|
||||
// Add predefined macros for your project here. For example:
|
||||
// #define THE_ANSWER 42
|
||||
#define EBUG
|
||||
#define _GNU_SOURCE
|
||||
#define _XOPEN_SOURCE=1111
|
||||
|
||||
1
_deprecated/Socket_snippet/socksnippet.creator
Normal file
1
_deprecated/Socket_snippet/socksnippet.creator
Normal file
@@ -0,0 +1 @@
|
||||
[General]
|
||||
163
_deprecated/Socket_snippet/socksnippet.creator.user
Normal file
163
_deprecated/Socket_snippet/socksnippet.creator.user
Normal file
@@ -0,0 +1,163 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 6.0.0, 2022-02-02T17:26:10. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
<value type="QByteArray">{cf63021e-ef53-49b0-b03b-2f2570cdf3b6}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="int">0</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||
<value type="QString" key="language">Cpp</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||
<value type="QString" key="language">QmlJS</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||
<value type="QByteArray" key="EditorConfiguration.Codec">KOI8-R</value>
|
||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">false</value>
|
||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
|
||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">2</value>
|
||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">true</value>
|
||||
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<valuemap type="QVariantMap" key="ClangTools">
|
||||
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
|
||||
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||
<value type="int" key="ClangTools.ParallelJobs">4</value>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="CppEditor.QuickFix">
|
||||
<value type="bool" key="UseGlobalSettings">true</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="DeviceType">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{91347f2c-5221-46a7-80b1-0a054ca02f79}</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/eddy/Docs/SAO/ELECTRONICS/CAN_controller/Socket_CANserver</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Default</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||
<value type="int">1</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>Version</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
</qtcreator>
|
||||
1
_deprecated/Socket_snippet/socksnippet.cxxflags
Normal file
1
_deprecated/Socket_snippet/socksnippet.cxxflags
Normal file
@@ -0,0 +1 @@
|
||||
-std=c++17
|
||||
9
_deprecated/Socket_snippet/socksnippet.files
Normal file
9
_deprecated/Socket_snippet/socksnippet.files
Normal file
@@ -0,0 +1,9 @@
|
||||
client.c
|
||||
client.h
|
||||
cmdlnopts.c
|
||||
cmdlnopts.h
|
||||
main.c
|
||||
server.c
|
||||
server.h
|
||||
socket.c
|
||||
socket.h
|
||||
1
_deprecated/Socket_snippet/socksnippet.includes
Normal file
1
_deprecated/Socket_snippet/socksnippet.includes
Normal file
@@ -0,0 +1 @@
|
||||
.
|
||||
11
_deprecated/Socket_snippet/testcommands
Normal file
11
_deprecated/Socket_snippet/testcommands
Normal file
@@ -0,0 +1,11 @@
|
||||
time
|
||||
getval1
|
||||
setval1 = 56
|
||||
getval2
|
||||
setval2 = 189
|
||||
getval1 = asdf
|
||||
getval2 = 000000asdffd fdassdf fda
|
||||
time
|
||||
a
|
||||
getval1
|
||||
getval2
|
||||
6
_deprecated/astrosib/CMakeLists.txt
Normal file
6
_deprecated/astrosib/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
########## Tutorial two ##############
|
||||
add_executable(astrosib astrosib.cpp)
|
||||
|
||||
target_link_libraries(astrosib indidriver)
|
||||
|
||||
|
||||
6
_deprecated/astrosib/Readme.md
Normal file
6
_deprecated/astrosib/Readme.md
Normal file
@@ -0,0 +1,6 @@
|
||||
INDI driver for ASTROSIB telescopes
|
||||
|
||||
|
||||
|
||||
*Write at level upper to CMakeLists.txt:*
|
||||
add_subdirectory(astrosib)
|
||||
481
_deprecated/astrosib/astrosib.cpp
Normal file
481
_deprecated/astrosib/astrosib.cpp
Normal file
@@ -0,0 +1,481 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* astrosib.cpp
|
||||
*
|
||||
* Copyright 2017 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
INDI Developers Manual
|
||||
Tutorial #2
|
||||
|
||||
"Simple Telescope Driver"
|
||||
|
||||
We develop a simple telescope simulator.
|
||||
|
||||
Refer to README, which contains instruction on how to build this driver, and use it
|
||||
with an INDI-compatible client.
|
||||
|
||||
*/
|
||||
|
||||
/** \file simplescope.cpp
|
||||
\brief Construct a basic INDI telescope device that simulates GOTO commands.
|
||||
\author Jasem Mutlaq
|
||||
|
||||
\example simplescope.cpp
|
||||
A simple GOTO telescope that simulator slewing operation.
|
||||
*/
|
||||
|
||||
#include "astrosib.h"
|
||||
|
||||
#include "indicom.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <string.h>
|
||||
|
||||
// timer polling time
|
||||
#define POLLMS 1000
|
||||
|
||||
static const char *FOCUSER_TAB = "Focuser management";
|
||||
static const char *COOLER_TAB = "Cooler management";
|
||||
static const char *HEATER_TAB = "Heater management";
|
||||
|
||||
std::unique_ptr<AstroSib> aSib(new AstroSib());
|
||||
|
||||
/**************************************************************************************
|
||||
** Return properties of device.
|
||||
***************************************************************************************/
|
||||
void ISGetProperties(const char *dev){
|
||||
aSib->ISGetProperties(dev);
|
||||
}
|
||||
|
||||
/**************************************************************************************
|
||||
** Process new switch from client
|
||||
***************************************************************************************/
|
||||
void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n){
|
||||
aSib->ISNewSwitch(dev, name, states, names, n);
|
||||
}
|
||||
|
||||
/**************************************************************************************
|
||||
** Process new text from client
|
||||
***************************************************************************************/
|
||||
void ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n){
|
||||
aSib->ISNewText(dev, name, texts, names, n);
|
||||
}
|
||||
|
||||
/**************************************************************************************
|
||||
** Process new number from client
|
||||
***************************************************************************************/
|
||||
void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n){
|
||||
aSib->ISNewNumber(dev, name, values, names, n);
|
||||
}
|
||||
|
||||
/**************************************************************************************
|
||||
** Process new blob from client
|
||||
***************************************************************************************/
|
||||
void ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[],
|
||||
char *names[], int n){
|
||||
aSib->ISNewBLOB(dev, name, sizes, blobsizes, blobs, formats, names, n);
|
||||
}
|
||||
|
||||
/**************************************************************************************
|
||||
** Process snooped property from another driver
|
||||
***************************************************************************************/
|
||||
void ISSnoopDevice(XMLEle *root){
|
||||
INDI_UNUSED(root);
|
||||
}
|
||||
|
||||
AstroSib::AstroSib(){
|
||||
/* code should be here */
|
||||
//DBG_LEVEL = INDI::Logger::getInstance().addDebugLevel("Astrosib Verbose", "SCOPE");
|
||||
}
|
||||
|
||||
AstroSib::~AstroSib(){
|
||||
/* code should be here */
|
||||
if (isConnected()) AstroSib::Disconnect();
|
||||
}
|
||||
|
||||
/**************************************************************************************
|
||||
** We init our properties here. The only thing we want to init are the Debug controls
|
||||
***************************************************************************************/
|
||||
bool AstroSib::initProperties(){
|
||||
// ALWAYS call initProperties() of parent first
|
||||
INDI::DefaultDevice::initProperties();
|
||||
|
||||
// Shutter leaves
|
||||
IUFillSwitch(&ShtrsS[SHTR_OPENED], "SHTR_OPENED", "Open Scope", ISS_OFF);
|
||||
IUFillSwitch(&ShtrsS[SHTR_CLOSED], "SHTR_CLOSED", "Close Scope", ISS_ON);
|
||||
IUFillSwitchVector(&ShtrsSP, ShtrsS, 2, getDeviceName(), "SHTR_CONTROL", "Shutter Control",
|
||||
MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 1, IPS_OK);
|
||||
|
||||
// Mirror and ambient temperature
|
||||
IUFillNumber(&TempN[0], "MIRROR_TEMP", "Mirror temperature", "%.1f", -100., 100., 0.1, 0.);
|
||||
IUFillNumber(&TempN[1], "AMBIENT_TEMP", "Ambient temperature", "%.1f", -100., 100., 0.1, 0.);
|
||||
IUFillNumber(&TempN[2], "FOCUSER_TEMP", "Focuser temperature", "%.1f", -100., 100., 0.1, 0.);
|
||||
IUFillNumberVector(&TempNP, TempN, 3, getDeviceName(), "TEMPERATURE", "Temperature",
|
||||
MAIN_CONTROL_TAB, IP_RO, 1, IPS_IDLE);
|
||||
|
||||
// Focuser: current, relative and absolute position
|
||||
IUFillNumber(&FocuserN[0], "FOC_CUR", "Current focuser position", "%.0f", 0, 65536, 1, 0);
|
||||
IUFillNumber(&FocuserN[1], "FOC_REL", "Relative focuser position", "%.0f", -65536, 65536, 1, 0);
|
||||
IUFillNumber(&FocuserN[2], "FOC_ABS", "Absolute focuser position", "%.0f", 0, 65536, 1, 0);
|
||||
IUFillNumberVector(&FocuserNPcur, FocuserN, 1, getDeviceName(), "FOCUS_CUR", "Focuser current",
|
||||
FOCUSER_TAB, IP_RO, 1, IPS_IDLE);
|
||||
FocuserNPcur.s = IPS_OK;
|
||||
IUFillNumberVector(&FocuserNP, &FocuserN[1], 2, getDeviceName(), "FOCUS_SET", "Focuser set",
|
||||
FOCUSER_TAB, IP_RW, 1, IPS_IDLE);
|
||||
DEBUGF(INDI::Logger::DBG_SESSION, "FOCINIT, cur: %g, rel: %g, abs: %g", FocuserN[0].value, FocuserN[1].value, FocuserN[2].value);
|
||||
// Mirror cooler ON/OFF
|
||||
IUFillSwitch(&CoolerS[_ON], "COOLER_ON", "Cooler ON", ISS_OFF);
|
||||
IUFillSwitch(&CoolerS[_OFF], "COOLER_OFF", "Cooler OFF", ISS_ON);
|
||||
IUFillSwitchVector(&CoolerSP, CoolerS, 2, getDeviceName(), "COOLER_CONTROL", "Cooler Control",
|
||||
COOLER_TAB, IP_RW, ISR_1OFMANY, 1, IPS_IDLE);
|
||||
IUFillSwitch(&ACoolerS[_ON], "ACOOLER_ON", "Cooler auto ON", ISS_OFF);
|
||||
IUFillSwitch(&ACoolerS[_OFF], "ACOOLER_OFF", "Cooler auto OFF", ISS_ON);
|
||||
IUFillSwitchVector(&ACoolerSP, ACoolerS, 2, getDeviceName(), "ACOOLER_CONTROL", "Auto Cooler Control",
|
||||
COOLER_TAB, IP_RW, ISR_1OFMANY, 1, IPS_IDLE);
|
||||
// Secondary mirror / Primary focus corrector Heater
|
||||
IUFillSwitch(&AHeaterS[_ON], "HTR_ON", "Auto Heater ON", ISS_OFF);
|
||||
IUFillSwitch(&AHeaterS[_OFF], "HTR_OFF", "Auto Heater OFF", ISS_ON);
|
||||
IUFillSwitchVector(&AHeaterSP, AHeaterS, 2, getDeviceName(), "HEATER_CONTROL", "Heater Control",
|
||||
HEATER_TAB, IP_RW, ISR_1OFMANY, 1, IPS_IDLE);
|
||||
IUFillNumber(&PHeaterN, "PHTR", "Set heater power", "%.0f", 0, 100, 1, 0);
|
||||
IUFillNumberVector(&PHeaterNP, &PHeaterN, 1, getDeviceName(), "PHTR_CTRL", "Heater power",
|
||||
HEATER_TAB, IP_RW, 1, IPS_IDLE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AstroSib::updateProperties(){
|
||||
// We must ALWAYS call the parent class updateProperties() first
|
||||
DefaultDevice::updateProperties();
|
||||
|
||||
// If we are connected, we define the property to the client.
|
||||
if (isConnected()){
|
||||
defineSwitch(&ShtrsSP);
|
||||
defineNumber(&TempNP);
|
||||
defineNumber(&FocuserNPcur);
|
||||
defineNumber(&FocuserNP);
|
||||
defineSwitch(&CoolerSP);
|
||||
defineSwitch(&ACoolerSP);
|
||||
defineSwitch(&AHeaterSP);
|
||||
defineNumber(&PHeaterNP);
|
||||
SetTimer(POLLMS);
|
||||
// Otherwise, we delete the property from the client
|
||||
}else{
|
||||
deleteProperty(ShtrsSP.name);
|
||||
deleteProperty(TempNP.name);
|
||||
deleteProperty(FocuserNPcur.name);
|
||||
deleteProperty(FocuserNP.name);
|
||||
deleteProperty(CoolerSP.name);
|
||||
deleteProperty(ACoolerSP.name);
|
||||
deleteProperty(AHeaterSP.name);
|
||||
deleteProperty(PHeaterNP.name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************************
|
||||
** Process new switch from client
|
||||
***************************************************************************************/
|
||||
bool AstroSib::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n){
|
||||
// Mak sure the call is for our device
|
||||
if(!strcmp(dev,getDeviceName())){
|
||||
// Check if the call for shutters
|
||||
if (!strcmp(name, ShtrsSP.name)){
|
||||
// Find out which state is requested by the client
|
||||
const char *actionName = IUFindOnSwitchName(states, names, n);
|
||||
// If door is the same state as actionName, then we do nothing. i.e. if actionName is SHTR_OPENED and our shutter is already open, we return
|
||||
int currentIndex = IUFindOnSwitchIndex(&ShtrsSP);
|
||||
if (!strcmp(actionName, ShtrsS[currentIndex].name)){
|
||||
DEBUGF(INDI::Logger::DBG_SESSION, "Shutter is already %s", ShtrsS[currentIndex].label);
|
||||
ShtrsSP.s = IPS_OK;
|
||||
IDSetSwitch(&ShtrsSP, NULL);
|
||||
return true;
|
||||
}
|
||||
// Otherwise, let us update the switch state
|
||||
IUUpdateSwitch(&ShtrsSP, states, names, n);
|
||||
DEBUGF(INDI::Logger::DBG_SESSION, "Shutter is going to %s", ShtrsS[currentIndex].label);
|
||||
ShtrsSP.s = IPS_BUSY;
|
||||
IDSetSwitch(&ShtrsSP, NULL);
|
||||
return ShutterSetState(currentIndex);
|
||||
}else if (!strcmp(name, CoolerSP.name)){
|
||||
// Find out which state is requested by the client
|
||||
const char *actionName = IUFindOnSwitchName(states, names, n);
|
||||
int currentIndex = IUFindOnSwitchIndex(&CoolerSP);
|
||||
CoolerSP.s = IPS_OK;
|
||||
if (!strcmp(actionName, CoolerS[currentIndex].name)){
|
||||
DEBUGF(INDI::Logger::DBG_SESSION, "Cooler is already %s", CoolerS[currentIndex].label);
|
||||
IDSetSwitch(&CoolerSP, NULL);
|
||||
return true;
|
||||
}
|
||||
IUUpdateSwitch(&CoolerSP, states, names, n);
|
||||
currentIndex = IUFindOnSwitchIndex(&CoolerSP);
|
||||
DEBUGF(INDI::Logger::DBG_SESSION, "Cooler is now %s", CoolerS[currentIndex].label);
|
||||
IDSetSwitch(&CoolerSP, NULL);
|
||||
return CoolerSetState(currentIndex);
|
||||
}else if (!strcmp(name, ACoolerSP.name)){
|
||||
// Find out which state is requested by the client
|
||||
const char *actionName = IUFindOnSwitchName(states, names, n);
|
||||
int currentIndex = IUFindOnSwitchIndex(&ACoolerSP);
|
||||
ACoolerSP.s = IPS_OK;
|
||||
if (!strcmp(actionName, ACoolerS[currentIndex].name)){
|
||||
DEBUGF(INDI::Logger::DBG_SESSION, "Auto Cooler is already %s", ACoolerS[currentIndex].label);
|
||||
IDSetSwitch(&ACoolerSP, NULL);
|
||||
return true;
|
||||
}
|
||||
IUUpdateSwitch(&ACoolerSP, states, names, n);
|
||||
currentIndex = IUFindOnSwitchIndex(&ACoolerSP);
|
||||
DEBUGF(INDI::Logger::DBG_SESSION, "Auto Cooler is now %s", ACoolerS[currentIndex].label);
|
||||
IDSetSwitch(&ACoolerSP, NULL);
|
||||
return ACoolerSetState(currentIndex);
|
||||
}else if (!strcmp(name, AHeaterSP.name)){
|
||||
// Find out which state is requested by the client
|
||||
const char *actionName = IUFindOnSwitchName(states, names, n);
|
||||
int currentIndex = IUFindOnSwitchIndex(&AHeaterSP);
|
||||
AHeaterSP.s = IPS_OK;
|
||||
if (!strcmp(actionName, AHeaterS[currentIndex].name)){
|
||||
DEBUGF(INDI::Logger::DBG_SESSION, "Auto Heater is already %s", AHeaterS[currentIndex].label);
|
||||
IDSetSwitch(&AHeaterSP, NULL);
|
||||
return true;
|
||||
}
|
||||
IUUpdateSwitch(&AHeaterSP, states, names, n);
|
||||
currentIndex = IUFindOnSwitchIndex(&AHeaterSP);
|
||||
DEBUGF(INDI::Logger::DBG_SESSION, "Auto Heater is now %s", AHeaterS[currentIndex].label);
|
||||
IDSetSwitch(&AHeaterSP, NULL);
|
||||
return AHeaterSetState(currentIndex);
|
||||
}
|
||||
}
|
||||
// If we did not process the switch, let us pass it to the parent class to process it
|
||||
return INDI::DefaultDevice::ISNewSwitch(dev, name, states, names, n);
|
||||
}
|
||||
|
||||
bool AstroSib::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
|
||||
{
|
||||
DEBUGF(INDI::Logger::DBG_SESSION, "NEW NUM, name: %s, value=%g, names = %s, n: %d", name, values[0], names[0], n);
|
||||
if (dev != nullptr && strcmp(dev, getDeviceName()) == 0){
|
||||
if(strcmp(name, FocuserNP.name) == 0){
|
||||
if(FocInProgress){ // Already moving
|
||||
DEBUG(INDI::Logger::DBG_ERROR, "Wait still focus moving ends");
|
||||
return false;
|
||||
}
|
||||
if(IUUpdateNumber(&FocuserNP, values, names, n)){
|
||||
DEBUG(INDI::Logger::DBG_ERROR, "Can't set focuser value");
|
||||
FocuserN[1].value = 0;
|
||||
FocuserN[2].value = focabs;
|
||||
FocuserNP.s = IPS_ALERT;
|
||||
IDSetNumber(&FocuserNP, nullptr);
|
||||
return false;
|
||||
}
|
||||
DEBUGF(INDI::Logger::DBG_SESSION, "NEW NUMBER, rel: %g, abs: %g", FocuserN[1].value, FocuserN[2].value);
|
||||
if(FocuserN[1].value){ // relative
|
||||
focabs = foccur + FocuserN[1].value;
|
||||
}else if(FocuserN[2].value){ // absolute
|
||||
focabs = FocuserN[2].value;
|
||||
}
|
||||
if(focabs < 0){
|
||||
DEBUG(INDI::Logger::DBG_ERROR, "Can't move focuser to negative values");
|
||||
focabs = foccur;
|
||||
FocuserNP.s = IPS_ALERT;
|
||||
IDSetNumber(&FocuserNP, nullptr);
|
||||
return false;
|
||||
}
|
||||
FocInProgress = true;
|
||||
FocuserNP.s = IPS_BUSY;
|
||||
FocuserN[1].value = focabs - foccur;
|
||||
FocuserN[2].value = focabs;
|
||||
IDSetNumber(&FocuserNP, nullptr);
|
||||
return FocuserSetVal(focabs);
|
||||
}else if(strcmp(name, PHeaterNP.name) == 0){
|
||||
float oldval = PHeaterN.value;
|
||||
if(IUUpdateNumber(&PHeaterNP, values, names, n)){
|
||||
DEBUG(INDI::Logger::DBG_ERROR, "Can't set heater power value");
|
||||
return false;
|
||||
}
|
||||
bool stat = HeaterSetPower(*values);
|
||||
if(!stat) PHeaterN.value = oldval;
|
||||
PHeaterNP.s = (stat) ? IPS_OK : IPS_ALERT;
|
||||
IDSetNumber(&PHeaterNP, nullptr);
|
||||
return stat;
|
||||
}
|
||||
}
|
||||
return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************************
|
||||
** INDI is asking us for our default device name
|
||||
***************************************************************************************/
|
||||
const char *AstroSib::getDefaultName(){
|
||||
return "AstroSib telescope";
|
||||
}
|
||||
|
||||
|
||||
// Timer events
|
||||
void AstroSib::TimerHit(){
|
||||
static int tensecond = 0;
|
||||
++tensecond;
|
||||
if (isConnected()){
|
||||
// once per 10 seconds check cooler & heater status
|
||||
if(tensecond == 10){
|
||||
CoolerChk();
|
||||
HeaterChk();
|
||||
tensecond = 0;
|
||||
}
|
||||
// check shutter if(ShtrInProgress)
|
||||
if(ShtrInProgress){
|
||||
ShutterChk();
|
||||
}
|
||||
// once per second check temperatures
|
||||
TemperatureChk();
|
||||
// check focuser if(FocInProgress)
|
||||
if(FocInProgress){
|
||||
FocuserChk();
|
||||
}
|
||||
SetTimer(POLLMS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private functions working with RS-232
|
||||
*/
|
||||
void AstroSib::FocuserChk(){
|
||||
if(!FocInProgress){
|
||||
int cur = foccur, abs = focabs, del = cur - abs;
|
||||
if(del){
|
||||
if(cur > abs){
|
||||
cur -= 10;
|
||||
if(cur < abs) cur = abs;
|
||||
}else{
|
||||
cur += 10;
|
||||
if(cur > abs) cur = abs;
|
||||
}
|
||||
foccur = cur;
|
||||
focabs = abs;
|
||||
//DEBUGF(INDI::Logger::DBG_SESSION, "move, cur: %d, abs: %d", foccur, focabs);
|
||||
}
|
||||
if(foccur == focabs){
|
||||
FocInProgress = false;
|
||||
FocuserNP.s = IPS_IDLE;
|
||||
IDSetNumber(&FocuserNPcur, "Position reached");
|
||||
}else FocuserNP.s = IPS_BUSY;
|
||||
}else{
|
||||
FocuserNP.s = IPS_IDLE;
|
||||
}
|
||||
FocuserNPcur.s = IPS_OK;
|
||||
FocuserN[0].value = foccur;
|
||||
FocuserN[1].value = focabs - foccur;
|
||||
FocuserN[2].value = focabs;
|
||||
IDSetNumber(&FocuserNPcur, nullptr);
|
||||
IDSetNumber(&FocuserNP, nullptr);
|
||||
}
|
||||
|
||||
void AstroSib::TemperatureChk(){
|
||||
mirrtemp += 0.01; if(mirrtemp > 20.) mirrtemp = -20.;
|
||||
ambtemp += 0.05; if(ambtemp > 20.) ambtemp = -20;
|
||||
TempN[0].value = mirrtemp;
|
||||
TempN[1].value = ambtemp;
|
||||
TempN[2].value = focusert;
|
||||
TempNP.s = IPS_OK;
|
||||
IDSetNumber(&TempNP, nullptr);
|
||||
}
|
||||
|
||||
void AstroSib::ShutterChk(){
|
||||
if(ShtrInProgress){
|
||||
static bool closed = false;
|
||||
if(closed){
|
||||
ShtrsS[SHTR_OPENED].s = ISS_OFF;
|
||||
ShtrsS[SHTR_CLOSED].s = ISS_ON;
|
||||
}else{
|
||||
ShtrsS[SHTR_OPENED].s = ISS_ON;
|
||||
ShtrsS[SHTR_CLOSED].s = ISS_OFF;
|
||||
}
|
||||
closed = !closed;
|
||||
}
|
||||
ShtrInProgress = false;
|
||||
ShtrsSP.s = IPS_OK;
|
||||
IDSetSwitch(&ShtrsSP, NULL);
|
||||
}
|
||||
|
||||
void AstroSib::CoolerChk(){
|
||||
}
|
||||
|
||||
void AstroSib::HeaterChk(){
|
||||
}
|
||||
|
||||
bool AstroSib::ShutterSetState(int newstate){
|
||||
(void) newstate;
|
||||
ShtrInProgress = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AstroSib::CoolerSetState(int newstate){
|
||||
(void) newstate;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AstroSib::ACoolerSetState(int newstate){
|
||||
(void) newstate;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AstroSib::AHeaterSetState(int newstate){
|
||||
(void) newstate;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AstroSib::AstroSib::FocuserSetVal(int focval){
|
||||
(void) focval;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AstroSib::HeaterSetPower(int pwr){
|
||||
(void) pwr;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************************
|
||||
** Client is asking us to establish connection to the device
|
||||
***************************************************************************************/
|
||||
bool AstroSib::Connect(){
|
||||
/* code should be here */
|
||||
IDMessage(getDeviceName(), "Astrosib telescope connected successfully!");
|
||||
SetTimer(POLLMS);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************************
|
||||
** Client is asking us to terminate connection to the device
|
||||
***************************************************************************************/
|
||||
bool AstroSib::Disconnect(){
|
||||
/* code should be here */
|
||||
IDMessage(getDeviceName(), "Astrosib telescope disconnected successfully!");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************************
|
||||
** INDI is asking us to check communication with the device via a handshake
|
||||
***************************************************************************************/
|
||||
bool AstroSib::Handshake(){
|
||||
// When communicating with a real scope, we check here if commands are receieved
|
||||
// and acknolowedged by the mount.
|
||||
/* code should be here */
|
||||
return true;
|
||||
}
|
||||
103
_deprecated/astrosib/astrosib.h
Normal file
103
_deprecated/astrosib/astrosib.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* astrosib.h
|
||||
*
|
||||
* Copyright 2017 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
INDI Developers Manual
|
||||
Tutorial #2
|
||||
|
||||
"Simple Telescope Driver"
|
||||
|
||||
We develop a simple telescope simulator.
|
||||
|
||||
Refer to README, which contains instruction on how to build this driver, and use it
|
||||
with an INDI-compatible client.
|
||||
|
||||
*/
|
||||
|
||||
/** \file simplescope.h
|
||||
\brief Construct a basic INDI telescope device that simulates GOTO commands.
|
||||
\author Jasem Mutlaq
|
||||
|
||||
\example simplescope.h
|
||||
A simple GOTO telescope that simulator slewing operation.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "inditelescope.h"
|
||||
|
||||
class AstroSib : public INDI::DefaultDevice{
|
||||
public:
|
||||
AstroSib();
|
||||
~AstroSib();
|
||||
bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);
|
||||
bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n);
|
||||
void TimerHit();
|
||||
|
||||
protected:
|
||||
bool Connect();
|
||||
bool Disconnect();
|
||||
|
||||
bool Handshake();
|
||||
const char *getDefaultName();
|
||||
bool initProperties();
|
||||
bool updateProperties();
|
||||
|
||||
private:
|
||||
enum {_ON, _OFF};
|
||||
// last ambient & mirror temperature values
|
||||
float ambtemp {0}, mirrtemp {0}, focusert{0};
|
||||
INumber TempN[3]; // mirror, ambient and focuser
|
||||
INumberVectorProperty TempNP;
|
||||
void TemperatureChk();
|
||||
// shutter leaves state
|
||||
enum {SHTR_OPENED, SHTR_CLOSED};
|
||||
bool ShtrInProgress{false};
|
||||
ISwitch ShtrsS[2]; // roof shutters switch
|
||||
ISwitchVectorProperty ShtrsSP;
|
||||
bool ShutterSetState(int newstate);
|
||||
void ShutterChk();
|
||||
// focuser current/relative/absolute position
|
||||
bool FocInProgress{false};
|
||||
int foccur{0}, focabs{0};
|
||||
INumber FocuserN[3];
|
||||
INumberVectorProperty FocuserNP, FocuserNPcur;
|
||||
bool FocuserSetVal(int focval);
|
||||
void FocuserChk();
|
||||
// mirror cooler
|
||||
ISwitch CoolerS[2];
|
||||
ISwitchVectorProperty CoolerSP;
|
||||
// cooler auto
|
||||
ISwitch ACoolerS[2];
|
||||
ISwitchVectorProperty ACoolerSP;
|
||||
bool CoolerSetState(int newstate);
|
||||
bool ACoolerSetState(int newstate);
|
||||
void CoolerChk();
|
||||
// heater
|
||||
ISwitch AHeaterS[2];
|
||||
ISwitchVectorProperty AHeaterSP;
|
||||
INumber PHeaterN;
|
||||
INumberVectorProperty PHeaterNP;
|
||||
bool AHeaterSetState(int newstate);
|
||||
bool HeaterSetPower(int pwr);
|
||||
void HeaterChk();
|
||||
};
|
||||
139
_deprecated/bidirectional_list.c
Normal file
139
_deprecated/bidirectional_list.c
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* bidirectional_list.c - bidi sorted list
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "bidirectional_list.h"
|
||||
|
||||
#ifndef Malloc
|
||||
#define Malloc my_alloc
|
||||
/**
|
||||
* Memory allocation with control
|
||||
* @param N - number of elements
|
||||
* @param S - size of one element
|
||||
* @return allocated memory or die
|
||||
*/
|
||||
void *my_alloc(size_t N, size_t S){
|
||||
void *p = calloc(N, S);
|
||||
if(!p) err(1, "malloc");
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
#ifndef FREE
|
||||
#define FREE(arg) do{free(arg); arg = NULL;}while(0)
|
||||
#endif
|
||||
|
||||
|
||||
List *l_search(List *root, int v, List **Left, List **Right){
|
||||
List *L = NULL, *R = NULL;
|
||||
int dir = -1;
|
||||
if(!root) goto not_Fnd;
|
||||
if(root->data == v)
|
||||
return root;
|
||||
if(root->data < v) dir = 1;
|
||||
do{
|
||||
L = root->left_p; // left leaf
|
||||
R = root->right_p; // right leaf
|
||||
int D = root->data;// data in leaf
|
||||
if(D > v && dir == -1){ // search to left is true
|
||||
R = root;
|
||||
root = L;
|
||||
}
|
||||
else if(D < v && dir == 1){ // search to right is true
|
||||
L = root;
|
||||
root = R;
|
||||
}
|
||||
else if(D == v){ // we found exact value
|
||||
if(Left) *Left = L;
|
||||
if(Right) *Right = R;
|
||||
return root;
|
||||
}
|
||||
else break;
|
||||
}while(root); // if root == NULL, we catch an edge
|
||||
// exact value not found
|
||||
if(root){ // we aren't on an edge
|
||||
if(dir == -1) L = root;
|
||||
else R = root;
|
||||
}
|
||||
not_Fnd:
|
||||
if(Left) *Left = L;
|
||||
if(Right) *Right = R;
|
||||
return NULL; // value not found
|
||||
}
|
||||
|
||||
|
||||
List *l_insert(List *root, int v){
|
||||
List *node, *L, *R;
|
||||
node = l_search(root, v, &L, &R);
|
||||
if(node) return node; // we found exact value V
|
||||
// there's no exact value: insert new
|
||||
if((node = (List*) Malloc(1, sizeof(List))) == 0) return NULL; // allocation error
|
||||
node->data = v; // insert data
|
||||
// add neighbours:
|
||||
node->left_p = L;
|
||||
node->right_p = R;
|
||||
// fix neighbours:
|
||||
if(L) L->right_p = node;
|
||||
if(R) R->left_p = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
void l_remove(List **root, int v){
|
||||
List *node, *left, *right;
|
||||
if(!root) return;
|
||||
if(!*root) return;
|
||||
node = l_search(*root, v, &left, &right);
|
||||
if(!node) return; // there's no such element
|
||||
if(node == *root) *root = node->right_p;
|
||||
if(!*root) *root = node->left_p;
|
||||
FREE(node);
|
||||
if(left) left->right_p = right;
|
||||
if(right) right->left_p = left;
|
||||
}
|
||||
|
||||
#ifdef STANDALONE
|
||||
int main(void) {
|
||||
List *tp, *root_p = NULL;
|
||||
int i, ins[] = {4,2,6,1,3,4,7};
|
||||
for(i = 0; i < 7; i++)
|
||||
if(!(root_p = l_insert(root_p, ins[i])))
|
||||
err(1, "Malloc error"); // can't insert
|
||||
for(i = 0; i < 9; i++){
|
||||
tp = l_search(root_p, i, NULL, NULL);
|
||||
printf("%d ", i);
|
||||
if(!tp) printf("not ");
|
||||
printf("found\n");
|
||||
}
|
||||
printf("now delete items 1, 4 and 8\n");
|
||||
l_remove(&root_p, 1);
|
||||
l_remove(&root_p, 4);
|
||||
l_remove(&root_p, 8);
|
||||
for(i = 0; i < 9; i++){
|
||||
tp = l_search(root_p, i, NULL, NULL);
|
||||
printf("%d ", i);
|
||||
if(!tp) printf("not ");
|
||||
printf("found\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
34
_deprecated/bidirectional_list.h
Normal file
34
_deprecated/bidirectional_list.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* bidirectional_list.h
|
||||
*
|
||||
* 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 __BIDIRECTIONAL_LIST_H__
|
||||
#define __BIDIRECTIONAL_LIST_H__
|
||||
|
||||
typedef struct list_node{
|
||||
int data;
|
||||
struct list_node *left_p, *right_p;
|
||||
} List;
|
||||
|
||||
List *l_search(List *root, int v, List **Left, List **Right);
|
||||
List *l_insert(List *root, int v);
|
||||
void l_remove(List **root, int v);
|
||||
|
||||
#endif // __BIDIRECTIONAL_LIST_H__
|
||||
19
_deprecated/erosion-dilation/Makefile
Normal file
19
_deprecated/erosion-dilation/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
PROGRAM = binmorph_test
|
||||
CXX.SRCS = binmorph.c main.c
|
||||
CC = gcc
|
||||
LDFLAGS = -lm -fopenmp
|
||||
CXX = gcc
|
||||
DEFINES = -DEBUG -DOMP
|
||||
CFLAGS = -fopenmp -Wall -Werror -O3 -std=gnu99 $(DEFINES)
|
||||
OBJS = $(CXX.SRCS:.c=.o)
|
||||
all : $(PROGRAM) clean
|
||||
binmorph.c : cclabling.h cclabling_1.h dilation.h fs_filter.h fc_filter.h
|
||||
$(PROGRAM) : $(OBJS)
|
||||
$(CC) $(LDFLAGS) $(OBJS) -o $(PROGRAM)
|
||||
clean:
|
||||
/bin/rm -f *.o *~
|
||||
depend:
|
||||
$(CXX) -MM $(CXX.SRCS)
|
||||
|
||||
### <DEPENDENCIES ON .h FILES GO HERE>
|
||||
# name1.o : header1.h header2.h ...
|
||||
523
_deprecated/erosion-dilation/README
Normal file
523
_deprecated/erosion-dilation/README
Normal file
@@ -0,0 +1,523 @@
|
||||
************************************
|
||||
СООБРАЖЕНИЯ ПО ПОВОДУ ЭРОЗИИ/ДИЛЯЦИИ
|
||||
************************************
|
||||
|
||||
|
||||
Эрозия
|
||||
|
||||
00000 00000
|
||||
01110 00000
|
||||
01110 => 00100
|
||||
01110 00000
|
||||
00000 00000
|
||||
|
||||
Бит равен единице лишь тогда, когда присутствуют все его 4 связи.
|
||||
Т.е. для срединных битов байта выполняем & текущего байта с байтами верхней и нижней строк. Для крайних битов необходимо проверить еще и 4-связные байты:
|
||||
|
||||
ABC
|
||||
DEF
|
||||
GHK
|
||||
|
||||
Младший бит E проверяется по старшему биту F, младшим битам B и H и второму биту E.
|
||||
Старший бит E проверяется по младшему биту D, старшим битам B и E и седьмому биту E.
|
||||
|
||||
Таким образом, алгоритм получается следующим:
|
||||
1. подменяем E маской[E] (эрозия внутренних битов)
|
||||
2. делаем &: E = E & B & H
|
||||
3. корректируем старший бит E по младшему D и младший бит E по старшему F.
|
||||
|
||||
ПРОВЕРИТЬ, ЧТО БЫСТРЕЙ: (A&0X80)>>8 ИЛИ РАЗЫМЕНОВАНИЕ УКАЗАТЕЛЯ (ПО ТАБЛИЦЕ)
|
||||
|
||||
|
||||
Диляция
|
||||
|
||||
00000 00110
|
||||
00110 01111
|
||||
01010 => 11111
|
||||
01100 11110
|
||||
00000 01100
|
||||
|
||||
Обратная ситуация: вместо & делаем | :
|
||||
1. подменяем E маской (диляция внутренних битов)
|
||||
2. делаем |: E = E | B | H
|
||||
3. корректируем старший и младший биты операцией |.
|
||||
|
||||
|
||||
|
||||
|
||||
**************************************************
|
||||
СООБРАЖЕНИЯ ПО ПОВОДУ ВЫДЕЛЕНИЯ СВЯЗАННЫХ ОБЛАСТЕЙ
|
||||
**************************************************
|
||||
|
||||
Вернемся к тому же общему случаю: искомый пиксель нахдится в байте E.
|
||||
ABC
|
||||
DEF
|
||||
GHK
|
||||
|
||||
Фильтрация 4-связанных областей схожа с операцией диляции за исключением собственно
|
||||
логики - в отсечении пикселей, не являющихся 4-связанными, необходимо провести операцию:
|
||||
|
||||
E4 = E & ( B|H|(E<<1)|(E>>1)|(D<<7)|(F>>7) )
|
||||
|
||||
Т.е. мы оставляем пиксель в E лишь в том случае, если хотя бы один из его
|
||||
4-связанных соседей присутствует.
|
||||
|
||||
Соответственно, для крайних пикселей (крайние столбцы/строки) выражение для E4
|
||||
будет видоизменяться (для крайних строк - наличием/отсутствием B,H; для крайних
|
||||
столбцов - наличием/отсутствием выражений с D, F).
|
||||
|
||||
Для упрощения записи можно было бы сделать макрос при помощи boost, но что-то
|
||||
лень мне в дебри буста погружаться, поэтому проблему решаю простым копипастом.
|
||||
|
||||
Кстати, здесь нет проверки A,C,G и K, иначе пришлось бы еще больше кода наворачивать
|
||||
(добавились бы особые случаи для углов изображения).
|
||||
|
||||
|
||||
Общее выражение для поиска 8-связанных областей несколько видоизменится:
|
||||
|
||||
пусть {x} = (x|(x<<1)|(x>>1)), тогда
|
||||
E8 = E & ( {B|H} | ((E<<1)|(E>>1)) | ((C|F|K)>>7) | ((A|D|G)<<7) )
|
||||
|
||||
Вычислительная сложность сильно возрастает, причем многие операции вычисляются по
|
||||
два раза. Пожалуй, можно попытаться немного ускорить вычисления, если заранее
|
||||
подготовить матрицу {x} (и матрицы (x<<7) и (x>>7) ???).
|
||||
/* (сомнительно) Аналогично, заранее подготовив матрицы x<<7) и (x>>7) можно
|
||||
* попытаться ускорить поиск E4 */
|
||||
|
||||
|
||||
Когда мы уже имеем отфильтрованное изображение, нужно "всего лишь" пробежаться
|
||||
по нему в поисках областей, со всех сторон ограниченных нулями. Грубо говоря,
|
||||
мы маркируем 8-связанные области без проверки на 8-связанность.
|
||||
|
||||
Первое, что приходит на ум - двухпроходная маркировка: сначала мы пробегаемся
|
||||
по связанной области, постепенно расширяя границы заключающего ее прямоугольника.
|
||||
Затем мы выделяем память для этого кусочка и заполняем его, пробегаясь по нашей
|
||||
области еще раз (ну или делаем полную копию содержимого бокса, а затем выкидываем
|
||||
все, что не принадлежит искомой связанной области).
|
||||
|
||||
Еще вариант - сразу выделять область памяти (вспомогательную) размером со ВСЕ
|
||||
первоначальное изображение (гениально!). В этом случае мы сможем сразу же копировать
|
||||
в эту область памяти нашу х-связанную область, а затем, когда она целиком будет
|
||||
скопирована и будут ясны параметры описывающего ее прямоугольника, выделяем уже
|
||||
память именно под эту область и копируем в нее содержимое бокса.
|
||||
|
||||
Логично было бы преобразовать картинку до анализа в бинарный вид, поэтому сначала
|
||||
будем предполагать, что мы имеем дело с бинарным изображением (а не "сжатым"
|
||||
битовым).
|
||||
|
||||
Теперь каждый пиксель нашей матрицы соответствует одному пикселю изображения
|
||||
ABC
|
||||
DEF
|
||||
GHK
|
||||
|
||||
На ум приходит использовать метод шагающих квадратов, однако, он применяется
|
||||
для обхода границ -> мало чем поможет (разве что первоначальным определением
|
||||
размеров бокса, но я уже решил делать лишь один проход обнаружения связанных
|
||||
областей). Интернета под рукой нет, чтобы подсмотреть наиболее эффективный
|
||||
способ, поэтому буду изобретать велосипед.
|
||||
|
||||
|
||||
=== Нулевое приближение ===
|
||||
|
||||
/*
|
||||
Работаем с копией изображения, т.к. уже пройденные значения будем обнулять.
|
||||
*/
|
||||
|
||||
Итак, выделим память под промежуточный буфер (сразу обнулив ее) и начнем
|
||||
проходить изображение с левого верхнего угла. Как только мы натыкаемся
|
||||
на единицу в E, записываем в соответствующие координаты буфера 1.
|
||||
Далее смотрим, куда нам нужно двигаться. Считаем, что в A,B,C и D нули (т.к. там -
|
||||
уже пройденная область). Нам необходимо проверить пиксели F, G, H и K.
|
||||
Теперь каждый из них становится E. Если кто-то из них установлен в 1, проверяем
|
||||
его соседей и т.д. Однако, на всех шагах, отличных от первого, мы уже обязаны
|
||||
проверить ВСЕХ СОСЕДЕЙ, т.к. не факт, что наша область не представляет собою
|
||||
какой-нибудь извращенной фигуры с отростками и многочисленными полостями.
|
||||
|
||||
На ум приходит рекурсия, однако, учитывая то, что изображения могут быть довольно-таки
|
||||
огромными, с горем расстаюсь с этой идеей. А так было бы хорошо: рекурсия сделала
|
||||
бы очень простым этот алгоритм. Но регистры не бесконечные.
|
||||
|
||||
Кстати, если не преобразовывать изображение в бинарное, то вполне возможны случаи,
|
||||
когда один и тот же байт будет проходиться вплоть до четырех раз!
|
||||
|
||||
После копирования каждого пикселя с 1 в результирующий буфер, "стираем" его
|
||||
с оригинала (сбросом в 0). По окончанию операций обнуляем буфер.
|
||||
|
||||
Тут мне опять пришла в голову идея о шагающих квадратах: а что, если в первый
|
||||
проход пробежаться по границе области, определить описывающий ее прямоугольник,
|
||||
выделить буфер по размеру прямоугольника (это - как раз искомое возвращаемое
|
||||
функцией значение); после этого, проходя по объекту, пиксель за пикселем копировать
|
||||
его в буфер, "стирая" с оригинала. Правда, здесь опять та же самая проблема:
|
||||
нет гарантии, что за один проход все будет сделано.
|
||||
|
||||
|
||||
=== "Гюйгенс". ===
|
||||
Один из вариантов прохождения по изображению в поисках связанных областей (который,
|
||||
собственно, первым пришел мне в голову еще вчера, но лучше всего, конечно, он бы
|
||||
выглядел в рекурсивном исполнении).
|
||||
|
||||
== лирика по поводу рекурсии ==
|
||||
Еще раз, чтобы убедиться лишний раз в том, что рекурсия невозможна, я набросал
|
||||
элементарнейшую проверялку:
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int incr(int a){
|
||||
fprintf(stderr, "%d ", a++);
|
||||
incr(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
main(){
|
||||
incr(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Проверялочка эта должна вылетать с сегфолтом как только скончаются все ресурсы
|
||||
на рекурсию. Получилось вот что:
|
||||
|
||||
... 261504 Ошибка сегментирования (core dumped)
|
||||
... 261350 Ошибка сегментирования (core dumped)
|
||||
... 261333 Ошибка сегментирования (core dumped)
|
||||
|
||||
ЕМНИП, что-то подобное было на ЛОРе. И, возможно, предел этот даже как-то регулируется.
|
||||
Число это подозрительно близко к 256к (262144): возможно, оно так и есть (просто
|
||||
еще кучу места в стеке занимают всякие вспомогательные буферы из stdio).
|
||||
|
||||
Я немного видоизменил программку: она теперь еще и по 1к выделяет:
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int incr(int a){
|
||||
char *x = malloc(1024);
|
||||
memset(x, 1, 1024);
|
||||
fprintf(stderr, "%d ", a++);
|
||||
incr(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
main(){
|
||||
incr(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Теперь цифры "более другие":
|
||||
|
||||
... 174258 Ошибка сегментирования (core dumped)
|
||||
... 174372 Ошибка сегментирования (core dumped)
|
||||
... 174325 Ошибка сегментирования (core dumped)
|
||||
|
||||
Кто сожрал 85к? Почему именно 85к? Заменяю выделение памяти на `char x = 2;` -
|
||||
получаю то же самое. Добавление переменных ничего не меняет.
|
||||
В любом случае, все-таки про рекурсию придется забыть: если искомая область будет
|
||||
иметь площадь, превышающую эдак 170 тысяч пикселей (а это не так уж и много), то
|
||||
я получу большой фигвам.
|
||||
## конец лирики
|
||||
|
||||
Принцип Гюйгенса прост: каждая точка волнового фронта (в нашем случае - точка
|
||||
внутри искомой области) является источником нового волнового фронта (в нашем
|
||||
случае - центром, от которого "расходится" поисковая волна).
|
||||
|
||||
Пробегаясь такой "волной" от первого обнаруженного пикселя, принадлежащего
|
||||
искомой фигуре, мы пройдем все ее закоулки.
|
||||
Однако, проблема в том, как реализовать это без бешеного количества разыменования
|
||||
указателей и проверок.
|
||||
|
||||
Долго кумекая, я так и не придумал, как реализовать "Гюйгенса", не вводя уйму
|
||||
промежуточных матриц.
|
||||
|
||||
|
||||
### "Гюйгенс модифицированный" ###
|
||||
Для ограничения одной-единственной вспомогательной матрицей, можно попробовать
|
||||
оставить одну "волну": от первоначальной точки проводим расходящуюся во все
|
||||
стороны "волну". Пусть для простоты она будет "квадратной".
|
||||
Пробегаясь по всем точкам очередного фронта "волны", кроме особых (о них -
|
||||
позже, их тоже надо контролировать), "стираем" единицы с изображения, перенося их в маску.
|
||||
Как только натыкаемся на нуль, если до этого тоже был нуль, заносим единичку в
|
||||
матрицу спец.маски в соответствующий пиксель, а также в пиксель,
|
||||
соседний с текущим, но расположеный на "волне" с радиусом на 1 больше (т.е. для левой
|
||||
поверхности переносим пиксель влево на 1, для правой - вправо на 1 и т.п.).
|
||||
Если натыкаемся на 1, делаем обнуление соответствующего пикселя на "волне" с радиусом
|
||||
на 1 больше + его предыдущего соседа в спец.маске. Таким образом, "тени" получаются постепенно
|
||||
сходящимися. Но все равно, остается возможность того, что эти "тени" что-нибудь да
|
||||
сокроют, не говоря уже о том, что эта "волна" только в очень редких случаях сразу
|
||||
выявит хотя бы внешний контур искомой фигуры.
|
||||
Именно для этого и нужна наша спец.маска: как только "кончится" искомая фигура по
|
||||
"большой волне", нужно будет просмотреть все пиксели маски (внутри уже получившегося
|
||||
прямоугольника + 1 по радиусу, т.к. снаружи все равно нули), пробегая по их
|
||||
внешней границе: как только обнаруживаем 1 в изображении, "выпускаем" новую "волну".
|
||||
Пока бежим первый раз, пропускаем все единички в маске, копируя их на "волну" маски
|
||||
с большим радиусом.
|
||||
|
||||
Метод получился опять каким-то уж очень извращенным. Глаза уже слипаются, поэтому
|
||||
пока - отбой.
|
||||
|
||||
=== первое приближение к решению ===
|
||||
Итак, сегодня я накачал всяких статеек. Почитал. Обычный алгоритм выделения
|
||||
связанных областей (как я мог о нем не вспомнить?) жутко тормозной: он требует
|
||||
как минимум четыре прохода (1 - маркировка соседних областей, 2 - построение
|
||||
списка эквивалентности номеров, 3 - переименование областей, 4 - выделение
|
||||
объектов). При этом на первом шаге мы должны проверять, были ли до пикселя нули,
|
||||
на втором - верхнего соседа (и его боковых, если нужно заполнить 8-связанную
|
||||
область), на третьем - сверяться с таблицей, на четвертом -
|
||||
многократно сканировать изображение, пока все объекты не будут выделены.
|
||||
Конечно, четвертый шаг можно укоротить: на третьем же шаге выделить массив
|
||||
прямоугольников и обновлять размеры соответствующего прямоугольника.
|
||||
Тогда четвертый шаг сведется к сканированию внутренностей каждого прямоугольника
|
||||
с заполнением его маски единицами там, где в массиве номеров пиксель == N.
|
||||
|
||||
Процедура перемаркировки такова:
|
||||
проходя матрицу с маркерами, проверяем каждый пиксель. Если пиксель нулевой,
|
||||
устанавливаем флаг обнаружения в false и продолжаем. Если флаг == true, это значит,
|
||||
что данный номер мы уже перемаркировали - продолжаем.
|
||||
Если же пиксель - "свеженайденный", надо проверить все 6 пикселей (для 8-связных
|
||||
областей) в предыдущем и последующем рядах (снизу - т.к. возможен вариант коротенького
|
||||
кусочка, а то и единичного пикселя над длинной линией - из-за флага обнаружения мы
|
||||
пролетим под ним, а вот на этапе сканирования его, изучая то, что под ним, сделаем
|
||||
правильную ремаркировку). Вполне возможно, что нет необходимости проверять сразу и
|
||||
пиксель над, и под нашим: пиксель точно под ним по-любому будет проверен (он - либо
|
||||
часть более длинной линии, которую мы обнаружим в DL или DR углах, либо часть
|
||||
вертикальной, которая обнаружится при сканировании нижней линии).
|
||||
|
||||
А вообще, полезно рассмотреть, какие варианты расположения соседей
|
||||
могут быть, чтобы не пропустить мелочей (нумерация не важна, поэтому просто 1/0;
|
||||
кроме того, т.к вариантов аж 256, рассмотрим лишь некоторые):
|
||||
(X - что угодно, U - единица в одном из пикселей, V - единица в одном и более пикселей)
|
||||
|
||||
A B C D E F G H I J K L M N O P Q R
|
||||
XXX 000 UUU 000 101 101 11X 000 010 000 000 000 000 000 000 000 000 000
|
||||
11X 01X 01X 01X 01X 01X 01X 01X 01X 01X 01X 01X 01X 01X 01X 01X 01X 01X
|
||||
XXX 000 000 VVV 000 VVV VVV 010 000 000 000 000 000 000 000 000 000 000
|
||||
|
||||
A - просто проходим мимо
|
||||
B - инкрементируем счетчик уникальных объектов и перемаркируем текущий номер
|
||||
C - ремаркируем текущее значение на то, которое содержится в массиве с индексом,
|
||||
имеющим значение счетчика в пикселе с единичкой
|
||||
D - то же, что в B + ремаркировка значений в нижней строке
|
||||
E - ремаркировка текущего + правого верхнего счетчика по массиву с индексом,
|
||||
равным значению счетчика в левом верхнем пикселе
|
||||
F - ремаркировка всех по левому верхнему
|
||||
G - для упрощения можно сделать эквивалентом F: нет нужды усложнять алгоритм ради
|
||||
пары лишних операций
|
||||
H - нет нужды проверять этот вариант, т.к. на стадии I он ремаркируется
|
||||
I - заменяет H
|
||||
|
||||
Итак, общие тенденции:
|
||||
- Если в верхней строке ничего нет, проверяем, не является ли наше текущее
|
||||
значение счетчика уже перемаркированным: если является, оставляем как есть,
|
||||
иначе - счетчик уникальных объектов инкрементируется и текущее значение перемаркируется
|
||||
им; объекты внизу (если есть) тоже перемаркируются им
|
||||
- если в левом верхнем углу !=0, все номера перемаркируются им, а пиксель над
|
||||
нами проверять нет нужды
|
||||
- если обнаружен !=0 ровно над нами, правый верхний проверять нет нужды, а оставшиеся
|
||||
перемаркируются им
|
||||
|
||||
При организации процедуры переименования я натолкнулся на следующее: если ряд
|
||||
X переименовывается в нижележащий Y, а потом Y переименовывается в Z, то ряд
|
||||
X так и остается переименованным в Y.
|
||||
Следовательно, при переименовании в массиве ассоциаций на стадии перенумерования
|
||||
надо проверять, выполняется ли равенство assoc[assoc[X]] == assoc[X], т.е. зафиксировать
|
||||
сложные связи.
|
||||
|
||||
Оказалось не все так просто с переименованием: надо будет нарисовать на бумажке,
|
||||
что-то засыпаю уже. На сегодняшний день ничего не планирую (спать надо лечь рано,
|
||||
т.к. завтра в 5 утра вставать), так что, пожалуй, закруглюсь и буду спать.
|
||||
Сегодня еще вопросы с криостатом утрясти надо будет.
|
||||
|
||||
Пока засыпал, придумал, как правильно скорректировать алгоритм переименования:
|
||||
скажем, переименовываем мы пиксель с изначальной меткой "X", имеющий новую
|
||||
метку "Y" (т.е. assoc[X] != X) в "Z". В этом случае надо наоборот переименовать
|
||||
Z в Y, а величины, больше Z, но <= Ncur декрементировать, затем декрементировать
|
||||
и Ncur.
|
||||
Все довольно просто, а очевидным
|
||||
плюсом является то, что не надо многократно сканировать изображение для переименования
|
||||
"по месту": это будет сделано на шаге 3.
|
||||
|
||||
Конечно, все познается в сравнении, поэтому сразу обливать дерьмом этот метод
|
||||
нельзя: стоит попытаться его реализовать. А учитывая то, что все шаги, кроме второго,
|
||||
превосходно параллелизуются (1, 3 - хоть по строкам, хоть по прямоугольным областям,
|
||||
4 - по номерам объектов), на куде, пожалуй, он будет работать просто превосходно!
|
||||
|
||||
|
||||
== еще мысли ==
|
||||
Однако, меня все еще грызут сомнения: ведь по сути обнаружение связанных областей
|
||||
подобно закрашиванию области, ограниченной контуром (в данном случае - "закрашивание"
|
||||
нулями этой самой связанной области с "перенесением" соответствующих пикселей
|
||||
во временное хранилище (а оттуда уже, по завершению закрашивания, - в соответствующее
|
||||
подызображение).
|
||||
|
||||
Итак, если выбрать эффективный метод закрашивания областей, то обнаружение
|
||||
сведется к следующему:
|
||||
1. пробегаемся по точкам изображения, как только находим 1, "закрашиваем" всю
|
||||
область нулями с "перенесением" ее во временную маску (равную размеру изображения)
|
||||
и параллельным обновлением границ бокса;
|
||||
2. выделяем для бокса память и переносим в него кусок из маски ("модифицированный"
|
||||
шаг 4 из предыдущих размышлений);
|
||||
3. сканируем изображение, начиная со следующей точки после точки из п.1.
|
||||
|
||||
Если опустить "волшебную" фразу "закрашиваем" из п.1, то изображение сканируется
|
||||
не "три с половиной", а "полтора" раза. Т.о., если "закрашивание" будет
|
||||
сканировать пиксели изображения лишь один раз, то получим весомый выигрыш.
|
||||
Однако, тут же всплывает и минус: параллелится эта задача только разбиением
|
||||
изображения на фреймы с последующим объединением оных. В принципе, если "закрашивание"
|
||||
будет достаточно быстрым, то проблем не будет: все равно алгоритм будет работать
|
||||
быстрее классического.
|
||||
|
||||
Итак, теперь остается прикинуть: что же за алгоритмы закрашивания есть.
|
||||
Если верить википедии, то самый быстрый алгоритм основывается на закрашивании
|
||||
области линиями с параллельной проверкой соседних сверху и снизу пикселей и
|
||||
занесением в список координат пикселей, которые появляются после 0. По окончанию
|
||||
сканирования линии, мы переходим к следующему пикселю в списке. И так до тех
|
||||
пор, пока список не кончится. Причем, сканирование идет в двух направлениях!
|
||||
|
||||
Еще я наткнулся на какой-то "очень быстрый метод" маркирования связанных областей
|
||||
от братьев-китайцев, но что-то даже после трехкратного прочтения я так и не понял:
|
||||
то ли братья-китайцы что-то темнят, то ли я - идиот (конечно, возможны оба
|
||||
варианта, но мне больше первый нравится).
|
||||
|
||||
Итак, хватит растекаться мысью по древу - пора переключаться в "медленный режим"
|
||||
и реализовывать методы. В любом случае, закрашивание областей реализовать надо
|
||||
(для начала - хотя бы 4-связанных, а о восьмисвязанных подумать, т.к. я что-то
|
||||
с трудом себе представляю реальные объекты, ограниченные четким 4-связанным
|
||||
контуром), поэтому стоит для начала на CPU с помощью openMP реализовать названные
|
||||
два способа маркировки, да и сравнить их: даже если окажется, что второй способ
|
||||
медленнее, он все равно понадобится для закрашивания.
|
||||
|
||||
|
||||
// что-то у меня промежуточные всякие выкладки много времени занимают: сейчас вот
|
||||
начал организовывать FIFO и подумал, что неплохо было бы туда и LIFO добавить...
|
||||
|
||||
|
||||
== реализация перемаркировки ==
|
||||
Реализуя перемаркировку, я наткнулся на кое-какие "косяки". В итоге "малюсенькая"
|
||||
inline-функция для перемаркировки превратилась в громоздкого монстра.
|
||||
Но надо еще протестировать на разных "картинках" ее поведение. Если проблем
|
||||
с перемаркировкой не будет, можно будет переходить к завершающему этапу - заполнению.
|
||||
|
||||
Так как в процессе перемаркировки счетчик количества объектов скачет туда-сюда,
|
||||
для завершающего - четвертого - этапа придется-таки использовать "полтора" прохода:
|
||||
сначала пробежаться по изображению с заполнением величин соответствующих боксов,
|
||||
а затем уже пробежаться по внутренностям каждого бокса, заполняя их маски.
|
||||
|
||||
Пожалуй, цикл по ремаркировке стоит вынести в отдельную функцию: тогда можно будет
|
||||
искать и 4-связанные области без предварительной 4-фильтрации.
|
||||
|
||||
Проверка на случайно сгенерированных "картинках" показала, что алгоритм вроде бы
|
||||
вполне рабочий. Надо бы добавить отбрасывание одиночных точек. Но что-то не
|
||||
хочется мне утяжелять и без того уже тормозной и раздувшийся алгоритм.
|
||||
Проще все-таки, наверное, сделать предварительную фильтрацию (по октетам)
|
||||
"сжатого" изображения (как в FCfilter), а потом уже обрабатывать ее результат.
|
||||
|
||||
Кстати, сейчас прогнал поиск 8-связанных областей по изображению, отфильтрованному
|
||||
функцией FCfilter, и до меня дошло, что все равно нужно писать отдельную функцию
|
||||
поиска 4-связанных областей, т.к. вполне может быть так, что две 4-связанные
|
||||
области соприкасаются по диагонали. При этом они являются разными объектами, но
|
||||
поиск 8-связанных областей обзывает их одинаково (что понятно).
|
||||
|
||||
Для упрощения громоздких выкладок я сделал такой велосипед: внутренности некоторых
|
||||
функций были вынесены в отдельные (многократно подключаемые) файлы. Перед подключением
|
||||
файла для модификации устанавливается тот или иной флаг. В результате некоторое
|
||||
количество условных операций отпадает. Правда, реализация перемаркировки
|
||||
получилась у меня такой страшнючей, что мне лень ее оптимизировать подобным образом.
|
||||
|
||||
Перед тем, как выполнить поиск 4-связанных областей, я выполняю фильтрацию. Она
|
||||
заодно отсекает и одиночные пиксели. А вот фильтрация для функции выделения
|
||||
8-связанных областей заключается в том, что как раз только одиночные пиксели
|
||||
и отсекаются. Жалею сейчас, что пока был в ИПФ, не нагуглил, как наиболее оптимально
|
||||
их фильтровать, поэтому опять буду изобретать велосипед.
|
||||
Фильтрация одиночных точек на "упакованном" изображении при помощи логических
|
||||
операций, как я говорил выше, использует огромное количество промежуточных
|
||||
вычислений, поэтому я даже и браться не буду за нее: выигрыш производительности
|
||||
получится сомнительным. Поэтому, пожалуй, проще всего будет воткнуть эту проверку
|
||||
в функцию поиска связанных областей.
|
||||
|
||||
Красотищща! Оно работает!!!
|
||||
|
||||
Рано радовался: запустил тест (случайная картинка 2000х2000): получилось, что
|
||||
cc4 работает почти в 2 раза медленней, чем cc8!!! Как? А ведь у cc8 значительно
|
||||
больше проверок... Черт знает что! Да и вообще не понравилось мне время
|
||||
выполнения: 13.3 секунд у cc4 и 7.8 у cc8. Кстати, я еще не реализовал
|
||||
шаг 4! При этом если из cc4 выкинуть функцию `FC_filter`, производительность
|
||||
возрастает еще на пару секунд (ну, это,
|
||||
наверное, из-за того, что приходится лишние пиксели проверять).
|
||||
|
||||
Я подозреваю, что виновата перемаркировка, занимающая тем больше времени,
|
||||
чем больше областей обнаружено на изображении. Сейчас воткну тайминги в cclabel.
|
||||
Тайминги показали, что действительно шаг 2 занимает на 4 порядка больше времени,
|
||||
чем остальные шаги. А ведь сканирование-то идет единожды!
|
||||
Отключив функцию ремаркировки, я получил крайне высокую производительность.
|
||||
Глянул количество первично обнаруженных областей - их больше 200 тысяч!
|
||||
Понятное дело, что если каждый раз при перемаркировке пробегаться по 200000
|
||||
значений, а ремаркировок получаем почти столько же, производительность выйдет
|
||||
вообще никакая!
|
||||
|
||||
В общем, надо думать, как оптимизировать это узкое место. Параллелизация
|
||||
дала прирост производительности всего лишь в полтора раза. Я, правда, еще заметил,
|
||||
что у меня количество итераций постоянно - по всем элементам, хотя стоит
|
||||
проверять лишь те, которые уже пройдены. Скорректировал, получил прирост
|
||||
производительности всего-то в полтора раза у cc4 и никакого прироста у cc8!
|
||||
|
||||
Уменьшив содержание единиц и нулей на изображении от 50/50 до 10/90, я получил
|
||||
поразительно низкие цифры для cc4: полторы сотни миллисекунд! Время cc8 получилось
|
||||
в районе 1с. Даже не знаю, нормально ли это: надо будет сравнить с другими
|
||||
алгоритмами (хотя бы с лептоникой).
|
||||
Уже сравнение с октавой показало, что у меня полная лажа: для тех же 50/50
|
||||
октава дает 20мс! Зато для 10/90 у меня быстрей, чем в октаве (но октава
|
||||
считает и одиночные точки :( ).
|
||||
|
||||
Проверка на очень большом количестве единиц показала, что считать все-таки надо
|
||||
не до текущего значения (я про цикл с перемаркировкой) ведь нижняя строчкае
|
||||
уже может быть ремаркирована -> получаем косячок-с. Чтобы его не было, добавлю
|
||||
"про запас" половину ширины строки (больше объектов все равно быть не может).
|
||||
|
||||
Я долго думал, как бы это на графах реализовать, но что-то так и не придумал.
|
||||
Посмотрел на время - уже начало 11-го. Пора баиньки, а то завтра в 4:30 вставать.
|
||||
|
||||
== другой метод ==
|
||||
Пока сидел в аэропорту НН, было время почитать статью китайцев. Действительно,
|
||||
интересный способ: мой метод (теоретически) будет хорош на небольшом количестве
|
||||
больших объектов, а их метод - на большом количестве малых.
|
||||
Принцип почти тот же, что и в моем случае, но:
|
||||
- шаги 1 и 2 объединены: на стадии именования меток происходит и ремаркировка;
|
||||
- второй проход (который у меня - третий) такой же, как у меня - переименование
|
||||
участков по скорректированным меткам.
|
||||
Правда, китайцы умолчали, как они создавали список меток: если его создавать
|
||||
динамически (как список, динамический массив или даже дерево), то все операции
|
||||
над списком будут довольно-таки дорогими, поэтому есть смысл просто выделить
|
||||
заранее достаточное количество памяти. Учитывая то, что объектов на изображении
|
||||
ну никак не может быть больше, чем 1/6 размера изображения, можно "на авось"
|
||||
выделить 1/4 размера изображения под массив ремаркировок.
|
||||
|
||||
Еще одним отличием является метод сканирования: сканируются все пиксели, но
|
||||
в зависимости от того, был ли ненулевой пиксель до текущего, или его не было,
|
||||
производятся разные действия: если точка новая, производится проверка ТРЕХ точек
|
||||
над ней (точки снизу не проверяются, понятное дело, т.к. происходит сканирование
|
||||
всех точек) с соответствующим именованием текущей точки и ремаркировкой, если мы
|
||||
натыкаемся на ситуацию, когда над точкой ничего нет, а вверху справа и слева -
|
||||
разные метки. Если же до текущей точки уже была точка, нам нужно лишь проверить,
|
||||
что находится в правом верхнем углу. Если там ничего нет, мы просто даем точке
|
||||
номер соседней слева, если же есть - все равно даем тот же номер, но еще и производим
|
||||
процедуру ремаркировки.
|
||||
|
||||
Благодаря такому методу сканирования (теоретически) повышается скорость: ремаркировки
|
||||
необходимо производить значительно реже. В общем, надо бы проверить этот метод.
|
||||
|
||||
Описанная выше процедура - для маркировки 8-связанных областей, если же нам нужно
|
||||
маркировать 4-связанные области, мы просто проверяем лишь точку НАД нашей.
|
||||
|
||||
Да уж, попытался я было что-нибудь "покодить", сидя в аэропорту. Оказалось, что это
|
||||
не так-то и просто: без мыши и нормальной клавиатуры ну совсем невозможно работать!
|
||||
Да еще и экран ноутбука перевешивает - бук так и норовит кувыркнуться с колен.
|
||||
В общем, откладываю до дома.
|
||||
|
||||
Черт бы подрал этот аэропорт: wifi как бы номинально есть, а реально - не работает,
|
||||
собака! Вроде бы соединяет, но скорость очень близка к нулю: tracepath дает
|
||||
аж секунды! В общем, на втором этаже жизни нет.
|
||||
|
||||
Все-таки сделал более-менее реализацию. Работает, но нужно еще внимательно
|
||||
просмотреть функцию ремаркировки: эта собака неправильно считает количество
|
||||
найденных объектов!
|
||||
|
||||
Бульбец! Самолет задерживают на полтора часа! Буду дописывать...
|
||||
431
_deprecated/erosion-dilation/binmorph.c
Normal file
431
_deprecated/erosion-dilation/binmorph.c
Normal file
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
* binmorph.c - functions for morphological operations on binary image
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
TEST (10000 dilations / erosions / substitutions) for i5-3210M CPU @ 2.50GHz x2cores x2hyper
|
||||
1. no openmp:
|
||||
* 28.8 / 29.2 / 14.8
|
||||
2. 2 threads:
|
||||
* 17.0 / 17.9 / 8.8
|
||||
3. 4 threads:
|
||||
* 17.0 / 17.5 / 8.8
|
||||
4. 8 threads:
|
||||
* 17.0 / 17.7 / 8.9
|
||||
*
|
||||
option -O3 gives for nthreads = 4:
|
||||
* 6.9 / 6.9 / 2.9
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <err.h>
|
||||
#include <sys/time.h>
|
||||
#include "binmorph.h"
|
||||
//#include "fifo.h"
|
||||
|
||||
#ifdef OMP
|
||||
#ifndef OMP_NUM_THREADS
|
||||
#define OMP_NUM_THREADS 4
|
||||
#endif
|
||||
#define Stringify(x) #x
|
||||
#define OMP_FOR(x) _Pragma(Stringify(omp parallel for x))
|
||||
#else
|
||||
#define OMP_FOR(x)
|
||||
#endif
|
||||
|
||||
// global arrays for erosion/dilation masks
|
||||
unsigned char *ER = NULL, *DIL = NULL;
|
||||
bool __Init_done = false; // == true if arrays are inited
|
||||
|
||||
/*
|
||||
* =================== AUXILIARY FUNCTIONS ===================>
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Memory allocation with control
|
||||
* @param N - number of elements
|
||||
* @param S - size of one element
|
||||
* @return allocated memory or die
|
||||
*/
|
||||
void *my_alloc(size_t N, size_t S){
|
||||
void *p = calloc(N, S);
|
||||
if(!p) err(1, "malloc");
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function inits masks arrays for erosion and dilation
|
||||
* You may call it yourself or it will be called when one of
|
||||
* `erosion` or `dilation` functions will be ran first time
|
||||
*/
|
||||
void morph_init(){
|
||||
if(__Init_done) return;
|
||||
int i;//,j;
|
||||
//bool a[8], b[8], c[9];
|
||||
ER = Malloc(256, 1);
|
||||
DIL = Malloc(256, 1);
|
||||
for(i = 0; i < 256; i++){
|
||||
/*ER[i] = DIL[i] = 0;
|
||||
for(j = 0; j < 8; j++){
|
||||
a[j] = (i >> j) & 1;
|
||||
b[j] = a[j];
|
||||
c[j] = a[j];
|
||||
}
|
||||
for(j = 1; j < 7; j++)
|
||||
if(!a[j])
|
||||
b[j+1] = b[j-1]= false;
|
||||
else
|
||||
c[j] = c[j-1] = c[j+1] = true;
|
||||
b[1] &= a[0]; b[6] &= a[7];
|
||||
c[1] |= a[0]; c[6] |= a[7];
|
||||
for(j = 0; j < 8; j++){
|
||||
ER[i] |= b[j] << j;
|
||||
DIL[i] |= c[j] << j;
|
||||
}
|
||||
*/
|
||||
ER[i] = i & ((i << 1) | 1) & ((i >> 1) | (0x80)); // don't forget that << and >> set borders to zero
|
||||
DIL[i] = i | (i << 1) | (i >> 1);
|
||||
}
|
||||
__Init_done = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print out small "packed" images as matrix of "0" and "1"
|
||||
* @param i (i) - image
|
||||
* @param W, H - size of image
|
||||
*/
|
||||
void printC(unsigned char *i, int W, int H){
|
||||
int x,y,b;
|
||||
for(y = 0; y < H; y++){
|
||||
for(x = 0; x < W; x++, i++){
|
||||
unsigned char c = *i;
|
||||
for(b = 0; b < 8; b++)
|
||||
printf("%c", c << b & 0x80 ? '1' : '0');
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print out small "unpacked" images as almost equiaxed matrix of ".." and "##"
|
||||
* @param img (i) - image
|
||||
* @param W, H - size of image
|
||||
*/
|
||||
void printB(bool *img, int W, int H){
|
||||
int i, j;
|
||||
for(j = 0; j < W; j++)
|
||||
if(j % 10 == 1){ printf("%02d", j-1); printf(" ");}
|
||||
printf("\n");
|
||||
for(i = 0; i < H; i++){
|
||||
printf("%2d ",i);
|
||||
for(j = 0; j < W; j++)
|
||||
printf("%s", (*img++) ? "##" : "..");
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* <=================== AUXILIARY FUNCTIONS ===================
|
||||
*/
|
||||
|
||||
/*
|
||||
* =================== CONVERT IMAGE TYPES ===================>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Convert boolean image into pseudo-packed (1 char == 8 pixels)
|
||||
* @param im (i) - image to convert
|
||||
* @param W, H - size of image im (must be larger than 1)
|
||||
* @param W_0 (o) - (stride) new width of image
|
||||
* @return allocated memory area with "packed" image
|
||||
*/
|
||||
unsigned char *bool2char(bool *im, int W, int H, int *W_0){
|
||||
if(W < 2 || H < 2) errx(1, "bool2char: image size too small");
|
||||
int y, W0 = (W + 7) / 8;
|
||||
unsigned char *ret = Malloc(W0 * H, 1);
|
||||
OMP_FOR()
|
||||
for(y = 0; y < H; y++){
|
||||
int x, i, X;
|
||||
bool *ptr = &im[y*W];
|
||||
unsigned char *rptr = &ret[y*W0];
|
||||
for(x = 0, X = 0; x < W0; x++, rptr++){
|
||||
for(i = 7; i > -1 && X < W; i--, X++, ptr++){
|
||||
*rptr |= *ptr << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(W_0) *W_0 = W0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert "packed" image into boolean
|
||||
* @param image (i) - input image
|
||||
* @param W, H, W_0 - size of image and width of "packed" image
|
||||
* @return allocated memory area with "unpacked" image
|
||||
*/
|
||||
bool *char2bool(unsigned char *image, int W, int H, int W_0){
|
||||
int y;
|
||||
bool *ret = Malloc(W * H, sizeof(bool));
|
||||
OMP_FOR()
|
||||
for(y = 0; y < H; y++){
|
||||
int x, X, i;
|
||||
bool *optr = &ret[y*W];
|
||||
unsigned char *iptr = &image[y*W_0];
|
||||
for(x = 0, X = 0; x < W_0; x++, iptr++)
|
||||
for(i = 7; i > -1 && X < W; i--, X++, optr++){
|
||||
*optr = (*iptr >> i) & 1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert "packed" image into size_t array for conncomp procedure
|
||||
* @param image (i) - input image
|
||||
* @param W, H, W_0 - size of image and width of "packed" image
|
||||
* @return allocated memory area with copy of an image
|
||||
*/
|
||||
size_t *char2st(unsigned char *image, int W, int H, int W_0){
|
||||
int y;
|
||||
size_t *ret = Malloc(W * H, sizeof(size_t));
|
||||
OMP_FOR()
|
||||
for(y = 0; y < H; y++){
|
||||
int x, X, i;
|
||||
size_t *optr = &ret[y*W];
|
||||
unsigned char *iptr = &image[y*W_0];
|
||||
for(x = 0, X = 0; x < W_0; x++, iptr++)
|
||||
for(i = 7; i > -1 && X < W; i--, X++, optr++){
|
||||
*optr = (*iptr >> i) & 1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* <=================== CONVERT IMAGE TYPES ===================
|
||||
*/
|
||||
|
||||
/*
|
||||
* =================== MORPHOLOGICAL OPERATIONS ===================>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Remove all non-4-connected pixels
|
||||
* @param image (i) - input image
|
||||
* @param W, H - size of image
|
||||
* @return allocated memory area with converted input image
|
||||
*/
|
||||
unsigned char *FC_filter(unsigned char *image, int W, int H){
|
||||
if(W < 1 || H < 2) errx(1, "4-connect: image size too small");
|
||||
unsigned char *ret = Malloc(W*H, 1);
|
||||
int y = 0, w = W-1, h = H-1;
|
||||
// top of image, y = 0
|
||||
#define IM_UP
|
||||
#include "fc_filter.h"
|
||||
#undef IM_UP
|
||||
// mid of image, y = 1..h-1
|
||||
#include "fc_filter.h"
|
||||
// image bottom, y = h
|
||||
y = h;
|
||||
#define IM_DOWN
|
||||
#include "fc_filter.h"
|
||||
#undef IM_DOWN
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make morphological operation of dilation
|
||||
* @param image (i) - input image
|
||||
* @param W, H - size of image
|
||||
* @return allocated memory area with dilation of input image
|
||||
*/
|
||||
unsigned char *dilation(unsigned char *image, int W, int H){
|
||||
if(W < 2 || H < 2) errx(1, "Dilation: image size too small");
|
||||
if(!__Init_done) morph_init();
|
||||
unsigned char *ret = Malloc(W*H, 1);
|
||||
int y = 0, w = W-1, h = H-1;
|
||||
// top of image, y = 0
|
||||
#define IM_UP
|
||||
#include "dilation.h"
|
||||
#undef IM_UP
|
||||
// mid of image, y = 1..h-1
|
||||
#include "dilation.h"
|
||||
// image bottom, y = h
|
||||
y = h;
|
||||
#define IM_DOWN
|
||||
#include "dilation.h"
|
||||
#undef IM_DOWN
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make morphological operation of erosion
|
||||
* @param image (i) - input image
|
||||
* @param W, H - size of image
|
||||
* @return allocated memory area with erosion of input image
|
||||
*/
|
||||
unsigned char *erosion(unsigned char *image, int W, int H){
|
||||
if(W < 2 || H < 2) errx(1, "Erosion: image size too small");
|
||||
if(!__Init_done) morph_init();
|
||||
unsigned char *ret = Malloc(W*H, 1);
|
||||
int y, w = W-1, h = H-1;
|
||||
OMP_FOR()
|
||||
for(y = 1; y < h; y++){ // reset first & last rows of image
|
||||
unsigned char *iptr = &image[W*y];
|
||||
unsigned char *optr = &ret[W*y];
|
||||
unsigned char p = ER[*iptr] & 0x7f & iptr[-W] & iptr[W];
|
||||
int x;
|
||||
if(!(iptr[1] & 0x80)) p &= 0xfe;
|
||||
*optr++ = p;
|
||||
iptr++;
|
||||
for(x = 1; x < w; x++, iptr++, optr++){
|
||||
p = ER[*iptr] & iptr[-W] & iptr[W];
|
||||
if(!(iptr[-1] & 1)) p &= 0x7f;
|
||||
if(!(iptr[1] & 0x80)) p &= 0xfe;
|
||||
*optr = p;
|
||||
}
|
||||
p = ER[*iptr] & 0xfe & iptr[-W] & iptr[W];
|
||||
if(!(iptr[-1] & 1)) p &= 0x7f;
|
||||
*optr++ = p;
|
||||
iptr++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* <=================== MORPHOLOGICAL OPERATIONS ===================
|
||||
*/
|
||||
|
||||
/*
|
||||
* =================== LOGICAL OPERATIONS ===================>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Logical AND of two images
|
||||
* @param im1, im2 (i) - two images
|
||||
* @param W, H - their size (of course, equal for both images)
|
||||
* @return allocated memory area with image = (im1 AND im2)
|
||||
*/
|
||||
unsigned char *imand(unsigned char *im1, unsigned char *im2, int W, int H){
|
||||
unsigned char *ret = Malloc(W*H, 1);
|
||||
int y;
|
||||
OMP_FOR()
|
||||
for(y = 0; y < H; y++){
|
||||
int x, S = y*W;
|
||||
unsigned char *rptr = &ret[S], *p1 = &im1[S], *p2 = &im2[S];
|
||||
for(x = 0; x < W; x++)
|
||||
*rptr++ = *p1++ & *p2++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitute image 2 from image 1: reset to zero all bits of image 1 which set to 1 on image 2
|
||||
* @param im1, im2 (i) - two images
|
||||
* @param W, H - their size (of course, equal for both images)
|
||||
* @return allocated memory area with image = (im1 AND (!im2))
|
||||
*/
|
||||
unsigned char *substim(unsigned char *im1, unsigned char *im2, int W, int H){
|
||||
unsigned char *ret = Malloc(W*H, 1);
|
||||
int y;
|
||||
OMP_FOR()
|
||||
for(y = 0; y < H; y++){
|
||||
int x, S = y*W;
|
||||
unsigned char *rptr = &ret[S], *p1 = &im1[S], *p2 = &im2[S];
|
||||
for(x = 0; x < W; x++)
|
||||
*rptr++ = *p1++ & (~*p2++);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* <=================== LOGICAL OPERATIONS ===================
|
||||
*/
|
||||
|
||||
/*
|
||||
* =================== CONNECTED COMPONENTS LABELING ===================>
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* label 4-connected components on image
|
||||
* (slow algorythm, but easy to parallel)
|
||||
*
|
||||
* @param I (i) - image ("packed")
|
||||
* @param W,H,W_0 - size of the image (W - width in pixels, W_0 - width in octets)
|
||||
* @param Nobj (o) - number of objects found
|
||||
* @return an array of labeled components
|
||||
*/
|
||||
CCbox *cclabel4(unsigned char *Img, int W, int H, int W_0, size_t *Nobj){
|
||||
unsigned char *I = FC_filter(Img, W_0, H);
|
||||
#include "cclabling.h"
|
||||
FREE(I);
|
||||
return ret;
|
||||
}
|
||||
|
||||
CCbox *cclabel4_1(unsigned char *Img, int W, int H, int W_0, size_t *Nobj){
|
||||
unsigned char *I = FC_filter(Img, W_0, H);
|
||||
#include "cclabling_1.h"
|
||||
FREE(I);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// label 8-connected components, look cclabel4
|
||||
CCbox *cclabel8(unsigned char *I, int W, int H, int W_0, size_t *Nobj){
|
||||
//unsigned char *I = EC_filter(Img, W_0, H);
|
||||
#define LABEL_8
|
||||
#include "cclabling.h"
|
||||
#undef LABEL_8
|
||||
// FREE(I);
|
||||
return ret;
|
||||
}
|
||||
|
||||
CCbox *cclabel8_1(unsigned char *I, int W, int H, int W_0, size_t *Nobj){
|
||||
#define LABEL_8
|
||||
#include "cclabling_1.h"
|
||||
#undef LABEL_8
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* <=================== CONNECTED COMPONENTS LABELING ===================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* <=================== template ===================>
|
||||
*/
|
||||
87
_deprecated/erosion-dilation/binmorph.h
Normal file
87
_deprecated/erosion-dilation/binmorph.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* binmorph.h
|
||||
*
|
||||
* 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 __EROSION_DILATION_H__
|
||||
#define __EROSION_DILATION_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef EBUG
|
||||
#define DBG(...) do{fprintf(stderr, __VA_ARGS__);}while(0)
|
||||
#else
|
||||
#define DBG(...)
|
||||
#endif
|
||||
|
||||
#define _U_ __attribute__((__unused__))
|
||||
|
||||
#ifndef Malloc
|
||||
#define Malloc my_alloc
|
||||
#endif
|
||||
|
||||
#ifndef FREE
|
||||
#define FREE(arg) do{free(arg); arg = NULL;}while(0)
|
||||
#endif
|
||||
|
||||
#ifndef _
|
||||
#define _(X) X
|
||||
#endif
|
||||
|
||||
// auxiliary functions
|
||||
void *my_alloc(size_t N, size_t S);
|
||||
double dtime();
|
||||
void printC(unsigned char *i, int W, int H);
|
||||
void printB(bool *i, int W, int H);
|
||||
void morph_init(); // there's no need to run it by hands, but your will is the law
|
||||
|
||||
// convert image types
|
||||
unsigned char *bool2char(bool *im, int W, int H, int *stride);
|
||||
bool *char2bool(unsigned char *image, int W, int H, int W_0);
|
||||
size_t *char2st(unsigned char *image, int W, int H, int W_0);
|
||||
|
||||
// morphological operations
|
||||
unsigned char *dilation(unsigned char *image, int W, int H);
|
||||
unsigned char *erosion(unsigned char *image, int W, int H);
|
||||
unsigned char *FC_filter(unsigned char *image, int W, int H);
|
||||
|
||||
// logical operations
|
||||
unsigned char *imand(unsigned char *im1, unsigned char *im2, int W, int H);
|
||||
unsigned char *substim(unsigned char *im1, unsigned char *im2, int W, int H);
|
||||
|
||||
// conncomp
|
||||
// this is a box structure containing one object; data is aligned by original image bytes!
|
||||
typedef struct {
|
||||
unsigned char *data; // pattern data in "packed" format
|
||||
int x, // x coordinate of LU-pixel of box in "unpacked" image (by pixels)
|
||||
y, // y -//-
|
||||
x_0; // x coordinate in "packed" image (morph operations should work with it)
|
||||
size_t N;// number of component, starting from 1
|
||||
} CCbox;
|
||||
|
||||
CCbox *cclabel4(unsigned char *I, int W, int H, int W_0, size_t *Nobj);
|
||||
CCbox *cclabel8(unsigned char *I, int W, int H, int W_0, size_t *Nobj);
|
||||
|
||||
CCbox *cclabel4_1(unsigned char *I, int W, int H, int W_0, size_t *Nobj);
|
||||
CCbox *cclabel8_1(unsigned char *I, int W, int H, int W_0, size_t *Nobj);
|
||||
#endif // __EROSION_DILATION_H__
|
||||
|
||||
|
||||
210
_deprecated/erosion-dilation/cclabling.h
Normal file
210
_deprecated/erosion-dilation/cclabling.h
Normal file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* cclabling.h - inner part of functions cclabel4 and cclabel8
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
double t0 = dtime();
|
||||
CCbox *ret = NULL;
|
||||
size_t N _U_ = 0, Ncur = 0;
|
||||
size_t *labels = char2st(I, W, H, W_0);
|
||||
int y;
|
||||
/*
|
||||
#ifdef EBUG
|
||||
for(y = 0; y < H; y++){
|
||||
size_t *ptr = &labels[y*W];
|
||||
for(int x = 0; x < W; x++, ptr++){
|
||||
if(*ptr) printf("%02zx", *ptr);
|
||||
else printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
FREE(labels); return ret;
|
||||
#endif
|
||||
*/
|
||||
//printf("time for char2st: %gs\n", dtime()-t0);
|
||||
//t0 = dtime();
|
||||
// Step 1: mark neighbours by strings
|
||||
size_t *ptr = labels;
|
||||
for(y = 0; y < H; y++){
|
||||
bool found = false;
|
||||
for(int x = 0; x < W; x++, ptr++){
|
||||
if(!*ptr){ found = false; continue;}
|
||||
if(!found){
|
||||
found = true;
|
||||
++Ncur;
|
||||
}
|
||||
*ptr = Ncur;
|
||||
}
|
||||
}
|
||||
//printf("\n\ntime for step1: %gs (Ncur=%zd)\n", dtime()-t0, Ncur);
|
||||
//t0 = dtime();
|
||||
DBG("Initial mark\n");
|
||||
#ifdef EBUG
|
||||
for(y = 0; y < H; y++){
|
||||
size_t *ptr = &labels[y*W];
|
||||
for(int x = 0; x < W; x++, ptr++){
|
||||
if(*ptr) printf("%02zx", *ptr);
|
||||
else printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Step 2: fill associative array with remarking
|
||||
DBG("remarking\n");
|
||||
N = Ncur+1; // size of markers array (starting from 1)
|
||||
size_t i, *assoc = Malloc(N, sizeof(size_t));
|
||||
for(i = 0; i < N; i++) assoc[i] = i; // primary initialisation
|
||||
// now we should scan image again to rebuild enumeration
|
||||
// THIS PROCESS AVOID PARALLELISATION???
|
||||
Ncur = 0;
|
||||
size_t h = H-1, w = W-1;
|
||||
inline void remark(size_t old, size_t *newv){
|
||||
size_t new = *newv;
|
||||
if(assoc[old] == new){
|
||||
DBG("(%zd)\n", new);
|
||||
return;
|
||||
}
|
||||
DBG("[%zx], %zx -> %zx ", Ncur, old, new);
|
||||
if(assoc[old] == old){ // remark non-remarked value
|
||||
assoc[old] = new;
|
||||
DBG("\n");
|
||||
return;
|
||||
}
|
||||
// value was remarked -> we have to remark "new" to assoc[old]
|
||||
// and decrement all marks, that are greater than "new"
|
||||
size_t ao = assoc[old];
|
||||
DBG("(remarked to %zx) ", assoc[old]);
|
||||
// now we must check assoc[old]: if it is < new -> change *newv, else remark assoc[old]
|
||||
if(ao < new)
|
||||
*newv = ao;
|
||||
else{
|
||||
size_t x = ao; ao = new; new = x; // swap values
|
||||
}
|
||||
int xx = old + W / 2;
|
||||
if(xx > N) xx = N;
|
||||
OMP_FOR()
|
||||
for(int i = 1; i <= xx; i++){
|
||||
size_t m = assoc[i];
|
||||
if(m < new) continue;
|
||||
if(m == new){
|
||||
assoc[i] = ao;
|
||||
DBG("remark %x (%zd) to %zx ", i, m, ao);
|
||||
}else if(m <= Ncur){
|
||||
assoc[i]--;
|
||||
DBG("decr %x: %zx, ", i, assoc[i]);
|
||||
}
|
||||
}
|
||||
DBG("\n");
|
||||
Ncur--;
|
||||
}
|
||||
for(y = 0; y < H; y++){ // FIXME!!!! throw out that fucking "if" checking coordinates!!!
|
||||
size_t *ptr = &labels[y*W];
|
||||
bool found = false;
|
||||
for(int x = 0; x < W; x++, ptr++){
|
||||
size_t curval = *ptr;
|
||||
if(!curval){ found = false; continue;}
|
||||
if(found) continue; // we go through remarked pixels
|
||||
found = true;
|
||||
DBG("curval: %zx ", curval);
|
||||
// now check neighbours in upper and lower string:
|
||||
size_t *U = (y) ? &ptr[-W] : NULL;
|
||||
size_t *D = (y < h) ? &ptr[W] : NULL;
|
||||
size_t upmark = 0; // mark from line above
|
||||
if(U){
|
||||
#ifdef LABEL_8
|
||||
if(x && U[-1]){ // there is something in upper left corner -> make remark by its value
|
||||
upmark = assoc[U[-1]];
|
||||
}else // check point above only if there's nothing in left up
|
||||
#endif
|
||||
if(U[0]) upmark = assoc[U[0]];
|
||||
#ifdef LABEL_8
|
||||
if(x < w) if(U[1]){ // there's something in upper right
|
||||
if(upmark){ // to the left of it was pixels
|
||||
remark(U[1], &upmark);
|
||||
}else
|
||||
upmark = assoc[U[1]];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(!upmark){ // there's nothing above - set current pixel to incremented counter
|
||||
#ifdef LABEL_8 // check, whether pixel is not single
|
||||
if( !(x && ((D && D[-1]) || ptr[-1])) // no left neighbours
|
||||
&& !(x < w && ((D && D[1]) || ptr[1])) // no right neighbours
|
||||
&& !(D && D[0])){ // no neighbour down
|
||||
*ptr = 0; // erase this hermit!
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
// no neighbour down & neighbour to the right -> hermit
|
||||
if((y < h && ptr[W] == 0) && (x < w && ptr[1] == 0)){
|
||||
*ptr = 0; // erase this hermit!
|
||||
DBG("hermit!\n");
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
upmark = ++Ncur;
|
||||
}
|
||||
|
||||
// now remark DL and DR corners (bottom pixel will be checked on next line)
|
||||
if(D){
|
||||
#ifdef LABEL_8
|
||||
if(x && D[-1]){
|
||||
remark(D[-1], &upmark);
|
||||
}
|
||||
if(x < w && D[1]){
|
||||
remark(D[1], &upmark);
|
||||
}
|
||||
#else
|
||||
if(D[0]) remark(D[0], &upmark);
|
||||
#endif
|
||||
}
|
||||
// remark current
|
||||
remark(curval, &upmark);
|
||||
}
|
||||
}
|
||||
//printf("time for step 2: %gs, found %zd objects\n", dtime()-t0, Ncur);
|
||||
//t0 = dtime();
|
||||
// Step 3: rename markers
|
||||
DBG("rename markers\n");
|
||||
// first correct complex assotiations in assoc
|
||||
OMP_FOR()
|
||||
for(y = 0; y < H; y++){
|
||||
size_t *ptr = &labels[y*W];
|
||||
for(int x = 0; x < W; x++, ptr++){
|
||||
size_t p = *ptr;
|
||||
if(!p){continue;}
|
||||
*ptr = assoc[p];
|
||||
}
|
||||
}
|
||||
//printf("time for step 3: %gs\n", dtime()-t0);
|
||||
#ifdef EBUG
|
||||
printf("\n\n");
|
||||
for(y = 0; y < H; y++){
|
||||
size_t *ptr = &labels[y*W];
|
||||
for(int x = 0; x < W; x++, ptr++){
|
||||
if(*ptr) printf("%02zx", *ptr);
|
||||
else printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
FREE(assoc);
|
||||
FREE(labels);
|
||||
printf("%6.4f\t%zd\n", dtime()-t0, Ncur);
|
||||
168
_deprecated/erosion-dilation/cclabling_1.h
Normal file
168
_deprecated/erosion-dilation/cclabling_1.h
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* cclabling_1.h - inner part of functions cclabel4_1 and cclabel8_1
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
double t0 = dtime();
|
||||
|
||||
CCbox *ret = NULL;
|
||||
size_t N = 0, // current label
|
||||
Nmax = W*H/4; // max number of labels
|
||||
size_t *labels = char2st(I, W, H, W_0);
|
||||
int w = W - 1, h = H - 1;
|
||||
//printf("time for char2st: %gs\n", dtime()-t0);
|
||||
int y;
|
||||
size_t *assoc = Malloc(Nmax, sizeof(size_t)); // allocate memory for "remark" array
|
||||
size_t last_assoc_idx = 0; // last index filled in assoc array
|
||||
size_t currentnum = 0; // current pixel number
|
||||
inline void remark(size_t old, size_t new){ // remark in assoc[] pixel with value old to assoc[new] or vice versa
|
||||
size_t New = assoc[new], Old = assoc[old];
|
||||
if(Old == New){
|
||||
DBG("components equal (%zd->%zd and %zd->%zd)\n", old, Old, new, New);
|
||||
return;
|
||||
}
|
||||
DBG("N=%zd, curr=%zd, old:%zd->%zd <-> new:%zd->%zd ", N, currentnum, old, Old, new, New);
|
||||
// now we must check Old: if Old<New we should swap them
|
||||
if(Old < New){
|
||||
register size_t _tmp_ = Old; Old = New; New = _tmp_; // swap values
|
||||
_tmp_ = old; old = new; new = _tmp_;
|
||||
}
|
||||
// decrement counters for current value (because we make merging)
|
||||
--currentnum;
|
||||
//OMP_FOR()
|
||||
for(size_t i = 1; i < last_assoc_idx; ++i){
|
||||
size_t m = assoc[i];
|
||||
DBG("assoc[%zd]=%zd ", i, m);
|
||||
if(m < Old) continue; // lower values
|
||||
if(m == Old){ // change all old markers to new
|
||||
assoc[i] = New;
|
||||
DBG("remark %zd->%zd to ->%zd ", i, m, New);
|
||||
}else{ // decrement all higher values
|
||||
DBG("decr %zd->%zd, ", i, m);
|
||||
assoc[i]--;
|
||||
}
|
||||
}
|
||||
DBG("\n");
|
||||
}
|
||||
//t0 = dtime();
|
||||
size_t *ptr = labels;
|
||||
for(y = 0; y < H; y++){
|
||||
bool found = false;
|
||||
size_t curmark = 0; // mark of pixel to the left
|
||||
for(int x = 0; x < W; x++, ptr++){
|
||||
size_t curval = *ptr;
|
||||
if(!curval){ found = false; continue;}
|
||||
size_t *U = (y) ? &ptr[-W] : NULL;
|
||||
size_t upmark = 0; // mark from line above
|
||||
if(!found){ // new pixel, check neighbours above
|
||||
found = true;
|
||||
// now check neighbours in upper string:
|
||||
if(U){
|
||||
#ifdef LABEL_8
|
||||
if(x && U[-1]){ // there is something in upper left corner -> use its value
|
||||
upmark = U[-1];
|
||||
}else // check point above only if there's nothing in left up
|
||||
#endif
|
||||
if(U[0]) upmark = U[0];
|
||||
#ifdef LABEL_8
|
||||
if(x < w && U[1]){ // there's something in upper right
|
||||
if(upmark){ // to the left of it was pixels
|
||||
remark(U[1], upmark);
|
||||
}else
|
||||
upmark = U[1];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(!upmark){ // there's nothing above - set current pixel to incremented counter
|
||||
DBG("line #%d (w = %d) ", y, h);
|
||||
#ifdef LABEL_8 // check, whether pixel is not single
|
||||
size_t *D = (y < h) ? &ptr[W] : NULL;
|
||||
if( !(x && ((D && D[-1]) /*|| ptr[-1]*/)) // no left neighbours
|
||||
&& !(x < w && ((D && D[1]) || ptr[1])) // no right neighbours
|
||||
&& !(D && D[0])){ // no neighbour down
|
||||
*ptr = 0; // erase this hermit!
|
||||
DBG("hermit!\n");
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
// no neighbour down & neighbour to the right -> hermit
|
||||
if((y < h && ptr[W] == 0) && (x < w && ptr[1] == 0)){
|
||||
*ptr = 0; // erase this hermit!
|
||||
DBG("hermit!\n");
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
upmark = ++N;
|
||||
assoc[upmark] = ++currentnum; // refresh "assoc"
|
||||
DBG("assoc[%zd] = %zd\n", upmark, currentnum);
|
||||
last_assoc_idx = upmark + 1;
|
||||
}
|
||||
*ptr = upmark;
|
||||
curmark = upmark;
|
||||
}else{ // there was something to the left -> we must chek only U[1]
|
||||
if(U){
|
||||
if(x < w && U[1]){ // there's something in upper right
|
||||
remark(U[1], curmark);
|
||||
}
|
||||
}
|
||||
*ptr = curmark;
|
||||
}
|
||||
}
|
||||
}
|
||||
//printf("time for step 2: %gs, found %zd objects\n", dtime()-t0, currentnum);
|
||||
DBG("Initial mark\n");
|
||||
#ifdef EBUG
|
||||
for(y = 0; y < H; y++){
|
||||
size_t *ptr = &labels[y*W];
|
||||
for(int x = 0; x < W; x++, ptr++){
|
||||
if(*ptr) printf("%02zx", *ptr);
|
||||
else printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
//t0 = dtime();
|
||||
// Step 2: rename markers
|
||||
DBG("rename markers\n");
|
||||
// first correct complex assotiations in assoc
|
||||
OMP_FOR()
|
||||
for(y = 0; y < H; y++){
|
||||
size_t *ptr = &labels[y*W];
|
||||
for(int x = 0; x < W; x++, ptr++){
|
||||
size_t p = *ptr;
|
||||
if(!p){continue;}
|
||||
*ptr = assoc[p];
|
||||
}
|
||||
}
|
||||
//printf("time for step 3: %gs\n", dtime()-t0);
|
||||
#ifdef EBUG
|
||||
printf("\n\n");
|
||||
for(y = 0; y < H; y++){
|
||||
size_t *ptr = &labels[y*W];
|
||||
for(int x = 0; x < W; x++, ptr++){
|
||||
if(*ptr) printf("%02zx", *ptr);
|
||||
else printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
FREE(assoc);
|
||||
FREE(labels);
|
||||
printf("%6.4f\t%zd\n", dtime()-t0, currentnum);
|
||||
75
_deprecated/erosion-dilation/dilation.h
Normal file
75
_deprecated/erosion-dilation/dilation.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* dilation.h - inner part of function `dilation`
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* HERE'S NO ANY "FILE-GUARDS" BECAUSE FILE IS MULTIPLY INCLUDED!
|
||||
* I use this because don't want to dive into depths of BOOST
|
||||
*
|
||||
* multi-including with different defines before - is a simplest way to
|
||||
* modify simple code for avoiding extra if-then-else
|
||||
*/
|
||||
|
||||
|
||||
#if ! defined IM_UP && ! defined IM_DOWN // image without upper and lower borders
|
||||
OMP_FOR()
|
||||
for(y = 1; y < h; y++)
|
||||
#endif
|
||||
{
|
||||
unsigned char *iptr = &image[W*y];
|
||||
unsigned char *optr = &ret[W*y];
|
||||
unsigned char p = DIL[*iptr]
|
||||
#ifndef IM_UP
|
||||
| iptr[-W]
|
||||
#endif
|
||||
#ifndef IM_DOWN
|
||||
| iptr[W]
|
||||
#endif
|
||||
;
|
||||
int x;
|
||||
if(iptr[1] & 0x80) p |= 1;
|
||||
*optr = p;
|
||||
optr++; iptr++;
|
||||
for(x = 1; x < w; x++, iptr++, optr++){
|
||||
p = DIL[*iptr]
|
||||
#ifndef IM_UP
|
||||
| iptr[-W]
|
||||
#endif
|
||||
#ifndef IM_DOWN
|
||||
| iptr[W]
|
||||
#endif
|
||||
;
|
||||
if(iptr[1] & 0x80) p |= 1;
|
||||
if(iptr[-1] & 1) p |= 0x80;
|
||||
*optr = p;
|
||||
}
|
||||
p = DIL[*iptr]
|
||||
#ifndef IM_UP
|
||||
| iptr[-W]
|
||||
#endif
|
||||
#ifndef IM_DOWN
|
||||
| iptr[W]
|
||||
#endif
|
||||
;
|
||||
if(iptr[-1] & 1) p |= 0x80;
|
||||
*optr = p;
|
||||
optr++; iptr++;
|
||||
}
|
||||
|
||||
67
_deprecated/erosion-dilation/fc_filter.h
Normal file
67
_deprecated/erosion-dilation/fc_filter.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* fc_filter.h - inner part of function `FC_filter`
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// The same shit as for dilation.h
|
||||
|
||||
#if ! defined IM_UP && ! defined IM_DOWN
|
||||
OMP_FOR()
|
||||
for(y = 1; y < h; y++)
|
||||
#endif
|
||||
{
|
||||
unsigned char *iptr = &image[W*y];
|
||||
unsigned char *optr = &ret[W*y];
|
||||
unsigned char p = *iptr << 1 | *iptr >> 1
|
||||
#ifndef IM_UP
|
||||
| iptr[-W]
|
||||
#endif
|
||||
#ifndef IM_DOWN
|
||||
| iptr[W]
|
||||
#endif
|
||||
;
|
||||
int x;
|
||||
if(iptr[1] & 0x80) p |= 1;
|
||||
*optr = p & *iptr;
|
||||
optr++; iptr++;
|
||||
for(x = 1; x < w; x++, iptr++, optr++){
|
||||
p = *iptr << 1 | *iptr >> 1
|
||||
#ifndef IM_UP
|
||||
| iptr[-W]
|
||||
#endif
|
||||
#ifndef IM_DOWN
|
||||
| iptr[W]
|
||||
#endif
|
||||
;
|
||||
if(iptr[1] & 0x80) p |= 1;
|
||||
if(iptr[-1] & 1) p |= 0x80;
|
||||
*optr = p & *iptr;
|
||||
}
|
||||
p = *iptr << 1 | *iptr >> 1
|
||||
#ifndef IM_UP
|
||||
| iptr[-W]
|
||||
#endif
|
||||
#ifndef IM_DOWN
|
||||
| iptr[W]
|
||||
#endif
|
||||
;
|
||||
if(iptr[-1] & 1) p |= 0x80;
|
||||
*optr = p & *iptr;
|
||||
optr++; iptr++;
|
||||
}
|
||||
0
_deprecated/erosion-dilation/fs_filter.h
Normal file
0
_deprecated/erosion-dilation/fs_filter.h
Normal file
114
_deprecated/erosion-dilation/main.c
Normal file
114
_deprecated/erosion-dilation/main.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* main.c - test file for binmorph.c
|
||||
*
|
||||
* 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 <math.h>
|
||||
#include <stdio.h>
|
||||
#include "binmorph.h"
|
||||
|
||||
// these includes are for randini
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
/*
|
||||
* Generate a quasy-random number to initialize PRNG
|
||||
* name: throw_random_seed
|
||||
* @return value for curandSetPseudoRandomGeneratorSeed or srand48
|
||||
*/
|
||||
long throw_random_seed(){
|
||||
//FNAME();
|
||||
long r_ini;
|
||||
int fail = 0;
|
||||
int fd = open("/dev/random", O_RDONLY);
|
||||
do{
|
||||
if(-1 == fd){
|
||||
fail = 1; break;
|
||||
}
|
||||
if(sizeof(long) != read(fd, &r_ini, sizeof(long))){
|
||||
fail = 1;
|
||||
}
|
||||
close(fd);
|
||||
}while(0);
|
||||
if(fail){
|
||||
double tt = dtime() * 1e6;
|
||||
double mx = (double)LONG_MAX;
|
||||
r_ini = (long)(tt - mx * floor(tt/mx));
|
||||
}
|
||||
return (r_ini);
|
||||
}
|
||||
|
||||
|
||||
int main(int ac, char **v){
|
||||
int i,j, W = 500, H = 500, W_0;
|
||||
//double midX = (W - 1.0)/ 4. - 1., midY = (H - 1.) / 4. - 1.;
|
||||
//double ro = sqrt(midX*midY), ri = ro / 1.5;
|
||||
bool *inp = Malloc(W * H, sizeof(bool));
|
||||
srand48(throw_random_seed());
|
||||
for(i = 0; i < H; i++)
|
||||
for(j = 0; j < W; j++)
|
||||
inp[i*W+j] = (drand48() > 0.7);
|
||||
unsigned char *b2ch = bool2char(inp, W, H, &W_0);//, *immer;
|
||||
/*printf("image:\n");
|
||||
printC(b2ch, W_0, H);*/
|
||||
// immer = FC_filter(b2ch, W_0, H);
|
||||
// printf("\n\n\nFilter for 4-connected areas searching:\n");
|
||||
// printC(immer, W_0, H);
|
||||
// FREE(immer);
|
||||
size_t NL;
|
||||
// printf("\nmark 4-connected components:\n");
|
||||
printf("4new\t");
|
||||
cclabel4_1(b2ch, W, H, W_0, &NL);
|
||||
// printf("\nmark 4-connected components (old):\n");
|
||||
printf("4old\t");
|
||||
cclabel4(b2ch, W, H, W_0, &NL);
|
||||
// printf("\nmark 8-connected components:\n");
|
||||
printf("8new\t");
|
||||
cclabel8_1(b2ch, W, H, W_0, &NL);
|
||||
// printf("\nmark 8-connected components (old):\n");
|
||||
printf("8old\t");
|
||||
cclabel8(b2ch, W, H, W_0, &NL);
|
||||
FREE(b2ch);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* bench
|
||||
* names = ["4new"; "4old"; "8new"; "8old"]; for i = 1:4; nm = names(i,:); time = []; sz = []; for i = 1:52; if(name{i} == nm) time = [time speed(i)]; sz = [sz num(i)]; endif;endfor; ts = time./sz; printf("%s: time/object = %.1f +- %.1f us\n", nm, mean(ts)*1e6, std(ts)*1e6);endfor;
|
||||
*
|
||||
* 0.25 megapixels
|
||||
* 4new: time/object = 1.9 +- 0.4 us
|
||||
* 4old: time/object = 1.7 +- 0.1 us
|
||||
* 8new: time/object = 3.9 +- 0.1 us
|
||||
* 8old: time/object = 13.5 +- 2.1 us
|
||||
*
|
||||
* 1 megapixels ---> [name speed num] = textread("1megapixel", "%s %f %f");
|
||||
* 4new: time/object = 5.5 +- 0.5 us
|
||||
* 4old: time/object = 5.3 +- 0.0 us
|
||||
* 8new: time/object = 13.3 +- 0.1 us
|
||||
* 8old: time/object = 47.6 +- 2.2 us
|
||||
*
|
||||
* 4 megapixels ---> [name speed num] = textread("4megapixels", "%s %f %f");
|
||||
* 4new: time/object = 21.3 +- 1.5 us
|
||||
* 4old: time/object = 22.3 +- 2.2 us
|
||||
* 8new: time/object = 57.6 +- 1.3 us
|
||||
* 8old: time/object = 195.5 +- 11.7 us
|
||||
*
|
||||
*
|
||||
*/
|
||||
129
_deprecated/fifo_lifo.c
Normal file
129
_deprecated/fifo_lifo.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* fifo_lifo.c - simple FIFO/LIFO
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "fifo_lifo.h"
|
||||
|
||||
#ifndef Malloc
|
||||
#define Malloc my_alloc
|
||||
/**
|
||||
* Memory allocation with control
|
||||
* @param N - number of elements
|
||||
* @param S - size of one element
|
||||
* @return allocated memory or die
|
||||
*/
|
||||
void *my_alloc(size_t N, size_t S){
|
||||
void *p = calloc(N, S);
|
||||
if(!p) err(1, "malloc");
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
#ifndef FREE
|
||||
#define FREE(arg) do{free(arg); arg = NULL;}while(0)
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* push data into the tail of a stack (like FIFO)
|
||||
* @param lst (io) - list
|
||||
* @param v (i) - data to push
|
||||
* @return pointer to just pused node
|
||||
*/
|
||||
List *push_tail(List **lst, Ldata v){
|
||||
List *node;
|
||||
if(!lst) return NULL;
|
||||
if((node = (List*) Malloc(1, sizeof(List))) == 0)
|
||||
return NULL; // allocation error
|
||||
node->data = v; // insert data
|
||||
if(!*lst){
|
||||
*lst = node;
|
||||
(*lst)->last = node;
|
||||
return node;
|
||||
}
|
||||
(*lst)->last->next = node;
|
||||
(*lst)->last = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* push data into the head of a stack (like LIFO)
|
||||
* @param lst (io) - list
|
||||
* @param v (i) - data to push
|
||||
* @return pointer to just pused node
|
||||
*/
|
||||
List *push(List **lst, Ldata v){
|
||||
List *node;
|
||||
if(!lst) return NULL;
|
||||
if((node = (List*) Malloc(1, sizeof(List))) == 0)
|
||||
return NULL; // allocation error
|
||||
node->data = v; // insert data
|
||||
if(!*lst){
|
||||
*lst = node;
|
||||
(*lst)->last = node;
|
||||
return node;
|
||||
}
|
||||
node->next = *lst;
|
||||
node->last = (*lst)->last;
|
||||
*lst = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* get data from head of list
|
||||
* @param lst (io) - list
|
||||
* @return data from lst head
|
||||
*/
|
||||
Ldata pop(List **lst){
|
||||
Ldata ret;
|
||||
List *node = *lst;
|
||||
if(!lst) errx(1, "NULL pointer to buffer");
|
||||
if(!*lst) errx(1, "Empty buffer");
|
||||
ret = (*lst)->data;
|
||||
*lst = (*lst)->next;
|
||||
FREE(node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef STANDALONE
|
||||
int main(void) {
|
||||
List *f = NULL;
|
||||
int i, d, ins[] = {4,2,6,1,3,4,7};
|
||||
for(i = 0; i < 7; i++)
|
||||
if(!(push(&f, ins[i])))
|
||||
err(1, "Malloc error"); // can't insert
|
||||
else printf("pushed %d\n", ins[i]);
|
||||
while(f){
|
||||
d = pop(&f);
|
||||
printf("pulled: %d\n", d);
|
||||
}
|
||||
for(i = 0; i < 7; i++)
|
||||
if(!(push_tail(&f, ins[i])))
|
||||
err(1, "Malloc error"); // can't insert
|
||||
else printf("pushed to head %d\n", ins[i]);
|
||||
while(f){
|
||||
d = pop(&f);
|
||||
printf("pulled: %d\n", d);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
37
_deprecated/fifo_lifo.h
Normal file
37
_deprecated/fifo_lifo.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* fifo_lifo.h
|
||||
*
|
||||
* 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 __FIFO_LIFO_H__
|
||||
#define __FIFO_LIFO_H__
|
||||
|
||||
typedef int Ldata;
|
||||
|
||||
typedef struct buff_node{
|
||||
Ldata data;
|
||||
struct buff_node *next, *last;
|
||||
} List;
|
||||
|
||||
List *push_tail(List **lst, Ldata v);
|
||||
List *push(List **lst, Ldata v);
|
||||
Ldata pop(List **lst);
|
||||
|
||||
#endif // __FIFO_LIFO_H__
|
||||
9
_deprecated/getopt/README
Normal file
9
_deprecated/getopt/README
Normal file
@@ -0,0 +1,9 @@
|
||||
1. Functions for simplify control of complex parameters
|
||||
cmdlnopts.c - example of use
|
||||
parceargs.c - main functions
|
||||
parceargs.h - their header
|
||||
|
||||
2. Functions for regular getopt_long
|
||||
getopt.c - snippet file
|
||||
getopt.h - its header
|
||||
|
||||
22
_deprecated/getopt/cmdlnopts/Makefile
Normal file
22
_deprecated/getopt/cmdlnopts/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
PROGRAM = myopt_example
|
||||
LDFLAGS = -lm
|
||||
SRCS = $(wildcard *.c)
|
||||
CC = gcc
|
||||
DEFINES = -D_XOPEN_SOURCE=1111
|
||||
CXX = gcc
|
||||
CFLAGS = -Wall -Werror -Wextra $(DEFINES)
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
all : $(PROGRAM)
|
||||
$(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)
|
||||
264
_deprecated/getopt/cmdlnopts/cmdlnopts.c
Normal file
264
_deprecated/getopt/cmdlnopts/cmdlnopts.c
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* cmdlnopts.c - the only function that parse 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 <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <math.h>
|
||||
#include "cmdlnopts.h"
|
||||
|
||||
#define RAD 57.2957795130823
|
||||
#define D2R(x) ((x) / RAD)
|
||||
#define R2D(x) ((x) * RAD)
|
||||
|
||||
/*
|
||||
* here are global parameters initialisation
|
||||
*/
|
||||
int help;
|
||||
glob_pars G;
|
||||
mirPar M;
|
||||
|
||||
int rewrite_ifexists = 0, // rewrite existing files == 0 or 1
|
||||
verbose = 0; // each -v increments this value, e.g. -vvv sets it to 3
|
||||
// DEFAULTS
|
||||
// default global parameters
|
||||
glob_pars const Gdefault = {
|
||||
NULL, // size of initial array of surface deviations
|
||||
100, // size of interpolated S0
|
||||
1000, // resulting image size
|
||||
10000, // amount of photons falled to one pixel of S1 by one iteration
|
||||
0, // add to mask random numbers
|
||||
NULL, // amplitude of added random noice
|
||||
NULL, // mirror
|
||||
0, // rest num
|
||||
NULL, // rest pars
|
||||
NULL, // str
|
||||
NULL // filter
|
||||
};
|
||||
//default mirror parameters
|
||||
mirPar const Mdefault = {
|
||||
6., // diameter
|
||||
24.024, // focus
|
||||
0., // inclination from Z axe (radians)
|
||||
0. // azimuth of inclination (radians)
|
||||
};
|
||||
|
||||
// here are functions & definitions for complex parameters (with suboptions etc)
|
||||
bool get_mir_par(void *arg);
|
||||
const char MirPar[] = "set mirror parameters, arg=[diam=num:foc=num:Zincl=ang:Aincl=ang]\n" \
|
||||
"\t\t\tALL DEGREES ARE IN FORMAT [+-][DDd][MMm][SS.S] like -10m13.4 !\n" \
|
||||
"\t\tdiam - diameter of mirror\n" \
|
||||
"\t\tfoc - mirror focus ratio\n" \
|
||||
"\t\tZincl - inclination from Z axe\n" \
|
||||
"\t\tAincl - azimuth of inclination";
|
||||
|
||||
const char FilPar[] = "set filter parameters, arg=[type=type:xsz=num:ysz=num]\n" \
|
||||
"\t\ttype - filter type(med, lap, lg)\n" \
|
||||
"\t\txsz,ysz - area size (default is 3x3)";
|
||||
|
||||
/*
|
||||
* Define command line options by filling structure:
|
||||
* name has_arg flag val type argptr help
|
||||
*/
|
||||
myoption cmdlnopts[] = {
|
||||
// set 1 to param despite of its repeating number:
|
||||
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), "show this help"},
|
||||
// simple integer parameter with obligatory arg:
|
||||
{"int-size",NEED_ARG, NULL, 'i', arg_int, APTR(&G.S_interp), "size of interpolated array of surface deviations"},
|
||||
{"image-size",NEED_ARG,NULL, 'I', arg_int, APTR(&G.S_image), "resulting image size"},
|
||||
{"N-photons",NEED_ARG,NULL, 'N', arg_int, APTR(&G.N_phot), "amount of photons falled to one pixel of matrix by one iteration"},
|
||||
// parameter with suboptions parsed directly in parseargs
|
||||
{"mir-parameters",NEED_ARG,NULL,'M', arg_function,APTR(&get_mir_par),MirPar},
|
||||
// another variant of setting parameter without argument
|
||||
{"add-noice",NO_ARGS, &G.randMask,1, arg_none, NULL, "add random noice to mirror surface deviations"},
|
||||
{"force", NO_ARGS, &rewrite_ifexists,1,arg_none,NULL, "rewrite output file if exists"},
|
||||
// incremented parameter without args (any -v will increment value of "verbose")
|
||||
{"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&verbose), "verbose level (each -v increase it)"},
|
||||
// integer parameter which can occur several times:
|
||||
{"dev-size",MULT_PAR, NULL, 'd', arg_int, APTR(&G.S_dev), "size of initial array of surface deviations"},
|
||||
// double array
|
||||
{"noice-amp",MULT_PAR, NULL, 'a', arg_double, APTR(&G.randAmp), "amplitude of random noice (default: 1e-8)"},
|
||||
// string array
|
||||
{"str", MULT_PAR, NULL, 's', arg_string, APTR(&G.str), "some string parameters (may meets many times)"},
|
||||
// suboptions array that will be parsed outside (the same as string array):
|
||||
{"filter", MULT_PAR, NULL, 'f', arg_string, APTR(&G.filter), FilPar},
|
||||
end_option
|
||||
};
|
||||
|
||||
|
||||
// suboptions structure for get_mirpars
|
||||
// in array last MUST BE {0,0,0}
|
||||
typedef struct{
|
||||
double *val; // pointer to result
|
||||
char *par; // parameter name (CASE-INSENSITIVE!)
|
||||
bool isdegr; // == TRUE if parameter is an angle in format "[+-][DDd][MMm][SS.S]"
|
||||
} suboptions;
|
||||
|
||||
/**
|
||||
* Safely convert data from string to double
|
||||
*
|
||||
* @param num (o) - double number read from string
|
||||
* @param str (i) - input string
|
||||
* @return TRUE if success
|
||||
*/
|
||||
bool myatod(double *num, const char *str){
|
||||
double res;
|
||||
char *endptr;
|
||||
assert(str);
|
||||
res = strtod(str, &endptr);
|
||||
if(endptr == str || *str == '\0' || *endptr != '\0'){
|
||||
printf("Wrong double number format!");
|
||||
return FALSE;
|
||||
}
|
||||
*num = res;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert string "[+-][DDd][MMm][SS.S]" into radians
|
||||
*
|
||||
* @param ang (o) - angle in radians or exit with help message
|
||||
* @param str (i) - string with angle
|
||||
* @return TRUE if OK
|
||||
*/
|
||||
bool get_radians(double *ret, char *str){
|
||||
double val = 0., ftmp, sign = 1.;
|
||||
char *ptr;
|
||||
assert(str);
|
||||
switch(*str){ // check sign
|
||||
case '-':
|
||||
sign = -1.;
|
||||
case '+':
|
||||
str++;
|
||||
}
|
||||
if((ptr = strchr(str, 'd'))){ // found DDD.DDd
|
||||
*ptr = 0; if(!myatod(&ftmp, str)) return FALSE;
|
||||
ftmp = fabs(ftmp);
|
||||
if(ftmp > 360.){
|
||||
printf("Degrees should be less than 360");
|
||||
return FALSE;
|
||||
}
|
||||
val += ftmp;
|
||||
str = ptr + 1;
|
||||
}
|
||||
if((ptr = strchr(str, 'm'))){ // found DDD.DDm
|
||||
*ptr = 0; if(!myatod(&ftmp, str)) return FALSE;
|
||||
ftmp = fabs(ftmp);
|
||||
val += ftmp / 60.;
|
||||
str = ptr + 1;
|
||||
}
|
||||
if(strlen(str)){ // there is something more
|
||||
if(!myatod(&ftmp, str)) return FALSE;
|
||||
ftmp = fabs(ftmp);
|
||||
val += ftmp / 3600.;
|
||||
}
|
||||
*ret = D2R(val * sign); // convert degrees to radians
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse string of suboptions (--option=name1=var1:name2=var2... or -O name1=var1,name2=var2...)
|
||||
* Suboptions could be divided by colon or comma
|
||||
*
|
||||
* !!NAMES OF SUBOPTIONS ARE CASE-UNSENSITIVE!!!
|
||||
*
|
||||
* @param arg (i) - string with description
|
||||
* @param V (io) - pointer to suboptions array (result will be stored in sopts->val)
|
||||
* @return TRUE if success
|
||||
*/
|
||||
bool get_mirpars(void *arg, suboptions *V){
|
||||
char *tok, *val, *par;
|
||||
int i;
|
||||
tok = strtok(arg, ":,");
|
||||
do{
|
||||
if((val = strchr(tok, '=')) == NULL){ // wrong format
|
||||
printf("Wrong format: no value for keyword");
|
||||
return FALSE;
|
||||
}
|
||||
*val++ = '\0';
|
||||
par = tok;
|
||||
for(i = 0; V[i].val; i++){
|
||||
if(strcasecmp(par, V[i].par) == 0){ // found parameter
|
||||
if(V[i].isdegr){ // DMS
|
||||
if(!get_radians(V[i].val, val)) // wrong angle
|
||||
return FALSE;
|
||||
}else{ // simple double
|
||||
if(!myatod(V[i].val, val)) // wrong number
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!V[i].val){ // nothing found - wrong format
|
||||
printf("Bad keyword!");
|
||||
return FALSE;
|
||||
}
|
||||
}while((tok = strtok(NULL, ":,")));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* functions of subargs parsing can looks as this
|
||||
*/
|
||||
/**
|
||||
* Parse string of mirror parameters (--mir-diam=...)
|
||||
*
|
||||
* @param arg (i) - string with description
|
||||
* @return TRUE if success
|
||||
*/
|
||||
bool get_mir_par(void *arg){
|
||||
suboptions V[] = { // array of mirror parameters and string keys for cmdln pars
|
||||
{&M.D, "diam", FALSE},
|
||||
{&M.F, "foc", FALSE},
|
||||
{&M.Zincl, "zincl", TRUE},
|
||||
{&M.Aincl, "aincl", TRUE},
|
||||
{0,0,0}
|
||||
};
|
||||
return get_mirpars(arg, V);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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){
|
||||
int i;
|
||||
void *ptr;
|
||||
ptr = memcpy(&G, &Gdefault, sizeof(G)); assert(ptr);
|
||||
ptr = memcpy(&M, &Mdefault, sizeof(M)); assert(ptr);
|
||||
G.Mirror = &M;
|
||||
// format of help: "Usage: progname [args]\n"
|
||||
change_helpstring("Usage: %s [args]\n\n\tWhere args are:\n");
|
||||
// parse arguments
|
||||
parseargs(&argc, &argv, cmdlnopts);
|
||||
if(help) showhelp(-1, cmdlnopts);
|
||||
if(argc > 0){
|
||||
G.rest_pars_num = argc;
|
||||
G.rest_pars = calloc(argc, sizeof(char*));
|
||||
for (i = 0; i < argc; i++)
|
||||
G.rest_pars[i] = strdup(argv[i]);
|
||||
}
|
||||
return &G;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user