Instrument Neutral Distributed Interface INDI 2.2.5
mxhd_serial.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 Copyright(c) 2026 Makoto Kasahara All rights reserved.
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 LICENSE. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
17*******************************************************************************/
18#include "mxhd_serial.h"
19
20#include <indicom.h>
21
22#include <cerrno>
23#include <cstring>
24#include <termios.h>
25#include <unistd.h>
26
28
29static void setTTYError(int rc, std::string &err)
30{
31 char msg[1024] = {0};
32 tty_error_msg(rc, msg, sizeof(msg));
33 err = msg;
34}
35
36static void splitTimeoutMs(int timeoutMs, long &seconds, long &microseconds)
37{
38 if (timeoutMs < 0)
39 timeoutMs = 0;
40
41 seconds = timeoutMs / 1000;
42 microseconds = static_cast<long>(timeoutMs % 1000) * 1000L;
43}
44
45bool MXHDSerial::discardInput(std::string &err)
46{
47 if (::tcflush(m_fd, TCIFLUSH) != 0)
48 {
49 err = std::string("tcflush(TCIFLUSH) failed: ") + std::strerror(errno);
50 return false;
51 }
52 return true;
53}
54
55bool MXHDSerial::writeRaw(const void *data, size_t len, std::string &err)
56{
57 int nbytesWritten = 0;
58 const auto *buffer = static_cast<const char *>(data);
59 const int rc = tty_write(m_fd, buffer, static_cast<int>(len), &nbytesWritten);
60 if (rc != TTY_OK)
61 {
62 setTTYError(rc, err);
63 return false;
64 }
65
66 if (static_cast<size_t>(nbytesWritten) != len)
67 {
68 err = "short write";
69 return false;
70 }
71
72 return true;
73}
74
75bool MXHDSerial::writeString(const std::string &s, std::string &err)
76{
77 int nbytesWritten = 0;
78 const int rc = tty_write_string(m_fd, s.c_str(), &nbytesWritten);
79 if (rc != TTY_OK)
80 {
81 setTTYError(rc, err);
82 return false;
83 }
84
85 if (nbytesWritten != static_cast<int>(s.size()))
86 {
87 err = "short write";
88 return false;
89 }
90
91 return true;
92}
93
94bool MXHDSerial::readExact(std::vector<uint8_t> &out, size_t n, int timeoutMs, std::string &err)
95{
96 out.clear();
97 out.resize(n);
98
99 long seconds = 0;
100 long microseconds = 0;
101 splitTimeoutMs(timeoutMs, seconds, microseconds);
102
103 int nbytesRead = 0;
104 const int rc = tty_read_expanded(m_fd, reinterpret_cast<char *>(out.data()), static_cast<int>(n), seconds, microseconds,
105 &nbytesRead);
106 if (rc != TTY_OK)
107 {
108 setTTYError(rc, err);
109 return false;
110 }
111
112 if (static_cast<size_t>(nbytesRead) != n)
113 {
114 err = "short read";
115 return false;
116 }
117
118 return true;
119}
120
121bool MXHDSerial::readChar(char &ch, int timeoutMs, std::string &err)
122{
123 uint8_t byte = 0;
124 std::vector<uint8_t> buf;
125 if (!readExact(buf, 1, timeoutMs, err))
126 return false;
127 byte = buf[0];
128 ch = static_cast<char>(byte);
129 return true;
130}
131
132bool MXHDSerial::readHashTerminated(std::string &out, int timeoutMs, std::string &err)
133{
134 out.clear();
135
136 long seconds = 0;
137 long microseconds = 0;
138 splitTimeoutMs(timeoutMs, seconds, microseconds);
139
140 char buffer[1024] = {0};
141 int nbytesRead = 0;
142 const int rc = tty_nread_section_expanded(m_fd, buffer, sizeof(buffer), '#', seconds, microseconds, &nbytesRead);
143 if (rc != TTY_OK)
144 {
145 setTTYError(rc, err);
146 return false;
147 }
148
149 out.assign(buffer, nbytesRead);
150 if (!out.empty() && out.back() == '#')
151 out.pop_back();
152
153 return true;
154}
155
156bool MXHDSerial::queryHash(const std::string &cmd, std::string &response, int timeoutMs, std::string &err)
157{
158 // Drain stale bytes first. This is important for mixed command patterns.
159 if (!discardInput(err))
160 return false;
161 if (!writeString(cmd, err))
162 return false;
163 return readHashTerminated(response, timeoutMs, err);
164}
165
166bool MXHDSerial::queryAck(const std::string &cmd, char &ack, int timeoutMs, std::string &err)
167{
168 if (!discardInput(err))
169 return false;
170 if (!writeString(cmd, err))
171 return false;
172 if (!readChar(ack, timeoutMs, err))
173 return false;
174 return true;
175}
176
177bool MXHDSerial::queryStatus3(const std::string &cmd, uint8_t &b1, uint8_t &b2, uint8_t &b3, int timeoutMs, std::string &err)
178{
179 // Drain stale bytes before binary status read.
180 if (!discardInput(err))
181 return false;
182 if (!writeString(cmd, err))
183 return false;
184 std::vector<uint8_t> buf;
185 if (!readExact(buf, 3, timeoutMs, err))
186 return false;
187 b1 = buf[0];
188 b2 = buf[1];
189 b3 = buf[2];
190 return true;
191}
bool queryStatus3(const std::string &cmd, uint8_t &b1, uint8_t &b2, uint8_t &b3, int timeoutMs, std::string &err)
bool discardInput(std::string &err)
bool writeRaw(const void *data, size_t len, std::string &err)
bool queryHash(const std::string &cmd, std::string &response, int timeoutMs, std::string &err)
MXHDSerial(int fd)
bool readHashTerminated(std::string &out, int timeoutMs, std::string &err)
bool writeString(const std::string &s, std::string &err)
bool readExact(std::vector< uint8_t > &out, size_t n, int timeoutMs, std::string &err)
bool queryAck(const std::string &cmd, char &ack, int timeoutMs, std::string &err)
bool readChar(char &ch, int timeoutMs, std::string &err)
int errno
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition indicom.c:418
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition indicom.c:473
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition indicom.c:1243
int tty_read_expanded(int fd, char *buf, int nbytes, long timeout_seconds, long timeout_microseconds, int *nbytes_read)
read buffer from terminal with a delimiter
Definition indicom.c:553
int tty_nread_section_expanded(int fd, char *buf, int nsize, char stop_char, long timeout_seconds, long timeout_microseconds, int *nbytes_read)
read buffer from terminal with a delimiter
Definition indicom.c:764
Implementations for common driver routines.
@ TTY_OK
Definition indicom.h:54
int fd
uint8_t cmd[4]
Definition pwc-ioctl.h:2
unsigned char byte
Definition stvdriver.h:175