mirror of
https://github.com/eddyem/astrovideoguide_v3.git
synced 2026-03-20 00:31:01 +03:00
Add toupcam support
This commit is contained in:
@@ -19,6 +19,7 @@ option(DEBUG "Compile in debug mode" OFF)
|
||||
option(BASLER "Add Basler cameras support" OFF)
|
||||
option(GRASSHOPPER "Add GrassHopper cameras support" OFF)
|
||||
option(HIKROBOT "Add HikRobot cameras support" OFF)
|
||||
option(TOUPCAM "Add Toupcam CMOS support" OFF)
|
||||
|
||||
# default flags (c17 because MVS code have `typedef char bool`)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -W -Wextra -Werror -std=c17")
|
||||
@@ -63,6 +64,13 @@ if(HIKROBOT)
|
||||
else()
|
||||
list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/hikrobot.c")
|
||||
endif()
|
||||
if(TOUPCAM)
|
||||
pkg_check_modules(TOUPCAM REQUIRED toupcam)
|
||||
add_definitions("-DTOUPCAM_FOUND=1")
|
||||
else()
|
||||
list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/toupcam.c")
|
||||
endif()
|
||||
|
||||
pkg_check_modules(MODULES REQUIRED ${MODULES})
|
||||
|
||||
include(FindOpenMP)
|
||||
@@ -89,10 +97,10 @@ message("Install dir prefix: ${CMAKE_INSTALL_PREFIX}")
|
||||
# exe file
|
||||
add_executable(${PROJ} ${SOURCES})
|
||||
# -I
|
||||
target_include_directories(${PROJ} PUBLIC ${MODULES_INCLUDE_DIRS} ${FLYCAP_INCLUDE_DIRS} ${BASLER_INCLUDE_DIRS} ${MVS_INCLUDE_DIRS})
|
||||
target_include_directories(${PROJ} PUBLIC ${MODULES_INCLUDE_DIRS} ${FLYCAP_INCLUDE_DIRS} ${BASLER_INCLUDE_DIRS} ${MVS_INCLUDE_DIRS} ${TOUPCAM_INCLUDE_DIRS})
|
||||
# -L
|
||||
target_link_directories(${PROJ} PUBLIC ${MODULES_LIBRARY_DIRS} ${FLYCAP_LIBRARY_DIRS} ${BASLER_LIBRARY_DIRS} ${MVS_LIBRARY_DIRS})
|
||||
message("MOD: ${MODULES_LIBRARY_DIRS}, FC: ${FLYCAP_LIBRARY_DIRS}, MVS: ${MVS_LIBRARY_DIRS}")
|
||||
target_link_directories(${PROJ} PUBLIC ${MODULES_LIBRARY_DIRS} ${FLYCAP_LIBRARY_DIRS} ${BASLER_LIBRARY_DIRS} ${MVS_LIBRARY_DIRS} ${TOUPCAM_LIBRARY_DIRS})
|
||||
message("MOD: ${MODULES_LIBRARY_DIRS}, FC: ${FLYCAP_LIBRARY_DIRS}, MVS: ${MVS_LIBRARY_DIRS}, TOUPCAM: ${TOUPCAM_LIBRARY_DIRS}")
|
||||
# -D
|
||||
add_definitions(${CFLAGS} -D_XOPEN_SOURCE=666 -D_POSIX_C_SOURCE=600700 -D_DEFAULT_SOURCE -DLOCALEDIR=\"${LOCALEDIR}\"
|
||||
-DPACKAGE_VERSION=\"${VERSION}\" -DGETTEXT_PACKAGE=\"${PROJ}\"
|
||||
@@ -100,7 +108,7 @@ add_definitions(${CFLAGS} -D_XOPEN_SOURCE=666 -D_POSIX_C_SOURCE=600700 -D_DEFAUL
|
||||
-DMAJOR_VERSION=\"${MAJOR_VERSION}\" -DTHREAD_NUMBER=${PROCESSOR_COUNT})
|
||||
|
||||
# -l
|
||||
target_link_libraries(${PROJ} ${MODULES_LIBRARIES} ${FLYCAP_LIBRARIES} ${BASLER_LIBRARIES} ${MVS_LIBRARIES} -lm)
|
||||
target_link_libraries(${PROJ} ${MODULES_LIBRARIES} ${FLYCAP_LIBRARIES} ${BASLER_LIBRARIES} ${MVS_LIBRARIES} ${TOUPCAM_LIBRARIES} -lm)
|
||||
|
||||
# Installation of the program
|
||||
INSTALL(TARGETS ${PROJ} DESTINATION "bin")
|
||||
|
||||
28
LocCorr_new/Toupcam.h
Normal file
28
LocCorr_new/Toupcam.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of the loccorr project.
|
||||
* Copyright 2026 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
|
||||
|
||||
#ifdef TOUPCAM_FOUND
|
||||
#include "cameracapture.h" // `camera`
|
||||
|
||||
#define TOUPCAM_CAPT_NAME "toupcam"
|
||||
|
||||
extern camera Toupcam;
|
||||
|
||||
#endif
|
||||
@@ -239,12 +239,12 @@ static void *procthread(void* v){
|
||||
void (*process)(Image*) = (procfn_t)v;
|
||||
#ifdef EBUG
|
||||
double t0 = sl_dtime();
|
||||
int imno = 0;
|
||||
#endif
|
||||
while(!stopwork){
|
||||
pthread_mutex_lock(&capt_mutex);
|
||||
//DBG("===== iCaptured=%d", iCaptured);
|
||||
if(Icap[iCaptured]){
|
||||
DBG("===== got image iCaptured=#%d @ %g", iCaptured, sl_dtime() - t0);
|
||||
DBG("===== got image #%d, iCaptured=#%d @ %g", imno++, iCaptured, sl_dtime() - t0);
|
||||
Image *oIma = Icap[iCaptured]; // take image here and free buffer
|
||||
Icap[iCaptured] = NULL;
|
||||
pthread_mutex_unlock(&capt_mutex);
|
||||
@@ -300,6 +300,9 @@ int camcapture(void (*process)(Image*)){
|
||||
ERR("pthread_create()");
|
||||
}
|
||||
exptime = theconf.exptime;
|
||||
#ifdef EBUG
|
||||
static int imno = 0;
|
||||
#endif
|
||||
while(1){
|
||||
#ifdef EBUG
|
||||
double t0 = sl_dtime();
|
||||
@@ -371,7 +374,7 @@ int camcapture(void (*process)(Image*)){
|
||||
}
|
||||
continue;
|
||||
}else errctr = 0;
|
||||
DBG("---- Grabbed @ %g", sl_dtime() - t0);
|
||||
DBG("---- Grabbed #%d @ %g", imno++, sl_dtime() - t0);
|
||||
pthread_mutex_lock(&capt_mutex);
|
||||
if(iCaptured < 0) iCaptured = 0;
|
||||
else iCaptured = !iCaptured;
|
||||
@@ -388,7 +391,7 @@ int camcapture(void (*process)(Image*)){
|
||||
Image_free(&oIma);
|
||||
}
|
||||
pthread_mutex_unlock(&capt_mutex);
|
||||
DBG("unlocked, T=%g", sl_dtime() - t0);
|
||||
DBG("T=%g", sl_dtime() - t0);
|
||||
}
|
||||
pthread_cancel(proc_thread);
|
||||
if(oIma) Image_free(&oIma);
|
||||
|
||||
@@ -70,7 +70,7 @@ static sl_option_t cmdlnopts[] = {
|
||||
{"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 ")")},
|
||||
{"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&G.verb), _("increase verbosity level of log file (each -v increased by 1)")},
|
||||
{"input", NEED_ARG, NULL, 'i', arg_string, APTR(&G.inputname), _("file or directory name for monitoring (or grasshopper/basler/hikrobot for capturing)")},
|
||||
{"input", NEED_ARG, NULL, 'i', arg_string, APTR(&G.inputname), _("file or directory name for monitoring (or grasshopper/basler/hikrobot/toupcam for capturing)")},
|
||||
{"blackp", NEED_ARG, NULL, 'b', arg_double, APTR(&G.throwpart), _("fraction of black pixels to throw away when make histogram eq")},
|
||||
// {"radius", NEED_ARG, NULL, 'r', arg_int, APTR(&G.medradius), _("radius of median filter (r=1 -> 3x3, r=2 -> 5x5 etc.)")},
|
||||
{"equalize", NO_ARGS, NULL, 'e', arg_int, APTR(&G.equalize), _("make historam equalization of saved jpeg")},
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "hikrobot.h"
|
||||
#include "imagefile.h"
|
||||
#include "median.h"
|
||||
#include "Toupcam.h"
|
||||
|
||||
typedef struct{
|
||||
const uint8_t signature[8];
|
||||
@@ -112,6 +113,9 @@ InputType chkinput(const char *name){
|
||||
#endif
|
||||
#ifdef MVS_FOUND
|
||||
if(0 == strcmp(name, HIKROBOT_CAPT_NAME)) return T_CAPT_HIKROBOT;
|
||||
#endif
|
||||
#ifdef TOUPCAM_FOUND
|
||||
if(0 == strcmp(name, TOUPCAM_CAPT_NAME)) return T_CAPT_TOUPCAM;
|
||||
#endif
|
||||
struct stat fd_stat;
|
||||
stat(name, &fd_stat);
|
||||
|
||||
@@ -61,7 +61,8 @@ typedef enum{
|
||||
T_PNG,
|
||||
T_CAPT_GRASSHOPPER, // capture grasshopper
|
||||
T_CAPT_BASLER,
|
||||
T_CAPT_HIKROBOT
|
||||
T_CAPT_HIKROBOT,
|
||||
T_CAPT_TOUPCAM,
|
||||
} InputType;
|
||||
|
||||
void Image_minmax(Image *I);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "improc.h"
|
||||
#include "inotify.h"
|
||||
#include "steppers.h"
|
||||
#include "Toupcam.h"
|
||||
|
||||
volatile atomic_ullong ImNumber = 0; // GLOBAL: counter of processed images
|
||||
volatile atomic_bool stopwork = FALSE; // GLOBAL: suicide
|
||||
@@ -424,7 +425,7 @@ int process_input(InputType tp, char *name){
|
||||
if(tp == T_DIRECTORY){
|
||||
imagedata = watchdr;
|
||||
return watch_directory(name, process_file);
|
||||
}else if(tp == T_CAPT_GRASSHOPPER || tp == T_CAPT_BASLER || tp == T_CAPT_HIKROBOT){
|
||||
}else if(tp == T_CAPT_GRASSHOPPER || tp == T_CAPT_BASLER || tp == T_CAPT_HIKROBOT || tp == T_CAPT_TOUPCAM){
|
||||
camera *cam = NULL;
|
||||
switch(tp){
|
||||
case T_CAPT_GRASSHOPPER:
|
||||
@@ -440,6 +441,11 @@ int process_input(InputType tp, char *name){
|
||||
case T_CAPT_HIKROBOT:
|
||||
#ifdef MVS_FOUND
|
||||
cam = &Hikrobot;
|
||||
#endif
|
||||
break;
|
||||
case T_CAPT_TOUPCAM:
|
||||
#ifdef TOUPCAM_FOUND
|
||||
cam = &Toupcam;
|
||||
#endif
|
||||
break;
|
||||
default: return FALSE;
|
||||
|
||||
@@ -76,7 +76,8 @@ static InputType chk_inp(const char *name){
|
||||
if(!name) ERRX("Point file or directory name to monitor");
|
||||
InputType itp = chkinput(name);
|
||||
if(T_WRONG == itp) return T_WRONG;
|
||||
green("\n%s is a ", name);
|
||||
green("\n%s", name);
|
||||
printf(" is a ");
|
||||
switch(itp){
|
||||
case T_DIRECTORY:
|
||||
printf("directory");
|
||||
@@ -108,6 +109,9 @@ static InputType chk_inp(const char *name){
|
||||
case T_CAPT_HIKROBOT:
|
||||
printf("hikrobot camera capture");
|
||||
break;
|
||||
case T_CAPT_TOUPCAM:
|
||||
printf("toupcam camera capture");
|
||||
break;
|
||||
default:
|
||||
printf("unsupported type\n");
|
||||
return T_WRONG;
|
||||
|
||||
318
LocCorr_new/toupcam.c
Normal file
318
LocCorr_new/toupcam.c
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* This file is part of the loccorr project.
|
||||
* Copyright 2026 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 <float.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <toupcam.h>
|
||||
#include <usefull_macros.h>
|
||||
|
||||
#include "Toupcam.h"
|
||||
|
||||
// flags for image processing
|
||||
typedef enum{
|
||||
IM_SLEEP,
|
||||
IM_STARTED,
|
||||
IM_READY,
|
||||
IM_ERROR
|
||||
} imstate_t;
|
||||
|
||||
// devices
|
||||
static ToupcamDeviceV2 g_dev[TOUPCAM_MAX] = {0};
|
||||
static struct{
|
||||
ToupcamDeviceV2* dev; // device
|
||||
HToupcam hcam; // hcam for all functions
|
||||
unsigned long long flags; // flags (read on connect)
|
||||
pthread_mutex_t mutex; // lock mutex for `data` writing/reading
|
||||
void* data; // image data
|
||||
size_t imsz; // size of current image in bytes
|
||||
imstate_t state; // current state
|
||||
uint64_t imseqno; // number of image from connection
|
||||
uint64_t lastcapno; // last captured image number
|
||||
} toupcam = {0};
|
||||
|
||||
// array - max ROI; geometry - current ROI
|
||||
static frameformat array = {.xoff=0, .yoff = 0, .w = 800, .h = 600}, geometry = {0};
|
||||
|
||||
// exptime (in seconds!!!) and starting of exposition
|
||||
static double exptimeS = 0.1, starttime = 0.;
|
||||
|
||||
#define TCHECK() do{if(!toupcam.hcam) return FALSE;}while(0)
|
||||
|
||||
// return constant string with error code description
|
||||
static const char *errcode(int ecode){
|
||||
switch(ecode){
|
||||
case 0: return "S_OK";
|
||||
case 1: return "S_FALSE";
|
||||
case 0x8000ffff: return "E_UNEXPECTED";
|
||||
case 0x80004001: return "E_NOTIMPL";
|
||||
case 0x80004002: return "E_NOINTERFACE";
|
||||
case 0x80070005: return "E_ACCESSDENIED";
|
||||
case 0x8007000e: return "E_OUTOFMEMORY";
|
||||
case 0x80070057: return "E_INVALIDARG";
|
||||
case 0x80004003: return "E_POINTER";
|
||||
case 0x80004005: return "E_FAIL";
|
||||
case 0x8001010e: return "E_WRONG_THREAD";
|
||||
case 0x8007001f: return "E_GEN_FAILURE";
|
||||
case 0x800700aa: return "E_BUSY";
|
||||
case 0x8000000a: return "E_PENDING";
|
||||
case 0x8001011f: return "E_TIMEOUT";
|
||||
case 0x80072743: return "E_UNREACH";
|
||||
default: return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
static void camcancel(){
|
||||
FNAME();
|
||||
if(!toupcam.hcam) return;
|
||||
int e = Toupcam_Trigger(toupcam.hcam, 0); // stop triggering
|
||||
if(e < 0) WARNX("Can't trigger 0: %s", errcode(e));
|
||||
e = Toupcam_Stop(toupcam.hcam);
|
||||
if(e < 0) WARNX("Can't stop: %s", errcode(e));
|
||||
toupcam.state = IM_SLEEP;
|
||||
}
|
||||
|
||||
static void Tdisconnect(){
|
||||
FNAME();
|
||||
camcancel();
|
||||
if(toupcam.hcam){
|
||||
DBG("Close camera");
|
||||
Toupcam_Close(toupcam.hcam);
|
||||
toupcam.hcam = NULL;
|
||||
}
|
||||
if(toupcam.data){
|
||||
DBG("Free image data");
|
||||
free(toupcam.data);
|
||||
toupcam.data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void EventCallback(unsigned nEvent, void _U_ *pCallbackCtx){
|
||||
FNAME();
|
||||
DBG("CALLBACK with evt %d", nEvent);
|
||||
if(!toupcam.hcam || !toupcam.data){ DBG("NO data!"); return; }
|
||||
if(nEvent != TOUPCAM_EVENT_IMAGE){ DBG("Not image event"); return; }
|
||||
ToupcamFrameInfoV4 info = {0};
|
||||
pthread_mutex_lock(&toupcam.mutex);
|
||||
if(Toupcam_PullImageV4(toupcam.hcam, toupcam.data, 0, 0, 0, &info) < 0){
|
||||
DBG("Error pulling image");
|
||||
toupcam.state = IM_ERROR;
|
||||
}else{
|
||||
++toupcam.imseqno;
|
||||
DBG("Image %lu (%dx%d) ready!", toupcam.imseqno, info.v3.width, info.v3.height);
|
||||
toupcam.state = IM_READY;
|
||||
toupcam.imsz = info.v3.height * info.v3.width;
|
||||
geometry.h = info.v3.height;
|
||||
geometry.w = info.v3.width;
|
||||
}
|
||||
pthread_mutex_unlock(&toupcam.mutex);
|
||||
}
|
||||
|
||||
static int startexp(){
|
||||
FNAME();
|
||||
TCHECK();
|
||||
if(toupcam.state == IM_SLEEP){
|
||||
DBG("Sleeping -> start pull mode");
|
||||
if(Toupcam_StartPullModeWithCallback(toupcam.hcam, EventCallback, NULL) < 0){
|
||||
WARNX("Can't run PullMode with Callback!");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
// Ask to trigger for several images (maximal speed available)
|
||||
DBG("Trigger images");
|
||||
int e = Toupcam_Trigger(toupcam.hcam, 100);
|
||||
if(e < 0){
|
||||
DBG("Can't ask for images stream: %s; try 1", errcode(e));
|
||||
e = Toupcam_Trigger(toupcam.hcam, 1);
|
||||
if(e < 0){
|
||||
WARNX("Can't ask for next image: %s", errcode(e));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
toupcam.state = IM_STARTED;
|
||||
starttime = sl_dtime();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int Texp(float t){ // t - in milliseconds!!!
|
||||
FNAME();
|
||||
TCHECK();
|
||||
if(t < FLT_EPSILON) return FALSE;
|
||||
unsigned int microseconds = (unsigned)(t * 1e3f);
|
||||
DBG("Set exptime to %dus", microseconds);
|
||||
camcancel();
|
||||
int e = Toupcam_put_ExpoTime(toupcam.hcam, microseconds);
|
||||
if(e < 0){
|
||||
WARNX("Can't set exp: %s", errcode(e));
|
||||
//startexp();
|
||||
return FALSE;
|
||||
}
|
||||
DBG("OK");
|
||||
if(Toupcam_get_ExpoTime(toupcam.hcam, µseconds) < 0) exptimeS = (double) t / 1e3;
|
||||
else exptimeS = (float)microseconds / 1e6f;
|
||||
DBG("Real exptime: %.4fs", exptimeS);
|
||||
//startexp();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int Tconnect(){
|
||||
FNAME();
|
||||
Tdisconnect();
|
||||
unsigned N = Toupcam_EnumV2(g_dev);
|
||||
if(0 == N){
|
||||
DBG("Found 0 toupcams");
|
||||
return FALSE;
|
||||
}
|
||||
toupcam.dev = &g_dev[0];
|
||||
toupcam.hcam = Toupcam_Open(g_dev[0].id);
|
||||
if(!toupcam.hcam){
|
||||
WARN("Can't open toupcam camera");
|
||||
return FALSE;
|
||||
}
|
||||
DBG("Opened %s", toupcam.dev->displayname);
|
||||
DBG("Clear ROI");
|
||||
Toupcam_put_Roi(toupcam.hcam, 0, 0, 0, 0); // clear ROI
|
||||
// now fill camera geometry
|
||||
unsigned int xoff, yoff, h, w;
|
||||
DBG("Get ROI");
|
||||
Toupcam_get_Roi(toupcam.hcam, &xoff, &yoff, &w, &h);
|
||||
DBG("off (x/y): %d/%d; wxh: %dx%d", xoff, yoff, w, h);
|
||||
geometry.xoff = xoff; geometry.yoff = yoff; geometry.w = w; geometry.h = h;
|
||||
toupcam.flags = Toupcam_query_Model(toupcam.hcam)->flag;
|
||||
DBG("flags: 0x%llx", toupcam.flags);
|
||||
DBG("Allocate data (%d bytes: 2*%d*%d)", 2 * array.w * array.h, array.w, array.h);
|
||||
toupcam.data = calloc(array.w * array.h, 1);
|
||||
#define OPT(opt, val, comment) do{DBG(comment); if(Toupcam_put_Option(toupcam.hcam, opt, val) < 0){ DBG("Can't put this option"); }}while(0)
|
||||
// 12 frames/sec
|
||||
OPT(TOUPCAM_OPTION_TRIGGER, 1, "Software/simulated trigger mode");
|
||||
OPT(TOUPCAM_OPTION_RAW, 1, "Put to RAW mode");
|
||||
OPT(TOUPCAM_OPTION_BINNING, 1, "Set binning to 1x1");
|
||||
#undef OPT
|
||||
toupcam.state = IM_SLEEP;
|
||||
toupcam.imseqno = toupcam.lastcapno = 0;
|
||||
// 8bit
|
||||
if(Toupcam_put_Option(toupcam.hcam, TOUPCAM_OPTION_BITDEPTH, 0) < 0) WARNX("Cant set bitdepth");
|
||||
if(Toupcam_put_Option(toupcam.hcam, TOUPCAM_OPTION_PIXEL_FORMAT, TOUPCAM_PIXELFORMAT_RAW8) < 0){
|
||||
WARNX("Cannot init 8bit mode!");
|
||||
Tdisconnect();
|
||||
return FALSE;
|
||||
}
|
||||
pthread_mutex_init(&toupcam.mutex, NULL);
|
||||
if(!Texp(0.1)){ WARNX("Can't set default exptime"); }
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static Image *Tcapture(){
|
||||
FNAME();
|
||||
if(!toupcam.hcam || !toupcam.data) return NULL;
|
||||
if(!startexp()){
|
||||
WARNX("Can't start exposition");
|
||||
return NULL;
|
||||
}
|
||||
DBG("here, exptime=%gs, dstart=%g", exptimeS, (sl_dtime() - starttime));
|
||||
double tremain = 0.;
|
||||
while(toupcam.state != IM_READY){
|
||||
tremain = exptimeS - (sl_dtime() - starttime);
|
||||
if(tremain < -2.0){
|
||||
WARNX("Timeout - failed");
|
||||
camcancel();
|
||||
return NULL;
|
||||
}
|
||||
usleep(100);
|
||||
}
|
||||
if(toupcam.state != IM_READY){
|
||||
WARNX("State=%d, not ready", toupcam.state);
|
||||
return NULL;
|
||||
}
|
||||
pthread_mutex_lock(&toupcam.mutex);
|
||||
Image *o = u8toImage(toupcam.data, geometry.w, geometry.h, geometry.w);
|
||||
toupcam.lastcapno = toupcam.imseqno;
|
||||
pthread_mutex_unlock(&toupcam.mutex);
|
||||
return o;
|
||||
}
|
||||
|
||||
static int Tbright(float b){
|
||||
FNAME();
|
||||
TCHECK();
|
||||
if(b < -255.f || b > 255.f){
|
||||
WARNX("Available brightness: -255..255");
|
||||
return FALSE;
|
||||
}
|
||||
int br = (int) b;
|
||||
DBG("Try to set brightness to %d", br);
|
||||
camcancel();
|
||||
int e = Toupcam_put_Brightness(toupcam.hcam, br);
|
||||
//startexp();
|
||||
if(e < 0){
|
||||
WARNX("Can't set brightness: %s", errcode(e));
|
||||
return FALSE;
|
||||
}
|
||||
DBG("OK");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int Tgain(float g){
|
||||
FNAME();
|
||||
TCHECK();
|
||||
unsigned short G = (unsigned short)(100.f * g);
|
||||
int ret = FALSE;
|
||||
camcancel();
|
||||
if(Toupcam_put_ExpoAGain(toupcam.hcam, G) < 0){
|
||||
WARNX("Gain out of range: 1..8");
|
||||
}else{ DBG("GAIN is %d", G); ret = TRUE;}
|
||||
//startexp();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static float Tmaxgain(){
|
||||
FNAME();
|
||||
return 8.f; // toupcam SDK returns wrong value: 16.
|
||||
}
|
||||
|
||||
static int Tgeometry(frameformat *f){
|
||||
FNAME();
|
||||
TCHECK();
|
||||
int ret = FALSE;
|
||||
camcancel();
|
||||
if(Toupcam_put_Roi(toupcam.hcam, (unsigned) f->xoff, (unsigned) f->yoff, (unsigned) f->w, (unsigned) f->h) >= 0){
|
||||
geometry = *f;
|
||||
ret = TRUE;
|
||||
}
|
||||
//startexp();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int Tglimits(frameformat *max, frameformat *step){
|
||||
FNAME();
|
||||
TCHECK();
|
||||
if(max) *max = array;
|
||||
if(step) *step = (frameformat){.w = 2, .h = 2, .xoff = 2, .yoff = 2};
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
camera Toupcam = {
|
||||
.disconnect = Tdisconnect,
|
||||
.connect = Tconnect,
|
||||
.capture = Tcapture,
|
||||
.setbrightness = Tbright,
|
||||
.setexp = Texp,
|
||||
.setgain = Tgain,
|
||||
.getmaxgain = Tmaxgain,
|
||||
.setgeometry = Tgeometry,
|
||||
.getgeomlimits = Tglimits,
|
||||
};
|
||||
Reference in New Issue
Block a user