Instrument Neutral Distributed Interface INDI  1.9.5
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, errmsg, nr);
183  return false;
184  }
185 
186  int len = rxbuf[0];
187  buffer packet(2);
188  packet[0] = Packet::AUX_HDR;
189  packet[1] = len;
190 
191  // get source, destination, command, data and checksum
192  char rxdata[MAXRBUF] = {0};
193  if ( (ttyrc = tty_read(portFD, rxdata, len + 1, SHORT_TIMEOUT, &nr) != TTY_OK))
194  {
195  char errmsg[MAXRBUF];
196  tty_error_msg(ttyrc, errmsg, MAXRBUF);
197  DEBUGFDEVICE(Communicator::Device.c_str(), INDI::Logger::DBG_ERROR, "readPacket fail data tty %i %s, nr %i", ttyrc, errmsg, nr);
198  return false;
199  }
200 
201  packet.insert(packet.end(), rxdata, rxdata + len + 1);
202 
203  DEBUGFDEVICE(Communicator::Device.c_str(), INDI::Logger::DBG_DEBUG, "RES <%s>", toHexStr(packet));
204 
205  return reply.Parse(packet);
206 }
207 
208 // send command with data and reply
209 bool Communicator::sendCommand(int portFD, Target dest, Command cmd, buffer data, buffer &reply)
210 {
211  int num_tries = 0;
212 
213  while (num_tries++ < 3)
214  {
215  if (!sendPacket(portFD, dest, cmd, data))
216  return false; // failure to send is fatal
217 
218  Packet pkt;
219  if (!readPacket(portFD, pkt))
220  continue; // try again
221 
222  // check the packet is the one we want
223  if (pkt.command != cmd || pkt.destination != Target::APP || pkt.source != dest)
224  {
225  DEBUGFDEVICE(Communicator::Device.c_str(), INDI::Logger::DBG_ERROR, "sendCommand pkt.command %i cmd %i, pkt.destination %i pkt.source %i dest %i",
226  pkt.command, cmd, pkt.destination, pkt.source, dest);
227  continue; // wrong packet, try again
228  }
229 
230  reply = pkt.data;
231  return true;
232  }
233  return false;
234 }
235 
236 // send command with reply but no data
237 bool Communicator::sendCommand(int portFD, Target dest, Command cmd, buffer &reply)
238 {
239  buffer data(0);
240  return sendCommand(portFD, dest, cmd, data, reply);
241 }
242 
243 // send command with data but no reply
244 bool Communicator::commandBlind(int portFD, Target dest, Command cmd, buffer data)
245 {
246  buffer reply;
247  return sendCommand(portFD, dest, cmd, data, reply);
248 }
249 
250 }
Aux::Communicator::Communicator
Communicator()
Definition: celestronauxpacket.cpp:131
Aux::debugStr
char debugStr[301]
Definition: celestronauxpacket.cpp:36
cmd
__u8 cmd[4]
Definition: pwc-ioctl.h:4
indicom.h
Implementations for common driver routines.
INDI::Logger::DBG_WARNING
@ DBG_WARNING
Definition: indilogger.h:193
Aux::toHexStr
char * toHexStr(buffer data)
Definition: celestronauxpacket.cpp:39
Aux
Definition: celestronauxpacket.cpp:33
INDI::Logger::DBG_ERROR
@ DBG_ERROR
Definition: indilogger.h:192
Aux::Packet::source
Target source
Definition: celestronauxpacket.h:115
Aux::APP
@ APP
Definition: celestronauxpacket.h:93
Aux::Communicator::commandBlind
bool commandBlind(int port, Target dest, Command cmd, buffer data)
Definition: celestronauxpacket.cpp:244
celestronauxpacket.h
DEBUGDEVICE
#define DEBUGDEVICE(device, priority, msg)
Definition: indilogger.h:60
MAXRBUF
#define MAXRBUF
Definition: indidriver.c:52
Aux::Packet::command
Command command
Definition: celestronauxpacket.h:117
tty_error_msg
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1156
INDI::Logger::DBG_DEBUG
@ DBG_DEBUG
Definition: indilogger.h:195
indilogger.h
Aux::Communicator::sendCommand
bool sendCommand(int port, Target dest, Command cmd, buffer data, buffer &reply)
Definition: celestronauxpacket.cpp:209
tty_read
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:473
Aux::Command
Command
The Command enum includes all the command types sent to the various devices (motor,...
Definition: celestronauxpacket.h:43
Aux::Packet::length
uint32_t length
Definition: celestronauxpacket.h:114
Aux::Packet::data
buffer data
Definition: celestronauxpacket.h:118
SHORT_TIMEOUT
#define SHORT_TIMEOUT
Definition: celestronauxpacket.cpp:31
tty_write
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:415
Aux::Packet::Parse
bool Parse(buffer buf)
Definition: celestronauxpacket.cpp:80
Aux::Packet::Packet
Packet()
Definition: celestronauxpacket.h:108
Aux::Packet::destination
Target destination
Definition: celestronauxpacket.h:116
Aux::Packet::AUX_HDR
static const uint8_t AUX_HDR
Definition: celestronauxpacket.h:113
Aux::Communicator::Device
static std::string Device
Definition: celestronauxpacket.h:145
Aux::Packet::FillBuffer
void FillBuffer(buffer &buf)
Definition: celestronauxpacket.cpp:62
Aux::NEX_REMOTE
@ NEX_REMOTE
Definition: celestronauxpacket.h:94
DEBUGFDEVICE
#define DEBUGFDEVICE(device, priority, msg,...)
Definition: indilogger.h:61
Aux::Communicator::source
Target source
Definition: celestronauxpacket.h:143
Aux::Packet
The Packet class handles low-level communication with the Celestron devices.
Definition: celestronauxpacket.h:105
Aux::Target
Target
The Target enum Specifies the target device of the command.
Definition: celestronauxpacket.h:84
TTY_OK
@ TTY_OK
Definition: indicom.h:94
Aux::buffer
std::vector< uint8_t > buffer
Definition: celestronauxpacket.h:38