mirror of
https://github.com/eddyem/eddys_snippets.git
synced 2026-01-31 20:35:15 +03:00
GPS alpha
This commit is contained in:
parent
e9e7f10da6
commit
451da2be50
29
GPS/Makefile
Normal file
29
GPS/Makefile
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
PROGRAM = gpstest
|
||||||
|
LDFLAGS =
|
||||||
|
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
GPS/README
Normal file
1
GPS/README
Normal file
@ -0,0 +1 @@
|
|||||||
|
Small utility for working with GPS module NEO-6M
|
||||||
71
GPS/cmdlnopts.c
Normal file
71
GPS/cmdlnopts.c
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* 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",
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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")},
|
||||||
|
// ...
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
38
GPS/cmdlnopts.h
Normal file
38
GPS/cmdlnopts.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* cmdlnopts.h - comand line options for parceargs
|
||||||
|
*
|
||||||
|
* Copyright 2013 Edward V. Emelianoff <eddy@sao.ru>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef __CMDLNOPTS_H__
|
||||||
|
#define __CMDLNOPTS_H__
|
||||||
|
|
||||||
|
#include "parceargs.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* here are some typedef's for global data
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
char *devpath; // device path
|
||||||
|
}glob_pars;
|
||||||
|
|
||||||
|
glob_pars *parce_args(int argc, char **argv);
|
||||||
|
|
||||||
|
#endif // __CMDLNOPTS_H__
|
||||||
140
GPS/daemon.c
Normal file
140
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
GPS/daemon.h
Normal file
28
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));
|
||||||
264
GPS/main.c
Normal file
264
GPS/main.c
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
#ifndef PIDFILE
|
||||||
|
#define PIDFILE "/tmp/GPStest.pid"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
glob_pars *GP = NULL;
|
||||||
|
|
||||||
|
static void signals(int sig){
|
||||||
|
DBG("Get signal %d, quit.\n", sig);
|
||||||
|
restore_tty();
|
||||||
|
exit(sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *get_portdata(){
|
||||||
|
static char buf[1025];
|
||||||
|
char *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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checksum: return 0 if fails
|
||||||
|
*/
|
||||||
|
int checksum(char *buf){
|
||||||
|
char *eol;
|
||||||
|
char chs[2];
|
||||||
|
unsigned char checksum = 0;
|
||||||
|
if(*buf != '$' || !(eol = strchr(buf, '*'))){
|
||||||
|
DBG("Wrong data: %s\n", buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
while(++buf != eol)
|
||||||
|
checksum ^= (unsigned char) (*buf);
|
||||||
|
snprintf(chs, 2, "%X", checksum);
|
||||||
|
if(!strncmp(chs, ++buf, 2)) return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gsv(_U_ char *buf){
|
||||||
|
//DBG("gsv: %s\n", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Recommended minimum specific GPS/Transit data
|
||||||
|
* $GPRMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,ddmmyy,x.x,a*hh
|
||||||
|
* 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 = Track made good in degrees True
|
||||||
|
* 9 = UT date
|
||||||
|
* 10 = Magnetic variation degrees (Easterly var. subtracts from true course)
|
||||||
|
* 11 = E or W
|
||||||
|
* 12 = Checksum
|
||||||
|
* 213457.00,A,4340.59415,N,04127.47560,E,2.494,,290615,,,A*7B
|
||||||
|
*/
|
||||||
|
void rmc(char *buf){
|
||||||
|
int H, M, LO, LA, d, m, y;
|
||||||
|
float S;
|
||||||
|
float longitude, lattitude, speed, track, mag;
|
||||||
|
char varn = 'V', north = '0', east = '0', mageast = '0';
|
||||||
|
sscanf(buf, "%2d%2d%f", &H, &M, &S);
|
||||||
|
buf = strchr(buf, ',')+1;
|
||||||
|
if(*buf != ',') varn = *buf;
|
||||||
|
if(varn != 'A')
|
||||||
|
printf("(data could be wrong)");
|
||||||
|
else
|
||||||
|
printf("(data valid)");
|
||||||
|
printf(" time: %02d:%02d:%05.2f", H, M, S);
|
||||||
|
buf = strchr(buf, ',')+1;
|
||||||
|
sscanf(buf, "%2d%f", &LA, &lattitude);
|
||||||
|
buf = strchr(buf, ',')+1;
|
||||||
|
if(*buf != ','){
|
||||||
|
north = *buf;
|
||||||
|
lattitude = (float)LA + lattitude / 60.;
|
||||||
|
if(north == 'S') lattitude = -lattitude;
|
||||||
|
printf(" latt: %f", lattitude);
|
||||||
|
}
|
||||||
|
buf = strchr(buf, ',')+1;
|
||||||
|
sscanf(buf, "%3d%f", &LO, &longitude);
|
||||||
|
buf = strchr(buf, ',')+1;
|
||||||
|
if(*buf != ','){
|
||||||
|
east = *buf;
|
||||||
|
longitude = (float)LO + longitude / 60.;
|
||||||
|
if(east == 'W') longitude = -longitude;
|
||||||
|
printf(" long: %f", longitude);
|
||||||
|
}
|
||||||
|
buf = strchr(buf, ',')+1;
|
||||||
|
if(*buf != ','){
|
||||||
|
sscanf(buf, "%f", &speed);
|
||||||
|
printf(" speed: %fknots", speed);
|
||||||
|
}
|
||||||
|
buf = strchr(buf, ',')+1;
|
||||||
|
if(*buf != ','){
|
||||||
|
sscanf(buf, "%f", &track);
|
||||||
|
printf(" track: %fdeg,True", track);
|
||||||
|
}
|
||||||
|
buf = strchr(buf, ',')+1;
|
||||||
|
if(sscanf(buf, "%2d%2d%2d", &d, &m, &y) == 3)
|
||||||
|
printf(" date(dd/mm/yy): %02d/%02d/%02d", d, m, y);
|
||||||
|
buf = strchr(buf, ',')+1;
|
||||||
|
sscanf(buf, "%f,%c*", &mag, &mageast);
|
||||||
|
if(mageast == 'E' || mageast == 'W'){
|
||||||
|
if(mageast == 'W') mag = -mag;
|
||||||
|
printf(" magnetic var: %f", mag);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// A,2,04,31,32,14,19,,,,,,,,2.77,2.58,1.00*05
|
||||||
|
void gsa(_U_ char *buf){
|
||||||
|
//DBG("gsa: %s\n", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 213457.00,4340.59415,N,04127.47560,E,1,05,2.58,1275.8,M,17.0,M,,*60
|
||||||
|
void gga(_U_ char *buf){
|
||||||
|
//DBG("gga: %s\n", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
//4340.59415,N,04127.47560,E,213457.00,A,A*60
|
||||||
|
void gll(_U_ char *buf){
|
||||||
|
//DBG("gll: %s\n", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ,T,,M,2.494,N,4.618,K,A*23
|
||||||
|
void vtg(_U_ char *buf){
|
||||||
|
//DBG("vtg: %s\n", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void txt(_U_ char *buf){
|
||||||
|
//DBG("txt: %s\n", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parce content of buffer with GPS data
|
||||||
|
* WARNING! This function changes data content
|
||||||
|
*/
|
||||||
|
void parce_data(char *buf){
|
||||||
|
char *eol;
|
||||||
|
while(buf && (eol = strchr(buf, '\r'))){
|
||||||
|
*eol = 0;
|
||||||
|
// now make checksum checking:
|
||||||
|
if(!checksum(buf)) goto cont;
|
||||||
|
if(strncmp(buf, "$GP", 3)){
|
||||||
|
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(buf, "SV", 2) == 0){
|
||||||
|
gsv(buf+3);
|
||||||
|
}else if(strncmp(buf, "SA", 2) == 0){
|
||||||
|
gsa(buf+3);
|
||||||
|
}else if(strncmp(buf, "GA", 2) == 0){
|
||||||
|
gga(buf+3);
|
||||||
|
}else if(strncmp(buf, "LL", 2) == 0){
|
||||||
|
gll(buf+3);
|
||||||
|
}else{
|
||||||
|
DBG("Unknown: $GPG%s", buf);
|
||||||
|
goto cont;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'R': // RMC
|
||||||
|
++buf;
|
||||||
|
if(strncmp(buf, "MC", 2) == 0){
|
||||||
|
rmc(buf+3);
|
||||||
|
}else{
|
||||||
|
DBG("Unknown: $GPR%s", buf);
|
||||||
|
goto cont;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'V': // VTG
|
||||||
|
++buf;
|
||||||
|
if(strncmp(buf, "TG", 2) == 0){
|
||||||
|
vtg(buf+3);
|
||||||
|
}else{
|
||||||
|
DBG("Unknown: $GPV%s", buf);
|
||||||
|
goto cont;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'T': // TXT
|
||||||
|
++buf;
|
||||||
|
if(strncmp(buf, "XT", 2) == 0){
|
||||||
|
txt(buf+3);
|
||||||
|
}else{
|
||||||
|
DBG("Unknown: $GPT%s", buf);
|
||||||
|
goto cont;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBG("Unknown: $GP%s", buf);
|
||||||
|
goto cont;
|
||||||
|
}
|
||||||
|
// printf("GOT: %s\n", buf);
|
||||||
|
cont:
|
||||||
|
if(eol[1] != '\n') break;
|
||||||
|
buf = eol + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
double T0 = dtime();
|
||||||
|
char *str = NULL;
|
||||||
|
while(dtime() - T0 < 10.){
|
||||||
|
if((str = get_portdata()))
|
||||||
|
parce_data(str);
|
||||||
|
}
|
||||||
|
signals(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
296
GPS/parceargs.c
Normal file
296
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
GPS/parceargs.h
Normal file
105
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__
|
||||||
311
GPS/usefull_macros.c
Normal file
311
GPS/usefull_macros.c
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
/*
|
||||||
|
* 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){
|
||||||
|
printf("\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?
|
||||||
|
}
|
||||||
|
printf(" 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
|
||||||
|
printf(" OK\n");
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Read data from TTY
|
||||||
|
* @param buff (o) - buffer for data read
|
||||||
|
* @param length - buffer len
|
||||||
|
* @return amount of readed bytes
|
||||||
|
*/
|
||||||
|
size_t read_tty(char *buff, size_t length){
|
||||||
|
ssize_t L = 0;
|
||||||
|
fd_set rfds;
|
||||||
|
struct timeval tv;
|
||||||
|
int retval;
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_SET(comfd, &rfds);
|
||||||
|
tv.tv_sec = 0; tv.tv_usec = 50000; // 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;
|
||||||
|
}
|
||||||
122
GPS/usefull_macros.h
Normal file
122
GPS/usefull_macros.h
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* 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(char *buff, size_t length);
|
||||||
|
|
||||||
|
#endif // __USEFULL_MACROS_H__
|
||||||
Loading…
x
Reference in New Issue
Block a user