mirror of
https://github.com/eddyem/SBIG_340.git
synced 2025-12-06 02:35:12 +03:00
take image works
This commit is contained in:
parent
88b2cfcdbe
commit
06d0ad7082
2
Makefile
2
Makefile
@ -1,6 +1,6 @@
|
||||
# run `make DEF=...` to add extra defines
|
||||
PROGRAM := sbig340
|
||||
LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all
|
||||
LDFLAGS := -ltiff -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all
|
||||
SRCS := $(wildcard *.c)
|
||||
DEFINES := $(DEF) -D_XOPEN_SOURCE=1111 -DEBUG
|
||||
OBJDIR := mk
|
||||
|
||||
21
cmdlnopts.c
21
cmdlnopts.c
@ -45,7 +45,16 @@ glob_pars const Gdefault = {
|
||||
.rest_pars_num = 0,
|
||||
.splist = 0,
|
||||
.newspeed = 0,
|
||||
.rest_pars = NULL
|
||||
.rest_pars = NULL,
|
||||
.shutter_cmd = NULL,
|
||||
.subframe = NULL,
|
||||
.speed = 0,
|
||||
.exptime = 1.,
|
||||
.binning = 0,
|
||||
.takeimg = 0,
|
||||
.imtype = "a",
|
||||
.imstoretype = NULL,
|
||||
.outpfname = "output.tiff"
|
||||
};
|
||||
|
||||
/*
|
||||
@ -61,7 +70,17 @@ myoption cmdlnopts[] = {
|
||||
{"heater-on",NO_ARGS, APTR(&G.heater),HEATER_ON, arg_none, NULL, _("turn heater on")},
|
||||
{"heater-off",NO_ARGS, APTR(&G.heater),HEATER_OFF, arg_none, NULL, _("turn heater off")},
|
||||
{"spd-list",NO_ARGS, NULL, 'l', arg_int, APTR(&G.splist), _("list speeds available")},
|
||||
{"baudrate",NEED_ARG, NULL, 'b', arg_int, APTR(&G.speed), _("connect at given baudrate without autocheck")},
|
||||
{"spd-set", NEED_ARG, NULL, 's', arg_int, APTR(&G.newspeed), _("set terminal speed")},
|
||||
// only long variants
|
||||
{"shutter", NEED_ARG, NULL, 0, arg_string, APTR(&G.shutter_cmd),_("shutter command: 'o' for open, 'c' for close, 'k' for de-energize")},
|
||||
{"subframe",NEED_ARG, NULL, 0, arg_string, APTR(&G.subframe), _("select subframe: x,y,size")},
|
||||
{"exptime", NEED_ARG, NULL, 'x', arg_double, APTR(&G.exptime), _("exposition time (1s by default)")},
|
||||
{"binning", NEED_ARG, NULL, 'B', arg_int, APTR(&G.binning), _("binning (1 by default)")},
|
||||
{"start-exp",NO_ARGS, NULL, 'X', arg_int, APTR(&G.takeimg), _("start exposition")},
|
||||
{"imtype", NEED_ARG, NULL, 'T', arg_string, APTR(&G.imtype), _("image type: light (l, L), autodark (a, A), dark (d, D)")},
|
||||
{"storetype",NEED_ARG, NULL, 'S', arg_string, APTR(&G.imstoretype),_("'overwrite'/'rewrite' to rewrite existing image, 'enumerate'/'numerate' to use given filename as base for series")},
|
||||
{"output", NEED_ARG, NULL, 'o', arg_string, APTR(&G.outpfname), _("output file name (default: output.tiff)")},
|
||||
// simple integer parameter with obligatory arg:
|
||||
end_option
|
||||
};
|
||||
|
||||
@ -37,6 +37,15 @@ typedef struct{
|
||||
heater_cmd heater; // turn heater on/off/leave unchanged
|
||||
int splist; // list speeds available
|
||||
int newspeed; // change speed
|
||||
int speed; // connect @ this speed
|
||||
char *shutter_cmd; // shutter command: 'o' for open, 'c' for close, 'k' for de-energize
|
||||
char *subframe; // select subframe (x,y,size)
|
||||
double exptime; // exsposition time (1s by default)
|
||||
int binning; // binning (1 by default)
|
||||
int takeimg; // take image
|
||||
char *imtype; // image type (light, autodark, dark)
|
||||
char *imstoretype; // "overwrite" (or "rewrite"), "normal" (or NULL), "enumerate" (or "numerate")
|
||||
char *outpfname; // output filename for image storing
|
||||
char** rest_pars; // the rest parameters: array of char*
|
||||
} glob_pars;
|
||||
|
||||
|
||||
156
imfunctions.c
Normal file
156
imfunctions.c
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* imfunctions.c - functions to work with image
|
||||
*
|
||||
* Copyright 2017 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "usefull_macros.h"
|
||||
#include "imfunctions.h"
|
||||
#include "term.h"
|
||||
#include <strings.h> // strncasecmp
|
||||
#include <tiffio.h> // save tiff
|
||||
|
||||
|
||||
// find the first non-exists filename
|
||||
char *make_filename(char *outfile, char *ext){
|
||||
struct stat filestat;
|
||||
static char buff[FILENAME_MAX];
|
||||
int num;
|
||||
for(num = 1; num < 10000; num++){
|
||||
if(snprintf(buff, FILENAME_MAX, "%s_%04d.%s", outfile, num, ext) < 1)
|
||||
return NULL;
|
||||
if(stat(buff, &filestat) && ENOENT == errno) // OK, file not exists
|
||||
return buff;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check image to store
|
||||
* @param filename (i) - output file name (or prefix with suffix)
|
||||
* @param store (i) - "overwrite" (or "rewrite"), "normal" (or NULL), "enumerate" (or "numerate")
|
||||
*/
|
||||
imstorage *chk_storeimg(char *filename, char* store){
|
||||
store_type st = STORE_NORMAL;
|
||||
if(store){ // rewrite or enumerate
|
||||
int L = strlen(store);
|
||||
if(0 == strncasecmp(store, "overwrite", L) || 0 == strncasecmp(store, "rewrite", L)) st = STORE_REWRITE;
|
||||
else if(0 == strncasecmp(store, "enumerate", L) || 0 == strncasecmp(store, "numerate", L)) st = STORE_NEXTNUM;
|
||||
else{
|
||||
WARNX(_("Wrong storing type: %s"), store);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
char *f2store = filename;
|
||||
char *nm = strdup(filename);
|
||||
if(!nm) ERRX("strdup");
|
||||
char *pt = strrchr(nm, '.');
|
||||
if(!pt){
|
||||
WARNX(_("Wrong image name pattern: this should be a filename with suffix .tiff or .jpg"));
|
||||
FREE(nm);
|
||||
return NULL;
|
||||
}
|
||||
*pt++ = 0;
|
||||
if(strcmp(pt, "tiff") && strcmp(pt, "jpg")){
|
||||
WARNX("Can save only into jpg or tiff files!");
|
||||
return NULL;
|
||||
}
|
||||
if(st == STORE_NORMAL){
|
||||
struct stat filestat;
|
||||
if(stat(filename, &filestat)){
|
||||
if(ENOENT != errno){
|
||||
WARN(_("Error access file %s"), filename);
|
||||
return NULL;
|
||||
}
|
||||
}else{
|
||||
WARNX(_("The file %s exists, use '-Srew' option to rewrite"));
|
||||
return NULL;
|
||||
}
|
||||
}else if(st == STORE_NEXTNUM){
|
||||
f2store = make_filename(nm, pt);
|
||||
}
|
||||
FREE(nm);
|
||||
imstorage *ist = MALLOC(imstorage, 1);
|
||||
ist->st = st;
|
||||
ist->imname = strdup(f2store);
|
||||
if(!ist->imname)ERR("strdup");
|
||||
return ist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to write tiff file
|
||||
*/
|
||||
int writetiff(imstorage *img){
|
||||
int ret = 1, H = img->H, W = img->W, y;
|
||||
uint16_t *data = img->imdata;
|
||||
TIFF *image = TIFFOpen(img->imname, "w");
|
||||
if(!image){
|
||||
WARN("Can't open tiff file");
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
TIFFSetField(image, TIFFTAG_IMAGEWIDTH, W);
|
||||
TIFFSetField(image, TIFFTAG_IMAGELENGTH, H);
|
||||
TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 16);
|
||||
TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, 1);
|
||||
TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, 1);
|
||||
TIFFSetField(image, TIFFTAG_ORIENTATION, ORIENTATION_BOTLEFT);
|
||||
TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
|
||||
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
|
||||
TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
||||
TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT, RESUNIT_NONE);
|
||||
//tstrip_t strip = 0;
|
||||
for (y = 0; y < H; ++y, data += W){
|
||||
TIFFWriteScanline(image, data, y, 0);
|
||||
/* if(TIFFWriteEncodedStrip(image, strip, data, W) < 0){
|
||||
ret = 0;
|
||||
goto done;
|
||||
}*/
|
||||
}
|
||||
|
||||
done:
|
||||
if(image) TIFFClose(image);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save image
|
||||
* @param filename (i) - output file name
|
||||
* @return 0 if all OK
|
||||
*/
|
||||
int store_image(imstorage *img){
|
||||
if(wait4image()) return 1;
|
||||
DBG("OK, get image");
|
||||
uint16_t *imdata = get_image(img);
|
||||
if(!imdata){
|
||||
WARNX(_("Error readout"));
|
||||
return 2;
|
||||
}
|
||||
img->imdata = imdata;
|
||||
green("Save image into %s\n", img->imname);
|
||||
/*int f = open(img->imname, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
if(f){
|
||||
DBG("%zd", write(f, img->imdata, img->W*img->H*2));
|
||||
close(f);
|
||||
}*/
|
||||
if(!writetiff(img)) return 3;
|
||||
return 0;
|
||||
}
|
||||
60
imfunctions.h
Normal file
60
imfunctions.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* geany_encoding=koi8-r
|
||||
* imfunctions.h
|
||||
*
|
||||
* Copyright 2017 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef __IMFUNCTIONS_H__
|
||||
#define __IMFUNCTIONS_H__
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum{
|
||||
STORE_REWRITE,
|
||||
STORE_NORMAL,
|
||||
STORE_NEXTNUM
|
||||
} store_type;
|
||||
|
||||
typedef enum{
|
||||
IMTYPE_AUTODARK,
|
||||
IMTYPE_LIGHT,
|
||||
IMTYPE_DARK
|
||||
} image_type;
|
||||
|
||||
typedef struct{
|
||||
uint16_t Xstart;
|
||||
uint16_t Ystart;
|
||||
uint8_t size;
|
||||
} imsubframe;
|
||||
|
||||
typedef struct{
|
||||
store_type st; // how would files be stored
|
||||
char *imname;
|
||||
int binning;
|
||||
image_type imtype;
|
||||
double exptime;
|
||||
imsubframe *subframe;
|
||||
size_t W, H; // image size
|
||||
uint16_t *imdata; // image data itself
|
||||
} imstorage;
|
||||
|
||||
imstorage *chk_storeimg(char *filename, char* store);
|
||||
int store_image(imstorage *filename);
|
||||
|
||||
#endif // __IMFUNCTIONS_H__
|
||||
28
main.c
28
main.c
@ -22,8 +22,10 @@
|
||||
#include <signal.h>
|
||||
#include "term.h"
|
||||
#include "cmdlnopts.h"
|
||||
#include "imfunctions.h"
|
||||
|
||||
void signals(int signo){
|
||||
abort_image();
|
||||
restore_console();
|
||||
restore_tty();
|
||||
exit(signo);
|
||||
@ -42,7 +44,7 @@ int main(int argc, char **argv){
|
||||
WARNX(_("Options --daemon and --terminal can't be together!"));
|
||||
return 1;
|
||||
}
|
||||
if(!try_connect(G->device)){
|
||||
if(!try_connect(G->device, G->speed)){
|
||||
WARNX(_("Check power and connection: device not answer!"));
|
||||
return 1;
|
||||
}
|
||||
@ -50,8 +52,32 @@ int main(int argc, char **argv){
|
||||
if(fw) printf(_("Firmware version: %s\n"), fw);
|
||||
if(G->newspeed && term_setspeed(G->newspeed))
|
||||
ERRX(_("Can't change speed to %d"), G->newspeed);
|
||||
if(G->shutter_cmd && shutter_command(G->shutter_cmd))
|
||||
WARNX(_("Can't send shutter command: %s"), G->shutter_cmd);
|
||||
if(G->heater != HEATER_LEAVE)
|
||||
heater(G->heater); // turn on/off heater
|
||||
if(G->takeimg){
|
||||
imsubframe *F = NULL;
|
||||
if(G->subframe){
|
||||
if(!(F = define_subframe(G->subframe)))
|
||||
ERRX(_("Error defining subframe"));
|
||||
G->binning = 0xff; // take subframe
|
||||
}
|
||||
imstorage *img = chk_storeimg(G->outpfname, G->imstoretype);
|
||||
if(img){
|
||||
img->subframe = F;
|
||||
img->exptime = G->exptime;
|
||||
img->binning = G->binning;
|
||||
if(start_exposition(img, G->imtype))
|
||||
WARNX(_("Error starting exposition"));
|
||||
else if(store_image(img))
|
||||
WARNX(_("Error storing image %s"), img->imname);
|
||||
FREE(img->imname);
|
||||
FREE(img->imdata);
|
||||
FREE(img);
|
||||
}
|
||||
FREE(F);
|
||||
}
|
||||
if(G->daemon || G->terminal){
|
||||
red(_("All other commandline options rejected!\n"));
|
||||
if(G->terminal) run_terminal(); // non-echo terminal mode
|
||||
|
||||
@ -340,12 +340,12 @@ static int argsort(const void *a1, const void *a2){
|
||||
int s1 = o1->val, s2 = o2->val;
|
||||
int *f1 = o1->flag, *f2 = o2->flag;
|
||||
// check if both options has short arg
|
||||
if(f1 == NULL && f2 == NULL){ // both have short arg
|
||||
if(f1 == NULL && f2 == NULL && s1 && s2){ // both have short arg
|
||||
return (s1 - s2);
|
||||
}else if(f1 != NULL && f2 != NULL){ // both don't have short arg - sort by long
|
||||
}else if((f1 != NULL || !s1) && (f2 != NULL || !s2)){ // both don't have short arg - sort by long
|
||||
return strcmp(l1, l2);
|
||||
}else{ // only one have short arg -- return it
|
||||
if(f2) return -1; // a1 have short - it is 'lesser'
|
||||
if(f2 || !s2) return -1; // a1 have short - it is 'lesser'
|
||||
else return 1;
|
||||
}
|
||||
}
|
||||
|
||||
1083
sbig340.c.tags
1083
sbig340.c.tags
File diff suppressed because it is too large
Load Diff
447
term.c
447
term.c
@ -20,20 +20,8 @@
|
||||
*/
|
||||
#include "usefull_macros.h"
|
||||
#include "term.h"
|
||||
/*
|
||||
#include <termios.h> // tcsetattr
|
||||
#include <unistd.h> // tcsetattr, close, read, write
|
||||
#include <sys/ioctl.h> // ioctl
|
||||
#include <stdio.h> // printf, getchar, fopen, perror
|
||||
#include <stdlib.h> // exit
|
||||
#include <sys/stat.h> // read
|
||||
#include <fcntl.h> // read
|
||||
#include <signal.h> // signal
|
||||
#include <time.h> // time
|
||||
#include <string.h> // memcpy
|
||||
#include <stdint.h> // int types
|
||||
#include <sys/time.h> // gettimeofday
|
||||
*/
|
||||
#include <strings.h> // strncasecmp
|
||||
|
||||
#define BUFLEN 1024
|
||||
|
||||
tcflag_t Bspeeds[] = {
|
||||
@ -75,17 +63,17 @@ int get_curspeed(){
|
||||
* Send command by serial port, return 0 if all OK
|
||||
*/
|
||||
static uint8_t last_chksum = 0;
|
||||
int send_data(uint8_t *buf){
|
||||
if(!*buf) return 1;
|
||||
int send_data(uint8_t *buf, int len){
|
||||
if(len < 1) return 1;
|
||||
uint8_t chksum = 0, *ptr = buf;
|
||||
int l;
|
||||
for(l = 0; *ptr; ++l)
|
||||
for(l = 0; l < len; ++l)
|
||||
chksum ^= ~(*ptr++) & 0x7f;
|
||||
DBG("send: %s%c", buf, (char)chksum);
|
||||
if(write_tty(buf, l)) return 1;
|
||||
DBG("cmd done");
|
||||
DBG("send: %s (chksum: 0x%X)", buf, chksum);
|
||||
if(write_tty(buf, len)) return 1;
|
||||
DBG("cmd sent");
|
||||
if(write_tty(&chksum, 1)) return 1;
|
||||
DBG("checksum done");
|
||||
DBG("checksum sent");
|
||||
last_chksum = chksum;
|
||||
return 0;
|
||||
}
|
||||
@ -93,6 +81,7 @@ int send_cmd(uint8_t cmd){
|
||||
uint8_t s[2];
|
||||
s[0] = cmd;
|
||||
s[1] = ~(cmd) & 0x7f;
|
||||
DBG("Write %c", cmd);
|
||||
if(write_tty(s, 2)) return 1;
|
||||
last_chksum = s[1];
|
||||
return 0;
|
||||
@ -102,18 +91,40 @@ int send_cmd(uint8_t cmd){
|
||||
* Wait for answer with checksum
|
||||
*/
|
||||
trans_status wait_checksum(){
|
||||
double d0 = dtime();
|
||||
uint8_t chr;
|
||||
int r;
|
||||
double d0 = dtime();
|
||||
do{
|
||||
if(read_tty(&chr, 1)) break;
|
||||
if((r = read_tty(&chr, 1))) break;
|
||||
DBG("wait..");
|
||||
}while(dtime() - d0 < WAIT_TMOUT);
|
||||
if(dtime() - d0 >= WAIT_TMOUT) return TRANS_TIMEOUT;
|
||||
DBG("chksum: got 0x%x, need 0x%x", chr, last_chksum);
|
||||
if(chr != last_chksum) return TRANS_BADCHSUM;
|
||||
if(chr != last_chksum){
|
||||
if(chr == 0x7f) return TRANS_TRYAGAIN;
|
||||
else if(chr == ANS_EXP_IN_PROGRESS) return TRANS_BUSY;
|
||||
else return TRANS_BADCHSUM;
|
||||
}
|
||||
return TRANS_SUCCEED;
|
||||
}
|
||||
|
||||
/**
|
||||
* send command and wait for checksum
|
||||
* @return TRANS_SUCCEED if all OK
|
||||
*/
|
||||
trans_status send_cmd_cs(uint8_t cmd){
|
||||
if(send_cmd(cmd)) return TRANS_ERROR;
|
||||
return wait_checksum();
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort image exposition
|
||||
* Used only on exit, so don't check commands status
|
||||
*/
|
||||
void abort_image(){
|
||||
send_cmd_cs(CMD_ABORT_IMAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* read string from terminal (with timeout)
|
||||
* @param str (o) - buffer for string
|
||||
@ -140,7 +151,7 @@ size_t read_string(uint8_t *str, int L){
|
||||
* @return transaction status
|
||||
*/
|
||||
trans_status wait4answer(uint8_t **rdata, int *rdlen){
|
||||
*rdlen = 0;
|
||||
if(rdlen) *rdlen = 0;
|
||||
static uint8_t buf[128];
|
||||
int L = 0;
|
||||
trans_status st = wait_checksum();
|
||||
@ -149,20 +160,42 @@ trans_status wait4answer(uint8_t **rdata, int *rdlen){
|
||||
do{
|
||||
if((L = read_tty(buf, sizeof(buf)))) break;
|
||||
}while(dtime() - d0 < WAIT_TMOUT);
|
||||
DBG("read %d bytes, first: 0x%x",L, buf[0]);
|
||||
if(!L) return TRANS_TIMEOUT;
|
||||
*rdata = buf;
|
||||
*rdlen = L;
|
||||
if(rdata) *rdata = buf;
|
||||
if(rdlen) *rdlen = L;
|
||||
return TRANS_SUCCEED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to connect to `device` at different speeds
|
||||
* check if given baudrate right
|
||||
* @return its number in `speeds` array or -1 if fault
|
||||
*/
|
||||
int chkspeed(int speed){
|
||||
int spdidx = 0;
|
||||
for(; spdidx < speedssize; ++spdidx)
|
||||
if(speeds[spdidx] == speed) break;
|
||||
if(spdidx == speedssize){
|
||||
WARNX(_("Wrong speed: %d!"), speed);
|
||||
list_speeds();
|
||||
return -1;
|
||||
}
|
||||
return spdidx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to connect to `device` at given speed (or try all speeds, if speed == 0)
|
||||
* @return connection speed if success or 0
|
||||
*/
|
||||
int try_connect(char *device){
|
||||
int try_connect(char *device, int speed){
|
||||
if(!device) return 0;
|
||||
int spdstart = 0, spdmax = speedssize;
|
||||
if(speed){
|
||||
if((spdstart = chkspeed(speed)) < 0) return 0;
|
||||
spdmax = spdstart + 1;
|
||||
}
|
||||
green(_("Connecting to %s... "), device);
|
||||
for(curspd = 0; curspd < speedssize; ++curspd){
|
||||
for(curspd = spdstart; curspd < spdmax; ++curspd){
|
||||
tty_init(device, Bspeeds[curspd]);
|
||||
DBG("Try speed %d", speeds[curspd]);
|
||||
int ctr;
|
||||
@ -174,12 +207,23 @@ int try_connect(char *device){
|
||||
uint8_t *rd;
|
||||
int l;
|
||||
// OK, now check an answer
|
||||
if(TRANS_SUCCEED != wait4answer(&rd, &l) || l != 1 || *rd != ANS_COMM_TEST) continue;
|
||||
trans_status st = wait4answer(&rd, &l);
|
||||
DBG("st: %d", st);
|
||||
if(st == TRANS_BUSY){ // busy - send command 'abort exp'
|
||||
send_cmd(CMD_ABORT_IMAGE);
|
||||
--curspd;
|
||||
continue;
|
||||
}
|
||||
if(st == TRANS_TRYAGAIN){ // there was an error in last communications - try again
|
||||
--curspd;
|
||||
continue;
|
||||
}
|
||||
if(TRANS_SUCCEED != st || l != 1 || *rd != ANS_COMM_TEST) continue;
|
||||
DBG("Got it!");
|
||||
green(_("Connection established at B%d.\n"), speeds[curspd]);
|
||||
return speeds[curspd];
|
||||
}
|
||||
green(_("No connection!"));
|
||||
green(_("No connection!\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -188,22 +232,16 @@ int try_connect(char *device){
|
||||
* @return 0 if all OK
|
||||
*/
|
||||
int term_setspeed(int speed){
|
||||
int spdidx = 0;
|
||||
size_t L;
|
||||
for(; spdidx < speedssize; ++spdidx)
|
||||
if(speeds[spdidx] == speed) break;
|
||||
if(spdidx == speedssize){
|
||||
WARNX(_("Wrong speed: %d!"), speed);
|
||||
list_speeds();
|
||||
return 1;
|
||||
}
|
||||
int spdidx = chkspeed(speed);
|
||||
if(spdidx < 0) return 1;
|
||||
if(spdidx == curspd){
|
||||
printf(_("Already connected at %d\n"), speeds[spdidx]);
|
||||
return 0;
|
||||
}
|
||||
green(_("Try to change speed to %d\n"), speed);
|
||||
uint8_t msg[7] = {CMD_CHANGE_BAUDRATE, spdidx + '0', 0};
|
||||
if(send_data(msg)){
|
||||
uint8_t msg[7] = {CMD_CHANGE_BAUDRATE, spdidx + '0'};
|
||||
if(send_data(msg, 2)){
|
||||
WARNX(_("Error during message send"));
|
||||
return 1;
|
||||
}
|
||||
@ -284,10 +322,10 @@ void daemonize(){
|
||||
|
||||
void heater(heater_cmd cmd){
|
||||
if(cmd == HEATER_LEAVE) return;
|
||||
uint8_t buf[3] = {CMD_HEATER, 0, 0};
|
||||
uint8_t buf[2] = {CMD_HEATER, 0};
|
||||
if(cmd == HEATER_ON) buf[1] = 1;
|
||||
int i;
|
||||
for(i = 0; i < 10 && send_data(buf); ++i);
|
||||
for(i = 0; i < 10 && send_data(buf, 2); ++i);
|
||||
trans_status st = TRANS_TIMEOUT;
|
||||
if(i < 10) st = wait_checksum();
|
||||
if(i == 10 || st != TRANS_SUCCEED){
|
||||
@ -300,10 +338,329 @@ void heater(heater_cmd cmd){
|
||||
*/
|
||||
char *get_firmvare_version(){
|
||||
static char buf[256];
|
||||
if(TRANS_SUCCEED != send_cmd(CMD_FIRMWARE_WERSION)) return NULL;
|
||||
if(TRANS_SUCCEED != send_cmd(CMD_FIRMWARE_VERSION)) return NULL;
|
||||
if(TRANS_SUCCEED != wait_checksum()) return NULL;
|
||||
uint8_t V[2];
|
||||
if(2 != read_string(V, 2)) return NULL;
|
||||
snprintf(buf, 256, "%c%d.%d", (V[0] &0x80)?'T':'V', V[0]&0x7f, V[1]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send command to shutter
|
||||
* @param cmd (i) - command (register-independent): o - open, c - close, k - de-energize
|
||||
* cmd may include 'k' with 'o' or 'c' (means "open/close and de-energize")
|
||||
* @return 1 in case of wrong command
|
||||
*/
|
||||
int shutter_command(char *cmd){
|
||||
if(!cmd) return 1;
|
||||
int deenerg = 0, openclose = 0, N = 0;
|
||||
while(*cmd){
|
||||
char c = *cmd++;
|
||||
if(N > 2) return 1; // too much commands
|
||||
if(c == 'o' || c == 'O'){
|
||||
++N; if(openclose) return 1; // already meet 'o' or 'c'
|
||||
openclose = 1; // open
|
||||
}else if(c == 'c' || c == 'C'){
|
||||
++N; if(openclose) return 1;
|
||||
openclose = -1; // close
|
||||
}else if(c == 'k' || c == 'K'){
|
||||
++N; deenerg = 1;
|
||||
}
|
||||
else if(c != '\'' && c != '"') return 1; // wrong symbol in command
|
||||
}
|
||||
if(openclose){
|
||||
if(TRANS_SUCCEED != send_cmd_cs(openclose > 0 ? CMD_SHUTTER_OPEN : CMD_SHUTTER_CLOSE))
|
||||
return 1;
|
||||
}
|
||||
if(deenerg){
|
||||
if(TRANS_SUCCEED != send_cmd_cs(CMD_SHUTTER_DEENERGIZE))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define subframe region
|
||||
* TODO: test this function. It doesnt work
|
||||
* @param parm (i) - parameters in format Xstart,Ystart,size
|
||||
* `parm` can be Xstart,Ystart for default size (127px)
|
||||
* @return structure allocated here (should be free'd outside)
|
||||
*/
|
||||
imsubframe *define_subframe(char *parm){
|
||||
if(!parm) return NULL;
|
||||
// default parameters
|
||||
uint16_t X = 0, Y = 0;
|
||||
uint8_t sz = 127;
|
||||
char *eptr;
|
||||
long int L = strtol(parm, &eptr, 10);
|
||||
DBG("L=%ld, parm=%s, eptr=%s",L,parm,eptr);
|
||||
if(eptr == parm || !*eptr || *eptr != ','){
|
||||
WARNX(_("Subframe parameter should have format Xstart,Ystart,size or Xstart,Ystart when size=127"));
|
||||
return NULL;
|
||||
}
|
||||
if(L > IMWIDTH - 1 || L < 1){
|
||||
WARNX(_("Xstart should be in range 0..%d"), IMWIDTH - 1 );
|
||||
return NULL;
|
||||
}
|
||||
parm = eptr + 1;
|
||||
X = (uint16_t)L;
|
||||
L = strtol(parm, &eptr, 10);
|
||||
if(eptr == parm){
|
||||
WARNX(_("Wrong Ystart format"));
|
||||
return NULL;
|
||||
}
|
||||
if(L > IMHEIGHT - 1 || L < 1){
|
||||
WARNX(_("Ystart should be in range 0..%d"), IMHEIGHT - 1 );
|
||||
return NULL;
|
||||
}
|
||||
Y = (uint16_t)L;
|
||||
if(*eptr){
|
||||
if(*eptr != ','){
|
||||
WARNX(_("Wrong size format"));
|
||||
return NULL;
|
||||
}
|
||||
parm = eptr + 1;
|
||||
L = strtol(parm, &eptr, 10);
|
||||
if(L > MAX_SUBFRAME_SZ || L < 1){
|
||||
WARNX(_("Subframe size could be in range 1..%d"), MAX_SUBFRAME_SZ);
|
||||
return NULL;
|
||||
}
|
||||
sz = (uint8_t)L;
|
||||
}
|
||||
if(X+sz > IMWIDTH){
|
||||
WARNX(_("Xstart+size should be less or equal %d"), IMWIDTH);
|
||||
return NULL;
|
||||
}
|
||||
if(Y+sz > IMHEIGHT){
|
||||
WARNX(_("Ystart+size should be less or equal %d"), IMHEIGHT);
|
||||
return NULL;
|
||||
}
|
||||
// now all OK, send command
|
||||
uint8_t cmd[6] = {CMD_DEFINE_SUBFRAME, 0};
|
||||
cmd[1] = (X>>8) & 0xff;
|
||||
cmd[2] = X & 0xff;
|
||||
cmd[3] = (Y>>8) & 0xff;
|
||||
cmd[4] = Y & 0xff;
|
||||
cmd[5] = sz;
|
||||
if(send_data(cmd, 6)){
|
||||
WARNX(_("Error sending command"));
|
||||
return NULL;
|
||||
}
|
||||
wait4answer(NULL, NULL);
|
||||
// ALL OK!
|
||||
imsubframe *F = MALLOC(imsubframe, 1);
|
||||
F->Xstart = X, F->Ystart = Y, F->size = sz;
|
||||
return F;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send command to start exposition
|
||||
* @param binning - binning to expose
|
||||
* @param exptime - exposition time
|
||||
* @param imtype - autodark, light or dark
|
||||
* @return 0 if all OK
|
||||
*/
|
||||
int start_exposition(imstorage *im, char *imtype){
|
||||
double exptime = im->exptime;
|
||||
uint64_t exp100us = exptime * 10000.;
|
||||
uint8_t cmd[6] = {CMD_TAKE_IMAGE};
|
||||
int binning = im->binning;
|
||||
image_type it = IMTYPE_AUTODARK;
|
||||
if(exptime < 5e-5){// 50us
|
||||
WARNX(_("Exposition time should be not less than 1us"));
|
||||
return 1;
|
||||
}
|
||||
DBG("exp: %lu", exp100us);
|
||||
cmd[1] = (exp100us >> 16) & 0xff;
|
||||
cmd[2] = (exp100us >> 8) & 0xff;
|
||||
cmd[3] = exp100us & 0xff;
|
||||
if(exp100us > MAX_EXPTIME_100){
|
||||
WARNX(_("Exposition time too large! Max value: %gs"), ((double)MAX_EXPTIME_100)/10000.);
|
||||
return 2;
|
||||
}
|
||||
const char *bngs[] = {"full", "cropped", "binned 2x2"};
|
||||
const char *b;
|
||||
if(binning != 0xff){ // check binning for non-subframe
|
||||
if(binning > 2 || binning < 0){
|
||||
WARNX(_("Bad binning size: %d, should be 0 (full), 1 (crop) or 2 (binned)"), binning);
|
||||
return 3;
|
||||
}
|
||||
b = bngs[binning];
|
||||
}else b = "subframe";
|
||||
cmd[4] = binning;
|
||||
// and now check image type
|
||||
if(!imtype) return 4;
|
||||
int L = strlen(imtype);
|
||||
if(!L){ WARNX(_("Empty image type")); return 4;}
|
||||
const char *m = "autodark";
|
||||
if(0 == strncasecmp(imtype, "autodark", L)){
|
||||
if(binning == 0){
|
||||
WARNX(_("Auto dark mode don't support full image"));
|
||||
return 5;
|
||||
}
|
||||
cmd[5] = 2;}
|
||||
else if(0 == strncasecmp(imtype, "dark", L)) { cmd[5] = 0; m = "dark"; it = IMTYPE_DARK; }
|
||||
else if(0 == strncasecmp(imtype, "light", L)){ cmd[5] = 1; m = "light"; it = IMTYPE_LIGHT;}
|
||||
else{
|
||||
WARNX(_("Wrong image type: %s, should be \"autodark\", \"light\" or \"dark\""), imtype);
|
||||
return 6;
|
||||
}
|
||||
if(shutter_command("ok")){ // open shutter
|
||||
WARNX(_("Can't open shutter"));
|
||||
return 8;
|
||||
}
|
||||
green("Start expose for %gseconds, mode \"%s\", %s image\n", exptime, m, b);
|
||||
if(send_data(cmd, 6)){
|
||||
WARNX(_("Error sending command"));
|
||||
return 7;
|
||||
}
|
||||
DBG("send: %c %u %u %u %u %u", cmd[0], cmd[1],cmd[2],cmd[3],cmd[4],cmd[5]);
|
||||
if(TRANS_SUCCEED != wait_checksum()){
|
||||
WARNX(_("Didn't get the respond"));
|
||||
return 8;
|
||||
}
|
||||
im->imtype = it;
|
||||
size_t W, H;
|
||||
switch(im->binning){ // set image size
|
||||
case 1: // cropped
|
||||
W = IM_CROPWIDTH;
|
||||
H = IMHEIGHT;
|
||||
break;
|
||||
case 2: // binned
|
||||
W = IMWIDTH / 2;
|
||||
H = IMHEIGHT / 2;
|
||||
break;
|
||||
case 0xff: // subframe
|
||||
W = H = im->subframe->size;
|
||||
break;
|
||||
case 0: // full image
|
||||
default:
|
||||
W = IMWIDTH;
|
||||
H = IMHEIGHT;
|
||||
}
|
||||
im->W = W; im->H = H;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait till image ready
|
||||
* @return 0 if all OK
|
||||
*/
|
||||
int wait4image(){
|
||||
uint8_t rd = 0;
|
||||
char indi[] = "|/-\\";
|
||||
char *iptr = indi;
|
||||
int stage = 1; // 1 - exp in progress, 2 - readout, 3 - done
|
||||
printf("\nExposure in progress ");
|
||||
fflush(stdout);
|
||||
while(rd != ANS_EXP_DONE){
|
||||
int L = 0;
|
||||
double d0 = dtime();
|
||||
do{
|
||||
if((L = read_tty(&rd, 1))) break;
|
||||
}while(dtime() - d0 < EXP_DONE_TMOUT);
|
||||
if(!L){
|
||||
printf("\n");
|
||||
WARNX(_("CCD not answer"));
|
||||
return 1;
|
||||
}
|
||||
int nxtstage = 1;
|
||||
if(rd != ANS_EXP_IN_PROGRESS){
|
||||
if(rd == ANS_RDOUT_IN_PROGRESS) nxtstage = 2;
|
||||
else nxtstage = 3;
|
||||
}
|
||||
if(nxtstage == stage){
|
||||
printf("\b%c", *iptr++); // rotating line
|
||||
fflush(stdout);
|
||||
if(!*iptr) iptr = indi;
|
||||
}else{
|
||||
stage = nxtstage;
|
||||
if(stage == 2){
|
||||
printf(_("\nReadout "));
|
||||
fflush(stdout);
|
||||
}else printf(_("\nDone!\n"));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect data by serial terminal
|
||||
* @param img - parameters of exposed image
|
||||
* @return array with image data (allocated here) or NULL
|
||||
*/
|
||||
uint16_t *get_image(imstorage *img){
|
||||
size_t L = img->W * img->H, rest = L * 2; // rest is datasize in bytes
|
||||
uint16_t *buff = MALLOC(uint16_t, L);
|
||||
if(TRANS_SUCCEED != send_cmd_cs(CMD_XFER_IMAGE)){
|
||||
WARNX(_("Error sending transfer command"));
|
||||
FREE(buff);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef EBUG
|
||||
double tstart = dtime();
|
||||
#endif
|
||||
DBG("rest = %zd", rest);
|
||||
uint8_t *getdataportion(uint8_t *start, size_t l){ // return last byte read + 1
|
||||
int i;
|
||||
uint8_t cs = 0;
|
||||
for(i = 0; i < 4; ++i){ // four tries to get datablock
|
||||
size_t r = 0, got = 0;
|
||||
uint8_t *ptr = start;
|
||||
double d0 = dtime();
|
||||
do{
|
||||
if((r = read_tty(ptr, l))){
|
||||
d0 = dtime();
|
||||
ptr += r;
|
||||
got += r;
|
||||
l -= r;
|
||||
}
|
||||
}while(l && dtime() - d0 < IMTRANS_TMOUT);
|
||||
DBG("got: %zd", got);
|
||||
if(got < 3){
|
||||
cs = IMTRANS_STOP;
|
||||
write_tty(&cs, 1);
|
||||
return NULL; // nothing to read
|
||||
}
|
||||
--ptr; // *ptr is checksum
|
||||
while(start < ptr) cs ^= *start++;
|
||||
DBG("got checksum: %x, calc: %x", *ptr, cs);
|
||||
if(*ptr == cs){ // all OK
|
||||
DBG("Checksum good");
|
||||
cs = IMTRANS_CONTINUE;
|
||||
write_tty(&cs, 1);
|
||||
return ptr;
|
||||
}else{ // bad checksum
|
||||
DBG("Ask to resend data");
|
||||
cs = IMTRANS_RESEND;
|
||||
write_tty(&cs, 1);
|
||||
}
|
||||
}
|
||||
DBG("not reached");
|
||||
cs = IMTRANS_STOP;
|
||||
write_tty(&cs, 1);
|
||||
return NULL;
|
||||
}
|
||||
uint8_t *bptr = (uint8_t*) buff;
|
||||
int i = 0;
|
||||
// size of single block: 4096 pix in full frame or 1x1bin mode, 1024 in binned mode, subfrmsize in subframe mode
|
||||
size_t dpsize = 4096*2 + 1;
|
||||
if(img->binning == 2) dpsize = 1024*2 + 1;
|
||||
else if(img->binning == 0xff) dpsize = 2*img->subframe->size + 1;
|
||||
do{
|
||||
size_t need = (rest > dpsize) ? dpsize : rest + 1;
|
||||
DBG("I want %zd bytes", need);
|
||||
uint8_t *ptr = getdataportion(bptr, need);
|
||||
if(!ptr){
|
||||
WARNX(_("Error receiving data"));
|
||||
FREE(buff);
|
||||
return NULL;
|
||||
}
|
||||
DBG("portion %d", ++i);
|
||||
rest -= need - 1;
|
||||
bptr = ptr;
|
||||
}while(rest);
|
||||
DBG("Got full data packet, capture time: %.1f seconds", dtime() - tstart);
|
||||
return buff;
|
||||
}
|
||||
|
||||
42
term.h
42
term.h
@ -21,12 +21,16 @@
|
||||
#pragma once
|
||||
#ifndef __TERM_H__
|
||||
#define __TERM_H__
|
||||
#include "imfunctions.h"
|
||||
|
||||
// communication errors
|
||||
typedef enum{
|
||||
TRANS_SUCCEED = 0, // no errors
|
||||
TRANS_ERROR, // some error occured
|
||||
TRANS_BADCHSUM, // wrong checksum
|
||||
TRANS_TIMEOUT // no data for 0.1s
|
||||
TRANS_TIMEOUT, // no data for 0.1s
|
||||
TRANS_TRYAGAIN, // checksum return 0x7f - maybe try again?
|
||||
TRANS_BUSY // image exposure in progress
|
||||
} trans_status;
|
||||
|
||||
// change heater
|
||||
@ -38,25 +42,57 @@ typedef enum{
|
||||
|
||||
// terminal timeout (seconds)
|
||||
#define WAIT_TMOUT (0.1)
|
||||
// timeout waitint 'D'
|
||||
#define EXP_DONE_TMOUT (5.0)
|
||||
// dataportion transfer timeout
|
||||
#define IMTRANS_TMOUT (1.0)
|
||||
// image size
|
||||
#define IMWIDTH (640)
|
||||
#define IM_CROPWIDTH (512)
|
||||
#define IMHEIGHT (480)
|
||||
#define MAX_SUBFRAME_SZ (127)
|
||||
// maximal expposition time in 100th of us
|
||||
#define MAX_EXPTIME_100 ((uint64_t)0x63ffff)
|
||||
/******************************** Commands definition ********************************/
|
||||
// communications test
|
||||
#define CMD_COMM_TEST 'E'
|
||||
#define CMD_HEATER 'g'
|
||||
#define CMD_CHANGE_BAUDRATE 'B'
|
||||
#define CMD_FIRMWARE_WERSION 'V'
|
||||
#define CMD_FIRMWARE_VERSION 'V'
|
||||
#define CMD_SHUTTER_OPEN 'O'
|
||||
#define CMD_SHUTTER_CLOSE 'C'
|
||||
#define CMD_SHUTTER_DEENERGIZE 'K'
|
||||
#define CMD_DEFINE_SUBFRAME 'S'
|
||||
#define CMD_TAKE_IMAGE 'T'
|
||||
#define CMD_ABORT_IMAGE 'A'
|
||||
#define CMD_XFER_IMAGE 'X'
|
||||
|
||||
/******************************** Image transfer ********************************/
|
||||
#define IMTRANS_CONTINUE 'K'
|
||||
#define IMTRANS_RESEND 'R'
|
||||
#define IMTRANS_STOP 'S'
|
||||
|
||||
/******************************** Answers definition ********************************/
|
||||
#define ANS_COMM_TEST 'O'
|
||||
#define ANS_CHANGE_BAUDRATE 'S'
|
||||
#define ANS_EXP_IN_PROGRESS 'E'
|
||||
#define ANS_RDOUT_IN_PROGRESS 'R'
|
||||
#define ANS_EXP_DONE 'D'
|
||||
|
||||
void run_terminal();
|
||||
void daemonize();
|
||||
int open_serial(char *dev);
|
||||
int get_curspeed();
|
||||
int try_connect(char *device);
|
||||
int try_connect(char *device, int speed);
|
||||
void heater(heater_cmd cmd);
|
||||
void list_speeds();
|
||||
void abort_image();
|
||||
int term_setspeed(int speed);
|
||||
char *get_firmvare_version();
|
||||
int shutter_command(char *cmd);
|
||||
imsubframe *define_subframe(char *parm);
|
||||
int start_exposition(imstorage *im, char *imtype);
|
||||
int wait4image();
|
||||
uint16_t *get_image(imstorage *img);
|
||||
|
||||
#endif // __TERM_H__
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user