1 /*******************************************************************************
2   Copyright(c) 2016 Radek Kaczorek  <rkaczorek AT gmail DOT com>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License version 2 as published by the Free Software Foundation.
7  .
8  This library is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  Library General Public License for more details.
12  .
13  You should have received a copy of the GNU Library General Public License
14  along with this library; see the file COPYING.LIB.  If not, write to
15  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  Boston, MA 02110-1301, USA.
17 *******************************************************************************/
18 
19 #include "quantum_wheel.h"
20 
21 #include "connectionplugins/connectionserial.h"
22 
23 #include <memory>
24 #include <cstring>
25 #include <termios.h>
26 #include <unistd.h>
27 
28 #include "indicom.h"
29 
30 #define VERSION_MAJOR 0
31 #define VERSION_MINOR 3
32 
33 #define QUANTUM_TIMEOUT 5
34 
35 std::unique_ptr<QFW> qfw(new QFW());
36 
QFW()37 QFW::QFW()
38 {
39     setDeviceName(QFW::getDefaultName());
40     setVersion(VERSION_MAJOR, VERSION_MINOR);
41     setFilterConnection(CONNECTION_SERIAL | CONNECTION_TCP);
42 }
43 
debugTriggered(bool enable)44 void QFW::debugTriggered(bool enable)
45 {
46     INDI_UNUSED(enable);
47 }
48 
simulationTriggered(bool enable)49 void QFW::simulationTriggered(bool enable)
50 {
51     INDI_UNUSED(enable);
52 }
53 
getDefaultName()54 const char *QFW::getDefaultName()
55 {
56     return (const char *)"Quantum Wheel";
57 }
58 
Handshake()59 bool QFW::Handshake()
60 {
61     if (isSimulation())
62     {
63         IDMessage(getDeviceName(), "Simulation: connected");
64         PortFD = 1;
65         return true;
66     }
67     // check serial connection
68     if (PortFD < 0 || isatty(PortFD) == 0)
69     {
70         IDMessage(getDeviceName(), "Device /dev/ttyACM0 is not available\n");
71         return false;
72     }
73     // read description
74     char cmd[10] = {"SN\r\n"};
75     char resp[255]={0};
76     if (send_command(PortFD, cmd, resp) < 2)
77         return false;
78 
79     // SN should respond SN<number>, this identifies a Quantum wheel
80     return strncmp(cmd, resp, 2) == 0;
81 }
82 
initProperties()83 bool QFW::initProperties()
84 {
85     INDI::FilterWheel::initProperties();
86     addDebugControl();
87     addSimulationControl();
88 
89     serialConnection->setDefaultPort("/dev/ttyACM0");
90 
91     FilterSlotN[0].min = 1;
92     FilterSlotN[0].max = 7;
93     CurrentFilter      = 1;
94 
95     return true;
96 }
97 
98 //bool QFW::updateProperties()
99 //{
100 //    INDI::FilterWheel::updateProperties();
101 
102 //    if (isConnected())
103 //    {
104 //        // read number of filters
105 //        char cmd[10] = {"EN\r\n"};
106 //        char resp[255]={0};
107 //        if (send_command(PortFD, cmd, resp) < 2)
108 //            return false;
109 //        int numFilters = resp[1] - '0';
110 //        //FilterNameTP->ntp = numFilters;
111 //        for (int i = 0; i < numFilters; i++)
112 //        {
113 //            sprintf(cmd, "F%1d\r\n", i);
114 //            if (send_command(PortFD, cmd, resp) < 3)
115 //                return false;
116 //            char name[64];
117 //            int n = strlen(resp);
118 //            strncpy(name, &resp[2], n - 4);
119 //            name[n] = 0;
120 //            IUFillText(&FilterNameT[i], name, name, name);
121 //        }
122 //    }
123 
124 //    return true;
125 //}
126 
ISGetProperties(const char * dev)127 void QFW::ISGetProperties(const char *dev)
128 {
129     INDI::FilterWheel::ISGetProperties(dev);
130 }
131 
QueryFilter()132 int QFW::QueryFilter()
133 {
134     return CurrentFilter;
135 }
136 
SelectFilter(int position)137 bool QFW::SelectFilter(int position)
138 {
139     // count from 0 to 6 for positions 1 to 7
140     position = position - 1;
141 
142     if (position < 0 || position > 6)
143         return false;
144 
145     if (isSimulation())
146     {
147         CurrentFilter = position + 1;
148         SelectFilterDone(CurrentFilter);
149         return true;
150     }
151 
152     // goto
153     char targetpos[255]={0};
154     char curpos[255]={0};
155     char dmp[255];
156     int err;
157     int nbytes;
158 
159     // format target position G[0-6]
160     sprintf(targetpos, "G%d\r\n ", position);
161 
162     // write command
163     //int len = strlen(targetpos);
164 
165     err = tty_write_string(PortFD, targetpos, &nbytes);
166     if (err)
167     {
168         char errmsg[255];
169         tty_error_msg(err, errmsg, MAXRBUF);
170         LOGF_ERROR("Serial write error: %s", errmsg);
171         return false;
172     }
173     //res = write(PortFD, targetpos, len);
174     dump(dmp, targetpos);
175     LOGF_DEBUG("CMD: %s", dmp);
176 
177     // format target marker P[0-6]
178     sprintf(targetpos, "P%d", position);
179 
180     // check current position
181     do
182     {
183         usleep(100 * 1000);
184         //res         = read(PortFD, curpos, 255);
185         err = tty_read_section(PortFD, curpos, '\n', QUANTUM_TIMEOUT, &nbytes);
186         if (err)
187         {
188             char errmsg[255];
189             tty_error_msg(err, errmsg, MAXRBUF);
190             LOGF_ERROR("Serial read error: %s", errmsg);
191             return false;
192         }
193         curpos[nbytes] = 0;
194         dump(dmp, curpos);
195         LOGF_DEBUG("REP: %s", dmp);
196     } while (strncmp(targetpos, curpos, 2) != 0);
197 
198     // return current position to indi
199     CurrentFilter = position + 1;
200     SelectFilterDone(CurrentFilter);
201     LOGF_DEBUG("CurrentFilter set to %d", CurrentFilter);
202 
203     return true;
204 }
205 
dump(char * buf,const char * data)206 void QFW::dump(char *buf, const char *data)
207 {
208     int i = 0;
209     int n = 0;
210     while(data[i] != 0)
211     {
212         if (isprint(data[i]))
213         {
214             buf[n] = data[i];
215             n++;
216         }
217         else
218         {
219             sprintf(buf + n, "[%02X]", data[i]);
220             n+=4;
221         }
222         i++;
223     }
224 }
225 
226 // Send a command to the mount. Return the number of bytes received or 0 if
227 // case of error
228 // commands are null terminated, replies end with /n
send_command(int fd,const char * cmd,char * resp)229 int QFW::send_command(int fd, const char* cmd, char *resp)
230 {
231     int err;
232     int nbytes = 0;
233     char errmsg[MAXRBUF];
234     int cmd_len = strlen(cmd);
235     char dmp[255];
236 
237     dump(dmp, cmd);
238     LOGF_DEBUG("CMD <%s>", dmp);
239 
240     tcflush(fd, TCIOFLUSH);
241     if ((err = tty_write(fd, cmd, cmd_len, &nbytes)) != TTY_OK)
242     {
243         tty_error_msg(err, errmsg, MAXRBUF);
244         LOGF_ERROR("Serial write error: %s", errmsg);
245         return 0;
246     }
247 
248     err = tty_read_section(fd, resp, '\n', QUANTUM_TIMEOUT, &nbytes);
249     if (err)
250     {
251         tty_error_msg(err, errmsg, MAXRBUF);
252         LOGF_ERROR("Serial read error: %s", errmsg);
253         return 0;
254     }
255 
256     resp[nbytes] = 0;
257     dump(dmp, resp);
258     LOGF_DEBUG("RES <%s>", dmp);
259     return nbytes;
260 }
261 
262