From: Bert Vermeulen Date: Wed, 18 Sep 2013 11:28:07 +0000 (+0200) Subject: Add sr_session_append(): add captured data to an existing session file X-Git-Tag: libsigrok-0.2.2~59 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=f438e0c923a114d7fd34fe0729ecd6891cb262f4;p=libsigrok.git Add sr_session_append(): add captured data to an existing session file This extends the session file format to contain logic data files named either "logic-1" as before, or "logic-1-1", "logic-1-2", ... representing chronologically ordered chunks of captured data. The chunks are transparently concatenated together by sr_session_load(). --- diff --git a/libsigrok-internal.h b/libsigrok-internal.h index 423463a2..93434ab3 100644 --- a/libsigrok-internal.h +++ b/libsigrok-internal.h @@ -119,6 +119,7 @@ SR_PRIV int sr_source_add(int fd, int events, int timeout, SR_PRIV int sr_session_send(const struct sr_dev_inst *sdi, const struct sr_datafeed_packet *packet); SR_PRIV int sr_session_stop_sync(void); +SR_PRIV int sr_sessionfile_check(const char *filename); /*--- std.c -----------------------------------------------------------------*/ diff --git a/proto.h b/proto.h index ca23fc7c..2c078a7c 100644 --- a/proto.h +++ b/proto.h @@ -103,6 +103,8 @@ SR_API int sr_session_run(void); SR_API int sr_session_stop(void); SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi, unsigned char *buf, int unitsize, int units); +SR_API int sr_session_append(const char *filename, unsigned char *buf, + int unitsize, int units); SR_API int sr_session_source_add(int fd, int events, int timeout, sr_receive_data_callback_t cb, void *cb_data); SR_API int sr_session_source_add_pollfd(GPollFD *pollfd, int timeout, diff --git a/session_driver.c b/session_driver.c index 435d46af..8090df9d 100644 --- a/session_driver.c +++ b/session_driver.c @@ -49,6 +49,7 @@ struct session_vdev { uint64_t samplerate; int unitsize; int num_probes; + int cur_chunk; }; static GSList *dev_insts = NULL; @@ -64,21 +65,20 @@ static int receive_data(int fd, int revents, void *cb_data) struct session_vdev *vdev; struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; + struct zip_stat zs; GSList *l; - void *buf; int ret, got_data; + char capturefile[16]; + void *buf; (void)fd; (void)revents; - sr_dbg("Feed chunk."); - got_data = FALSE; for (l = dev_insts; l; l = l->next) { sdi = l->data; - vdev = sdi->priv; - if (!vdev) - /* already done with this instance */ + if (!(vdev = sdi->priv)) + /* Already done with this instance. */ continue; if (!(buf = g_try_malloc(CHUNKSIZE))) { @@ -86,6 +86,53 @@ static int receive_data(int fd, int revents, void *cb_data) return FALSE; } + if (!vdev->capfile) { + /* No capture file opened yet, or finished with the last + * chunked one. */ + if (vdev->cur_chunk == 0) { + /* capturefile is always the unchunked base name. */ + if (zip_stat(vdev->archive, vdev->capturefile, 0, &zs) != -1) { + /* No chunks, just a single capture file. */ + vdev->cur_chunk = 0; + if (!(vdev->capfile = zip_fopen(vdev->archive, + vdev->capturefile, 0))) + return FALSE; + sr_dbg("Opened %s.", vdev->capturefile); + } else { + /* Try as first chunk filename. */ + snprintf(capturefile, 15, "%s-1", vdev->capturefile); + if (zip_stat(vdev->archive, capturefile, 0, &zs) != -1) { + vdev->cur_chunk = 1; + if (!(vdev->capfile = zip_fopen(vdev->archive, + capturefile, 0))) + return FALSE; + sr_dbg("Opened %s.", capturefile); + } else { + sr_err("No capture file '%s' in " "session file '%s'.", + vdev->capturefile, vdev->sessionfile); + return FALSE; + } + } + } else { + /* Capture data is chunked, advance to the next chunk. */ + vdev->cur_chunk++; + snprintf(capturefile, 15, "%s-%d", vdev->capturefile, + vdev->cur_chunk); + if (zip_stat(vdev->archive, capturefile, 0, &zs) != -1) { + if (!(vdev->capfile = zip_fopen(vdev->archive, + capturefile, 0))) + return FALSE; + sr_dbg("Opened %s.", capturefile); + } else { + /* We got all the chunks, finish up. */ + g_free(vdev->capturefile); + g_free(vdev); + sdi->priv = NULL; + continue; + } + } + } + ret = zip_fread(vdev->capfile, buf, CHUNKSIZE); if (ret > 0) { got_data = TRUE; @@ -99,9 +146,17 @@ static int receive_data(int fd, int revents, void *cb_data) } else { /* done with this capture file */ zip_fclose(vdev->capfile); - g_free(vdev->capturefile); - g_free(vdev); - sdi->priv = NULL; + vdev->capfile = NULL; + if (vdev->cur_chunk == 0) { + /* It was the only file. */ + g_free(vdev->capturefile); + g_free(vdev); + sdi->priv = NULL; + } else { + /* There might be more chunks, so don't fall through + * to the SR_DF_END here. */ + return TRUE; + } } } @@ -115,7 +170,6 @@ static int receive_data(int fd, int revents, void *cb_data) } /* driver callbacks */ -static int cleanup(void); static int init(struct sr_context *sr_ctx) { @@ -218,7 +272,6 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi) static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { - struct zip_stat zs; struct session_vdev *vdev; int ret; @@ -233,18 +286,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) return SR_ERR; } - if (zip_stat(vdev->archive, vdev->capturefile, 0, &zs) == -1) { - sr_err("Failed to check capture file '%s' in " - "session file '%s'.", vdev->capturefile, vdev->sessionfile); - return SR_ERR; - } - - if (!(vdev->capfile = zip_fopen(vdev->archive, vdev->capturefile, 0))) { - sr_err("Failed to open capture file '%s' in " - "session file '%s'.", vdev->capturefile, vdev->sessionfile); - return SR_ERR; - } - /* Send header packet to the session bus. */ std_session_send_df_header(cb_data, LOG_PREFIX); diff --git a/session_file.c b/session_file.c index 4838a6be..479dba04 100644 --- a/session_file.c +++ b/session_file.c @@ -51,54 +51,35 @@ extern struct sr_session *session; extern SR_PRIV struct sr_dev_driver session_driver; -/** - * Load the session from the specified filename. - * - * @param filename The name of the session file to load. Must not be NULL. - * - * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, - * SR_ERR_MALLOC upon memory allocation errors, or SR_ERR upon - * other errors. - */ -SR_API int sr_session_load(const char *filename) +SR_PRIV int sr_sessionfile_check(const char *filename) { - GKeyFile *kf; - GPtrArray *capturefiles; struct zip *archive; struct zip_file *zf; struct zip_stat zs; - struct sr_dev_inst *sdi; - struct sr_probe *probe; - int ret, probenum, devcnt, version, i, j; - uint64_t tmp_u64, total_probes, enabled_probes, p; - char **sections, **keys, *metafile, *val, s[11]; - char probename[SR_MAX_PROBENAME_LEN + 1]; + int version, ret; + char s[11]; - if (!filename) { - sr_err("%s: filename was NULL", __func__); + if (!filename) return SR_ERR_ARG; - } - if (!(archive = zip_open(filename, 0, &ret))) { - sr_dbg("Failed to open session file: zip error %d", ret); + if (!(archive = zip_open(filename, 0, &ret))) + /* No logging: this can be used just to check if it's + * a sigrok session file or not. */ return SR_ERR; - } /* check "version" */ version = 0; if (!(zf = zip_fopen(archive, "version", 0))) { - sr_dbg("Not a sigrok session file."); + sr_dbg("Not a sigrok session file: no version found."); return SR_ERR; } - if ((ret = zip_fread(zf, s, 10)) == -1) { - sr_dbg("Not a valid sigrok session file."); + if ((ret = zip_fread(zf, s, 10)) == -1) return SR_ERR; - } zip_fclose(zf); s[ret] = 0; version = strtoull(s, NULL, 10); if (version != 1) { - sr_dbg("Not a valid sigrok session file version."); + sr_dbg("Cannot handle sigrok session file version %d.", version); return SR_ERR; } @@ -108,6 +89,41 @@ SR_API int sr_session_load(const char *filename) return SR_ERR; } + return SR_OK; +} + +/** + * Load the session from the specified filename. + * + * @param filename The name of the session file to load. Must not be NULL. + * + * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, + * SR_ERR_MALLOC upon memory allocation errors, or SR_ERR upon + * other errors. + */ +SR_API int sr_session_load(const char *filename) +{ + GKeyFile *kf; + GPtrArray *capturefiles; + struct zip *archive; + struct zip_file *zf; + struct zip_stat zs; + struct sr_dev_inst *sdi; + struct sr_probe *probe; + int ret, probenum, devcnt, i, j; + uint64_t tmp_u64, total_probes, enabled_probes, p; + char **sections, **keys, *metafile, *val; + char probename[SR_MAX_PROBENAME_LEN + 1]; + + if ((ret = sr_sessionfile_check(filename)) != SR_OK) + return ret; + + if (!(archive = zip_open(filename, 0, &ret))) + return SR_ERR; + + if (zip_stat(archive, "metadata", 0, &zs) == -1) + return SR_ERR; + if (!(metafile = g_try_malloc(zs.size))) { sr_err("%s: metafile malloc failed", __func__); return SR_ERR_MALLOC; @@ -306,4 +322,65 @@ SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi, return SR_OK; } +/** + * Append data to an existing session file. + * + * @param filename The name of the filename to append to. Must not be NULL. + * @param buf The data to be appended. + * @param unitsize The number of bytes per sample. + * @param units The number of samples. + * + * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or SR_ERR + * upon other errors. + */ +SR_API int sr_session_append(const char *filename, unsigned char *buf, + int unitsize, int units) +{ + struct zip *archive; + struct zip_source *logicsrc; + zip_int64_t num_files; + int chunk_num, next_chunk_num, ret, i; + const char *entry_name; + char chunkname[16]; + + if ((ret = sr_sessionfile_check(filename)) != SR_OK) + return ret; + + if (!(archive = zip_open(filename, 0, &ret))) + return SR_ERR; + + next_chunk_num = 1; + num_files = zip_get_num_entries(archive, 0); + for (i = 0; i < num_files; i++) { + entry_name = zip_get_name(archive, i, 0); + if (strncmp(entry_name, "logic-1", 7)) + continue; + if (strlen(entry_name) == 7) { + /* This file has no extra chunks, just a single "logic-1". + * Rename it to "logic-1-1" * and continue with chunk 2. */ + if (zip_rename(archive, i, "logic-1-1") == -1) { + sr_err("Failed to rename 'logic-1' to 'logic-1-1'."); + return SR_ERR; + } + next_chunk_num = 2; + break; + } else if (strlen(entry_name) > 8 && entry_name[7] == '-') { + chunk_num = strtoull(entry_name + 8, NULL, 10); + if (chunk_num >= next_chunk_num) + next_chunk_num = chunk_num + 1; + } + } + snprintf(chunkname, 15, "logic-1-%d", next_chunk_num); + if (!(logicsrc = zip_source_buffer(archive, buf, units * unitsize, FALSE))) + return SR_ERR; + if (zip_add(archive, chunkname, logicsrc) == -1) + return SR_ERR; + if ((ret = zip_close(archive)) == -1) { + sr_info("error saving session file: %s", zip_strerror(archive)); + return SR_ERR; + } + + return SR_OK; +} + /** @} */