Instrument Neutral Distributed Interface INDI 2.2.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 ([email protected])
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
33namespace Aux
34{
35// holds the string generated by toHexStr
36char debugStr[301];
37
38// free function to return the contents of a buffer as a string containing a series of hex numbers
39char * 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 - 3 * i, "%02X ", data[i]);
47 }
48 return debugStr;
49}
50
51std::string Communicator::Device;
52
53Packet::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
81{
82 if (packet.size() < 6) // must contain header, len, src, dest, cmd and checksum at least
83 {
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
117uint8_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
135
137{
138 this->source = source;
139}
140
141bool 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
161bool Communicator::readPacket(int portFD, Packet &reply)
162{
163 char rxbuf[1] = {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;
189 packet.reserve(2 + len + 1);
190 packet.push_back(Packet::AUX_HDR);
191 packet.push_back(len);
192
193 // get source, destination, command, data and checksum
194 char rxdata[MAXRBUF] = {0};
195 if ( (ttyrc = tty_read(portFD, rxdata, len + 1, SHORT_TIMEOUT, &nr) != TTY_OK))
196 {
197 char errmsg[MAXRBUF];
198 tty_error_msg(ttyrc, errmsg, MAXRBUF);
199 DEBUGFDEVICE(Communicator::Device.c_str(), INDI::Logger::DBG_ERROR, "readPacket fail data tty %i %s, nr %i", ttyrc, errmsg,
200 nr);
201 return false;
202 }
203
204 packet.insert(packet.end(), rxdata, rxdata + len + 1);
205
207
208 return reply.Parse(packet);
209}
210
211// send command with data and reply
212bool Communicator::sendCommand(int portFD, Target dest, Command cmd, buffer data, buffer &reply)
213{
214 int num_tries = 0;
215
216 while (num_tries++ < 3)
217 {
218 if (!sendPacket(portFD, dest, cmd, data))
219 return false; // failure to send is fatal
220
221 Packet pkt;
222 if (!readPacket(portFD, pkt))
223 continue; // try again
224
225 // check the packet is the one we want
226 if (pkt.command != cmd || pkt.destination != Target::APP || pkt.source != dest)
227 {
229 "sendCommand pkt.command %i cmd %i, pkt.destination %i pkt.source %i dest %i",
230 pkt.command, cmd, pkt.destination, pkt.source, dest);
231 continue; // wrong packet, try again
232 }
233
234 reply = pkt.data;
235 return true;
236 }
237 return false;
238}
239
240// send command with reply but no data
241bool Communicator::sendCommand(int portFD, Target dest, Command cmd, buffer &reply)
242{
243 buffer data(0);
244 return sendCommand(portFD, dest, cmd, data, reply);
245}
246
247// send command with data but no reply
249{
250 buffer reply;
251 return sendCommand(portFD, dest, cmd, data, reply);
252}
253
254}
#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.
void FillBuffer(buffer &buf)
bool Parse(buffer buf)
static constexpr uint8_t AUX_HDR
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition indicom.c:418
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition indicom.c:548
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition indicom.c:1243
Implementations for common driver routines.
@ TTY_OK
Definition indicom.h:54
#define MAXRBUF
Definition indidriver.c:52
#define DEBUGDEVICE(device, priority, msg)
Definition indilogger.h:60
#define DEBUGFDEVICE(device, priority, msg,...)
Definition indilogger.h:61
Command
The Command enum includes all the command types sent to the various devices (motor,...
char debugStr[301]
char * toHexStr(buffer data)
std::vector< uint8_t > buffer
Target
The Target enum Specifies the target device of the command.
uint8_t cmd[4]
Definition pwc-ioctl.h:2