Added Apogee support

This commit is contained in:
Edward Emelianov 2023-03-06 17:36:41 +03:00
parent 644de638ca
commit 64a2ec11a0
8 changed files with 371 additions and 13 deletions

View File

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.20)
set(CCDLIB devapogee)
SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
find_package(PkgConfig REQUIRED)
pkg_check_modules(${CCDLIB} REQUIRED usefull_macros apogeec>=1.71 libusb)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SRC)
include_directories(${${CCDLIB}_INCLUDE_DIRS} ..)
link_directories(${${CCDLIB}_LIBRARY_DIRS})
add_library(${CCDLIB} SHARED ${SRC})
target_link_libraries(${CCDLIB} ${${CCDLIB}_LIBRARIES} -fPIC)
install(TARGETS ${CCDLIB} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})

338
APOGEE_cameras/apogee.c Normal file
View File

@ -0,0 +1,338 @@
/*
* This file is part of the CCD_Capture project.
* Copyright 2023 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 <libapogee.h>
#include <linux/usbdevice_fs.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <usb.h>
#include <usefull_macros.h>
#include "basestructs.h"
//#include "omp.h"
extern Camera camera;
static int ncameras = 0;
static int isopened = FALSE;
static int osw = 0; // overscan width
static int hbin = 1, vbin = 1;
static int is16bit = 1;
static int isobject = 0;
static int maxbinv = 0, maxbinh = 0; // max binning
static char camname[BUFSIZ] = {0};
static double expt[2] = {0.}; // min/max exposition time
static double exptime = 0.; // actual exposition time
static double tstart = 0.; // exposure start time
static char whynot[BUFSIZ]; // temporary buffer for error messages
static int imW = 0, imH = 0; // size of output image
static int pid = -1, vid = -1;
static int isexposuring = 0;
static void disconnect(){
FNAME();
if(!isopened) return;
ApnGlueExpAbort();
ApnGlueClose();
isopened = FALSE;
}
static void cancel(){
//if(!isexposuring) return;
FNAME();
ApnGlueReset();
//ApnGlueExpAbort();
//ApnGlueStopExposure();
DBG("OK");
}
static int ndev(){
ncameras = 1;
if(ApnGlueOpen(ncameras)) ncameras = 0;
else ApnGlueClose();
DBG("Found %d cameras", ncameras);
camera.Ndevices = ncameras;
return ncameras;
}
/*
static void reset_usb_port(){
if(vid < 0 || pid < 0) return;
int fd, rc;
char buf[FILENAME_MAX*3], *d = NULL, *f = NULL;
struct usb_bus *bus;
struct usb_device *dev;
int found = 0;
usb_init();
usb_find_busses();
usb_find_devices();
for(bus = usb_busses; bus && !found; bus = bus->next) {
for(dev = bus->devices; dev && !found; dev = dev->next) {
if (dev->descriptor.idVendor == vid && dev->descriptor.idProduct == pid){
found = 1;
d = bus->dirname;
f = dev->filename;
}
}
}
if(!found){
ERR(_("Device not found"));
return;
}
DBG("found camera device, reseting");
snprintf(buf, sizeof(buf), "/dev/bus/usb/%s/%s", d,f);
fd = open(buf, O_WRONLY);
if(fd < 0){
ERR("Can't open device file %s: %s", buf, strerror(errno));
return;
}
WARNX("Resetting USB device %s", buf);
rc = ioctl(fd, USBDEVFS_RESET, 0);
if(rc < 0){
perror("Error in ioctl");
return;
}
close(fd);
}*/
static int setdevno(int n){
FNAME();
if(n > ncameras - 1) return FALSE;
if(ApnGlueOpen(n)) return FALSE;
ApnGlueExpAbort();
ApnGluePowerResume();
ApnGlueReset();
char *msg = ApnGlueGetInfo(&pid, &vid);
DBG("CAMERA msg:\n%s\n", msg);
char *f = strstr(msg, "Model: ");
if(f){
f += strlen("Model: ");
char *e = strchr(f, '\n');
size_t l = (e) ? (size_t)(e-f) : strlen(f);
if(l >= BUFSIZ) l = BUFSIZ - 1;
snprintf(camname, l, "%s", f);
}
ApnGlueGetMaxValues(expt, &camera.array.w, &camera.array.h, &osw, NULL, &maxbinh, &maxbinv, NULL, NULL);
DBG("MAX format: W/H: %d/%d; osw=%d, binh/v=%d/%d", camera.array.w, camera.array.h, osw, maxbinh, maxbinv);
double x, y;
ApnGlueGetGeom(&x, &y);
camera.pixX = x, camera.pixY = y;
camera.field.w = camera.array.w - osw;
camera.field.h = camera.array.h;
DBG("Pixel size W/H: %g/%g; field w/h: %d/%d", x, y, camera.field.w, camera.field.h);
;
return TRUE;
}
static int modelname(char *buf, int bufsz){
strncpy(buf, camname, bufsz);
return TRUE;
}
static int shutter(shutter_op cmd){
int op = (cmd == SHUTTER_OPEN) ? 1 : 0;
ApnGlueOpenShutter(op);
return TRUE;
}
static int geometrylimits(frameformat *l, frameformat *s){
if(l) *l = camera.array;
if(s) *s = (frameformat){.w = 1, .h = 1, .xoff = 1, .yoff = 1};
return TRUE;
}
static int sett(float t){
ApnGlueSetTemp(t);
return TRUE;
}
static int setfanspd(fan_speed s){
ApnGlueSetFan((int) s);
return TRUE;
}
static int preflash(int n){
if(n > 0) n = 1; else n = 0;
ApnGluePreFlash(n);
return TRUE;
}
// 0 - 12 bit, 1 - 16bit
static int setbitdepth(int i){
DBG("set bit depth %d", i);
Apn_Resolution res = (i) ? Apn_Resolution_SixteenBit : Apn_Resolution_TwelveBit;
ApnGlueSetDatabits(res);
is16bit = i;
return TRUE;
}
static int setfastspeed(int fast){
DBG("set fast speed %d", fast);
unsigned short spd = (fast) ? AdcSpeed_Fast : AdcSpeed_Normal;
ApnGlueSetSpeed(spd);
return TRUE;
}
static int setgeometry(frameformat *f){
if(!f) return FALSE;
int ow = (f->w > camera.field.w) ? camera.array.w - f->w : f->w;
if(ow < 0) ow = 0;
if(ApnGlueSetExpGeom(f->w * hbin, f->h * vbin, ow, 0, hbin, vbin,
f->xoff, f->yoff, &imW, &imH, whynot)){
WARNX("Can't set geometry: %s", whynot);
}else{
camera.geometry = *f;
}
return TRUE;
}
static int setbin(int binh, int binv){
DBG("set bin v/h: %d/%d", binv, binh);
if(binh > maxbinh || binv > maxbinv) return FALSE;
hbin = binh; vbin = binv;
return TRUE;
}
static int tcold(float *t){
if(!t) return FALSE;
double dt;
ApnGlueGetTemp(&dt);
*t = dt;
return TRUE;
}
static int thot(float *t){
if(t) *t = ApnGlueGetHotTemp();
return TRUE;
}
static int startexp(){
tstart = dtime();
DBG("Start exposition");
CCDerr r = ApnGlueStartExp(&exptime, isobject);
if(ALTA_OK != r){
/*reset_usb_port();
r = ApnGlueStartExp(&exptime, isobject);
if(ALTA_OK != r){*/
ApnGlueReset();
DBG("Error starting exp: %d", (int)r);
return FALSE;
//}
}
isexposuring = 1;
return TRUE;
}
static int frametype(int islight){
DBG("set frame type %d", islight);
isobject = islight;
return TRUE;
}
static int setexp(float t){
DBG("start exp %g, min: %g, max: %g", t, expt[0], expt[1]);
if(t < expt[0] || t > expt[1]) return FALSE; // too big or too small exptime
exptime = t;
return TRUE;
}
static int getbin(int *h, int *v){
DBG("get bin v/h: %d/%d", vbin, hbin);
if(h) *h = hbin;
if(v) *v = vbin;
return TRUE;
}
static int pollcapt(capture_status *st, float *remain){
DBG("Poll capture, tremain=%g", dtime() - tstart);
if(dtime() - tstart > 5.){ // capture error?
ApnGlueExpAbort();
if(*st) *st = CAPTURE_ABORTED;
return FALSE;
}
if(remain) *remain = dtime() - tstart;
if(st) *st = CAPTURE_PROCESS;
if(ApnGlueExpDone()){
if(st) *st = CAPTURE_READY;
isexposuring = 0;
DBG("Capture ready");
}
return TRUE;
}
static int capture(IMG *ima){
FNAME();
if(!ima || !ima->data) return FALSE;
if(ApnGlueReadPixels((uint16_t*)ima->data, imW * imH, whynot)){
WARNX("Can't read image: %s", whynot);
return FALSE;
}
ima->bitpix = is16bit ? 16 : 12;
return TRUE;
}
static int ffalse(_U_ float f){ return FALSE; }
static int fpfalse(_U_ float *f){ return FALSE; }
static int ifalse(_U_ int i){ return FALSE; }
//static int vtrue(){ return TRUE; }
static int ipfalse(_U_ int *i){ return FALSE; }
/*
* Global objects: camera, focuser and wheel
*/
Camera camera = {
.check = ndev,
.close = disconnect,
.pollcapture = pollcapt,
.capture = capture,
.cancel = cancel,
.startexposition = startexp,
// setters:
.setDevNo = setdevno,
.setbrightness = ffalse,
.setexp = setexp,
.setgain = ffalse,
.setT = sett,
.setbin = setbin,
.setnflushes = preflash,
.shuttercmd = shutter,
.confio = ifalse,
.setio = ifalse,
.setframetype = frametype, // set DARK or NORMAL: no shutter -> no darks
.setbitdepth = setbitdepth,
.setfastspeed = setfastspeed,
.setgeometry = setgeometry,
.setfanspeed = setfanspd,
// getters:
.getbrightness = fpfalse,
.getModelName = modelname,
.getgain = fpfalse,
.getmaxgain = fpfalse,
.getgeomlimits = geometrylimits,
.getTcold = tcold,
.getThot = thot,
.getTbody = fpfalse,
.getbin = getbin,
.getio = ipfalse,
};

View File

@ -17,6 +17,7 @@ option(FLI "Add support of FLI cameras" OFF)
option(BASLER "Add support of BASLER cameras" OFF) option(BASLER "Add support of BASLER cameras" OFF)
option(HIKROBOT "Add support of HIKROBOT cameras" OFF) option(HIKROBOT "Add support of HIKROBOT cameras" OFF)
option(FLYCAP "Add support of Grasshopper FlyCap cameras" OFF) option(FLYCAP "Add support of Grasshopper FlyCap cameras" OFF)
option(APOGEE "Add support of Apogee cameras" OFF)
# default flags # default flags
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -W -Wextra -std=gnu99") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -W -Wextra -std=gnu99")
@ -96,7 +97,9 @@ endif()
if(FLYCAP) if(FLYCAP)
add_subdirectory(GRH_cameras) add_subdirectory(GRH_cameras)
endif() endif()
if(APOGEE)
add_subdirectory(APOGEE_cameras)
endif()
# directory should contain dir locale/ru for gettext translations # directory should contain dir locale/ru for gettext translations
set(LCPATH ${CMAKE_SOURCE_DIR}/locale/ru) set(LCPATH ${CMAKE_SOURCE_DIR}/locale/ru)

View File

@ -1,7 +1,7 @@
CCD/CMOS imaging server CCD/CMOS imaging server
======================= =======================
Supports FLI cameras/focusers/wheels and cameras: ZWO, Basler, HikRobot. Supports FLI cameras/focusers/wheels and cameras: ZWO, Basler, HikRobot, PointGrey, Apogee.
Allows to run as standalone application or imaging server/client. Allows to run as standalone application or imaging server/client.
To restart server (e.g. if hardware was off) kill it with SIGUSR1 To restart server (e.g. if hardware was off) kill it with SIGUSR1
@ -10,10 +10,12 @@ To restart server (e.g. if hardware was off) kill it with SIGUSR1
cmake options: cmake options:
- `-DAPOGEE=ON` - compile Apogee plugin
- `-DDEBUG=ON` - make with a lot debugging info - `-DDEBUG=ON` - make with a lot debugging info
- `-DIMAGEVIEW=ON` - compile with image viewer support (only for standalone) (OpenGL!!!) - `-DIMAGEVIEW=ON` - compile with image viewer support (only for standalone) (OpenGL!!!)
- `-DBASLER=ON` - compile Basler support plugin - `-DBASLER=ON` - compile Basler support plugin
- `-DFLI=ON` - compile FLI support plugin - `-DFLI=ON` - compile FLI support plugin
- `-DFLYCAPT=ON` - compile GrassHopper PointGrey plugin
- `-DHIKROBOT=ON` - compile HikRobot support plugin - `-DHIKROBOT=ON` - compile HikRobot support plugin
- `-DZWO=ON` - compile ZWO support plugin - `-DZWO=ON` - compile ZWO support plugin

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-02-28 17:05+0300\n" "POT-Creation-Date: 2023-03-06 17:25+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -474,12 +474,12 @@ msgstr ""
msgid "Can't set brightness to %g" msgid "Can't set brightness to %g"
msgstr "" msgstr ""
#: ccdfunc.c:725 server.c:230 #: ccdfunc.c:725 server.c:229
#, c-format #, c-format
msgid "Can't set binning %dx%d" msgid "Can't set binning %dx%d"
msgstr "" msgstr ""
#: ccdfunc.c:737 server.c:231 #: ccdfunc.c:737 server.c:230
msgid "Can't set given geometry" msgid "Can't set given geometry"
msgstr "" msgstr ""
@ -525,7 +525,7 @@ msgstr ""
msgid "Capture frame %d" msgid "Capture frame %d"
msgstr "" msgstr ""
#: ccdfunc.c:781 ccdfunc.c:831 server.c:125 #: ccdfunc.c:781 ccdfunc.c:831 server.c:124
msgid "Can't start exposition" msgid "Can't start exposition"
msgstr "" msgstr ""
@ -547,7 +547,7 @@ msgstr ""
msgid "%d seconds till pause ends\n" msgid "%d seconds till pause ends\n"
msgstr "" msgstr ""
#: server.c:168 #: server.c:167
msgid "No camera device" msgid "No camera device"
msgstr "" msgstr ""

View File

@ -7,7 +7,7 @@
msgid "" msgid ""
msgstr "Project-Id-Version: PACKAGE VERSION\n" msgstr "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-02-28 17:05+0300\n" "POT-Creation-Date: 2023-03-01 08:54+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -162,7 +162,7 @@ msgstr "
msgid "Can't set active wheel number" msgid "Can't set active wheel number"
msgstr "îÅ ÍÏÇÕ ÕÓÔÁÎÏ×ÉÔØ ÎÏÍÅÒ ÁËÔÉ×ÎÏÇÏ ËÏÌÅÓÁ" msgstr "îÅ ÍÏÇÕ ÕÓÔÁÎÏ×ÉÔØ ÎÏÍÅÒ ÁËÔÉ×ÎÏÇÏ ËÏÌÅÓÁ"
#: ccdfunc.c:725 server.c:230 #: ccdfunc.c:725 server.c:229
#, c-format #, c-format
msgid "Can't set binning %dx%d" msgid "Can't set binning %dx%d"
msgstr "îÅ ÍÏÇÕ ÕÓÔÁÎÏ×ÉÔØ ÂÉÎÎÉÎÇ %dx%d" msgstr "îÅ ÍÏÇÕ ÕÓÔÁÎÏ×ÉÔØ ÂÉÎÎÉÎÇ %dx%d"
@ -190,7 +190,7 @@ msgstr "
msgid "Can't set gain to %g" msgid "Can't set gain to %g"
msgstr "îÅ ÍÏÇÕ ÕÓÔÁÎÏ×ÉÔØ Gain × %g" msgstr "îÅ ÍÏÇÕ ÕÓÔÁÎÏ×ÉÔØ Gain × %g"
#: ccdfunc.c:737 server.c:231 #: ccdfunc.c:737 server.c:230
msgid "Can't set given geometry" msgid "Can't set given geometry"
msgstr "îÅ ÍÏÇÕ ÕÓÔÁÎÏ×ÉÔØ ÇÅÏÍÅÔÒÉÀ" msgstr "îÅ ÍÏÇÕ ÕÓÔÁÎÏ×ÉÔØ ÇÅÏÍÅÔÒÉÀ"
@ -213,7 +213,7 @@ msgstr "
msgid "Can't set wheel position %d" msgid "Can't set wheel position %d"
msgstr "îÅ ÍÏÇÕ ÕÓÔÁÎÏ×ÉÔØ ÐÏÌÏÖÅÎÉÅ ËÏÌÅÓÁ %d" msgstr "îÅ ÍÏÇÕ ÕÓÔÁÎÏ×ÉÔØ ÐÏÌÏÖÅÎÉÅ ËÏÌÅÓÁ %d"
#: ccdfunc.c:781 ccdfunc.c:831 server.c:125 #: ccdfunc.c:781 ccdfunc.c:831 server.c:124
msgid "Can't start exposition" msgid "Can't start exposition"
msgstr "îÅ ÍÏÇÕ ÎÁÞÁÔØ ÜËÓÐÏÚÉÃÉÀ" msgstr "îÅ ÍÏÇÕ ÎÁÞÁÔØ ÜËÓÐÏÚÉÃÉÀ"
@ -289,7 +289,7 @@ msgstr "
msgid "N flushes before exposing (default: 1)" msgid "N flushes before exposing (default: 1)"
msgstr "N ÚÁÓ×ÅÞÉ×ÁÎÉÊ ÐÅÒÅÄ ÜËÓÐÏÚÉÃÉÅÊ (ÐÏ ÕÍÏÌÞÁÎÉÀ: 1)" msgstr "N ÚÁÓ×ÅÞÉ×ÁÎÉÊ ÐÅÒÅÄ ÜËÓÐÏÚÉÃÉÅÊ (ÐÏ ÕÍÏÌÞÁÎÉÀ: 1)"
#: server.c:168 #: server.c:167
msgid "No camera device" msgid "No camera device"
msgstr "îÅ ÕËÁÚÁÎÏ ÕÓÔÒÏÊÓÔ×Ï ËÁÍÅÒÙ" msgstr "îÅ ÕËÁÚÁÎÏ ÕÓÔÒÏÊÓÔ×Ï ËÁÍÅÒÙ"

View File

@ -885,7 +885,7 @@ static hresult imsendhandler(int fd, _U_ const char *key, _U_ const char *val){
if(!ima.data || !ima.h || !ima.w) return RESULT_FAIL; if(!ima.data || !ima.h || !ima.w) return RESULT_FAIL;
// send image as raw data w*h*2 // send image as raw data w*h*2
if(!sendimage(fd, ima.data, 2*ima.h*ima.w)) return RESULT_DISCONNECTED; if(!sendimage(fd, ima.data, 2*ima.h*ima.w)) return RESULT_DISCONNECTED;
return RESULT_OK; return RESULT_SILENCE;
} }
static hresult imsizehandler(int fd, const char *key, _U_ const char *val){ static hresult imsizehandler(int fd, const char *key, _U_ const char *val){

View File

@ -132,6 +132,7 @@ int start_socket(int isserver, char *path, int isnet){
return 0; return 0;
} }
// send image data to client
int sendimage(int fd, uint16_t *data, int l){ int sendimage(int fd, uint16_t *data, int l){
if(fd < 1 || !data || l < 1) return TRUE; // empty message if(fd < 1 || !data || l < 1) return TRUE; // empty message
DBG("send new image (size=%d) to fd %d", l, fd); DBG("send new image (size=%d) to fd %d", l, fd);