take image works

This commit is contained in:
eddyem 2017-01-31 18:21:26 +03:00
parent 88b2cfcdbe
commit 06d0ad7082
10 changed files with 1750 additions and 104 deletions

View File

@ -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

View File

@ -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
};

View File

@ -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
View 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
View 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
View File

@ -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

View File

@ -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;
}
}

File diff suppressed because it is too large Load Diff

447
term.c
View File

@ -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
View File

@ -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__