libsigrok
|
00001 /* 00002 * This file is part of the sigrok project. 00003 * 00004 * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com> 00005 * 00006 * This program is free software: you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation, either version 3 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 */ 00019 00020 #include <stdio.h> 00021 #include <stdlib.h> 00022 #include <unistd.h> 00023 #include <string.h> 00024 #include <glib.h> 00025 #include "sigrok.h" 00026 #include "sigrok-internal.h" 00027 00028 /* demo.c. TODO: Should not be global! */ 00029 extern SR_PRIV GIOChannel channels[2]; 00030 00031 struct source { 00032 int fd; 00033 int events; 00034 int timeout; 00035 sr_receive_data_callback_t cb; 00036 void *cb_data; 00037 }; 00038 00039 /* There can only be one session at a time. */ 00040 /* 'session' is not static, it's used elsewhere (via 'extern'). */ 00041 struct sr_session *session; 00042 static int num_sources = 0; 00043 00044 static struct source *sources = NULL; 00045 static int source_timeout = -1; 00046 00047 /** 00048 * Create a new session. 00049 * 00050 * TODO: Should it use the file-global "session" variable or take an argument? 00051 * The same question applies to all the other session functions. 00052 * 00053 * @return A pointer to the newly allocated session, or NULL upon errors. 00054 */ 00055 SR_API struct sr_session *sr_session_new(void) 00056 { 00057 if (!(session = g_try_malloc0(sizeof(struct sr_session)))) { 00058 sr_err("session: %s: session malloc failed", __func__); 00059 return NULL; /* TODO: SR_ERR_MALLOC? */ 00060 } 00061 00062 return session; 00063 } 00064 00065 /** 00066 * Destroy the current session. 00067 * 00068 * This frees up all memory used by the session. 00069 * 00070 * @return SR_OK upon success, SR_ERR_BUG if no session exists. 00071 */ 00072 SR_API int sr_session_destroy(void) 00073 { 00074 if (!session) { 00075 sr_err("session: %s: session was NULL", __func__); 00076 return SR_ERR_BUG; 00077 } 00078 00079 g_slist_free(session->devs); 00080 session->devs = NULL; 00081 00082 /* TODO: Error checks needed? */ 00083 00084 /* TODO: Loop over protocol decoders and free them. */ 00085 00086 g_free(session); 00087 session = NULL; 00088 00089 return SR_OK; 00090 } 00091 00092 /** 00093 * Remove all the devices from the current session. TODO? 00094 * 00095 * The session itself (i.e., the struct sr_session) is not free'd and still 00096 * exists after this function returns. 00097 * 00098 * @return SR_OK upon success, SR_ERR_BUG if no session exists. 00099 */ 00100 SR_API int sr_session_dev_remove_all(void) 00101 { 00102 if (!session) { 00103 sr_err("session: %s: session was NULL", __func__); 00104 return SR_ERR_BUG; 00105 } 00106 00107 g_slist_free(session->devs); 00108 session->devs = NULL; 00109 00110 return SR_OK; 00111 } 00112 00113 /** 00114 * Add a device to the current session. 00115 * 00116 * @param dev The device to add to the current session. Must not be NULL. 00117 * Also, dev->driver and dev->driver->dev_open must not be NULL. 00118 * 00119 * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments. 00120 */ 00121 SR_API int sr_session_dev_add(struct sr_dev *dev) 00122 { 00123 int ret; 00124 00125 if (!dev) { 00126 sr_err("session: %s: dev was NULL", __func__); 00127 return SR_ERR_ARG; 00128 } 00129 00130 if (!session) { 00131 sr_err("session: %s: session was NULL", __func__); 00132 return SR_ERR_BUG; 00133 } 00134 00135 /* If dev->driver is NULL, this is a virtual device. */ 00136 if (!dev->driver) { 00137 sr_dbg("session: %s: dev->driver was NULL, this seems to be " 00138 "a virtual device; continuing", __func__); 00139 /* Just add the device, don't run dev_open(). */ 00140 session->devs = g_slist_append(session->devs, dev); 00141 return SR_OK; 00142 } 00143 00144 /* dev->driver is non-NULL (i.e. we have a real device). */ 00145 if (!dev->driver->dev_open) { 00146 sr_err("session: %s: dev->driver->dev_open was NULL", 00147 __func__); 00148 return SR_ERR_BUG; 00149 } 00150 00151 if ((ret = dev->driver->dev_open(dev->driver_index)) != SR_OK) { 00152 sr_err("session: %s: dev_open failed (%d)", __func__, ret); 00153 return ret; 00154 } 00155 00156 session->devs = g_slist_append(session->devs, dev); 00157 00158 return SR_OK; 00159 } 00160 00161 /** 00162 * Remove all datafeed callbacks in the current session. 00163 * 00164 * @return SR_OK upon success, SR_ERR_BUG if no session exists. 00165 */ 00166 SR_API int sr_session_datafeed_callback_remove_all(void) 00167 { 00168 if (!session) { 00169 sr_err("session: %s: session was NULL", __func__); 00170 return SR_ERR_BUG; 00171 } 00172 00173 g_slist_free(session->datafeed_callbacks); 00174 session->datafeed_callbacks = NULL; 00175 00176 return SR_OK; 00177 } 00178 00179 /** 00180 * Add a datafeed callback to the current session. 00181 * 00182 * @param cb Function to call when a chunk of data is received. 00183 * Must not be NULL. 00184 * 00185 * @return SR_OK upon success, SR_ERR_BUG if no session exists. 00186 */ 00187 SR_API int sr_session_datafeed_callback_add(sr_datafeed_callback_t cb) 00188 { 00189 if (!session) { 00190 sr_err("session: %s: session was NULL", __func__); 00191 return SR_ERR_BUG; 00192 } 00193 00194 if (!cb) { 00195 sr_err("session: %s: cb was NULL", __func__); 00196 return SR_ERR_ARG; 00197 } 00198 00199 session->datafeed_callbacks = 00200 g_slist_append(session->datafeed_callbacks, cb); 00201 00202 return SR_OK; 00203 } 00204 00205 /** 00206 * TODO. 00207 */ 00208 static int sr_session_run_poll(void) 00209 { 00210 GPollFD *fds, my_gpollfd; 00211 int ret, i; 00212 00213 fds = NULL; 00214 while (session->running) { 00215 /* TODO: Add comment. */ 00216 g_free(fds); 00217 00218 /* Construct g_poll()'s array. */ 00219 if (!(fds = g_try_malloc(sizeof(GPollFD) * num_sources))) { 00220 sr_err("session: %s: fds malloc failed", __func__); 00221 return SR_ERR_MALLOC; 00222 } 00223 for (i = 0; i < num_sources; i++) { 00224 #ifdef _WIN32 00225 g_io_channel_win32_make_pollfd(&channels[0], 00226 sources[i].events, &my_gpollfd); 00227 #else 00228 my_gpollfd.fd = sources[i].fd; 00229 my_gpollfd.events = sources[i].events; 00230 fds[i] = my_gpollfd; 00231 #endif 00232 } 00233 00234 ret = g_poll(fds, num_sources, source_timeout); 00235 00236 for (i = 0; i < num_sources; i++) { 00237 if (fds[i].revents > 0 || (ret == 0 00238 && source_timeout == sources[i].timeout)) { 00239 /* 00240 * Invoke the source's callback on an event, 00241 * or if the poll timeout out and this source 00242 * asked for that timeout. 00243 */ 00244 if (!sources[i].cb(fds[i].fd, fds[i].revents, 00245 sources[i].cb_data)) 00246 sr_session_source_remove(sources[i].fd); 00247 } 00248 } 00249 } 00250 g_free(fds); 00251 00252 return SR_OK; 00253 } 00254 00255 /** 00256 * Start a session. 00257 * 00258 * There can only be one session at a time. 00259 * 00260 * @return SR_OK upon success, SR_ERR upon errors. 00261 */ 00262 SR_API int sr_session_start(void) 00263 { 00264 struct sr_dev *dev; 00265 GSList *l; 00266 int ret; 00267 00268 if (!session) { 00269 sr_err("session: %s: session was NULL; a session must be " 00270 "created first, before starting it.", __func__); 00271 return SR_ERR_BUG; 00272 } 00273 00274 if (!session->devs) { 00275 /* TODO: Actually the case? */ 00276 sr_err("session: %s: session->devs was NULL; a session " 00277 "cannot be started without devices.", __func__); 00278 return SR_ERR_BUG; 00279 } 00280 00281 /* TODO: Check driver_index validity? */ 00282 00283 sr_info("session: starting"); 00284 00285 for (l = session->devs; l; l = l->next) { 00286 dev = l->data; 00287 /* TODO: Check for dev != NULL. */ 00288 if ((ret = dev->driver->dev_acquisition_start( 00289 dev->driver_index, dev)) != SR_OK) { 00290 sr_err("session: %s: could not start an acquisition " 00291 "(%d)", __func__, ret); 00292 break; 00293 } 00294 } 00295 00296 /* TODO: What if there are multiple devices? Which return code? */ 00297 00298 return ret; 00299 } 00300 00301 /** 00302 * Run the session. 00303 * 00304 * TODO: Various error checks etc. 00305 * 00306 * @return SR_OK upon success, SR_ERR_BUG upon errors. 00307 */ 00308 SR_API int sr_session_run(void) 00309 { 00310 if (!session) { 00311 sr_err("session: %s: session was NULL; a session must be " 00312 "created first, before running it.", __func__); 00313 return SR_ERR_BUG; 00314 } 00315 00316 if (!session->devs) { 00317 /* TODO: Actually the case? */ 00318 sr_err("session: %s: session->devs was NULL; a session " 00319 "cannot be run without devices.", __func__); 00320 return SR_ERR_BUG; 00321 } 00322 00323 sr_info("session: running"); 00324 session->running = TRUE; 00325 00326 /* Do we have real sources? */ 00327 if (num_sources == 1 && sources[0].fd == -1) { 00328 /* Dummy source, freewheel over it. */ 00329 while (session->running) 00330 sources[0].cb(-1, 0, sources[0].cb_data); 00331 } else { 00332 /* Real sources, use g_poll() main loop. */ 00333 sr_session_run_poll(); 00334 } 00335 00336 return SR_OK; 00337 } 00338 00339 /** 00340 * Halt the current session. 00341 * 00342 * This requests the current session be stopped as soon as possible, for 00343 * example on receiving an SR_DF_END packet. 00344 * 00345 * @return SR_OK upon success, SR_ERR_BUG if no session exists. 00346 */ 00347 SR_API int sr_session_halt(void) 00348 { 00349 if (!session) { 00350 sr_err("session: %s: session was NULL", __func__); 00351 return SR_ERR_BUG; 00352 } 00353 00354 sr_info("session: halting"); 00355 session->running = FALSE; 00356 00357 return SR_OK; 00358 } 00359 00360 /** 00361 * Stop the current session. 00362 * 00363 * The current session is stopped immediately, with all acquisition sessions 00364 * being stopped and hardware drivers cleaned up. 00365 * 00366 * @return SR_OK upon success, SR_ERR_BUG if no session exists. 00367 */ 00368 SR_API int sr_session_stop(void) 00369 { 00370 struct sr_dev *dev; 00371 GSList *l; 00372 00373 if (!session) { 00374 sr_err("session: %s: session was NULL", __func__); 00375 return SR_ERR_BUG; 00376 } 00377 00378 sr_info("session: stopping"); 00379 session->running = FALSE; 00380 00381 for (l = session->devs; l; l = l->next) { 00382 dev = l->data; 00383 /* Check for dev != NULL. */ 00384 if (dev->driver) { 00385 if (dev->driver->dev_acquisition_stop) 00386 dev->driver->dev_acquisition_stop(dev->driver_index, dev); 00387 if (dev->driver->cleanup) 00388 dev->driver->cleanup(); 00389 } 00390 } 00391 00392 return SR_OK; 00393 } 00394 00395 /** 00396 * Debug helper. 00397 * 00398 * @param packet The packet to show debugging information for. 00399 */ 00400 static void datafeed_dump(struct sr_datafeed_packet *packet) 00401 { 00402 struct sr_datafeed_logic *logic; 00403 00404 switch (packet->type) { 00405 case SR_DF_HEADER: 00406 sr_dbg("bus: received SR_DF_HEADER"); 00407 break; 00408 case SR_DF_TRIGGER: 00409 sr_dbg("bus: received SR_DF_TRIGGER"); 00410 break; 00411 case SR_DF_LOGIC: 00412 logic = packet->payload; 00413 /* TODO: Check for logic != NULL. */ 00414 sr_dbg("bus: received SR_DF_LOGIC %" PRIu64 " bytes", logic->length); 00415 break; 00416 case SR_DF_END: 00417 sr_dbg("bus: received SR_DF_END"); 00418 break; 00419 default: 00420 sr_dbg("bus: received unknown packet type %d", packet->type); 00421 break; 00422 } 00423 } 00424 00425 /** 00426 * Send a packet to whatever is listening on the datafeed bus. 00427 * 00428 * Hardware drivers use this to send a data packet to the frontend. 00429 * 00430 * @param dev TODO. 00431 * @param packet The datafeed packet to send to the session bus. 00432 * 00433 * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments. 00434 */ 00435 SR_PRIV int sr_session_send(struct sr_dev *dev, 00436 struct sr_datafeed_packet *packet) 00437 { 00438 GSList *l; 00439 sr_datafeed_callback_t cb; 00440 00441 if (!dev) { 00442 sr_err("session: %s: dev was NULL", __func__); 00443 return SR_ERR_ARG; 00444 } 00445 00446 if (!packet) { 00447 sr_err("session: %s: packet was NULL", __func__); 00448 return SR_ERR_ARG; 00449 } 00450 00451 for (l = session->datafeed_callbacks; l; l = l->next) { 00452 if (sr_log_loglevel_get() >= SR_LOG_DBG) 00453 datafeed_dump(packet); 00454 cb = l->data; 00455 /* TODO: Check for cb != NULL. */ 00456 cb(dev, packet); 00457 } 00458 00459 return SR_OK; 00460 } 00461 00462 /** 00463 * TODO. 00464 * 00465 * TODO: More error checks etc. 00466 * 00467 * @param fd TODO. 00468 * @param events TODO. 00469 * @param timeout TODO. 00470 * @param cb Callback function to add. Must not be NULL. 00471 * @param cb_data Data for the callback function. Can be NULL. 00472 * 00473 * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or 00474 * SR_ERR_MALLOC upon memory allocation errors. 00475 */ 00476 SR_API int sr_session_source_add(int fd, int events, int timeout, 00477 sr_receive_data_callback_t cb, void *cb_data) 00478 { 00479 struct source *new_sources, *s; 00480 00481 if (!cb) { 00482 sr_err("session: %s: cb was NULL", __func__); 00483 return SR_ERR_ARG; 00484 } 00485 00486 /* Note: cb_data can be NULL, that's not a bug. */ 00487 00488 new_sources = g_try_malloc0(sizeof(struct source) * (num_sources + 1)); 00489 if (!new_sources) { 00490 sr_err("session: %s: new_sources malloc failed", __func__); 00491 return SR_ERR_MALLOC; 00492 } 00493 00494 if (sources) { 00495 memcpy(new_sources, sources, 00496 sizeof(struct source) * num_sources); 00497 g_free(sources); 00498 } 00499 00500 s = &new_sources[num_sources++]; 00501 s->fd = fd; 00502 s->events = events; 00503 s->timeout = timeout; 00504 s->cb = cb; 00505 s->cb_data = cb_data; 00506 sources = new_sources; 00507 00508 if (timeout != source_timeout && timeout > 0 00509 && (source_timeout == -1 || timeout < source_timeout)) 00510 source_timeout = timeout; 00511 00512 return SR_OK; 00513 } 00514 00515 /** 00516 * Remove the source belonging to the specified file descriptor. 00517 * 00518 * TODO: More error checks. 00519 * 00520 * @param fd TODO. 00521 * 00522 * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or 00523 * SR_ERR_MALLOC upon memory allocation errors, SR_ERR_BUG upon 00524 * internal errors. 00525 */ 00526 SR_API int sr_session_source_remove(int fd) 00527 { 00528 struct source *new_sources; 00529 int old, new; 00530 00531 if (!sources) { 00532 sr_err("session: %s: sources was NULL", __func__); 00533 return SR_ERR_BUG; 00534 } 00535 00536 /* TODO: Check if 'fd' valid. */ 00537 00538 new_sources = g_try_malloc0(sizeof(struct source) * num_sources); 00539 if (!new_sources) { 00540 sr_err("session: %s: new_sources malloc failed", __func__); 00541 return SR_ERR_MALLOC; 00542 } 00543 00544 for (old = 0, new = 0; old < num_sources; old++) { 00545 if (sources[old].fd != fd) 00546 memcpy(&new_sources[new++], &sources[old], 00547 sizeof(struct source)); 00548 } 00549 00550 if (old != new) { 00551 g_free(sources); 00552 sources = new_sources; 00553 num_sources--; 00554 } else { 00555 /* Target fd was not found. */ 00556 g_free(new_sources); 00557 } 00558 00559 return SR_OK; 00560 }