summaryrefslogtreecommitdiff
path: root/utils/jztool/src/context.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/jztool/src/context.c')
-rw-r--r--utils/jztool/src/context.c177
1 files changed, 177 insertions, 0 deletions
diff --git a/utils/jztool/src/context.c b/utils/jztool/src/context.c
new file mode 100644
index 0000000000..d269d1eece
--- /dev/null
+++ b/utils/jztool/src/context.c
@@ -0,0 +1,177 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "jztool_private.h"
23#include <string.h>
24#include <stdlib.h>
25#include <stddef.h>
26#include <stdarg.h>
27#include <stdio.h>
28#include <time.h>
29
30#ifdef WIN32
31# include <windows.h>
32#endif
33
34/** \brief Allocate a library context
35 * \returns New context or NULL if out of memory
36 */
37jz_context* jz_context_create(void)
38{
39 jz_context* jz = malloc(sizeof(struct jz_context));
40 if(!jz)
41 return NULL;
42
43 memset(jz, 0, sizeof(struct jz_context));
44 jz->log_level = JZ_LOG_ERROR;
45 return jz;
46}
47
48/** \brief Destroy the context and free its memory */
49void jz_context_destroy(jz_context* jz)
50{
51 if(jz->usb_ctx) {
52 jz_log(jz, JZ_LOG_ERROR, "BUG: USB was not cleaned up properly");
53 libusb_exit(jz->usb_ctx);
54 }
55
56 free(jz);
57}
58
59/** \brief Set a user data pointer. Useful for callbacks. */
60void jz_context_set_user_data(jz_context* jz, void* ptr)
61{
62 jz->user_data = ptr;
63}
64
65/** \brief Get the user data pointer */
66void* jz_context_get_user_data(jz_context* jz)
67{
68 return jz->user_data;
69}
70
71/** \brief Set the log message callback.
72 * \note By default, no message callback is set! No messages will be logged
73 * in this case, so ensure you set a callback if messages are desired.
74 */
75void jz_context_set_log_cb(jz_context* jz, jz_log_cb cb)
76{
77 jz->log_cb = cb;
78}
79
80/** \brief Set the log level.
81 *
82 * Messages of less importance than the set log level are not logged.
83 * The default log level is `JZ_LOG_WARNING`. The special log level
84 * `JZ_LOG_IGNORE` can be used to disable all logging temporarily.
85 *
86 * The `JZ_LOG_DEBUG` log level is extremely verbose and will log all calls,
87 * normally it's only useful for catching bugs.
88 */
89void jz_context_set_log_level(jz_context* jz, jz_log_level lev)
90{
91 jz->log_level = lev;
92}
93
94/** \brief Log an informational message.
95 * \param lev Log level for this message
96 * \param fmt `printf` style message format string
97 */
98void jz_log(jz_context* jz, jz_log_level lev, const char* fmt, ...)
99{
100 if(!jz->log_cb)
101 return;
102 if(lev == JZ_LOG_IGNORE)
103 return;
104 if(lev > jz->log_level)
105 return;
106
107 va_list ap;
108
109 va_start(ap, fmt);
110 int n = vsnprintf(NULL, 0, fmt, ap);
111 va_end(ap);
112
113 if(n < 0)
114 return;
115
116 char* buf = malloc(n + 1);
117 if(!buf)
118 return;
119
120 va_start(ap, fmt);
121 n = vsnprintf(buf, n + 1, fmt, ap);
122 va_end(ap);
123
124 if(n >= 0)
125 jz->log_cb(lev, buf);
126
127 free(buf);
128}
129
130/** \brief Log callback which writes messages to `stderr`.
131 */
132void jz_log_cb_stderr(jz_log_level lev, const char* msg)
133{
134 static const char* const tags[] =
135 {"ERROR", "WARNING", "NOTICE", "DETAIL", "DEBUG"};
136 fprintf(stderr, "[%7s] %s\n", tags[lev], msg);
137 fflush(stderr);
138}
139
140/** \brief Sleep for `ms` milliseconds.
141 */
142void jz_sleepms(int ms)
143{
144#ifdef WIN32
145 Sleep(ms);
146#else
147 struct timespec ts;
148 long ns = ms % 1000;
149 ts.tv_nsec = ns * 1000 * 1000;
150 ts.tv_sec = ms / 1000;
151 nanosleep(&ts, NULL);
152#endif
153}
154
155/** \brief Add reference to libusb context, allocating it if necessary */
156int jz_context_ref_libusb(jz_context* jz)
157{
158 if(jz->usb_ctxref == 0) {
159 int rc = libusb_init(&jz->usb_ctx);
160 if(rc < 0) {
161 jz_log(jz, JZ_LOG_ERROR, "libusb_init: %s", libusb_strerror(rc));
162 return JZ_ERR_USB;
163 }
164 }
165
166 jz->usb_ctxref += 1;
167 return JZ_SUCCESS;
168}
169
170/** \brief Remove reference to libusb context, freeing if it hits zero */
171void jz_context_unref_libusb(jz_context* jz)
172{
173 if(--jz->usb_ctxref == 0) {
174 libusb_exit(jz->usb_ctx);
175 jz->usb_ctx = NULL;
176 }
177}