Instrument Neutral Distributed Interface INDI 2.2.5
si_efs.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 Copyright(c) 2019 Jasem Mutlaq. All rights reserved.
3
4 Starlight Instruments EFS Focuser
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License version 2 as published by the Free Software Foundation.
9 .
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14 .
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*******************************************************************************/
20
21#include "si_efs.h"
22
23#include <cmath>
24#include <cstring>
25#include <memory>
26
27#define FOCUS_SETTINGS_TAB "Settings"
28
29static std::unique_ptr<SIEFS> siefs(new SIEFS());
30
31const std::map<SIEFS::SI_COMMANDS, std::string> SIEFS::CommandsMap =
32{
33 {SIEFS::SI_NOOP, "No Operation"},
34 {SIEFS::SI_IN, "Moving Inwards"},
35 {SIEFS::SI_OUT, "Moving Outwards"},
36 {SIEFS::SI_GOTO, "Goto"},
37 {SIEFS::SI_SET_POS, "Set Position"},
38 {SIEFS::SI_MAX_POS, "Set Max Position"},
39 {SIEFS::SI_FAST_IN, "Fast In"},
40 {SIEFS::SI_FAST_OUT, "Fast Out"},
41 {SIEFS::SI_HALT, "Halt"},
42 {SIEFS::SI_MOTOR_POLARITY, "Motor Polarity"},
43};
44
45const std::map<SIEFS::SI_MOTOR, std::string> SIEFS::MotorMap =
46{
47 {SIEFS::SI_NOT_MOVING, "Idle"},
48 {SIEFS::SI_MOVING_IN, "Moving Inwards"},
49 {SIEFS::SI_MOVING_OUT, "Moving Outwards"},
50 {SIEFS::SI_LOCKED, "Locked"},
51};
52
64
66{
67 if (isSimulation())
68 {
70 return true;
71 }
72
73 handle = hid_open(0x04D8, 0xF056, nullptr);
74
75 if (handle == nullptr)
76 {
77 LOG_ERROR("No SIEFS focuser found.");
78 return false;
79 }
80 else
81 {
82 uint32_t maximumPosition = 0;
83 bool rc = getMaxPosition(&maximumPosition);
84 if (rc)
85 {
86 FocusMaxPosNP[0].setValue(maximumPosition);
87
88 FocusAbsPosNP[0].setMin(0);
89 FocusAbsPosNP[0].setMax(FocusMaxPosNP[0].getValue());
90 FocusAbsPosNP[0].setStep(FocusMaxPosNP[0].getValue() / 50.0);
91
92 FocusSyncNP[0].setMin(0);
93 FocusSyncNP[0].setMax(FocusMaxPosNP[0].getValue());
94 FocusSyncNP[0].setStep(FocusMaxPosNP[0].getValue() / 50.0);
95
96 FocusRelPosNP[0].setMax(FocusMaxPosNP[0].getValue() / 2);
97 FocusRelPosNP[0].setStep(FocusMaxPosNP[0].getValue() / 100.0);
98 FocusRelPosNP[0].setMin(0);
99 }
100
101 bool reversed = isReversed();
106 }
107
108 return (handle != nullptr);
109}
110
112{
113 if (isSimulation() == false)
114 {
115 hid_close(handle);
116 hid_exit();
117 }
118
119 return true;
120}
121
123{
124 return "SI EFS";
125}
126
128{
130
132
133 return true;
134}
135
137{
138 if (!isConnected())
139 return;
140
141 uint32_t currentTicks = 0;
142
143 bool rc = getAbsPosition(&currentTicks);
144
145 if (rc)
146 FocusAbsPosNP[0].setValue(currentTicks);
147
148 getStatus();
149
151 {
152 if (isSimulation())
153 {
154 if (FocusAbsPosNP[0].getValue() < targetPosition)
155 simPosition += 500;
156 else
157 simPosition -= 500;
158
159 if (std::abs(simPosition - static_cast<int32_t>(targetPosition)) < 500)
160 {
161 FocusAbsPosNP[0].setValue(targetPosition);
162 simPosition = FocusAbsPosNP[0].getValue();
163 m_Motor = SI_NOT_MOVING;
164 }
165
166 FocusAbsPosNP[0].setValue(simPosition);
167 }
168
169 if (m_Motor == SI_NOT_MOVING && targetPosition == FocusAbsPosNP[0].getValue())
170 {
172 {
175 }
176
178 LOG_DEBUG("Focuser reached target position.");
179 }
180 }
181
183
185}
186
187IPState SIEFS::MoveAbsFocuser(uint32_t targetTicks)
188{
189 bool rc = setAbsPosition(targetTicks);
190
191 if (!rc)
192 return IPS_ALERT;
193
194 targetPosition = targetTicks;
195
196 rc = sendCommand(SI_GOTO);
197
198 if (!rc)
199 return IPS_ALERT;
200
202
203 return IPS_BUSY;
204}
205
207{
208 int direction = (dir == FOCUS_INWARD) ? -1 : 1;
209 int reversed = (FocusReverseSP[INDI_ENABLED].getState() == ISS_ON) ? -1 : 1;
210 int relative = static_cast<int>(ticks);
211
212 int targetAbsPosition = FocusAbsPosNP[0].getValue() + (relative * direction * reversed);
213
214 targetAbsPosition = std::min(static_cast<uint32_t>(FocusMaxPosNP[0].getValue())
215 , static_cast<uint32_t>(std::max(static_cast<int>(FocusAbsPosNP[0].getMin()), targetAbsPosition)));
216
217 return MoveAbsFocuser(targetAbsPosition);
218}
219
220bool SIEFS::setPosition(uint32_t ticks, uint8_t cmdCode)
221{
222 int rc = 0;
223 uint8_t command[3];
224 uint8_t response[3];
225
226 // 20 bit resolution position. 4 high bits + 16 lower bits
227
228 // Send 4 high bits first
229 command[0] = cmdCode + 8;
230 command[1] = (ticks & 0x40000) >> 16;
231
232 LOGF_DEBUG("Set %s Position (%ld)", cmdCode == 0x20 ? "Absolute" : "Maximum", ticks);
233 LOGF_DEBUG("CMD <%02X %02X>", command[0], command[1]);
234
235 if (isSimulation())
236 rc = 2;
237 else
238 rc = hid_write(handle, command, 2);
239
240 if (rc < 0)
241 {
242 LOGF_ERROR("setPosition: Error writing to device (%s)", hid_error(handle));
243 return false;
244 }
245
246 if (isSimulation())
247 {
248 rc = 2;
249 response[0] = cmdCode + 8;
250 response[1] = command[1];
251 }
252 else
253 rc = hid_read_timeout(handle, response, 2, SI_TIMEOUT);
254
255 if (rc < 0)
256 {
257 LOGF_ERROR("setPosition: Error reading from device (%s)", hid_error(handle));
258 return false;
259 }
260
261 LOGF_DEBUG("RES <%02X %02X>", response[0], response[1]);
262
263 // Send lower 16 bit
264 command[0] = cmdCode;
265 // Low Byte
266 command[1] = ticks & 0xFF;
267 // High Byte
268 command[2] = (ticks & 0xFF00) >> 8;
269
270 LOGF_DEBUG("CMD <%02X %02X %02X>", command[0], command[1], command[2]);
271
272 if (isSimulation())
273 rc = 3;
274 else
275 rc = hid_write(handle, command, 3);
276
277 if (rc < 0)
278 {
279 LOGF_ERROR("setPosition: Error writing to device (%s)", hid_error(handle));
280 return false;
281 }
282
283 if (isSimulation())
284 {
285 rc = 3;
286 response[0] = command[0];
287 response[1] = command[1];
288 response[2] = command[2];
289 }
290 else
291 rc = hid_read_timeout(handle, response, 3, SI_TIMEOUT);
292
293 if (rc < 0)
294 {
295 LOGF_ERROR("setPosition: Error reading from device (%s)", hid_error(handle));
296 return false;
297 }
298
299 LOGF_DEBUG("RES <%02X %02X %02X>", response[0], response[1], response[2]);
300
301 targetPosition = ticks;
302
303 // TODO add checking later
304 return true;
305}
306
307bool SIEFS::getPosition(uint32_t *ticks, uint8_t cmdCode)
308{
309 int rc = 0;
310 uint32_t pos = 0;
311 uint8_t command[1] = {0};
312 uint8_t response[3] = {0};
313
314 // 20 bit resolution position. 4 high bits + 16 lower bits
315
316 // Get 4 high bits first
317 command[0] = cmdCode + 8;
318
319 LOGF_DEBUG("Get %s Position (High 4 bits)", cmdCode == 0x21 ? "Absolute" : "Maximum");
320 LOGF_DEBUG("CMD <%02X>", command[0]);
321
322 if (isSimulation())
323 rc = 2;
324 else
325 rc = hid_write(handle, command, 1);
326
327 if (rc < 0)
328 {
329 LOGF_ERROR("getPosition: Error writing to device (%s)", hid_error(handle));
330 return false;
331 }
332
333 if (isSimulation())
334 {
335 rc = 2;
336 response[0] = command[0];
337 response[1] = simPosition >> 16;
338 }
339 else
340 rc = hid_read_timeout(handle, response, 2, SI_TIMEOUT);
341
342 if (rc < 0)
343 {
344 LOGF_ERROR("getPosition: Error reading from device (%s)", hid_error(handle));
345 return false;
346 }
347
348 LOGF_DEBUG("RES <%02X %02X>", response[0], response[1]);
349
350 // Store 4 high bits part of a 20 bit number
351 pos = response[1] << 16;
352
353 // Get 16 lower bits
354 command[0] = cmdCode;
355
356 LOGF_DEBUG("Get %s Position (Lower 16 bits)", cmdCode == 0x21 ? "Absolute" : "Maximum");
357 LOGF_DEBUG("CMD <%02X>", command[0]);
358
359 if (isSimulation())
360 rc = 1;
361 else
362 rc = hid_write(handle, command, 1);
363
364 if (rc < 0)
365 {
366 LOGF_ERROR("getPosition: Error writing to device (%s)", hid_error(handle));
367 return false;
368 }
369
370 if (isSimulation())
371 {
372 rc = 3;
373 response[0] = command[0];
374 response[1] = simPosition & 0xFF;
375 response[2] = (simPosition & 0xFF00) >> 8;
376 }
377 else
378 rc = hid_read_timeout(handle, response, 3, SI_TIMEOUT);
379
380 if (rc < 0)
381 {
382 LOGF_ERROR("getPosition: Error reading from device (%s)", hid_error(handle));
383 return false;
384 }
385
386 LOGF_DEBUG("RES <%02X %02X %02X>", response[0], response[1], response[2]);
387
388 // Res[1] is lower byte and Res[2] is high byte. Combine them and add them to ticks.
389 pos |= response[1] | response[2] << 8;
390
391 *ticks = pos;
392
393 LOGF_DEBUG("%s Position: %ld", cmdCode == 0x21 ? "Absolute" : "Maximum", pos);
394
395 return true;
396}
397
398bool SIEFS::setAbsPosition(uint32_t ticks)
399{
400 return setPosition(ticks, 0x20);
401}
402
403bool SIEFS::getAbsPosition(uint32_t *ticks)
404{
405 return getPosition(ticks, 0x21);
406}
407
408bool SIEFS::setMaxPosition(uint32_t ticks)
409{
410 return setPosition(ticks, 0x22);
411}
412
413bool SIEFS::getMaxPosition(uint32_t *ticks)
414{
415 return getPosition(ticks, 0x23);
416}
417
418bool SIEFS::sendCommand(SI_COMMANDS targetCommand)
419{
420 int rc = 0;
421 uint8_t command[2] = {0};
422 uint8_t response[3] = {0};
423
424 command[0] = 0x10;
425 command[1] = targetCommand;
426
427 LOGF_DEBUG("CMD <%02X %02X>", command[0], command[1]);
428
429 if (isSimulation())
430 rc = 2;
431 else
432 rc = hid_write(handle, command, 2);
433
434 if (rc < 0)
435 {
436 LOGF_ERROR("setStatus: Error writing to device (%s)", hid_error(handle));
437 return false;
438 }
439
440 if (isSimulation())
441 {
442 rc = 3;
443 response[0] = command[0];
444 response[1] = 0;
445 response[2] = command[1];
446 // m_Motor = targetCommand;
447 }
448 else
449 rc = hid_read_timeout(handle, response, 3, SI_TIMEOUT);
450
451 if (rc < 0)
452 {
453 LOGF_ERROR("setStatus: Error reading from device (%s)", hid_error(handle));
454 return false;
455 }
456
457 LOGF_DEBUG("RES <%02X %02X %02X>", response[0], response[1], response[2]);
458
459 if (response[1] == 0xFF)
460 {
461 LOG_ERROR("setStatus: Invalid state change.");
462 return false;
463 }
464
465 return true;
466}
467
468bool SIEFS::getStatus()
469{
470 int rc = 0;
471 uint8_t command[1] = {0};
472 uint8_t response[2] = {0};
473
474 command[0] = 0x11;
475
476 LOGF_DEBUG("CMD <%02X>", command[0]);
477
478 if (isSimulation())
479 rc = 1;
480 else
481 rc = hid_write(handle, command, 1);
482
483 if (rc < 0)
484 {
485 LOGF_ERROR("getStatus: Error writing to device (%s)", hid_error(handle));
486 return false;
487 }
488
489 if (isSimulation())
490 {
491 rc = 2;
492 response[0] = command[0];
493 response[1] = m_Motor;
494 // Halt/SetPos is state = 0 "not moving".
495 // if (response[1] == SI_HALT || response[1] == SI_SET_POS)
496 // response[1] = 0;
497 }
498 else
499 rc = hid_read_timeout(handle, response, 2, SI_TIMEOUT);
500
501 if (rc < 0)
502 {
503 LOGF_ERROR("getStatus: Error reading from device (%s)", hid_error(handle));
504 return false;
505 }
506
507 LOGF_DEBUG("RES <%02X %02X>", response[0], response[1]);
508
509 m_Motor = static_cast<SI_MOTOR>(response[1]);
510 if (MotorMap.count(m_Motor) > 0)
511 LOGF_DEBUG("State: %s", MotorMap.at(m_Motor).c_str());
512 else
513 {
514 LOGF_WARN("Warning: Unknown status (%d)", response[1]);
515 return false;
516 }
517
518 return true;
519}
520
522{
523 return sendCommand(SI_HALT);
524}
525
526bool SIEFS::SyncFocuser(uint32_t ticks)
527{
528 bool rc = setAbsPosition(ticks);
529
530 if (!rc)
531 return false;
532
533 simPosition = ticks;
534
535 rc = sendCommand(SI_SET_POS);
536
537 return rc;
538}
539
541{
542 bool rc = setAbsPosition(ticks);
543
544 if (!rc)
545 return false;
546
547 rc = sendCommand(SI_MAX_POS);
548
549 return rc;
550}
551
552bool SIEFS::ReverseFocuser(bool enabled)
553{
554 return setReversed(enabled);
555}
556
557bool SIEFS::setReversed(bool enabled)
558{
559 int rc = 0;
560 uint8_t command[2] = {0};
561 uint8_t response[2] = {0};
562
563 command[0] = SI_MOTOR_POLARITY;
564 command[1] = enabled ? 1 : 0;
565
566 LOGF_DEBUG("CMD <%02X> <%02X>", command[0], command[1]);
567
568 if (isSimulation())
569 rc = 1;
570 else
571 rc = hid_write(handle, command, 2);
572
573 if (rc < 0)
574 {
575 LOGF_ERROR("setReversed: Error writing to device (%s)", hid_error(handle));
576 return false;
577 }
578
579 if (isSimulation())
580 {
581 rc = 2;
582 response[0] = command[0];
583 // Normal
584 response[1] = 0;
585 }
586 else
587 rc = hid_read_timeout(handle, response, 2, SI_TIMEOUT);
588
589 if (rc < 0)
590 {
591 LOGF_ERROR("setReversed: Error reading from device (%s)", hid_error(handle));
592 return false;
593 }
594
595 LOGF_DEBUG("RES <%02X %02X>", response[0], response[1]);
596
597 return true;
598}
599
600bool SIEFS::isReversed()
601{
602 int rc = 0;
603 uint8_t command[1] = {0};
604 uint8_t response[2] = {0};
605
606 command[0] = SI_MOTOR_POLARITY;
607
608 LOGF_DEBUG("CMD <%02X>", command[0]);
609
610 if (isSimulation())
611 rc = 1;
612 else
613 rc = hid_write(handle, command, 1);
614
615 if (rc < 0)
616 {
617 LOGF_ERROR("setReversed: Error writing to device (%s)", hid_error(handle));
618 return false;
619 }
620
621 if (isSimulation())
622 {
623 rc = 2;
624 response[0] = command[0];
625 // Normal
626 response[1] = 0;
627 }
628 else
629 rc = hid_read_timeout(handle, response, 2, SI_TIMEOUT);
630
631 if (rc < 0)
632 {
633 LOGF_ERROR("setReversed: Error reading from device (%s)", hid_error(handle));
634 return false;
635 }
636
637 LOGF_DEBUG("RES <%02X %02X>", response[0], response[1]);
638
639 return response[1] != 0;
640}
bool isConnected() const
void addSimulationControl()
Add Simulation control to the driver.
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
bool isSimulation() const
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
INDI::PropertyNumber FocusRelPosNP
INDI::PropertySwitch FocusReverseSP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INDI::PropertyNumber FocusSyncNP
INDI::PropertyNumber FocusMaxPosNP
INDI::PropertyNumber FocusAbsPosNP
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
void setSupportedConnections(const uint8_t &value)
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
Definition si_efs.h:34
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition si_efs.cpp:136
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
Definition si_efs.cpp:187
virtual bool SetFocuserMaxPosition(uint32_t ticks) override
SetFocuserMaxPosition Update focuser maximum position. It only updates the PresetNP property limits.
Definition si_efs.cpp:540
@ SI_NOOP
Definition si_efs.h:38
@ SI_MOTOR_POLARITY
Definition si_efs.h:47
@ SI_FAST_OUT
Definition si_efs.h:45
@ SI_OUT
Definition si_efs.h:40
@ SI_FAST_IN
Definition si_efs.h:44
@ SI_HALT
Definition si_efs.h:46
@ SI_SET_POS
Definition si_efs.h:42
@ SI_IN
Definition si_efs.h:39
@ SI_MAX_POS
Definition si_efs.h:43
@ SI_GOTO
Definition si_efs.h:41
virtual bool ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
Definition si_efs.cpp:552
virtual bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
Definition si_efs.cpp:526
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
Definition si_efs.cpp:521
SIEFS()
Definition si_efs.cpp:53
virtual bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
Definition si_efs.cpp:65
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
Definition si_efs.cpp:127
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
Definition si_efs.cpp:206
virtual bool Disconnect() override
Disconnect from device.
Definition si_efs.cpp:111
SI_MOTOR
Definition si_efs.h:52
@ SI_MOVING_IN
Definition si_efs.h:53
@ SI_MOVING_OUT
Definition si_efs.h:54
@ SI_NOT_MOVING
Definition si_efs.h:52
@ SI_LOCKED
Definition si_efs.h:55
const char * getDefaultName() override
Definition si_efs.cpp:122
hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
Open a HID device using a Vendor ID (VID), Product ID (PID) and optionally a serial number.
Definition hid_libusb.c:612
int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
Read an Input report from a HID device with timeout.
Definition hid_libusb.c:997
int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
Write an Output report to a HID device.
Definition hid_libusb.c:929
void HID_API_EXPORT hid_close(hid_device *dev)
Close a HID device.
HID_API_EXPORT const wchar_t *HID_API_CALL hid_error(hid_device *dev)
Get a string describing the last error which occurred.
int HID_API_EXPORT hid_exit(void)
Finalize the HIDAPI library.
Definition hid_libusb.c:407
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
IPState
Property state.
Definition indiapi.h:158
@ IPS_BUSY
Definition indiapi.h:161
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_OK
Definition indiapi.h:160
#define LOG_DEBUG(txt)
Definition indilogger.h:75
#define LOGF_WARN(fmt,...)
Definition indilogger.h:81
#define LOGF_DEBUG(fmt,...)
Definition indilogger.h:83
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition indilogger.h:72
#define LOGF_ERROR(fmt,...)
Definition indilogger.h:80
#define currentTicks
Definition robofocus.cpp:38