1 /*
2     TTY Base
3 
4     Base class for TTY Serial Connections.
5 
6     Copyright (C) 2018 Jasem Mutlaq
7     Copyright (C) 2011 Wildi Markus
8 
9     This library is free software; you can redistribute it and/or
10     modify it under the terms of the GNU Lesser General Public
11     License as published by the Free Software Foundation; either
12     version 2.1 of the License, or (at your option) any later version.
13 
14     This library is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17     Lesser General Public License for more details.
18 
19     You should have received a copy of the GNU Lesser General Public
20     License along with this library; if not, write to the Free Software
21     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 
23 */
24 
25 #pragma once
26 
27 #include <string>
28 #include <indilogger.h>
29 
30 /** \class TTYBase
31     \brief Base class for serial communications
32 
33     This class is the C++ implementation of indicom serial functionality. Due to the idiosyncrasies of different serial implementation (including TCP/UDP),
34     the base class methods can be overridden to provide specific implementations for a particular serial behavior.
35 
36     It provides methods to connect to and disconnect from serial devices, including TCP/UDP connections.
37 
38     \author Jasem Mutlaq
39     \author Wildi Markus
40 */
41 
42 class TTYBase
43 {
44 public:
45     typedef enum
46     {
47         TTY_OK           = 0,
48         TTY_READ_ERROR   = -1,
49         TTY_WRITE_ERROR  = -2,
50         TTY_SELECT_ERROR = -3,
51         TTY_TIME_OUT     = -4,
52         TTY_PORT_FAILURE = -5,
53         TTY_PARAM_ERROR  = -6,
54         TTY_ERRNO        = -7,
55         TTY_OVERFLOW     = -8
56     } TTY_RESPONSE;
57 
58     TTYBase(const char *driverName);
59     virtual ~TTYBase();
60 
61     /** \brief read buffer from terminal
62         \param fd file descriptor
63         \param buf pointer to store data. Must be initilized and big enough to hold data.
64         \param nbytes number of bytes to read.
65         \param timeout number of seconds to wait for terminal before a timeout error is issued.
66         \param nbytes_read the number of bytes read.
67         \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code.
68     */
69     TTY_RESPONSE read(uint8_t *buffer, uint32_t nbytes, uint8_t timeout, uint32_t *nbytes_read);
70 
71     /** \brief read buffer from terminal with a delimiter
72         \param fd file descriptor
73         \param buf pointer to store data. Must be initilized and big enough to hold data.
74         \param stop_char if the function encounters \e stop_char then it stops reading and returns the buffer.
75         \param nsize size of buf. If stop character is not encountered before nsize, the function aborts.
76         \param timeout number of seconds to wait for terminal before a timeout error is issued.
77         \param nbytes_read the number of bytes read.
78         \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code.
79     */
80     TTY_RESPONSE readSection(uint8_t *buffer, uint32_t nsize, uint8_t stop_byte, uint8_t timeout, uint32_t *nbytes_read);
81 
82     /** \brief Writes a buffer to fd.
83         \param fd file descriptor
84         \param buffer a null-terminated buffer to write to fd.
85         \param nbytes number of bytes to write from \e buffer
86         \param nbytes_written the number of bytes written
87         \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code.
88     */
89     TTY_RESPONSE write(const uint8_t *buffer, uint32_t nbytes, uint32_t *nbytes_written);
90 
91     /** \brief Writes a null terminated string to fd.
92         \param fd file descriptor
93         \param buffer the buffer to write to fd.
94         \param nbytes_written the number of bytes written
95         \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code.
96     */
97     TTY_RESPONSE writeString(const char *string, uint32_t *nbytes_written);
98 
99     /** \brief Establishes a tty connection to a terminal device.
100         \param device the device node. e.g. /dev/ttyS0
101         \param bit_rate bit rate
102         \param word_size number of data bits, 7 or 8, USE 8 DATA BITS with modbus
103         \param parity 0=no parity, 1=parity EVEN, 2=parity ODD
104         \param stop_bits number of stop bits : 1 or 2
105         \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code.
106     */
107 
108     TTY_RESPONSE connect(const char *device, uint32_t bit_rate, uint8_t word_size, uint8_t parity, uint8_t stop_bits);
109 
110     /** \brief Closes a tty connection and flushes the bus.
111         \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code.
112     */
113     TTY_RESPONSE disconnect();
114 
115     /**
116      * @brief setDebug Enable or Disable debug logging
117      * @param enabled If true, TTY traffic will be logged.
118      * @param channel Channel from INDI logger to log to.
119      * @warning Only enable TTY debugging when diagnosting issues with serial communications. Due to the verbose traffic
120      * generated from serial data, this can have significant adverse effects on the function of the driver. Use with caution!
121      */
122     void setDebug(INDI::Logger::VerbosityLevel channel);
123 
124     /** \brief Retrieve the tty error message
125         \param err_code the error code return by any TTY function.
126         \return Error message string
127     */
128     const std::string error(TTY_RESPONSE code) const;
129 
getPortFD()130     int getPortFD() const { return m_PortFD; }
131 
132 private:
133 
134     TTY_RESPONSE checkTimeout(uint8_t timeout);
135 
136     int m_PortFD { -1 };
137     bool m_Debug { false };
138     INDI::Logger::VerbosityLevel m_DebugChannel { INDI::Logger::DBG_IGNORE };
139     const char *m_DriverName;
140 };
141