1 /*
2  *  Hamlib Interface - debug
3  *  Copyright (c) 2000-2010 by Stephane Fillod
4  *
5  *
6  *   This library is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU Lesser General Public
8  *   License as published by the Free Software Foundation; either
9  *   version 2.1 of the License, or (at your option) any later version.
10  *
11  *   This library is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *   Lesser General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Lesser General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21 
22 /**
23  * \addtogroup rig
24  * @{
25  */
26 
27 /**
28  * \file debug.c
29  *
30  * \brief Control Hamlib debugging functions.
31  */
32 
33 #ifdef HAVE_CONFIG_H
34 #  include "config.h"
35 #endif
36 
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <stdio.h>  /* Standard input/output definitions */
40 #include <string.h> /* String function definitions */
41 #include <unistd.h> /* UNIX standard function definitions */
42 #include <fcntl.h>  /* File control definitions */
43 #include <errno.h>  /* Error number definitions */
44 #include <sys/types.h>
45 #include <unistd.h>
46 #include <time.h>
47 
48 #ifdef ANDROID
49 #  include <android/log.h>
50 #endif
51 
52 #include <hamlib/rig.h>
53 #include <hamlib/rig_dll.h>
54 #include "misc.h"
55 
56 /*! @} */
57 
58 
59 /**
60  * \addtogroup rig_internal
61  * @{
62  */
63 
64 
65 /** \brief Sets the number of hexadecimal pairs to print per line. */
66 #define DUMP_HEX_WIDTH 16
67 
68 
69 static int rig_debug_level = RIG_DEBUG_TRACE;
70 static int rig_debug_time_stamp = 0;
71 static FILE *rig_debug_stream;
72 static vprintf_cb_t rig_vprintf_cb;
73 static rig_ptr_t rig_vprintf_arg;
74 
75 extern HAMLIB_EXPORT(void) dump_hex(const unsigned char ptr[], size_t size);
76 
77 /**
78  * \brief Do a hex dump of the unsigned char array.
79  *
80  * \param ptr Pointer to a character array.
81  * \param size Number of chars to words to dump.
82  *
83  * Prints the hex dump to `stderr` via rig_debug():
84  *
85  * ```
86  * 0000  4b 30 30 31 34 35 30 30 30 30 30 30 30 35 30 32  K001450000000502
87  * 0010  30 30 0d 0a                                      00..
88  * ```
89  */
dump_hex(const unsigned char ptr[],size_t size)90 void dump_hex(const unsigned char ptr[], size_t size)
91 {
92     /* example
93      * 0000  4b 30 30 31 34 35 30 30 30 30 30 30 30 35 30 32  K001450000000502
94      * 0010  30 30 0d 0a                                      00..
95      */
96     char line[4 + 4 + 3 * DUMP_HEX_WIDTH + 4 + DUMP_HEX_WIDTH + 1];
97     int i;
98 
99     if (!rig_need_debug(RIG_DEBUG_TRACE))
100     {
101         return;
102     }
103 
104     line[sizeof(line) - 1] = '\0';
105 
106     for (i = 0; i < size; ++i)
107     {
108         unsigned char c;
109 
110         if (i % DUMP_HEX_WIDTH == 0)
111         {
112             /* new line */
113             sprintf(line + 0, "%04x", i);
114             memset(line + 4, ' ', sizeof(line) - 4 - 1);
115         }
116 
117         c = ptr[i];
118 
119         /* hex print */
120         sprintf(line + 8 + 3 * (i % DUMP_HEX_WIDTH), "%02x", c);
121         line[8 + 3 * (i % DUMP_HEX_WIDTH) + 2] = ' '; /* no \0 */
122 
123         /* ascii print */
124         line[8 + 3 * DUMP_HEX_WIDTH + 4 + (i % DUMP_HEX_WIDTH)] = (c >= ' '
125                 && c < 0x7f) ? c : '.';
126 
127         /* actually print the line */
128         if (i + 1 == size || (i && i % DUMP_HEX_WIDTH == DUMP_HEX_WIDTH - 1))
129         {
130             rig_debug(RIG_DEBUG_TRACE, "%s\n", line);
131         }
132     }
133 }
134 
135 /*! @} */
136 
137 
138 /**
139  * \addtogroup rig
140  * @{
141  */
142 
143 /**
144  * \brief Change the current debug level.
145  *
146  * \param debug_level Equivalent to the `-v` option of the utilities.
147  *
148  * Allows for dynamically changing the debugging output without reinitializing
149  * the library.
150  *
151  * Useful for programs that want to enable and disable debugging
152  * output without restarting.
153  */
rig_set_debug(enum rig_debug_level_e debug_level)154 void HAMLIB_API rig_set_debug(enum rig_debug_level_e debug_level)
155 {
156     rig_debug_level = debug_level;
157 }
158 
159 
160 /**
161  * \brief Test if a given debug level is active.
162  *
163  * \param debug_level The level to test.
164  *
165  * May be used to determine if an action such as opening a dialog should
166  * happen only if a desired debug level is active.
167  *
168  * Also useful for dump_hex(), etc.
169  */
rig_need_debug(enum rig_debug_level_e debug_level)170 int HAMLIB_API rig_need_debug(enum rig_debug_level_e debug_level)
171 {
172     return (debug_level <= rig_debug_level);
173 }
174 
175 
176 /**
177  * \brief Enable or disable the time stamp on debugging output.
178  *
179  * \param flag `TRUE` or `FALSE`.
180  *
181  * Sets or unsets the flag which controls whether debugging output includes a
182  * time stamp.
183  */
rig_set_debug_time_stamp(int flag)184 void HAMLIB_API rig_set_debug_time_stamp(int flag)
185 {
186     rig_debug_time_stamp = flag;
187 }
188 
189 //! @endcond
190 
191 
192 /**
193  * \brief Print debugging messages through `stderr` by default.
194  *
195  * \param debug_level Debug level from none to most output.
196  * \param fmt Formatted character string to print.
197  *
198  * The formatted character string is passed to the `frprintf`(3) C library
199  * call and follows its format specification.
200  */
201 #undef rig_debug
rig_debug(enum rig_debug_level_e debug_level,const char * fmt,...)202 void HAMLIB_API rig_debug(enum rig_debug_level_e debug_level,
203                           const char *fmt, ...)
204 {
205     va_list ap;
206 
207     if (!rig_need_debug(debug_level))
208     {
209         return;
210     }
211 
212 
213     va_start(ap, fmt);
214 
215     if (rig_vprintf_cb)
216     {
217         rig_vprintf_cb(debug_level, rig_vprintf_arg, fmt, ap);
218     }
219     else
220     {
221         if (!rig_debug_stream)
222         {
223             rig_debug_stream = stderr;
224         }
225 
226         if (rig_debug_time_stamp)
227         {
228             char buf[256];
229             fprintf(rig_debug_stream, "%s: ", date_strget(buf, sizeof(buf)));
230         }
231 
232         vfprintf(rig_debug_stream, fmt, ap);
233         fflush(rig_debug_stream);
234     }
235 
236     va_end(ap);
237 #ifdef ANDROID
238     int a;
239     va_start(ap, fmt);
240 
241     switch (debug_level)
242     {
243 //        case RIG_DEBUG_NONE:
244     case RIG_DEBUG_BUG:
245         a = ANDROID_LOG_FATAL;
246         break;
247 
248     case RIG_DEBUG_ERR:
249         a = ANDROID_LOG_ERROR;
250         break;
251 
252     case RIG_DEBUG_WARN:
253         a = ANDROID_LOG_WARN;
254         break;
255 
256     case RIG_DEBUG_VERBOSE:
257         a = ANDROID_LOG_VERBOSE;
258         break;
259 
260     case RIG_DEBUG_TRACE:
261         a = ANDROID_LOG_VERBOSE;
262         break;
263 
264     default:
265         a = ANDROID_LOG_DEBUG;
266         break;
267     }
268 
269     __android_log_vprint(a, PACKAGE_NAME, fmt, ap);
270 
271     va_end(ap);
272 #endif
273 }
274 
275 
276 /**
277  * \brief Set callback to handle debugging messages.
278  *
279  * \param cb The callback function to install.
280  * \param arg A Pointer to some private data to pass later on to the callback.
281  *
282  *  Install a callback for rig_debug() messages.
283  * \code
284  * int
285  * rig_message_cb(enum rig_debug_level_e debug_level,
286  *                rig_ptr_t user_data,
287  *                const char *fmt,
288  *                va_list ap)
289  * {
290  *     char buf[1024];
291  *
292  *     sprintf (buf, "Message(%s) ", (char*)user_data);
293  *     syslog (LOG_USER, buf);
294  *     vsprintf (buf, fmt, ap);
295  *     syslog (LOG_USER, buf);
296  *
297  *     return RIG_OK;
298  * }
299  *
300  * . . .
301  *
302  * char *cookie = "Foo";
303  * rig_set_debug_callback (rig_message_cb, (rig_ptr_t)cookie);
304  * \endcode
305  *
306  * \return A pointer to the previous callback that was set, if any.
307  *
308  * \sa rig_debug()
309  */
rig_set_debug_callback(vprintf_cb_t cb,rig_ptr_t arg)310 vprintf_cb_t HAMLIB_API rig_set_debug_callback(vprintf_cb_t cb, rig_ptr_t arg)
311 {
312     vprintf_cb_t prev_cb = rig_vprintf_cb;
313 
314     rig_vprintf_cb = cb;
315     rig_vprintf_arg = arg;
316 
317     return prev_cb;
318 }
319 
320 
321 /**
322  * \brief Change the output stream from `stderr` a different stream.
323  *
324  * \param stream The stream to direct debugging output.
325  *
326  * \sa `FILE`(3)
327  */
rig_set_debug_file(FILE * stream)328 FILE *HAMLIB_API rig_set_debug_file(FILE *stream)
329 {
330     FILE *prev_stream = rig_debug_stream;
331 
332     rig_debug_stream = stream;
333 
334     return prev_stream;
335 }
336 
337 /** @} */
338