1st commit

This commit is contained in:
Edward Emelianov 2020-03-24 17:38:06 +03:00
parent a3b739723c
commit 913f6dfe85
8 changed files with 664 additions and 36 deletions

41
.gitignore vendored
View File

@ -3,18 +3,6 @@
# Object files # Object files
*.o *.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries # Libraries
*.lib *.lib
@ -23,30 +11,11 @@
*.lo *.lo
# Shared objects (inc. Windows DLLs) # Shared objects (inc. Windows DLLs)
*.dll
*.so *.so
*.so.* *.so.*
*.dylib
# Executables # qt-creator
*.exe *.config
*.out *.creator
*.app *.files
*.i*86 *.includes
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf

44
Makefile Normal file
View File

@ -0,0 +1,44 @@
# run `make DEF=...` to add extra defines
PROGRAM := grasshopper
LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all
LDFLAGS += -lusefull_macros -lflycapture-c -lflycapture -L/usr/local/lib
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

4
Readme.md Normal file
View File

@ -0,0 +1,4 @@
Simplest tool for Grasshopper3 control
======================================
(pre-pre-alpha version)

34
aux.c Normal file
View File

@ -0,0 +1,34 @@
/*
* This file is part of the grasshopper 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 <stdio.h>
#include <stdarg.h>
#include "aux.h"
#include "cmdlnopts.h"
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;
}

34
aux.h Normal file
View File

@ -0,0 +1,34 @@
/*
* This file is part of the grasshopper 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, ...);
#define VMESG(...) do{verbose(VERB_MESG, __VA_ARGS__);}while(0)
#define VDBG(...) do{verbose(VERB_DEBUG, __VA_ARGS__);}while(0)
#endif // AUX_H__

90
cmdlnopts.c Normal file
View File

@ -0,0 +1,90 @@
/*
* This file is part of the grasshopper 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/grasshopper.pid"
// DEFAULTS
// default global parameters
static glob_pars const Gdefault = {
.device = NULL,
.pidfile = DEFAULT_PIDFILE,
.exptime = 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)")},
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]\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++)
G.rest_pars[i] = strdup(argv[i]);
}
return &G;
}

41
cmdlnopts.h Normal file
View File

@ -0,0 +1,41 @@
/*
* This file is part of the grasshopper 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 rest_pars_num; // number of rest parameters
int camno; // number of camera to work with
float exptime; // exposition time
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__

412
grasshopper.c Normal file
View File

@ -0,0 +1,412 @@
/*
* This file is part of the grasshopper 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 <C/FlyCapture2_C.h>
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <usefull_macros.h>
#include "aux.h"
#include "cmdlnopts.h"
static fc2Error err;
#define FC2FNE(fn, ...) do{if(FC2_ERROR_OK != (err=fn(__VA_ARGS__))){fc2DestroyContext(context); \
ERRX(#fn "(): %s", fc2ErrorToDescription(err));}}while(0)
#define FC2FNW(fn, ...) do{if(FC2_ERROR_OK != (err=fn(__VA_ARGS__))){fc2DestroyContext(context); \
WARNX(#fn "(): %s", fc2ErrorToDescription(err)); return err;}}while(0)
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);
restore_console();
exit(sig);
}
#if 0
typedef struct _Property
{
/** Property info type. */
fc2PropertyType type;
/** Flag indicating if the property is present. */
BOOL present;
/**
* Flag controlling absolute mode (real world units)
* or non-absolute mode (camera internal units).
*/
BOOL absControl;
/** Flag controlling one push. */
BOOL onePush;
/** Flag controlling on/off. */
BOOL onOff;
/** Flag controlling auto. */
BOOL autoManualMode;
/**
* Value A (integer).
* Used to configure properties in non-absolute mode.
*/
unsigned int valueA;
/**
* Value B (integer). For white balance, value B applies to the blue value and
* value A applies to the red value.
*/
unsigned int valueB;
/**
* Floating point value.
* Used to configure properties in absolute mode.
*/
float absValue;
/** Reserved for future use. */
unsigned int reserved[8];
// For convenience, trigger delay is the same structure
// used in a separate function along with trigger mode.
} fc2Property, fc2TriggerDelay;
typedef enum _fc2PropertyType
{
FC2_BRIGHTNESS,
FC2_AUTO_EXPOSURE,
FC2_SHARPNESS,
FC2_WHITE_BALANCE,
FC2_HUE,
FC2_SATURATION,
FC2_GAMMA,
FC2_IRIS,
FC2_FOCUS,
FC2_ZOOM,
FC2_PAN,
FC2_TILT,
FC2_SHUTTER,
FC2_GAIN,
FC2_TRIGGER_MODE,
FC2_TRIGGER_DELAY,
FC2_FRAME_RATE,
FC2_TEMPERATURE,
FC2_UNSPECIFIED_PROPERTY_TYPE,
FC2_PROPERTY_TYPE_FORCE_32BITS = FULL_32BIT_VALUE
} fc2PropertyType;
#endif
static const char *propnames[] = {
[FC2_BRIGHTNESS] = "brightness",
[FC2_AUTO_EXPOSURE] = "auto exposure",
[FC2_SHARPNESS] = "sharpness",
[FC2_WHITE_BALANCE] = "white balance",
[FC2_HUE] = "hue",
[FC2_SATURATION] = "saturation",
[FC2_GAMMA] = "gamma",
[FC2_IRIS] = "iris",
[FC2_FOCUS] = "focus",
[FC2_ZOOM] = "zoom",
[FC2_PAN] = "pan",
[FC2_TILT] = "tilt",
[FC2_SHUTTER] = "shutter",
[FC2_GAIN] = "gain",
[FC2_TRIGGER_MODE] = "trigger mode",
[FC2_TRIGGER_DELAY] = "trigger delay",
[FC2_FRAME_RATE] = "frame rate",
[FC2_TEMPERATURE] = "temperature",
[FC2_UNSPECIFIED_PROPERTY_TYPE] = "unspecified"
};
static void prbl(char *s, BOOL prop){
printf("\t%s = ", s);
if(prop) green("true");
else red("false");
printf("\n");
}
static fc2Error getproperty(fc2Context context, fc2PropertyType t){
fc2Property prop;
prop.type = t;
FC2FNW(fc2GetProperty, context, &prop);
if(!prop.present) return FC2_ERROR_NOT_FOUND;
if(t <= FC2_UNSPECIFIED_PROPERTY_TYPE) green("\nProperty \"%s\":\n", propnames[t]);
prbl("absControl", prop.absControl); // 1 - world units, 0 - camera units
prbl("onePush", prop.onePush); // "one push"
prbl("onOff", prop.onOff);
prbl("autoManualMode", prop.autoManualMode); // 1 - auto, 0 - manual
printf("\tvalueA = %u\n", prop.valueA); // values in non-absolute mode
printf("\tvalueB = %u\n", prop.valueB);
printf("\tabsValue = %g\n", prop.absValue); // value in absolute mode
fc2PropertyInfo i;
i.type = t;
FC2FNW(fc2GetPropertyInfo, context, &i);
if(!i.present) return FC2_ERROR_OK;
green("Property Info:\n");
prbl("autoSupported", i.autoSupported); // can be auto
prbl("manualSupported", i.manualSupported); // can be manual
prbl("onOffSupported", i.onOffSupported); // can be on/off
prbl("onePushSupported", i.onePushSupported); // can be "one push"
prbl("absValSupported", i.absValSupported); // can be absolute
prbl("readOutSupported", i.readOutSupported); // could be read out
printf("\tmin = %u\n", i.min);
printf("\tmax = %u\n", i.max);
printf("\tabsMin = %g\n", i.absMin);
printf("\tabsMax = %g\n", i.absMax);
printf("\tpUnits = %s\n", i.pUnits);
printf("\tpUnitAbbr = %s\n", i.pUnitAbbr);
return FC2_ERROR_OK;
}
static fc2Error setexp(fc2Context context, float e){
fc2Property prop;
prop.type = FC2_SHUTTER;
prop.autoManualMode = false;
prop.absValue = e;
FC2FNW(fc2SetProperty, context, &prop);
// now check
FC2FNW(fc2GetProperty, context, &prop);
if(fabs(prop.absValue - e) > 0.0001){
WARNX("Can't set exposure! Got %g instead of %g.", prop.absValue, e);
return FC2_ERROR_FAILED;
}
return FC2_ERROR_OK;
}
static void PrintCameraInfo(fc2Context context, int n){
fc2Error error;
fc2CameraInfo camInfo;
error = fc2GetCameraInfo(context, &camInfo);
if(error != FC2_ERROR_OK){
WARNX("fc2GetCameraInfo(): %s", fc2ErrorToDescription(error));
return;
}
printf("\n\n");
green("*** CAMERA %d INFORMATION ***\n", n);
printf("Serial number - %u\n"
"Camera model - %s\n"
"Camera vendor - %s\n"
"Sensor - %s\n"
"Resolution - %s\n"
"Firmware version - %s\n"
"Firmware build time - %s\n\n",
camInfo.serialNumber,
camInfo.modelName,
camInfo.vendorName,
camInfo.sensorInfo,
camInfo.sensorResolution,
camInfo.firmwareVersion,
camInfo.firmwareBuildTime);
if(verbose_level >= VERB_DEBUG){
for(fc2PropertyType t = FC2_BRIGHTNESS; t < FC2_UNSPECIFIED_PROPERTY_TYPE; ++t)
getproperty(context, t);
}
}
static void SetTimeStamping(fc2Context context, BOOL enableTimeStamp)
{
fc2Error error;
fc2EmbeddedImageInfo embeddedInfo;
error = fc2GetEmbeddedImageInfo(context, &embeddedInfo);
if (error != FC2_ERROR_OK)
{
printf("Error in fc2GetEmbeddedImageInfo: %s\n", fc2ErrorToDescription(error));
}
if (embeddedInfo.timestamp.available != 0)
{
embeddedInfo.timestamp.onOff = enableTimeStamp;
}
error = fc2SetEmbeddedImageInfo(context, &embeddedInfo);
if (error != FC2_ERROR_OK)
{
printf("Error in fc2SetEmbeddedImageInfo: %s\n", fc2ErrorToDescription(error));
}
}
static int GrabImages(fc2Context context, int numImagesToGrab)
{
fc2Error error;
fc2Image rawImage;
fc2Image convertedImage;
fc2TimeStamp prevTimestamp = {0};
int i;
error = fc2CreateImage(&rawImage);
if (error != FC2_ERROR_OK)
{
printf("Error in fc2CreateImage: %s\n", fc2ErrorToDescription(error));
return -1;
}
error = fc2CreateImage(&convertedImage);
if (error != FC2_ERROR_OK)
{
printf("Error in fc2CreateImage: %s\n", fc2ErrorToDescription(error));
return -1;
}
// If externally allocated memory is to be used for the converted image,
// simply assigning the pData member of the fc2Image structure is
// insufficient. fc2SetImageData() should be called in order to populate
// the fc2Image structure correctly. This can be done at this point,
// assuming that the memory has already been allocated.
for (i = 0; i < numImagesToGrab; i++)
{
// Retrieve the image
error = fc2RetrieveBuffer(context, &rawImage);
if (error != FC2_ERROR_OK)
{
printf("Error in retrieveBuffer: %s\n", fc2ErrorToDescription(error));
return -1;
}
else
{
// Get and print out the time stamp
fc2TimeStamp ts = fc2GetImageTimeStamp(&rawImage);
int diff = (ts.cycleSeconds - prevTimestamp.cycleSeconds) * 8000 +
(ts.cycleCount - prevTimestamp.cycleCount);
prevTimestamp = ts;
printf("timestamp [%d %d] - %d\n",
ts.cycleSeconds,
ts.cycleCount,
diff);
}
}
if (error == FC2_ERROR_OK)
{
// Convert the final image to RGB
error = fc2ConvertImageTo(FC2_PIXEL_FORMAT_MONO8, &rawImage, &convertedImage);
if (error != FC2_ERROR_OK)
{
printf("Error in fc2ConvertImageTo: %s\n", fc2ErrorToDescription(error));
return -1;
}
// Save it to PNG
printf("Saving the last image to fc2TestImage.png \n");
error = fc2SaveImage(&convertedImage, "fc2TestImage.png", FC2_PNG);
if (error != FC2_ERROR_OK)
{
printf("Error in fc2SaveImage: %s\n", fc2ErrorToDescription(error));
printf("Please check write permissions.\n");
return -1;
}
}
error = fc2DestroyImage(&rawImage);
if (error != FC2_ERROR_OK)
{
printf("Error in fc2DestroyImage: %s\n", fc2ErrorToDescription(error));
return -1;
}
error = fc2DestroyImage(&convertedImage);
if (error != FC2_ERROR_OK)
{
printf("Error in fc2DestroyImage: %s\n", fc2ErrorToDescription(error));
return -1;
}
return 0;
}
int main(int argc, char **argv){
int ret = 0;
initial_setup();
char *self = strdup(argv[0]);
parse_args(argc, argv);
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
setup_con();
fc2Context context;
fc2PGRGuid guid;
unsigned int numCameras = 0;
if(FC2_ERROR_OK != (err = fc2CreateContext(&context))){
ERRX("fc2CreateContext(): %s", fc2ErrorToDescription(err));
}
FC2FNE(fc2GetNumOfCameras, context, &numCameras);
if(numCameras == 0){
fc2DestroyContext(context);
ERRX("No cameras detected!");
}
VMESG("Found %d camera[s]", numCameras);
if(verbose_level >= VERB_MESG){
for(int i = 0; i < numCameras; ++i){
FC2FNE(fc2GetCameraFromIndex, context, i, &guid);
FC2FNE(fc2Connect, context, &guid);
PrintCameraInfo(context, i);
}
}
FC2FNE(fc2GetCameraFromIndex, context, G.camno, &guid);
FC2FNE(fc2Connect, context, &guid);
if(verbose_level >= VERB_MESG && numCameras > 1) PrintCameraInfo(context, G.camno);
if(isnan(G.exptime)){ // no expose time -> return
goto destr;
}
if(FC2_ERROR_OK != setexp(context, G.exptime)){
ret = 1;
goto destr;
}
VMESG("Set exposition to %gms", G.exptime);
SetTimeStamping(context, TRUE);
err = fc2StartCapture(context);
if (err != FC2_ERROR_OK)
{
fc2DestroyContext(context);
printf("Error in fc2StartCapture: %s\n", fc2ErrorToDescription(err));
signals(12);
}
if (GrabImages(context, 3) != 0)
{
fc2DestroyContext(context);
signals(12);
}
err = fc2StopCapture(context);
if (err != FC2_ERROR_OK)
{
fc2DestroyContext(context);
printf("Error in fc2StopCapture: %s\n", fc2ErrorToDescription(err));
signals(12);
}
destr:
fc2DestroyContext(context);
signals(ret);
return ret;
}