Instrument Neutral Distributed Interface INDI  2.0.2
celestronauxpacket.cpp
Go to the documentation of this file.
1 /*
2  Celestron Focuser for SCT and EDGEHD
3 
4  Copyright (C) 2019 Chris Rowland
5  Copyright (C) 2019 Jasem Mutlaq (mutlaqja@ikarustech.com)
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public
9  License as published by the Free Software Foundation; either
10  version 2.1 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License along with this library; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 
21 */
22 
23 
24 #include "celestronauxpacket.h"
25 #include "indicom.h"
26 #include "indilogger.h"
27 
28 #include <termios.h>
29 #include <stdio.h>
30 
31 #define SHORT_TIMEOUT 2
32 
33 namespace Aux
34 {
35 // holds the string generated by toHexStr
36 char debugStr[301];
37 
38 // free function to return the contents of a buffer as a string containing a series of hex numbers
39 char * toHexStr(buffer data)
40 {
41  int sz = (int)data.size();
42  if (sz > 100)
43  sz = 100;
44  for (int i = 0; i < sz; i++)
45  {
46  snprintf(&debugStr[i * 3], 301, "%02X ", data[i]);
47  }
48  return debugStr;
49 }
50 
51 std::string Communicator::Device;
52 
53 Packet::Packet(Target source, Target destination, Command command, buffer data)
54 {
55  this->command = command;
56  this->source = source;
57  this->destination = destination;
58  this->data = data;
59  this->length = data.size() + 3;
60 }
61 
63 {
64  buff.resize(this->length + 3);
65  buff[0] = AUX_HDR;
66  buff[1] = length;
67  buff[2] = source;
68  buff[3] = destination;
69  buff[4] = command;
70  for (uint32_t i = 0; i < data.size(); i++)
71  {
72  buff[5 + i] = data[i];
73  }
74 
75  buff.back() = checksum(buff);
76 
77  DEBUGFDEVICE(Communicator::Device.c_str(), INDI::Logger::DBG_DEBUG, "fillBuffer <%s>", toHexStr(buff));
78 }
79 
80 bool Packet::Parse(buffer packet)
81 {
82  if (packet.size() < 6) // must contain header, len, src, dest, cmd and checksum at least
83  {
84  DEBUGDEVICE(Communicator::Device.c_str(), INDI::Logger::DBG_ERROR, "Parse size < 6");
85  return false;
86  }
87  if (packet[0] != AUX_HDR)
88  {
89  DEBUGDEVICE(Communicator::Device.c_str(), INDI::Logger::DBG_ERROR, "Parse [0] |= 0x3b");
90  return false;
91  }
92 
93  length = packet[1];
94  // length must be correct
95  if (packet.size() != length + 3)
96  {
97  DEBUGFDEVICE(Communicator::Device.c_str(), INDI::Logger::DBG_ERROR, "Parse size %i |= length+3 %i",
98  packet.size(), length + 3);
99  return false;
100  }
101 
102  source = static_cast<Target>(packet[2]);
103  destination = static_cast<Target>(packet[3]);
104  command = static_cast<Command>(packet[4]);
105  data = buffer(packet.begin() + 5, packet.end() - 1);
106 
107  uint8_t cs = checksum(packet);
108  uint8_t cb = packet[length + 2];
109 
110  if (cs != cb)
111  {
112  DEBUGFDEVICE(Communicator::Device.c_str(), INDI::Logger::DBG_WARNING, "Parse checksum error cs %i |= cb %i", cs, cb);
113  }
114  return cb == cs;
115 }
116 
117 uint8_t Packet::checksum(buffer packet)
118 {
119  int cs = 0;
120  for (int i = 1; i < packet[1] + 2; i++)
121  {
122  cs += packet[i];
123  }
124  return (-cs & 0xff);
125 }
126 
130 
132 {
133  this->source = Target::NEX_REMOTE;
134 }
135 
137 {
138  this->source = source;
139 }
140 
141 bool Communicator::sendPacket(int portFD, Target dest, Command cmd, buffer data)
142 {
143  Packet pkt(source, dest, cmd, data);
144 
145  buffer txbuff;
146  pkt.FillBuffer(txbuff);
147  int ns;
148 
149  int ttyrc = 0;
150  tcflush(portFD, TCIOFLUSH);
151  if ( (ttyrc = tty_write(portFD, reinterpret_cast<const char *>(txbuff.data()), txbuff.size(), &ns)) != TTY_OK)
152  {
153  char errmsg[MAXRBUF];
154  tty_error_msg(ttyrc, errmsg, MAXRBUF);
155  DEBUGFDEVICE(Communicator::Device.c_str(), INDI::Logger::DBG_ERROR, "sendPacket fail tty %i %s, ns %i", ttyrc, errmsg, ns);
156  return false;
157  }
158  return true;
159 }
160 
161 bool Communicator::readPacket(int portFD, Packet &reply)
162 {
163  char rxbuf[] = {0};
164  int nr = 0, ttyrc = 0;
165  // look for header
166  while(rxbuf[0] != Packet::AUX_HDR)
167  {
168  if ( (ttyrc = tty_read(portFD, rxbuf, 1, SHORT_TIMEOUT, &nr) != TTY_OK))
169  {
170  char errmsg[MAXRBUF];
171  tty_error_msg(ttyrc, errmsg, MAXRBUF);
173  "readPacket fail read hdr tty %i %s, nr %i", ttyrc, errmsg, nr);
174  return false; // read failure is instantly fatal
175  }
176  }
177  // get length
178  if (tty_read(portFD, rxbuf, 1, SHORT_TIMEOUT, &nr) != TTY_OK)
179  {
180  char errmsg[MAXRBUF];
181  tty_error_msg(ttyrc, errmsg, MAXRBUF);
182  DEBUGFDEVICE(Communicator::Device.c_str(), INDI::Logger::DBG_ERROR, "readPacket fail read len tty %i %s, ns %i", ttyrc,
183  errmsg, nr);
184  return false;
185  }
186 
187  int len = rxbuf[0];
188  buffer packet(2);
189  packet[0] = Packet::AUX_HDR;
190  packet[1] = len;
191 
192  // get source, destination, command, data and checksum
193  char rxdata[MAXRBUF] = {0};
194  if ( (ttyrc = tty_read(portFD, rxdata, len + 1, SHORT_TIMEOUT, &nr) != TTY_OK))
195  {
196  char errmsg[MAXRBUF];
197  tty_error_msg(ttyrc, errmsg, MAXRBUF);
198  DEBUGFDEVICE(Communicator::Device.c_str(), INDI::Logger::DBG_ERROR, "readPacket fail data tty %i %s, nr %i", ttyrc, errmsg,
199  nr);
200  return false;
201  }
202 
203  packet.insert(packet.end(), rxdata, rxdata + len + 1);
204 
205  DEBUGFDEVICE(Communicator::Device.c_str(), INDI::Logger::DBG_DEBUG, "RES <%s>", toHexStr(packet));
206 
207  return reply.Parse(packet);
208 }
209 
210 // send command with data and reply
211 bool Communicator::sendCommand(int portFD, Target dest, Command cmd, buffer data, buffer &reply)
212 {
213  int num_tries = 0;
214 
215  while (num_tries++ < 3)
216  {
217  if (!sendPacket(portFD, dest, cmd, data))
218  return false; // failure to send is fatal
219 
220  Packet pkt;
221  if (!readPacket(portFD, pkt))
222  continue; // try again
223 
224  // check the packet is the one we want
225  if (pkt.command != cmd || pkt.destination != Target::APP || pkt.source != dest)
226  {
228  "sendCommand pkt.command %i cmd %i, pkt.destination %i pkt.source %i dest %i",
229  pkt.command, cmd, pkt.destination, pkt.source, dest);
230  continue; // wrong packet, try again
231  }
232 
233  reply = pkt.data;
234  return true;
235  }
236  return false;
237 }
238 
239 // send command with reply but no data
240 bool Communicator::sendCommand(int portFD, Target dest, Command cmd, buffer &reply)
241 {
242  buffer data(0);
243  return sendCommand(portFD, dest, cmd, data, reply);
244 }
245 
246 // send command with data but no reply
247 bool Communicator::commandBlind(int portFD, Target dest, Command cmd, buffer data)
248 {
249  buffer reply;
250  return sendCommand(portFD, dest, cmd, data, reply);
251 }
252 
253 }
#define SHORT_TIMEOUT
static std::string Device
bool commandBlind(int port, Target dest, Command cmd, buffer data)
bool sendCommand(int port, Target dest, Command cmd, buffer data, buffer &reply)
The Packet class handles low-level communication with the Celestron devices.
static const uint8_t AUX_HDR
void FillBuffer(buffer &buf)
bool Parse(buffer buf)
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:424
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:482
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
#define DEBUGDEVICE(device, priority, msg)
Definition: indilogger.h:60
#define DEBUGFDEVICE(device, priority, msg,...)
Definition: indilogger.h:61
#define MAXRBUF
Definition: indiserver.cpp:102
Command
The Command enum includes all the command types sent to the various devices (motor,...
char debugStr[301]
std::vector< uint8_t > buffer
Target
The Target enum Specifies the target device of the command.
char * toHexStr(buffer data)
__u8 cmd[4]
Definition: pwc-ioctl.h:2