fixed some bugs & made more

This commit is contained in:
Edward Emelianov 2021-07-20 16:52:17 +03:00
parent c55b407cf8
commit b32ca38018
12 changed files with 358 additions and 185 deletions

View File

@ -62,7 +62,7 @@ static void morph_init(){
* @return allocated memory area with converted input image * @return allocated memory area with converted input image
*/ */
uint8_t *filter4(uint8_t *image, int W, int H){ uint8_t *filter4(uint8_t *image, int W, int H){
FNAME(); //FNAME();
if(W < MINWIDTH || H < MINHEIGHT) return NULL; if(W < MINWIDTH || H < MINHEIGHT) return NULL;
uint8_t *ret = MALLOC(uint8_t, W*H); uint8_t *ret = MALLOC(uint8_t, W*H);
int W0 = (W + 7) / 8; // width in bytes int W0 = (W + 7) / 8; // width in bytes
@ -94,7 +94,7 @@ uint8_t *filter4(uint8_t *image, int W, int H){
* @return allocated memory area with converted input image * @return allocated memory area with converted input image
*/ */
uint8_t *filter8(uint8_t *image, int W, int H){ uint8_t *filter8(uint8_t *image, int W, int H){
FNAME(); //FNAME();
if(W < MINWIDTH || H < MINHEIGHT) return NULL; if(W < MINWIDTH || H < MINHEIGHT) return NULL;
uint8_t *ret = MALLOC(uint8_t, W*H); uint8_t *ret = MALLOC(uint8_t, W*H);
int W0 = (W + 7) / 8; // width in bytes int W0 = (W + 7) / 8; // width in bytes
@ -123,7 +123,7 @@ uint8_t *filter8(uint8_t *image, int W, int H){
* @return allocated memory area with dilation of input image * @return allocated memory area with dilation of input image
*/ */
uint8_t *dilation(uint8_t *image, int W, int H){ uint8_t *dilation(uint8_t *image, int W, int H){
FNAME(); //FNAME();
if(W < MINWIDTH || H < MINHEIGHT) return NULL; if(W < MINWIDTH || H < MINHEIGHT) return NULL;
int W0 = (W + 7) / 8; // width in bytes int W0 = (W + 7) / 8; // width in bytes
int w = W0-1, h = H-1, rest = 7 - (W - w*8); int w = W0-1, h = H-1, rest = 7 - (W - w*8);
@ -156,14 +156,14 @@ uint8_t *dilation(uint8_t *image, int W, int H){
* @return allocated memory area with erosion of input image * @return allocated memory area with erosion of input image
*/ */
uint8_t *erosion(uint8_t *image, int W, int H){ uint8_t *erosion(uint8_t *image, int W, int H){
FNAME(); //FNAME();
if(W < MINWIDTH || H < MINHEIGHT) return NULL; if(W < MINWIDTH || H < MINHEIGHT) return NULL;
if(!ER) morph_init(); if(!ER) morph_init();
int W0 = (W + 7) / 8; // width in bytes int W0 = (W + 7) / 8; // width in bytes
int w = W0-1, h = H-1, rest = 8 - (W - w*8); int w = W0-1, h = H-1, rest = 8 - (W - w*8);
uint8_t lastmask = ~(1<<rest); uint8_t lastmask = ~(1<<rest);
uint8_t *ret = MALLOC(uint8_t, W0*H); uint8_t *ret = MALLOC(uint8_t, W0*H);
DBG("rest=%d, mask:0x%x", rest, lastmask); //DBG("rest=%d, mask:0x%x", rest, lastmask);
OMP_FOR() OMP_FOR()
for(int y = 1; y < h; y++){ // reset first & last rows of image for(int y = 1; y < h; y++){ // reset first & last rows of image
uint8_t *iptr = &image[W0*y]; uint8_t *iptr = &image[W0*y];
@ -189,7 +189,7 @@ uint8_t *erosion(uint8_t *image, int W, int H){
// Make erosion N times // Make erosion N times
uint8_t *erosionN(uint8_t *image, int W, int H, int N){ uint8_t *erosionN(uint8_t *image, int W, int H, int N){
FNAME(); //FNAME();
if(W < 1 || H < 1) return NULL; if(W < 1 || H < 1) return NULL;
if(W < MINWIDTH || H < MINHEIGHT || N < 1){ if(W < MINWIDTH || H < MINHEIGHT || N < 1){
uint8_t *copy = MALLOC(uint8_t, W*H); uint8_t *copy = MALLOC(uint8_t, W*H);
@ -206,7 +206,7 @@ uint8_t *erosionN(uint8_t *image, int W, int H, int N){
} }
// Make dilation N times // Make dilation N times
uint8_t *dilationN(uint8_t *image, int W, int H, int N){ uint8_t *dilationN(uint8_t *image, int W, int H, int N){
FNAME(); //FNAME();
if(W < 1 || H < 1) return NULL; if(W < 1 || H < 1) return NULL;
if(W < MINWIDTH || H < MINHEIGHT || N < 1){ if(W < MINWIDTH || H < MINHEIGHT || N < 1){
uint8_t *copy = MALLOC(uint8_t, W*H); uint8_t *copy = MALLOC(uint8_t, W*H);
@ -224,7 +224,7 @@ uint8_t *dilationN(uint8_t *image, int W, int H, int N){
// Ntimes opening // Ntimes opening
uint8_t *openingN(uint8_t *image, int W, int H, int N){ uint8_t *openingN(uint8_t *image, int W, int H, int N){
FNAME(); //FNAME();
if(W < MINWIDTH || H < MINHEIGHT || N < 1) return NULL; if(W < MINWIDTH || H < MINHEIGHT || N < 1) return NULL;
uint8_t *er = erosionN(image, W, H, N); uint8_t *er = erosionN(image, W, H, N);
uint8_t *op = dilationN(er, W, H, N); uint8_t *op = dilationN(er, W, H, N);
@ -234,7 +234,7 @@ uint8_t *openingN(uint8_t *image, int W, int H, int N){
// Ntimes closing // Ntimes closing
uint8_t *closingN(uint8_t *image, int W, int H, int N){ uint8_t *closingN(uint8_t *image, int W, int H, int N){
FNAME(); //FNAME();
if(W < MINWIDTH || H < MINHEIGHT || N < 1) return NULL; if(W < MINWIDTH || H < MINHEIGHT || N < 1) return NULL;
uint8_t *di = dilationN(image, W, H, N); uint8_t *di = dilationN(image, W, H, N);
uint8_t *cl = erosionN(di, W, H, N); uint8_t *cl = erosionN(di, W, H, N);
@ -244,7 +244,7 @@ uint8_t *closingN(uint8_t *image, int W, int H, int N){
// top hat operation: image - opening(image) // top hat operation: image - opening(image)
uint8_t *topHat(uint8_t *image, int W, int H, int N){ uint8_t *topHat(uint8_t *image, int W, int H, int N){
FNAME(); //FNAME();
if(W < MINWIDTH || H < MINHEIGHT || N < 1) return NULL; if(W < MINWIDTH || H < MINHEIGHT || N < 1) return NULL;
uint8_t *op = openingN(image, W, H, N); uint8_t *op = openingN(image, W, H, N);
int W0 = (W + 7) / 8; // width in bytes int W0 = (W + 7) / 8; // width in bytes
@ -257,7 +257,7 @@ uint8_t *topHat(uint8_t *image, int W, int H, int N){
// bottom hat operation: closing(image) - image // bottom hat operation: closing(image) - image
uint8_t *botHat(uint8_t *image, int W, int H, int N){ uint8_t *botHat(uint8_t *image, int W, int H, int N){
FNAME(); //FNAME();
if(W < MINWIDTH || H < MINHEIGHT || N < 1) return NULL; if(W < MINWIDTH || H < MINHEIGHT || N < 1) return NULL;
uint8_t *op = closingN(image, W, H, N); uint8_t *op = closingN(image, W, H, N);
int W0 = (W + 7) / 8; // width in bytes int W0 = (W + 7) / 8; // width in bytes
@ -358,10 +358,10 @@ size_t *cclabel4(uint8_t *Img, int W, int H, ConnComps **CC){
} }
if(W < MINWIDTH || H < MINHEIGHT) return NULL; if(W < MINWIDTH || H < MINHEIGHT) return NULL;
uint8_t *f = filter4(Img, W, H); // remove all non 4-connected pixels uint8_t *f = filter4(Img, W, H); // remove all non 4-connected pixels
DBG("convert to size_t"); //DBG("convert to size_t");
size_t *labels = bin2ST(f, W, H); size_t *labels = bin2ST(f, W, H);
FREE(f); FREE(f);
DBG("Calculate"); //DBG("Calculate");
size_t Nmax = W*H/4; // max number of 4-connected labels size_t Nmax = W*H/4; // max number of 4-connected labels
assoc = MALLOC(size_t, Nmax); // allocate memory for "remark" array assoc = MALLOC(size_t, Nmax); // allocate memory for "remark" array
size_t last_assoc_idx = 1; // last index filled in assoc array size_t last_assoc_idx = 1; // last index filled in assoc array
@ -416,7 +416,7 @@ size_t *cclabel4(uint8_t *Img, int W, int H, ConnComps **CC){
indexes[i] = cidx++; indexes[i] = cidx++;
} }
// cidx now is amount of detected objects + 1 - size of output array (0th idx is not used) // cidx now is amount of detected objects + 1 - size of output array (0th idx is not used)
DBG("amount after rebuild: %zd", cidx-1); //DBG("amount after rebuild: %zd", cidx-1);
#ifdef TESTMSGS #ifdef TESTMSGS
printf("\n\n\nI\tASS[I]\tIDX[I]\n"); printf("\n\n\nI\tASS[I]\tIDX[I]\n");
for(size_t i = 1; i < last_assoc_idx; ++i) for(size_t i = 1; i < last_assoc_idx; ++i)

View File

@ -48,8 +48,9 @@ configuration theconf = {
.xtarget=-1, .xtarget=-1,
.ytarget=-1, .ytarget=-1,
.throwpart=DEFAULT_THROWPART, .throwpart=DEFAULT_THROWPART,
.maxexp=EXPOS_MAX - DBL_EPSILON, .maxexp=EXPOS_MAX + DBL_EPSILON,
.minexp=EXPOS_MIN + DBL_EPSILON, .minexp=EXPOS_MIN - DBL_EPSILON,
.fixedexp=EXPOS_MIN,
.intensthres=DEFAULT_INTENSTHRES .intensthres=DEFAULT_INTENSTHRES
}; };
@ -73,6 +74,8 @@ static confparam parvals[] = {
"subimage height"}, "subimage height"},
{"equalize", PAR_INT, (void*)&theconf.equalize, 0, -DBL_EPSILON, 1.+DBL_EPSILON, {"equalize", PAR_INT, (void*)&theconf.equalize, 0, -DBL_EPSILON, 1.+DBL_EPSILON,
"make histogram equalization"}, "make histogram equalization"},
{"expmethod", PAR_INT, (void*)&theconf.expmethod, 0, -DBL_EPSILON, 1.+DBL_EPSILON,
"exposition method: 0 - auto, 1 - fixed"},
{"naverage", PAR_INT, (void*)&theconf.naverage, 0, 1-DBL_EPSILON, NAVER_MAX+DBL_EPSILON, {"naverage", PAR_INT, (void*)&theconf.naverage, 0, 1-DBL_EPSILON, NAVER_MAX+DBL_EPSILON,
"calculate mean position by N images"}, "calculate mean position by N images"},
{"umax", PAR_INT, (void*)&theconf.maxUsteps, 0, MINSTEPS-DBL_EPSILON, MAXSTEPS+DBL_EPSILON, {"umax", PAR_INT, (void*)&theconf.maxUsteps, 0, MINSTEPS-DBL_EPSILON, MAXSTEPS+DBL_EPSILON,
@ -99,8 +102,12 @@ static confparam parvals[] = {
"minimal exposition time"}, "minimal exposition time"},
{"maxexp", PAR_DOUBLE, (void*)&theconf.maxexp, 0, -DBL_EPSILON, EXPOS_MAX+DBL_EPSILON, {"maxexp", PAR_DOUBLE, (void*)&theconf.maxexp, 0, -DBL_EPSILON, EXPOS_MAX+DBL_EPSILON,
"maximal exposition time"}, "maximal exposition time"},
{"fixedexp", PAR_DOUBLE, (void*)&theconf.fixedexp, 0, EXPOS_MIN-DBL_EPSILON, EXPOS_MAX+DBL_EPSILON,
"fixed (in manual mode) exposition time"},
{"intensthres", PAR_DOUBLE, (void*)&theconf.intensthres, 0, DBL_EPSILON, 1.+DBL_EPSILON, {"intensthres", PAR_DOUBLE, (void*)&theconf.intensthres, 0, DBL_EPSILON, 1.+DBL_EPSILON,
"threshold by total object intensity when sorting = |I1-I2|/(I1+I2)"}, "threshold by total object intensity when sorting = |I1-I2|/(I1+I2)"},
{"gain", PAR_DOUBLE, (void*)&theconf.gain, 0, GAIN_MIN-DBL_EPSILON, GAIN_MAX+DBL_EPSILON,
"gain value in manual mode"},
{"starssort", PAR_INT, (void*)&theconf.starssort, 0, -DBL_EPSILON, 1.+DBL_EPSILON, {"starssort", PAR_INT, (void*)&theconf.starssort, 0, -DBL_EPSILON, 1.+DBL_EPSILON,
"stars sorting algorithm: by distance from target (0) or by intensity (1)"}, "stars sorting algorithm: by distance from target (0) or by intensity (1)"},
{NULL, 0, NULL, 0, 0., 0., NULL} {NULL, 0, NULL, 0, 0., 0., NULL}
@ -363,17 +370,19 @@ int saveconf(const char *confname){
} }
// return buffer filled with current configuration // return buffer filled with current configuration
char *listconf(char *buf, int buflen){ char *listconf(const char *messageid, char *buf, int buflen){
int L; int L;
char *ptr = buf; char *ptr = buf;
confparam *par = parvals; confparam *par = parvals;
L = snprintf(ptr, buflen, "{ \"%s\": \"%s\", ", MESSAGEID, messageid);
buflen -= L; ptr += L;
while(par->name && buflen > 0){ while(par->name && buflen > 0){
switch(par->type){ switch(par->type){
case PAR_INT: case PAR_INT:
L = snprintf(ptr, buflen, "%s=%d\n", par->name, *((int*)par->ptr)); L = snprintf(ptr, buflen, "\"%s\": %d", par->name, *((int*)par->ptr));
break; break;
case PAR_DOUBLE: case PAR_DOUBLE:
L = snprintf(ptr, buflen, "%s=%.3f\n", par->name, *((double*)par->ptr)); L = snprintf(ptr, buflen, "\"%s\": %.3f", par->name, *((double*)par->ptr));
break; break;
default: default:
L = 0; L = 0;
@ -384,6 +393,11 @@ char *listconf(char *buf, int buflen){
}else{ }else{
buf[buflen-1] = 0; break; buf[buflen-1] = 0; break;
} }
if(par->name){ // put comma
L = snprintf(ptr, buflen, ", ");
if(L > -1){buflen -= L; ptr += L;}
} }
}
snprintf(ptr, buflen, " }\n");
return buf; return buf;
} }

View File

@ -28,13 +28,17 @@
#define COEFMAX (10000) #define COEFMAX (10000)
// area // area
#define MINAREA (4) #define MINAREA (4)
#define MAXAREA (250000) #define MAXAREA (2500000)
#define MAX_NDILAT (100) #define MAX_NDILAT (100)
#define MAX_NEROS (100) #define MAX_NEROS (100)
#define MAX_THROWPART (0.9) #define MAX_THROWPART (0.9)
#define MAX_OFFSET (10000) #define MAX_OFFSET (10000)
#define EXPOS_MIN (0.001) // min/max exposition in ms
#define EXPOS_MAX (500.) #define EXPOS_MIN (0.1)
#define EXPOS_MAX (4000.)
#define GAIN_MIN (0.)
#define GAIN_MAX (20.)
// max average images counter
#define NAVER_MAX (50) #define NAVER_MAX (50)
// coefficients to convert dx,dy to du,dv // coefficients to convert dx,dy to du,dv
#define KUVMIN (-5000.) #define KUVMIN (-5000.)
@ -42,6 +46,13 @@
// default coefficient for corrections (move to Kdu, Kdv instead of du, dv) // default coefficient for corrections (move to Kdu, Kdv instead of du, dv)
#define KCORR (0.9) #define KCORR (0.9)
// exposition methods: 0 - auto, 1 - fixed
#define EXPAUTO (0)
#define EXPMANUAL (1)
// messageID field name
#define MESSAGEID "messageid"
typedef struct{ typedef struct{
int maxUsteps; // max amount of steps by both axes int maxUsteps; // max amount of steps by both axes
int maxVsteps; int maxVsteps;
@ -57,14 +68,17 @@ typedef struct{
int naverage; // amount of images for average calculation (>1) int naverage; // amount of images for average calculation (>1)
int stpserverport; // steppers' server port int stpserverport; // steppers' server port
int starssort; // stars sorting algorithm: by distance from target (0) or by intensity (1) int starssort; // stars sorting algorithm: by distance from target (0) or by intensity (1)
int expmethod; // 0 - auto, 1 - fixed
// dU = Kxu*dX + Kyu*dY; dV = Kxv*dX + Kyv*dY // dU = Kxu*dX + Kyu*dY; dV = Kxv*dX + Kyv*dY
double Kxu; double Kyu; double Kxu; double Kyu;
double Kxv; double Kyv; double Kxv; double Kyv;
double xtarget; // target (center) values double xtarget; // target (center) values (in absolute coordinates! screen coords = target - offset)
double ytarget; double ytarget;
double throwpart; // part of values to throw avay @ histogram equalisation double throwpart; // part of values to throw avay @ histogram equalisation
double maxexp; // minimal and maximal exposition (in ms) double maxexp; // minimal and maximal exposition (in ms)
double minexp; double minexp;
double fixedexp; // exptime in manual mode
double gain; // gain value in manual mode
double intensthres; // threshold for stars intensity comparison: fabs(Ia-Ib)/(Ia+Ib) > thres -> stars differs double intensthres; // threshold for stars intensity comparison: fabs(Ia-Ib)/(Ia+Ib) > thres -> stars differs
} configuration; } configuration;
@ -99,6 +113,6 @@ int chkconfig(const char *confname);
int saveconf(const char *confname); int saveconf(const char *confname);
char *get_keyval(const char *pair, char value[128]); char *get_keyval(const char *pair, char value[128]);
confparam *chk_keyval(const char *key, const char *val, key_value *result); confparam *chk_keyval(const char *key, const char *val, key_value *result);
char *listconf(char *buf, int buflen); char *listconf(const char *messageid, char *buf, int buflen);
#endif // CONFIG_H__ #endif // CONFIG_H__

View File

@ -21,6 +21,7 @@
#include <float.h> // FLT_EPSILON #include <float.h> // FLT_EPSILON
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <usefull_macros.h> #include <usefull_macros.h>
#include "cmdlnopts.h" #include "cmdlnopts.h"
@ -33,7 +34,6 @@
static fc2Context context; static fc2Context context;
static fc2PGRGuid guid; static fc2PGRGuid guid;
static fc2Error err = FC2_ERROR_OK; static fc2Error err = FC2_ERROR_OK;
static float exptime = 10.; // exposition time in milliseconds
static float gain = 0.; static float gain = 0.;
#define FC2FN(fn, ...) do{err = FC2_ERROR_OK; if(FC2_ERROR_OK != (err=fn(context __VA_OPT__(,) __VA_ARGS__))){ \ #define FC2FN(fn, ...) do{err = FC2_ERROR_OK; if(FC2_ERROR_OK != (err=fn(context __VA_OPT__(,) __VA_ARGS__))){ \
@ -42,7 +42,6 @@ static float gain = 0.;
/** /**
* @brief setfloat - set absolute property value (float) * @brief setfloat - set absolute property value (float)
* @param t - type of property * @param t - type of property
* @param context - initialized context
* @param f - new value * @param f - new value
* @return 1 if all OK * @return 1 if all OK
*/ */
@ -155,8 +154,8 @@ static int changeformat(){
} }
static int connect(){ static int connect(){
FNAME();
if(connected) return 1; if(connected) return 1;
FNAME();
unsigned int numCameras = 0; unsigned int numCameras = 0;
if(FC2_ERROR_OK != (err = fc2CreateContext(&context))){ if(FC2_ERROR_OK != (err = fc2CreateContext(&context))){
WARNX("fc2CreateContext(): %s", fc2ErrorToDescription(err)); WARNX("fc2CreateContext(): %s", fc2ErrorToDescription(err));
@ -188,29 +187,32 @@ static int connect(){
static int GrabImage(fc2Image *convertedImage){ static int GrabImage(fc2Image *convertedImage){
FNAME(); FNAME();
int ret = 0;
fc2Image rawImage; fc2Image rawImage;
// start capture // start capture
FC2FN(fc2StartCapture); FC2FN(fc2StartCapture);
err = fc2CreateImage(&rawImage); err = fc2CreateImage(&rawImage);
if(err != FC2_ERROR_OK){ if(err != FC2_ERROR_OK){
WARNX("Error in fc2CreateImage: %s", fc2ErrorToDescription(err)); WARNX("Error in fc2CreateImage: %s", fc2ErrorToDescription(err));
return 0; goto rtn;
} }
// Retrieve the image // Retrieve the image
err = fc2RetrieveBuffer(context, &rawImage); err = fc2RetrieveBuffer(context, &rawImage);
if(err != FC2_ERROR_OK){ if(err != FC2_ERROR_OK){
WARNX("Error in fc2RetrieveBuffer: %s", fc2ErrorToDescription(err)); WARNX("Error in fc2RetrieveBuffer: %s", fc2ErrorToDescription(err));
return 0; goto rtn;
} }
// Convert image to gray // Convert image to gray
err = fc2ConvertImageTo(FC2_PIXEL_FORMAT_MONO8, &rawImage, convertedImage); err = fc2ConvertImageTo(FC2_PIXEL_FORMAT_MONO8, &rawImage, convertedImage);
if(err != FC2_ERROR_OK){ if(err != FC2_ERROR_OK){
WARNX("Error in fc2ConvertImageTo: %s", fc2ErrorToDescription(err)); WARNX("Error in fc2ConvertImageTo: %s", fc2ErrorToDescription(err));
return 0; goto rtn;
} }
ret = 1;
rtn:
fc2StopCapture(context); fc2StopCapture(context);
fc2DestroyImage(&rawImage); fc2DestroyImage(&rawImage);
return 1; return ret;
} }
static void calcexpgain(float newexp){ static void calcexpgain(float newexp){
@ -241,6 +243,15 @@ static void calcexpgain(float newexp){
//convertedImage.pData, convertedImage.cols, convertedImage.rows, convertedImage.stride //convertedImage.pData, convertedImage.cols, convertedImage.rows, convertedImage.stride
static void recalcexp(fc2Image *img){ static void recalcexp(fc2Image *img){
// check if user changed exposition values
if(exptime < theconf.minexp){
exptime = theconf.minexp;
return;
}
else if(exptime > theconf.maxexp){
exptime = theconf.maxexp;
return;
}
uint8_t *data = img->pData; uint8_t *data = img->pData;
int W = img->cols, H = img->rows, S = img->stride; int W = img->cols, H = img->rows, S = img->stride;
int histogram[256] = {0}; int histogram[256] = {0};
@ -271,15 +282,19 @@ int capture_grasshopper(void (*process)(Image*)){
FNAME(); FNAME();
static float oldexptime = 0.; static float oldexptime = 0.;
static float oldgain = -1.; static float oldgain = -1.;
Image *oIma = NULL;
fc2Image convertedImage; fc2Image convertedImage;
err = fc2CreateImage(&convertedImage); err = fc2CreateImage(&convertedImage);
if(err != FC2_ERROR_OK){ if(err != FC2_ERROR_OK){
WARNX("capture_grasshopper(): can't create image, %s", fc2ErrorToDescription(err)); WARNX("capture_grasshopper(): can't create image, %s", fc2ErrorToDescription(err));
disconnectGrasshopper();
return 0; return 0;
} }
Image *oIma = NULL;
while(1){ while(1){
if(stopwork) return 1; if(stopwork){
DBG("STOP");
break;
}
if(!connect()){ // wait until camera be powered on if(!connect()){ // wait until camera be powered on
DBG("Disconnected"); DBG("Disconnected");
sleep(1); sleep(1);
@ -291,8 +306,8 @@ int capture_grasshopper(void (*process)(Image*)){
oldexptime = exptime; oldexptime = exptime;
}else{ }else{
WARNX("Can't change exposition time to %gms", exptime); WARNX("Can't change exposition time to %gms", exptime);
disconnectGrasshopper(); //disconnectGrasshopper();
continue; //continue;
} }
} }
if(fabs(oldgain - gain) > FLT_EPSILON){ // change gain if(fabs(oldgain - gain) > FLT_EPSILON){ // change gain
@ -301,8 +316,8 @@ int capture_grasshopper(void (*process)(Image*)){
oldgain = gain; oldgain = gain;
}else{ }else{
WARNX("Can't change gain to %g", gain); WARNX("Can't change gain to %g", gain);
disconnectGrasshopper(); //disconnectGrasshopper();
continue; //continue;
} }
} }
if(!GrabImage(&convertedImage)){ if(!GrabImage(&convertedImage)){
@ -310,15 +325,42 @@ int capture_grasshopper(void (*process)(Image*)){
disconnectGrasshopper(); disconnectGrasshopper();
continue; continue;
} }
if(!process) continue; if(theconf.expmethod == EXPAUTO) recalcexp(&convertedImage);
recalcexp(&convertedImage); else{
if(fabs(theconf.fixedexp - exptime) > FLT_EPSILON)
exptime = theconf.fixedexp;
if(fabs(theconf.gain - gain) > FLT_EPSILON)
gain = theconf.gain;
}
if(!process){
continue;
}
oIma = u8toImage(convertedImage.pData, convertedImage.cols, convertedImage.rows, convertedImage.stride); oIma = u8toImage(convertedImage.pData, convertedImage.cols, convertedImage.rows, convertedImage.stride);
if(oIma){ if(oIma){
process(oIma); process(oIma);
FREE(oIma->data);
FREE(oIma); FREE(oIma);
} }
} }
fc2DestroyImage(&convertedImage); fc2DestroyImage(&convertedImage);
fc2DestroyContext(context); disconnectGrasshopper();
DBG("GRASSHOPPER: out");
return 1; return 1;
} }
// return JSON with image status
char *gsimagestatus(const char *messageid, char *buf, int buflen){
static char *impath = NULL;
if(!impath){
if(!(impath = realpath(GP->outputjpg, impath))){
WARN("realpath() (%s)", impath);
impath = strdup(GP->outputjpg);
}
DBG("path: %s", impath);
}
snprintf(buf, buflen, "{ \"%s\": \"%s\", \"camstatus\": \"%sconnected\", \"impath\": \"%s\", \"imctr\": %llu, "
"\"fps\": %.3f, \"expmethod\": \"%s\", \"exposition\": %g, \"gain\": %g }\n",
MESSAGEID, messageid, connected ? "" : "dis", impath, ImNumber, getFramesPerS(),
(theconf.expmethod == EXPAUTO) ? "auto" : "manual", exptime, gain);
return buf;
}

View File

@ -25,5 +25,6 @@
void disconnectGrasshopper(); void disconnectGrasshopper();
int capture_grasshopper(void (*process)(Image *)); int capture_grasshopper(void (*process)(Image *));
char *gsimagestatus(const char *messageid, char *buf, int buflen);
#endif // GRASSHOPPER_H__ #endif // GRASSHOPPER_H__

View File

@ -34,11 +34,6 @@
#include "imagefile.h" #include "imagefile.h"
#include "median.h" #include "median.h"
// weights to convert colour image into gray (sum=1!)
#define WEIGHT_RED ()
#define WEIGHT_GREEN ()
#define WEIGHT_BLUE ()
typedef struct{ typedef struct{
const char signature[8]; const char signature[8];
uint8_t len; uint8_t len;
@ -224,7 +219,7 @@ uint8_t *linear(const Image *I, int nchannels){ // only 1 and 3 channels support
size_t stride = width*nchannels, S = height*stride; size_t stride = width*nchannels, S = height*stride;
uint8_t *outp = MALLOC(uint8_t, S); uint8_t *outp = MALLOC(uint8_t, S);
Imtype min = I->minval, max = I->maxval, W = 255./(max - min); Imtype min = I->minval, max = I->maxval, W = 255./(max - min);
DBG("make linear transform %dx%d, %d channels", I->width, I->height, nchannels); //DBG("make linear transform %dx%d, %d channels", I->width, I->height, nchannels);
if(nchannels == 3){ if(nchannels == 3){
OMP_FOR() OMP_FOR()
for(int y = 0; y < height; ++y){ for(int y = 0; y < height; ++y){
@ -340,7 +335,6 @@ int Image_write_jpg(const Image *I, const char *name, int eq){
DBG("Try to write %s", name); DBG("Try to write %s", name);
char *tmpnm = MALLOC(char, strlen(name) + 5); char *tmpnm = MALLOC(char, strlen(name) + 5);
sprintf(tmpnm, "%s-tmp", name); sprintf(tmpnm, "%s-tmp", name);
// char *tmpnm = tmpnam_r(buf);
int r = stbi_write_jpg(tmpnm, I->width, I->height, 1, outp, 95); int r = stbi_write_jpg(tmpnm, I->width, I->height, 1, outp, 95);
if(r){ if(r){
if(rename(tmpnm, name)){ if(rename(tmpnm, name)){
@ -361,22 +355,6 @@ void Image_minmax(Image *I){
#ifdef EBUG #ifdef EBUG
double t0 = dtime(); double t0 = dtime();
#endif #endif
/*
int N = omp_get_max_threads();
Imtype arrmin[N], arrmax[N];
for(int i = 0; i < N; ++i){
arrmin[i] = min; arrmax[i] = max;
}
OMP_FOR()
for(int i = 0; i < wh; ++i){
if(I->data[i] < arrmin[omp_get_thread_num()]) arrmin[omp_get_thread_num()] = I->data[i];
else if(I->data[i] > arrmax[omp_get_thread_num()]) arrmax[omp_get_thread_num()] = I->data[i];
}
for(int i = 0; i < N; ++i){
if(min > arrmin[i]) min = arrmin[i];
if(max < arrmax[i]) max = arrmax[i];
}*/
#pragma omp parallel shared(min, max) #pragma omp parallel shared(min, max)
{ {
int min_p = min, max_p = min; int min_p = min, max_p = min;

View File

@ -34,19 +34,27 @@
#include "median.h" #include "median.h"
#include "pusirobo.h" #include "pusirobo.h"
static FILE *fXYlog = NULL; float exptime = 10.; // GLOBAL: exposition time in milliseconds
volatile atomic_ullong ImNumber = 0; // GLOBAL: counter of processed images
volatile atomic_bool stopwork = FALSE; // GLOBAL: suicide
//int autoExposition = 1; // GLOBAL: ==1 if exposition calculation is auto
// GLOBAL: function to get stepper server status
char *(*stepstatus)(const char *messageid, char *buf, int buflen) = NULL;
// GLOBAL: set new status
char *(*setstepstatus)(const char *newstatus, char *buf, int buflen) = NULL;
// GLOBAL: move focus
char *(*movefocus)(const char *newstatus, char *buf, int buflen) = NULL;
// GLOBAL: get image information
char *(*imagedata)(const char *messageid, char *buf, int buflen);
static FILE *fXYlog = NULL;
static double tstart = 0.; // time of logging start static double tstart = 0.; // time of logging start
int stopwork = 0; static double FPS = 0.; // frames per second
// function to process calculated corrections // function to process calculated corrections
static void (*proc_corr)(double, double, int) = NULL; static void (*proc_corr)(double, double, int) = NULL;
// function to get stepper server status
char *(*stepstatus)(char *buf, int buflen) = NULL;
// set new status
char *(*setstepstatus)(const char *newstatus, char *buf, int buflen) = NULL;
// move focus
char *(*movefocus)(const char *newstatus, char *buf, int buflen) = NULL;
typedef struct{ typedef struct{
uint32_t area; // object area in pixels uint32_t area; // object area in pixels
@ -65,6 +73,7 @@ typedef enum{
static postproc_type postprocess = PROCESS_NONE; static postproc_type postprocess = PROCESS_NONE;
/*
static bool save_fits(Image *I, const char *name){ static bool save_fits(Image *I, const char *name){
char fname[PATH_MAX]; char fname[PATH_MAX];
snprintf(fname, PATH_MAX, name); snprintf(fname, PATH_MAX, name);
@ -75,14 +84,15 @@ static bool save_fits(Image *I, const char *name){
unlink(name); unlink(name);
return FITS_write(name, I); return FITS_write(name, I);
} }
*/
/*
static void savebin(uint8_t *b, int W, int H, const char *name){ static void savebin(uint8_t *b, int W, int H, const char *name){
Image *I = bin2Im(b, W, H); Image *I = bin2Im(b, W, H);
if(I){ if(I){
save_fits(I, name); save_fits(I, name);
Image_free(&I); Image_free(&I);
} }
} }*/
// functions for Qsort // functions for Qsort
static int compIntens(const void *a, const void *b){ // compare by intensity static int compIntens(const void *a, const void *b){ // compare by intensity
@ -97,8 +107,9 @@ static int compIntens(const void *a, const void *b){ // compare by intensity
static int compDist(const void *a, const void *b){ // compare by distanse from target static int compDist(const void *a, const void *b){ // compare by distanse from target
const object *oa = (const object*)a; const object *oa = (const object*)a;
const object *ob = (const object*)b; const object *ob = (const object*)b;
double xa = oa->xc - theconf.xtarget, xb = ob->xc - theconf.xtarget, double xtg = theconf.xtarget - theconf.xoff, ytg = theconf.ytarget - theconf.yoff;
ya = oa->yc - theconf.ytarget, yb = ob->yc - theconf.ytarget; double xa = oa->xc - xtg, xb = ob->xc - xtg,
ya = oa->yc - ytg, yb = ob->yc - ytg;
double r2a = xa*xa + ya*ya; double r2a = xa*xa + ya*ya;
double r2b = xb*xb + yb*yb; double r2b = xb*xb + yb*yb;
return (r2a < r2b) ? -1 : 1; return (r2a < r2b) ? -1 : 1;
@ -122,7 +133,7 @@ static void getDeviation(object *curobj){
dtime() - tstart, curobj->xc, curobj->yc, dtime() - tstart, curobj->xc, curobj->yc,
curobj->xsigma, curobj->ysigma, curobj->WdivH); curobj->xsigma, curobj->ysigma, curobj->WdivH);
} }
DBG("counter = %d", counter); //DBG("counter = %d", counter);
if(++counter != theconf.naverage){ if(++counter != theconf.naverage){
goto process_corrections; goto process_corrections;
} }
@ -142,7 +153,7 @@ static void getDeviation(object *curobj){
if(fXYlog) fprintf(fXYlog, "%.1f\t%.1f\t%.1f\t%.1f", xx, yy, Sx, Sy); if(fXYlog) fprintf(fXYlog, "%.1f\t%.1f\t%.1f\t%.1f", xx, yy, Sx, Sy);
process_corrections: process_corrections:
if(proc_corr){ if(proc_corr){
if(Sx > 1. || Sy > 1.){ if(Sx > XY_TOLERANCE || Sy > XY_TOLERANCE){
LOGDBG("Bad value - not process"); // don't run processing for bad data LOGDBG("Bad value - not process"); // don't run processing for bad data
}else }else
proc_corr(xx, yy, averflag); proc_corr(xx, yy, averflag);
@ -151,12 +162,15 @@ process_corrections:
} }
void process_file(Image *I){ void process_file(Image *I){
static double lastTproc = 0.;
/*
#ifdef EBUG #ifdef EBUG
double t0 = dtime(), tlast = t0; double t0 = dtime(), tlast = t0;
#define DELTA(p) do{double t = dtime(); DBG("---> %s @ %gms (delta: %gms)", p, (t-t0)*1e3, (t-tlast)*1e3); tlast = t;}while(0) #define DELTA(p) do{double t = dtime(); DBG("---> %s @ %gms (delta: %gms)", p, (t-t0)*1e3, (t-tlast)*1e3); tlast = t;}while(0)
#else #else
*/
#define DELTA(x) #define DELTA(x)
#endif //#endif
// I - original image // I - original image
// mean - local mean // mean - local mean
// std - local STD // std - local STD
@ -168,28 +182,28 @@ void process_file(Image *I){
} }
int W = I->width, H = I->height; int W = I->width, H = I->height;
if(!I->dtype) I->dtype = FLOAT_IMG; if(!I->dtype) I->dtype = FLOAT_IMG;
save_fits(I, "fitsout.fits"); //save_fits(I, "fitsout.fits");
DELTA("Save original"); //DELTA("Save original");
Imtype bk; Imtype bk;
if(calc_background(I, &bk)){ if(calc_background(I, &bk)){
DBG("backgr = %g", bk); //DBG("backgr = %g", bk);
DELTA("Got background"); DELTA("Got background");
uint8_t *ibin = Im2bin(I, bk); uint8_t *ibin = Im2bin(I, bk);
DELTA("Made binary"); DELTA("Made binary");
if(ibin){ if(ibin){
savebin(ibin, W, H, "binary.fits"); //savebin(ibin, W, H, "binary.fits");
DELTA("save binary.fits"); //DELTA("save binary.fits");
uint8_t *er = erosionN(ibin, W, H, theconf.Nerosions); uint8_t *er = erosionN(ibin, W, H, theconf.Nerosions);
FREE(ibin); FREE(ibin);
DELTA("Erosion"); DELTA("Erosion");
savebin(er, W, H, "erosion.fits"); //savebin(er, W, H, "erosion.fits");
DELTA("Save erosion"); //DELTA("Save erosion");
uint8_t *opn = dilationN(er, W, H, theconf.Ndilations); uint8_t *opn = dilationN(er, W, H, theconf.Ndilations);
FREE(er); FREE(er);
DELTA("Opening"); DELTA("Opening");
savebin(opn, W, H, "opening.fits"); //savebin(opn, W, H, "opening.fits");
DELTA("Save opening"); //DELTA("Save opening");
ConnComps *cc; ConnComps *cc = NULL;
size_t *S = cclabel4(opn, W, H, &cc); size_t *S = cclabel4(opn, W, H, &cc);
FREE(opn); FREE(opn);
if(cc->Nobj > 1){ if(cc->Nobj > 1){
@ -245,8 +259,8 @@ void process_file(Image *I){
printf("%6d\t%6d\t%6.1f\t%6.1f\t%6.1f\t%6.1f\t%6.1f\t%6.1f\n", printf("%6d\t%6d\t%6.1f\t%6.1f\t%6.1f\t%6.1f\t%6.1f\t%6.1f\n",
i, o->area, 20.-1.0857*log(o->Isum), o->WdivH, o->xc, o->yc, o->xsigma, o->ysigma); i, o->area, 20.-1.0857*log(o->Isum), o->WdivH, o->xc, o->yc, o->xsigma, o->ysigma);
} }
getDeviation(Objects); getDeviation(Objects); // calculate dX/dY and process corrections
{ // prepare image { // prepare image and save jpeg
uint8_t *outp = NULL; uint8_t *outp = NULL;
if(theconf.equalize) if(theconf.equalize)
outp = equalize(I, 3, theconf.throwpart); outp = equalize(I, 3, theconf.throwpart);
@ -262,16 +276,29 @@ void process_file(Image *I){
Pattern_draw3(&i3, cross, Objects[i].xc, H-Objects[i].yc, C_R); Pattern_draw3(&i3, cross, Objects[i].xc, H-Objects[i].yc, C_R);
// Pattern_free(&cross); don't free - static variable! // Pattern_free(&cross); don't free - static variable!
} }
stbi_write_jpg(GP->outputjpg, I->width, I->height, 3, outp, 95); char *tmpnm = MALLOC(char, strlen(GP->outputjpg) + 5);
sprintf(tmpnm, "%s-tmp", GP->outputjpg);
if(stbi_write_jpg(tmpnm, I->width, I->height, 3, outp, 95)){
if(rename(tmpnm, GP->outputjpg)){
WARN("rename()");
LOGWARN("can't save %s", GP->outputjpg);
}
}
FREE(tmpnm);
++ImNumber;
if(lastTproc > 1.) FPS = 1. / (dtime() - lastTproc);
lastTproc = dtime();
FREE(outp); FREE(outp);
} }
FREE(cc);
FREE(Objects); FREE(Objects);
/*
Image *c = ST2Im(S, W, H); Image *c = ST2Im(S, W, H);
DELTA("conv size_t -> Ima"); DELTA("conv size_t -> Ima");
save_fits(c, "size_t.fits"); save_fits(c, "size_t.fits");
Image_free(&c); Image_free(&c);
DELTA("Save size_t"); DELTA("Save size_t");
*/
/*
Image *obj = Image_sim(I); Image *obj = Image_sim(I);
OMP_FOR() OMP_FOR()
for(int y = 0; y < H; ++y){ for(int y = 0; y < H; ++y){
@ -286,17 +313,41 @@ void process_file(Image *I){
Image_minmax(obj); Image_minmax(obj);
save_fits(obj, "object.fits"); save_fits(obj, "object.fits");
Image_free(&obj); Image_free(&obj);
} */
}else Image_write_jpg(I, GP->outputjpg, theconf.equalize);
FREE(S); FREE(S);
FREE(cc);
} }
} }
DELTA("End"); DELTA("End");
} }
static char *localimages(const char *messageid, int isdir, char *buf, int buflen){
static char *impath = NULL;
if(!impath){
if(!realpath(GP->outputjpg, impath)) impath = strdup(GP->outputjpg);
}
snprintf(buf, buflen, "{ \"%s\": \"%s\", \"camstatus\": \"watch %s\", \"impath\": \"%s\"}",
MESSAGEID, messageid, isdir ? "directory" : "file", impath);
return buf;
}
static char *watchdr(const char *messageid, char *buf, int buflen){
return localimages(messageid, 1, buf, buflen);
}
static char *watchfl(const char *messageid, char *buf, int buflen){
return localimages(messageid, 0, buf, buflen);
}
int process_input(InputType tp, char *name){ int process_input(InputType tp, char *name){
DBG("process_input(%d, %s)", tp, name); //DBG("process_input(%d, %s)", tp, name);
if(tp == T_DIRECTORY) return watch_directory(name, process_file); if(tp == T_DIRECTORY){
else if(tp == T_CAPT_GRASSHOPPER) return capture_grasshopper(process_file); imagedata = watchdr;
return watch_directory(name, process_file);
}else if(tp == T_CAPT_GRASSHOPPER){
imagedata = gsimagestatus;
return capture_grasshopper(process_file);
}
imagedata = watchfl;
return watch_file(name, process_file); return watch_file(name, process_file);
} }
@ -348,3 +399,5 @@ void setpostprocess(const char *name){
LOGERR("Unknown postprocess \"%s\"", name); LOGERR("Unknown postprocess \"%s\"", name);
} }
} }
double getFramesPerS(){ return FPS; }

View File

@ -19,28 +19,35 @@
#ifndef IMPROC_H__ #ifndef IMPROC_H__
#define IMPROC_H__ #define IMPROC_H__
#include <stdatomic.h>
#include "imagefile.h" #include "imagefile.h"
// tolerance of deviations by X and Y axis // tolerance of deviations by X and Y axis (if sigmaX or sigmaY greater, values considered to be wrong)
#define XY_TOLERANCE (1.) #define XY_TOLERANCE (1.)
// roundness parameter // roundness parameter
#define MINWH (0.2) #define MINWH (0.5)
#define MAXWH (5.) #define MAXWH (2.)
#define PUSIROBO_POSTPROC "pusirobo" #define PUSIROBO_POSTPROC "pusirobo"
// how many frames will be averaged to count image deviation // how many frames will be averaged to count image deviation
#define MAX_AVERAGING_ARRAY_SIZE (25) #define MAX_AVERAGING_ARRAY_SIZE (25)
extern int stopwork; extern volatile atomic_bool stopwork;
extern double Xtarget, Ytarget; extern double Xtarget, Ytarget;
extern volatile atomic_ullong ImNumber;
extern float exptime;
//extern int autoExposition;
extern char *(*stepstatus)(const char *messageid, char *buf, int buflen);
extern char *(*setstepstatus)(const char *newstatus, char *buf, int buflen);
extern char *(*movefocus)(const char *newstatus, char *buf, int buflen);
extern char *(*imagedata)(const char *messageid, char *buf, int buflen);
void process_file(Image *I); void process_file(Image *I);
int process_input(InputType tp, char *name); int process_input(InputType tp, char *name);
void openXYlog(const char *name); void openXYlog(const char *name);
void closeXYlog(); void closeXYlog();
void setpostprocess(const char *name); void setpostprocess(const char *name);
extern char *(*stepstatus)(char *buf, int buflen); double getFramesPerS();
extern char *(*setstepstatus)(const char *newstatus, char *buf, int buflen);
extern char *(*movefocus)(const char *newstatus, char *buf, int buflen);
#endif // IMPROC_H__ #endif // IMPROC_H__

View File

@ -17,6 +17,7 @@
*/ */
#include <math.h> #include <math.h>
#include <pthread.h>
#include <signal.h> // signal #include <signal.h> // signal
#include <string.h> // strdup #include <string.h> // strdup
#include <usefull_macros.h> #include <usefull_macros.h>
@ -28,6 +29,8 @@
#include "pusirobo.h" #include "pusirobo.h"
#include "socket.h" #include "socket.h"
static InputType tp;
/** /**
* We REDEFINE the default WEAK function of signal processing * We REDEFINE the default WEAK function of signal processing
*/ */
@ -36,21 +39,17 @@ void signals(int sig){
signal(sig, SIG_IGN); signal(sig, SIG_IGN);
DBG("Get signal %d, quit.\n", sig); DBG("Get signal %d, quit.\n", sig);
} }
stopwork = TRUE;
DBG("exit %d", sig); DBG("exit %d", sig);
LOGERR("Exit with status %d", sig); LOGERR("Exit with status %d", sig);
stopwork = 1;
saveconf(NULL); saveconf(NULL);
usleep(10000);
DBG("disconnectGrasshopper()");
disconnectGrasshopper();
DBG("pusi_disconnect()");
pusi_disconnect();
DBG("closeXYlog()");
closeXYlog();
if(GP && GP->pidfile){ // remove unnesessary PID file if(GP && GP->pidfile){ // remove unnesessary PID file
DBG("unlink(GP->pidfile)"); DBG("unlink(GP->pidfile)");
unlink(GP->pidfile); unlink(GP->pidfile);
} }
DBG("closeXYlog()");
closeXYlog();
DBG("EXIT %d", sig);
exit(sig); exit(sig);
} }
@ -58,12 +57,18 @@ void iffound_default(pid_t pid){
ERRX("Another copy of this process found, pid=%d. Exit.", pid); ERRX("Another copy of this process found, pid=%d. Exit.", pid);
} }
void *procinp_thread(_U_ void* arg){
int p = process_input(tp, GP->inputname);
LOGDBG("process_input=%d", p);
return NULL;
}
static InputType chk_inp(const char *name){ static InputType chk_inp(const char *name){
if(!name) ERRX("Point file or directory name to monitor"); if(!name) ERRX("Point file or directory name to monitor");
InputType tp = chkinput(GP->inputname); InputType itp = chkinput(GP->inputname);
if(T_WRONG == tp) return T_WRONG; if(T_WRONG == itp) return T_WRONG;
green("\n%s is a ", name); green("\n%s is a ", name);
switch(tp){ switch(itp){
case T_DIRECTORY: case T_DIRECTORY:
printf("directory"); printf("directory");
break; break;
@ -93,7 +98,7 @@ static InputType chk_inp(const char *name){
return T_WRONG; return T_WRONG;
} }
printf("\n"); printf("\n");
return tp; return itp;
} }
int main(int argc, char *argv[]){ int main(int argc, char *argv[]){
@ -105,8 +110,14 @@ int main(int argc, char *argv[]){
} }
if(GP->Naveraging < 2 || GP->Naveraging > MAX_AVERAGING_ARRAY_SIZE) if(GP->Naveraging < 2 || GP->Naveraging > MAX_AVERAGING_ARRAY_SIZE)
ERRX("Averaging amount should be from 2 to 25"); ERRX("Averaging amount should be from 2 to 25");
InputType tp = chk_inp(GP->inputname); tp = chk_inp(GP->inputname);
if(tp == T_WRONG) ERRX("Enter correct image file or directory name"); if(tp == T_WRONG) ERRX("Enter correct image file or directory name");
// check ability of saving file
{
FILE *f = fopen(GP->outputjpg, "w");
if(!f) ERR("Can't create %s", GP->outputjpg);
fclose(f);
}
if(GP->logfile){ if(GP->logfile){
sl_loglevel lvl = LOGLEVEL_ERR; // default log level - errors sl_loglevel lvl = LOGLEVEL_ERR; // default log level - errors
int v = GP->verb; int v = GP->verb;
@ -178,9 +189,18 @@ int main(int argc, char *argv[]){
LOGMSG("Start application..."); LOGMSG("Start application...");
LOGDBG("xtag=%g, ytag=%g", theconf.xtarget, theconf.ytarget); LOGDBG("xtag=%g, ytag=%g", theconf.xtarget, theconf.ytarget);
openIOport(GP->ioport); openIOport(GP->ioport);
int p = process_input(tp, GP->inputname); pthread_t inp_thread;
DBG("process_input=%d", p); if(pthread_create(&inp_thread, NULL, procinp_thread, NULL)){
// never reached LOGERR("pthread_create() for image input failed");
signals(p); // clean everything ERR("pthread_create()");
return p; }
while(1){
if(stopwork || pthread_kill(inp_thread, 0) == ESRCH){
DBG("close");
pthread_join(inp_thread, NULL);
DBG("out");
return 0;
}
};
return 0;
} }

View File

@ -45,7 +45,7 @@
#define registerFocus "register F 0x583 stepper" #define registerFocus "register F 0x583 stepper"
#define setUspeed "mesg U maxspeed 12800" #define setUspeed "mesg U maxspeed 12800"
#define setVspeed "mesg V maxspeed 12800" #define setVspeed "mesg V maxspeed 12800"
#define setFspeed "mesg F maxspeed 1600" #define setFspeed "mesg F maxspeed 12800"
#define Urelsteps "mesg U relmove " #define Urelsteps "mesg U relmove "
#define Vrelsteps "mesg V relmove " #define Vrelsteps "mesg V relmove "
#define Fabssteps "mesg F absmove " #define Fabssteps "mesg F absmove "
@ -93,6 +93,7 @@ static int sockfd = -1; // server file descriptor
// current steps counters (zero at the middle) // current steps counters (zero at the middle)
static int Uposition = 0, Vposition = 0, Fposition = 0; static int Uposition = 0, Vposition = 0, Fposition = 0;
static uint8_t fixerr = 0; // ==1 if can't fixed
void pusi_disconnect(){ void pusi_disconnect(){
if(sockfd > -1) close(sockfd); if(sockfd > -1) close(sockfd);
@ -353,7 +354,7 @@ static int move_motor(const char *movecmd, int s/*, int *counter*/){
static void process_movetomiddle_stage(){ static void process_movetomiddle_stage(){
switch(sstatus){ switch(sstatus){
case SETUP_INIT: // initial moving case SETUP_INIT: // initial moving
if(moveU(-UVmaxsteps) && moveV(-UVmaxsteps) && moveF(-Fmaxsteps*2)) if(moveU(-UVmaxsteps) && moveV(-UVmaxsteps) && moveF(-Fmaxsteps))
sstatus = SETUP_WAITUV0; sstatus = SETUP_WAITUV0;
break; break;
case SETUP_WAITUV0: // wait for both coordinates moving to zero case SETUP_WAITUV0: // wait for both coordinates moving to zero
@ -501,8 +502,8 @@ static int process_targetstage(double X, double Y){
DBG("nhit = %d", nhit); DBG("nhit = %d", nhit);
return FALSE; return FALSE;
} }
theconf.xtarget = X; theconf.xtarget = X + theconf.xoff;
theconf.ytarget = Y; theconf.ytarget = Y + theconf.yoff;
DBG("Got target coordinates: (%.1f, %.1f)", X, Y); DBG("Got target coordinates: (%.1f, %.1f)", X, Y);
saveconf(FALSE); saveconf(FALSE);
nhit = 0; xprev = 0.; yprev = 0.; nhit = 0; xprev = 0.; yprev = 0.;
@ -550,13 +551,19 @@ mesg F relmove 32000
* This function called from improc.c each time the corrections calculated (ONLY IF Xtarget/Ytarget > -1) * This function called from improc.c each time the corrections calculated (ONLY IF Xtarget/Ytarget > -1)
*/ */
void pusi_process_corrections(double X, double Y, int aver){ void pusi_process_corrections(double X, double Y, int aver){
DBG("got centroid data: %g, %g", X, Y); //DBG("got centroid data: %g, %g", X, Y);
double xdev = X - theconf.xtarget, ydev = Y - theconf.ytarget; static int first = TRUE;
double xtg = theconf.xtarget - theconf.xoff, ytg = theconf.ytarget - theconf.yoff;
double xdev = X - xtg, ydev = Y - ytg;
if(state != PUSI_DISCONN) first = TRUE;
switch(state){ switch(state){
case PUSI_DISCONN: case PUSI_DISCONN:
if(!pusi_connect()){ if(!pusi_connect()){
WARN("Can't reconnect"); WARN("Can't reconnect");
}
if(first){
LOGWARN("Can't reconnect"); LOGWARN("Can't reconnect");
first = FALSE;
} }
break; break;
case PUSI_SETUP: // setup axes (before this state set Xtarget/Ytarget in improc.c) case PUSI_SETUP: // setup axes (before this state set Xtarget/Ytarget in improc.c)
@ -581,9 +588,10 @@ void pusi_process_corrections(double X, double Y, int aver){
Uposition, Vposition, xdev, ydev); Uposition, Vposition, xdev, ydev);
if(!try2correct(xdev, ydev)){ if(!try2correct(xdev, ydev)){
LOGWARN("failed to correct"); LOGWARN("failed to correct");
fixerr = 1;
// TODO: do something here // TODO: do something here
DBG("FAILED"); DBG("FAILED");
} } else fixerr = 0;
} }
break; break;
default: // PUSI_RELAX default: // PUSI_RELAX
@ -614,11 +622,11 @@ pusistate pusi_getstate(){
// get current status // get current status
// return JSON string with different parameters // return JSON string with different parameters
char *pusi_status(char *buf, int buflen){ char *pusi_status(const char *messageid, char *buf, int buflen){
int l; int l;
char *bptr = buf; char *bptr = buf;
const char *s = NULL, *stage = NULL; const char *s = NULL, *stage = NULL;
l = snprintf(bptr, buflen, "{ \"status\": "); l = snprintf(bptr, buflen, "{ \"%s\": \"%s\", \"status\": ", MESSAGEID, messageid);
buflen -= l; bptr += l; buflen -= l; bptr += l;
switch(state){ switch(state){
case PUSI_DISCONN: case PUSI_DISCONN:
@ -664,7 +672,7 @@ char *pusi_status(char *buf, int buflen){
l = snprintf(bptr, buflen, "\"findtarget\""); l = snprintf(bptr, buflen, "\"findtarget\"");
break; break;
case PUSI_FIX: case PUSI_FIX:
l = snprintf(bptr, buflen, "\"fixing\""); l = snprintf(bptr, buflen, "\"%s\"", fixerr ? "fixoutofrange" : "fixing");
break; break;
default: default:
l = snprintf(bptr, buflen, "\"unknown\""); l = snprintf(bptr, buflen, "\"unknown\"");
@ -676,11 +684,13 @@ char *pusi_status(char *buf, int buflen){
const char *motors[] = {"Umotor", "Vmotor", "Fmotor"}; const char *motors[] = {"Umotor", "Vmotor", "Fmotor"};
const char *statuses[] = {Ustatus, Vstatus, Fstatus}; const char *statuses[] = {Ustatus, Vstatus, Fstatus};
int *pos[] = {&Uposition, &Vposition, &Fposition}; int *pos[] = {&Uposition, &Vposition, &Fposition};
const int maxpos[] = {UVmaxsteps, UVmaxsteps, Fmaxsteps};
const int minpos[] = {-UVmaxsteps, -UVmaxsteps, 0};
for(int i = 0; i < 3; ++i){ for(int i = 0; i < 3; ++i){
const char *stat = "moving"; const char *stat = "moving";
if(moving_finished(statuses[i], pos[i])) stat = "stopping"; if(moving_finished(statuses[i], pos[i])) stat = "stopping";
l = snprintf(bptr, buflen, "\"%s\": { \"status\": \"%s\", \"position\": %d }%s", l = snprintf(bptr, buflen, "\"%s\": { \"status\": \"%s\", \"position\": %d, \"minpos\": %d, \"maxpos\": %d }%s",
motors[i], stat, *pos[i], (i==2)?"":", "); motors[i], stat, *pos[i], minpos[i], maxpos[i], (i==2)?"":", ");
buflen -= l; bptr += l; buflen -= l; bptr += l;
} }
} }
@ -717,7 +727,10 @@ char *set_pusistatus(const char *newstatus, char *buf, int buflen){
if(pusi_setstate(newstate)){ if(pusi_setstate(newstate)){
snprintf(buf, buflen, OK); snprintf(buf, buflen, OK);
return buf; return buf;
}else return pusi_status(buf, buflen); }else{
snprintf(buf, buflen, FAIL);
return buf;
}
} }
int L = snprintf(buf, buflen, "status '%s' undefined, allow: ", newstatus); int L = snprintf(buf, buflen, "status '%s' undefined, allow: ", newstatus);
char *ptr = buf; char *ptr = buf;
@ -734,12 +747,12 @@ char *set_pusistatus(const char *newstatus, char *buf, int buflen){
// change focus // change focus
char *set_pfocus(const char *newstatus, char *buf, int buflen){ char *set_pfocus(const char *newstatus, char *buf, int buflen){
if(!moving_finished(Fstatus, &Fposition)){ if(!moving_finished(Fstatus, &Fposition)){
snprintf(buf, buflen, "moving\n"); snprintf(buf, buflen, FAIL);
return buf; return buf;
} }
int newval = atoi(newstatus); int newval = atoi(newstatus);
if(newval < 0 || newval > Fmaxsteps){ if(newval < 0 || newval > Fmaxsteps){
snprintf(buf, buflen, "Bad value: %d", newval); snprintf(buf, buflen, FAIL);
}else{ }else{
if(!setF(newval)) snprintf(buf, buflen, FAIL); if(!setF(newval)) snprintf(buf, buflen, FAIL);
else snprintf(buf, buflen, OK); else snprintf(buf, buflen, OK);

View File

@ -35,7 +35,7 @@ int pusi_setstate(pusistate newstate);
pusistate pusi_getstate(); pusistate pusi_getstate();
void pusi_disconnect(); void pusi_disconnect();
void pusi_process_corrections(double X, double Y, int corrflag); void pusi_process_corrections(double X, double Y, int corrflag);
char *pusi_status(char *buf, int buflen); char *pusi_status(const char *messageid, char *buf, int buflen);
char *set_pusistatus(const char *newstatus, char *buf, int buflen); char *set_pusistatus(const char *newstatus, char *buf, int buflen);
char *set_pfocus(const char *newstatus, char *buf, int buflen); char *set_pfocus(const char *newstatus, char *buf, int buflen);
char *get_JSON_status(char *buf, int buflen); char *get_JSON_status(char *buf, int buflen);

View File

@ -16,8 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <arpa/inet.h> // inet_ntop #include <arpa/inet.h> // inet_ntop
#include <sys/ioctl.h> #include <libgen.h> // basename
#include <limits.h> // INT_xxx #include <limits.h> // INT_xxx
#include <netdb.h> // addrinfo #include <netdb.h> // addrinfo
#include <poll.h> #include <poll.h>
@ -25,10 +26,12 @@
#include <signal.h> // pthread_kill #include <signal.h> // pthread_kill
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/ioctl.h>
#include <sys/syscall.h> // syscall #include <sys/syscall.h> // syscall
#include <unistd.h> // daemon #include <unistd.h> // daemon
#include <usefull_macros.h> #include <usefull_macros.h>
#include "cmdlnopts.h"
#include "config.h" #include "config.h"
#include "improc.h" #include "improc.h"
#include "socket.h" #include "socket.h"
@ -40,10 +43,15 @@
// Max amount of connections // Max amount of connections
#define BACKLOG (10) #define BACKLOG (10)
/*
TODO3: add 'FAIL error text' if not OK and instead all "wrong message"
*/
// additional commands list - getters // additional commands list - getters
typedef struct{ typedef struct{
const char *command; const char *command;
char *(*handler)(char *buf, int buflen); char *(*handler)(const char *messageid, char *buf, int buflen);
const char *help; const char *help;
} getter; } getter;
// setters // setters
@ -53,26 +61,32 @@ typedef struct{
const char *help; const char *help;
} setter; } setter;
static char *helpmsg(char *buf, int buflen); static char *helpmsg(const char *messageid, char *buf, int buflen);
static char *stepperstatus(char *buf, int buflen); static char *stepperstatus(const char *messageid, char *buf, int buflen);
static char *getimagedata(const char *messageid, char *buf, int buflen);
static getter getterHandlers[] = { static getter getterHandlers[] = {
{"help", helpmsg, "List avaiable commands"}, {"help", helpmsg, "List avaiable commands"},
{"settings", listconf, "List current configuration"}, {"settings", listconf, "List current configuration"},
{"steppers", stepperstatus, "Get status of steppers' server"}, {"canbus", stepperstatus, "Get status of CAN bus server"},
{"imdata", getimagedata, "Get image data (status, path, FPS, counter)"},
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };
static char *setstepperstate(const char *state, char *buf, int buflen); static char *setstepperstate(const char *state, char *buf, int buflen);
static char *setfocusstate(const char *state, char *buf, int buflen); static char *setfocusstate(const char *state, char *buf, int buflen);
//static char *setexposition(const char *expos, char *buf, int buflen);
//static char *setexposmethod(const char *expos, char *buf, int buflen);
static setter setterHandlers[] = { static setter setterHandlers[] = {
{"stpstate", setstepperstate, "Set given steppers' server state"}, {"stpstate", setstepperstate, "Set given steppers' server state"},
{"focus", setfocusstate, "Move focus to given value"}, {"focus", setfocusstate, "Move focus to given value"},
// {"exptime", setexposition, "Set exposition to new value (s)"},
// {"expmethod", setexposmethod, "Set exposition method (\"manual\"/\"auto\")"},
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };
/**************** functions to process commands ****************/ /**************** functions to process commands ****************/
// getters // getters
static char *helpmsg(char *buf, int buflen){ static char *helpmsg(_U_ const char *messageid, char *buf, int buflen){
if(get_cmd_list(buf, buflen)){ if(get_cmd_list(buf, buflen)){
int l = strlen(buf), L = buflen - l; int l = strlen(buf), L = buflen - l;
char *ptr = buf + l; char *ptr = buf + l;
@ -94,9 +108,14 @@ static char *helpmsg(char *buf, int buflen){
} }
return NULL; return NULL;
} }
static char *stepperstatus(char *buf, int buflen){ static char *stepperstatus(const char *messageid, char *buf, int buflen){
if(stepstatus) return stepstatus(buf, buflen); if(stepstatus) return stepstatus(messageid, buf, buflen);
snprintf(buf, buflen, "not defined"); snprintf(buf, buflen, FAIL);
return buf;
}
static char *getimagedata(const char *messageid, char *buf, int buflen){
if(imagedata) return imagedata(messageid, buf, buflen);
else snprintf(buf, buflen, FAIL);
return buf; return buf;
} }
@ -104,23 +123,54 @@ static char *stepperstatus(char *buf, int buflen){
static char *setstepperstate(const char *state, char *buf, int buflen){ static char *setstepperstate(const char *state, char *buf, int buflen){
DBG("set steppersstate to %s", state); DBG("set steppersstate to %s", state);
if(setstepstatus) return setstepstatus(state, buf, buflen); if(setstepstatus) return setstepstatus(state, buf, buflen);
snprintf(buf, buflen, "not defined"); snprintf(buf, buflen, FAIL);
return buf; return buf;
} }
static char *setfocusstate(const char *state, char *buf, int buflen){ static char *setfocusstate(const char *state, char *buf, int buflen){
DBG("move focus to %s", state); DBG("move focus to %s", state);
if(movefocus) return movefocus(state, buf, buflen); if(movefocus) return movefocus(state, buf, buflen);
snprintf(buf, buflen, "not defined"); snprintf(buf, buflen, FAIL);
return buf; return buf;
} }
/*
static char *setexposition(const char *expos, char *buf, int buflen){
DBG("Set exp to %s ms", expos);
float e = atof(expos);
if(e < EXPOS_MIN || e > EXPOS_MAX){
snprintf(buf, buflen, "bad value");
}else{
exptime = (float) e;
LOGMSG("Set exposition time to %gms", e);
snprintf(buf, buflen, OK);
}
return buf;
}
static char *setexposmethod(const char *expos, char *buf, int buflen){
int good = 0;
if(strncasecmp(expos, "auto", 4) == 0){
autoExposition = TRUE;
LOGMSG("Set exposition method to \"auto\"");
good = 1;
}else if(strncasecmp(expos, "manual", 6) == 0){
autoExposition = FALSE;
LOGMSG("Set exposition method to \"manual\"");
good = 1;
}
if(good) snprintf(buf, buflen, OK);
else snprintf(buf, buflen, "wrong method: \"%s\"", expos);
return buf;
}
*/
/*
static char *rmnl(const char *msg, char *buf, int buflen){ static char *rmnl(const char *msg, char *buf, int buflen){
strncpy(buf, msg, buflen); strncpy(buf, msg, buflen);
char *nl = strchr(buf, '\n'); char *nl = strchr(buf, '\n');
if(nl) *nl = 0; if(nl) *nl = 0;
return buf; return buf;
} }
*/
/** /**
* @brief processCommand - command parser * @brief processCommand - command parser
* @param msg - incoming message * @param msg - incoming message
@ -144,12 +194,13 @@ static char *processCommand(const char msg[BUFLEN], char *ans, int anslen){
break; break;
case PAR_DOUBLE: case PAR_DOUBLE:
DBG("FOUND! Double, old=%g, new=%g", *((double*)par->ptr), result.val.dblval); DBG("FOUND! Double, old=%g, new=%g", *((double*)par->ptr), result.val.dblval);
*((double*)par->ptr) = result.val.dblval;
break; break;
default: default:
snprintf(ans, anslen, "undefined type"); snprintf(ans, anslen, FAIL);
return ans; return ans;
} }
snprintf(ans, anslen, "success"); snprintf(ans, anslen, OK);
return ans; return ans;
}else{ }else{
setter *s = setterHandlers; setter *s = setterHandlers;
@ -166,11 +217,11 @@ static char *processCommand(const char msg[BUFLEN], char *ans, int anslen){
while(g->command){ while(g->command){
int l = strlen(g->command); int l = strlen(g->command);
if(strncasecmp(msg, g->command, l) == 0) if(strncasecmp(msg, g->command, l) == 0)
return g->handler(ans, anslen); return g->handler(g->command, ans, anslen);
++g; ++g;
} }
} }
snprintf(ans, anslen, "Message '%s' is wrong", rmnl(msg, value, BUFLEN)); snprintf(ans, anslen, FAIL);
return ans; return ans;
} }
@ -238,6 +289,10 @@ static void *server(void *asock){
poll_set[0].fd = sock; poll_set[0].fd = sock;
poll_set[0].events = POLLIN; poll_set[0].events = POLLIN;
while(1){ while(1){
if(stopwork){
DBG("server() exit @ global stop");
return NULL;
}
poll(poll_set, nfd, 1); // poll for 1ms poll(poll_set, nfd, 1); // poll for 1ms
for(int fdidx = 0; fdidx < nfd; ++fdidx){ // poll opened FDs for(int fdidx = 0; fdidx < nfd; ++fdidx){ // poll opened FDs
if((poll_set[fdidx].revents & POLLIN) == 0) continue; if((poll_set[fdidx].revents & POLLIN) == 0) continue;
@ -252,8 +307,6 @@ static void *server(void *asock){
LOGMSG("Client %d disconnected", fd); LOGMSG("Client %d disconnected", fd);
// move last to free space // move last to free space
poll_set[fdidx] = poll_set[nfd - 1]; poll_set[fdidx] = poll_set[nfd - 1];
//for(int i = fdidx; i < nfd-1; ++i)
// poll_set[i] = poll_set[i + 1];
--nfd; --nfd;
} }
}else{ // server }else{ // server
@ -283,15 +336,6 @@ static void *server(void *asock){
} }
} }
} // endfor } // endfor
/*
char *srvmesg = mesgGetText(&ServerMessages); // broadcast messages to all clients
if(srvmesg){ // send broadcast message to all clients or throw them to /dev/null
for(int fdidx = 1; fdidx < nfd; ++fdidx){
send_data(poll_set[fdidx].fd, srvmesg);
}
FREE(srvmesg);
}
*/
} }
LOGERR("server(): UNREACHABLE CODE REACHED!"); LOGERR("server(): UNREACHABLE CODE REACHED!");
} }
@ -300,13 +344,16 @@ static void *server(void *asock){
static void daemon_(int sock){ static void daemon_(int sock){
if(sock < 0) return; if(sock < 0) return;
pthread_t sock_thread;//, canserver_thread; pthread_t sock_thread;//, canserver_thread;
if(pthread_create(&sock_thread, NULL, server, (void*) &sock) if(pthread_create(&sock_thread, NULL, server, (void*) &sock)){
//|| pthread_create(&canserver_thread, NULL, CANserver, NULL)
){
LOGERR("daemon_(): pthread_create() failed"); LOGERR("daemon_(): pthread_create() failed");
ERR("pthread_create()"); ERR("pthread_create()");
} }
do{ do{
if(stopwork){
DBG("kill");
pthread_join(sock_thread, NULL);
return;
}
if(pthread_kill(sock_thread, 0) == ESRCH){ // died if(pthread_kill(sock_thread, 0) == ESRCH){ // died
WARNX("Sockets thread died"); WARNX("Sockets thread died");
LOGERR("Sockets thread died"); LOGERR("Sockets thread died");
@ -316,23 +363,7 @@ static void daemon_(int sock){
ERR("pthread_create(sock_thread)"); ERR("pthread_create(sock_thread)");
} }
} }
/*if(pthread_kill(canserver_thread, 0) == ESRCH){
WARNX("CANserver thread died");
LOGERR("CANserver thread died");
pthread_join(canserver_thread, NULL);
if(pthread_create(&canserver_thread, NULL, CANserver, NULL)){
LOGERR("daemon_(): new pthread_create(canserver_thread) failed");
ERR("pthread_create(canserver_thread)");
}
}*/
usleep(1000); // sleep a little or thread's won't be able to lock mutex usleep(1000); // sleep a little or thread's won't be able to lock mutex
// copy temporary buffers to main
//pthread_mutex_lock(&mutex);
/*
* INSERT CODE HERE
* fill global data buffers
*/
//pthread_mutex_unlock(&mutex);
}while(1); }while(1);
LOGERR("daemon_(): UNREACHABLE CODE REACHED!"); LOGERR("daemon_(): UNREACHABLE CODE REACHED!");
} }
@ -388,8 +419,7 @@ static void *connect2sock(void *data){
freeaddrinfo(res); freeaddrinfo(res);
daemon_(sock); daemon_(sock);
close(sock); close(sock);
LOGERR("openIOport(): UNREACHABLE CODE REACHED!"); LOGWARN("openIOport(): close @ global stop");
signals(22);
return NULL; return NULL;
} }
@ -405,4 +435,5 @@ void openIOport(int portN){
LOGERR("openIOport(): pthread_create() failed"); LOGERR("openIOport(): pthread_create() failed");
ERR("pthread_create()"); ERR("pthread_create()");
} }
pthread_detach(connthread);
} }