29#define DOWNLOAD_TAB "Download images"
30#define IMAGE_NAME "%s/%s_%d_%03d%s"
31#define IMAGE_PREFIX "_TMP_"
34#define GROUP_PREFIX "GROUP_"
35#define GROUP_PREFIX_LEN 6
48 std::generate(groups.begin(), groups.end(), [
this, &i] { return std::make_shared<Group>(i++, this); });
51bool Imager::isRunning()
56bool Imager::isCCDConnected()
61bool Imager::isFilterConnected()
66std::shared_ptr<Group> Imager::getGroup(
int index)
const
68 if(index > -1 && index <= maxGroup)
73std::shared_ptr<Group> Imager::currentGroup()
const
75 return getGroup(group - 1);
80std::shared_ptr<Group> Imager::nextGroup()
const
82 return getGroup(group);
85void Imager::initiateNextFilter()
90 if (group > 0 && image > 0 && group <= maxGroup && image <= maxImage)
92 int filterSlot = currentGroup()->filterSlot();
94 if (!isFilterConnected())
99 LOG_INFO(
"Filter wheel is not connected");
105 initiateNextCapture();
108 else if (filterSlot != 0 && FilterSlotNP[0].getValue() != filterSlot)
110 FilterSlotNP[0].setValue(filterSlot);
112 LOGF_DEBUG(
"Group %d of %d, image %d of %d, filer %d, filter set initiated on %s",
113 group, maxGroup, image, maxImage, (
int)FilterSlotNP[0].getValue(), FilterSlotNP.
getDeviceName());
117 initiateNextCapture();
122void Imager::initiateNextCapture()
126 if (group > 0 && image > 0 && group <= maxGroup && image <= maxImage)
128 if (!isCCDConnected())
135 CCDImageBinNP[HOR_BIN].setValue(currentGroup()->binning());
136 CCDImageBinNP[VER_BIN].setValue(currentGroup()->binning());
138 CCDImageExposureNP[0].setValue(currentGroup()->exposure());
140 CCDUploadSettingsTP[UPLOAD_DIR].setText(ImageNameTP[IMAGE_FOLDER].
getText());
141 CCDUploadSettingsTP[UPLOAD_PREFIX].setText(
"_TMP_");
144 LOGF_DEBUG(
"Group %d of %d, image %d of %d, duration %.1fs, binning %d, capture initiated on %s", group,
145 maxGroup, image, maxImage, CCDImageExposureNP[0].getValue(), (
int)CCDImageBinNP[HOR_BIN].getValue(),
151void Imager::startBatch()
154 ProgressNP[GROUP].setValue(group = 1);
155 ProgressNP[IMAGE].setValue(image = 1);
156 maxImage = currentGroup()->count();
159 initiateNextFilter();
162void Imager::abortBatch()
169void Imager::batchDone()
176void Imager::initiateDownload()
178 int group = (int)DownloadNP[GROUP].getValue();
179 int image = (int)DownloadNP[IMAGE].getValue();
180 char name[128] = {0};
183 if (group == 0 || image == 0)
186 snprintf(name,
sizeof(name),
IMAGE_NAME, ImageNameTP[IMAGE_FOLDER].
getText(), ImageNameTP[IMAGE_NAME_PREFIX].
getText(), group, image,
188 file.open(name, std::ios::in | std::ios::binary | std::ios::ate);
189 DownloadNP[GROUP].setValue(0);
190 DownloadNP[IMAGE].setValue(0);
193 long size = file.tellg();
194 char *data =
new char[size];
196 file.seekg(0, std::ios::beg);
197 file.read(data, size);
200 LOGF_DEBUG(
"Group %d, image %d, download initiated", group, image);
205 FitsBP[0].setFormat(format);
206 FitsBP[0].setBlob(data);
207 FitsBP[0].setBlobLen(FitsBP[0].getSize() == size);
219 LOGF_DEBUG(
"Group %d, image %d, upload failed", group, image);
236 GroupCountNP[0].
fill(
"GROUP_COUNT",
"Image group count",
"%3.0f", 1,
MAX_GROUP_COUNT, 1, maxGroup = 1);
240 ControlledDeviceTP[CCD].
fill(
"CCD",
"CCD",
"CCD Simulator");
241 ControlledDeviceTP[FILTER].
fill(
"FILTER",
"Filter wheel",
"Filter Simulator");
244 controlledCCD = ControlledDeviceTP[CCD].
getText();
245 controlledFilterWheel = ControlledDeviceTP[FILTER].
getText();
248 StatusLP[FILTER].
fill(
"FILTER", controlledFilterWheel,
IPS_IDLE);
252 ProgressNP[IMAGE].
fill(
"IMAGE",
"Current image",
"%3.0f", 1, 100, 1, 0);
253 ProgressNP[REMAINING_TIME].
fill(
"REMAINING_TIME",
"Remaining time",
"%5.2f", 0, 36000, 0, 0.0);
257 BatchSP[START].
fill(
"START",
"Start batch",
ISS_OFF);
258 BatchSP[ABORT].
fill(
"ABORT",
"Abort batch",
ISS_OFF);
262 ImageNameTP[IMAGE_FOLDER].
fill(
"IMAGE_FOLDER",
"Image folder",
"/tmp");
263 ImageNameTP[IMAGE_NAME_PREFIX].
fill(
"IMAGE_NAME_PREFIX",
"Image prefix",
"IMG");
268 DownloadNP[IMAGE].
fill(
"IMAGE",
"Image",
"%3.0f", 1, 100, 1, 1);
272 FitsBP[0].
fill(
"IMAGE",
"Image",
"");
279 for (
int i = 0; i < GroupCountNP[0].getValue(); i++)
281 groups[i]->defineProperties();
284 CCDImageExposureNP[0].
fill(
"CCD_EXPOSURE_VALUE",
"Duration (s)",
"%5.2f", 0, 36000, 0, 1.0);
285 CCDImageExposureNP.
fill(ControlledDeviceTP[CCD].
getText(),
"CCD_EXPOSURE",
"Expose",
288 CCDImageBinNP[HOR_BIN].
fill(
"HOR_BIN",
"X",
"%2.0f", 1, 4, 1, 1);
289 CCDImageBinNP[VER_BIN].
fill(
"VER_BIN",
"Y",
"%2.0f", 1, 4, 1, 1);
290 CCDImageBinNP.
fill(ControlledDeviceTP[CCD].
getText(),
"CCD_BINNING",
"Binning",
293 CCDUploadSP[UPLOAD_CLIENT].
fill(
"UPLOAD_CLIENT",
"Client",
ISS_OFF);
294 CCDUploadSP[UPLOAD_LOCAL].
fill(
"UPLOAD_LOCAL",
"Local",
ISS_ON);
295 CCDUploadSP[UPLOAD_BOTH].
fill(
"UPLOAD_BOTH",
"Both",
ISS_OFF);
299 CCDUploadSettingsTP[UPLOAD_DIR].
fill(
"UPLOAD_DIR",
"Dir",
"");
300 CCDUploadSettingsTP[UPLOAD_PREFIX].
fill(
"UPLOAD_PREFIX",
"Prefix",
IMAGE_PREFIX);
301 CCDUploadSettingsTP.
fill(ControlledDeviceTP[CCD].
getText(),
"UPLOAD_SETTINGS",
304 FilterSlotNP[0].
fill(
"FILTER_SLOT_VALUE",
"Filter",
"%3.0f", 1.0, 12.0, 1.0, 1.0);
305 FilterSlotNP.
fill(ControlledDeviceTP[FILTER].
getText(),
"FILTER_SLOT",
"Filter Slot",
316 ProgressNP[GROUP].setValue(group = 0);
317 ProgressNP[IMAGE].setValue(image = 0);
322 DownloadNP[GROUP].setValue(0);
323 DownloadNP[IMAGE].setValue(0);
342 DefaultDevice::ISGetProperties(dev);
349 if (GroupCountNP[0].isNameMatch(name))
351 for (
int i = 0; i < maxGroup; i++)
352 groups[i]->deleteProperties();
353 GroupCountNP.
update(values, names, n);
354 maxGroup = (int)GroupCountNP[0].getValue();
357 for (
int i = 0; i < maxGroup; i++)
358 groups[i]->defineProperties();
360 GroupCountNP.
apply();
365 DownloadNP.
update(values, names, n);
371 for (
int i = 0; i < GroupCountNP[0].getValue(); i++)
372 if (groups[i]->
ISNewNumber(dev, name, values, names, n))
379 return DefaultDevice::ISNewNumber(dev, name, values, names, n);
388 for (
int i = 0; i < n; i++)
390 if (strcmp(names[i], BatchSP[START].getName()) == 0 && states[i] ==
ISS_ON)
395 if (strcmp(names[i], BatchSP[ABORT].getName()) == 0 && states[i] ==
ISS_ON)
406 return DefaultDevice::ISNewSwitch(dev, name, states, names, n);
415 ControlledDeviceTP.
update(texts, names, n);
416 ControlledDeviceTP.
apply();
428 ImageNameTP.
update(texts, names, n);
436bool Imager::ISNewBLOB(
const char *dev,
const char *name,
int sizes[],
int blobsizes[],
char *blobs[],
char *formats[],
437 char *names[],
int n)
450 BaseClient::watchDevice(controlledCCD);
451 BaseClient::watchDevice(controlledFilterWheel);
480 LOGF_DEBUG(
"Device %s detected", deviceName.c_str());
481 if (deviceName == controlledCCD)
483 if (deviceName == controlledFilterWheel)
491 std::string deviceName{
property.getDeviceName()};
496 if (deviceName == controlledCCD)
508 if (deviceName == controlledFilterWheel)
517 LOGF_DEBUG(
"Connecting %s", controlledFilterWheel);
526 std::string deviceName{
property.getDeviceName()};
534 char name[128] = {0};
537 snprintf(format,
sizeof(format),
"%s", bp.getFormat());
538 snprintf(name,
sizeof(name),
IMAGE_NAME, ImageNameTP[IMAGE_FOLDER].
getText(), ImageNameTP[IMAGE_NAME_PREFIX].
getText(), group, image,
540 file.open(name, std::ios::out | std::ios::binary | std::ios::trunc);
541 file.write(
static_cast<char *
>(bp.getBlob()), bp.getBlobLen());
543 LOGF_DEBUG(
"Group %d of %d, image %d of %d, saved to %s", group, maxGroup, image, maxImage,
545 if (image == maxImage)
547 if (group == maxGroup)
553 maxImage = nextGroup()->count();
554 ProgressNP[GROUP].setValue(group = group + 1);
555 ProgressNP[IMAGE].setValue(image = 1);
557 initiateNextFilter();
562 ProgressNP[IMAGE].setValue(image = image + 1);
564 initiateNextFilter();
576 if (deviceName == controlledCCD)
581 if (deviceName == controlledFilterWheel)
589 if (deviceName == controlledCCD && property.
isNameMatch(
"CCD_EXPOSURE"))
592 ProgressNP[REMAINING_TIME].setValue(propertyNumber[0].getValue());
597 if (deviceName == controlledFilterWheel && property.
isNameMatch(
"FILTER_SLOT"))
600 FilterSlotNP[0].setValue(propertyNumber[0].getValue());
602 initiateNextCapture();
606 if (deviceName == controlledCCD && property.
isNameMatch(
"CCD_FILE_PATH"))
609 char name[128] = {0};
611 snprintf(format,
sizeof(format),
"%s", strrchr(propertyText[0].
getText(),
'.'));
612 snprintf(name,
sizeof(name),
IMAGE_NAME, ImageNameTP[IMAGE_FOLDER].
getText(), ImageNameTP[IMAGE_NAME_PREFIX].
getText(), group, image,
614 rename(propertyText[0].
getText(), name);
615 LOGF_DEBUG(
"Group %d of %d, image %d of %d, saved to %s", group, maxGroup, image,
617 if (image == maxImage)
619 if (group == maxGroup)
625 maxImage = nextGroup()->count();
626 ProgressNP[GROUP].setValue(group = group + 1);
627 ProgressNP[IMAGE].setValue(image = 1);
629 initiateNextFilter();
634 ProgressNP[IMAGE].setValue(image = image + 1);
636 initiateNextFilter();
std::shared_ptr< Imager > imager(new Imager())
void setServer(const char *hostname, unsigned int port)
Set the server host name and port.
void sendNewSwitch(INDI::Property pp)
Send new Switch command to server.
void setBLOBMode(BLOBHandling blobH, const char *dev, const char *prop=nullptr)
Set Binary Large Object policy mode.
void connectDevice(const char *deviceName)
Disconnect INDI driver.
void sendNewNumber(INDI::Property pp)
Send new Number command to server.
void sendNewText(INDI::Property pp)
Send new Text command to server.
bool disconnectServer(int exit_code=0) override
Disconnect from INDI server. Any devices previously created will be deleted and memory cleared.
bool connectServer() override
Connect to INDI server.
Class to provide basic INDI device functionality.
const char * getDeviceName() const
INDI::PropertyText getText(const char *name) const
virtual bool ISSnoopDevice(XMLEle *root)
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
virtual bool initProperties()
Initialize properties initial state and value. The child class must implement this function.
virtual bool ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
Process the client newBLOB command.
void addDebugControl()
Add Debug control to the driver.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process the client newSwitch command.
void setDeviceName(const char *name)
void setState(IPState state)
const char * getDeviceName() const
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void setLabel(const char *label)
bool isNameMatch(const char *otherName) const
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
void fill(const char *device, const char *name, const char *label, const char *group, IPState state)
bool update(const double values[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, double timeout, IPState state)
bool update(const char *const texts[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
Provides generic container for INDI properties.
INDI::PropertyViewText * getText() const
bool isNameMatch(const char *otherName) const
INDI_PROPERTY_TYPE getType() const
virtual void updateProperty(INDI::Property property) override
Emmited when a new property value arrives from INDI server.
static const std::string DEVICE_NAME
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
virtual const char * getDefaultName() override
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
virtual void serverConnected() override
Emmited when the server is connected.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual void newDevice(INDI::BaseDevice baseDevice) override
Emmited when a new device is created from INDI server.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool Disconnect() override
Disconnect from device.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual void serverDisconnected(int exit_code) override
Emmited when the server gets disconnected.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool ISSnoopDevice(XMLEle *root) override
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
virtual void newProperty(INDI::Property property) override
Emmited when a new property is created for an INDI driver.
virtual bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
virtual bool ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) override
Process the client newBLOB command.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
#define LOGF_DEBUG(fmt,...)
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
const char * CONNECTION
Connect to and disconnect from device.