session_driver.c 29.2 KB
Newer Older
DreamSourceLab's avatar
DreamSourceLab committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * This file is part of the libsigrok project.
 *
 * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

DreamSourceLab's avatar
DreamSourceLab committed
20 21
#include "libsigrok.h"
#include "libsigrok-internal.h"
DreamSourceLab's avatar
DreamSourceLab committed
22 23 24 25 26 27
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <zip.h>
28
#include <assert.h>
DreamSourceLab's avatar
DreamSourceLab committed
29
#include <string.h>
DreamSourceLab's avatar
DreamSourceLab committed
30 31 32 33 34 35 36 37 38 39 40 41 42

/* Message logging helpers with subsystem-specific prefix string. */
#define LOG_PREFIX "virtual-session: "
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)

/* size of payloads sent across the session bus */
/** @cond PRIVATE */
#define CHUNKSIZE (512 * 1024)
43
#define UNITLEN 64
DreamSourceLab's avatar
DreamSourceLab committed
44 45
/** @endcond */

DreamSourceLab's avatar
DreamSourceLab committed
46 47 48
static uint64_t samplerates[1];
static uint64_t samplecounts[1];

49 50 51 52 53 54 55
static const char *maxHeights[] = {
    "1X",
    "2X",
    "3X",
    "4X",
    "5X",
};
56 57 58 59 60 61 62 63 64 65
static const uint64_t vdivs[] = {
    SR_mV(10),
    SR_mV(20),
    SR_mV(50),
    SR_mV(100),
    SR_mV(200),
    SR_mV(500),
    SR_V(1),
    SR_V(2),
};
66

DreamSourceLab's avatar
DreamSourceLab committed
67
struct session_vdev {
Andy Dneg's avatar
Andy Dneg committed
68
    int language;
69
    int version;
DreamSourceLab's avatar
DreamSourceLab committed
70 71 72 73
	char *sessionfile;
	char *capturefile;
	struct zip *archive;
	struct zip_file *capfile;
74
    void *buf;
75
    void *logic_buf;
DreamSourceLab's avatar
DreamSourceLab committed
76
	int bytes_read;
77 78 79 80
    int cur_channel;
    int cur_block;
    int num_blocks;
    gboolean file_opened;
DreamSourceLab's avatar
DreamSourceLab committed
81 82
	uint64_t samplerate;
    uint64_t total_samples;
83 84
    int64_t trig_time;
    uint64_t trig_pos;
DreamSourceLab's avatar
DreamSourceLab committed
85
	int num_probes;
86
    int enabled_probes;
87
    uint64_t timebase;
88 89
    uint64_t max_timebase;
    uint64_t min_timebase;
90
    uint8_t unit_bits;
Andy Dneg's avatar
Andy Dneg committed
91 92
    uint32_t ref_min;
    uint32_t ref_max;
93
    uint8_t max_height;
94
    struct sr_status mstatus;
DreamSourceLab's avatar
DreamSourceLab committed
95 96 97 98
};

static GSList *dev_insts = NULL;

99 100 101 102
static const int hwoptions[] = {
    SR_CONF_MAX_HEIGHT,
};

Andy Dneg's avatar
Andy Dneg committed
103 104 105 106
static const int32_t sessions[] = {
    SR_CONF_MAX_HEIGHT,
};

107 108 109 110 111 112 113 114 115
static const int32_t probeOptions[] = {
    SR_CONF_PROBE_MAP_UNIT,
    SR_CONF_PROBE_MAP_MIN,
    SR_CONF_PROBE_MAP_MAX,
};

static const char *probeMapUnits[] = {
    "V",
    "A",
116 117
    "℃",
    "℉",
118 119 120 121 122
    "g",
    "m",
    "m/s",
};

Andy Dneg's avatar
Andy Dneg committed
123
static struct sr_dev_mode mode_list[] = {
124 125 126
    {LOGIC, "Logic Analyzer", "逻辑分析仪", "la", "la.png"},
    {ANALOG, "Data Acquisition", "数据记录仪", "daq", "daq.png"},
    {DSO, "Oscilloscope", "示波器", "osc", "osc.png"},
Andy Dneg's avatar
Andy Dneg committed
127 128
};

129 130 131 132
static int trans_data(struct sr_dev_inst *sdi)
{
    // translate for old format
    struct session_vdev *vdev = sdi->priv;
DreamSourceLab's avatar
DreamSourceLab committed
133
    GSList *l;
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
    struct sr_channel *probe;

    assert(vdev->buf != NULL);
    assert(vdev->logic_buf != NULL);
    assert(CHUNKSIZE % UNITLEN == 0);

    //int bytes = ceil(vdev->num_probes / 8.0);
    int bytes = 2;
    uint8_t *src_ptr = (uint8_t *)vdev->buf;
    uint64_t *dest_ptr = (uint64_t *)vdev->logic_buf;
    for (int k = 0; k < CHUNKSIZE / (UNITLEN * bytes); k++) {
        src_ptr = (uint8_t *)vdev->buf + (k * bytes * UNITLEN);
        for (l = sdi->channels; l; l = l->next) {
            probe = l->data;
            if (!probe->enabled)
                continue;
            uint64_t mask = 1ULL << probe->index;
            uint64_t result = 0;
            for (int j = 0; j < UNITLEN; j++) {
                if (*(uint64_t *)(src_ptr + j * bytes) & mask)
                    result += 1ULL << j;
            }
            *dest_ptr++ = result;
        }
    }

    return SR_OK;
}

Andy Dneg's avatar
Andy Dneg committed
163 164 165 166 167 168 169 170 171 172
static int file_close(struct session_vdev *vdev)
{
    int ret = zip_close(vdev->archive);
    if (ret  == -1) {
        sr_info("error close session file: %s", zip_strerror(vdev->archive));
        return SR_ERR;
    }
    return SR_OK;
}

DreamSourceLab's avatar
DreamSourceLab committed
173 174 175
static int receive_data(int fd, int revents, const struct sr_dev_inst *cb_sdi)
{
	struct sr_dev_inst *sdi;
DreamSourceLab's avatar
DreamSourceLab committed
176
    struct session_vdev *vdev = NULL;
DreamSourceLab's avatar
DreamSourceLab committed
177 178
	struct sr_datafeed_packet packet;
	struct sr_datafeed_logic logic;
179 180
    struct sr_datafeed_dso dso;
    struct sr_datafeed_analog analog;
DreamSourceLab's avatar
DreamSourceLab committed
181
	GSList *l;
182 183
    int ret;
    char file_name[32];
DreamSourceLab's avatar
DreamSourceLab committed
184
    struct sr_channel *probe = NULL;
185 186 187
    GSList *pl;
    int channel;

DreamSourceLab's avatar
DreamSourceLab committed
188
	(void)fd;
189
    //(void)revents;
DreamSourceLab's avatar
DreamSourceLab committed
190 191 192

	sr_dbg("Feed chunk.");

193 194
    ret = 0;
    packet.status = SR_PKT_OK;
DreamSourceLab's avatar
DreamSourceLab committed
195 196 197 198 199 200 201
	for (l = dev_insts; l; l = l->next) {
		sdi = l->data;
		vdev = sdi->priv;
		if (!vdev)
			/* already done with this instance */
			continue;

202
        assert(vdev->unit_bits > 0);
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
        assert(vdev->cur_channel >= 0);
        if (vdev->cur_channel < vdev->num_probes) {
            if (vdev->version == 1) {
                ret = zip_fread(vdev->capfile, vdev->buf, CHUNKSIZE);
            } else if (vdev->version == 2) {
                channel = vdev->cur_channel;
                pl = sdi->channels;
                while (channel--)
                    pl = pl->next;
                probe = (struct sr_channel *)pl->data;

                if (!vdev->file_opened) {
                    char *type_name = (probe->type == SR_CHANNEL_LOGIC) ? "L" :
                                (probe->type == SR_CHANNEL_DSO) ? "O" :
                                (probe->type == SR_CHANNEL_ANALOG) ? "A" : "U";
                    snprintf(file_name, 31, "%s-%d/%d", type_name,
219
                             sdi->mode == LOGIC ? probe->index : 0, vdev->cur_block);
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
                    if (!(vdev->capfile = zip_fopen(vdev->archive, file_name, 0))) {
                        sr_err("Failed to open capture file '%s' in "
                               "session file '%s'.", file_name, vdev->sessionfile);
                    } else {
                        vdev->file_opened = TRUE;
                    }
                }
                if (vdev->file_opened)
                    ret = zip_fread(vdev->capfile, vdev->buf, CHUNKSIZE);
            }

            if (!vdev->file_opened) {
                packet.type = SR_DF_END;
                packet.status = SR_PKT_SOURCE_ERROR;
                sr_session_send(cb_sdi, &packet);
                sr_session_source_remove(-1);
Andy Dneg's avatar
Andy Dneg committed
236
                file_close(vdev);
237 238 239 240 241 242 243
                return FALSE;
            }

            if (ret > 0) {
                if (sdi->mode == DSO) {
                    packet.type = SR_DF_DSO;
                    packet.payload = &dso;
244
                    dso.num_samples = ret / vdev->num_probes;
245 246 247 248 249 250 251 252 253
                    dso.data = vdev->buf;
                    dso.probes = sdi->channels;
                    dso.mq = SR_MQ_VOLTAGE;
                    dso.unit = SR_UNIT_VOLT;
                    dso.mqflags = SR_MQFLAG_AC;
                } else if (sdi->mode == ANALOG){
                    packet.type = SR_DF_ANALOG;
                    packet.payload = &analog;
                    analog.probes = sdi->channels;
254
                    analog.num_samples = ret / vdev->num_probes / ((vdev->unit_bits + 7) / 8);
255
                    analog.unit_bits = vdev->unit_bits;
256 257 258 259 260 261 262 263 264
                    analog.mq = SR_MQ_VOLTAGE;
                    analog.unit = SR_UNIT_VOLT;
                    analog.mqflags = SR_MQFLAG_AC;
                    analog.data = vdev->buf;
                } else {
                    packet.type = SR_DF_LOGIC;
                    packet.payload = &logic;
                    logic.length = ret;
                    logic.format = (vdev->version == 2) ? LA_SPLIT_DATA : LA_CROSS_DATA;
DreamSourceLab's avatar
DreamSourceLab committed
265 266 267 268
                    if (probe)
                        logic.index = probe->index;
                    else
                        logic.index = 0;
269 270 271 272 273 274 275 276 277 278 279 280 281
                    logic.order = vdev->cur_channel;

                    if (vdev->version == 1) {
                        logic.length = ret / 16 * vdev->enabled_probes;
                        logic.data = vdev->logic_buf;
                        trans_data(sdi);
                    } else if (vdev->version == 2) {
                        logic.length = ret;
                        logic.data = vdev->buf;
                    }
                }
                vdev->bytes_read += ret;
                sr_session_send(cb_sdi, &packet);
282
            } else {
283 284 285 286 287 288 289 290 291 292 293 294 295
                /* done with this capture file */
                zip_fclose(vdev->capfile);

                if (vdev->version == 1) {
                    vdev->cur_channel++;
                } else if (vdev->version == 2) {
                    vdev->file_opened = FALSE;
                    vdev->cur_block++;
                    if (vdev->cur_block == vdev->num_blocks) {
                        vdev->cur_block = 0;
                        vdev->cur_channel++;
                    }
                }
296
            }
297
        }
DreamSourceLab's avatar
DreamSourceLab committed
298 299
	}

DreamSourceLab's avatar
DreamSourceLab committed
300 301
    if (!vdev ||
        vdev->cur_channel >= vdev->num_probes ||
302
        revents == -1) {
DreamSourceLab's avatar
DreamSourceLab committed
303 304 305
		packet.type = SR_DF_END;
		sr_session_send(cb_sdi, &packet);
		sr_session_source_remove(-1);
Andy Dneg's avatar
Andy Dneg committed
306
        file_close(vdev);
DreamSourceLab's avatar
DreamSourceLab committed
307 308 309 310 311 312
	}

	return TRUE;
}

/* driver callbacks */
DreamSourceLab's avatar
DreamSourceLab committed
313
static int dev_clear(void);
DreamSourceLab's avatar
DreamSourceLab committed
314

DreamSourceLab's avatar
DreamSourceLab committed
315
static int init(struct sr_context *sr_ctx)
DreamSourceLab's avatar
DreamSourceLab committed
316 317 318 319 320 321
{
	(void)sr_ctx;

	return SR_OK;
}

Andy Dneg's avatar
Andy Dneg committed
322 323 324 325 326 327 328 329 330 331 332 333 334
static const GSList *dev_mode_list(const struct sr_dev_inst *sdi)
{
    GSList *l = NULL;
    unsigned int i;

    for (i = 0; i < ARRAY_SIZE(mode_list); i++) {
        if (sdi->mode == mode_list[i].mode)
            l = g_slist_append(l, &mode_list[i]);
    }

    return l;
}

DreamSourceLab's avatar
DreamSourceLab committed
335
static int dev_clear(void)
DreamSourceLab's avatar
DreamSourceLab committed
336 337 338 339 340 341 342 343 344 345 346
{
	GSList *l;

	for (l = dev_insts; l; l = l->next)
		sr_dev_inst_free(l->data);
	g_slist_free(dev_insts);
	dev_insts = NULL;

	return SR_OK;
}

DreamSourceLab's avatar
DreamSourceLab committed
347
static int dev_open(struct sr_dev_inst *sdi)
DreamSourceLab's avatar
DreamSourceLab committed
348 349 350 351 352 353
{
	if (!(sdi->priv = g_try_malloc0(sizeof(struct session_vdev)))) {
		sr_err("%s: sdi->priv malloc failed", __func__);
		return SR_ERR_MALLOC;
	}

DreamSourceLab's avatar
DreamSourceLab committed
354 355
    struct session_vdev *vdev;
    vdev = sdi->priv;
356
    if (!(vdev->buf = g_try_malloc(CHUNKSIZE + sizeof(uint64_t)))) {
DreamSourceLab's avatar
DreamSourceLab committed
357 358 359
        sr_err("%s: vdev->buf malloc failed", __func__);
        return SR_ERR_MALLOC;
    }
360 361
    vdev->trig_pos = 0;
    vdev->trig_time = 0;
362 363 364 365
    vdev->cur_block = 0;
    vdev->cur_channel = 0;
    vdev->file_opened = FALSE;
    vdev->num_blocks = 0;
366
    vdev->unit_bits = 1;
Andy Dneg's avatar
Andy Dneg committed
367 368
    vdev->ref_min = 0;
    vdev->ref_max = 0;
369 370
    vdev->max_timebase = MAX_TIMEBASE;
    vdev->min_timebase = MIN_TIMEBASE;
371
    vdev->max_height = 0;
Andy Dneg's avatar
Andy Dneg committed
372
    vdev->mstatus.measure_valid = TRUE;
DreamSourceLab's avatar
DreamSourceLab committed
373

DreamSourceLab's avatar
DreamSourceLab committed
374 375 376 377 378
	dev_insts = g_slist_append(dev_insts, sdi);

	return SR_OK;
}

DreamSourceLab's avatar
DreamSourceLab committed
379 380 381 382 383
static int dev_close(struct sr_dev_inst *sdi)
{
    const struct session_vdev *const vdev = sdi->priv;
    g_free(vdev->sessionfile);
    g_free(vdev->capturefile);
384
    g_free(vdev->buf);
385 386
    if (vdev->logic_buf)
        g_free(vdev->logic_buf);
DreamSourceLab's avatar
DreamSourceLab committed
387 388 389 390 391 392 393

    g_free(sdi->priv);
    sdi->priv = NULL;

    return SR_OK;
}

394 395 396
static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
                      const struct sr_channel *ch,
                      const struct sr_channel_group *cg)
DreamSourceLab's avatar
DreamSourceLab committed
397
{
DreamSourceLab's avatar
DreamSourceLab committed
398 399
    (void)cg;

DreamSourceLab's avatar
DreamSourceLab committed
400 401 402
	struct session_vdev *vdev;

	switch (id) {
Andy Dneg's avatar
Andy Dneg committed
403 404 405 406 407 408
    case SR_CONF_LANGUAGE:
        if (!sdi)
            return SR_ERR;
        vdev = sdi->priv;
        *data = g_variant_new_int16(vdev->language);
        break;
DreamSourceLab's avatar
DreamSourceLab committed
409 410 411 412 413 414 415 416 417 418 419 420 421 422
	case SR_CONF_SAMPLERATE:
		if (sdi) {
			vdev = sdi->priv;
			*data = g_variant_new_uint64(vdev->samplerate);
		} else
			return SR_ERR;
		break;
    case SR_CONF_LIMIT_SAMPLES:
        if (sdi) {
            vdev = sdi->priv;
            *data = g_variant_new_uint64(vdev->total_samples);
        } else
            return SR_ERR;
        break;
423 424 425 426 427 428 429
    case SR_CONF_TRIGGER_TIME:
        if (sdi) {
            vdev = sdi->priv;
            *data = g_variant_new_int64(vdev->trig_time);
        } else
            return SR_ERR;
        break;
430 431 432 433 434 435 436
    case SR_CONF_TIMEBASE:
        if (sdi) {
            vdev = sdi->priv;
            *data = g_variant_new_uint64(vdev->timebase);
        } else
            return SR_ERR;
        break;
437
    case SR_CONF_MAX_TIMEBASE:
438 439 440 441 442 443 444 445 446 447 448
        if (sdi) {
            vdev = sdi->priv;
            *data = g_variant_new_uint64(vdev->max_timebase);
        } else
            return SR_ERR;
        break;
    case SR_CONF_MIN_TIMEBASE:
        if (sdi) {
            vdev = sdi->priv;
            *data = g_variant_new_uint64(vdev->min_timebase);
        } else
449 450
            return SR_ERR;
        break;
451
    case SR_CONF_UNIT_BITS:
452 453
        if (sdi) {
            vdev = sdi->priv;
454
            *data = g_variant_new_byte(vdev->unit_bits);
455 456 457
        } else
            return SR_ERR;
        break;
Andy Dneg's avatar
Andy Dneg committed
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
    case SR_CONF_REF_MIN:
        if (sdi) {
            vdev = sdi->priv;
            if (vdev->ref_min == 0)
                return SR_ERR;
            else
                *data = g_variant_new_uint32(vdev->ref_min);
        } else
            return SR_ERR;
        break;
    case SR_CONF_REF_MAX:
        if (sdi) {
            vdev = sdi->priv;
            if (vdev->ref_max == 0)
                return SR_ERR;
            else
                *data = g_variant_new_uint32(vdev->ref_max);
        } else
            return SR_ERR;
        break;
478
    case SR_CONF_PROBE_EN:
479 480 481 482 483
        if (sdi && ch) {
            *data = g_variant_new_boolean(ch->enabled);
        } else
            return SR_ERR;
        break;
484
    case SR_CONF_PROBE_COUPLING:
485 486 487 488 489
        if (sdi && ch) {
            *data = g_variant_new_byte(ch->coupling);
        } else
            return SR_ERR;
        break;
490
    case SR_CONF_PROBE_VDIV:
491 492 493 494 495
        if (sdi && ch) {
            *data = g_variant_new_uint64(ch->vdiv);
        } else
            return SR_ERR;
        break;
496
    case SR_CONF_PROBE_FACTOR:
497 498 499 500 501
        if (sdi && ch) {
            *data = g_variant_new_uint64(ch->vfactor);
        } else
            return SR_ERR;
        break;
Andy Dneg's avatar
Andy Dneg committed
502
    case SR_CONF_PROBE_OFFSET:
503
        if (sdi && ch) {
Andy Dneg's avatar
Andy Dneg committed
504
            *data = g_variant_new_uint16(ch->offset);
505 506 507
        } else
            return SR_ERR;
        break;
Andy Dneg's avatar
Andy Dneg committed
508 509 510 511 512 513
    case SR_CONF_PROBE_HW_OFFSET:
        if (sdi && ch) {
            *data = g_variant_new_uint16(ch->hw_offset);
        } else
            return SR_ERR;
        break;      
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
    case SR_CONF_PROBE_MAP_UNIT:
        if (!sdi || !ch)
            return SR_ERR;
        *data = g_variant_new_string(ch->map_unit);
        break;
    case SR_CONF_PROBE_MAP_MIN:
        if (!sdi || !ch)
            return SR_ERR;
        *data = g_variant_new_double(ch->map_min);
        break;
    case SR_CONF_PROBE_MAP_MAX:
        if (!sdi || !ch)
            return SR_ERR;
        *data = g_variant_new_double(ch->map_max);
        break;
529 530 531 532 533 534
    case SR_CONF_TRIGGER_VALUE:
        if (sdi && ch) {
            *data = g_variant_new_byte(ch->trig_value);
        } else
            return SR_ERR;
        break;
535 536 537
    case SR_CONF_MAX_DSO_SAMPLERATE:
        if (!sdi)
            return SR_ERR;
538
        vdev = sdi->priv;
539 540 541 542 543
        *data = g_variant_new_uint64(vdev->samplerate);
        break;
    case SR_CONF_MAX_DSO_SAMPLELIMITS:
        if (!sdi)
            return SR_ERR;
544 545 546 547 548 549 550
        vdev = sdi->priv;
        *data = g_variant_new_uint64(vdev->total_samples);
        break;
    case SR_CONF_HW_DEPTH:
        if (!sdi)
            return SR_ERR;
        vdev = sdi->priv;
551 552
        *data = g_variant_new_uint64(vdev->total_samples);
        break;
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
    case SR_CONF_MAX_HEIGHT:
        if (!sdi)
            return SR_ERR;
        vdev = sdi->priv;
        *data = g_variant_new_string(maxHeights[vdev->max_height]);
        break;
    case SR_CONF_MAX_HEIGHT_VALUE:
        if (!sdi)
            return SR_ERR;
        vdev = sdi->priv;
        *data = g_variant_new_byte(vdev->max_height);
        break;
    case SR_CONF_VLD_CH_NUM:
        if (!sdi)
            return SR_ERR;
        vdev = sdi->priv;
        *data = g_variant_new_int16(vdev->num_probes);
        break;
    case SR_CONF_FILE_VERSION:
        if (!sdi)
            return SR_ERR;
        vdev = sdi->priv;
        *data = g_variant_new_int16(vdev->version);
576
        break;
577
    default:
DreamSourceLab's avatar
DreamSourceLab committed
578 579 580 581 582 583
		return SR_ERR_ARG;
	}

	return SR_OK;
}

DreamSourceLab's avatar
DreamSourceLab committed
584
static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi,
585
                      struct sr_channel *ch,
DreamSourceLab's avatar
DreamSourceLab committed
586
                      struct sr_channel_group *cg)
DreamSourceLab's avatar
DreamSourceLab committed
587
{
DreamSourceLab's avatar
DreamSourceLab committed
588 589
    (void)cg;

DreamSourceLab's avatar
DreamSourceLab committed
590
	struct session_vdev *vdev;
591
    const char *stropt;
DreamSourceLab's avatar
DreamSourceLab committed
592
    unsigned int i;
DreamSourceLab's avatar
DreamSourceLab committed
593 594 595 596

	vdev = sdi->priv;

	switch (id) {
Andy Dneg's avatar
Andy Dneg committed
597 598 599
    case SR_CONF_LANGUAGE:
        vdev->language = g_variant_get_int16(data);
        break;
DreamSourceLab's avatar
DreamSourceLab committed
600 601
	case SR_CONF_SAMPLERATE:
		vdev->samplerate = g_variant_get_uint64(data);
DreamSourceLab's avatar
DreamSourceLab committed
602
        samplerates[0] = vdev->samplerate;
DreamSourceLab's avatar
DreamSourceLab committed
603 604
		sr_info("Setting samplerate to %" PRIu64 ".", vdev->samplerate);
		break;
605 606 607 608
    case SR_CONF_TIMEBASE:
        vdev->timebase = g_variant_get_uint64(data);
        sr_info("Setting timebase to %" PRIu64 ".", vdev->timebase);
        break;
609 610 611 612 613 614 615 616
    case SR_CONF_MAX_TIMEBASE:
        vdev->max_timebase = g_variant_get_uint64(data);
        sr_info("Setting max timebase to %" PRIu64 ".", vdev->max_timebase);
        break;
    case SR_CONF_MIN_TIMEBASE:
        vdev->min_timebase = g_variant_get_uint64(data);
        sr_info("Setting min timebase to %" PRIu64 ".", vdev->min_timebase);
        break;
617 618 619
    case SR_CONF_UNIT_BITS:
        vdev->unit_bits = g_variant_get_byte(data);
        sr_info("Setting unit bits to %d.", vdev->unit_bits);
620
        break;
Andy Dneg's avatar
Andy Dneg committed
621 622 623 624 625 626 627 628
    case SR_CONF_REF_MIN:
        vdev->ref_min = g_variant_get_uint32(data);
        sr_info("Setting ref min to %d.", vdev->ref_min);
        break;
    case SR_CONF_REF_MAX:
        vdev->ref_max = g_variant_get_uint32(data);
        sr_info("Setting ref max to %d.", vdev->ref_max);
        break;
629
    case SR_CONF_SESSIONFILE:
630
        vdev->sessionfile = g_strdup(g_variant_get_bytestring(data));
DreamSourceLab's avatar
DreamSourceLab committed
631 632 633
		sr_info("Setting sessionfile to '%s'.", vdev->sessionfile);
		break;
	case SR_CONF_CAPTUREFILE:
634
        vdev->capturefile = g_strdup(g_variant_get_bytestring(data));
DreamSourceLab's avatar
DreamSourceLab committed
635 636
		sr_info("Setting capturefile to '%s'.", vdev->capturefile);
		break;
637 638 639 640
    case SR_CONF_FILE_VERSION:
        vdev->version = g_variant_get_int16(data);
        sr_info("Setting file version to '%d'.", vdev->version);
        break;
DreamSourceLab's avatar
DreamSourceLab committed
641 642
    case SR_CONF_LIMIT_SAMPLES:
        vdev->total_samples = g_variant_get_uint64(data);
DreamSourceLab's avatar
DreamSourceLab committed
643 644
        samplecounts[0] = vdev->total_samples;
        sr_info("Setting limit samples to %" PRIu64 ".", vdev->total_samples);
DreamSourceLab's avatar
DreamSourceLab committed
645
        break;
646 647 648 649 650 651 652 653
    case SR_CONF_TRIGGER_TIME:
        vdev->trig_time = g_variant_get_int64(data);
        sr_info("Setting trigger time to %" PRId64 ".", vdev->trig_time);
        break;
    case SR_CONF_TRIGGER_POS:
        vdev->trig_pos = g_variant_get_uint64(data);
        sr_info("Setting trigger position to %" PRIu64 ".", vdev->trig_pos);
        break;
654 655 656 657
    case SR_CONF_NUM_BLOCKS:
        vdev->num_blocks = g_variant_get_uint64(data);
        sr_info("Setting block number to %" PRIu64 ".", vdev->num_blocks);
        break;
658
    case SR_CONF_CAPTURE_NUM_PROBES:
DreamSourceLab's avatar
DreamSourceLab committed
659
		vdev->num_probes = g_variant_get_uint64(data);
Andy Dneg's avatar
Andy Dneg committed
660 661 662 663 664
        if (vdev->version == 1) {
            if (sdi->mode == LOGIC) {
                if (!(vdev->logic_buf = g_try_malloc(CHUNKSIZE/16*vdev->num_probes))) {
                    sr_err("%s: vdev->logic_buf malloc failed", __func__);
                }
665
            }
Andy Dneg's avatar
Andy Dneg committed
666 667
        } else {
            vdev->logic_buf = NULL;
668
        }
DreamSourceLab's avatar
DreamSourceLab committed
669
		break;
670
    case SR_CONF_PROBE_EN:
671 672
        ch->enabled = g_variant_get_boolean(data);
        break;
673
    case SR_CONF_PROBE_COUPLING:
674 675
        ch->coupling = g_variant_get_byte(data);
        break;
676
    case SR_CONF_PROBE_VDIV:
677 678
        ch->vdiv = g_variant_get_uint64(data);
        break;
679
    case SR_CONF_PROBE_FACTOR:
680 681
        ch->vfactor = g_variant_get_uint64(data);
        break;
Andy Dneg's avatar
Andy Dneg committed
682 683
    case SR_CONF_PROBE_OFFSET:
        ch->offset = g_variant_get_uint16(data);
684
        break;
Andy Dneg's avatar
Andy Dneg committed
685 686 687 688
    case SR_CONF_PROBE_HW_OFFSET:
        ch->hw_offset = g_variant_get_uint16(data);
        ch->offset = ch->hw_offset;
        break;       
689 690 691 692 693 694 695 696 697
    case SR_CONF_PROBE_MAP_UNIT:
        ch->map_unit = g_variant_get_string(data, NULL);
        break;
    case SR_CONF_PROBE_MAP_MIN:
        ch->map_min = g_variant_get_double(data);
        break;
    case SR_CONF_PROBE_MAP_MAX:
        ch->map_max = g_variant_get_double(data);
        break;
698 699 700
    case SR_CONF_TRIGGER_VALUE:
        ch->trig_value = g_variant_get_byte(data);
        break;
701 702
    case SR_CONF_STATUS_PERIOD:
        if (ch->index == 0)
Andy Dneg's avatar
Andy Dneg committed
703
            vdev->mstatus.ch0_cyc_tlen = g_variant_get_uint32(data);
704
        else
Andy Dneg's avatar
Andy Dneg committed
705
            vdev->mstatus.ch1_cyc_tlen = g_variant_get_uint32(data);
706 707 708
        break;
    case SR_CONF_STATUS_PCNT:
        if (ch->index == 0)
Andy Dneg's avatar
Andy Dneg committed
709
            vdev->mstatus.ch0_cyc_cnt = g_variant_get_uint32(data);
710
        else
Andy Dneg's avatar
Andy Dneg committed
711
            vdev->mstatus.ch1_cyc_cnt = g_variant_get_uint32(data);
712 713 714
        break;
    case SR_CONF_STATUS_MAX:
        if (ch->index == 0)
Andy Dneg's avatar
Andy Dneg committed
715
            vdev->mstatus.ch0_max = g_variant_get_byte(data);
716
        else
Andy Dneg's avatar
Andy Dneg committed
717
            vdev->mstatus.ch1_max = g_variant_get_byte(data);
718 719 720
        break;
    case SR_CONF_STATUS_MIN:
        if (ch->index == 0)
Andy Dneg's avatar
Andy Dneg committed
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751
            vdev->mstatus.ch0_min = g_variant_get_byte(data);
        else
            vdev->mstatus.ch1_min = g_variant_get_byte(data);
        break;
    case SR_CONF_STATUS_PLEN:
        if (ch->index == 0)
            vdev->mstatus.ch0_cyc_plen = g_variant_get_uint32(data);
        else
            vdev->mstatus.ch1_cyc_plen = g_variant_get_uint32(data);
        break;
    case SR_CONF_STATUS_LLEN:
        if (ch->index == 0)
            vdev->mstatus.ch0_cyc_llen = g_variant_get_uint32(data);
        else
            vdev->mstatus.ch0_cyc_llen = g_variant_get_uint32(data);
        break;
    case SR_CONF_STATUS_LEVEL:
        if (ch->index == 0)
            vdev->mstatus.ch0_level_valid = g_variant_get_boolean(data);
        else
            vdev->mstatus.ch1_level_valid = g_variant_get_boolean(data);
        break;
    case SR_CONF_STATUS_PLEVEL:
        if (ch->index == 0)
            vdev->mstatus.ch0_plevel = g_variant_get_boolean(data);
        else
            vdev->mstatus.ch1_plevel = g_variant_get_boolean(data);
        break;
    case SR_CONF_STATUS_LOW:
        if (ch->index == 0)
            vdev->mstatus.ch0_low_level = g_variant_get_byte(data);
752
        else
Andy Dneg's avatar
Andy Dneg committed
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
            vdev->mstatus.ch1_low_level = g_variant_get_byte(data);
        break;
    case SR_CONF_STATUS_HIGH:
        if (ch->index == 0)
            vdev->mstatus.ch0_high_level = g_variant_get_byte(data);
        else
            vdev->mstatus.ch1_high_level = g_variant_get_byte(data);
        break;
    case SR_CONF_STATUS_RLEN:
        if (ch->index == 0)
            vdev->mstatus.ch0_cyc_rlen = g_variant_get_uint32(data);
        else
            vdev->mstatus.ch1_cyc_rlen = g_variant_get_uint32(data);
        break;
    case SR_CONF_STATUS_FLEN:
        if (ch->index == 0)
            vdev->mstatus.ch0_cyc_flen = g_variant_get_uint32(data);
        else
            vdev->mstatus.ch1_cyc_flen = g_variant_get_uint32(data);
        break;
    case SR_CONF_STATUS_RMS:
        if (ch->index == 0)
            vdev->mstatus.ch0_acc_square = g_variant_get_uint64(data);
        else
            vdev->mstatus.ch1_acc_square = g_variant_get_uint64(data);
        break;
    case SR_CONF_STATUS_MEAN:
        if (ch->index == 0)
            vdev->mstatus.ch0_acc_mean = g_variant_get_uint32(data);
        else
            vdev->mstatus.ch1_acc_mean = g_variant_get_uint32(data);
784
        break;
785 786 787 788 789 790 791 792 793 794 795
    case SR_CONF_MAX_HEIGHT:
        stropt = g_variant_get_string(data, NULL);
        for (i = 0; i < ARRAY_SIZE(maxHeights); i++) {
            if (!strcmp(stropt, maxHeights[i])) {
                vdev->max_height = i;
                break;
            }
        }
        sr_dbg("%s: setting Signal Max Height to %d",
            __func__, vdev->max_height);
        break;
Andy Dneg's avatar
Andy Dneg committed
796 797 798
    case SR_CONF_INSTANT:
    case SR_CONF_RLE:
        break;
799
    default:
DreamSourceLab's avatar
DreamSourceLab committed
800 801 802 803 804 805 806
		sr_err("Unknown capability: %d.", id);
		return SR_ERR;
	}

	return SR_OK;
}

DreamSourceLab's avatar
DreamSourceLab committed
807 808 809
static int config_list(int key, GVariant **data,
                       const struct sr_dev_inst *sdi,
                       const struct sr_channel_group *cg)
DreamSourceLab's avatar
DreamSourceLab committed
810
{
DreamSourceLab's avatar
DreamSourceLab committed
811 812
    (void)cg;

DreamSourceLab's avatar
DreamSourceLab committed
813 814
    GVariant *gvar;
    GVariantBuilder gvb;
DreamSourceLab's avatar
DreamSourceLab committed
815 816 817 818

	(void)sdi;

	switch (key) {
819
    case SR_CONF_DEVICE_OPTIONS:
820 821 822 823 824
//		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
//				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
        *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"),
                hwoptions, ARRAY_SIZE(hwoptions)*sizeof(int32_t), TRUE, NULL, NULL);
        break;
Andy Dneg's avatar
Andy Dneg committed
825 826 827 828
    case SR_CONF_DEVICE_SESSIONS:
        *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"),
                sessions, ARRAY_SIZE(sessions)*sizeof(int32_t), TRUE, NULL, NULL);
        break;
DreamSourceLab's avatar
DreamSourceLab committed
829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
    case SR_CONF_SAMPLERATE:
        g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
//		gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
//				ARRAY_SIZE(samplerates), sizeof(uint64_t));
        gvar = g_variant_new_from_data(G_VARIANT_TYPE("at"),
                samplerates, ARRAY_SIZE(samplerates)*sizeof(uint64_t), TRUE, NULL, NULL);
        g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
        *data = g_variant_builder_end(&gvb);
        break;
    case SR_CONF_LIMIT_SAMPLES:
        g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
        gvar = g_variant_new_from_data(G_VARIANT_TYPE("at"),
                samplecounts, ARRAY_SIZE(samplecounts)*sizeof(uint64_t), TRUE, NULL, NULL);
        g_variant_builder_add(&gvb, "{sv}", "samplecounts", gvar);
        *data = g_variant_builder_end(&gvb);
        break;
845 846 847
    case SR_CONF_MAX_HEIGHT:
        *data = g_variant_new_strv(maxHeights, ARRAY_SIZE(maxHeights));
        break;
848 849 850 851 852

    case SR_CONF_PROBE_CONFIGS:
        *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"),
                probeOptions, ARRAY_SIZE(probeOptions)*sizeof(int32_t), TRUE, NULL, NULL);
        break;
853 854 855 856 857 858 859
    case SR_CONF_PROBE_VDIV:
        g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
        gvar = g_variant_new_from_data(G_VARIANT_TYPE("at"),
                vdivs, ARRAY_SIZE(vdivs)*sizeof(uint64_t), TRUE, NULL, NULL);
        g_variant_builder_add(&gvb, "{sv}", "vdivs", gvar);
        *data = g_variant_builder_end(&gvb);
        break;
860 861 862
    case SR_CONF_PROBE_MAP_UNIT:
        *data = g_variant_new_strv(probeMapUnits, ARRAY_SIZE(probeMapUnits));
        break;
863
    default:
DreamSourceLab's avatar
DreamSourceLab committed
864 865 866 867 868 869
		return SR_ERR_ARG;
	}

	return SR_OK;
}

870
static int dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg, int begin, int end)
871
{
872
    (void)prg;
873 874 875 876 877 878 879 880 881 882 883 884 885 886
    (void)begin;
    (void)end;

    struct session_vdev *vdev;

    if (sdi) {
        vdev = sdi->priv;
        *status = vdev->mstatus;
        return SR_OK;
    } else {
        return SR_ERR;
    }
}

DreamSourceLab's avatar
DreamSourceLab committed
887
static int dev_acquisition_start(struct sr_dev_inst *sdi,
DreamSourceLab's avatar
DreamSourceLab committed
888 889
		void *cb_data)
{
DreamSourceLab's avatar
DreamSourceLab committed
890 891
    (void)cb_data;

DreamSourceLab's avatar
DreamSourceLab committed
892 893
	struct zip_stat zs;
	struct session_vdev *vdev;
894
    struct sr_datafeed_packet packet;
DreamSourceLab's avatar
DreamSourceLab committed
895
	int ret;
DreamSourceLab's avatar
DreamSourceLab committed
896
    GSList *l;
897
    struct sr_channel *probe;
DreamSourceLab's avatar
DreamSourceLab committed
898 899

	vdev = sdi->priv;
900 901
    vdev->enabled_probes = 0;
    packet.status = SR_PKT_OK;
DreamSourceLab's avatar
DreamSourceLab committed
902 903 904 905 906 907 908 909 910 911

	sr_info("Opening archive %s file %s", vdev->sessionfile,
		vdev->capturefile);

	if (!(vdev->archive = zip_open(vdev->sessionfile, 0, &ret))) {
		sr_err("Failed to open session file '%s': "
		       "zip error %d\n", vdev->sessionfile, ret);
		return SR_ERR;
	}

912 913 914 915 916 917
    if (vdev->version == 1) {
        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;
        }
DreamSourceLab's avatar
DreamSourceLab committed
918

919 920 921 922 923 924 925 926
        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;
        }
        vdev->file_opened = TRUE;
        vdev->cur_channel = vdev->num_probes - 1;
    } else {
927 928 929 930
        if (sdi->mode == LOGIC)
            vdev->cur_channel = 0;
        else
            vdev->cur_channel = vdev->num_probes - 1;
931 932 933 934 935 936 937
    }

    for (l = sdi->channels; l; l = l->next) {
        probe = l->data;
        if (probe->enabled)
            vdev->enabled_probes++;
    }
DreamSourceLab's avatar
DreamSourceLab committed
938 939 940 941

	/* Send header packet to the session bus. */
    std_session_send_df_header(sdi, LOG_PREFIX);

942 943 944
    /* Send trigger packet to the session bus */
    if (vdev->trig_pos != 0) {
        struct ds_trigger_pos session_trigger;
945 946 947 948
        if (sdi->mode == DSO)
            session_trigger.real_pos = vdev->trig_pos * vdev->enabled_probes / vdev->num_probes;
        else
            session_trigger.real_pos = vdev->trig_pos;
949 950 951 952 953
        packet.type = SR_DF_TRIGGER;
        packet.payload = &session_trigger;
        sr_session_send(sdi, &packet);
    }

DreamSourceLab's avatar
DreamSourceLab committed
954 955 956 957 958 959 960 961
	/* freewheeling source */
    sr_session_source_add(-1, 0, 0, receive_data, sdi);

	return SR_OK;
}

/** @private */
SR_PRIV struct sr_dev_driver session_driver = {
DreamSourceLab's avatar
DreamSourceLab committed
962 963 964 965 966 967 968
    .name = "virtual-session",
    .longname = "Session-emulating driver",
    .api_version = 1,
    .init = init,
    .cleanup = dev_clear,
    .scan = NULL,
    .dev_list = NULL,
Andy Dneg's avatar
Andy Dneg committed
969
    .dev_mode_list = dev_mode_list,
DreamSourceLab's avatar
DreamSourceLab committed
970 971 972 973 974 975
    .dev_clear = dev_clear,
    .config_get = config_get,
    .config_set = config_set,
    .config_list = config_list,
    .dev_open = dev_open,
    .dev_close = dev_close,
976
    .dev_status_get = dev_status_get,
DreamSourceLab's avatar
DreamSourceLab committed
977 978 979
    .dev_acquisition_start = dev_acquisition_start,
    .dev_acquisition_stop = NULL,
    .priv = NULL,
DreamSourceLab's avatar
DreamSourceLab committed
980
};